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