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

This commit is contained in:
Mark Brown 2021-04-23 19:01:02 +01:00
commit ffc9841d52
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
338 changed files with 17560 additions and 3624 deletions

View File

@ -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:

View File

@ -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

View File

@ -0,0 +1,108 @@
# 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";
};

View File

@ -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.

View File

@ -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";
};

View File

@ -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:

View File

@ -0,0 +1,108 @@
# 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>;
};

View File

@ -1,43 +0,0 @@
* 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>;
};

View File

@ -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:

View File

@ -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:
- |

View File

@ -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:
- |

View File

@ -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:
- |

View File

@ -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:
- |

View File

@ -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:
- |

View File

@ -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:

View File

@ -0,0 +1,35 @@
# 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>;
};
};

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -1,6 +1,6 @@
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>;
};
};

View File

@ -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*

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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" },
{

View File

@ -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

View File

@ -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;

View File

@ -1,12 +0,0 @@
/* 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 */

View File

@ -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()

View File

@ -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
*/

View File

@ -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 */

View File

@ -1,32 +0,0 @@
/* 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

View File

@ -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

View File

@ -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;
};
/**

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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);
}

770
sound/core/control_led.c Normal file
View File

@ -0,0 +1,770 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LED state routines for driver control interface
* Copyright (c) 2021 by Jaroslav Kysela <perex@perex.cz>
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <sound/core.h>
#include <sound/control.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("ALSA control interface to LED trigger code.");
MODULE_LICENSE("GPL");
#define MAX_LED (((SNDRV_CTL_ELEM_ACCESS_MIC_LED - SNDRV_CTL_ELEM_ACCESS_SPK_LED) \
>> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) + 1)
enum snd_ctl_led_mode {
MODE_FOLLOW_MUTE = 0,
MODE_FOLLOW_ROUTE,
MODE_OFF,
MODE_ON,
};
struct snd_ctl_led_card {
struct device dev;
int number;
struct snd_ctl_led *led;
};
struct snd_ctl_led {
struct device dev;
struct list_head controls;
const char *name;
unsigned int group;
enum led_audio trigger_type;
enum snd_ctl_led_mode mode;
struct snd_ctl_led_card *cards[SNDRV_CARDS];
};
struct snd_ctl_led_ctl {
struct list_head list;
struct snd_card *card;
unsigned int access;
struct snd_kcontrol *kctl;
unsigned int index_offset;
};
static DEFINE_MUTEX(snd_ctl_led_mutex);
static bool snd_ctl_led_card_valid[SNDRV_CARDS];
static struct snd_ctl_led snd_ctl_leds[MAX_LED] = {
{
.name = "speaker",
.group = (SNDRV_CTL_ELEM_ACCESS_SPK_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1,
.trigger_type = LED_AUDIO_MUTE,
.mode = MODE_FOLLOW_MUTE,
},
{
.name = "mic",
.group = (SNDRV_CTL_ELEM_ACCESS_MIC_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1,
.trigger_type = LED_AUDIO_MICMUTE,
.mode = MODE_FOLLOW_MUTE,
},
};
static void snd_ctl_led_sysfs_add(struct snd_card *card);
static void snd_ctl_led_sysfs_remove(struct snd_card *card);
#define UPDATE_ROUTE(route, cb) \
do { \
int route2 = (cb); \
if (route2 >= 0) \
route = route < 0 ? route2 : (route | route2); \
} while (0)
static inline unsigned int access_to_group(unsigned int access)
{
return ((access & SNDRV_CTL_ELEM_ACCESS_LED_MASK) >>
SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1;
}
static inline unsigned int group_to_access(unsigned int group)
{
return (group + 1) << SNDRV_CTL_ELEM_ACCESS_LED_SHIFT;
}
static struct snd_ctl_led *snd_ctl_led_get_by_access(unsigned int access)
{
unsigned int group = access_to_group(access);
if (group >= MAX_LED)
return NULL;
return &snd_ctl_leds[group];
}
static int snd_ctl_led_get(struct snd_ctl_led_ctl *lctl)
{
struct snd_kcontrol *kctl = lctl->kctl;
struct snd_ctl_elem_info info;
struct snd_ctl_elem_value value;
unsigned int i;
int result;
memset(&info, 0, sizeof(info));
info.id = kctl->id;
info.id.index += lctl->index_offset;
info.id.numid += lctl->index_offset;
result = kctl->info(kctl, &info);
if (result < 0)
return -1;
memset(&value, 0, sizeof(value));
value.id = info.id;
result = kctl->get(kctl, &value);
if (result < 0)
return -1;
if (info.type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
info.type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < info.count; i++)
if (value.value.integer.value[i] != info.value.integer.min)
return 1;
} else if (info.type == SNDRV_CTL_ELEM_TYPE_INTEGER64) {
for (i = 0; i < info.count; i++)
if (value.value.integer64.value[i] != info.value.integer64.min)
return 1;
}
return 0;
}
static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
struct snd_kcontrol *kctl, unsigned int ioff)
{
struct snd_ctl_led *led;
struct snd_ctl_led_ctl *lctl;
int route;
bool found;
led = snd_ctl_led_get_by_access(access);
if (!led)
return;
route = -1;
found = false;
mutex_lock(&snd_ctl_led_mutex);
/* the card may not be registered (active) at this point */
if (card && !snd_ctl_led_card_valid[card->number]) {
mutex_unlock(&snd_ctl_led_mutex);
return;
}
list_for_each_entry(lctl, &led->controls, list) {
if (lctl->kctl == kctl && lctl->index_offset == ioff)
found = true;
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
}
if (!found && kctl && card) {
lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
if (lctl) {
lctl->card = card;
lctl->access = access;
lctl->kctl = kctl;
lctl->index_offset = ioff;
list_add(&lctl->list, &led->controls);
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
}
}
mutex_unlock(&snd_ctl_led_mutex);
switch (led->mode) {
case MODE_OFF: route = 1; break;
case MODE_ON: route = 0; break;
case MODE_FOLLOW_ROUTE: if (route >= 0) route ^= 1; break;
case MODE_FOLLOW_MUTE: /* noop */ break;
}
if (route >= 0)
ledtrig_audio_set(led->trigger_type, route ? LED_OFF : LED_ON);
}
static struct snd_ctl_led_ctl *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff)
{
struct list_head *controls;
struct snd_ctl_led_ctl *lctl;
unsigned int group;
for (group = 0; group < MAX_LED; group++) {
controls = &snd_ctl_leds[group].controls;
list_for_each_entry(lctl, controls, list)
if (lctl->kctl == kctl && lctl->index_offset == ioff)
return lctl;
}
return NULL;
}
static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int ioff,
unsigned int access)
{
struct snd_ctl_led_ctl *lctl;
unsigned int ret = 0;
mutex_lock(&snd_ctl_led_mutex);
lctl = snd_ctl_led_find(kctl, ioff);
if (lctl && (access == 0 || access != lctl->access)) {
ret = lctl->access;
list_del(&lctl->list);
kfree(lctl);
}
mutex_unlock(&snd_ctl_led_mutex);
return ret;
}
static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask,
struct snd_kcontrol *kctl, unsigned int ioff)
{
struct snd_kcontrol_volatile *vd;
unsigned int access, access2;
if (mask == SNDRV_CTL_EVENT_MASK_REMOVE) {
access = snd_ctl_led_remove(kctl, ioff, 0);
if (access)
snd_ctl_led_set_state(card, access, NULL, 0);
} else if (mask & SNDRV_CTL_EVENT_MASK_INFO) {
vd = &kctl->vd[ioff];
access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
access2 = snd_ctl_led_remove(kctl, ioff, access);
if (access2)
snd_ctl_led_set_state(card, access2, NULL, 0);
if (access)
snd_ctl_led_set_state(card, access, kctl, ioff);
} else if ((mask & (SNDRV_CTL_EVENT_MASK_ADD |
SNDRV_CTL_EVENT_MASK_VALUE)) != 0) {
vd = &kctl->vd[ioff];
access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
if (access)
snd_ctl_led_set_state(card, access, kctl, ioff);
}
}
static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
unsigned int group, bool set)
{
struct snd_card *card;
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
unsigned int ioff, access, new_access;
int err = 0;
card = snd_card_ref(card_number);
if (card) {
down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, id);
if (kctl) {
ioff = snd_ctl_get_ioff(kctl, id);
vd = &kctl->vd[ioff];
access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
if (access != 0 && access != group_to_access(group)) {
err = -EXDEV;
goto unlock;
}
new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
if (set)
new_access |= group_to_access(group);
if (new_access != vd->access) {
vd->access = new_access;
snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
}
} else {
err = -ENOENT;
}
unlock:
up_write(&card->controls_rwsem);
snd_card_unref(card);
} else {
err = -ENXIO;
}
return err;
}
static void snd_ctl_led_refresh(void)
{
unsigned int group;
for (group = 0; group < MAX_LED; group++)
snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
}
static void snd_ctl_led_ctl_destroy(struct snd_ctl_led_ctl *lctl)
{
list_del(&lctl->list);
kfree(lctl);
}
static void snd_ctl_led_clean(struct snd_card *card)
{
unsigned int group;
struct snd_ctl_led *led;
struct snd_ctl_led_ctl *lctl;
for (group = 0; group < MAX_LED; group++) {
led = &snd_ctl_leds[group];
repeat:
list_for_each_entry(lctl, &led->controls, list)
if (!card || lctl->card == card) {
snd_ctl_led_ctl_destroy(lctl);
goto repeat;
}
}
}
static int snd_ctl_led_reset(int card_number, unsigned int group)
{
struct snd_card *card;
struct snd_ctl_led *led;
struct snd_ctl_led_ctl *lctl;
struct snd_kcontrol_volatile *vd;
bool change = false;
card = snd_card_ref(card_number);
if (!card)
return -ENXIO;
mutex_lock(&snd_ctl_led_mutex);
if (!snd_ctl_led_card_valid[card_number]) {
mutex_unlock(&snd_ctl_led_mutex);
snd_card_unref(card);
return -ENXIO;
}
led = &snd_ctl_leds[group];
repeat:
list_for_each_entry(lctl, &led->controls, list)
if (lctl->card == card) {
vd = &lctl->kctl->vd[lctl->index_offset];
vd->access &= ~group_to_access(group);
snd_ctl_led_ctl_destroy(lctl);
change = true;
goto repeat;
}
mutex_unlock(&snd_ctl_led_mutex);
if (change)
snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
snd_card_unref(card);
return 0;
}
static void snd_ctl_led_register(struct snd_card *card)
{
struct snd_kcontrol *kctl;
unsigned int ioff;
if (snd_BUG_ON(card->number < 0 ||
card->number >= ARRAY_SIZE(snd_ctl_led_card_valid)))
return;
mutex_lock(&snd_ctl_led_mutex);
snd_ctl_led_card_valid[card->number] = true;
mutex_unlock(&snd_ctl_led_mutex);
/* the register callback is already called with held card->controls_rwsem */
list_for_each_entry(kctl, &card->controls, list)
for (ioff = 0; ioff < kctl->count; ioff++)
snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, ioff);
snd_ctl_led_refresh();
snd_ctl_led_sysfs_add(card);
}
static void snd_ctl_led_disconnect(struct snd_card *card)
{
snd_ctl_led_sysfs_remove(card);
mutex_lock(&snd_ctl_led_mutex);
snd_ctl_led_card_valid[card->number] = false;
snd_ctl_led_clean(card);
mutex_unlock(&snd_ctl_led_mutex);
snd_ctl_led_refresh();
}
/*
* sysfs
*/
static ssize_t show_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
const char *str;
switch (led->mode) {
case MODE_FOLLOW_MUTE: str = "follow-mute"; break;
case MODE_FOLLOW_ROUTE: str = "follow-route"; break;
case MODE_ON: str = "on"; break;
case MODE_OFF: str = "off"; break;
}
return sprintf(buf, "%s\n", str);
}
static ssize_t store_mode(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
char _buf[16];
size_t l = min(count, sizeof(_buf) - 1) + 1;
enum snd_ctl_led_mode mode;
memcpy(_buf, buf, l);
_buf[l] = '\0';
if (strstr(_buf, "mute"))
mode = MODE_FOLLOW_MUTE;
else if (strstr(_buf, "route"))
mode = MODE_FOLLOW_ROUTE;
else if (strncmp(_buf, "off", 3) == 0 || strncmp(_buf, "0", 1) == 0)
mode = MODE_OFF;
else if (strncmp(_buf, "on", 2) == 0 || strncmp(_buf, "1", 1) == 0)
mode = MODE_ON;
else
return count;
mutex_lock(&snd_ctl_led_mutex);
led->mode = mode;
mutex_unlock(&snd_ctl_led_mutex);
snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0);
return count;
}
static ssize_t show_brightness(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
return sprintf(buf, "%u\n", ledtrig_audio_get(led->trigger_type));
}
static DEVICE_ATTR(mode, 0644, show_mode, store_mode);
static DEVICE_ATTR(brightness, 0444, show_brightness, NULL);
static struct attribute *snd_ctl_led_dev_attrs[] = {
&dev_attr_mode.attr,
&dev_attr_brightness.attr,
NULL,
};
static const struct attribute_group snd_ctl_led_dev_attr_group = {
.attrs = snd_ctl_led_dev_attrs,
};
static const struct attribute_group *snd_ctl_led_dev_attr_groups[] = {
&snd_ctl_led_dev_attr_group,
NULL,
};
static char *find_eos(char *s)
{
while (*s && *s != ',')
s++;
if (*s)
s++;
return s;
}
static char *parse_uint(char *s, unsigned int *val)
{
unsigned long long res;
if (kstrtoull(s, 10, &res))
res = 0;
*val = res;
return find_eos(s);
}
static char *parse_string(char *s, char *val, size_t val_size)
{
if (*s == '"' || *s == '\'') {
char c = *s;
s++;
while (*s && *s != c) {
if (val_size > 1) {
*val++ = *s;
val_size--;
}
s++;
}
} else {
while (*s && *s != ',') {
if (val_size > 1) {
*val++ = *s;
val_size--;
}
s++;
}
}
*val = '\0';
if (*s)
s++;
return s;
}
static char *parse_iface(char *s, unsigned int *val)
{
if (!strncasecmp(s, "card", 4))
*val = SNDRV_CTL_ELEM_IFACE_CARD;
else if (!strncasecmp(s, "mixer", 5))
*val = SNDRV_CTL_ELEM_IFACE_MIXER;
return find_eos(s);
}
/*
* These types of input strings are accepted:
*
* unsigned integer - numid (equivaled to numid=UINT)
* string - basic mixer name (equivalent to iface=MIXER,name=STR)
* numid=UINT
* [iface=MIXER,][device=UINT,][subdevice=UINT,]name=STR[,index=UINT]
*/
static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, size_t count,
bool attach)
{
char buf2[256], *s;
size_t len = max(sizeof(s) - 1, count);
struct snd_ctl_elem_id id;
int err;
strncpy(buf2, buf, len);
buf2[len] = '\0';
memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
s = buf2;
while (*s) {
if (!strncasecmp(s, "numid=", 6)) {
s = parse_uint(s + 6, &id.numid);
} else if (!strncasecmp(s, "iface=", 6)) {
s = parse_iface(s + 6, &id.iface);
} else if (!strncasecmp(s, "device=", 7)) {
s = parse_uint(s + 7, &id.device);
} else if (!strncasecmp(s, "subdevice=", 10)) {
s = parse_uint(s + 10, &id.subdevice);
} else if (!strncasecmp(s, "name=", 5)) {
s = parse_string(s + 5, id.name, sizeof(id.name));
} else if (!strncasecmp(s, "index=", 6)) {
s = parse_uint(s + 6, &id.index);
} else if (s == buf2) {
while (*s) {
if (*s < '0' || *s > '9')
break;
s++;
}
if (*s == '\0')
parse_uint(buf2, &id.numid);
else {
for (; *s >= ' '; s++);
*s = '\0';
strlcpy(id.name, buf2, sizeof(id.name));
}
break;
}
if (*s == ',')
s++;
}
err = snd_ctl_led_set_id(led_card->number, &id, led_card->led->group, attach);
if (err < 0)
return err;
return count;
}
static ssize_t parse_attach(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
return set_led_id(led_card, buf, count, true);
}
static ssize_t parse_detach(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
return set_led_id(led_card, buf, count, false);
}
static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
int err;
if (count > 0 && buf[0] == '1') {
err = snd_ctl_led_reset(led_card->number, led_card->led->group);
if (err < 0)
return err;
}
return count;
}
static ssize_t ctl_list(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
struct snd_card *card;
struct snd_ctl_led_ctl *lctl;
char *buf2 = buf;
size_t l;
card = snd_card_ref(led_card->number);
if (!card)
return -ENXIO;
down_read(&card->controls_rwsem);
mutex_lock(&snd_ctl_led_mutex);
if (snd_ctl_led_card_valid[led_card->number]) {
list_for_each_entry(lctl, &led_card->led->controls, list)
if (lctl->card == card) {
if (buf2 - buf > PAGE_SIZE - 16)
break;
if (buf2 != buf)
*buf2++ = ' ';
l = scnprintf(buf2, 15, "%u",
lctl->kctl->id.numid +
lctl->index_offset);
buf2[l] = '\0';
buf2 += l + 1;
}
}
mutex_unlock(&snd_ctl_led_mutex);
up_read(&card->controls_rwsem);
snd_card_unref(card);
return buf2 - buf;
}
static DEVICE_ATTR(attach, 0200, NULL, parse_attach);
static DEVICE_ATTR(detach, 0200, NULL, parse_detach);
static DEVICE_ATTR(reset, 0200, NULL, ctl_reset);
static DEVICE_ATTR(list, 0444, ctl_list, NULL);
static struct attribute *snd_ctl_led_card_attrs[] = {
&dev_attr_attach.attr,
&dev_attr_detach.attr,
&dev_attr_reset.attr,
&dev_attr_list.attr,
NULL,
};
static const struct attribute_group snd_ctl_led_card_attr_group = {
.attrs = snd_ctl_led_card_attrs,
};
static const struct attribute_group *snd_ctl_led_card_attr_groups[] = {
&snd_ctl_led_card_attr_group,
NULL,
};
static struct device snd_ctl_led_dev;
static void snd_ctl_led_sysfs_add(struct snd_card *card)
{
unsigned int group;
struct snd_ctl_led_card *led_card;
struct snd_ctl_led *led;
char link_name[32];
for (group = 0; group < MAX_LED; group++) {
led = &snd_ctl_leds[group];
led_card = kzalloc(sizeof(*led_card), GFP_KERNEL);
if (!led_card)
goto cerr2;
led_card->number = card->number;
led_card->led = led;
device_initialize(&led_card->dev);
if (dev_set_name(&led_card->dev, "card%d", card->number) < 0)
goto cerr;
led_card->dev.parent = &led->dev;
led_card->dev.groups = snd_ctl_led_card_attr_groups;
if (device_add(&led_card->dev))
goto cerr;
led->cards[card->number] = led_card;
snprintf(link_name, sizeof(link_name), "led-%s", led->name);
WARN(sysfs_create_link(&card->ctl_dev.kobj, &led_card->dev.kobj, link_name),
"can't create symlink to controlC%i device\n", card->number);
WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"),
"can't create symlink to card%i\n", card->number);
continue;
cerr:
put_device(&led_card->dev);
cerr2:
printk(KERN_ERR "snd_ctl_led: unable to add card%d", card->number);
kfree(led_card);
}
}
static void snd_ctl_led_sysfs_remove(struct snd_card *card)
{
unsigned int group;
struct snd_ctl_led_card *led_card;
struct snd_ctl_led *led;
char link_name[32];
for (group = 0; group < MAX_LED; group++) {
led = &snd_ctl_leds[group];
led_card = led->cards[card->number];
if (!led_card)
continue;
snprintf(link_name, sizeof(link_name), "led-%s", led->name);
sysfs_remove_link(&card->ctl_dev.kobj, link_name);
sysfs_remove_link(&led_card->dev.kobj, "card");
device_del(&led_card->dev);
kfree(led_card);
led->cards[card->number] = NULL;
}
}
/*
* Control layer registration
*/
static struct snd_ctl_layer_ops snd_ctl_led_lops = {
.module_name = SND_CTL_LAYER_MODULE_LED,
.lregister = snd_ctl_led_register,
.ldisconnect = snd_ctl_led_disconnect,
.lnotify = snd_ctl_led_notify,
};
static int __init snd_ctl_led_init(void)
{
struct snd_ctl_led *led;
unsigned int group;
device_initialize(&snd_ctl_led_dev);
snd_ctl_led_dev.class = sound_class;
dev_set_name(&snd_ctl_led_dev, "ctl-led");
if (device_add(&snd_ctl_led_dev)) {
put_device(&snd_ctl_led_dev);
return -ENOMEM;
}
for (group = 0; group < MAX_LED; group++) {
led = &snd_ctl_leds[group];
INIT_LIST_HEAD(&led->controls);
device_initialize(&led->dev);
led->dev.parent = &snd_ctl_led_dev;
led->dev.groups = snd_ctl_led_dev_attr_groups;
dev_set_name(&led->dev, led->name);
if (device_add(&led->dev)) {
put_device(&led->dev);
for (; group > 0; group--) {
led = &snd_ctl_leds[group];
device_del(&led->dev);
}
device_del(&snd_ctl_led_dev);
return -ENOMEM;
}
}
snd_ctl_register_layer(&snd_ctl_led_lops);
return 0;
}
static void __exit snd_ctl_led_exit(void)
{
struct snd_ctl_led *led;
struct snd_card *card;
unsigned int group, card_number;
snd_ctl_disconnect_layer(&snd_ctl_led_lops);
for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
if (!snd_ctl_led_card_valid[card_number])
continue;
card = snd_card_ref(card_number);
if (card) {
snd_ctl_led_sysfs_remove(card);
snd_card_unref(card);
}
}
for (group = 0; group < MAX_LED; group++) {
led = &snd_ctl_leds[group];
device_del(&led->dev);
}
device_del(&snd_ctl_led_dev);
snd_ctl_led_clean(NULL);
}
module_init(snd_ctl_led_init)
module_exit(snd_ctl_led_exit)

View File

@ -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.

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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 */

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 =

View File

@ -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);

View File

@ -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

View File

@ -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),)

View File

@ -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.

View File

@ -1,27 +1,8 @@
/*
* 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;
struct device *dev = &pdev->dev;
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;
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");

View File

@ -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");

View File

@ -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,

View File

@ -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,
};

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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)

View File

@ -9,6 +9,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@ -23,6 +24,11 @@
#include "ak5558.h"
enum ak555x_type {
AK5558,
AK5552,
};
#define AK5558_NUM_SUPPLIES 2
static const char *ak5558_supply_names[AK5558_NUM_SUPPLIES] = {
"DVDD",
@ -59,9 +65,18 @@ static const struct soc_enum ak5558_mono_enum[] = {
ARRAY_SIZE(mono_texts), mono_texts),
};
static const char * const mono_5552_texts[] = {
"2 Slot", "1 Slot (Fixed)", "2 Slot", "1 Slot (Optimal)",
};
static const struct soc_enum ak5552_mono_enum[] = {
SOC_ENUM_SINGLE(AK5558_01_POWER_MANAGEMENT2, 1,
ARRAY_SIZE(mono_5552_texts), mono_5552_texts),
};
static const char * const digfil_texts[] = {
"Sharp Roll-Off", "Show Roll-Off",
"Short Delay Sharp Roll-Off", "Short Delay Show Roll-Off",
"Sharp Roll-Off", "Slow Roll-Off",
"Short Delay Sharp Roll-Off", "Short Delay Slow Roll-Off",
};
static const struct soc_enum ak5558_adcset_enum[] = {
@ -70,8 +85,13 @@ static const struct soc_enum ak5558_adcset_enum[] = {
};
static const struct snd_kcontrol_new ak5558_snd_controls[] = {
SOC_ENUM("AK5558 Monaural Mode", ak5558_mono_enum[0]),
SOC_ENUM("AK5558 Digital Filter", ak5558_adcset_enum[0]),
SOC_ENUM("Monaural Mode", ak5558_mono_enum[0]),
SOC_ENUM("Digital Filter", ak5558_adcset_enum[0]),
};
static const struct snd_kcontrol_new ak5552_snd_controls[] = {
SOC_ENUM("Monaural Mode", ak5552_mono_enum[0]),
SOC_ENUM("Digital Filter", ak5558_adcset_enum[0]),
};
static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = {
@ -97,6 +117,17 @@ static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("SDTO", "Capture", 0, SND_SOC_NOPM, 0, 0),
};
static const struct snd_soc_dapm_widget ak5552_dapm_widgets[] = {
/* Analog Input */
SND_SOC_DAPM_INPUT("AIN1"),
SND_SOC_DAPM_INPUT("AIN2"),
SND_SOC_DAPM_ADC("ADC Ch1", NULL, AK5558_00_POWER_MANAGEMENT1, 0, 0),
SND_SOC_DAPM_ADC("ADC Ch2", NULL, AK5558_00_POWER_MANAGEMENT1, 1, 0),
SND_SOC_DAPM_AIF_OUT("SDTO", "Capture", 0, SND_SOC_NOPM, 0, 0),
};
static const struct snd_soc_dapm_route ak5558_intercon[] = {
{"ADC Ch1", NULL, "AIN1"},
{"SDTO", NULL, "ADC Ch1"},
@ -123,6 +154,14 @@ static const struct snd_soc_dapm_route ak5558_intercon[] = {
{"SDTO", NULL, "ADC Ch8"},
};
static const struct snd_soc_dapm_route ak5552_intercon[] = {
{"ADC Ch1", NULL, "AIN1"},
{"SDTO", NULL, "ADC Ch1"},
{"ADC Ch2", NULL, "AIN2"},
{"SDTO", NULL, "ADC Ch2"},
};
static int ak5558_set_mcki(struct snd_soc_component *component)
{
return snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_CKS,
@ -267,21 +306,24 @@ static struct snd_soc_dai_driver ak5558_dai = {
.ops = &ak5558_dai_ops,
};
static void ak5558_power_off(struct ak5558_priv *ak5558)
static struct snd_soc_dai_driver ak5552_dai = {
.name = "ak5558-aif",
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = AK5558_FORMATS,
},
.ops = &ak5558_dai_ops,
};
static void ak5558_reset(struct ak5558_priv *ak5558, bool active)
{
if (!ak5558->reset_gpiod)
return;
gpiod_set_value_cansleep(ak5558->reset_gpiod, 0);
usleep_range(1000, 2000);
}
static void ak5558_power_on(struct ak5558_priv *ak5558)
{
if (!ak5558->reset_gpiod)
return;
gpiod_set_value_cansleep(ak5558->reset_gpiod, 1);
gpiod_set_value_cansleep(ak5558->reset_gpiod, active);
usleep_range(1000, 2000);
}
@ -289,7 +331,7 @@ static int ak5558_probe(struct snd_soc_component *component)
{
struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
ak5558_power_on(ak5558);
ak5558_reset(ak5558, false);
return ak5558_set_mcki(component);
}
@ -297,7 +339,7 @@ static void ak5558_remove(struct snd_soc_component *component)
{
struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
ak5558_power_off(ak5558);
ak5558_reset(ak5558, true);
}
static int __maybe_unused ak5558_runtime_suspend(struct device *dev)
@ -305,7 +347,7 @@ static int __maybe_unused ak5558_runtime_suspend(struct device *dev)
struct ak5558_priv *ak5558 = dev_get_drvdata(dev);
regcache_cache_only(ak5558->regmap, true);
ak5558_power_off(ak5558);
ak5558_reset(ak5558, true);
regulator_bulk_disable(ARRAY_SIZE(ak5558->supplies),
ak5558->supplies);
@ -324,8 +366,8 @@ static int __maybe_unused ak5558_runtime_resume(struct device *dev)
return ret;
}
ak5558_power_off(ak5558);
ak5558_power_on(ak5558);
ak5558_reset(ak5558, true);
ak5558_reset(ak5558, false);
regcache_cache_only(ak5558->regmap, false);
regcache_mark_dirty(ak5558->regmap);
@ -354,6 +396,21 @@ static const struct snd_soc_component_driver soc_codec_dev_ak5558 = {
.non_legacy_dai_naming = 1,
};
static const struct snd_soc_component_driver soc_codec_dev_ak5552 = {
.probe = ak5558_probe,
.remove = ak5558_remove,
.controls = ak5552_snd_controls,
.num_controls = ARRAY_SIZE(ak5552_snd_controls),
.dapm_widgets = ak5552_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak5552_dapm_widgets),
.dapm_routes = ak5552_intercon,
.num_dapm_routes = ARRAY_SIZE(ak5552_intercon),
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static const struct regmap_config ak5558_regmap = {
.reg_bits = 8,
.val_bits = 8,
@ -368,6 +425,7 @@ static int ak5558_i2c_probe(struct i2c_client *i2c)
{
struct ak5558_priv *ak5558;
int ret = 0;
int dev_id;
int i;
ak5558 = devm_kzalloc(&i2c->dev, sizeof(*ak5558), GFP_KERNEL);
@ -396,11 +454,26 @@ static int ak5558_i2c_probe(struct i2c_client *i2c)
return ret;
}
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_codec_dev_ak5558,
&ak5558_dai, 1);
if (ret)
dev_id = (uintptr_t)of_device_get_match_data(&i2c->dev);
switch (dev_id) {
case AK5552:
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_codec_dev_ak5552,
&ak5552_dai, 1);
break;
case AK5558:
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_codec_dev_ak5558,
&ak5558_dai, 1);
break;
default:
dev_err(&i2c->dev, "unexpected device type\n");
return -EINVAL;
}
if (ret < 0) {
dev_err(&i2c->dev, "failed to register component: %d\n", ret);
return ret;
}
pm_runtime_enable(&i2c->dev);
regcache_cache_only(ak5558->regmap, true);
@ -416,7 +489,8 @@ static int ak5558_i2c_remove(struct i2c_client *i2c)
}
static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = {
{ .compatible = "asahi-kasei,ak5558"},
{ .compatible = "asahi-kasei,ak5558", .data = (void *) AK5558 },
{ .compatible = "asahi-kasei,ak5552", .data = (void *) AK5552 },
{ }
};
MODULE_DEVICE_TABLE(of, ak5558_i2c_dt_ids);

View File

@ -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

View File

@ -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;

View File

@ -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++)

View File

@ -1721,7 +1721,7 @@ static int cs35l36_i2c_probe(struct i2c_client *i2c_client,
if (IS_ERR(cs35l36->regmap)) {
ret = PTR_ERR(cs35l36->regmap);
dev_err(dev, "regmap_init() failed: %d\n", ret);
goto err;
return ret;
}
cs35l36->num_supplies = ARRAY_SIZE(cs35l36_supplies);

View File

@ -400,6 +400,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
* cs4270_dai_mute - enable/disable the CS4270 external mute
* @dai: the SOC DAI
* @mute: 0 = disable mute, 1 = enable mute
* @direction: (ignored)
*
* This function toggles the mute bits in the MUTE register. The CS4270's
* mute capability is intended for external muting circuitry, so if the

View File

@ -25,6 +25,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@ -461,64 +462,78 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = {
0x3f, 1, mixer_tlv)
};
static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
if (event & SND_SOC_DAPM_POST_PMU) {
/* Enable the channels */
snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN,
CS42L42_ASP_RX0_CH_EN_MASK,
(CS42L42_ASP_RX0_CH1_EN |
CS42L42_ASP_RX0_CH2_EN) <<
CS42L42_ASP_RX0_CH_EN_SHIFT);
/* Power up */
snd_soc_component_update_bits(component, CS42L42_PWR_CTL1,
CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
CS42L42_HP_PDN_MASK, 0);
} else if (event & SND_SOC_DAPM_PRE_PMD) {
/* Disable the channels */
snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN,
CS42L42_ASP_RX0_CH_EN_MASK, 0);
/* Power down */
snd_soc_component_update_bits(component, CS42L42_PWR_CTL1,
CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
CS42L42_HP_PDN_MASK,
CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
CS42L42_HP_PDN_MASK);
} else {
dev_err(component->dev, "Invalid event 0x%x\n", event);
}
return 0;
}
static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = {
/* Playback Path */
SND_SOC_DAPM_OUTPUT("HP"),
SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS42L42_ASP_CLK_CFG,
CS42L42_ASP_SCLK_EN_SHIFT, false),
SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0,
0, NULL, 0, cs42l42_hpdrv_evt,
SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD)
SND_SOC_DAPM_DAC("DAC", NULL, CS42L42_PWR_CTL1, CS42L42_HP_PDN_SHIFT, 1),
SND_SOC_DAPM_MIXER("MIXER", CS42L42_PWR_CTL1, CS42L42_MIXER_PDN_SHIFT, 1, NULL, 0),
SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, CS42L42_ASP_RX_DAI0_EN, CS42L42_ASP_RX0_CH1_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, CS42L42_ASP_RX_DAI0_EN, CS42L42_ASP_RX0_CH2_SHIFT, 0),
/* Playback Requirements */
SND_SOC_DAPM_SUPPLY("ASP DAI0", CS42L42_PWR_CTL1, CS42L42_ASP_DAI_PDN_SHIFT, 1, NULL, 0),
/* Capture Path */
SND_SOC_DAPM_INPUT("HS"),
SND_SOC_DAPM_ADC("ADC", NULL, CS42L42_PWR_CTL1, CS42L42_ADC_PDN_SHIFT, 1),
SND_SOC_DAPM_AIF_OUT("SDOUT1", NULL, 0, CS42L42_ASP_TX_CH_EN, CS42L42_ASP_TX0_CH1_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("SDOUT2", NULL, 1, CS42L42_ASP_TX_CH_EN, CS42L42_ASP_TX0_CH2_SHIFT, 0),
/* Capture Requirements */
SND_SOC_DAPM_SUPPLY("ASP DAO0", CS42L42_PWR_CTL1, CS42L42_ASP_DAO_PDN_SHIFT, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("ASP TX EN", CS42L42_ASP_TX_SZ_EN, CS42L42_ASP_TX_EN_SHIFT, 0, NULL, 0),
/* Playback/Capture Requirements */
SND_SOC_DAPM_SUPPLY("SCLK", CS42L42_ASP_CLK_CFG, CS42L42_ASP_SCLK_EN_SHIFT, 0, NULL, 0),
};
static const struct snd_soc_dapm_route cs42l42_audio_map[] = {
{"SDIN", NULL, "Playback"},
{"HPDRV", NULL, "SDIN"},
{"HP", NULL, "HPDRV"}
/* Playback Path */
{"HP", NULL, "DAC"},
{"DAC", NULL, "MIXER"},
{"MIXER", NULL, "SDIN1"},
{"MIXER", NULL, "SDIN2"},
{"SDIN1", NULL, "Playback"},
{"SDIN2", NULL, "Playback"},
/* Playback Requirements */
{"SDIN1", NULL, "ASP DAI0"},
{"SDIN2", NULL, "ASP DAI0"},
{"SDIN1", NULL, "SCLK"},
{"SDIN2", NULL, "SCLK"},
/* Capture Path */
{"ADC", NULL, "HS"},
{ "SDOUT1", NULL, "ADC" },
{ "SDOUT2", NULL, "ADC" },
{ "Capture", NULL, "SDOUT1" },
{ "Capture", NULL, "SDOUT2" },
/* Capture Requirements */
{ "SDOUT1", NULL, "ASP DAO0" },
{ "SDOUT2", NULL, "ASP DAO0" },
{ "SDOUT1", NULL, "SCLK" },
{ "SDOUT2", NULL, "SCLK" },
{ "SDOUT1", NULL, "ASP TX EN" },
{ "SDOUT2", NULL, "ASP TX EN" },
};
static int cs42l42_component_probe(struct snd_soc_component *component)
{
struct cs42l42_private *cs42l42 =
(struct cs42l42_private *)snd_soc_component_get_drvdata(component);
struct snd_soc_card *crd = component->card;
int ret = 0;
cs42l42->component = component;
return 0;
ret = snd_soc_card_jack_new(crd, "CS42L42 Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3,
&cs42l42->jack, NULL, 0);
if (ret < 0)
dev_err(component->dev, "Cannot create CS42L42 Headset: %d\n", ret);
return ret;
}
static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
@ -534,6 +549,24 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
.non_legacy_dai_naming = 1,
};
/* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */
static const struct reg_sequence cs42l42_to_sclk_seq[] = {
{
.reg = CS42L42_OSC_SWITCH,
.def = CS42L42_SCLK_PRESENT_MASK,
.delay_us = CS42L42_CLOCK_SWITCH_DELAY_US,
},
};
/* Switch to OSC. Atomic delay after the write to allow the switch to complete. */
static const struct reg_sequence cs42l42_to_osc_seq[] = {
{
.reg = CS42L42_OSC_SWITCH,
.def = 0,
.delay_us = CS42L42_CLOCK_SWITCH_DELAY_US,
},
};
struct cs42l42_pll_params {
u32 sclk;
u8 mclk_div;
@ -573,10 +606,16 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
{
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
int i;
u32 clk;
u32 fsync;
if (!cs42l42->sclk)
clk = cs42l42->bclk;
else
clk = cs42l42->sclk;
for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
if (pll_ratio_table[i].sclk == cs42l42->sclk) {
if (pll_ratio_table[i].sclk == clk) {
/* Configure the internal sample rate */
snd_soc_component_update_bits(component, CS42L42_MCLK_CTL,
CS42L42_INTERNAL_FS_MASK,
@ -596,12 +635,12 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
(pll_ratio_table[i].mclk_div <<
CS42L42_MCLKDIV_SHIFT));
/* Set up the LRCLK */
fsync = cs42l42->sclk / cs42l42->srate;
if (((fsync * cs42l42->srate) != cs42l42->sclk)
fsync = clk / cs42l42->srate;
if (((fsync * cs42l42->srate) != clk)
|| ((fsync % 2) != 0)) {
dev_err(component->dev,
"Unsupported sclk %d/sample rate %d\n",
cs42l42->sclk,
clk,
cs42l42->srate);
return -EINVAL;
}
@ -768,12 +807,25 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
unsigned int channels = params_channels(params);
unsigned int width = (params_width(params) / 8) - 1;
unsigned int val = 0;
cs42l42->srate = params_rate(params);
cs42l42->bclk = snd_soc_params_to_bclk(params);
switch(substream->stream) {
case SNDRV_PCM_STREAM_CAPTURE:
if (channels == 2) {
val |= CS42L42_ASP_TX_CH2_AP_MASK;
val |= width << CS42L42_ASP_TX_CH2_RES_SHIFT;
}
val |= width << CS42L42_ASP_TX_CH1_RES_SHIFT;
snd_soc_component_update_bits(component, CS42L42_ASP_TX_CH_AP_RES,
CS42L42_ASP_TX_CH1_AP_MASK | CS42L42_ASP_TX_CH2_AP_MASK |
CS42L42_ASP_TX_CH2_RES_MASK | CS42L42_ASP_TX_CH1_RES_MASK, val);
break;
case SNDRV_PCM_STREAM_PLAYBACK:
val |= width << CS42L42_ASP_RX_CH_RES_SHIFT;
/* channel 1 on low LRCLK */
@ -804,52 +856,73 @@ static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
return 0;
}
static int cs42l42_mute(struct snd_soc_dai *dai, int mute, int direction)
static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_component *component = dai->component;
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
unsigned int regval;
u8 fullScaleVol;
int ret;
if (mute) {
/* Mark SCLK as not present to turn on the internal
* oscillator.
*/
snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
CS42L42_SCLK_PRESENT_MASK, 0);
snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
CS42L42_PLL_START_MASK,
0 << CS42L42_PLL_START_SHIFT);
/* Mute the headphone */
snd_soc_component_update_bits(component, CS42L42_HP_CTL,
CS42L42_HP_ANA_AMUTE_MASK |
CS42L42_HP_ANA_BMUTE_MASK,
CS42L42_HP_ANA_AMUTE_MASK |
CS42L42_HP_ANA_BMUTE_MASK);
} else {
snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
CS42L42_PLL_START_MASK,
1 << CS42L42_PLL_START_SHIFT);
/* Read the headphone load */
regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT);
if (((regval & CS42L42_RLA_STAT_MASK) >>
CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) {
fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
} else {
fullScaleVol = 0;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_component_update_bits(component, CS42L42_HP_CTL,
CS42L42_HP_ANA_AMUTE_MASK |
CS42L42_HP_ANA_BMUTE_MASK,
CS42L42_HP_ANA_AMUTE_MASK |
CS42L42_HP_ANA_BMUTE_MASK);
cs42l42->stream_use &= ~(1 << stream);
if(!cs42l42->stream_use) {
/*
* Switch to the internal oscillator.
* SCLK must remain running until after this clock switch.
* Without a source of clock the I2C bus doesn't work.
*/
regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_osc_seq,
ARRAY_SIZE(cs42l42_to_osc_seq));
snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
CS42L42_PLL_START_MASK, 0);
}
} else {
if (!cs42l42->stream_use) {
/* SCLK must be running before codec unmute */
if ((cs42l42->bclk < 11289600) && (cs42l42->sclk < 11289600)) {
snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
CS42L42_PLL_START_MASK, 1);
ret = regmap_read_poll_timeout(cs42l42->regmap,
CS42L42_PLL_LOCK_STATUS,
regval,
(regval & 1),
CS42L42_PLL_LOCK_POLL_US,
CS42L42_PLL_LOCK_TIMEOUT_US);
if (ret < 0)
dev_warn(component->dev, "PLL failed to lock: %d\n", ret);
}
/* Un-mute the headphone, set the full scale volume flag */
snd_soc_component_update_bits(component, CS42L42_HP_CTL,
CS42L42_HP_ANA_AMUTE_MASK |
CS42L42_HP_ANA_BMUTE_MASK |
CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
/* Mark SCLK as present, turn off internal oscillator */
regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_sclk_seq,
ARRAY_SIZE(cs42l42_to_sclk_seq));
}
cs42l42->stream_use |= 1 << stream;
/* Mark SCLK as present, turn off internal oscillator */
snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
CS42L42_SCLK_PRESENT_MASK,
CS42L42_SCLK_PRESENT_MASK);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* Read the headphone load */
regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT);
if (((regval & CS42L42_RLA_STAT_MASK) >> CS42L42_RLA_STAT_SHIFT) ==
CS42L42_RLA_STAT_15_OHM) {
fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
} else {
fullScaleVol = 0;
}
/* Un-mute the headphone, set the full scale volume flag */
snd_soc_component_update_bits(component, CS42L42_HP_CTL,
CS42L42_HP_ANA_AMUTE_MASK |
CS42L42_HP_ANA_BMUTE_MASK |
CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
}
}
return 0;
@ -864,8 +937,7 @@ static const struct snd_soc_dai_ops cs42l42_ops = {
.hw_params = cs42l42_pcm_hw_params,
.set_fmt = cs42l42_set_dai_fmt,
.set_sysclk = cs42l42_set_sysclk,
.mute_stream = cs42l42_mute,
.no_capture_mute = 1,
.mute_stream = cs42l42_mute_stream,
};
static struct snd_soc_dai_driver cs42l42_dai = {
@ -884,6 +956,8 @@ static struct snd_soc_dai_driver cs42l42_dai = {
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = CS42L42_FORMATS,
},
.symmetric_rate = 1,
.symmetric_sample_bits = 1,
.ops = &cs42l42_ops,
};
@ -1169,7 +1243,7 @@ static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42)
(3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
}
static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
static int cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
{
int bias_level;
unsigned int detect_status;
@ -1212,17 +1286,24 @@ static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
switch (bias_level) {
case 1: /* Function C button press */
bias_level = SND_JACK_BTN_2;
dev_dbg(cs42l42->component->dev, "Function C button press\n");
break;
case 2: /* Function B button press */
bias_level = SND_JACK_BTN_1;
dev_dbg(cs42l42->component->dev, "Function B button press\n");
break;
case 3: /* Function D button press */
bias_level = SND_JACK_BTN_3;
dev_dbg(cs42l42->component->dev, "Function D button press\n");
break;
case 4: /* Function A button press */
bias_level = SND_JACK_BTN_0;
dev_dbg(cs42l42->component->dev, "Function A button press\n");
break;
default:
bias_level = 0;
break;
}
/* Set button detect level sensitivity back to default */
@ -1252,6 +1333,8 @@ static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
(0 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
(1 << CS42L42_M_SHORT_RLS_SHIFT) |
(1 << CS42L42_M_SHORT_DET_SHIFT));
return bias_level;
}
struct cs42l42_irq_params {
@ -1296,6 +1379,8 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
unsigned int current_plug_status;
unsigned int current_button_status;
unsigned int i;
int report = 0;
/* Read sticky registers to clear interurpt */
for (i = 0; i < ARRAY_SIZE(stickies); i++) {
@ -1322,9 +1407,20 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
if ((~masks[5]) & irq_params_table[5].mask) {
if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) {
cs42l42_process_hs_type_detect(cs42l42);
dev_dbg(component->dev,
"Auto detect done (%d)\n",
cs42l42->hs_type);
switch(cs42l42->hs_type){
case CS42L42_PLUG_CTIA:
case CS42L42_PLUG_OMTP:
snd_soc_jack_report(&cs42l42->jack, SND_JACK_HEADSET,
SND_JACK_HEADSET);
break;
case CS42L42_PLUG_HEADPHONE:
snd_soc_jack_report(&cs42l42->jack, SND_JACK_HEADPHONE,
SND_JACK_HEADPHONE);
break;
default:
break;
}
dev_dbg(component->dev, "Auto detect done (%d)\n", cs42l42->hs_type);
}
}
@ -1342,8 +1438,19 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
if (cs42l42->plug_state != CS42L42_TS_UNPLUG) {
cs42l42->plug_state = CS42L42_TS_UNPLUG;
cs42l42_cancel_hs_type_detect(cs42l42);
dev_dbg(component->dev,
"Unplug event\n");
switch(cs42l42->hs_type){
case CS42L42_PLUG_CTIA:
case CS42L42_PLUG_OMTP:
snd_soc_jack_report(&cs42l42->jack, 0, SND_JACK_HEADSET);
break;
case CS42L42_PLUG_HEADPHONE:
snd_soc_jack_report(&cs42l42->jack, 0, SND_JACK_HEADPHONE);
break;
default:
break;
}
dev_dbg(component->dev, "Unplug event\n");
}
break;
@ -1358,14 +1465,15 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
if (!(current_button_status &
CS42L42_M_HSBIAS_HIZ_MASK)) {
if (current_button_status &
CS42L42_M_DETECT_TF_MASK) {
dev_dbg(component->dev,
"Button released\n");
} else if (current_button_status &
CS42L42_M_DETECT_FT_MASK) {
cs42l42_handle_button_press(cs42l42);
if (current_button_status & CS42L42_M_DETECT_TF_MASK) {
dev_dbg(component->dev, "Button released\n");
report = 0;
} else if (current_button_status & CS42L42_M_DETECT_FT_MASK) {
report = cs42l42_handle_button_press(cs42l42);
}
snd_soc_jack_report(&cs42l42->jack, report, SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3);
}
}
@ -1749,8 +1857,10 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
/* Reset the Device */
cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(cs42l42->reset_gpio))
return PTR_ERR(cs42l42->reset_gpio);
if (IS_ERR(cs42l42->reset_gpio)) {
ret = PTR_ERR(cs42l42->reset_gpio);
goto err_disable;
}
if (cs42l42->reset_gpio) {
dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
@ -1784,13 +1894,13 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
dev_err(&i2c_client->dev,
"CS42L42 Device ID (%X). Expected %X\n",
devid, CS42L42_CHIP_ID);
return ret;
goto err_disable;
}
ret = regmap_read(cs42l42->regmap, CS42L42_REVID, &reg);
if (ret < 0) {
dev_err(&i2c_client->dev, "Get Revision ID failed\n");
return ret;
goto err_disable;
}
dev_info(&i2c_client->dev,
@ -1816,7 +1926,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
if (i2c_client->dev.of_node) {
ret = cs42l42_handle_device_data(i2c_client, cs42l42);
if (ret != 0)
return ret;
goto err_disable;
}
/* Setup headset detection */
@ -1842,8 +1952,9 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
{
struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client);
/* Hold down reset */
gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
devm_free_irq(&i2c_client->dev, i2c_client->irq, cs42l42);
pm_runtime_suspend(&i2c_client->dev);
pm_runtime_disable(&i2c_client->dev);
return 0;
}

View File

@ -12,6 +12,8 @@
#ifndef __CS42L42_H__
#define __CS42L42_H__
#include <sound/jack.h>
#define CS42L42_PAGE_REGISTER 0x00 /* Page Select Register */
#define CS42L42_WIN_START 0x00
#define CS42L42_WIN_LEN 0x100
@ -683,8 +685,20 @@
/* Page 0x29 Serial Port TX Registers */
#define CS42L42_ASP_TX_SZ_EN (CS42L42_PAGE_29 + 0x01)
#define CS42L42_ASP_TX_EN_SHIFT 0
#define CS42L42_ASP_TX_CH_EN (CS42L42_PAGE_29 + 0x02)
#define CS42L42_ASP_TX0_CH2_SHIFT 1
#define CS42L42_ASP_TX0_CH1_SHIFT 0
#define CS42L42_ASP_TX_CH_AP_RES (CS42L42_PAGE_29 + 0x03)
#define CS42L42_ASP_TX_CH1_AP_SHIFT 7
#define CS42L42_ASP_TX_CH1_AP_MASK (1 << CS42L42_ASP_TX_CH1_AP_SHIFT)
#define CS42L42_ASP_TX_CH2_AP_SHIFT 6
#define CS42L42_ASP_TX_CH2_AP_MASK (1 << CS42L42_ASP_TX_CH2_AP_SHIFT)
#define CS42L42_ASP_TX_CH2_RES_SHIFT 2
#define CS42L42_ASP_TX_CH2_RES_MASK (3 << CS42L42_ASP_TX_CH2_RES_SHIFT)
#define CS42L42_ASP_TX_CH1_RES_SHIFT 0
#define CS42L42_ASP_TX_CH1_RES_MASK (3 << CS42L42_ASP_TX_CH1_RES_SHIFT)
#define CS42L42_ASP_TX_CH1_BIT_MSB (CS42L42_PAGE_29 + 0x04)
#define CS42L42_ASP_TX_CH1_BIT_LSB (CS42L42_PAGE_29 + 0x05)
#define CS42L42_ASP_TX_HIZ_DLY_CFG (CS42L42_PAGE_29 + 0x06)
@ -695,10 +709,10 @@
#define CS42L42_ASP_RX_DAI0_EN (CS42L42_PAGE_2A + 0x01)
#define CS42L42_ASP_RX0_CH_EN_SHIFT 2
#define CS42L42_ASP_RX0_CH_EN_MASK (0xf << CS42L42_ASP_RX0_CH_EN_SHIFT)
#define CS42L42_ASP_RX0_CH1_EN 1
#define CS42L42_ASP_RX0_CH2_EN 2
#define CS42L42_ASP_RX0_CH3_EN 4
#define CS42L42_ASP_RX0_CH4_EN 8
#define CS42L42_ASP_RX0_CH1_SHIFT 2
#define CS42L42_ASP_RX0_CH2_SHIFT 3
#define CS42L42_ASP_RX0_CH3_SHIFT 4
#define CS42L42_ASP_RX0_CH4_SHIFT 5
#define CS42L42_ASP_RX_DAI0_CH1_AP_RES (CS42L42_PAGE_2A + 0x02)
#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x03)
@ -741,6 +755,9 @@
#define CS42L42_NUM_SUPPLIES 5
#define CS42L42_BOOT_TIME_US 3000
#define CS42L42_CLOCK_SWITCH_DELAY_US 150
#define CS42L42_PLL_LOCK_POLL_US 250
#define CS42L42_PLL_LOCK_TIMEOUT_US 1250
static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
"VA",
@ -756,6 +773,8 @@ struct cs42l42_private {
struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES];
struct gpio_desc *reset_gpio;
struct completion pdn_done;
struct snd_soc_jack jack;
int bclk;
u32 sclk;
u32 srate;
u8 plug_state;
@ -768,6 +787,7 @@ struct cs42l42_private {
u8 bias_thresholds[CS42L42_NUM_BIASES];
u8 hs_bias_ramp_rate;
u8 hs_bias_ramp_time;
u8 stream_use;
};
#endif /* __CS42L42_H__ */

View File

@ -827,9 +827,6 @@ static int cx2072x_config_i2spcm(struct cx2072x_priv *cx2072x)
}
regdbt2.r.i2s_bclk_invert = is_bclk_inv;
reg1.r.rx_data_one_line = 1;
reg1.r.tx_data_one_line = 1;
/* Configures the BCLK output */
bclk_rate = cx2072x->sample_rate * frame_len;
reg5.r.i2s_pcm_clk_div_chan_en = 0;
@ -1433,11 +1430,11 @@ static int cx2072x_jack_status_check(void *data)
state |= SND_JACK_HEADSET;
if (type & 0x2)
state |= SND_JACK_BTN_0;
} else if (type & 0x4) {
/* Nokia headset */
state |= SND_JACK_HEADPHONE;
} else {
/* Headphone */
/*
* Nokia headset (type & 0x4) and
* regular Headphone
*/
state |= SND_JACK_HEADPHONE;
}
}
@ -1535,7 +1532,7 @@ static const struct snd_soc_component_driver soc_codec_driver_cx2072x = {
/*
* DAI ops
*/
static struct snd_soc_dai_ops cx2072x_dai_ops = {
static const struct snd_soc_dai_ops cx2072x_dai_ops = {
.set_sysclk = cx2072x_set_dai_sysclk,
.set_fmt = cx2072x_set_dai_fmt,
.hw_params = cx2072x_hw_params,

View File

@ -115,7 +115,7 @@ static void da7219_aad_hptest_work(struct work_struct *work)
__le16 tonegen_freq_hptest;
u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8;
int report = 0, ret = 0;
int report = 0, ret;
/* Lock DAPM, Kcontrols affected by this test and the PLL */
snd_soc_dapm_mutex_lock(dapm);

View File

@ -2181,7 +2181,10 @@ static int da7219_register_dai_clks(struct snd_soc_component *component)
ret);
goto err;
}
da7219->dai_clks[i] = dai_clk_hw->clk;
da7219->dai_clks[i] = devm_clk_hw_get_clk(dev, dai_clk_hw, NULL);
if (IS_ERR(da7219->dai_clks[i]))
return PTR_ERR(da7219->dai_clks[i]);
/* For DT setup onecell data, otherwise create lookup */
if (np) {

View File

@ -168,30 +168,25 @@ static const struct reg_default da732x_reg_cache[] = {
static inline int da732x_get_input_div(struct snd_soc_component *component, int sysclk)
{
int val;
int ret;
if (sysclk < DA732X_MCLK_10MHZ) {
val = DA732X_MCLK_RET_0_10MHZ;
ret = DA732X_MCLK_VAL_0_10MHZ;
val = DA732X_MCLK_VAL_0_10MHZ;
} else if ((sysclk >= DA732X_MCLK_10MHZ) &&
(sysclk < DA732X_MCLK_20MHZ)) {
val = DA732X_MCLK_RET_10_20MHZ;
ret = DA732X_MCLK_VAL_10_20MHZ;
val = DA732X_MCLK_VAL_10_20MHZ;
} else if ((sysclk >= DA732X_MCLK_20MHZ) &&
(sysclk < DA732X_MCLK_40MHZ)) {
val = DA732X_MCLK_RET_20_40MHZ;
ret = DA732X_MCLK_VAL_20_40MHZ;
val = DA732X_MCLK_VAL_20_40MHZ;
} else if ((sysclk >= DA732X_MCLK_40MHZ) &&
(sysclk <= DA732X_MCLK_54MHZ)) {
val = DA732X_MCLK_RET_40_54MHZ;
ret = DA732X_MCLK_VAL_40_54MHZ;
val = DA732X_MCLK_VAL_40_54MHZ;
} else {
return -EINVAL;
}
snd_soc_component_write(component, DA732X_REG_PLL_CTRL, val);
return ret;
return val;
}
static void da732x_set_charge_pump(struct snd_soc_component *component, int state)
@ -1158,7 +1153,7 @@ static int da732x_set_dai_pll(struct snd_soc_component *component, int pll_id,
if (indiv < 0)
return indiv;
fref = (da732x->sysclk / indiv);
fref = da732x->sysclk / BIT(indiv);
div_hi = freq_out / fref;
frac_div = (u64)(freq_out % fref) * 8192ULL;
do_div(frac_div, fref);

View File

@ -48,14 +48,10 @@
#define DA732X_MCLK_20MHZ 20000000
#define DA732X_MCLK_40MHZ 40000000
#define DA732X_MCLK_54MHZ 54000000
#define DA732X_MCLK_RET_0_10MHZ 0
#define DA732X_MCLK_VAL_0_10MHZ 1
#define DA732X_MCLK_RET_10_20MHZ 1
#define DA732X_MCLK_VAL_10_20MHZ 2
#define DA732X_MCLK_RET_20_40MHZ 2
#define DA732X_MCLK_VAL_20_40MHZ 4
#define DA732X_MCLK_RET_40_54MHZ 3
#define DA732X_MCLK_VAL_40_54MHZ 8
#define DA732X_MCLK_VAL_0_10MHZ 0
#define DA732X_MCLK_VAL_10_20MHZ 1
#define DA732X_MCLK_VAL_20_40MHZ 2
#define DA732X_MCLK_VAL_40_54MHZ 3
#define DA732X_DAI_ID1 0
#define DA732X_DAI_ID2 1
#define DA732X_SRCCLK_PLL 0

View File

@ -523,7 +523,7 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
struct hdac_hdmi_cvt *cvt)
{
struct hdac_hdmi_pcm *pcm;
struct hdac_hdmi_port *port = NULL;
struct hdac_hdmi_port *port;
int ret, i;
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
@ -713,7 +713,7 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_device *hdev,
struct hdac_hdmi_port *port)
{
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm = NULL;
struct hdac_hdmi_pcm *pcm;
struct hdac_hdmi_port *p;
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
@ -900,7 +900,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
struct hdac_hdmi_port *port = w->priv;
struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm = NULL;
struct hdac_hdmi_pcm *pcm;
const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]];
ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
@ -1693,7 +1693,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
{
struct hdac_device *hdev = aptr;
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pin *pin = NULL;
struct hdac_hdmi_pin *pin;
struct hdac_hdmi_port *hport = NULL;
struct snd_soc_component *component = hdmi->component;
int i;
@ -1958,7 +1958,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
struct hdac_device *hdev = hdmi->hdev;
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
struct hdac_ext_link *hlink = NULL;
struct hdac_ext_link *hlink;
int ret;
hdmi->component = component;
@ -2227,7 +2227,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
{
struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink = NULL;
struct hdac_ext_link *hlink;
dev_dbg(dev, "Enter: %s\n", __func__);
@ -2263,7 +2263,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
{
struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink = NULL;
struct hdac_ext_link *hlink;
dev_dbg(dev, "Enter: %s\n", __func__);

View File

@ -2,7 +2,7 @@
#ifndef __HDAC_HDMI_H__
#define __HDAC_HDMI_H__
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
struct snd_soc_jack *jack);
int hdac_hdmi_jack_port_init(struct snd_soc_component *component,

View File

@ -22,7 +22,6 @@
struct hdmi_codec_channel_map_table {
unsigned char map; /* ALSA API channel map position */
unsigned long spk_mask; /* speaker position bit mask */
};
/*
@ -735,7 +734,7 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component,
static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
{
struct hdmi_codec_daifmt *cf = dai->playback_dma_data;
struct hdmi_codec_daifmt *cf;
int ret;
ret = hdmi_dai_probe(dai);

View File

@ -198,7 +198,7 @@ static int jz4760_codec_startup(struct snd_pcm_substream *substream,
{
struct snd_soc_component *codec = dai->component;
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
int ret;
int ret = 0;
/*
* SYSCLK output from the codec to the AIC is required to keep the
@ -207,7 +207,7 @@ static int jz4760_codec_startup(struct snd_pcm_substream *substream,
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ret = snd_soc_dapm_force_enable_pin(dapm, "SYSCLK");
return 0;
return ret;
}
static void jz4760_codec_shutdown(struct snd_pcm_substream *substream,
@ -841,11 +841,8 @@ static int jz4760_codec_probe(struct platform_device *pdev)
codec->dev = dev;
codec->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(codec->base)) {
ret = PTR_ERR(codec->base);
dev_err(dev, "Failed to ioremap mmio memory: %d\n", ret);
return ret;
}
if (IS_ERR(codec->base))
return PTR_ERR(codec->base);
codec->regmap = devm_regmap_init(dev, NULL, codec,
&jz4760_codec_regmap_config);

View File

@ -893,11 +893,8 @@ static int jz4770_codec_probe(struct platform_device *pdev)
codec->dev = dev;
codec->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(codec->base)) {
ret = PTR_ERR(codec->base);
dev_err(dev, "Failed to ioremap mmio memory: %d\n", ret);
return ret;
}
if (IS_ERR(codec->base))
return PTR_ERR(codec->base);
codec->regmap = devm_regmap_init(dev, NULL, codec,
&jz4770_codec_regmap_config);

View File

@ -1206,8 +1206,6 @@ static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
break;
case 48000:
case 32576:
/* fll clk slection */
pll_clk = BIT(4);
return 0;
default:
return -EINVAL;

View File

@ -1620,8 +1620,6 @@ static int rx_macro_set_interpolator_rate(struct snd_soc_dai *dai,
return ret;
ret = rx_macro_set_mix_interpolator_rate(dai, rate_val, sample_rate);
if (ret)
return ret;
return ret;
}
@ -1767,7 +1765,7 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
static struct snd_soc_dai_ops rx_macro_dai_ops = {
static const struct snd_soc_dai_ops rx_macro_dai_ops = {
.hw_params = rx_macro_hw_params,
.get_channel_map = rx_macro_get_channel_map,
.mute_stream = rx_macro_digital_mute,
@ -2038,7 +2036,7 @@ static int rx_macro_load_compander_coeff(struct snd_soc_component *component,
{
u16 comp_coeff_lsb_reg, comp_coeff_msb_reg;
int i;
int hph_pwr_mode = HPH_LOHIFI;
int hph_pwr_mode;
if (!rx->comp_enabled[comp])
return 0;
@ -3585,7 +3583,6 @@ static const struct of_device_id rx_macro_dt_match[] = {
static struct platform_driver rx_macro_driver = {
.driver = {
.name = "rx_macro",
.owner = THIS_MODULE,
.of_match_table = rx_macro_dt_match,
.suppress_bind_attrs = true,
},

View File

@ -1124,7 +1124,7 @@ static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
static struct snd_soc_dai_ops tx_macro_dai_ops = {
static const struct snd_soc_dai_ops tx_macro_dai_ops = {
.hw_params = tx_macro_hw_params,
.get_channel_map = tx_macro_get_channel_map,
.mute_stream = tx_macro_digital_mute,

View File

@ -894,7 +894,7 @@ static int va_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
static struct snd_soc_dai_ops va_macro_dai_ops = {
static const struct snd_soc_dai_ops va_macro_dai_ops = {
.hw_params = va_macro_hw_params,
.get_channel_map = va_macro_get_channel_map,
.mute_stream = va_macro_digital_mute,
@ -1343,7 +1343,7 @@ static int va_macro_register_fsgen_output(struct va_macro *va)
if (ret)
return ret;
return of_clk_add_provider(np, of_clk_src_simple_get, va->hw.clk);
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &va->hw);
}
static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate,
@ -1452,12 +1452,10 @@ static int va_macro_probe(struct platform_device *pdev)
va_macro_dais,
ARRAY_SIZE(va_macro_dais));
if (ret)
goto soc_err;
goto err;
return ret;
soc_err:
of_clk_del_provider(pdev->dev.of_node);
err:
clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks);
@ -1468,7 +1466,6 @@ static int va_macro_remove(struct platform_device *pdev)
{
struct va_macro *va = dev_get_drvdata(&pdev->dev);
of_clk_del_provider(pdev->dev.of_node);
clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks);
return 0;

View File

@ -944,6 +944,8 @@ static int wsa_macro_set_interpolator_rate(struct snd_soc_dai *dai,
goto prim_rate;
ret = wsa_macro_set_mix_interpolator_rate(dai, (u8) rate_val, sample_rate);
if (ret < 0)
return ret;
prim_rate:
/* set primary path sample rate */
for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) {
@ -1029,7 +1031,7 @@ static int wsa_macro_get_channel_map(struct snd_soc_dai *dai,
return 0;
}
static struct snd_soc_dai_ops wsa_macro_dai_ops = {
static const struct snd_soc_dai_ops wsa_macro_dai_ops = {
.hw_params = wsa_macro_hw_params,
.get_channel_map = wsa_macro_get_channel_map,
};
@ -2335,10 +2337,9 @@ static const struct clk_ops swclk_gate_ops = {
.recalc_rate = swclk_recalc_rate,
};
static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa)
static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
{
struct device *dev = wsa->dev;
struct device_node *np = dev->of_node;
const char *parent_clk_name;
const char *clk_name = "mclk";
struct clk_hw *hw;
@ -2356,11 +2357,9 @@ static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa)
hw = &wsa->hw;
ret = clk_hw_register(wsa->dev, hw);
if (ret)
return ERR_PTR(ret);
return ret;
of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
return NULL;
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
}
static const struct snd_soc_component_driver wsa_macro_component_drv = {
@ -2436,8 +2435,6 @@ static int wsa_macro_remove(struct platform_device *pdev)
{
struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev);
of_clk_del_provider(pdev->dev.of_node);
clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks);
return 0;

View File

@ -430,7 +430,7 @@ int madera_init_bus_error_irq(struct madera_priv *priv, int dsp_num,
irq_handler_t handler);
void madera_free_bus_error_irq(struct madera_priv *priv, int dsp_num);
int madera_init_dai(struct madera_priv *priv, int dai);
int madera_init_dai(struct madera_priv *priv, int id);
int madera_set_output_mode(struct snd_soc_component *component, int output,
bool differential);

View File

@ -1832,7 +1832,7 @@ static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */
static int max98090_find_divisor(int target_freq, int pclk)
{
int current_diff = INT_MAX;
int test_diff = INT_MAX;
int test_diff;
int divisor_index = 0;
int i;

View File

@ -204,6 +204,15 @@ SOC_SINGLE("Ramp Up Switch", MAX98373_R203F_AMP_DSP_CFG,
MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0),
SOC_SINGLE("Ramp Down Switch", MAX98373_R203F_AMP_DSP_CFG,
MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0),
/* Speaker Amplifier Overcurrent Automatic Restart Enable */
SOC_SINGLE("OVC Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
MAX98373_OVC_AUTORESTART_SHIFT, 1, 0),
/* Thermal Shutdown Automatic Restart Enable */
SOC_SINGLE("THERM Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
MAX98373_THERM_AUTORESTART_SHIFT, 1, 0),
/* Clock Monitor Automatic Restart Enable */
SOC_SINGLE("CMON Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
MAX98373_CMON_AUTORESTART_SHIFT, 1, 0),
SOC_SINGLE("CLK Monitor Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
MAX98373_CLOCK_MON_SHIFT, 1, 0),
SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG,
@ -392,6 +401,11 @@ static int max98373_probe(struct snd_soc_component *component)
MAX98373_R2021_PCM_TX_HIZ_EN_2,
1 << (max98373->i_slot - 8), 0);
/* enable auto restart function by default */
regmap_write(max98373->regmap,
MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
0xF);
/* speaker feedback slot configuration */
regmap_write(max98373->regmap,
MAX98373_R2023_PCM_TX_SRC_2,

View File

@ -195,6 +195,9 @@
#define MAX98373_LIMITER_EN_SHIFT (0)
/* MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG */
#define MAX98373_OVC_AUTORESTART_SHIFT (3)
#define MAX98373_THERM_AUTORESTART_SHIFT (2)
#define MAX98373_CMON_AUTORESTART_SHIFT (1)
#define MAX98373_CLOCK_MON_SHIFT (0)
/* MAX98373_R20FF_GLOBAL_SHDN */

View File

@ -856,6 +856,48 @@ static void max98390_init_regs(struct snd_soc_component *component)
regmap_write(max98390->regmap, MAX98390_ENV_TRACK_VOUT_HEADROOM, 0x0e);
regmap_write(max98390->regmap, MAX98390_BOOST_BYPASS1, 0x46);
regmap_write(max98390->regmap, MAX98390_FET_SCALING3, 0x03);
/* voltage, current slot configuration */
regmap_write(max98390->regmap,
MAX98390_PCM_CH_SRC_2,
(max98390->i_l_slot << 4 |
max98390->v_l_slot)&0xFF);
if (max98390->v_l_slot < 8) {
regmap_update_bits(max98390->regmap,
MAX98390_PCM_TX_HIZ_CTRL_A,
1 << max98390->v_l_slot, 0);
regmap_update_bits(max98390->regmap,
MAX98390_PCM_TX_EN_A,
1 << max98390->v_l_slot,
1 << max98390->v_l_slot);
} else {
regmap_update_bits(max98390->regmap,
MAX98390_PCM_TX_HIZ_CTRL_B,
1 << (max98390->v_l_slot - 8), 0);
regmap_update_bits(max98390->regmap,
MAX98390_PCM_TX_EN_B,
1 << (max98390->v_l_slot - 8),
1 << (max98390->v_l_slot - 8));
}
if (max98390->i_l_slot < 8) {
regmap_update_bits(max98390->regmap,
MAX98390_PCM_TX_HIZ_CTRL_A,
1 << max98390->i_l_slot, 0);
regmap_update_bits(max98390->regmap,
MAX98390_PCM_TX_EN_A,
1 << max98390->i_l_slot,
1 << max98390->i_l_slot);
} else {
regmap_update_bits(max98390->regmap,
MAX98390_PCM_TX_HIZ_CTRL_B,
1 << (max98390->i_l_slot - 8), 0);
regmap_update_bits(max98390->regmap,
MAX98390_PCM_TX_EN_B,
1 << (max98390->i_l_slot - 8),
1 << (max98390->i_l_slot - 8));
}
}
static int max98390_probe(struct snd_soc_component *component)
@ -946,6 +988,23 @@ static const struct regmap_config max98390_regmap = {
.cache_type = REGCACHE_RBTREE,
};
static void max98390_slot_config(struct i2c_client *i2c,
struct max98390_priv *max98390)
{
int value;
struct device *dev = &i2c->dev;
if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value))
max98390->v_l_slot = value & 0xF;
else
max98390->v_l_slot = 0;
if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value))
max98390->i_l_slot = value & 0xF;
else
max98390->i_l_slot = 1;
}
static int max98390_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@ -988,6 +1047,9 @@ static int max98390_i2c_probe(struct i2c_client *i2c,
__func__, max98390->ref_rdc_value,
max98390->ambient_temp_value);
/* voltage/current slot configuration */
max98390_slot_config(i2c, max98390);
/* regmap initialization */
max98390->regmap = devm_regmap_init_i2c(i2c, &max98390_regmap);
if (IS_ERR(max98390->regmap)) {

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