Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (c) 2020 BayLibre, SAS.
0004 // Author: Jerome Brunet <jbrunet@baylibre.com>
0005 
0006 #include <linux/bitfield.h>
0007 #include <sound/pcm_params.h>
0008 #include <sound/soc.h>
0009 #include <sound/soc-dai.h>
0010 
0011 #include <dt-bindings/sound/meson-aiu.h>
0012 #include "aiu.h"
0013 #include "meson-codec-glue.h"
0014 
0015 #define CTRL_CLK_SEL        GENMASK(1, 0)
0016 #define CTRL_DATA_SEL_SHIFT 4
0017 #define CTRL_DATA_SEL       (0x3 << CTRL_DATA_SEL_SHIFT)
0018 
0019 static const char * const aiu_codec_ctrl_mux_texts[] = {
0020     "DISABLED", "PCM", "I2S",
0021 };
0022 
0023 static int aiu_codec_ctrl_mux_put_enum(struct snd_kcontrol *kcontrol,
0024                        struct snd_ctl_elem_value *ucontrol)
0025 {
0026     struct snd_soc_component *component =
0027         snd_soc_dapm_kcontrol_component(kcontrol);
0028     struct snd_soc_dapm_context *dapm =
0029         snd_soc_dapm_kcontrol_dapm(kcontrol);
0030     struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
0031     unsigned int mux, changed;
0032 
0033     mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
0034     changed = snd_soc_component_test_bits(component, e->reg,
0035                           CTRL_DATA_SEL,
0036                           FIELD_PREP(CTRL_DATA_SEL, mux));
0037 
0038     if (!changed)
0039         return 0;
0040 
0041     /* Force disconnect of the mux while updating */
0042     snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
0043 
0044     /* Reset the source first */
0045     snd_soc_component_update_bits(component, e->reg,
0046                       CTRL_CLK_SEL |
0047                       CTRL_DATA_SEL,
0048                       FIELD_PREP(CTRL_CLK_SEL, 0) |
0049                       FIELD_PREP(CTRL_DATA_SEL, 0));
0050 
0051     /* Set the appropriate source */
0052     snd_soc_component_update_bits(component, e->reg,
0053                       CTRL_CLK_SEL |
0054                       CTRL_DATA_SEL,
0055                       FIELD_PREP(CTRL_CLK_SEL, mux) |
0056                       FIELD_PREP(CTRL_DATA_SEL, mux));
0057 
0058     snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
0059 
0060     return 1;
0061 }
0062 
0063 static SOC_ENUM_SINGLE_DECL(aiu_hdmi_ctrl_mux_enum, AIU_HDMI_CLK_DATA_CTRL,
0064                 CTRL_DATA_SEL_SHIFT,
0065                 aiu_codec_ctrl_mux_texts);
0066 
0067 static const struct snd_kcontrol_new aiu_hdmi_ctrl_mux =
0068     SOC_DAPM_ENUM_EXT("HDMI Source", aiu_hdmi_ctrl_mux_enum,
0069               snd_soc_dapm_get_enum_double,
0070               aiu_codec_ctrl_mux_put_enum);
0071 
0072 static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = {
0073     SND_SOC_DAPM_MUX("HDMI CTRL SRC", SND_SOC_NOPM, 0, 0,
0074              &aiu_hdmi_ctrl_mux),
0075 };
0076 
0077 static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = {
0078     .hw_params  = meson_codec_glue_input_hw_params,
0079     .set_fmt    = meson_codec_glue_input_set_fmt,
0080 };
0081 
0082 static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = {
0083     .startup    = meson_codec_glue_output_startup,
0084 };
0085 
0086 #define AIU_CODEC_CTRL_FORMATS                  \
0087     (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |   \
0088      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE |   \
0089      SNDRV_PCM_FMTBIT_S32_LE)
0090 
0091 #define AIU_CODEC_CTRL_STREAM(xname, xsuffix)           \
0092 {                               \
0093     .stream_name    = xname " " xsuffix,            \
0094     .channels_min   = 1,                    \
0095     .channels_max   = 8,                    \
0096     .rate_min       = 5512,                 \
0097     .rate_max   = 192000,               \
0098     .formats    = AIU_CODEC_CTRL_FORMATS,       \
0099 }
0100 
0101 #define AIU_CODEC_CTRL_INPUT(xname) {               \
0102     .name = "CODEC CTRL " xname,                \
0103     .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"),   \
0104     .ops = &aiu_codec_ctrl_input_ops,           \
0105     .probe = meson_codec_glue_input_dai_probe,      \
0106     .remove = meson_codec_glue_input_dai_remove,        \
0107 }
0108 
0109 #define AIU_CODEC_CTRL_OUTPUT(xname) {              \
0110     .name = "CODEC CTRL " xname,                \
0111     .capture = AIU_CODEC_CTRL_STREAM(xname, "Capture"), \
0112     .ops = &aiu_codec_ctrl_output_ops,          \
0113 }
0114 
0115 static struct snd_soc_dai_driver aiu_hdmi_ctrl_dai_drv[] = {
0116     [CTRL_I2S] = AIU_CODEC_CTRL_INPUT("HDMI I2S IN"),
0117     [CTRL_PCM] = AIU_CODEC_CTRL_INPUT("HDMI PCM IN"),
0118     [CTRL_OUT] = AIU_CODEC_CTRL_OUTPUT("HDMI OUT"),
0119 };
0120 
0121 static const struct snd_soc_dapm_route aiu_hdmi_ctrl_routes[] = {
0122     { "HDMI CTRL SRC", "I2S", "HDMI I2S IN Playback" },
0123     { "HDMI CTRL SRC", "PCM", "HDMI PCM IN Playback" },
0124     { "HDMI OUT Capture", NULL, "HDMI CTRL SRC" },
0125 };
0126 
0127 static int aiu_hdmi_of_xlate_dai_name(struct snd_soc_component *component,
0128                       const struct of_phandle_args *args,
0129                       const char **dai_name)
0130 {
0131     return aiu_of_xlate_dai_name(component, args, dai_name, AIU_HDMI);
0132 }
0133 
0134 static const struct snd_soc_component_driver aiu_hdmi_ctrl_component = {
0135     .name           = "AIU HDMI Codec Control",
0136     .dapm_widgets       = aiu_hdmi_ctrl_widgets,
0137     .num_dapm_widgets   = ARRAY_SIZE(aiu_hdmi_ctrl_widgets),
0138     .dapm_routes        = aiu_hdmi_ctrl_routes,
0139     .num_dapm_routes    = ARRAY_SIZE(aiu_hdmi_ctrl_routes),
0140     .of_xlate_dai_name  = aiu_hdmi_of_xlate_dai_name,
0141     .endianness     = 1,
0142 #ifdef CONFIG_DEBUG_FS
0143     .debugfs_prefix     = "hdmi",
0144 #endif
0145 };
0146 
0147 int aiu_hdmi_ctrl_register_component(struct device *dev)
0148 {
0149     return snd_soc_register_component(dev, &aiu_hdmi_ctrl_component,
0150                       aiu_hdmi_ctrl_dai_drv,
0151                       ARRAY_SIZE(aiu_hdmi_ctrl_dai_drv));
0152 }
0153