未验证 提交 ffc9841d 编写于 作者: M Mark Brown

Merge remote-tracking branch 'asoc/for-5.13' into asoc-next

......@@ -4,7 +4,7 @@ This device supports I2C mode only.
Required properties:
- compatible : "asahi-kasei,ak5558"
- compatible : "asahi-kasei,ak5558" or "asahi-kasei,ak5552".
- reg : The I2C address of the device.
Optional properties:
......
......@@ -11,71 +11,59 @@ maintainers:
select: false
allOf:
- $ref: /schemas/graph.yaml#/$defs/port-base
properties:
port:
description: single OF-Graph subnode
type: object
prefix:
description: "device name prefix"
$ref: /schemas/types.yaml#/definitions/string
convert-rate:
description: CPU to Codec rate convert.
$ref: /schemas/types.yaml#/definitions/uint32
convert-channels:
description: CPU to Codec rate channels.
$ref: /schemas/types.yaml#/definitions/uint32
patternProperties:
"^endpoint(@[0-9a-f]+)?":
$ref: /schemas/graph.yaml#/$defs/endpoint-base
properties:
reg:
maxItems: 1
prefix:
description: "device name prefix"
$ref: /schemas/types.yaml#/definitions/string
mclk-fs:
description: |
Multiplication factor between stream rate and codec mclk.
When defined, mclk-fs property defined in dai-link sub nodes are
ignored.
$ref: /schemas/types.yaml#/definitions/uint32
frame-inversion:
description: dai-link uses frame clock inversion
$ref: /schemas/types.yaml#/definitions/flag
bitclock-inversion:
description: dai-link uses bit clock inversion
$ref: /schemas/types.yaml#/definitions/flag
frame-master:
description: Indicates dai-link frame master.
$ref: /schemas/types.yaml#/definitions/phandle
bitclock-master:
description: Indicates dai-link bit clock master
$ref: /schemas/types.yaml#/definitions/phandle
dai-format:
description: audio format.
items:
enum:
- i2s
- right_j
- left_j
- dsp_a
- dsp_b
- ac97
- pdm
- msb
- lsb
convert-rate:
description: CPU to Codec rate convert.
$ref: /schemas/types.yaml#/definitions/uint32
convert-channels:
description: CPU to Codec rate channels.
$ref: /schemas/types.yaml#/definitions/uint32
patternProperties:
"^endpoint(@[0-9a-f]+)?":
type: object
properties:
remote-endpoint:
maxItems: 1
mclk-fs:
description: |
Multiplication factor between stream rate and codec mclk.
When defined, mclk-fs property defined in dai-link sub nodes are
ignored.
$ref: /schemas/types.yaml#/definitions/uint32
frame-inversion:
description: dai-link uses frame clock inversion
$ref: /schemas/types.yaml#/definitions/flag
bitclock-inversion:
description: dai-link uses bit clock inversion
$ref: /schemas/types.yaml#/definitions/flag
frame-master:
description: Indicates dai-link frame master.
$ref: /schemas/types.yaml#/definitions/phandle
bitclock-master:
description: Indicates dai-link bit clock master
$ref: /schemas/types.yaml#/definitions/phandle
dai-format:
description: audio format.
items:
enum:
- i2s
- right_j
- left_j
- dsp_a
- dsp_b
- ac97
- pdm
- msb
- lsb
convert-rate:
description: CPU to Codec rate convert.
$ref: /schemas/types.yaml#/definitions/uint32
convert-channels:
description: CPU to Codec rate channels.
$ref: /schemas/types.yaml#/definitions/uint32
ports:
description: multi OF-Graph subnode
type: object
patternProperties:
"^port(@[0-9a-f]+)?":
$ref: "#/properties/port"
additionalProperties: true
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/fsl,rpmsg.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP Audio RPMSG CPU DAI Controller
maintainers:
- Shengjiu Wang <shengjiu.wang@nxp.com>
description: |
fsl_rpmsg is a virtual audio device. Mapping to real hardware devices
are SAI, DMA controlled by Cortex M core. What we see from Linux
side is a device which provides audio service by rpmsg channel.
properties:
compatible:
enum:
- fsl,imx7ulp-rpmsg-audio
- fsl,imx8mn-rpmsg-audio
- fsl,imx8mm-rpmsg-audio
- fsl,imx8mp-rpmsg-audio
model:
$ref: /schemas/types.yaml#/definitions/string
description: User specified audio sound card name
clocks:
items:
- description: Peripheral clock for register access
- description: Master clock
- description: DMA clock for DMA register access
- description: Parent clock for multiple of 8kHz sample rates
- description: Parent clock for multiple of 11kHz sample rates
clock-names:
items:
- const: ipg
- const: mclk
- const: dma
- const: pll8k
- const: pll11k
power-domains:
description:
List of phandle and PM domain specifier as documented in
Documentation/devicetree/bindings/power/power_domain.txt
maxItems: 1
memory-region:
$ref: /schemas/types.yaml#/definitions/phandle
description:
phandle to a node describing reserved memory (System RAM memory)
The M core can't access all the DDR memory space on some platform,
So reserved a specific memory for dma buffer which M core can
access.
(see bindings/reserved-memory/reserved-memory.txt)
audio-codec:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle to a node of audio codec
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.
fsl,enable-lpa:
$ref: /schemas/types.yaml#/definitions/flag
description: enable low power audio path.
fsl,rpmsg-out:
$ref: /schemas/types.yaml#/definitions/flag
description: |
This is a boolean property. If present, the transmitting function
will be enabled.
fsl,rpmsg-in:
$ref: /schemas/types.yaml#/definitions/flag
description: |
This is a boolean property. If present, the receiving function
will be enabled.
required:
- compatible
- model
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8mn-clock.h>
rpmsg_audio: rpmsg_audio {
compatible = "fsl,imx8mn-rpmsg-audio";
model = "wm8524-audio";
fsl,enable-lpa;
fsl,rpmsg-out;
clocks = <&clk IMX8MN_CLK_SAI3_IPG>,
<&clk IMX8MN_CLK_SAI3_ROOT>,
<&clk IMX8MN_CLK_SDMA3_ROOT>,
<&clk IMX8MN_AUDIO_PLL1_OUT>,
<&clk IMX8MN_AUDIO_PLL2_OUT>;
clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k";
};
......@@ -42,6 +42,8 @@ The compatible list for this generic sound card currently:
"fsl,imx-audio-si476x"
"fsl,imx-audio-wm8958"
Required properties:
- compatible : Contains one of entries in the compatible list.
......
......@@ -81,6 +81,6 @@ examples:
interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "osc", "apb_clk";
clocks = <&scmi_clk KEEM_BAY_PSS_AUX_I2S3>, <&scmi_clk KEEM_BAY_PSS_I2S3>;
dmas = <&axi_dma0 29 &axi_dma0 33>;
dmas = <&axi_dma0 29>, <&axi_dma0 33>;
dma-names = "tx", "rx";
};
......@@ -9,9 +9,6 @@ title: Marvel SSPA Digital Audio Interface Bindings
maintainers:
- Lubomir Rintel <lkundrak@v3.sk>
allOf:
- $ref: audio-graph-port.yaml#
properties:
$nodename:
pattern: "^audio-controller(@.*)?$"
......@@ -54,7 +51,8 @@ properties:
- const: rx
port:
type: object
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
properties:
endpoint:
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mchp,i2s-mcc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip I2S Multi-Channel Controller
maintainers:
- Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
description:
The I2SMCC complies with the Inter-IC Sound (I2S) bus specification and
supports a Time Division Multiplexed (TDM) interface with external
multi-channel audio codecs. It consists of a receiver, a transmitter and a
common clock generator that can be enabled separately to provide Adapter,
Client or Controller modes with receiver and/or transmitter active.
On later I2SMCC versions (starting with Microchip's SAMA7G5) I2S
multi-channel is supported by using multiple data pins, output and
input, without TDM.
properties:
"#sound-dai-cells":
const: 0
compatible:
enum:
- microchip,sam9x60-i2smcc
- microchip,sama7g5-i2smcc
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: Peripheral Bus Clock
- description: Generic Clock (Optional). Should be set mostly when Master
Mode is required.
minItems: 1
clock-names:
items:
- const: pclk
- const: gclk
minItems: 1
dmas:
items:
- description: TX DMA Channel
- description: RX DMA Channel
dma-names:
items:
- const: tx
- const: rx
microchip,tdm-data-pair:
description:
Represents the DIN/DOUT pair pins that are used to receive/send
TDM data. It is optional and it is only needed if the controller
uses the TDM mode.
$ref: /schemas/types.yaml#/definitions/uint8
enum: [0, 1, 2, 3]
default: 0
if:
properties:
compatible:
const: microchip,sam9x60-i2smcc
then:
properties:
microchip,tdm-data-pair: false
required:
- "#sound-dai-cells"
- compatible
- reg
- interrupts
- clocks
- clock-names
- dmas
- dma-names
additionalProperties: false
examples:
- |
#include <dt-bindings/dma/at91.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
i2s@f001c000 {
#sound-dai-cells = <0>;
compatible = "microchip,sam9x60-i2smcc";
reg = <0xf001c000 0x100>;
interrupts = <34 IRQ_TYPE_LEVEL_HIGH 7>;
dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(36))>,
<&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(37))>;
dma-names = "tx", "rx";
clocks = <&i2s_clk>, <&i2s_gclk>;
clock-names = "pclk", "gclk";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2s_default>;
};
* Microchip I2S Multi-Channel Controller
Required properties:
- compatible: Should be "microchip,sam9x60-i2smcc".
- reg: Should be the physical base address of the controller and the
length of memory mapped region.
- interrupts: Should contain the interrupt for the controller.
- dmas: Should be one per channel name listed in the dma-names property,
as described in atmel-dma.txt and dma.txt files.
- dma-names: Identifier string for each DMA request line in the dmas property.
Two dmas have to be defined, "tx" and "rx".
- clocks: Must contain an entry for each entry in clock-names.
Please refer to clock-bindings.txt.
- clock-names: Should be one of each entry matching the clocks phandles list:
- "pclk" (peripheral clock) Required.
- "gclk" (generated clock) Optional (1).
Optional properties:
- pinctrl-0: Should specify pin control groups used for this controller.
- princtrl-names: Should contain only one value - "default".
(1) : Only the peripheral clock is required. The generated clock is optional
and should be set mostly when Master Mode is required.
Example:
i2s@f001c000 {
compatible = "microchip,sam9x60-i2smcc";
reg = <0xf001c000 0x100>;
interrupts = <34 IRQ_TYPE_LEVEL_HIGH 7>;
dmas = <&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(36))>,
<&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(37))>;
dma-names = "tx", "rx";
clocks = <&i2s_clk>, <&i2s_gclk>;
clock-names = "pclk", "gclk";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2s_default>;
};
......@@ -4,6 +4,7 @@ Required properties:
- compatible : "mediatek,mt8183_mt6358_ts3a227_max98357" for MAX98357A codec
"mediatek,mt8183_mt6358_ts3a227_max98357b" for MAX98357B codec
"mediatek,mt8183_mt6358_ts3a227_rt1015" for RT1015 codec
"mediatek,mt8183_mt6358_ts3a227_rt1015p" for RT1015P codec
- mediatek,platform: the phandle of MT8183 ASoC platform
Optional properties:
......
......@@ -17,9 +17,6 @@ maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: audio-graph-port.yaml#
properties:
$nodename:
pattern: "^dspk@[0-9a-f]*$"
......@@ -59,14 +56,18 @@ properties:
available instances on a Tegra SoC.
ports:
type: object
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
DSPK ACIF (Audio Client Interface) port connected to the
corresponding AHUB (Audio Hub) ACIF port.
port@1:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
DSPK DAP (Digital Audio Port) interface which can be connected
to external audio codec for playback.
......@@ -80,7 +81,7 @@ required:
- assigned-clock-parents
- sound-name-prefix
unevaluatedProperties: false
additionalProperties: false
examples:
- |
......
......@@ -17,9 +17,6 @@ maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: audio-graph-port.yaml#
properties:
$nodename:
pattern: "^admaif@[0-9a-f]*$"
......@@ -41,6 +38,7 @@ properties:
dma-names: true
ports:
$ref: /schemas/graph.yaml#/properties/ports
description: |
Contains list of ACIF (Audio CIF) port nodes for ADMAIF channels.
The number of port nodes depends on the number of ADMAIF channels
......@@ -48,6 +46,11 @@ properties:
in AHUB (Audio Hub). Each port is capable of data transfers in
both directions.
patternProperties:
'^port@[0-9]':
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
if:
properties:
compatible:
......@@ -92,7 +95,7 @@ required:
- dmas
- dma-names
unevaluatedProperties: false
additionalProperties: false
examples:
- |
......
......@@ -17,9 +17,6 @@ maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: audio-graph-port.yaml#
properties:
$nodename:
pattern: "^ahub@[0-9a-f]*$"
......@@ -60,12 +57,34 @@ properties:
ranges: true
ports:
$ref: /schemas/graph.yaml#/properties/ports
description: |
Contains list of ACIF (Audio CIF) port nodes for AHUB (Audio Hub).
These are connected to ACIF interfaces of AHUB clients. Thus the
number of port nodes depend on the number of clients that AHUB may
have depending on the SoC revision.
patternProperties:
'^port@[0-9]':
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
patternProperties:
'^i2s@[0-9a-f]+$':
type: object
'^dmic@[0-9a-f]+$':
type: object
$ref: nvidia,tegra210-dmic.yaml#
'^admaif@[0-9a-f]+$':
type: object
$ref: nvidia,tegra210-admaif.yaml#
'^dspk@[0-9a-f]+$':
type: object
$ref: nvidia,tegra186-dspk.yaml#
required:
- compatible
- reg
......@@ -77,7 +96,7 @@ required:
- "#size-cells"
- ranges
unevaluatedProperties: false
additionalProperties: false
examples:
- |
......
......@@ -16,9 +16,6 @@ maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: audio-graph-port.yaml#
properties:
$nodename:
pattern: "^dmic@[0-9a-f]*$"
......@@ -60,14 +57,18 @@ properties:
on the maximum available instances on a Tegra SoC.
ports:
type: object
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
DMIC ACIF (Audio Client Interface) port connected to the
corresponding AHUB (Audio Hub) ACIF port.
port@1:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
DMIC DAP (Digital Audio Port) interface which can be connected
to external audio codec for capture.
......@@ -80,7 +81,7 @@ required:
- assigned-clocks
- assigned-clock-parents
unevaluatedProperties: false
additionalProperties: false
examples:
- |
......
......@@ -16,9 +16,6 @@ maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: audio-graph-port.yaml#
properties:
$nodename:
pattern: "^i2s@[0-9a-f]*$"
......@@ -78,14 +75,18 @@ properties:
on the maximum available instances on a Tegra SoC.
ports:
type: object
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
I2S ACIF (Audio Client Interface) port connected to the
corresponding AHUB (Audio Hub) ACIF port.
port@1:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
I2S DAP (Digital Audio Port) interface which can be connected
to external audio codec for playback or capture.
......@@ -98,7 +99,7 @@ required:
- assigned-clocks
- assigned-clock-parents
unevaluatedProperties: false
additionalProperties: false
examples:
- |
......
......@@ -111,7 +111,9 @@ properties:
- pattern: '^dvc\.[0-1]$'
- pattern: '^clk_(a|b|c|i)$'
port: true
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
# use patternProperties to avoid naming "xxx,yyy" issue
patternProperties:
......@@ -257,7 +259,6 @@ required:
allOf:
- $ref: audio-graph.yaml#
- $ref: audio-graph-port.yaml#
- if:
properties:
compatible:
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/rt1019.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: RT1019 Mono Class-D Audio Amplifier
maintainers:
- jack.yu@realtek.com
properties:
compatible:
const: realtek,rt1019
reg:
maxItems: 1
description: I2C address of the device.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
rt1019: codec@28 {
compatible = "realtek,rt1019";
reg = <0x28>;
};
};
......@@ -44,7 +44,7 @@ Optional properties:
- realtek,dmic-delay-ms : Set the delay time (ms) for the requirement of
the particular DMIC.
- realtek,dmic-clk-driving-high : Set the high drving of the DMIC clock out.
- realtek,dmic-clk-driving-high : Set the high driving of the DMIC clock out.
Pins on the device (for linking into audio routes) for RT5682:
......
......@@ -46,11 +46,9 @@ properties:
patternProperties:
"^port@[0-9]$":
type: object
properties:
endpoint: true
required:
- endpoint
description: FIXME, Need to define what each port is.
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
additionalProperties: false
......
......@@ -40,11 +40,9 @@ properties:
patternProperties:
"^port@[0-9]$":
type: object
properties:
endpoint: true
required:
- endpoint
description: FIXME, Need to define what each port is.
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
additionalProperties: false
......
Texas Instruments - tlv320aic3x Codec module
The tlv320aic3x serial control bus communicates through I2C protocols
The tlv320aic3x serial control bus communicates through both I2C and SPI bus protocols
Required properties:
......@@ -63,7 +63,7 @@ CODEC input pins for other compatible codecs:
The pins can be used in referring sound node's audio-routing property.
Example:
I2C example:
#include <dt-bindings/gpio/gpio.h>
......@@ -78,3 +78,20 @@ tlv320aic3x: tlv320aic3x@1b {
DRVDD-supply = <&regulator>;
DVDD-supply = <&regulator>;
};
SPI example:
spi0: spi@f0000000 {
tlv320aic3x: codec@0 {
compatible = "ti,tlv320aic3x";
reg = <0>; /* CS number */
#sound-dai-cells = <0>;
spi-max-frequency = <1000000>;
AVDD-supply = <&regulator>;
IOVDD-supply = <&regulator>;
DRVDD-supply = <&regulator>;
DVDD-supply = <&regulator>;
ai3x-ocmv = <0>;
};
};
......@@ -19394,7 +19394,6 @@ F: Documentation/devicetree/bindings/sound/wlf,arizona.yaml
F: Documentation/hwmon/wm83??.rst
F: arch/arm/mach-s3c/mach-crag6410*
F: drivers/clk/clk-wm83*.c
F: drivers/extcon/extcon-arizona.c
F: drivers/gpio/gpio-*wm*.c
F: drivers/gpio/gpio-arizona.c
F: drivers/hwmon/wm83??-hwmon.c
......@@ -19418,7 +19417,7 @@ F: include/linux/mfd/wm8400*
F: include/linux/regulator/arizona*
F: include/linux/wm97xx.h
F: include/sound/wm????.h
F: sound/soc/codecs/arizona.?
F: sound/soc/codecs/arizona*
F: sound/soc/codecs/cs47l24*
F: sound/soc/codecs/wm*
......
......@@ -21,14 +21,6 @@ config EXTCON_ADC_JACK
help
Say Y here to enable extcon device driver based on ADC values.
config EXTCON_ARIZONA
tristate "Wolfson Arizona EXTCON support"
depends on MFD_ARIZONA && INPUT && SND_SOC
help
Say Y here to enable support for external accessory detection
with Wolfson Arizona devices. These are audio CODECs with
advanced audio accessory detection support.
config EXTCON_AXP288
tristate "X-Power AXP288 EXTCON support"
depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI
......
......@@ -6,7 +6,6 @@
obj-$(CONFIG_EXTCON) += extcon-core.o
extcon-core-objs += extcon.o devres.o
obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
obj-$(CONFIG_EXTCON_FSA9480) += extcon-fsa9480.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
......
......@@ -166,6 +166,7 @@ static int __init dmi_checksum(const u8 *buf, u8 len)
static const char *dmi_ident[DMI_STRING_MAX];
static LIST_HEAD(dmi_devices);
int dmi_available;
EXPORT_SYMBOL_GPL(dmi_available);
/*
* Save a DMI string
......
......@@ -881,11 +881,6 @@ static const char * const wm5102_supplies[] = {
static const struct mfd_cell wm5102_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
{
.name = "arizona-extcon",
.parent_supplies = wm5102_supplies,
.num_parent_supplies = 1, /* We only need MICVDD */
},
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
......@@ -898,11 +893,6 @@ static const struct mfd_cell wm5102_devs[] = {
static const struct mfd_cell wm5110_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
{
.name = "arizona-extcon",
.parent_supplies = wm5102_supplies,
.num_parent_supplies = 1, /* We only need MICVDD */
},
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
......@@ -939,11 +929,6 @@ static const char * const wm8997_supplies[] = {
static const struct mfd_cell wm8997_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
{
.name = "arizona-extcon",
.parent_supplies = wm8997_supplies,
.num_parent_supplies = 1, /* We only need MICVDD */
},
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
......@@ -956,11 +941,6 @@ static const struct mfd_cell wm8997_devs[] = {
static const struct mfd_cell wm8998_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-gpio" },
{
.name = "arizona-extcon",
.parent_supplies = wm5102_supplies,
.num_parent_supplies = 1, /* We only need MICVDD */
},
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{
......
......@@ -358,6 +358,30 @@ int reset_control_reset(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_reset);
/**
* reset_control_bulk_reset - reset the controlled devices in order
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* Issue a reset on all provided reset controls, in order.
*
* See also: reset_control_reset()
*/
int reset_control_bulk_reset(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int ret, i;
for (i = 0; i < num_rstcs; i++) {
ret = reset_control_reset(rstcs[i].rstc);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(reset_control_bulk_reset);
/**
* reset_control_rearm - allow shared reset line to be re-triggered"
* @rstc: reset controller
......@@ -461,6 +485,36 @@ int reset_control_assert(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_assert);
/**
* reset_control_bulk_assert - asserts the reset lines in order
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* Assert the reset lines for all provided reset controls, in order.
* If an assertion fails, already asserted resets are deasserted again.
*
* See also: reset_control_assert()
*/
int reset_control_bulk_assert(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int ret, i;
for (i = 0; i < num_rstcs; i++) {
ret = reset_control_assert(rstcs[i].rstc);
if (ret)
goto err;
}
return 0;
err:
while (i--)
reset_control_deassert(rstcs[i].rstc);
return ret;
}
EXPORT_SYMBOL_GPL(reset_control_bulk_assert);
/**
* reset_control_deassert - deasserts the reset line
* @rstc: reset controller
......@@ -511,6 +565,36 @@ int reset_control_deassert(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_deassert);
/**
* reset_control_bulk_deassert - deasserts the reset lines in reverse order
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* Deassert the reset lines for all provided reset controls, in reverse order.
* If a deassertion fails, already deasserted resets are asserted again.
*
* See also: reset_control_deassert()
*/
int reset_control_bulk_deassert(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int ret, i;
for (i = num_rstcs - 1; i >= 0; i--) {
ret = reset_control_deassert(rstcs[i].rstc);
if (ret)
goto err;
}
return 0;
err:
while (i < num_rstcs)
reset_control_assert(rstcs[i++].rstc);
return ret;
}
EXPORT_SYMBOL_GPL(reset_control_bulk_deassert);
/**
* reset_control_status - returns a negative errno if not supported, a
* positive value if the reset line is asserted, or zero if the reset
......@@ -588,6 +672,36 @@ int reset_control_acquire(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_acquire);
/**
* reset_control_bulk_acquire - acquires reset controls for exclusive use
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* This is used to explicitly acquire reset controls requested with
* reset_control_bulk_get_exclusive_release() for temporary exclusive use.
*
* See also: reset_control_acquire(), reset_control_bulk_release()
*/
int reset_control_bulk_acquire(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int ret, i;
for (i = 0; i < num_rstcs; i++) {
ret = reset_control_acquire(rstcs[i].rstc);
if (ret)
goto err;
}
return 0;
err:
while (i--)
reset_control_release(rstcs[i].rstc);
return ret;
}
EXPORT_SYMBOL_GPL(reset_control_bulk_acquire);
/**
* reset_control_release() - releases exclusive access to a reset control
* @rstc: reset control
......@@ -610,6 +724,26 @@ void reset_control_release(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_release);
/**
* reset_control_bulk_release() - releases exclusive access to reset controls
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*
* Releases exclusive access right to reset controls previously obtained by a
* call to reset_control_bulk_acquire().
*
* See also: reset_control_release(), reset_control_bulk_acquire()
*/
void reset_control_bulk_release(int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
int i;
for (i = 0; i < num_rstcs; i++)
reset_control_release(rstcs[i].rstc);
}
EXPORT_SYMBOL_GPL(reset_control_bulk_release);
static struct reset_control *__reset_control_get_internal(
struct reset_controller_dev *rcdev,
unsigned int index, bool shared, bool acquired)
......@@ -814,6 +948,32 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
}
EXPORT_SYMBOL_GPL(__reset_control_get);
int __reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
bool shared, bool optional, bool acquired)
{
int ret, i;
for (i = 0; i < num_rstcs; i++) {
rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0,
shared, optional, acquired);
if (IS_ERR(rstcs[i].rstc)) {
ret = PTR_ERR(rstcs[i].rstc);
goto err;
}
}
return 0;
err:
mutex_lock(&reset_list_mutex);
while (i--)
__reset_control_put_internal(rstcs[i].rstc);
mutex_unlock(&reset_list_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(__reset_control_bulk_get);
static void reset_control_array_put(struct reset_control_array *resets)
{
int i;
......@@ -845,6 +1005,23 @@ void reset_control_put(struct reset_control *rstc)
}
EXPORT_SYMBOL_GPL(reset_control_put);
/**
* reset_control_bulk_put - free the reset controllers
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset controls set
*/
void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
mutex_lock(&reset_list_mutex);
while (num_rstcs--) {
if (IS_ERR_OR_NULL(rstcs[num_rstcs].rstc))
continue;
__reset_control_put_internal(rstcs[num_rstcs].rstc);
}
mutex_unlock(&reset_list_mutex);
}
EXPORT_SYMBOL_GPL(reset_control_bulk_put);
static void devm_reset_control_release(struct device *dev, void *res)
{
reset_control_put(*(struct reset_control **)res);
......@@ -874,6 +1051,44 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
}
EXPORT_SYMBOL_GPL(__devm_reset_control_get);
struct reset_control_bulk_devres {
int num_rstcs;
struct reset_control_bulk_data *rstcs;
};
static void devm_reset_control_bulk_release(struct device *dev, void *res)
{
struct reset_control_bulk_devres *devres = res;
reset_control_bulk_put(devres->num_rstcs, devres->rstcs);
}
int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
bool shared, bool optional, bool acquired)
{
struct reset_control_bulk_devres *ptr;
int ret;
ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, shared, optional, acquired);
if (ret < 0) {
devres_free(ptr);
return ret;
}
ptr->num_rstcs = num_rstcs;
ptr->rstcs = rstcs;
devres_add(dev, ptr);
return 0;
}
EXPORT_SYMBOL_GPL(__devm_reset_control_bulk_get);
/**
* __device_reset - find reset controller associated with the device
* and perform reset
......
......@@ -1548,13 +1548,12 @@ static int spi_imx_slave_abort(struct spi_master *master)
static int spi_imx_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(spi_imx_dt_ids, &pdev->dev);
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
int ret, irq, spi_drctl;
const struct spi_imx_devtype_data *devtype_data = of_id->data;
const struct spi_imx_devtype_data *devtype_data =
of_device_get_match_data(&pdev->dev);
bool slave_mode;
u32 val;
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PLATFORM_DATA_ASOC_MX27VIS_H
#define __PLATFORM_DATA_ASOC_MX27VIS_H
struct snd_mx27vis_platform_data {
int amp_gain0_gpio;
int amp_gain1_gpio;
int amp_mutel_gpio;
int amp_muter_gpio;
};
#endif /* __PLATFORM_DATA_ASOC_MX27VIS_H */
......@@ -10,6 +10,21 @@ struct device;
struct device_node;
struct reset_control;
/**
* struct reset_control_bulk_data - Data used for bulk reset control operations.
*
* @id: reset control consumer ID
* @rstc: struct reset_control * to store the associated reset control
*
* The reset APIs provide a series of reset_control_bulk_*() API calls as
* a convenience to consumers which require multiple reset controls.
* This structure is used to manage data for these calls.
*/
struct reset_control_bulk_data {
const char *id;
struct reset_control *rstc;
};
#ifdef CONFIG_RESET_CONTROLLER
int reset_control_reset(struct reset_control *rstc);
......@@ -20,6 +35,12 @@ int reset_control_status(struct reset_control *rstc);
int reset_control_acquire(struct reset_control *rstc);
void reset_control_release(struct reset_control *rstc);
int reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs);
int reset_control_bulk_assert(int num_rstcs, struct reset_control_bulk_data *rstcs);
int reset_control_bulk_deassert(int num_rstcs, struct reset_control_bulk_data *rstcs);
int reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rstcs);
void reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs);
struct reset_control *__of_reset_control_get(struct device_node *node,
const char *id, int index, bool shared,
bool optional, bool acquired);
......@@ -27,10 +48,18 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
int index, bool shared,
bool optional, bool acquired);
void reset_control_put(struct reset_control *rstc);
int __reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
bool shared, bool optional, bool acquired);
void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs);
int __device_reset(struct device *dev, bool optional);
struct reset_control *__devm_reset_control_get(struct device *dev,
const char *id, int index, bool shared,
bool optional, bool acquired);
int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
bool shared, bool optional, bool acquired);
struct reset_control *devm_reset_control_array_get(struct device *dev,
bool shared, bool optional);
......@@ -96,6 +125,48 @@ static inline struct reset_control *__reset_control_get(
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
static inline int
reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
return 0;
}
static inline int
reset_control_bulk_assert(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
return 0;
}
static inline int
reset_control_bulk_deassert(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
return 0;
}
static inline int
reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
return 0;
}
static inline void
reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
}
static inline int
__reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
bool shared, bool optional, bool acquired)
{
return optional ? 0 : -EOPNOTSUPP;
}
static inline void
reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
}
static inline struct reset_control *__devm_reset_control_get(
struct device *dev, const char *id,
int index, bool shared, bool optional,
......@@ -104,6 +175,14 @@ static inline struct reset_control *__devm_reset_control_get(
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
static inline int
__devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
bool shared, bool optional, bool acquired)
{
return optional ? 0 : -EOPNOTSUPP;
}
static inline struct reset_control *
devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
{
......@@ -155,6 +234,23 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id)
return __reset_control_get(dev, id, 0, false, false, true);
}
/**
* reset_control_bulk_get_exclusive - Lookup and obtain exclusive references to
* multiple reset controllers.
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Fills the rstcs array with pointers to exclusive reset controls and
* returns 0, or an IS_ERR() condition containing errno.
*/
static inline int __must_check
reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true);
}
/**
* reset_control_get_exclusive_released - Lookup and obtain a temoprarily
* exclusive reference to a reset
......@@ -176,6 +272,48 @@ __must_check reset_control_get_exclusive_released(struct device *dev,
return __reset_control_get(dev, id, 0, false, false, false);
}
/**
* reset_control_bulk_get_exclusive_released - Lookup and obtain temporarily
* exclusive references to multiple reset
* controllers.
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Fills the rstcs array with pointers to exclusive reset controls and
* returns 0, or an IS_ERR() condition containing errno.
* reset-controls returned by this function must be acquired via
* reset_control_bulk_acquire() before they can be used and should be released
* via reset_control_bulk_release() afterwards.
*/
static inline int __must_check
reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false);
}
/**
* reset_control_bulk_get_optional_exclusive_released - Lookup and obtain optional
* temporarily exclusive references to multiple
* reset controllers.
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Optional variant of reset_control_bulk_get_exclusive_released(). If the
* requested reset is not specified in the device tree, this function returns 0
* instead of an error and missing rtsc is set to NULL.
*
* See reset_control_bulk_get_exclusive_released() for more information.
*/
static inline int __must_check
reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false);
}
/**
* reset_control_get_shared - Lookup and obtain a shared reference to a
* reset controller.
......@@ -204,6 +342,23 @@ static inline struct reset_control *reset_control_get_shared(
return __reset_control_get(dev, id, 0, true, false, false);
}
/**
* reset_control_bulk_get_shared - Lookup and obtain shared references to
* multiple reset controllers.
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Fills the rstcs array with pointers to shared reset controls and
* returns 0, or an IS_ERR() condition containing errno.
*/
static inline int __must_check
reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false);
}
/**
* reset_control_get_optional_exclusive - optional reset_control_get_exclusive()
* @dev: device to be reset by the controller
......@@ -221,6 +376,26 @@ static inline struct reset_control *reset_control_get_optional_exclusive(
return __reset_control_get(dev, id, 0, false, true, true);
}
/**
* reset_control_bulk_get_optional_exclusive - optional
* reset_control_bulk_get_exclusive()
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Optional variant of reset_control_bulk_get_exclusive(). If any of the
* requested resets are not specified in the device tree, this function sets
* them to NULL instead of returning an error.
*
* See reset_control_bulk_get_exclusive() for more information.
*/
static inline int __must_check
reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true);
}
/**
* reset_control_get_optional_shared - optional reset_control_get_shared()
* @dev: device to be reset by the controller
......@@ -238,6 +413,26 @@ static inline struct reset_control *reset_control_get_optional_shared(
return __reset_control_get(dev, id, 0, true, true, false);
}
/**
* reset_control_bulk_get_optional_shared - optional
* reset_control_bulk_get_shared()
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Optional variant of reset_control_bulk_get_shared(). If the requested resets
* are not specified in the device tree, this function sets them to NULL
* instead of returning an error.
*
* See reset_control_bulk_get_shared() for more information.
*/
static inline int __must_check
reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false);
}
/**
* of_reset_control_get_exclusive - Lookup and obtain an exclusive reference
* to a reset controller.
......@@ -343,6 +538,26 @@ __must_check devm_reset_control_get_exclusive(struct device *dev,
return __devm_reset_control_get(dev, id, 0, false, false, true);
}
/**
* devm_reset_control_bulk_get_exclusive - resource managed
* reset_control_bulk_get_exclusive()
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Managed reset_control_bulk_get_exclusive(). For reset controllers returned
* from this function, reset_control_put() is called automatically on driver
* detach.
*
* See reset_control_bulk_get_exclusive() for more information.
*/
static inline int __must_check
devm_reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true);
}
/**
* devm_reset_control_get_exclusive_released - resource managed
* reset_control_get_exclusive_released()
......@@ -362,6 +577,26 @@ __must_check devm_reset_control_get_exclusive_released(struct device *dev,
return __devm_reset_control_get(dev, id, 0, false, false, false);
}
/**
* devm_reset_control_bulk_get_exclusive_released - resource managed
* reset_control_bulk_get_exclusive_released()
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Managed reset_control_bulk_get_exclusive_released(). For reset controllers
* returned from this function, reset_control_put() is called automatically on
* driver detach.
*
* See reset_control_bulk_get_exclusive_released() for more information.
*/
static inline int __must_check
devm_reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false);
}
/**
* devm_reset_control_get_optional_exclusive_released - resource managed
* reset_control_get_optional_exclusive_released()
......@@ -381,6 +616,26 @@ __must_check devm_reset_control_get_optional_exclusive_released(struct device *d
return __devm_reset_control_get(dev, id, 0, false, true, false);
}
/**
* devm_reset_control_bulk_get_optional_exclusive_released - resource managed
* reset_control_bulk_optional_get_exclusive_released()
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Managed reset_control_bulk_optional_get_exclusive_released(). For reset
* controllers returned from this function, reset_control_put() is called
* automatically on driver detach.
*
* See reset_control_bulk_optional_get_exclusive_released() for more information.
*/
static inline int __must_check
devm_reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false);
}
/**
* devm_reset_control_get_shared - resource managed reset_control_get_shared()
* @dev: device to be reset by the controller
......@@ -396,6 +651,26 @@ static inline struct reset_control *devm_reset_control_get_shared(
return __devm_reset_control_get(dev, id, 0, true, false, false);
}
/**
* devm_reset_control_bulk_get_shared - resource managed
* reset_control_bulk_get_shared()
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Managed reset_control_bulk_get_shared(). For reset controllers returned
* from this function, reset_control_put() is called automatically on driver
* detach.
*
* See reset_control_bulk_get_shared() for more information.
*/
static inline int __must_check
devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false);
}
/**
* devm_reset_control_get_optional_exclusive - resource managed
* reset_control_get_optional_exclusive()
......@@ -414,6 +689,26 @@ static inline struct reset_control *devm_reset_control_get_optional_exclusive(
return __devm_reset_control_get(dev, id, 0, false, true, true);
}
/**
* devm_reset_control_bulk_get_optional_exclusive - resource managed
* reset_control_bulk_get_optional_exclusive()
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Managed reset_control_bulk_get_optional_exclusive(). For reset controllers
* returned from this function, reset_control_put() is called automatically on
* driver detach.
*
* See reset_control_bulk_get_optional_exclusive() for more information.
*/
static inline int __must_check
devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, true);
}
/**
* devm_reset_control_get_optional_shared - resource managed
* reset_control_get_optional_shared()
......@@ -432,6 +727,26 @@ static inline struct reset_control *devm_reset_control_get_optional_shared(
return __devm_reset_control_get(dev, id, 0, true, true, false);
}
/**
* devm_reset_control_bulk_get_optional_shared - resource managed
* reset_control_bulk_get_optional_shared()
* @dev: device to be reset by the controller
* @num_rstcs: number of entries in rstcs array
* @rstcs: array of struct reset_control_bulk_data with reset line names set
*
* Managed reset_control_bulk_get_optional_shared(). For reset controllers
* returned from this function, reset_control_put() is called automatically on
* driver detach.
*
* See reset_control_bulk_get_optional_shared() for more information.
*/
static inline int __must_check
devm_reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false);
}
/**
* devm_reset_control_get_exclusive_by_index - resource managed
* reset_control_get_exclusive()
......
......@@ -24,7 +24,7 @@ typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
/* internal flag for skipping validations */
#ifdef CONFIG_SND_CTL_VALIDATION
#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK (1 << 27)
#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK (1 << 24)
#define snd_ctl_skip_validation(info) \
((info)->access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK)
#else
......@@ -32,6 +32,12 @@ typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
#define snd_ctl_skip_validation(info) true
#endif
/* kernel only - LED bits */
#define SNDRV_CTL_ELEM_ACCESS_LED_SHIFT 25
#define SNDRV_CTL_ELEM_ACCESS_LED_MASK (7<<25) /* kernel three bits - LED group */
#define SNDRV_CTL_ELEM_ACCESS_SPK_LED (1<<25) /* kernel speaker (output) LED flag */
#define SNDRV_CTL_ELEM_ACCESS_MIC_LED (2<<25) /* kernel microphone (input) LED flag */
enum {
SNDRV_CTL_TLV_OP_READ = 0,
SNDRV_CTL_TLV_OP_WRITE = 1,
......@@ -108,6 +114,14 @@ struct snd_ctl_file {
struct list_head events; /* waiting events for read */
};
struct snd_ctl_layer_ops {
struct snd_ctl_layer_ops *next;
const char *module_name;
void (*lregister)(struct snd_card *card);
void (*ldisconnect)(struct snd_card *card);
void (*lnotify)(struct snd_card *card, unsigned int mask, struct snd_kcontrol *kctl, unsigned int ioff);
};
#define snd_ctl_file(n) list_entry(n, struct snd_ctl_file, list)
typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card,
......@@ -115,6 +129,7 @@ typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card,
unsigned int cmd, unsigned long arg);
void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id);
void snd_ctl_notify_one(struct snd_card * card, unsigned int mask, struct snd_kcontrol * kctl, unsigned int ioff);
struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data);
void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
......@@ -123,8 +138,7 @@ int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol);
int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace);
int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
int active);
int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active);
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid);
struct snd_kcontrol *snd_ctl_find_id(struct snd_card * card, struct snd_ctl_elem_id *id);
......@@ -140,6 +154,10 @@ int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
#define snd_ctl_unregister_ioctl_compat(fcn)
#endif
int snd_ctl_request_layer(const char *module_name);
void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops);
void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops);
int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type);
static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
......@@ -253,6 +271,17 @@ int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl,
void *arg),
void *arg);
/*
* Control LED trigger layer
*/
#define SND_CTL_LAYER_MODULE_LED "snd-ctl-led"
#if IS_MODULE(CONFIG_SND_CTL_LED)
static inline int snd_ctl_led_request(void) { return snd_ctl_request_layer(SND_CTL_LAYER_MODULE_LED); }
#else
static inline int snd_ctl_led_request(void) { return 0; }
#endif
/*
* Helper functions for jack-detection controls
*/
......
......@@ -9,10 +9,6 @@
#include <sound/simple_card_utils.h>
int audio_graph_card_probe(struct snd_soc_card *card);
int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev);
int audio_graph_remove(struct platform_device *pdev);
#endif /* __GRAPH_CARD_H */
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/sound/rt5645.h -- Platform data for RT5645
*
* Copyright 2013 Realtek Microelectronics
*/
#ifndef __LINUX_SND_RT5645_H
#define __LINUX_SND_RT5645_H
struct rt5645_platform_data {
/* IN2 can optionally be differential */
bool in2_diff;
unsigned int dmic1_data_pin;
/* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */
unsigned int dmic2_data_pin;
/* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
unsigned int jd_mode;
/* Use level triggered irq */
bool level_trigger_irq;
/* Invert JD1_1 status polarity */
bool inv_jd1_1;
/* Invert HP detect status polarity */
bool inv_hp_pol;
/* Value to asign to snd_soc_card.long_name */
const char *long_name;
};
#endif
......@@ -38,22 +38,31 @@ struct asoc_simple_jack {
struct snd_soc_jack_gpio gpio;
};
struct prop_nums {
int cpus;
int codecs;
int platforms;
};
struct asoc_simple_priv {
struct snd_soc_card snd_card;
struct simple_dai_props {
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component cpus; /* single cpu */
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platforms;
struct snd_soc_dai_link_component *cpus;
struct snd_soc_dai_link_component *codecs;
struct snd_soc_dai_link_component *platforms;
struct asoc_simple_data adata;
struct snd_soc_codec_conf *codec_conf;
struct prop_nums num;
unsigned int mclk_fs;
} *dai_props;
struct asoc_simple_jack hp_jack;
struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct snd_soc_dai_link_component *dlcs;
struct snd_soc_dai_link_component dummy;
struct snd_soc_codec_conf *codec_conf;
struct gpio_desc *pa_gpio;
const struct snd_soc_ops *ops;
......@@ -65,11 +74,53 @@ struct asoc_simple_priv {
#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
#define simple_props_to_dlc_cpu(props, i) ((props)->cpus + i)
#define simple_props_to_dlc_codec(props, i) ((props)->codecs + i)
#define simple_props_to_dlc_platform(props, i) ((props)->platforms + i)
#define simple_props_to_dai_cpu(props, i) ((props)->cpu_dai + i)
#define simple_props_to_dai_codec(props, i) ((props)->codec_dai + i)
#define simple_props_to_codec_conf(props, i) ((props)->codec_conf + i)
#define for_each_prop_dlc_cpus(props, i, cpu) \
for ((i) = 0; \
((i) < (props)->num.cpus) && \
((cpu) = simple_props_to_dlc_cpu(props, i)); \
(i)++)
#define for_each_prop_dlc_codecs(props, i, codec) \
for ((i) = 0; \
((i) < (props)->num.codecs) && \
((codec) = simple_props_to_dlc_codec(props, i)); \
(i)++)
#define for_each_prop_dlc_platforms(props, i, platform) \
for ((i) = 0; \
((i) < (props)->num.platforms) && \
((platform) = simple_props_to_dlc_platform(props, i)); \
(i)++)
#define for_each_prop_codec_conf(props, i, conf) \
for ((i) = 0; \
((i) < (props)->num.codecs) && \
(props)->codec_conf && \
((conf) = simple_props_to_codec_conf(props, i)); \
(i)++)
#define for_each_prop_dai_cpu(props, i, cpu) \
for ((i) = 0; \
((i) < (props)->num.cpus) && \
((cpu) = simple_props_to_dai_cpu(props, i)); \
(i)++)
#define for_each_prop_dai_codec(props, i, codec) \
for ((i) = 0; \
((i) < (props)->num.codecs) && \
((codec) = simple_props_to_dai_codec(props, i)); \
(i)++)
#define SNDRV_MAX_LINKS 128
struct link_info {
int dais; /* number of dai */
int link; /* number of link */
int conf; /* number of codec_conf */
int cpu; /* turn for CPU / Codec */
struct prop_nums num[SNDRV_MAX_LINKS];
};
int asoc_simple_parse_daifmt(struct device *dev,
......@@ -84,10 +135,6 @@ int asoc_simple_set_dailink_name(struct device *dev,
int asoc_simple_parse_card_name(struct snd_soc_card *card,
char *prefix);
#define asoc_simple_parse_clk_cpu(dev, node, dai_link, simple_dai) \
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->cpus)
#define asoc_simple_parse_clk_codec(dev, node, dai_link, simple_dai) \
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->codecs)
int asoc_simple_parse_clk(struct device *dev,
struct device_node *node,
struct asoc_simple_dai *simple_dai,
......@@ -100,29 +147,22 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd);
int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params);
#define asoc_simple_parse_cpu(node, dai_link, is_single_link) \
asoc_simple_parse_dai(node, dai_link->cpus, is_single_link)
#define asoc_simple_parse_codec(node, dai_link) \
asoc_simple_parse_dai(node, dai_link->codecs, NULL)
#define asoc_simple_parse_platform(node, dai_link) \
asoc_simple_parse_dai(node, dai_link->platforms, NULL)
#define asoc_simple_parse_tdm(np, dai) \
snd_soc_of_parse_tdm_slot(np, &(dai)->tx_slot_mask, \
&(dai)->rx_slot_mask, \
&(dai)->slots, \
&(dai)->slot_width);
void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link);
void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
int is_single_links);
void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
struct snd_soc_dai_link_component *cpus);
void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
int is_single_links);
int asoc_simple_clean_reference(struct snd_soc_card *card);
void asoc_simple_convert_fixup(struct asoc_simple_data *data,
struct snd_pcm_hw_params *params);
void asoc_simple_parse_convert(struct device *dev,
struct device_node *np, char *prefix,
void asoc_simple_parse_convert(struct device_node *np, char *prefix,
struct asoc_simple_data *data);
int asoc_simple_parse_routing(struct snd_soc_card *card,
......@@ -137,6 +177,9 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
int is_hp, char *prefix, char *pin);
int asoc_simple_init_priv(struct asoc_simple_priv *priv,
struct link_info *li);
int asoc_simple_remove(struct platform_device *pdev);
int asoc_graph_card_probe(struct snd_soc_card *card);
#ifdef DEBUG
static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
......@@ -152,12 +195,6 @@ static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
if (dai->name)
dev_dbg(dev, "%s dai name = %s\n",
name, dai->name);
if (dai->sysclk)
dev_dbg(dev, "%s sysclk = %d\n",
name, dai->sysclk);
dev_dbg(dev, "%s direction = %s\n",
name, dai->clk_direction ? "OUT" : "IN");
if (dai->slots)
dev_dbg(dev, "%s slots = %d\n", name, dai->slots);
......@@ -169,6 +206,12 @@ static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
dev_dbg(dev, "%s rx slot mask = %d\n", name, dai->rx_slot_mask);
if (dai->clk)
dev_dbg(dev, "%s clk %luHz\n", name, clk_get_rate(dai->clk));
if (dai->sysclk)
dev_dbg(dev, "%s sysclk = %dHz\n",
name, dai->sysclk);
if (dai->clk || dai->sysclk)
dev_dbg(dev, "%s direction = %s\n",
name, dai->clk_direction ? "OUT" : "IN");
}
static inline void asoc_simple_debug_info(struct asoc_simple_priv *priv)
......@@ -184,29 +227,32 @@ static inline void asoc_simple_debug_info(struct asoc_simple_priv *priv)
for (i = 0; i < card->num_links; i++) {
struct simple_dai_props *props = simple_priv_to_props(priv, i);
struct snd_soc_dai_link *link = simple_priv_to_link(priv, i);
struct asoc_simple_dai *dai;
struct snd_soc_codec_conf *cnf;
int j;
dev_dbg(dev, "DAI%d\n", i);
asoc_simple_debug_dai(priv, "cpu", props->cpu_dai);
asoc_simple_debug_dai(priv, "codec", props->codec_dai);
dev_dbg(dev, "cpu num = %d\n", link->num_cpus);
for_each_prop_dai_cpu(props, j, dai)
asoc_simple_debug_dai(priv, "cpu", dai);
dev_dbg(dev, "codec num = %d\n", link->num_codecs);
for_each_prop_dai_codec(props, j, dai)
asoc_simple_debug_dai(priv, "codec", dai);
if (link->name)
dev_dbg(dev, "dai name = %s\n", link->name);
dev_dbg(dev, "dai format = %04x\n", link->dai_fmt);
if (link->dai_fmt)
dev_dbg(dev, "dai format = %04x\n", link->dai_fmt);
if (props->adata.convert_rate)
dev_dbg(dev, "convert_rate = %d\n",
props->adata.convert_rate);
dev_dbg(dev, "convert_rate = %d\n", props->adata.convert_rate);
if (props->adata.convert_channels)
dev_dbg(dev, "convert_channels = %d\n",
props->adata.convert_channels);
if (props->codec_conf && props->codec_conf->name_prefix)
dev_dbg(dev, "name prefix = %s\n",
props->codec_conf->name_prefix);
dev_dbg(dev, "convert_channels = %d\n", props->adata.convert_channels);
for_each_prop_codec_conf(props, j, cnf)
if (cnf->name_prefix)
dev_dbg(dev, "name prefix = %s\n", cnf->name_prefix);
if (props->mclk_fs)
dev_dbg(dev, "mclk-fs = %d\n",
props->mclk_fs);
dev_dbg(dev, "mclk-fs = %d\n", props->mclk_fs);
}
}
#else
......
......@@ -63,6 +63,8 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
* @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver
* @link_mask: links enabled on the board
* @links: array of link _ADR descriptors, null terminated
* @num_dai_drivers: number of elements in @dai_drivers
* @dai_drivers: pointer to dai_drivers, used e.g. in nocodec mode
*/
struct snd_soc_acpi_mach_params {
u32 acpi_ipc_irq_index;
......@@ -72,6 +74,8 @@ struct snd_soc_acpi_mach_params {
bool common_hdmi_codec_drv;
u32 link_mask;
const struct snd_soc_acpi_link_adr *links;
u32 num_dai_drivers;
struct snd_soc_dai_driver *dai_drivers;
};
/**
......
......@@ -101,7 +101,7 @@ struct snd_soc_component_driver {
/* DT */
int (*of_xlate_dai_name)(struct snd_soc_component *component,
struct of_phandle_args *args,
const struct of_phandle_args *args,
const char **dai_name);
int (*of_xlate_dai_id)(struct snd_soc_component *comment,
struct device_node *endpoint);
......@@ -146,6 +146,8 @@ struct snd_soc_component_driver {
int (*mmap)(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct vm_area_struct *vma);
int (*ack)(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
const struct snd_compress_ops *compress_ops;
......@@ -336,6 +338,7 @@ static inline int snd_soc_component_cache_sync(
void snd_soc_component_set_aux(struct snd_soc_component *component,
struct snd_soc_aux_dev *aux);
int snd_soc_component_init(struct snd_soc_component *component);
int snd_soc_component_is_dummy(struct snd_soc_component *component);
/* component IO */
unsigned int snd_soc_component_read(struct snd_soc_component *component,
......@@ -450,7 +453,7 @@ void snd_soc_component_remove(struct snd_soc_component *component);
int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component,
struct device_node *ep);
int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component,
struct of_phandle_args *args,
const struct of_phandle_args *args,
const char **dai_name);
int snd_soc_component_compr_open(struct snd_compr_stream *cstream);
void snd_soc_component_compr_free(struct snd_compr_stream *cstream,
......@@ -498,5 +501,6 @@ int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
void *stream);
void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd,
void *stream, int rollback);
int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream);
#endif /* __SOC_COMPONENT_H */
......@@ -149,14 +149,20 @@ void dpcm_path_put(struct snd_soc_dapm_widget_list **list);
int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list, int new);
int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream);
int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream);
void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
int do_hw_free, struct snd_soc_dpcm *last);
void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream);
void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream);
int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream);
void dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream);
int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int tream);
int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd);
int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream);
int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
int event);
#define dpcm_be_dai_startup_rollback(fe, stream, last) \
dpcm_be_dai_stop(fe, stream, 0, last)
#define dpcm_be_dai_startup_unwind(fe, stream) dpcm_be_dai_stop(fe, stream, 0, NULL)
#define dpcm_be_dai_shutdown(fe, stream) dpcm_be_dai_stop(fe, stream, 1, NULL)
#endif
......@@ -716,20 +716,38 @@ struct snd_soc_dai_link {
struct snd_soc_dobj dobj; /* For topology */
#endif
};
static inline struct snd_soc_dai_link_component*
asoc_link_to_cpu(struct snd_soc_dai_link *link, int n) {
return &(link)->cpus[n];
}
static inline struct snd_soc_dai_link_component*
asoc_link_to_codec(struct snd_soc_dai_link *link, int n) {
return &(link)->codecs[n];
}
static inline struct snd_soc_dai_link_component*
asoc_link_to_platform(struct snd_soc_dai_link *link, int n) {
return &(link)->platforms[n];
}
#define for_each_link_codecs(link, i, codec) \
for ((i) = 0; \
((i) < link->num_codecs) && ((codec) = &link->codecs[i]); \
((i) < link->num_codecs) && \
((codec) = asoc_link_to_codec(link, i)); \
(i)++)
#define for_each_link_platforms(link, i, platform) \
for ((i) = 0; \
((i) < link->num_platforms) && \
((platform) = &link->platforms[i]); \
((platform) = asoc_link_to_platform(link, i)); \
(i)++)
#define for_each_link_cpus(link, i, cpu) \
for ((i) = 0; \
((i) < link->num_cpus) && ((cpu) = &link->cpus[i]); \
((i) < link->num_cpus) && \
((cpu) = asoc_link_to_cpu(link, i)); \
(i)++)
/*
......@@ -1219,7 +1237,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
struct device_node **bitclkmaster,
struct device_node **framemaster);
int snd_soc_get_dai_id(struct device_node *ep);
int snd_soc_get_dai_name(struct of_phandle_args *args,
int snd_soc_get_dai_name(const struct of_phandle_args *args,
const char **dai_name);
int snd_soc_of_get_dai_name(struct device_node *of_node,
const char **dai_name);
......@@ -1262,13 +1280,17 @@ int snd_soc_fixup_dai_links_platform_name(struct snd_soc_card *card,
/* set platform name for each dailink */
for_each_card_prelinks(card, i, dai_link) {
name = devm_kstrdup(card->dev, platform_name, GFP_KERNEL);
if (!name)
return -ENOMEM;
/* only single platform is supported for now */
if (dai_link->num_platforms != 1)
return -EINVAL;
if (!dai_link->platforms)
return -EINVAL;
name = devm_kstrdup(card->dev, platform_name, GFP_KERNEL);
if (!name)
return -ENOMEM;
/* only single platform is supported for now */
dai_link->platforms->name = name;
}
......
......@@ -100,8 +100,6 @@ struct sof_dev_desc {
const struct snd_sof_dsp_ops *ops;
};
int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops,
int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params));
int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd);
#endif
......@@ -203,4 +203,10 @@ config SND_DMA_SGBUF
def_bool y
depends on X86
config SND_CTL_LED
tristate
select NEW_LEDS if SND_CTL_LED
select LEDS_TRIGGERS if SND_CTL_LED
select LEDS_TRIGGER_AUDIO if SND_CTL_LED
source "sound/core/seq/Kconfig"
......@@ -27,6 +27,7 @@ CFLAGS_pcm_native.o := -I$(src)
snd-pcm-dmaengine-objs := pcm_dmaengine.o
snd-ctl-led-objs := control_led.o
snd-rawmidi-objs := rawmidi.o
snd-timer-objs := timer.o
snd-hrtimer-objs := hrtimer.o
......@@ -37,6 +38,7 @@ snd-seq-device-objs := seq_device.o
snd-compress-objs := compress_offload.o
obj-$(CONFIG_SND) += snd.o
obj-$(CONFIG_SND_CTL_LED) += snd-ctl-led.o
obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
obj-$(CONFIG_SND_TIMER) += snd-timer.o
obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o
......
......@@ -28,10 +28,12 @@ struct snd_kctl_ioctl {
};
static DECLARE_RWSEM(snd_ioctl_rwsem);
static DECLARE_RWSEM(snd_ctl_layer_rwsem);
static LIST_HEAD(snd_control_ioctls);
#ifdef CONFIG_COMPAT
static LIST_HEAD(snd_control_compat_ioctls);
#endif
static struct snd_ctl_layer_ops *snd_ctl_layer;
static int snd_ctl_open(struct inode *inode, struct file *file)
{
......@@ -181,6 +183,32 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
}
EXPORT_SYMBOL(snd_ctl_notify);
/**
* snd_ctl_notify_one - Send notification to user-space for a control change
* @card: the card to send notification
* @mask: the event mask, SNDRV_CTL_EVENT_*
* @kctl: the pointer with the control instance
* @ioff: the additional offset to the control index
*
* This function calls snd_ctl_notify() and does additional jobs
* like LED state changes.
*/
void snd_ctl_notify_one(struct snd_card *card, unsigned int mask,
struct snd_kcontrol *kctl, unsigned int ioff)
{
struct snd_ctl_elem_id id = kctl->id;
struct snd_ctl_layer_ops *lops;
id.index += ioff;
id.numid += ioff;
snd_ctl_notify(card, mask, &id);
down_read(&snd_ctl_layer_rwsem);
for (lops = snd_ctl_layer; lops; lops = lops->next)
lops->lnotify(card, mask, kctl, ioff);
up_read(&snd_ctl_layer_rwsem);
}
EXPORT_SYMBOL(snd_ctl_notify_one);
/**
* snd_ctl_new - create a new control instance with some elements
* @kctl: the pointer to store new control instance
......@@ -250,6 +278,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK |
SNDRV_CTL_ELEM_ACCESS_LED_MASK |
SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK);
err = snd_ctl_new(&kctl, count, access, NULL);
......@@ -342,7 +371,6 @@ static int __snd_ctl_add_replace(struct snd_card *card,
{
struct snd_ctl_elem_id id;
unsigned int idx;
unsigned int count;
struct snd_kcontrol *old;
int err;
......@@ -376,10 +404,8 @@ static int __snd_ctl_add_replace(struct snd_card *card,
kcontrol->id.numid = card->last_numid + 1;
card->last_numid += kcontrol->count;
id = kcontrol->id;
count = kcontrol->count;
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
for (idx = 0; idx < kcontrol->count; idx++)
snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_ADD, kcontrol, idx);
return 0;
}
......@@ -462,16 +488,14 @@ EXPORT_SYMBOL(snd_ctl_replace);
*/
int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
{
struct snd_ctl_elem_id id;
unsigned int idx;
if (snd_BUG_ON(!card || !kcontrol))
return -EINVAL;
list_del(&kcontrol->list);
card->controls_count -= kcontrol->count;
id = kcontrol->id;
for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id);
for (idx = 0; idx < kcontrol->count; idx++)
snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx);
snd_ctl_free_one(kcontrol);
return 0;
}
......@@ -584,11 +608,13 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
}
snd_ctl_build_ioff(id, kctl, index_offset);
ret = 1;
downgrade_write(&card->controls_rwsem);
snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, index_offset);
up_read(&card->controls_rwsem);
return 1;
unlock:
up_write(&card->controls_rwsem);
if (ret > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, id);
return ret;
}
EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
......@@ -1022,7 +1048,8 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
if (result < 0)
return result;
/* drop internal access flags */
info.access &= ~SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK;
info.access &= ~(SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK|
SNDRV_CTL_ELEM_ACCESS_LED_MASK);
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
return result;
......@@ -1110,25 +1137,34 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
unsigned int index_offset;
int result;
down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id);
if (kctl == NULL)
if (kctl == NULL) {
up_write(&card->controls_rwsem);
return -ENOENT;
}
index_offset = snd_ctl_get_ioff(kctl, &control->id);
vd = &kctl->vd[index_offset];
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || kctl->put == NULL ||
(file && vd->owner && vd->owner != file)) {
up_write(&card->controls_rwsem);
return -EPERM;
}
snd_ctl_build_ioff(&control->id, kctl, index_offset);
result = kctl->put(kctl, control);
if (result < 0)
if (result < 0) {
up_write(&card->controls_rwsem);
return result;
}
if (result > 0) {
struct snd_ctl_elem_id id = control->id;
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
downgrade_write(&card->controls_rwsem);
snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, index_offset);
up_read(&card->controls_rwsem);
} else {
up_write(&card->controls_rwsem);
}
return 0;
......@@ -1150,9 +1186,7 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
if (result < 0)
goto error;
down_write(&card->controls_rwsem);
result = snd_ctl_elem_write(card, file, control);
up_write(&card->controls_rwsem);
if (result < 0)
goto error;
......@@ -1301,7 +1335,6 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
{
struct user_element *ue = kctl->private_data;
unsigned int *container;
struct snd_ctl_elem_id id;
unsigned int mask = 0;
int i;
int change;
......@@ -1333,10 +1366,8 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
ue->tlv_data_size = size;
mask |= SNDRV_CTL_EVENT_MASK_TLV;
for (i = 0; i < kctl->count; ++i) {
snd_ctl_build_ioff(&id, kctl, i);
snd_ctl_notify(ue->card, mask, &id);
}
for (i = 0; i < kctl->count; ++i)
snd_ctl_notify_one(ue->card, mask, kctl, i);
return change;
}
......@@ -1975,6 +2006,86 @@ EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
#define snd_ctl_ioctl_compat NULL
#endif
/*
* control layers (audio LED etc.)
*/
/**
* snd_ctl_request_layer - request to use the layer
* @module_name: Name of the kernel module (NULL == build-in)
*
* Return an error code when the module cannot be loaded.
*/
int snd_ctl_request_layer(const char *module_name)
{
struct snd_ctl_layer_ops *lops;
if (module_name == NULL)
return 0;
down_read(&snd_ctl_layer_rwsem);
for (lops = snd_ctl_layer; lops; lops = lops->next)
if (strcmp(lops->module_name, module_name) == 0)
break;
up_read(&snd_ctl_layer_rwsem);
if (lops)
return 0;
return request_module(module_name);
}
EXPORT_SYMBOL_GPL(snd_ctl_request_layer);
/**
* snd_ctl_register_layer - register new control layer
* @lops: operation structure
*
* The new layer can track all control elements and do additional
* operations on top (like audio LED handling).
*/
void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
{
struct snd_card *card;
int card_number;
down_write(&snd_ctl_layer_rwsem);
lops->next = snd_ctl_layer;
snd_ctl_layer = lops;
up_write(&snd_ctl_layer_rwsem);
for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
card = snd_card_ref(card_number);
if (card) {
down_read(&card->controls_rwsem);
lops->lregister(card);
up_read(&card->controls_rwsem);
snd_card_unref(card);
}
}
}
EXPORT_SYMBOL_GPL(snd_ctl_register_layer);
/**
* snd_ctl_disconnect_layer - disconnect control layer
* @lops: operation structure
*
* It is expected that the information about tracked cards
* is freed before this call (the disconnect callback is
* not called here).
*/
void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
{
struct snd_ctl_layer_ops *lops2, *prev_lops2;
down_write(&snd_ctl_layer_rwsem);
for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next)
if (lops2 == lops) {
if (!prev_lops2)
snd_ctl_layer = lops->next;
else
prev_lops2->next = lops->next;
break;
}
up_write(&snd_ctl_layer_rwsem);
}
EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer);
/*
* INIT PART
*/
......@@ -1998,9 +2109,20 @@ static const struct file_operations snd_ctl_f_ops =
static int snd_ctl_dev_register(struct snd_device *device)
{
struct snd_card *card = device->device_data;
struct snd_ctl_layer_ops *lops;
int err;
return snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
&snd_ctl_f_ops, card, &card->ctl_dev);
err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
&snd_ctl_f_ops, card, &card->ctl_dev);
if (err < 0)
return err;
down_read(&card->controls_rwsem);
down_read(&snd_ctl_layer_rwsem);
for (lops = snd_ctl_layer; lops; lops = lops->next)
lops->lregister(card);
up_read(&snd_ctl_layer_rwsem);
up_read(&card->controls_rwsem);
return 0;
}
/*
......@@ -2010,6 +2132,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
{
struct snd_card *card = device->device_data;
struct snd_ctl_file *ctl;
struct snd_ctl_layer_ops *lops;
unsigned long flags;
read_lock_irqsave(&card->ctl_files_rwlock, flags);
......@@ -2019,6 +2142,13 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
}
read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
down_read(&card->controls_rwsem);
down_read(&snd_ctl_layer_rwsem);
for (lops = snd_ctl_layer; lops; lops = lops->next)
lops->ldisconnect(card);
up_read(&snd_ctl_layer_rwsem);
up_read(&card->controls_rwsem);
return snd_unregister_device(&card->ctl_dev);
}
......
此差异已折叠。
......@@ -221,10 +221,8 @@ comment "Set to Y if you want auto-loading the codec driver"
config SND_HDA_GENERIC
tristate "Enable generic HD-audio codec parser"
select NEW_LEDS if SND_HDA_GENERIC_LEDS
select SND_CTL_LED if SND_HDA_GENERIC_LEDS
select LEDS_CLASS if SND_HDA_GENERIC_LEDS
select LEDS_TRIGGERS if SND_HDA_GENERIC_LEDS
select LEDS_TRIGGER_AUDIO if SND_HDA_GENERIC_LEDS
help
Say Y or M here to enable the generic HD-audio codec parser
in snd-hda-intel driver.
......
......@@ -1952,7 +1952,7 @@ static int add_follower(struct hda_codec *codec,
int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char * const *followers,
const char *suffix, bool init_follower_vol,
struct snd_kcontrol **ctl_ret)
unsigned int access, struct snd_kcontrol **ctl_ret)
{
struct snd_kcontrol *kctl;
int err;
......@@ -1968,6 +1968,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
kctl = snd_ctl_make_virtual_master(name, tlv);
if (!kctl)
return -ENOMEM;
kctl->vd[0].access |= access;
err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0)
return err;
......@@ -1994,87 +1995,29 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
}
EXPORT_SYMBOL_GPL(__snd_hda_add_vmaster);
/*
* mute-LED control using vmaster
*/
static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
static const char * const texts[] = {
"On", "Off", "Follow Master"
};
return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = hook->mute_mode;
return 0;
}
static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
unsigned int old_mode = hook->mute_mode;
hook->mute_mode = ucontrol->value.enumerated.item[0];
if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER)
hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
if (old_mode == hook->mute_mode)
return 0;
snd_hda_sync_vmaster_hook(hook);
return 1;
}
static const struct snd_kcontrol_new vmaster_mute_mode = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mute-LED Mode",
.info = vmaster_mute_mode_info,
.get = vmaster_mute_mode_get,
.put = vmaster_mute_mode_put,
};
/* meta hook to call each driver's vmaster hook */
static void vmaster_hook(void *private_data, int enabled)
{
struct hda_vmaster_mute_hook *hook = private_data;
if (hook->mute_mode != HDA_VMUTE_FOLLOW_MASTER)
enabled = hook->mute_mode;
hook->hook(hook->codec, enabled);
}
/**
* snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED
* snd_hda_add_vmaster_hook - Add a vmaster hw specific hook
* @codec: the HDA codec
* @hook: the vmaster hook object
* @expose_enum_ctl: flag to create an enum ctl
*
* Add a mute-LED hook with the given vmaster switch kctl.
* When @expose_enum_ctl is set, "Mute-LED Mode" control is automatically
* created and associated with the given hook.
* Add a hw specific hook (like EAPD) with the given vmaster switch kctl.
*/
int snd_hda_add_vmaster_hook(struct hda_codec *codec,
struct hda_vmaster_mute_hook *hook,
bool expose_enum_ctl)
struct hda_vmaster_mute_hook *hook)
{
struct snd_kcontrol *kctl;
if (!hook->hook || !hook->sw_kctl)
return 0;
hook->codec = codec;
hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook);
if (!expose_enum_ctl)
return 0;
kctl = snd_ctl_new1(&vmaster_mute_mode, hook);
if (!kctl)
return -ENOMEM;
return snd_hda_ctl_add(codec, 0, kctl);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook);
......
......@@ -981,6 +981,8 @@ add_control(struct hda_gen_spec *spec, int type, const char *name,
knew->index = cidx;
if (get_amp_nid_(val))
knew->subdevice = HDA_SUBDEV_AMP_FLAG;
if (knew->access == 0)
knew->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
knew->private_value = val;
return knew;
}
......@@ -3618,8 +3620,11 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
amp_val_replace_channels(ctl, chs));
if (!knew)
return -ENOMEM;
if (is_switch)
if (is_switch) {
knew->put = cap_single_sw_put;
if (spec->mic_mute_led)
knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
}
if (!inv_dmic)
return 0;
......@@ -3634,8 +3639,11 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
amp_val_replace_channels(ctl, 2));
if (!knew)
return -ENOMEM;
if (is_switch)
if (is_switch) {
knew->put = cap_single_sw_put;
if (spec->mic_mute_led)
knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
}
return 0;
}
......@@ -3676,6 +3684,8 @@ static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
knew->index = idx;
knew->private_value = sw_ctl;
knew->subdevice = HDA_SUBDEV_AMP_FLAG;
if (spec->mic_mute_led)
knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
}
return 0;
}
......@@ -3917,11 +3927,6 @@ static int create_mute_led_cdev(struct hda_codec *codec,
return devm_led_classdev_register(&codec->core.dev, cdev);
}
static void vmaster_update_mute_led(void *private_data, int enabled)
{
ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON);
}
/**
* snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED
* @codec: the HDA codec
......@@ -3945,134 +3950,11 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
if (spec->vmaster_mute.hook)
codec_err(codec, "vmaster hook already present before cdev!\n");
spec->vmaster_mute.hook = vmaster_update_mute_led;
spec->vmaster_mute_enum = 1;
spec->vmaster_mute_led = 1;
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev);
/*
* mic mute LED hook helpers
*/
enum {
MICMUTE_LED_ON,
MICMUTE_LED_OFF,
MICMUTE_LED_FOLLOW_CAPTURE,
MICMUTE_LED_FOLLOW_MUTE,
};
static void call_micmute_led_update(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
unsigned int val;
switch (spec->micmute_led.led_mode) {
case MICMUTE_LED_ON:
val = 1;
break;
case MICMUTE_LED_OFF:
val = 0;
break;
case MICMUTE_LED_FOLLOW_CAPTURE:
val = !!spec->micmute_led.capture;
break;
case MICMUTE_LED_FOLLOW_MUTE:
default:
val = !spec->micmute_led.capture;
break;
}
if (val == spec->micmute_led.led_value)
return;
spec->micmute_led.led_value = val;
ledtrig_audio_set(LED_AUDIO_MICMUTE,
spec->micmute_led.led_value ? LED_ON : LED_OFF);
}
static void update_micmute_led(struct hda_codec *codec,
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_gen_spec *spec = codec->spec;
unsigned int mask;
if (spec->micmute_led.old_hook)
spec->micmute_led.old_hook(codec, kcontrol, ucontrol);
if (!ucontrol)
return;
mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
if (!strcmp("Capture Switch", ucontrol->id.name)) {
/* TODO: How do I verify if it's a mono or stereo here? */
if (ucontrol->value.integer.value[0] ||
ucontrol->value.integer.value[1])
spec->micmute_led.capture |= mask;
else
spec->micmute_led.capture &= ~mask;
call_micmute_led_update(codec);
}
}
static int micmute_led_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
static const char * const texts[] = {
"On", "Off", "Follow Capture", "Follow Mute",
};
return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
static int micmute_led_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hda_gen_spec *spec = codec->spec;
ucontrol->value.enumerated.item[0] = spec->micmute_led.led_mode;
return 0;
}
static int micmute_led_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hda_gen_spec *spec = codec->spec;
unsigned int mode;
mode = ucontrol->value.enumerated.item[0];
if (mode > MICMUTE_LED_FOLLOW_MUTE)
mode = MICMUTE_LED_FOLLOW_MUTE;
if (mode == spec->micmute_led.led_mode)
return 0;
spec->micmute_led.led_mode = mode;
call_micmute_led_update(codec);
return 1;
}
static const struct snd_kcontrol_new micmute_led_mode_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mic Mute-LED Mode",
.info = micmute_led_mode_info,
.get = micmute_led_mode_get,
.put = micmute_led_mode_put,
};
/* Set up the capture sync hook for controlling the mic-mute LED */
static int add_micmute_led_hook(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE;
spec->micmute_led.capture = 0;
spec->micmute_led.led_value = -1;
spec->micmute_led.old_hook = spec->cap_sync_hook;
spec->cap_sync_hook = update_micmute_led;
if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl))
return -ENOMEM;
return 0;
}
/**
* snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED
* @codec: the HDA codec
......@@ -4091,6 +3973,7 @@ int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
int (*callback)(struct led_classdev *,
enum led_brightness))
{
struct hda_gen_spec *spec = codec->spec;
int err;
if (callback) {
......@@ -4101,7 +3984,8 @@ int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
}
}
return add_micmute_led_hook(codec);
spec->mic_mute_led = 1;
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev);
#endif /* CONFIG_SND_HDA_GENERIC_LEDS */
......@@ -5060,6 +4944,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
parse_user_hints(codec);
if (spec->vmaster_mute_led || spec->mic_mute_led)
snd_ctl_led_request();
if (spec->mixer_nid && !spec->mixer_merge_nid)
spec->mixer_merge_nid = spec->mixer_nid;
......@@ -5291,7 +5178,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
spec->vmaster_tlv, follower_pfxs,
"Playback Volume");
"Playback Volume", 0);
if (err < 0)
return err;
}
......@@ -5299,13 +5186,14 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
NULL, follower_pfxs,
"Playback Switch",
true, &spec->vmaster_mute.sw_kctl);
"Playback Switch", true,
spec->vmaster_mute_led ?
SNDRV_CTL_ELEM_ACCESS_SPK_LED : 0,
&spec->vmaster_mute.sw_kctl);
if (err < 0)
return err;
if (spec->vmaster_mute.hook) {
snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute,
spec->vmaster_mute_enum);
snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
}
}
......
......@@ -84,15 +84,6 @@ struct badness_table {
extern const struct badness_table hda_main_out_badness;
extern const struct badness_table hda_extra_out_badness;
struct hda_micmute_hook {
unsigned int led_mode;
unsigned int capture;
unsigned int led_value;
void (*old_hook)(struct hda_codec *codec,
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
};
struct hda_gen_spec {
char stream_name_analog[32]; /* analog PCM stream */
const struct hda_pcm_stream *stream_analog_playback;
......@@ -229,7 +220,8 @@ struct hda_gen_spec {
unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
unsigned int own_eapd_ctl:1; /* set EAPD by own function */
unsigned int keep_eapd_on:1; /* don't turn off EAPD automatically */
unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */
unsigned int vmaster_mute_led:1; /* add SPK-LED flag to vmaster mute switch */
unsigned int mic_mute_led:1; /* add MIC-LED flag to capture mute switch */
unsigned int indep_hp:1; /* independent HP supported */
unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
unsigned int add_stereo_mix_input:2; /* add aamix as a capture src */
......@@ -285,9 +277,6 @@ struct hda_gen_spec {
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
/* mic mute LED hook; called via cap_sync_hook */
struct hda_micmute_hook micmute_led;
/* PCM hooks */
void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
......
......@@ -131,21 +131,15 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char * const *followers,
const char *suffix, bool init_follower_vol,
struct snd_kcontrol **ctl_ret);
#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix) \
__snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, NULL)
unsigned int access, struct snd_kcontrol **ctl_ret);
#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix, access) \
__snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, access, NULL)
int snd_hda_codec_reset(struct hda_codec *codec);
void snd_hda_codec_register(struct hda_codec *codec);
void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec);
#define snd_hda_regmap_sync(codec) snd_hdac_regmap_sync(&(codec)->core)
enum {
HDA_VMUTE_OFF,
HDA_VMUTE_ON,
HDA_VMUTE_FOLLOW_MASTER,
};
struct hda_vmaster_mute_hook {
/* below two fields must be filled by the caller of
* snd_hda_add_vmaster_hook() beforehand
......@@ -153,13 +147,11 @@ struct hda_vmaster_mute_hook {
struct snd_kcontrol *sw_kctl;
void (*hook)(void *, int);
/* below are initialized automatically */
unsigned int mute_mode; /* HDA_VMUTE_XXX */
struct hda_codec *codec;
};
int snd_hda_add_vmaster_hook(struct hda_codec *codec,
struct hda_vmaster_mute_hook *hook,
bool expose_enum_ctl);
struct hda_vmaster_mute_hook *hook);
void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook);
/* amp value bits */
......
......@@ -7041,11 +7041,11 @@ static int ca0132_build_controls(struct hda_codec *codec)
spec->tlv);
snd_hda_add_vmaster(codec, "Master Playback Volume",
spec->tlv, ca0132_alt_follower_pfxs,
"Playback Volume");
"Playback Volume", 0);
err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
NULL, ca0132_alt_follower_pfxs,
"Playback Switch",
true, &spec->vmaster_mute.sw_kctl);
true, 0, &spec->vmaster_mute.sw_kctl);
if (err < 0)
return err;
}
......
......@@ -292,7 +292,7 @@ static void alc_fixup_gpio4(struct hda_codec *codec,
static void alc_fixup_micmute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
if (action == HDA_FIXUP_ACT_PROBE)
if (action == HDA_FIXUP_ACT_PRE_PROBE)
snd_hda_gen_add_micmute_led_cdev(codec, NULL);
}
......
......@@ -4277,6 +4277,9 @@ static int stac_parse_auto_config(struct hda_codec *codec)
spec->gen.automute_hook = stac_update_outputs;
if (spec->gpio_led)
snd_hda_gen_add_mute_led_cdev(codec, stac_vmaster_hook);
err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
if (err < 0)
return err;
......@@ -4318,9 +4321,6 @@ static int stac_parse_auto_config(struct hda_codec *codec)
}
#endif
if (spec->gpio_led)
snd_hda_gen_add_mute_led_cdev(codec, stac_vmaster_hook);
if (spec->aloopback_ctl &&
snd_hda_get_bool_hint(codec, "loopback") == 1) {
unsigned int wr_verb =
......
......@@ -18,7 +18,7 @@ static bool is_thinkpad(struct hda_codec *codec)
static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
if (action == HDA_FIXUP_ACT_PROBE) {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
if (!is_thinkpad(codec))
return;
snd_hda_gen_add_mute_led_cdev(codec, NULL);
......
......@@ -37,7 +37,7 @@ config SND_SOC_COMPRESS
config SND_SOC_TOPOLOGY
bool
config SND_SOC_TOPOLOGY_KUNIT_TESTS
config SND_SOC_TOPOLOGY_KUNIT_TEST
tristate "KUnit tests for SoC topology"
depends on KUNIT
depends on SND_SOC_TOPOLOGY
......
......@@ -7,9 +7,9 @@ ifneq ($(CONFIG_SND_SOC_TOPOLOGY),)
snd-soc-core-objs += soc-topology.o
endif
ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS),)
ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),)
# snd-soc-test-objs := soc-topology-test.o
obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS) := soc-topology-test.o
obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) := soc-topology-test.o
endif
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
......
......@@ -5,14 +5,15 @@ config SND_SOC_AMD_ACP
This option enables ACP DMA support on AMD platform.
config SND_SOC_AMD_CZ_DA7219MX98357_MACH
tristate "AMD CZ support for DA7219 and MAX9835"
tristate "AMD CZ support for DA7219, RT5682 and MAX9835"
select SND_SOC_DA7219
select SND_SOC_RT5682_I2C
select SND_SOC_MAX98357A
select SND_SOC_ADAU7002
select REGULATOR
depends on SND_SOC_AMD_ACP && I2C && GPIOLIB
depends on SND_SOC_AMD_ACP && I2C && GPIOLIB && ACPI
help
This option enables machine driver for DA7219 and MAX9835.
This option enables machine driver for DA7219, RT5682 and MAX9835.
config SND_SOC_AMD_CZ_RT5645_MACH
tristate "AMD CZ support for RT5645"
......@@ -34,6 +35,7 @@ config SND_SOC_AMD_RV_RT5682_MACH
select SND_SOC_CROS_EC_CODEC
select I2C_CROS_EC_TUNNEL
select SND_SOC_RT1015
select SND_SOC_RT1015P
depends on SND_SOC_AMD_ACP3x && I2C && CROS_EC
help
This option enables machine driver for RT5682 and MAX9835.
......
/*
* Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec
*
* Copyright 2017 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
// SPDX-License-Identifier: MIT
//
// Machine driver for AMD ACP Audio engine using DA7219, RT5682 & MAX98357 codec
//
//Copyright 2017-2021 Advanced Micro Devices, Inc.
#include <sound/core.h>
#include <sound/soc.h>
......@@ -41,14 +22,19 @@
#include "acp.h"
#include "../codecs/da7219.h"
#include "../codecs/da7219-aad.h"
#include "../codecs/rt5682.h"
#define CZ_PLAT_CLK 48000000
#define DUAL_CHANNEL 2
#define RT5682_PLL_FREQ (48000 * 512)
static struct snd_soc_jack cz_jack;
static struct clk *da7219_dai_wclk;
static struct clk *da7219_dai_bclk;
static struct clk *rt5682_dai_wclk;
static struct clk *rt5682_dai_bclk;
extern bool bt_uart_enable;
void *acp_soc_is_rltk_max(struct device *dev);
static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
{
......@@ -128,6 +114,96 @@ static void da7219_clk_disable(void)
clk_disable_unprepare(da7219_dai_bclk);
}
static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
dev_info(codec_dai->dev, "codec dai name = %s\n", codec_dai->name);
/* Set codec sysclk */
ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2,
RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(codec_dai->dev,
"Failed to set rt5682 SYSCLK: %d\n", ret);
return ret;
}
/* set codec PLL */
ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK,
CZ_PLAT_CLK, RT5682_PLL_FREQ);
if (ret < 0) {
dev_err(codec_dai->dev, "can't set rt5682 PLL: %d\n", ret);
return ret;
}
rt5682_dai_wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
if (IS_ERR(rt5682_dai_wclk))
return PTR_ERR(rt5682_dai_wclk);
rt5682_dai_bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
if (IS_ERR(rt5682_dai_bclk))
return PTR_ERR(rt5682_dai_bclk);
ret = snd_soc_card_jack_new(card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
&cz_jack, NULL, 0);
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
}
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
ret = snd_soc_component_set_jack(component, &cz_jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
}
return 0;
}
static int rt5682_clk_enable(struct snd_pcm_substream *substream)
{
int ret;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
/*
* Set wclk to 48000 because the rate constraint of this driver is
* 48000. ADAU7002 spec: "The ADAU7002 requires a BCLK rate that is
* minimum of 64x the LRCLK sample rate." RT5682 is the only clk
* source so for all codecs we have to limit bclk to 64X lrclk.
*/
ret = clk_set_rate(rt5682_dai_wclk, 48000);
if (ret) {
dev_err(rtd->dev, "Error setting wclk rate: %d\n", ret);
return ret;
}
ret = clk_set_rate(rt5682_dai_bclk, 48000 * 64);
if (ret) {
dev_err(rtd->dev, "Error setting bclk rate: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(rt5682_dai_wclk);
if (ret < 0) {
dev_err(rtd->dev, "can't enable wclk %d\n", ret);
return ret;
}
return ret;
}
static void rt5682_clk_disable(void)
{
clk_disable_unprepare(rt5682_dai_wclk);
}
static const unsigned int channels[] = {
DUAL_CHANNEL,
};
......@@ -260,6 +336,118 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
da7219_clk_disable();
}
static int cz_rt5682_play_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
/*
* On this platform for PCM device we support stereo
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->play_i2s_instance = I2S_SP_INSTANCE;
return rt5682_clk_enable(substream);
}
static int cz_rt5682_cap_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
/*
* On this platform for PCM device we support stereo
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->cap_i2s_instance = I2S_SP_INSTANCE;
machine->capture_channel = CAP_CHANNEL1;
return rt5682_clk_enable(substream);
}
static int cz_rt5682_max_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
/*
* On this platform for PCM device we support stereo
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->play_i2s_instance = I2S_BT_INSTANCE;
return rt5682_clk_enable(substream);
}
static int cz_rt5682_dmic0_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
/*
* On this platform for PCM device we support stereo
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->cap_i2s_instance = I2S_BT_INSTANCE;
return rt5682_clk_enable(substream);
}
static int cz_rt5682_dmic1_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
/*
* On this platform for PCM device we support stereo
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
machine->cap_i2s_instance = I2S_SP_INSTANCE;
machine->capture_channel = CAP_CHANNEL0;
return rt5682_clk_enable(substream);
}
static void cz_rt5682_shutdown(struct snd_pcm_substream *substream)
{
rt5682_clk_disable();
}
static const struct snd_soc_ops cz_da7219_play_ops = {
.startup = cz_da7219_play_startup,
.shutdown = cz_da7219_shutdown,
......@@ -285,6 +473,31 @@ static const struct snd_soc_ops cz_dmic1_cap_ops = {
.shutdown = cz_da7219_shutdown,
};
static const struct snd_soc_ops cz_rt5682_play_ops = {
.startup = cz_rt5682_play_startup,
.shutdown = cz_rt5682_shutdown,
};
static const struct snd_soc_ops cz_rt5682_cap_ops = {
.startup = cz_rt5682_cap_startup,
.shutdown = cz_rt5682_shutdown,
};
static const struct snd_soc_ops cz_rt5682_max_play_ops = {
.startup = cz_rt5682_max_startup,
.shutdown = cz_rt5682_shutdown,
};
static const struct snd_soc_ops cz_rt5682_dmic0_cap_ops = {
.startup = cz_rt5682_dmic0_startup,
.shutdown = cz_rt5682_shutdown,
};
static const struct snd_soc_ops cz_rt5682_dmic1_cap_ops = {
.startup = cz_rt5682_dmic1_startup,
.shutdown = cz_rt5682_shutdown,
};
SND_SOC_DAILINK_DEF(designware1,
DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1.auto")));
SND_SOC_DAILINK_DEF(designware2,
......@@ -294,6 +507,8 @@ SND_SOC_DAILINK_DEF(designware3,
SND_SOC_DAILINK_DEF(dlgs,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", "da7219-hifi")));
SND_SOC_DAILINK_DEF(rt5682,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1")));
SND_SOC_DAILINK_DEF(mx,
DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", "HiFi")));
SND_SOC_DAILINK_DEF(adau,
......@@ -353,6 +568,57 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
},
};
static struct snd_soc_dai_link cz_dai_5682_98357[] = {
{
.name = "amd-rt5682-play",
.stream_name = "Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.init = cz_rt5682_init,
.dpcm_playback = 1,
.ops = &cz_rt5682_play_ops,
SND_SOC_DAILINK_REG(designware1, rt5682, platform),
},
{
.name = "amd-rt5682-cap",
.stream_name = "Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_capture = 1,
.ops = &cz_rt5682_cap_ops,
SND_SOC_DAILINK_REG(designware2, rt5682, platform),
},
{
.name = "amd-max98357-play",
.stream_name = "HiFi Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_playback = 1,
.ops = &cz_rt5682_max_play_ops,
SND_SOC_DAILINK_REG(designware3, mx, platform),
},
{
/* C panel DMIC */
.name = "dmic0",
.stream_name = "DMIC0 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_capture = 1,
.ops = &cz_rt5682_dmic0_cap_ops,
SND_SOC_DAILINK_REG(designware3, adau, platform),
},
{
/* A/B panel DMIC */
.name = "dmic1",
.stream_name = "DMIC1 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_capture = 1,
.ops = &cz_rt5682_dmic1_cap_ops,
SND_SOC_DAILINK_REG(designware2, adau, platform),
},
};
static const struct snd_soc_dapm_widget cz_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_SPK("Speakers", NULL),
......@@ -368,6 +634,14 @@ static const struct snd_soc_dapm_route cz_audio_route[] = {
{"PDM_DAT", NULL, "Int Mic"},
};
static const struct snd_soc_dapm_route cz_rt5682_audio_route[] = {
{"Headphones", NULL, "HPOL"},
{"Headphones", NULL, "HPOR"},
{"IN1P", NULL, "Headset Mic"},
{"Speakers", NULL, "Speaker"},
{"PDM_DAT", NULL, "Int Mic"},
};
static const struct snd_kcontrol_new cz_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphones"),
SOC_DAPM_PIN_SWITCH("Speakers"),
......@@ -388,6 +662,28 @@ static struct snd_soc_card cz_card = {
.num_controls = ARRAY_SIZE(cz_mc_controls),
};
static struct snd_soc_card cz_rt5682_card = {
.name = "acpr5682m98357",
.owner = THIS_MODULE,
.dai_link = cz_dai_5682_98357,
.num_links = ARRAY_SIZE(cz_dai_5682_98357),
.dapm_widgets = cz_widgets,
.num_dapm_widgets = ARRAY_SIZE(cz_widgets),
.dapm_routes = cz_rt5682_audio_route,
.controls = cz_mc_controls,
.num_controls = ARRAY_SIZE(cz_mc_controls),
};
void *acp_soc_is_rltk_max(struct device *dev)
{
const struct acpi_device_id *match;
match = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!match)
return NULL;
return (void *)match->driver_data;
}
static struct regulator_consumer_supply acp_da7219_supplies[] = {
REGULATOR_SUPPLY("VDD", "i2c-DLGS7219:00"),
REGULATOR_SUPPLY("VDDMIC", "i2c-DLGS7219:00"),
......@@ -425,29 +721,39 @@ static int cz_probe(struct platform_device *pdev)
struct snd_soc_card *card;
struct acp_platform_info *machine;
struct regulator_dev *rdev;
acp_da7219_cfg.dev = &pdev->dev;
rdev = devm_regulator_register(&pdev->dev, &acp_da7219_desc,
&acp_da7219_cfg);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "Failed to register regulator: %d\n",
(int)PTR_ERR(rdev));
return -EINVAL;
struct device *dev = &pdev->dev;
card = (struct snd_soc_card *)acp_soc_is_rltk_max(dev);
if (!card)
return -ENODEV;
if (!strcmp(card->name, "acpd7219m98357")) {
acp_da7219_cfg.dev = &pdev->dev;
rdev = devm_regulator_register(&pdev->dev, &acp_da7219_desc,
&acp_da7219_cfg);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "Failed to register regulator: %d\n",
(int)PTR_ERR(rdev));
return -EINVAL;
}
}
machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info),
GFP_KERNEL);
if (!machine)
return -ENOMEM;
card = &cz_card;
cz_card.dev = &pdev->dev;
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
dev_err(&pdev->dev,
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"devm_snd_soc_register_card(%s) failed: %d\n",
cz_card.name, ret);
card->name, ret);
else
dev_dbg(&pdev->dev,
"devm_snd_soc_register_card(%s) probe deferred: %d\n",
card->name, ret);
return ret;
}
bt_uart_enable = !device_property_read_bool(&pdev->dev,
......@@ -457,7 +763,8 @@ static int cz_probe(struct platform_device *pdev)
#ifdef CONFIG_ACPI
static const struct acpi_device_id cz_audio_acpi_match[] = {
{ "AMD7219", 0 },
{ "AMD7219", (unsigned long)&cz_card },
{ "AMDI5682", (unsigned long)&cz_rt5682_card},
{},
};
MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
......@@ -475,5 +782,6 @@ static struct platform_driver cz_pcm_driver = {
module_platform_driver(cz_pcm_driver);
MODULE_AUTHOR("akshu.agrawal@amd.com");
MODULE_DESCRIPTION("DA7219 & MAX98357A audio support");
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_DESCRIPTION("DA7219, RT5682 & MAX98357A audio support");
MODULE_LICENSE("GPL v2");
......@@ -275,6 +275,8 @@ SND_SOC_DAILINK_DEF(rt5682,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1")));
SND_SOC_DAILINK_DEF(max,
DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", "HiFi")));
SND_SOC_DAILINK_DEF(rt1015p,
DAILINK_COMP_ARRAY(COMP_CODEC("RTL1015:00", "HiFi")));
SND_SOC_DAILINK_DEF(rt1015,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1015:00", "rt1015-aif"),
COMP_CODEC("i2c-10EC1015:01", "rt1015-aif")));
......@@ -419,6 +421,43 @@ static struct snd_soc_card acp3x_1015 = {
.num_controls = ARRAY_SIZE(acp3x_mc_1015_controls),
};
static const struct snd_soc_dapm_widget acp3x_1015p_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0,
&acp3x_dmic_mux_control),
SND_SOC_DAPM_SPK("Speakers", NULL),
};
static const struct snd_soc_dapm_route acp3x_1015p_route[] = {
{"Headphone Jack", NULL, "HPOL"},
{"Headphone Jack", NULL, "HPOR"},
{"IN1P", NULL, "Headset Mic"},
{"Dmic Mux", "Front Mic", "DMIC"},
{"Dmic Mux", "Rear Mic", "DMIC"},
/* speaker */
{ "Speakers", NULL, "Speaker" },
};
static const struct snd_kcontrol_new acp3x_mc_1015p_controls[] = {
SOC_DAPM_PIN_SWITCH("Speakers"),
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
static struct snd_soc_card acp3x_1015p = {
.name = "acp3xalc56821015p",
.owner = THIS_MODULE,
.dai_link = acp3x_dai,
.num_links = ARRAY_SIZE(acp3x_dai),
.dapm_widgets = acp3x_1015p_widgets,
.num_dapm_widgets = ARRAY_SIZE(acp3x_1015p_widgets),
.dapm_routes = acp3x_1015p_route,
.num_dapm_routes = ARRAY_SIZE(acp3x_1015p_route),
.controls = acp3x_mc_1015p_controls,
.num_controls = ARRAY_SIZE(acp3x_mc_1015p_controls),
};
void *soc_is_rltk_max(struct device *dev)
{
const struct acpi_device_id *match;
......@@ -435,6 +474,9 @@ static void card_spk_dai_link_present(struct snd_soc_dai_link *links,
if (!strcmp(card_name, "acp3xalc56821015")) {
links[1].codecs = rt1015;
links[1].num_codecs = ARRAY_SIZE(rt1015);
} else if (!strcmp(card_name, "acp3xalc56821015p")) {
links[1].codecs = rt1015p;
links[1].num_codecs = ARRAY_SIZE(rt1015p);
} else {
links[1].codecs = max;
links[1].num_codecs = ARRAY_SIZE(max);
......@@ -486,6 +528,7 @@ static int acp3x_probe(struct platform_device *pdev)
static const struct acpi_device_id acp3x_audio_acpi_match[] = {
{ "AMDI5682", (unsigned long)&acp3x_5682},
{ "AMDI1015", (unsigned long)&acp3x_1015},
{ "10021015", (unsigned long)&acp3x_1015p},
{},
};
MODULE_DEVICE_TABLE(acpi, acp3x_audio_acpi_match);
......@@ -503,5 +546,6 @@ module_platform_driver(acp3x_audio);
MODULE_AUTHOR("akshu.agrawal@amd.com");
MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com");
MODULE_DESCRIPTION("ALC5682 ALC1015 & MAX98357 audio support");
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_DESCRIPTION("ALC5682 ALC1015, ALC1015P & MAX98357 audio support");
MODULE_LICENSE("GPL v2");
......@@ -249,7 +249,7 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
return ret;
}
static struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
.hw_params = acp3x_i2s_hwparams,
.trigger = acp3x_i2s_trigger,
.set_fmt = acp3x_i2s_set_fmt,
......
......@@ -129,7 +129,6 @@ static int start_pdm_dma(void __iomem *acp_base)
enable_pdm_clock(acp_base);
rn_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
rn_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
pdm_dma_enable = 0x00;
timeout = 0;
while (++timeout < ACP_COUNTER) {
pdm_dma_enable = rn_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
......@@ -153,7 +152,6 @@ static int stop_pdm_dma(void __iomem *acp_base)
if (pdm_dma_enable & 0x01) {
pdm_dma_enable = 0x02;
rn_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
pdm_dma_enable = 0x00;
timeout = 0;
while (++timeout < ACP_COUNTER) {
pdm_dma_enable = rn_readl(acp_base +
......@@ -358,7 +356,7 @@ static int acp_pdm_dai_trigger(struct snd_pcm_substream *substream,
return ret;
}
static struct snd_soc_dai_ops acp_pdm_dai_ops = {
static const struct snd_soc_dai_ops acp_pdm_dai_ops = {
.trigger = acp_pdm_dai_trigger,
};
......
......@@ -20,7 +20,7 @@ static int acp_power_gating;
module_param(acp_power_gating, int, 0644);
MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating");
/**
/*
* dmic_acpi_check = -1 - Use ACPI/DMI method to detect the DMIC hardware presence at runtime
* = 0 - Skip the DMIC device creation and return probe failure
* = 1 - Force DMIC support
......
......@@ -127,10 +127,13 @@ config SND_MCHP_SOC_I2S_MCC
Say Y or M if you want to add support for I2S Multi-Channel ASoC
driver on the following Microchip platforms:
- sam9x60
- sama7g5
The I2SMCC complies with the Inter-IC Sound (I2S) bus specification
and supports a Time Division Multiplexed (TDM) interface with
external multi-channel audio codecs.
Starting with sama7g5, I2S and Left-Justified multi-channel is
supported by using multiple data pins, output and input, without TDM.
config SND_MCHP_SOC_SPDIFTX
tristate "Microchip ASoC driver for boards using S/PDIF TX"
......
......@@ -48,7 +48,7 @@ static struct atmel_classd_pdata *atmel_classd_dt_init(struct device *dev)
{
struct device_node *np = dev->of_node;
struct atmel_classd_pdata *pdata;
const char *pwm_type;
const char *pwm_type_s;
int ret;
if (!np) {
......@@ -60,8 +60,8 @@ static struct atmel_classd_pdata *atmel_classd_dt_init(struct device *dev)
if (!pdata)
return ERR_PTR(-ENOMEM);
ret = of_property_read_string(np, "atmel,pwm-type", &pwm_type);
if ((ret == 0) && (strcmp(pwm_type, "diff") == 0))
ret = of_property_read_string(np, "atmel,pwm-type", &pwm_type_s);
if ((ret == 0) && (strcmp(pwm_type_s, "diff") == 0))
pdata->pwm_type = CLASSD_MR_PWMTYP_DIFF;
else
pdata->pwm_type = CLASSD_MR_PWMTYP_SINGLE;
......
......@@ -595,7 +595,7 @@ static int atmel_i2s_probe(struct platform_device *pdev)
struct regmap *regmap;
void __iomem *base;
int irq;
int err = -ENXIO;
int err;
unsigned int pcm_flags = 0;
unsigned int version;
......
......@@ -16,6 +16,7 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/lcm.h>
#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
......@@ -99,6 +100,8 @@
#define MCHP_I2SMCC_MRA_DATALENGTH_8_BITS_COMPACT (7 << 1)
#define MCHP_I2SMCC_MRA_WIRECFG_MASK GENMASK(5, 4)
#define MCHP_I2SMCC_MRA_WIRECFG_TDM(pin) (((pin) << 4) & \
MCHP_I2SMCC_MRA_WIRECFG_MASK)
#define MCHP_I2SMCC_MRA_WIRECFG_I2S_1_TDM_0 (0 << 4)
#define MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1 (1 << 4)
#define MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2 (2 << 4)
......@@ -173,7 +176,7 @@
*/
#define MCHP_I2SMCC_MRB_CRAMODE_REGULAR (1 << 0)
#define MCHP_I2SMCC_MRB_FIFOEN BIT(1)
#define MCHP_I2SMCC_MRB_FIFOEN BIT(4)
#define MCHP_I2SMCC_MRB_DMACHUNK_MASK GENMASK(9, 8)
#define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \
......@@ -225,6 +228,11 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = {
.max_register = MCHP_I2SMCC_VERSION,
};
struct mchp_i2s_mcc_soc_data {
unsigned int data_pin_pair_num;
bool has_fifo;
};
struct mchp_i2s_mcc_dev {
struct wait_queue_head wq_txrdy;
struct wait_queue_head wq_rxrdy;
......@@ -232,6 +240,7 @@ struct mchp_i2s_mcc_dev {
struct regmap *regmap;
struct clk *pclk;
struct clk *gclk;
const struct mchp_i2s_mcc_soc_data *soc;
struct snd_dmaengine_dai_dma_data playback;
struct snd_dmaengine_dai_dma_data capture;
unsigned int fmt;
......@@ -239,6 +248,7 @@ struct mchp_i2s_mcc_dev {
unsigned int frame_length;
int tdm_slots;
int channels;
u8 tdm_data_pair;
unsigned int gclk_use:1;
unsigned int gclk_running:1;
unsigned int tx_rdy:1;
......@@ -248,7 +258,7 @@ struct mchp_i2s_mcc_dev {
static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
{
struct mchp_i2s_mcc_dev *dev = dev_id;
u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0;
u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0, idrb = 0;
irqreturn_t ret = IRQ_NONE;
regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra);
......@@ -266,24 +276,36 @@ static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
* Tx/Rx ready interrupts are enabled when stopping only, to assure
* availability and to disable clocks if necessary
*/
idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) |
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
if (idra)
if (dev->soc->has_fifo) {
idrb |= pendingb & (MCHP_I2SMCC_INT_TXFFRDY |
MCHP_I2SMCC_INT_RXFFRDY);
} else {
idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) |
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
}
if (idra || idrb)
ret = IRQ_HANDLED;
if ((imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) &&
(imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) ==
(idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) {
if ((!dev->soc->has_fifo &&
(imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) &&
(imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) ==
(idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) ||
(dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_TXFFRDY)) {
dev->tx_rdy = 1;
wake_up_interruptible(&dev->wq_txrdy);
}
if ((imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) &&
(imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) ==
(idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) {
if ((!dev->soc->has_fifo &&
(imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) &&
(imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) ==
(idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) ||
(dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_RXFFRDY)) {
dev->rx_rdy = 1;
wake_up_interruptible(&dev->wq_rxrdy);
}
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);
if (dev->soc->has_fifo)
regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, idrb);
else
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);
return ret;
}
......@@ -549,6 +571,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
}
if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
/* for I2S and LEFT_J one pin is needed for every 2 channels */
if (channels > dev->soc->data_pin_pair_num * 2) {
dev_err(dev->dev,
"unsupported number of audio channels: %d\n",
channels);
return -EINVAL;
}
/* enable for interleaved format */
mrb |= MCHP_I2SMCC_MRB_CRAMODE_REGULAR;
switch (channels) {
case 1:
if (is_playback)
......@@ -558,6 +591,12 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
break;
case 2:
break;
case 4:
mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1;
break;
case 8:
mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2;
break;
default:
dev_err(dev->dev, "unsupported number of audio channels\n");
return -EINVAL;
......@@ -566,6 +605,8 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
if (!frame_length)
frame_length = 2 * params_physical_width(params);
} else if (dev->fmt & SND_SOC_DAIFMT_DSP_A) {
mra |= MCHP_I2SMCC_MRA_WIRECFG_TDM(dev->tdm_data_pair);
if (dev->tdm_slots) {
if (channels % 2 && channels * 2 <= dev->tdm_slots) {
/*
......@@ -636,6 +677,10 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
}
}
/* enable FIFO if available */
if (dev->soc->has_fifo)
mrb |= MCHP_I2SMCC_MRB_FIFOEN;
/*
* If we are already running, the wanted setup must be
* the same with the one that's currently ongoing
......@@ -698,8 +743,13 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
if (err == 0) {
dev_warn_once(dev->dev,
"Timeout waiting for Tx ready\n");
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels));
if (dev->soc->has_fifo)
regmap_write(dev->regmap, MCHP_I2SMCC_IDRB,
MCHP_I2SMCC_INT_TXFFRDY);
else
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels));
dev->tx_rdy = 1;
}
} else {
......@@ -709,8 +759,12 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
if (err == 0) {
dev_warn_once(dev->dev,
"Timeout waiting for Rx ready\n");
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
if (dev->soc->has_fifo)
regmap_write(dev->regmap, MCHP_I2SMCC_IDRB,
MCHP_I2SMCC_INT_RXFFRDY);
else
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
dev->rx_rdy = 1;
}
}
......@@ -737,7 +791,7 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
u32 cr = 0;
u32 iera = 0;
u32 iera = 0, ierb = 0;
u32 sr;
int err;
......@@ -761,7 +815,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
* Enable Tx Ready interrupts on all channels
* to assure all data is sent
*/
iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels);
if (dev->soc->has_fifo)
ierb = MCHP_I2SMCC_INT_TXFFRDY;
else
iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels);
} else if (!is_playback && (sr & MCHP_I2SMCC_SR_RXEN)) {
cr = MCHP_I2SMCC_CR_RXDIS;
dev->rx_rdy = 0;
......@@ -769,7 +826,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
* Enable Rx Ready interrupts on all channels
* to assure all data is received
*/
iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
if (dev->soc->has_fifo)
ierb = MCHP_I2SMCC_INT_RXFFRDY;
else
iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
}
break;
default:
......@@ -787,7 +847,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
}
}
regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera);
if (dev->soc->has_fifo)
regmap_write(dev->regmap, MCHP_I2SMCC_IERB, ierb);
else
regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera);
regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr);
return 0;
......@@ -869,15 +932,68 @@ static const struct snd_soc_component_driver mchp_i2s_mcc_component = {
};
#ifdef CONFIG_OF
static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sam9x60 = {
.data_pin_pair_num = 1,
};
static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sama7g5 = {
.data_pin_pair_num = 4,
.has_fifo = true,
};
static const struct of_device_id mchp_i2s_mcc_dt_ids[] = {
{
.compatible = "microchip,sam9x60-i2smcc",
.data = &mchp_i2s_mcc_sam9x60,
},
{
.compatible = "microchip,sama7g5-i2smcc",
.data = &mchp_i2s_mcc_sama7g5,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mchp_i2s_mcc_dt_ids);
#endif
static int mchp_i2s_mcc_soc_data_parse(struct platform_device *pdev,
struct mchp_i2s_mcc_dev *dev)
{
int err;
if (!dev->soc) {
dev_err(&pdev->dev, "failed to get soc data\n");
return -ENODEV;
}
if (dev->soc->data_pin_pair_num == 1)
return 0;
err = of_property_read_u8(pdev->dev.of_node, "microchip,tdm-data-pair",
&dev->tdm_data_pair);
if (err < 0 && err != -EINVAL) {
dev_err(&pdev->dev,
"bad property data for 'microchip,tdm-data-pair': %d",
err);
return err;
}
if (err == -EINVAL) {
dev_info(&pdev->dev,
"'microchip,tdm-data-pair' not found; assuming DIN/DOUT 0 for TDM\n");
dev->tdm_data_pair = 0;
} else {
if (dev->tdm_data_pair > dev->soc->data_pin_pair_num - 1) {
dev_err(&pdev->dev,
"invalid value for 'microchip,tdm-data-pair': %d\n",
dev->tdm_data_pair);
return -EINVAL;
}
dev_dbg(&pdev->dev, "TMD format on DIN/DOUT %d pins\n",
dev->tdm_data_pair);
}
return 0;
}
static int mchp_i2s_mcc_probe(struct platform_device *pdev)
{
struct mchp_i2s_mcc_dev *dev;
......@@ -929,6 +1045,11 @@ static int mchp_i2s_mcc_probe(struct platform_device *pdev)
dev->gclk = NULL;
}
dev->soc = of_device_get_match_data(&pdev->dev);
err = mchp_i2s_mcc_soc_data_parse(pdev, dev);
if (err < 0)
return err;
dev->dev = &pdev->dev;
dev->regmap = regmap;
platform_set_drvdata(pdev, dev);
......
......@@ -1310,7 +1310,7 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
struct device_node *child_node;
struct resource *res;
struct cygnus_audio *cygaud;
int err = -EINVAL;
int err;
int node_count;
int active_port_count;
......
......@@ -161,6 +161,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT1011
imply SND_SOC_RT1015
imply SND_SOC_RT1015P
imply SND_SOC_RT1019
imply SND_SOC_RT1305
imply SND_SOC_RT1308
imply SND_SOC_RT5514
......@@ -180,8 +181,11 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT5682_SDW
imply SND_SOC_RT700_SDW
imply SND_SOC_RT711_SDW
imply SND_SOC_RT711_SDCA_SDW
imply SND_SOC_RT715_SDW
imply SND_SOC_RT715_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
imply SND_SOC_SGTL5000
imply SND_SOC_SI476X
imply SND_SOC_SIMPLE_AMPLIFIER
......@@ -214,7 +218,8 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TLV320AIC31XX
imply SND_SOC_TLV320AIC32X4_I2C
imply SND_SOC_TLV320AIC32X4_SPI
imply SND_SOC_TLV320AIC3X
imply SND_SOC_TLV320AIC3X_I2C
imply SND_SOC_TLV320AIC3X_SPI
imply SND_SOC_TPA6130A2
imply SND_SOC_TLV320DAC33
imply SND_SOC_TSCS42XX
......@@ -1076,6 +1081,7 @@ config SND_SOC_RL6231
default y if SND_SOC_RT1011=y
default y if SND_SOC_RT1015=y
default y if SND_SOC_RT1015P=y
default y if SND_SOC_RT1019=y
default y if SND_SOC_RT1305=y
default y if SND_SOC_RT1308=y
default m if SND_SOC_RT5514=m
......@@ -1094,6 +1100,7 @@ config SND_SOC_RL6231
default m if SND_SOC_RT1011=m
default m if SND_SOC_RT1015=m
default m if SND_SOC_RT1015P=m
default m if SND_SOC_RT1019=m
default m if SND_SOC_RT1305=m
default m if SND_SOC_RT1308=m
......@@ -1130,6 +1137,10 @@ config SND_SOC_RT1015P
tristate
depends on GPIOLIB
config SND_SOC_RT1019
tristate
depends on I2C
config SND_SOC_RT1305
tristate
depends on I2C
......@@ -1143,6 +1154,11 @@ config SND_SOC_RT1308_SDW
depends on I2C && SOUNDWIRE
select REGMAP_SOUNDWIRE
config SND_SOC_RT1316_SDW
tristate "Realtek RT1316 Codec - SDW"
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
config SND_SOC_RT5514
tristate
depends on I2C
......@@ -1241,6 +1257,12 @@ config SND_SOC_RT711_SDW
select SND_SOC_RT711
select REGMAP_SOUNDWIRE
config SND_SOC_RT711_SDCA_SDW
tristate "Realtek RT711 SDCA Codec - SDW"
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
select REGMAP_SOUNDWIRE_MBQ
config SND_SOC_RT715
tristate
......@@ -1250,6 +1272,12 @@ config SND_SOC_RT715_SDW
select SND_SOC_RT715
select REGMAP_SOUNDWIRE
config SND_SOC_RT715_SDCA_SDW
tristate "Realtek RT715 SDCA Codec - SDW"
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
select REGMAP_SOUNDWIRE_MBQ
#Freescale sgtl5000 codec
config SND_SOC_SGTL5000
tristate "Freescale SGTL5000 CODEC"
......@@ -1419,8 +1447,19 @@ config SND_SOC_TLV320AIC32X4_SPI
select SND_SOC_TLV320AIC32X4
config SND_SOC_TLV320AIC3X
tristate "Texas Instruments TLV320AIC3x CODECs"
tristate
config SND_SOC_TLV320AIC3X_I2C
tristate "Texas Instruments TLV320AIC3x audio CODECs - I2C"
depends on I2C
select SND_SOC_TLV320AIC3X
select REGMAP_I2C
config SND_SOC_TLV320AIC3X_SPI
tristate "Texas Instruments TLV320AIC3x audio CODECs - SPI"
depends on SPI_MASTER
select SND_SOC_TLV320AIC3X
select REGMAP_SPI
config SND_SOC_TLV320DAC33
tristate
......@@ -1785,6 +1824,14 @@ config SND_SOC_MT6359
Enable support for the platform which uses MT6359 as
external codec device.
config SND_SOC_MT6359_ACCDET
tristate "MediaTek MT6359 ACCDET driver"
depends on MTK_PMIC_WRAP
help
ACCDET means Accessory Detection technology, MediaTek develop it
for ASoC codec soc-jack detection mechanism.
Select N if you don't have jack on board.
config SND_SOC_MT6660
tristate "Mediatek MT6660 Speaker Amplifier"
depends on I2C
......
......@@ -43,7 +43,7 @@ snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
snd-soc-ak5386-objs := ak5386.o
snd-soc-ak5558-objs := ak5558.o
snd-soc-arizona-objs := arizona.o
snd-soc-arizona-objs := arizona.o arizona-jack.o
snd-soc-bd28623-objs := bd28623.o
snd-soc-bt-sco-objs := bt-sco.o
snd-soc-cpcap-objs := cpcap.o
......@@ -136,6 +136,7 @@ snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
snd-soc-mt6351-objs := mt6351.o
snd-soc-mt6358-objs := mt6358.o
snd-soc-mt6359-objs := mt6359.o
snd-soc-mt6359-accdet-objs := mt6359-accdet.o
snd-soc-mt6660-objs := mt6660.o
snd-soc-nau8315-objs := nau8315.o
snd-soc-nau8540-objs := nau8540.o
......@@ -170,9 +171,11 @@ snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt1011-objs := rt1011.o
snd-soc-rt1015-objs := rt1015.o
snd-soc-rt1015p-objs := rt1015p.o
snd-soc-rt1019-objs := rt1019.o
snd-soc-rt1305-objs := rt1305.o
snd-soc-rt1308-objs := rt1308.o
snd-soc-rt1308-sdw-objs := rt1308-sdw.o
snd-soc-rt1316-sdw-objs := rt1316-sdw.o
snd-soc-rt274-objs := rt274.o
snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o
......@@ -196,7 +199,9 @@ snd-soc-rt5682-sdw-objs := rt5682-sdw.o
snd-soc-rt5682-i2c-objs := rt5682-i2c.o
snd-soc-rt700-objs := rt700.o rt700-sdw.o
snd-soc-rt711-objs := rt711.o rt711-sdw.o
snd-soc-rt711-sdca-objs := rt711-sdca.o rt711-sdca-sdw.o
snd-soc-rt715-objs := rt715.o rt715-sdw.o
snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o
snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o
snd-soc-alc5632-objs := alc5632.o
......@@ -233,6 +238,8 @@ snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o tlv320aic32x4-clk.o
snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-tlv320aic3x-i2c-objs := tlv320aic3x-i2c.o
snd-soc-tlv320aic3x-spi-objs := tlv320aic3x-spi.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-tlv320adcx140-objs := tlv320adcx140.o
snd-soc-tscs42xx-objs := tscs42xx.o
......@@ -450,6 +457,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o
obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o
obj-$(CONFIG_SND_SOC_MT6359_ACCDET) += mt6359-accdet.o
obj-$(CONFIG_SND_SOC_MT6660) += snd-soc-mt6660.o
obj-$(CONFIG_SND_SOC_NAU8315) += snd-soc-nau8315.o
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
......@@ -484,9 +492,11 @@ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o
obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o
obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o
obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o
obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o
obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o
obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o
obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
......@@ -511,7 +521,9 @@ obj-$(CONFIG_SND_SOC_RT5682_I2C) += snd-soc-rt5682-i2c.o
obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o
obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o
obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o
obj-$(CONFIG_SND_SOC_RT711_SDCA_SDW) += snd-soc-rt711-sdca.o
obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o
obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
......@@ -548,6 +560,8 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X_I2C) += snd-soc-tlv320aic3x-i2c.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X_SPI) += snd-soc-tlv320aic3x-spi.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TLV320ADCX140) += snd-soc-tlv320adcx140.o
obj-$(CONFIG_SND_SOC_TSCS42XX) += snd-soc-tscs42xx.o
......
......@@ -113,13 +113,6 @@ enum amic_idx {
AMIC_IDX_2
};
struct ab8500_codec_drvdata_dbg {
struct regulator *vaud;
struct regulator *vamic1;
struct regulator *vamic2;
struct regulator *vdmic;
};
/* Private data for AB8500 device-driver */
struct ab8500_codec_drvdata {
struct regmap *regmap;
......
......@@ -305,8 +305,6 @@ static int ad1836_probe(struct snd_soc_component *component)
return ret;
ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs);
if (ret)
return ret;
return ret;
}
......
......@@ -236,8 +236,6 @@ static int adau1977_reset(struct adau1977 *adau1977)
ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER,
ADAU1977_POWER_RESET);
regcache_cache_bypass(adau1977->regmap, false);
if (ret)
return ret;
return ret;
}
......
......@@ -306,6 +306,20 @@ static const struct snd_soc_dapm_route ak4497_intercon[] = {
};
static int ak4458_get_tdm_mode(struct ak4458_priv *ak4458)
{
switch (ak4458->slots * ak4458->slot_width) {
case 128:
return 1;
case 256:
return 2;
case 512:
return 3;
default:
return 0;
}
}
static int ak4458_rstn_control(struct snd_soc_component *component, int bit)
{
int ret;
......@@ -333,13 +347,16 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
int pcm_width = max(params_physical_width(params), ak4458->slot_width);
u8 format, dsdsel0, dsdsel1;
int nfs1, dsd_bclk;
u8 format, dsdsel0, dsdsel1, dchn;
int nfs1, dsd_bclk, ret, channels, channels_max;
nfs1 = params_rate(params);
ak4458->fs = nfs1;
/* calculate bit clock */
channels = params_channels(params);
channels_max = dai->driver->playback.channels_max;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_DSD_U8:
case SNDRV_PCM_FORMAT_DSD_U16_LE:
......@@ -419,8 +436,24 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream,
snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
AK4458_DIF_MASK, format);
ak4458_rstn_control(component, 0);
ak4458_rstn_control(component, 1);
/*
* Enable/disable Daisy Chain if in TDM mode and the number of played
* channels is bigger than the maximum supported number of channels
*/
dchn = ak4458_get_tdm_mode(ak4458) &&
(ak4458->fmt == SND_SOC_DAIFMT_DSP_B) &&
(channels > channels_max) ? AK4458_DCHAIN_MASK : 0;
snd_soc_component_update_bits(component, AK4458_0B_CONTROL7,
AK4458_DCHAIN_MASK, dchn);
ret = ak4458_rstn_control(component, 0);
if (ret)
return ret;
ret = ak4458_rstn_control(component, 1);
if (ret)
return ret;
return 0;
}
......@@ -429,6 +462,7 @@ static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
int ret;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS: /* Slave Mode */
......@@ -461,8 +495,13 @@ static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
ak4458->fmt == SND_SOC_DAIFMT_PDM ?
AK4458_DP_MASK : 0);
ak4458_rstn_control(component, 0);
ak4458_rstn_control(component, 1);
ret = ak4458_rstn_control(component, 0);
if (ret)
return ret;
ret = ak4458_rstn_control(component, 1);
if (ret)
return ret;
return 0;
}
......@@ -508,20 +547,7 @@ static int ak4458_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
ak4458->slots = slots;
ak4458->slot_width = slot_width;
switch (slots * slot_width) {
case 128:
mode = AK4458_MODE_TDM128;
break;
case 256:
mode = AK4458_MODE_TDM256;
break;
case 512:
mode = AK4458_MODE_TDM512;
break;
default:
mode = AK4458_MODE_NORMAL;
break;
}
mode = ak4458_get_tdm_mode(ak4458) << AK4458_MODE_SHIFT;
snd_soc_component_update_bits(component, AK4458_0A_CONTROL6,
AK4458_MODE_MASK,
......
......@@ -82,6 +82,7 @@
* */
#define AK4458_ATS_SHIFT 6
#define AK4458_ATS_MASK GENMASK(7, 6)
#define AK4458_DCHAIN_MASK (0x1 << 1)
#define AK4458_DSDSEL_MASK (0x1 << 0)
#define AK4458_DP_MASK (0x1 << 7)
......
此差异已折叠。
......@@ -91,6 +91,41 @@ struct arizona_priv {
unsigned int dvfs_reqs;
struct mutex dvfs_lock;
bool dvfs_cached;
/* Variables used by arizona-jack.c code */
struct mutex lock;
struct delayed_work hpdet_work;
struct delayed_work micd_detect_work;
struct delayed_work micd_timeout_work;
struct snd_soc_jack *jack;
struct regulator *micvdd;
struct gpio_desc *micd_pol_gpio;
u16 last_jackdet;
int micd_mode;
const struct arizona_micd_config *micd_modes;
int micd_num_modes;
int micd_button_mask;
const struct arizona_micd_range *micd_ranges;
int num_micd_ranges;
bool micd_reva;
bool micd_clamp;
bool hpdet_active;
bool hpdet_done;
bool hpdet_retried;
bool mic;
bool detecting;
int num_hpdet_res;
unsigned int hpdet_res[3];
int jack_flips;
int hpdet_ip_version;
};
struct arizona_voice_trigger_info {
......@@ -222,6 +257,9 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
#define ARIZONA_RATE_ENUM_SIZE 4
#define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14
/* SND_JACK_* mask for supported cable/switch types */
#define ARIZONA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_MECHANICAL)
extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
......@@ -317,7 +355,7 @@ int arizona_init_vol_limit(struct arizona *arizona);
int arizona_init_spk_irqs(struct arizona *arizona);
int arizona_free_spk_irqs(struct arizona *arizona);
int arizona_init_dai(struct arizona_priv *priv, int dai);
int arizona_init_dai(struct arizona_priv *priv, int id);
int arizona_set_output_mode(struct snd_soc_component *component, int output,
bool diff);
......@@ -351,4 +389,10 @@ static inline int arizona_unregister_notifier(struct snd_soc_component *componen
int arizona_of_get_audio_pdata(struct arizona *arizona);
int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev);
int arizona_jack_codec_dev_remove(struct arizona_priv *info);
int arizona_jack_set_jack(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *data);
#endif
......@@ -94,7 +94,7 @@ static int send_ec_host_command(struct cros_ec_device *ec_dev, uint32_t cmd,
if (ret < 0)
goto error;
if (insize)
if (in && insize)
memcpy(in, msg->data, insize);
ret = 0;
......
......@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
......@@ -1488,7 +1487,7 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client,
if (IS_ERR(cs35l35->regmap)) {
ret = PTR_ERR(cs35l35->regmap);
dev_err(dev, "regmap_init() failed: %d\n", ret);
goto err;
return ret;
}
for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册