Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/intel/boards/bytcht_nocodec.c
26493 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* bytcht_nocodec.c - ASoc Machine driver for MinnowBoard Max and Up
4
* to make I2S signals observable on the Low-Speed connector. Audio codec
5
* is not managed by ASoC/DAPM
6
*
7
* Copyright (C) 2015-2017 Intel Corp
8
*
9
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10
*
11
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12
*/
13
14
#include <linux/module.h>
15
#include <sound/pcm.h>
16
#include <sound/pcm_params.h>
17
#include <sound/soc.h>
18
#include "../atom/sst-atom-controls.h"
19
20
static const struct snd_soc_dapm_widget widgets[] = {
21
SND_SOC_DAPM_MIC("Mic", NULL),
22
SND_SOC_DAPM_SPK("Speaker", NULL),
23
};
24
25
static const struct snd_kcontrol_new controls[] = {
26
SOC_DAPM_PIN_SWITCH("Mic"),
27
SOC_DAPM_PIN_SWITCH("Speaker"),
28
};
29
30
static const struct snd_soc_dapm_route audio_map[] = {
31
{"ssp2 Tx", NULL, "codec_out0"},
32
{"ssp2 Tx", NULL, "codec_out1"},
33
{"codec_in0", NULL, "ssp2 Rx"},
34
{"codec_in1", NULL, "ssp2 Rx"},
35
36
{"ssp2 Rx", NULL, "Mic"},
37
{"Speaker", NULL, "ssp2 Tx"},
38
};
39
40
static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
41
struct snd_pcm_hw_params *params)
42
{
43
struct snd_interval *rate = hw_param_interval(params,
44
SNDRV_PCM_HW_PARAM_RATE);
45
struct snd_interval *channels = hw_param_interval(params,
46
SNDRV_PCM_HW_PARAM_CHANNELS);
47
int ret;
48
49
/* The DSP will convert the FE rate to 48k, stereo, 24bits */
50
rate->min = rate->max = 48000;
51
channels->min = channels->max = 2;
52
53
/* set SSP2 to 24-bit */
54
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
55
56
/*
57
* Default mode for SSP configuration is TDM 4 slot, override config
58
* with explicit setting to I2S 2ch 24-bit. The word length is set with
59
* dai_set_tdm_slot() since there is no other API exposed
60
*/
61
ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
62
SND_SOC_DAIFMT_I2S |
63
SND_SOC_DAIFMT_NB_NF |
64
SND_SOC_DAIFMT_BP_FP);
65
66
if (ret < 0) {
67
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
68
return ret;
69
}
70
71
ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
72
if (ret < 0) {
73
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
74
return ret;
75
}
76
77
return 0;
78
}
79
80
static const unsigned int rates_48000[] = {
81
48000,
82
};
83
84
static const struct snd_pcm_hw_constraint_list constraints_48000 = {
85
.count = ARRAY_SIZE(rates_48000),
86
.list = rates_48000,
87
};
88
89
static int aif1_startup(struct snd_pcm_substream *substream)
90
{
91
return snd_pcm_hw_constraint_list(substream->runtime, 0,
92
SNDRV_PCM_HW_PARAM_RATE,
93
&constraints_48000);
94
}
95
96
static const struct snd_soc_ops aif1_ops = {
97
.startup = aif1_startup,
98
};
99
100
SND_SOC_DAILINK_DEF(dummy,
101
DAILINK_COMP_ARRAY(COMP_DUMMY()));
102
103
SND_SOC_DAILINK_DEF(media,
104
DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
105
106
SND_SOC_DAILINK_DEF(deepbuffer,
107
DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
108
109
SND_SOC_DAILINK_DEF(ssp2_port,
110
DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
111
112
SND_SOC_DAILINK_DEF(platform,
113
DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
114
115
static struct snd_soc_dai_link dais[] = {
116
[MERR_DPCM_AUDIO] = {
117
.name = "Audio Port",
118
.stream_name = "Audio",
119
.ignore_suspend = 1,
120
.nonatomic = true,
121
.dynamic = 1,
122
.ops = &aif1_ops,
123
SND_SOC_DAILINK_REG(media, dummy, platform),
124
},
125
[MERR_DPCM_DEEP_BUFFER] = {
126
.name = "Deep-Buffer Audio Port",
127
.stream_name = "Deep-Buffer Audio",
128
.ignore_suspend = 1,
129
.nonatomic = true,
130
.dynamic = 1,
131
.playback_only = 1,
132
.ops = &aif1_ops,
133
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
134
},
135
/* CODEC<->CODEC link */
136
/* back ends */
137
{
138
.name = "SSP2-LowSpeed Connector",
139
.id = 0,
140
.no_pcm = 1,
141
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
142
| SND_SOC_DAIFMT_CBC_CFC,
143
.be_hw_params_fixup = codec_fixup,
144
.ignore_suspend = 1,
145
SND_SOC_DAILINK_REG(ssp2_port, dummy, platform),
146
},
147
};
148
149
/* SoC card */
150
static struct snd_soc_card bytcht_nocodec_card = {
151
.name = "bytcht-nocodec",
152
.owner = THIS_MODULE,
153
.dai_link = dais,
154
.num_links = ARRAY_SIZE(dais),
155
.dapm_widgets = widgets,
156
.num_dapm_widgets = ARRAY_SIZE(widgets),
157
.dapm_routes = audio_map,
158
.num_dapm_routes = ARRAY_SIZE(audio_map),
159
.controls = controls,
160
.num_controls = ARRAY_SIZE(controls),
161
.fully_routed = true,
162
};
163
164
static int snd_bytcht_nocodec_mc_probe(struct platform_device *pdev)
165
{
166
int ret_val = 0;
167
168
/* register the soc card */
169
bytcht_nocodec_card.dev = &pdev->dev;
170
171
ret_val = devm_snd_soc_register_card(&pdev->dev, &bytcht_nocodec_card);
172
173
if (ret_val) {
174
dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
175
ret_val);
176
return ret_val;
177
}
178
platform_set_drvdata(pdev, &bytcht_nocodec_card);
179
return ret_val;
180
}
181
182
static struct platform_driver snd_bytcht_nocodec_mc_driver = {
183
.driver = {
184
.name = "bytcht_nocodec",
185
},
186
.probe = snd_bytcht_nocodec_mc_probe,
187
};
188
module_platform_driver(snd_bytcht_nocodec_mc_driver);
189
190
MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Nocodec Machine driver");
191
MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>");
192
MODULE_LICENSE("GPL v2");
193
MODULE_ALIAS("platform:bytcht_nocodec");
194
195