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