]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - sound/soc/intel/boards/broadwell.c
Merge tag 'asoc-v5.7' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[mirror_ubuntu-hirsute-kernel.git] / sound / soc / intel / boards / broadwell.c
CommitLineData
1802d0be 1// SPDX-License-Identifier: GPL-2.0-only
afdb74fd
LG
2/*
3 * Intel Broadwell Wildcatpoint SST Audio
4 *
5 * Copyright (C) 2013, Intel Corporation. All rights reserved.
afdb74fd
LG
6 */
7
8#include <linux/module.h>
9#include <linux/platform_device.h>
10#include <sound/core.h>
11#include <sound/pcm.h>
12#include <sound/soc.h>
c1e99c91 13#include <sound/jack.h>
afdb74fd 14#include <sound/pcm_params.h>
2d067b28 15#include <sound/soc-acpi.h>
afdb74fd 16
e56c72d5
JY
17#include "../common/sst-dsp.h"
18#include "../haswell/sst-haswell-ipc.h"
afdb74fd 19
e56c72d5 20#include "../../codecs/rt286.h"
afdb74fd 21
c1e99c91
JY
22static struct snd_soc_jack broadwell_headset;
23/* Headset jack detection DAPM pins */
24static struct snd_soc_jack_pin broadwell_headset_pins[] = {
25 {
26 .pin = "Mic Jack",
27 .mask = SND_JACK_MICROPHONE,
28 },
29 {
30 .pin = "Headphone Jack",
31 .mask = SND_JACK_HEADPHONE,
32 },
33};
34
35static const struct snd_kcontrol_new broadwell_controls[] = {
36 SOC_DAPM_PIN_SWITCH("Speaker"),
37 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
38};
39
afdb74fd 40static const struct snd_soc_dapm_widget broadwell_widgets[] = {
c1e99c91 41 SND_SOC_DAPM_HP("Headphone Jack", NULL),
afdb74fd
LG
42 SND_SOC_DAPM_SPK("Speaker", NULL),
43 SND_SOC_DAPM_MIC("Mic Jack", NULL),
44 SND_SOC_DAPM_MIC("DMIC1", NULL),
45 SND_SOC_DAPM_MIC("DMIC2", NULL),
46 SND_SOC_DAPM_LINE("Line Jack", NULL),
47};
48
49static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
50
51 /* speaker */
52 {"Speaker", NULL, "SPOR"},
53 {"Speaker", NULL, "SPOL"},
54
55 /* HP jack connectors - unknown if we have jack deteck */
c1e99c91 56 {"Headphone Jack", NULL, "HPO Pin"},
afdb74fd
LG
57
58 /* other jacks */
59 {"MIC1", NULL, "Mic Jack"},
60 {"LINE1", NULL, "Line Jack"},
61
62 /* digital mics */
63 {"DMIC1 Pin", NULL, "DMIC1"},
64 {"DMIC2 Pin", NULL, "DMIC2"},
65
66 /* CODEC BE connections */
67 {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
68 {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
69};
70
c1e99c91
JY
71static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
72{
0d1571c1 73 struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
c1e99c91 74 int ret = 0;
85c85e5d
LPC
75 ret = snd_soc_card_jack_new(rtd->card, "Headset",
76 SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
77 broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins));
c1e99c91
JY
78 if (ret)
79 return ret;
80
45101122 81 rt286_mic_detect(component, &broadwell_headset);
c1e99c91
JY
82 return 0;
83}
84
85
afdb74fd
LG
86static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
87 struct snd_pcm_hw_params *params)
88{
89 struct snd_interval *rate = hw_param_interval(params,
90 SNDRV_PCM_HW_PARAM_RATE);
91 struct snd_interval *channels = hw_param_interval(params,
92 SNDRV_PCM_HW_PARAM_CHANNELS);
93
94 /* The ADSP will covert the FE rate to 48k, stereo */
95 rate->min = rate->max = 48000;
96 channels->min = channels->max = 2;
97
98 /* set SSP0 to 16 bit */
369a9f5f 99 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
afdb74fd
LG
100 return 0;
101}
102
103static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream,
104 struct snd_pcm_hw_params *params)
105{
106 struct snd_soc_pcm_runtime *rtd = substream->private_data;
0d1571c1 107 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
afdb74fd
LG
108 int ret;
109
110 ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
111 SND_SOC_CLOCK_IN);
112
113 if (ret < 0) {
114 dev_err(rtd->dev, "can't set codec sysclk configuration\n");
115 return ret;
116 }
117
118 return ret;
119}
120
d5bc18c1 121static const struct snd_soc_ops broadwell_rt286_ops = {
afdb74fd
LG
122 .hw_params = broadwell_rt286_hw_params,
123};
124
f35bf70f 125#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
afdb74fd
LG
126static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
127{
2ee178db
KM
128 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
129 struct sst_pdata *pdata = dev_get_platdata(component->dev);
afdb74fd
LG
130 struct sst_hsw *broadwell = pdata->dsp;
131 int ret;
132
133 /* Set ADSP SSP port settings */
134 ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
135 SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
136 SST_HSW_DEVICE_CLOCK_MASTER, 9);
137 if (ret < 0) {
138 dev_err(rtd->dev, "error: failed to set device config\n");
139 return ret;
140 }
141
afdb74fd
LG
142 return 0;
143}
f35bf70f 144#endif
afdb74fd 145
4c3db473
KM
146SND_SOC_DAILINK_DEF(system,
147 DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
148
149SND_SOC_DAILINK_DEF(offload0,
150 DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
151
152SND_SOC_DAILINK_DEF(offload1,
153 DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
154
155SND_SOC_DAILINK_DEF(loopback,
156 DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
157
158SND_SOC_DAILINK_DEF(dummy,
159 DAILINK_COMP_ARRAY(COMP_DUMMY()));
160
161SND_SOC_DAILINK_DEF(platform,
162 DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
163
164SND_SOC_DAILINK_DEF(codec,
165 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
166
64df6afa
PX
167#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
168SND_SOC_DAILINK_DEF(ssp0_port,
169 DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
64df6afa
PX
170#endif
171
afdb74fd
LG
172/* broadwell digital audio interface glue - connects codec <--> CPU */
173static struct snd_soc_dai_link broadwell_rt286_dais[] = {
174 /* Front End DAI links */
175 {
176 .name = "System PCM",
7bb73cbd 177 .stream_name = "System Playback/Capture",
afdb74fd 178 .dynamic = 1,
f35bf70f 179#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
afdb74fd 180 .init = broadwell_rtd_init,
f35bf70f 181#endif
afdb74fd
LG
182 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
183 .dpcm_playback = 1,
7bb73cbd 184 .dpcm_capture = 1,
4c3db473 185 SND_SOC_DAILINK_REG(system, dummy, platform),
afdb74fd
LG
186 },
187 {
188 .name = "Offload0",
189 .stream_name = "Offload0 Playback",
afdb74fd 190 .dynamic = 1,
afdb74fd
LG
191 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
192 .dpcm_playback = 1,
4c3db473 193 SND_SOC_DAILINK_REG(offload0, dummy, platform),
afdb74fd
LG
194 },
195 {
196 .name = "Offload1",
197 .stream_name = "Offload1 Playback",
afdb74fd 198 .dynamic = 1,
afdb74fd
LG
199 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
200 .dpcm_playback = 1,
4c3db473 201 SND_SOC_DAILINK_REG(offload1, dummy, platform),
afdb74fd
LG
202 },
203 {
204 .name = "Loopback PCM",
205 .stream_name = "Loopback",
906a9abc 206 .dynamic = 1,
afdb74fd
LG
207 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
208 .dpcm_capture = 1,
4c3db473 209 SND_SOC_DAILINK_REG(loopback, dummy, platform),
afdb74fd 210 },
afdb74fd
LG
211 /* Back End DAI links */
212 {
213 /* SSP0 - Codec */
214 .name = "Codec",
2f0ad491 215 .id = 0,
afdb74fd 216 .no_pcm = 1,
c1e99c91 217 .init = broadwell_rt286_codec_init,
afdb74fd
LG
218 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
219 SND_SOC_DAIFMT_CBS_CFS,
220 .ignore_suspend = 1,
221 .ignore_pmdown_time = 1,
222 .be_hw_params_fixup = broadwell_ssp0_fixup,
223 .ops = &broadwell_rt286_ops,
224 .dpcm_playback = 1,
225 .dpcm_capture = 1,
68999d93
CR
226#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
227 SND_SOC_DAILINK_REG(dummy, codec, dummy),
228#else
64df6afa 229 SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
68999d93 230#endif
afdb74fd
LG
231 },
232};
233
1a5ab21c 234static int broadwell_suspend(struct snd_soc_card *card){
d9fc4063
KM
235 struct snd_soc_component *component;
236
f70f18f7 237 for_each_card_components(card, component) {
d9fc4063 238 if (!strcmp(component->name, "i2c-INT343A:00")) {
1a5ab21c 239
45101122
KM
240 dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
241 rt286_mic_detect(component, NULL);
1a5ab21c
JY
242 break;
243 }
244 }
245 return 0;
246}
247
248static int broadwell_resume(struct snd_soc_card *card){
d9fc4063
KM
249 struct snd_soc_component *component;
250
f70f18f7 251 for_each_card_components(card, component) {
d9fc4063 252 if (!strcmp(component->name, "i2c-INT343A:00")) {
1a5ab21c 253
45101122
KM
254 dev_dbg(component->dev, "enabling jack detect for resume.\n");
255 rt286_mic_detect(component, &broadwell_headset);
1a5ab21c
JY
256 break;
257 }
258 }
259 return 0;
260}
261
afdb74fd
LG
262/* broadwell audio machine driver for WPT + RT286S */
263static struct snd_soc_card broadwell_rt286 = {
264 .name = "broadwell-rt286",
265 .owner = THIS_MODULE,
266 .dai_link = broadwell_rt286_dais,
267 .num_links = ARRAY_SIZE(broadwell_rt286_dais),
c1e99c91
JY
268 .controls = broadwell_controls,
269 .num_controls = ARRAY_SIZE(broadwell_controls),
afdb74fd
LG
270 .dapm_widgets = broadwell_widgets,
271 .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
272 .dapm_routes = broadwell_rt286_map,
273 .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map),
274 .fully_routed = true,
1a5ab21c
JY
275 .suspend_pre = broadwell_suspend,
276 .resume_post = broadwell_resume,
afdb74fd
LG
277};
278
279static int broadwell_audio_probe(struct platform_device *pdev)
280{
2d067b28 281 struct snd_soc_acpi_mach *mach;
2d067b28
PLB
282 int ret;
283
afdb74fd 284 broadwell_rt286.dev = &pdev->dev;
2d067b28
PLB
285
286 /* override plaform name, if required */
42432196 287 mach = pdev->dev.platform_data;
2d067b28 288 ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286,
54d037d5 289 mach->mach_params.platform);
2d067b28
PLB
290 if (ret)
291 return ret;
292
9ed74764 293 return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
afdb74fd
LG
294}
295
296static struct platform_driver broadwell_audio = {
297 .probe = broadwell_audio_probe,
afdb74fd
LG
298 .driver = {
299 .name = "broadwell-audio",
afdb74fd
LG
300 },
301};
302
303module_platform_driver(broadwell_audio)
304
305/* Module information */
306MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
307MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell");
308MODULE_LICENSE("GPL v2");
309MODULE_ALIAS("platform:broadwell-audio");