Commit f116d2ff authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/stm32', 'asoc/topic/sunxi',...

Merge remote-tracking branches 'asoc/topic/stm32', 'asoc/topic/sunxi', 'asoc/topic/tlv320dac31xx', 'asoc/topic/topology' and 'asoc/topic/wm-adsp' into asoc-next
STMicroelectronics STM32 SPI/I2S Controller
The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode.
Only some SPI instances support I2S.
Required properties:
- compatible: Must be "st,stm32h7-i2s"
- reg: Offset and length of the device's register set.
- interrupts: Must contain the interrupt line id.
- clocks: Must contain phandle and clock specifier pairs for each entry
in clock-names.
- clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k".
"i2sclk": clock which feeds the internal clock generator
"pclk": clock which feeds the peripheral bus interface
"x8k": I2S parent clock for sampling rates multiple of 8kHz.
"x11k": I2S parent clock for sampling rates multiple of 11.025kHz.
- dmas: DMA specifiers for tx and rx dma.
See Documentation/devicetree/bindings/dma/stm32-dma.txt.
- dma-names: Identifier for each DMA request line. Must be "tx" and "rx".
- pinctrl-names: should contain only value "default"
- pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
Optional properties:
- resets: Reference to a reset controller asserting the reset controller
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
graph.txt.
Example:
sound_card {
compatible = "audio-graph-card";
dais = <&i2s2_port>;
};
i2s2: audio-controller@40003800 {
compatible = "st,stm32h7-i2s";
reg = <0x40003800 0x400>;
interrupts = <36>;
clocks = <&rcc PCLK1>, <&rcc SPI2_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
clock-names = "pclk", "i2sclk", "x8k", "x11k";
dmas = <&dmamux2 2 39 0x400 0x1>,
<&dmamux2 3 40 0x400 0x1>;
dma-names = "rx", "tx";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2s2>;
i2s2_port: port@0 {
cpu_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
format = "i2s";
};
};
};
audio-codec {
codec_port: port@0 {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
...@@ -6,7 +6,7 @@ The SAI contains two independent audio sub-blocks. Each sub-block has ...@@ -6,7 +6,7 @@ The SAI contains two independent audio sub-blocks. Each sub-block has
its own clock generator and I/O lines controller. its own clock generator and I/O lines controller.
Required properties: Required properties:
- compatible: Should be "st,stm32f4-sai" - compatible: Should be "st,stm32f4-sai" or "st,stm32h7-sai"
- reg: Base address and size of SAI common register set. - reg: Base address and size of SAI common register set.
- clocks: Must contain phandle and clock specifier pairs for each entry - clocks: Must contain phandle and clock specifier pairs for each entry
in clock-names. in clock-names.
...@@ -36,6 +36,10 @@ SAI subnodes required properties: ...@@ -36,6 +36,10 @@ SAI subnodes required properties:
- pinctrl-names: should contain only value "default" - pinctrl-names: should contain only value "default"
- pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
graph.txt.
Example: Example:
sound_card { sound_card {
compatible = "audio-graph-card"; compatible = "audio-graph-card";
...@@ -43,38 +47,29 @@ sound_card { ...@@ -43,38 +47,29 @@ sound_card {
}; };
sai1: sai1@40015800 { sai1: sai1@40015800 {
compatible = "st,stm32f4-sai"; compatible = "st,stm32h7-sai";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
ranges; ranges = <0 0x40015800 0x400>;
reg = <0x40015800 0x4>; reg = <0x40015800 0x4>;
clocks = <&rcc 1 CLK_SAIQ_PDIV>, <&rcc 1 CLK_I2SQ_PDIV>; clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>;
clock-names = "x8k", "x11k"; clock-names = "x8k", "x11k";
interrupts = <87>; interrupts = <87>;
sai1b: audio-controller@40015824 { sai1a: audio-controller@40015804 {
#sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-a";
compatible = "st,stm32-sai-sub-b"; reg = <0x4 0x1C>;
reg = <0x40015824 0x1C>; clocks = <&rcc SAI1_CK>;
clocks = <&rcc 1 CLK_SAI2>;
clock-names = "sai_ck"; clock-names = "sai_ck";
dmas = <&dma2 5 0 0x400 0x0>; dmas = <&dmamux1 1 87 0x400 0x0>;
dma-names = "tx"; dma-names = "tx";
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sai1b>; pinctrl-0 = <&pinctrl_sai1a>;
ports {
#address-cells = <1>;
#size-cells = <0>;
sai1b_port: port@0 { sai1b_port: port {
reg = <0>; cpu_endpoint: endpoint {
cpu_endpoint: endpoint { remote-endpoint = <&codec_endpoint>;
remote-endpoint = <&codec_endpoint>; format = "i2s";
audio-graph-card,format = "i2s";
audio-graph-card,bitclock-master = <&codec_endpoint>;
audio-graph-card,frame-master = <&codec_endpoint>;
};
}; };
}; };
}; };
......
STMicroelectronics STM32 S/PDIF receiver (SPDIFRX).
The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with
IEC-60958 and IEC-61937.
Required properties:
- compatible: should be "st,stm32h7-spdifrx"
- reg: cpu DAI IP base address and size
- clocks: must contain an entry for kclk (used as S/PDIF signal reference)
- clock-names: must contain "kclk"
- interrupts: cpu DAI interrupt line
- dmas: DMA specifiers for audio data DMA and iec control flow DMA
See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt
- dma-names: two dmas have to be defined, "rx" and "rx-ctrl"
Optional properties:
- resets: Reference to a reset controller asserting the SPDIFRX
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
graph.txt.
Example:
spdifrx: spdifrx@40004000 {
compatible = "st,stm32h7-spdifrx";
reg = <0x40004000 0x400>;
clocks = <&rcc SPDIFRX_CK>;
clock-names = "kclk";
interrupts = <97>;
dmas = <&dmamux1 2 93 0x400 0x0>,
<&dmamux1 3 94 0x400 0x0>;
dma-names = "rx", "rx-ctrl";
pinctrl-0 = <&spdifrx_pins>;
pinctrl-names = "default";
spdifrx_port: port {
cpu_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
};
};
};
spdif_in: spdif-in {
compatible = "linux,spdif-dir";
codec_port: port {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
soundcard {
compatible = "audio-graph-card";
dais = <&spdifrx_port>;
};
...@@ -7,6 +7,7 @@ Required properties: ...@@ -7,6 +7,7 @@ Required properties:
- "allwinner,sun7i-a20-codec" - "allwinner,sun7i-a20-codec"
- "allwinner,sun8i-a23-codec" - "allwinner,sun8i-a23-codec"
- "allwinner,sun8i-h3-codec" - "allwinner,sun8i-h3-codec"
- "allwinner,sun8i-v3s-codec"
- reg: must contain the registers location and length - reg: must contain the registers location and length
- interrupts: must contain the codec interrupt - interrupts: must contain the codec interrupt
- dmas: DMA channels for tx and rx dma. See the DMA client binding, - dmas: DMA channels for tx and rx dma. See the DMA client binding,
...@@ -25,6 +26,7 @@ Required properties for the following compatibles: ...@@ -25,6 +26,7 @@ Required properties for the following compatibles:
- "allwinner,sun6i-a31-codec" - "allwinner,sun6i-a31-codec"
- "allwinner,sun8i-a23-codec" - "allwinner,sun8i-a23-codec"
- "allwinner,sun8i-h3-codec" - "allwinner,sun8i-h3-codec"
- "allwinner,sun8i-v3s-codec"
- resets: phandle to the reset control for this device - resets: phandle to the reset control for this device
- allwinner,audio-routing: A list of the connections between audio components. - allwinner,audio-routing: A list of the connections between audio components.
Each entry is a pair of strings, the first being the Each entry is a pair of strings, the first being the
...@@ -34,15 +36,15 @@ Required properties for the following compatibles: ...@@ -34,15 +36,15 @@ Required properties for the following compatibles:
Audio pins on the SoC: Audio pins on the SoC:
"HP" "HP"
"HPCOM" "HPCOM"
"LINEIN" "LINEIN" (not on sun8i-v3s)
"LINEOUT" (not on sun8i-a23) "LINEOUT" (not on sun8i-a23 or sun8i-v3s)
"MIC1" "MIC1"
"MIC2" "MIC2" (not on sun8i-v3s)
"MIC3" (sun6i-a31 only) "MIC3" (sun6i-a31 only)
Microphone biases from the SoC: Microphone biases from the SoC:
"HBIAS" "HBIAS"
"MBIAS" "MBIAS" (not on sun8i-v3s)
Board connectors: Board connectors:
"Headphone" "Headphone"
...@@ -55,6 +57,7 @@ Required properties for the following compatibles: ...@@ -55,6 +57,7 @@ Required properties for the following compatibles:
Required properties for the following compatibles: Required properties for the following compatibles:
- "allwinner,sun8i-a23-codec" - "allwinner,sun8i-a23-codec"
- "allwinner,sun8i-h3-codec" - "allwinner,sun8i-h3-codec"
- "allwinner,sun8i-v3s-codec"
- allwinner,codec-analog-controls: A phandle to the codec analog controls - allwinner,codec-analog-controls: A phandle to the codec analog controls
block in the PRCM. block in the PRCM.
......
...@@ -4,6 +4,7 @@ Required properties: ...@@ -4,6 +4,7 @@ Required properties:
- compatible: must be one of the following compatibles: - compatible: must be one of the following compatibles:
- "allwinner,sun8i-a23-codec-analog" - "allwinner,sun8i-a23-codec-analog"
- "allwinner,sun8i-h3-codec-analog" - "allwinner,sun8i-h3-codec-analog"
- "allwinner,sun8i-v3s-codec-analog"
Required properties if not a sub-node of the PRCM node: Required properties if not a sub-node of the PRCM node:
- reg: must contain the registers location and length - reg: must contain the registers location and length
......
...@@ -28,6 +28,8 @@ struct snd_soc_component; ...@@ -28,6 +28,8 @@ struct snd_soc_component;
struct snd_soc_tplg_pcm_fe; struct snd_soc_tplg_pcm_fe;
struct snd_soc_dapm_context; struct snd_soc_dapm_context;
struct snd_soc_card; struct snd_soc_card;
struct snd_kcontrol_new;
struct snd_soc_dai_link;
/* object scan be loaded and unloaded in groups with identfying indexes */ /* object scan be loaded and unloaded in groups with identfying indexes */
#define SND_SOC_TPLG_INDEX_ALL 0 /* ID that matches all FW objects */ #define SND_SOC_TPLG_INDEX_ALL 0 /* ID that matches all FW objects */
...@@ -116,6 +118,9 @@ struct snd_soc_tplg_ops { ...@@ -116,6 +118,9 @@ struct snd_soc_tplg_ops {
int (*widget_load)(struct snd_soc_component *, int (*widget_load)(struct snd_soc_component *,
struct snd_soc_dapm_widget *, struct snd_soc_dapm_widget *,
struct snd_soc_tplg_dapm_widget *); struct snd_soc_tplg_dapm_widget *);
int (*widget_ready)(struct snd_soc_component *,
struct snd_soc_dapm_widget *,
struct snd_soc_tplg_dapm_widget *);
int (*widget_unload)(struct snd_soc_component *, int (*widget_unload)(struct snd_soc_component *,
struct snd_soc_dobj *); struct snd_soc_dobj *);
......
...@@ -1210,7 +1210,7 @@ static const struct snd_soc_dai_ops aic31xx_dai_ops = { ...@@ -1210,7 +1210,7 @@ static const struct snd_soc_dai_ops aic31xx_dai_ops = {
static struct snd_soc_dai_driver dac31xx_dai_driver[] = { static struct snd_soc_dai_driver dac31xx_dai_driver[] = {
{ {
.name = "tlv32dac31xx-hifi", .name = "tlv320dac31xx-hifi",
.playback = { .playback = {
.stream_name = "Playback", .stream_name = "Playback",
.channels_min = 2, .channels_min = 2,
......
...@@ -482,8 +482,6 @@ struct wm_coeff_ctl_ops { ...@@ -482,8 +482,6 @@ struct wm_coeff_ctl_ops {
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int (*xput)(struct snd_kcontrol *kcontrol, int (*xput)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int (*xinfo)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
}; };
struct wm_coeff_ctl { struct wm_coeff_ctl {
...@@ -1890,7 +1888,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, ...@@ -1890,7 +1888,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
} }
if (be32_to_cpu(val) != 0xbedead) if (be32_to_cpu(val) != 0xbedead)
adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
pos + len, be32_to_cpu(val)); pos + len, be32_to_cpu(val));
alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA); alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
...@@ -2654,7 +2652,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, ...@@ -2654,7 +2652,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
char preload[32]; char preload[32];
snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", mc->shift); snprintf(preload, ARRAY_SIZE(preload), "DSP%u Preload", mc->shift);
dsp->preloaded = ucontrol->value.integer.value[0]; dsp->preloaded = ucontrol->value.integer.value[0];
......
...@@ -352,6 +352,17 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg, ...@@ -352,6 +352,17 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg,
return 0; return 0;
} }
/* optionally pass new dynamic widget to component driver. This is mainly for
* external widgets where we can assign private data/ops */
static int soc_tplg_widget_ready(struct soc_tplg *tplg,
struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
{
if (tplg->comp && tplg->ops && tplg->ops->widget_ready)
return tplg->ops->widget_ready(tplg->comp, w, tplg_w);
return 0;
}
/* pass DAI configurations to component driver for extra initialization */ /* pass DAI configurations to component driver for extra initialization */
static int soc_tplg_dai_load(struct soc_tplg *tplg, static int soc_tplg_dai_load(struct soc_tplg *tplg,
struct snd_soc_dai_driver *dai_drv) struct snd_soc_dai_driver *dai_drv)
...@@ -1160,7 +1171,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, ...@@ -1160,7 +1171,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
return -EINVAL; return -EINVAL;
} }
dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes\n", count); dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count,
hdr->index);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos;
...@@ -1473,6 +1485,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, ...@@ -1473,6 +1485,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
if (template.id < 0) if (template.id < 0)
return template.id; return template.id;
/* strings are allocated here, but used and freed by the widget */
template.name = kstrdup(w->name, GFP_KERNEL); template.name = kstrdup(w->name, GFP_KERNEL);
if (!template.name) if (!template.name)
return -ENOMEM; return -ENOMEM;
...@@ -1585,11 +1598,17 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, ...@@ -1585,11 +1598,17 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
widget->dobj.widget.kcontrol_type = kcontrol_type; widget->dobj.widget.kcontrol_type = kcontrol_type;
widget->dobj.ops = tplg->ops; widget->dobj.ops = tplg->ops;
widget->dobj.index = tplg->index; widget->dobj.index = tplg->index;
kfree(template.sname);
kfree(template.name);
list_add(&widget->dobj.list, &tplg->comp->dobj_list); list_add(&widget->dobj.list, &tplg->comp->dobj_list);
ret = soc_tplg_widget_ready(tplg, widget, w);
if (ret < 0)
goto ready_err;
return 0; return 0;
ready_err:
snd_soc_tplg_widget_remove(widget);
snd_soc_dapm_free_widget(widget);
hdr_err: hdr_err:
kfree(template.sname); kfree(template.sname);
err: err:
...@@ -1636,7 +1655,7 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg) ...@@ -1636,7 +1655,7 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
*/ */
if (!card || !card->instantiated) { if (!card || !card->instantiated) {
dev_warn(tplg->dev, "ASoC: Parent card not yet available," dev_warn(tplg->dev, "ASoC: Parent card not yet available,"
"Do not add new widgets now\n"); " widget card binding deferred\n");
return 0; return 0;
} }
...@@ -2371,7 +2390,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, ...@@ -2371,7 +2390,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,
/* check for matching ID */ /* check for matching ID */
if (hdr->index != tplg->req_index && if (hdr->index != tplg->req_index &&
hdr->index != SND_SOC_TPLG_INDEX_ALL) tplg->req_index != SND_SOC_TPLG_INDEX_ALL)
return 0; return 0;
tplg->index = hdr->index; tplg->index = hdr->index;
......
menuconfig SND_SOC_STM32 menu "STMicroelectronics STM32 SOC audio support"
tristate "STMicroelectronics STM32 SOC audio support"
config SND_SOC_STM32_SAI
tristate "STM32 SAI interface (Serial Audio Interface) support"
depends on ARCH_STM32 || COMPILE_TEST depends on ARCH_STM32 || COMPILE_TEST
depends on SND_SOC depends on SND_SOC
select SND_SOC_GENERIC_DMAENGINE_PCM select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO select REGMAP_MMIO
help help
Say Y if you want to enable ASoC-support for STM32 Say Y if you want to enable SAI for STM32
config SND_SOC_STM32_I2S
tristate "STM32 I2S interface (SPI/I2S block) support"
depends on ARCH_STM32 || COMPILE_TEST
depends on SND_SOC
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
help
Say Y if you want to enable I2S for STM32
config SND_SOC_STM32_SPDIFRX
tristate "STM32 S/PDIF receiver (SPDIFRX) support"
depends on ARCH_STM32 || COMPILE_TEST
depends on SND_SOC
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
select SND_SOC_SPDIF
help
Say Y if you want to enable S/PDIF capture for STM32
endmenu
# SAI # SAI
snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o
obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai-sub.o
snd-soc-stm32-sai-objs := stm32_sai.o snd-soc-stm32-sai-objs := stm32_sai.o
obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai.o
# I2S
snd-soc-stm32-i2s-objs := stm32_i2s.o
obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o
# SPDIFRX
snd-soc-stm32-spdifrx-objs := stm32_spdifrx.o
obj-$(CONFIG_SND_SOC_STM32_SPDIFRX) += snd-soc-stm32-spdifrx.o
This diff is collapsed.
...@@ -27,8 +27,17 @@ ...@@ -27,8 +27,17 @@
#include "stm32_sai.h" #include "stm32_sai.h"
static const struct stm32_sai_conf stm32_sai_conf_f4 = {
.version = SAI_STM32F4,
};
static const struct stm32_sai_conf stm32_sai_conf_h7 = {
.version = SAI_STM32H7,
};
static const struct of_device_id stm32_sai_ids[] = { static const struct of_device_id stm32_sai_ids[] = {
{ .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 }, { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 },
{ .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 },
{} {}
}; };
...@@ -52,7 +61,7 @@ static int stm32_sai_probe(struct platform_device *pdev) ...@@ -52,7 +61,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
of_id = of_match_device(stm32_sai_ids, &pdev->dev); of_id = of_match_device(stm32_sai_ids, &pdev->dev);
if (of_id) if (of_id)
sai->version = (enum stm32_sai_version)of_id->data; sai->conf = (struct stm32_sai_conf *)of_id->data;
else else
return -EINVAL; return -EINVAL;
...@@ -110,6 +119,6 @@ static struct platform_driver stm32_sai_driver = { ...@@ -110,6 +119,6 @@ static struct platform_driver stm32_sai_driver = {
module_platform_driver(stm32_sai_driver); module_platform_driver(stm32_sai_driver);
MODULE_DESCRIPTION("STM32 Soc SAI Interface"); MODULE_DESCRIPTION("STM32 Soc SAI Interface");
MODULE_AUTHOR("Olivier Moysan, <olivier.moysan@st.com>"); MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
MODULE_ALIAS("platform:st,stm32-sai"); MODULE_ALIAS("platform:st,stm32-sai");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -31,6 +31,10 @@ ...@@ -31,6 +31,10 @@
#define STM_SAI_CLRFR_REGX 0x18 #define STM_SAI_CLRFR_REGX 0x18
#define STM_SAI_DR_REGX 0x1C #define STM_SAI_DR_REGX 0x1C
/* Sub-block A registers, relative to sub-block A address */
#define STM_SAI_PDMCR_REGX 0x40
#define STM_SAI_PDMLY_REGX 0x44
/******************** Bit definition for SAI_GCR register *******************/ /******************** Bit definition for SAI_GCR register *******************/
#define SAI_GCR_SYNCIN_SHIFT 0 #define SAI_GCR_SYNCIN_SHIFT 0
#define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT) #define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
...@@ -75,10 +79,11 @@ ...@@ -75,10 +79,11 @@
#define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT) #define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT)
#define SAI_XCR1_MCKDIV_SHIFT 20 #define SAI_XCR1_MCKDIV_SHIFT 20
#define SAI_XCR1_MCKDIV_WIDTH 4 #define SAI_XCR1_MCKDIV_WIDTH(x) (((x) == SAI_STM32F4) ? 4 : 6)
#define SAI_XCR1_MCKDIV_MASK GENMASK(24, SAI_XCR1_MCKDIV_SHIFT) #define SAI_XCR1_MCKDIV_MASK(x) GENMASK((SAI_XCR1_MCKDIV_SHIFT + (x) - 1),\
SAI_XCR1_MCKDIV_SHIFT)
#define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT) #define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT)
#define SAI_XCR1_MCKDIV_MAX ((1 << SAI_XCR1_MCKDIV_WIDTH) - 1) #define SAI_XCR1_MCKDIV_MAX(x) ((1 << SAI_XCR1_MCKDIV_WIDTH(x)) - 1)
#define SAI_XCR1_OSR_SHIFT 26 #define SAI_XCR1_OSR_SHIFT 26
#define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT) #define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT)
...@@ -125,7 +130,6 @@ ...@@ -125,7 +130,6 @@
#define SAI_XFRCR_FSOFF BIT(SAI_XFRCR_FSOFF_SHIFT) #define SAI_XFRCR_FSOFF BIT(SAI_XFRCR_FSOFF_SHIFT)
/****************** Bit definition for SAI_XSLOTR register ******************/ /****************** Bit definition for SAI_XSLOTR register ******************/
#define SAI_XSLOTR_FBOFF_SHIFT 0 #define SAI_XSLOTR_FBOFF_SHIFT 0
#define SAI_XSLOTR_FBOFF_MASK GENMASK(4, SAI_XSLOTR_FBOFF_SHIFT) #define SAI_XSLOTR_FBOFF_MASK GENMASK(4, SAI_XSLOTR_FBOFF_SHIFT)
#define SAI_XSLOTR_FBOFF_SET(x) ((x) << SAI_XSLOTR_FBOFF_SHIFT) #define SAI_XSLOTR_FBOFF_SET(x) ((x) << SAI_XSLOTR_FBOFF_SHIFT)
...@@ -179,8 +183,65 @@ ...@@ -179,8 +183,65 @@
#define SAI_XCLRFR_SHIFT 0 #define SAI_XCLRFR_SHIFT 0
#define SAI_XCLRFR_MASK GENMASK(6, SAI_XCLRFR_SHIFT) #define SAI_XCLRFR_MASK GENMASK(6, SAI_XCLRFR_SHIFT)
/****************** Bit definition for SAI_PDMCR register ******************/
#define SAI_PDMCR_PDMEN BIT(0)
#define SAI_PDMCR_MICNBR_SHIFT 4
#define SAI_PDMCR_MICNBR_MASK GENMASK(5, SAI_PDMCR_MICNBR_SHIFT)
#define SAI_PDMCR_MICNBR_SET(x) ((x) << SAI_PDMCR_MICNBR_SHIFT)
#define SAI_PDMCR_CKEN1 BIT(8)
#define SAI_PDMCR_CKEN2 BIT(9)
#define SAI_PDMCR_CKEN3 BIT(10)
#define SAI_PDMCR_CKEN4 BIT(11)
/****************** Bit definition for (SAI_PDMDLY register ****************/
#define SAI_PDMDLY_1L_SHIFT 0
#define SAI_PDMDLY_1L_MASK GENMASK(2, SAI_PDMDLY_1L_SHIFT)
#define SAI_PDMDLY_1L_WIDTH 3
#define SAI_PDMDLY_1R_SHIFT 4
#define SAI_PDMDLY_1R_MASK GENMASK(6, SAI_PDMDLY_1R_SHIFT)
#define SAI_PDMDLY_1R_WIDTH 3
#define SAI_PDMDLY_2L_SHIFT 8
#define SAI_PDMDLY_2L_MASK GENMASK(10, SAI_PDMDLY_2L_SHIFT)
#define SAI_PDMDLY_2L_WIDTH 3
#define SAI_PDMDLY_2R_SHIFT 12
#define SAI_PDMDLY_2R_MASK GENMASK(14, SAI_PDMDLY_2R_SHIFT)
#define SAI_PDMDLY_2R_WIDTH 3
#define SAI_PDMDLY_3L_SHIFT 16
#define SAI_PDMDLY_3L_MASK GENMASK(18, SAI_PDMDLY_3L_SHIFT)
#define SAI_PDMDLY_3L_WIDTH 3
#define SAI_PDMDLY_3R_SHIFT 20
#define SAI_PDMDLY_3R_MASK GENMASK(22, SAI_PDMDLY_3R_SHIFT)
#define SAI_PDMDLY_3R_WIDTH 3
#define SAI_PDMDLY_4L_SHIFT 24
#define SAI_PDMDLY_4L_MASK GENMASK(26, SAI_PDMDLY_4L_SHIFT)
#define SAI_PDMDLY_4L_WIDTH 3
#define SAI_PDMDLY_4R_SHIFT 28
#define SAI_PDMDLY_4R_MASK GENMASK(30, SAI_PDMDLY_4R_SHIFT)
#define SAI_PDMDLY_4R_WIDTH 3
#define STM_SAI_IS_F4(ip) ((ip)->conf->version == SAI_STM32F4)
#define STM_SAI_IS_H7(ip) ((ip)->conf->version == SAI_STM32H7)
enum stm32_sai_version { enum stm32_sai_version {
SAI_STM32F4 SAI_STM32F4,
SAI_STM32H7
};
/**
* struct stm32_sai_conf - SAI configuration
* @version: SAI version
*/
struct stm32_sai_conf {
int version;
}; };
/** /**
...@@ -195,6 +256,6 @@ struct stm32_sai_data { ...@@ -195,6 +256,6 @@ struct stm32_sai_data {
struct platform_device *pdev; struct platform_device *pdev;
struct clk *clk_x8k; struct clk *clk_x8k;
struct clk *clk_x11k; struct clk *clk_x11k;
int version; struct stm32_sai_conf *conf;
int irq; int irq;
}; };
This diff is collapsed.
This diff is collapsed.
...@@ -1339,6 +1339,44 @@ static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) ...@@ -1339,6 +1339,44 @@ static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev)
return card; return card;
}; };
static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev)
{
struct snd_soc_card *card;
int ret;
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card)
return ERR_PTR(-ENOMEM);
aux_dev.codec_of_node = of_parse_phandle(dev->of_node,
"allwinner,codec-analog-controls",
0);
if (!aux_dev.codec_of_node) {
dev_err(dev, "Can't find analog controls for codec.\n");
return ERR_PTR(-EINVAL);
};
card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
if (!card->dai_link)
return ERR_PTR(-ENOMEM);
card->dev = dev;
card->name = "V3s Audio Codec";
card->dapm_widgets = sun6i_codec_card_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
card->dapm_routes = sun8i_codec_card_routes;
card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
card->aux_dev = &aux_dev;
card->num_aux_devs = 1;
card->fully_routed = true;
ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
if (ret)
dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
return card;
};
static const struct regmap_config sun4i_codec_regmap_config = { static const struct regmap_config sun4i_codec_regmap_config = {
.reg_bits = 32, .reg_bits = 32,
.reg_stride = 4, .reg_stride = 4,
...@@ -1374,6 +1412,13 @@ static const struct regmap_config sun8i_h3_codec_regmap_config = { ...@@ -1374,6 +1412,13 @@ static const struct regmap_config sun8i_h3_codec_regmap_config = {
.max_register = SUN8I_H3_CODEC_ADC_DBG, .max_register = SUN8I_H3_CODEC_ADC_DBG,
}; };
static const struct regmap_config sun8i_v3s_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = SUN8I_H3_CODEC_ADC_DBG,
};
struct sun4i_codec_quirks { struct sun4i_codec_quirks {
const struct regmap_config *regmap_config; const struct regmap_config *regmap_config;
const struct snd_soc_codec_driver *codec; const struct snd_soc_codec_driver *codec;
...@@ -1437,6 +1482,20 @@ static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { ...@@ -1437,6 +1482,20 @@ static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
.has_reset = true, .has_reset = true,
}; };
static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
.regmap_config = &sun8i_v3s_codec_regmap_config,
/*
* TODO The codec structure should be split out, like
* H3, when adding digital audio processing support.
*/
.codec = &sun8i_a23_codec_codec,
.create_card = sun8i_v3s_codec_create_card,
.reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
.reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
.reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
.has_reset = true,
};
static const struct of_device_id sun4i_codec_of_match[] = { static const struct of_device_id sun4i_codec_of_match[] = {
{ {
.compatible = "allwinner,sun4i-a10-codec", .compatible = "allwinner,sun4i-a10-codec",
...@@ -1458,6 +1517,10 @@ static const struct of_device_id sun4i_codec_of_match[] = { ...@@ -1458,6 +1517,10 @@ static const struct of_device_id sun4i_codec_of_match[] = {
.compatible = "allwinner,sun8i-h3-codec", .compatible = "allwinner,sun8i-h3-codec",
.data = &sun8i_h3_codec_quirks, .data = &sun8i_h3_codec_quirks,
}, },
{
.compatible = "allwinner,sun8i-v3s-codec",
.data = &sun8i_v3s_codec_quirks,
},
{} {}
}; };
MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
......
...@@ -219,6 +219,22 @@ static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = { ...@@ -219,6 +219,22 @@ static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = {
SUN8I_ADDA_LOMIXSC_MIC2, 1, 0), SUN8I_ADDA_LOMIXSC_MIC2, 1, 0),
}; };
/* mixer controls */
static const struct snd_kcontrol_new sun8i_v3s_codec_mixer_controls[] = {
SOC_DAPM_DOUBLE_R("DAC Playback Switch",
SUN8I_ADDA_LOMIXSC,
SUN8I_ADDA_ROMIXSC,
SUN8I_ADDA_LOMIXSC_DACL, 1, 0),
SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
SUN8I_ADDA_LOMIXSC,
SUN8I_ADDA_ROMIXSC,
SUN8I_ADDA_LOMIXSC_DACR, 1, 0),
SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
SUN8I_ADDA_LOMIXSC,
SUN8I_ADDA_ROMIXSC,
SUN8I_ADDA_LOMIXSC_MIC1, 1, 0),
};
/* ADC mixer controls */ /* ADC mixer controls */
static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = { static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = {
SOC_DAPM_DOUBLE_R("Mixer Capture Switch", SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
...@@ -243,6 +259,22 @@ static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = { ...@@ -243,6 +259,22 @@ static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = {
SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0), SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0),
}; };
/* ADC mixer controls */
static const struct snd_kcontrol_new sun8i_v3s_codec_adc_mixer_controls[] = {
SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
SUN8I_ADDA_LADCMIXSC,
SUN8I_ADDA_RADCMIXSC,
SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0),
SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
SUN8I_ADDA_LADCMIXSC,
SUN8I_ADDA_RADCMIXSC,
SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0),
SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
SUN8I_ADDA_LADCMIXSC,
SUN8I_ADDA_RADCMIXSC,
SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0),
};
/* volume / mute controls */ /* volume / mute controls */
static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale, static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale,
-450, 150, 0); -450, 150, 0);
...@@ -289,16 +321,12 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { ...@@ -289,16 +321,12 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = {
/* Microphone input */ /* Microphone input */
SND_SOC_DAPM_INPUT("MIC1"), SND_SOC_DAPM_INPUT("MIC1"),
/* Microphone Bias */
SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN,
0, NULL, 0),
/* Mic input path */ /* Mic input path */
SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0),
};
/* Mixers */ static const struct snd_soc_dapm_widget sun8i_codec_mixer_widgets[] = {
SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC, SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC,
SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
sun8i_codec_mixer_controls, sun8i_codec_mixer_controls,
...@@ -317,10 +345,31 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { ...@@ -317,10 +345,31 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = {
ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
}; };
static const struct snd_soc_dapm_widget sun8i_v3s_codec_mixer_widgets[] = {
SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC,
SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
sun8i_v3s_codec_mixer_controls,
ARRAY_SIZE(sun8i_v3s_codec_mixer_controls)),
SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC,
SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0,
sun8i_v3s_codec_mixer_controls,
ARRAY_SIZE(sun8i_v3s_codec_mixer_controls)),
SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0,
sun8i_v3s_codec_adc_mixer_controls,
ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)),
SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
SUN8I_ADDA_ADC_AP_EN_ADCREN, 0,
sun8i_v3s_codec_adc_mixer_controls,
ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)),
};
static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = {
/* Microphone Routes */ /* Microphone Routes */
{ "Mic1 Amplifier", NULL, "MIC1"}, { "Mic1 Amplifier", NULL, "MIC1"},
};
static const struct snd_soc_dapm_route sun8i_codec_mixer_routes[] = {
/* Left Mixer Routes */ /* Left Mixer Routes */
{ "Left Mixer", "DAC Playback Switch", "Left DAC" }, { "Left Mixer", "DAC Playback Switch", "Left DAC" },
{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
...@@ -453,6 +502,27 @@ static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt) ...@@ -453,6 +502,27 @@ static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt)
return 0; return 0;
} }
/* mbias specific widget */
static const struct snd_soc_dapm_widget sun8i_codec_mbias_widgets[] = {
SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN,
0, NULL, 0),
};
static int sun8i_codec_add_mbias(struct snd_soc_component *cmpnt)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
struct device *dev = cmpnt->dev;
int ret;
ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_mbias_widgets,
ARRAY_SIZE(sun8i_codec_mbias_widgets));
if (ret)
dev_err(dev, "Failed to add MBIAS DAPM widgets: %d\n", ret);
return ret;
}
/* hmic specific widget */ /* hmic specific widget */
static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = { static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = {
SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
...@@ -679,6 +749,7 @@ struct sun8i_codec_analog_quirks { ...@@ -679,6 +749,7 @@ struct sun8i_codec_analog_quirks {
bool has_hmic; bool has_hmic;
bool has_linein; bool has_linein;
bool has_lineout; bool has_lineout;
bool has_mbias;
bool has_mic2; bool has_mic2;
}; };
...@@ -686,15 +757,64 @@ static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { ...@@ -686,15 +757,64 @@ static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
.has_headphone = true, .has_headphone = true,
.has_hmic = true, .has_hmic = true,
.has_linein = true, .has_linein = true,
.has_mbias = true,
.has_mic2 = true, .has_mic2 = true,
}; };
static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
.has_linein = true, .has_linein = true,
.has_lineout = true, .has_lineout = true,
.has_mbias = true,
.has_mic2 = true, .has_mic2 = true,
}; };
static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt,
const struct sun8i_codec_analog_quirks *quirks)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
struct device *dev = cmpnt->dev;
int ret;
if (!quirks->has_mic2 && !quirks->has_linein) {
/*
* Apply the special widget set which has uses a control
* without MIC2 and Line In, for SoCs without these.
* TODO: not all special cases are supported now, this case
* is present because it's the case of V3s.
*/
ret = snd_soc_dapm_new_controls(dapm,
sun8i_v3s_codec_mixer_widgets,
ARRAY_SIZE(sun8i_v3s_codec_mixer_widgets));
if (ret) {
dev_err(dev, "Failed to add V3s Mixer DAPM widgets: %d\n", ret);
return ret;
}
} else {
/* Apply the generic mixer widget set. */
ret = snd_soc_dapm_new_controls(dapm,
sun8i_codec_mixer_widgets,
ARRAY_SIZE(sun8i_codec_mixer_widgets));
if (ret) {
dev_err(dev, "Failed to add Mixer DAPM widgets: %d\n", ret);
return ret;
}
}
ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_mixer_routes,
ARRAY_SIZE(sun8i_codec_mixer_routes));
if (ret) {
dev_err(dev, "Failed to add Mixer DAPM routes: %d\n", ret);
return ret;
}
return 0;
}
static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = {
.has_headphone = true,
.has_hmic = true,
};
static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
{ {
struct device *dev = cmpnt->dev; struct device *dev = cmpnt->dev;
...@@ -709,6 +829,9 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) ...@@ -709,6 +829,9 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
quirks = of_device_get_match_data(dev); quirks = of_device_get_match_data(dev);
/* Add controls, widgets, and routes for individual features */ /* Add controls, widgets, and routes for individual features */
ret = sun8i_codec_analog_add_mixer(cmpnt, quirks);
if (ret)
return ret;
if (quirks->has_headphone) { if (quirks->has_headphone) {
ret = sun8i_codec_add_headphone(cmpnt); ret = sun8i_codec_add_headphone(cmpnt);
...@@ -734,6 +857,12 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) ...@@ -734,6 +857,12 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
return ret; return ret;
} }
if (quirks->has_mbias) {
ret = sun8i_codec_add_mbias(cmpnt);
if (ret)
return ret;
}
if (quirks->has_mic2) { if (quirks->has_mic2) {
ret = sun8i_codec_add_mic2(cmpnt); ret = sun8i_codec_add_mic2(cmpnt);
if (ret) if (ret)
...@@ -762,6 +891,10 @@ static const struct of_device_id sun8i_codec_analog_of_match[] = { ...@@ -762,6 +891,10 @@ static const struct of_device_id sun8i_codec_analog_of_match[] = {
.compatible = "allwinner,sun8i-h3-codec-analog", .compatible = "allwinner,sun8i-h3-codec-analog",
.data = &sun8i_h3_quirks, .data = &sun8i_h3_quirks,
}, },
{
.compatible = "allwinner,sun8i-v3s-codec-analog",
.data = &sun8i_v3s_quirks,
},
{} {}
}; };
MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match); MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment