^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // Copyright (c) 2020 BayLibre, SAS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) // Author: Jerome Brunet <jbrunet@baylibre.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/bitfield.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <sound/soc-dai.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <dt-bindings/sound/meson-aiu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "aiu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "meson-codec-glue.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define CTRL_CLK_SEL GENMASK(1, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define CTRL_DATA_SEL_SHIFT 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define CTRL_DATA_SEL (0x3 << CTRL_DATA_SEL_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static const char * const aiu_codec_ctrl_mux_texts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) "DISABLED", "PCM", "I2S",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static int aiu_codec_ctrl_mux_put_enum(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct snd_soc_component *component =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) snd_soc_dapm_kcontrol_component(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct snd_soc_dapm_context *dapm =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) snd_soc_dapm_kcontrol_dapm(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) unsigned int mux, changed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) changed = snd_soc_component_test_bits(component, e->reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) CTRL_DATA_SEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) FIELD_PREP(CTRL_DATA_SEL, mux));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (!changed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /* Force disconnect of the mux while updating */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* Reset the source first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) snd_soc_component_update_bits(component, e->reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) CTRL_CLK_SEL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) CTRL_DATA_SEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) FIELD_PREP(CTRL_CLK_SEL, 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) FIELD_PREP(CTRL_DATA_SEL, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /* Set the appropriate source */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) snd_soc_component_update_bits(component, e->reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) CTRL_CLK_SEL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) CTRL_DATA_SEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) FIELD_PREP(CTRL_CLK_SEL, mux) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) FIELD_PREP(CTRL_DATA_SEL, mux));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static SOC_ENUM_SINGLE_DECL(aiu_hdmi_ctrl_mux_enum, AIU_HDMI_CLK_DATA_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) CTRL_DATA_SEL_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) aiu_codec_ctrl_mux_texts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static const struct snd_kcontrol_new aiu_hdmi_ctrl_mux =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) SOC_DAPM_ENUM_EXT("HDMI Source", aiu_hdmi_ctrl_mux_enum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) snd_soc_dapm_get_enum_double,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) aiu_codec_ctrl_mux_put_enum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) SND_SOC_DAPM_MUX("HDMI CTRL SRC", SND_SOC_NOPM, 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) &aiu_hdmi_ctrl_mux),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .hw_params = meson_codec_glue_input_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .set_fmt = meson_codec_glue_input_set_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .startup = meson_codec_glue_output_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define AIU_CODEC_CTRL_FORMATS \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) SNDRV_PCM_FMTBIT_S32_LE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define AIU_CODEC_CTRL_STREAM(xname, xsuffix) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) .stream_name = xname " " xsuffix, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .channels_min = 1, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .channels_max = 8, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .rate_min = 5512, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .rate_max = 192000, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .formats = AIU_CODEC_CTRL_FORMATS, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define AIU_CODEC_CTRL_INPUT(xname) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .name = "CODEC CTRL " xname, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .ops = &aiu_codec_ctrl_input_ops, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .probe = meson_codec_glue_input_dai_probe, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .remove = meson_codec_glue_input_dai_remove, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define AIU_CODEC_CTRL_OUTPUT(xname) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .name = "CODEC CTRL " xname, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .capture = AIU_CODEC_CTRL_STREAM(xname, "Capture"), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .ops = &aiu_codec_ctrl_output_ops, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static struct snd_soc_dai_driver aiu_hdmi_ctrl_dai_drv[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) [CTRL_I2S] = AIU_CODEC_CTRL_INPUT("HDMI I2S IN"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) [CTRL_PCM] = AIU_CODEC_CTRL_INPUT("HDMI PCM IN"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) [CTRL_OUT] = AIU_CODEC_CTRL_OUTPUT("HDMI OUT"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static const struct snd_soc_dapm_route aiu_hdmi_ctrl_routes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) { "HDMI CTRL SRC", "I2S", "HDMI I2S IN Playback" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) { "HDMI CTRL SRC", "PCM", "HDMI PCM IN Playback" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) { "HDMI OUT Capture", NULL, "HDMI CTRL SRC" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static int aiu_hdmi_of_xlate_dai_name(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct of_phandle_args *args,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) const char **dai_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return aiu_of_xlate_dai_name(component, args, dai_name, AIU_HDMI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static const struct snd_soc_component_driver aiu_hdmi_ctrl_component = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .name = "AIU HDMI Codec Control",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .dapm_widgets = aiu_hdmi_ctrl_widgets,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .num_dapm_widgets = ARRAY_SIZE(aiu_hdmi_ctrl_widgets),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .dapm_routes = aiu_hdmi_ctrl_routes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) .num_dapm_routes = ARRAY_SIZE(aiu_hdmi_ctrl_routes),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .of_xlate_dai_name = aiu_hdmi_of_xlate_dai_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .endianness = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .non_legacy_dai_naming = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int aiu_hdmi_ctrl_register_component(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return snd_soc_register_component(dev, &aiu_hdmi_ctrl_component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) aiu_hdmi_ctrl_dai_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) ARRAY_SIZE(aiu_hdmi_ctrl_dai_drv));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)