1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (c) 2020 BayLibre, SAS.
4 // Author: Jerome Brunet <jbrunet@baylibre.com>
6 #include <linux/bitfield.h>
7 #include <sound/pcm_params.h>
9 #include <sound/soc-dai.h>
11 #include <dt-bindings/sound/meson-aiu.h>
13 #include "meson-codec-glue.h"
15 #define CTRL_CLK_SEL GENMASK(1, 0)
16 #define CTRL_DATA_SEL_SHIFT 4
17 #define CTRL_DATA_SEL (0x3 << CTRL_DATA_SEL_SHIFT)
19 static const char * const aiu_codec_ctrl_mux_texts
[] = {
20 "DISABLED", "PCM", "I2S",
23 static int aiu_codec_ctrl_mux_put_enum(struct snd_kcontrol
*kcontrol
,
24 struct snd_ctl_elem_value
*ucontrol
)
26 struct snd_soc_component
*component
=
27 snd_soc_dapm_kcontrol_component(kcontrol
);
28 struct snd_soc_dapm_context
*dapm
=
29 snd_soc_dapm_kcontrol_dapm(kcontrol
);
30 struct soc_enum
*e
= (struct soc_enum
*)kcontrol
->private_value
;
31 unsigned int mux
, changed
;
33 mux
= snd_soc_enum_item_to_val(e
, ucontrol
->value
.enumerated
.item
[0]);
34 changed
= snd_soc_component_test_bits(component
, e
->reg
,
36 FIELD_PREP(CTRL_DATA_SEL
, mux
));
41 /* Force disconnect of the mux while updating */
42 snd_soc_dapm_mux_update_power(dapm
, kcontrol
, 0, NULL
, NULL
);
44 /* Reset the source first */
45 snd_soc_component_update_bits(component
, e
->reg
,
48 FIELD_PREP(CTRL_CLK_SEL
, 0) |
49 FIELD_PREP(CTRL_DATA_SEL
, 0));
51 /* Set the appropriate source */
52 snd_soc_component_update_bits(component
, e
->reg
,
55 FIELD_PREP(CTRL_CLK_SEL
, mux
) |
56 FIELD_PREP(CTRL_DATA_SEL
, mux
));
58 snd_soc_dapm_mux_update_power(dapm
, kcontrol
, mux
, e
, NULL
);
63 static SOC_ENUM_SINGLE_DECL(aiu_hdmi_ctrl_mux_enum
, AIU_HDMI_CLK_DATA_CTRL
,
65 aiu_codec_ctrl_mux_texts
);
67 static const struct snd_kcontrol_new aiu_hdmi_ctrl_mux
=
68 SOC_DAPM_ENUM_EXT("HDMI Source", aiu_hdmi_ctrl_mux_enum
,
69 snd_soc_dapm_get_enum_double
,
70 aiu_codec_ctrl_mux_put_enum
);
72 static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets
[] = {
73 SND_SOC_DAPM_MUX("HDMI CTRL SRC", SND_SOC_NOPM
, 0, 0,
77 static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops
= {
78 .probe
= meson_codec_glue_input_dai_probe
,
79 .remove
= meson_codec_glue_input_dai_remove
,
80 .hw_params
= meson_codec_glue_input_hw_params
,
81 .set_fmt
= meson_codec_glue_input_set_fmt
,
84 static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops
= {
85 .startup
= meson_codec_glue_output_startup
,
88 #define AIU_CODEC_CTRL_FORMATS \
89 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
90 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
91 SNDRV_PCM_FMTBIT_S32_LE)
93 #define AIU_CODEC_CTRL_STREAM(xname, xsuffix) \
95 .stream_name = xname " " xsuffix, \
100 .formats = AIU_CODEC_CTRL_FORMATS, \
103 #define AIU_CODEC_CTRL_INPUT(xname) { \
104 .name = "CODEC CTRL " xname, \
105 .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \
106 .ops = &aiu_codec_ctrl_input_ops, \
109 #define AIU_CODEC_CTRL_OUTPUT(xname) { \
110 .name = "CODEC CTRL " xname, \
111 .capture = AIU_CODEC_CTRL_STREAM(xname, "Capture"), \
112 .ops = &aiu_codec_ctrl_output_ops, \
115 static struct snd_soc_dai_driver aiu_hdmi_ctrl_dai_drv
[] = {
116 [CTRL_I2S
] = AIU_CODEC_CTRL_INPUT("HDMI I2S IN"),
117 [CTRL_PCM
] = AIU_CODEC_CTRL_INPUT("HDMI PCM IN"),
118 [CTRL_OUT
] = AIU_CODEC_CTRL_OUTPUT("HDMI OUT"),
121 static const struct snd_soc_dapm_route aiu_hdmi_ctrl_routes
[] = {
122 { "HDMI CTRL SRC", "I2S", "HDMI I2S IN Playback" },
123 { "HDMI CTRL SRC", "PCM", "HDMI PCM IN Playback" },
124 { "HDMI OUT Capture", NULL
, "HDMI CTRL SRC" },
127 static int aiu_hdmi_of_xlate_dai_name(struct snd_soc_component
*component
,
128 const struct of_phandle_args
*args
,
129 const char **dai_name
)
131 return aiu_of_xlate_dai_name(component
, args
, dai_name
, AIU_HDMI
);
134 static const struct snd_soc_component_driver aiu_hdmi_ctrl_component
= {
135 .name
= "AIU HDMI Codec Control",
136 .dapm_widgets
= aiu_hdmi_ctrl_widgets
,
137 .num_dapm_widgets
= ARRAY_SIZE(aiu_hdmi_ctrl_widgets
),
138 .dapm_routes
= aiu_hdmi_ctrl_routes
,
139 .num_dapm_routes
= ARRAY_SIZE(aiu_hdmi_ctrl_routes
),
140 .of_xlate_dai_name
= aiu_hdmi_of_xlate_dai_name
,
142 #ifdef CONFIG_DEBUG_FS
143 .debugfs_prefix
= "hdmi",
147 int aiu_hdmi_ctrl_register_component(struct device
*dev
)
149 return snd_soc_register_component(dev
, &aiu_hdmi_ctrl_component
,
150 aiu_hdmi_ctrl_dai_drv
,
151 ARRAY_SIZE(aiu_hdmi_ctrl_dai_drv
));