blob: b9c12e24c70bc0297485356f8b8568607d9b8b54 [file] [log] [blame]
Thomas Gleixner1802d0b2019-05-27 08:55:21 +02001// SPDX-License-Identifier: GPL-2.0-only
Liam Girdwoodafdb74f2014-07-14 10:35:40 +08002/*
3 * Intel Broadwell Wildcatpoint SST Audio
4 *
5 * Copyright (C) 2013, Intel Corporation. All rights reserved.
Liam Girdwoodafdb74f2014-07-14 10:35:40 +08006 */
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>
Jie Yangc1e99c92014-10-30 21:16:23 +080013#include <sound/jack.h>
Liam Girdwoodafdb74f2014-07-14 10:35:40 +080014#include <sound/pcm_params.h>
Pierre-Louis Bossart2d067b22019-01-25 14:34:57 -060015#include <sound/soc-acpi.h>
Liam Girdwoodafdb74f2014-07-14 10:35:40 +080016
Jie Yange56c72d2015-04-02 15:37:02 +080017#include "../common/sst-dsp.h"
18#include "../haswell/sst-haswell-ipc.h"
Liam Girdwoodafdb74f2014-07-14 10:35:40 +080019
Jie Yange56c72d2015-04-02 15:37:02 +080020#include "../../codecs/rt286.h"
Liam Girdwoodafdb74f2014-07-14 10:35:40 +080021
Jie Yangc1e99c92014-10-30 21:16:23 +080022static 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
Liam Girdwoodafdb74f2014-07-14 10:35:40 +080040static const struct snd_soc_dapm_widget broadwell_widgets[] = {
Jie Yangc1e99c92014-10-30 21:16:23 +080041 SND_SOC_DAPM_HP("Headphone Jack", NULL),
Liam Girdwoodafdb74f2014-07-14 10:35:40 +080042 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 */
Jie Yangc1e99c92014-10-30 21:16:23 +080056 {"Headphone Jack", NULL, "HPO Pin"},
Liam Girdwoodafdb74f2014-07-14 10:35:40 +080057
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
Jie Yangc1e99c92014-10-30 21:16:23 +080071static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
72{
Kuninori Morimoto45101122018-01-29 04:36:54 +000073 struct snd_soc_component *component = rtd->codec_dai->component;
Jie Yangc1e99c92014-10-30 21:16:23 +080074 int ret = 0;
Lars-Peter Clausen85c85e52015-03-04 10:33:21 +010075 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));
Jie Yangc1e99c92014-10-30 21:16:23 +080078 if (ret)
79 return ret;
80
Kuninori Morimoto45101122018-01-29 04:36:54 +000081 rt286_mic_detect(component, &broadwell_headset);
Jie Yangc1e99c92014-10-30 21:16:23 +080082 return 0;
83}
84
85
Liam Girdwoodafdb74f2014-07-14 10:35:40 +080086static 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 */
Fang, Yang A369a9f52015-02-09 00:18:12 -080099 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800100 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;
107 struct snd_soc_dai *codec_dai = rtd->codec_dai;
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
Julia Lawalld5bc18c2016-10-15 16:55:45 +0200121static const struct snd_soc_ops broadwell_rt286_ops = {
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800122 .hw_params = broadwell_rt286_hw_params,
123};
124
Liam Girdwoodf35bf702019-04-12 11:09:03 -0500125#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800126static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
127{
Kuninori Morimoto2ee178d2018-01-29 02:42:21 +0000128 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
129 struct sst_pdata *pdata = dev_get_platdata(component->dev);
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800130 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
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800142 return 0;
143}
Liam Girdwoodf35bf702019-04-12 11:09:03 -0500144#endif
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800145
Kuninori Morimoto4c3db472019-06-06 13:19:40 +0900146SND_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
Pan Xiuli64df6af2020-01-10 17:57:46 -0600167#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
168SND_SOC_DAILINK_DEF(ssp0_port,
169 DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
170#else
171SND_SOC_DAILINK_DEF(ssp0_port,
172 DAILINK_COMP_ARRAY(COMP_DUMMY()));
173#endif
174
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800175/* broadwell digital audio interface glue - connects codec <--> CPU */
176static struct snd_soc_dai_link broadwell_rt286_dais[] = {
177 /* Front End DAI links */
178 {
179 .name = "System PCM",
Jie Yang7bb73cb2014-11-28 21:52:11 +0800180 .stream_name = "System Playback/Capture",
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800181 .dynamic = 1,
Liam Girdwoodf35bf702019-04-12 11:09:03 -0500182#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800183 .init = broadwell_rtd_init,
Liam Girdwoodf35bf702019-04-12 11:09:03 -0500184#endif
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800185 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
186 .dpcm_playback = 1,
Jie Yang7bb73cb2014-11-28 21:52:11 +0800187 .dpcm_capture = 1,
Kuninori Morimoto4c3db472019-06-06 13:19:40 +0900188 SND_SOC_DAILINK_REG(system, dummy, platform),
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800189 },
190 {
191 .name = "Offload0",
192 .stream_name = "Offload0 Playback",
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800193 .dynamic = 1,
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800194 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
195 .dpcm_playback = 1,
Kuninori Morimoto4c3db472019-06-06 13:19:40 +0900196 SND_SOC_DAILINK_REG(offload0, dummy, platform),
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800197 },
198 {
199 .name = "Offload1",
200 .stream_name = "Offload1 Playback",
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800201 .dynamic = 1,
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800202 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
203 .dpcm_playback = 1,
Kuninori Morimoto4c3db472019-06-06 13:19:40 +0900204 SND_SOC_DAILINK_REG(offload1, dummy, platform),
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800205 },
206 {
207 .name = "Loopback PCM",
208 .stream_name = "Loopback",
Rander Wang906a9ab2018-12-18 16:24:54 +0800209 .dynamic = 1,
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800210 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
211 .dpcm_capture = 1,
Kuninori Morimoto4c3db472019-06-06 13:19:40 +0900212 SND_SOC_DAILINK_REG(loopback, dummy, platform),
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800213 },
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800214 /* Back End DAI links */
215 {
216 /* SSP0 - Codec */
217 .name = "Codec",
Mengdong Lin2f0ad492016-04-19 13:12:35 +0800218 .id = 0,
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800219 .no_pcm = 1,
Jie Yangc1e99c92014-10-30 21:16:23 +0800220 .init = broadwell_rt286_codec_init,
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800221 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
222 SND_SOC_DAIFMT_CBS_CFS,
223 .ignore_suspend = 1,
224 .ignore_pmdown_time = 1,
225 .be_hw_params_fixup = broadwell_ssp0_fixup,
226 .ops = &broadwell_rt286_ops,
227 .dpcm_playback = 1,
228 .dpcm_capture = 1,
Pan Xiuli64df6af2020-01-10 17:57:46 -0600229 SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800230 },
231};
232
Jie Yang1a5ab21c2015-02-27 12:54:29 +0800233static int broadwell_suspend(struct snd_soc_card *card){
Kuninori Morimotod9fc4062016-11-30 06:22:36 +0000234 struct snd_soc_component *component;
Jie Yang1a5ab21c2015-02-27 12:54:29 +0800235
Kuninori Morimotof70f18f72018-09-18 01:29:55 +0000236 for_each_card_components(card, component) {
Kuninori Morimotod9fc4062016-11-30 06:22:36 +0000237 if (!strcmp(component->name, "i2c-INT343A:00")) {
Kuninori Morimotod9fc4062016-11-30 06:22:36 +0000238
Kuninori Morimoto45101122018-01-29 04:36:54 +0000239 dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
240 rt286_mic_detect(component, NULL);
Jie Yang1a5ab21c2015-02-27 12:54:29 +0800241 break;
242 }
243 }
244 return 0;
245}
246
247static int broadwell_resume(struct snd_soc_card *card){
Kuninori Morimotod9fc4062016-11-30 06:22:36 +0000248 struct snd_soc_component *component;
Jie Yang1a5ab21c2015-02-27 12:54:29 +0800249
Kuninori Morimotof70f18f72018-09-18 01:29:55 +0000250 for_each_card_components(card, component) {
Kuninori Morimotod9fc4062016-11-30 06:22:36 +0000251 if (!strcmp(component->name, "i2c-INT343A:00")) {
Kuninori Morimotod9fc4062016-11-30 06:22:36 +0000252
Kuninori Morimoto45101122018-01-29 04:36:54 +0000253 dev_dbg(component->dev, "enabling jack detect for resume.\n");
254 rt286_mic_detect(component, &broadwell_headset);
Jie Yang1a5ab21c2015-02-27 12:54:29 +0800255 break;
256 }
257 }
258 return 0;
259}
260
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800261/* broadwell audio machine driver for WPT + RT286S */
262static struct snd_soc_card broadwell_rt286 = {
263 .name = "broadwell-rt286",
264 .owner = THIS_MODULE,
265 .dai_link = broadwell_rt286_dais,
266 .num_links = ARRAY_SIZE(broadwell_rt286_dais),
Jie Yangc1e99c92014-10-30 21:16:23 +0800267 .controls = broadwell_controls,
268 .num_controls = ARRAY_SIZE(broadwell_controls),
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800269 .dapm_widgets = broadwell_widgets,
270 .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
271 .dapm_routes = broadwell_rt286_map,
272 .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map),
273 .fully_routed = true,
Jie Yang1a5ab21c2015-02-27 12:54:29 +0800274 .suspend_pre = broadwell_suspend,
275 .resume_post = broadwell_resume,
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800276};
277
278static int broadwell_audio_probe(struct platform_device *pdev)
279{
Pierre-Louis Bossart2d067b22019-01-25 14:34:57 -0600280 struct snd_soc_acpi_mach *mach;
Pierre-Louis Bossart2d067b22019-01-25 14:34:57 -0600281 int ret;
282
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800283 broadwell_rt286.dev = &pdev->dev;
Pierre-Louis Bossart2d067b22019-01-25 14:34:57 -0600284
285 /* override plaform name, if required */
286 mach = (&pdev->dev)->platform_data;
Pierre-Louis Bossart2d067b22019-01-25 14:34:57 -0600287 ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286,
Cezary Rojewski54d037d2019-08-22 13:36:16 +0200288 mach->mach_params.platform);
Pierre-Louis Bossart2d067b22019-01-25 14:34:57 -0600289 if (ret)
290 return ret;
291
Axel Lin9ed74762015-09-02 12:01:27 +0800292 return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800293}
294
295static struct platform_driver broadwell_audio = {
296 .probe = broadwell_audio_probe,
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800297 .driver = {
298 .name = "broadwell-audio",
Liam Girdwoodafdb74f2014-07-14 10:35:40 +0800299 },
300};
301
302module_platform_driver(broadwell_audio)
303
304/* Module information */
305MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
306MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell");
307MODULE_LICENSE("GPL v2");
308MODULE_ALIAS("platform:broadwell-audio");