aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorJohn Keeping <john@metanate.com>2016-08-24 17:06:36 -0400
committerMark Brown <broonie@kernel.org>2016-09-24 15:02:03 -0400
commit2d995e5dc283adbfbf9c1eb81bf35ca7af2d22a6 (patch)
treef5d18f384970f7af4ed9db0893db0515c334a082 /sound
parentdc995069c675af71a2ecf2ade0995df084da3e2e (diff)
ASoC: Intel: boards: Add bdw-rt5677 machine driver
This is used by the Chromebook Pixel 2015. Signed-off-by: Ben Zhang <benzh@chromium.org> Signed-off-by: Dylan Reid <dgreid@chromium.org> [john@metanate.com: - forward-port driver from Chromium OS 3.14 tree to master - remove wake on voice function that isn't supported by upstream rt5677 driver - remote owner assignment in platform_driver (Evan McClain) - convert to devm_snd_soc_register_card (Evan McClain) - add a full copyright header based on module license and Chromium OS Git history ] Signed-off-by: John Keeping <john@metanate.com> Tested-by: Genki Marshall <genki@genki.is> Tested-by: Tom Rini <trini@konsulko.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/intel/Kconfig11
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c347
-rw-r--r--sound/soc/intel/common/sst-acpi.c1
4 files changed, 361 insertions, 0 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index fc6e78050a79..26eb5a0a5575 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -121,6 +121,17 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
121 This adds audio driver for Intel Baytrail platform based boards 121 This adds audio driver for Intel Baytrail platform based boards
122 with the MAX98090 audio codec. 122 with the MAX98090 audio codec.
123 123
124config SND_SOC_INTEL_BDW_RT5677_MACH
125 tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
126 depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC
127 depends on DW_DMAC_CORE=y
128 select SND_SOC_INTEL_SST
129 select SND_SOC_INTEL_HASWELL
130 select SND_SOC_RT5677
131 help
132 This adds support for Intel Broadwell platform based boards with
133 the RT5677 audio codec.
134
124config SND_SOC_INTEL_BROADWELL_MACH 135config SND_SOC_INTEL_BROADWELL_MACH
125 tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" 136 tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
126 depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ 137 depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index dac03a06bfd8..5639f10774e6 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -1,6 +1,7 @@
1snd-soc-sst-haswell-objs := haswell.o 1snd-soc-sst-haswell-objs := haswell.o
2snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o 2snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
3snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o 3snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
4snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o
4snd-soc-sst-broadwell-objs := broadwell.o 5snd-soc-sst-broadwell-objs := broadwell.o
5snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o 6snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o
6snd-soc-sst-bxt-rt298-objs := bxt_rt298.o 7snd-soc-sst-bxt-rt298-objs := bxt_rt298.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
19obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o 20obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o
20obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o 21obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o
21obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o 22obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
23obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o
22obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o 24obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
23obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o 25obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o
24obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o 26obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
new file mode 100644
index 000000000000..547e6705bf6d
--- /dev/null
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -0,0 +1,347 @@
1/*
2 * ASoC machine driver for Intel Broadwell platforms with RT5677 codec
3 *
4 * Copyright (c) 2014, The Chromium OS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/gpio/consumer.h>
22#include <linux/delay.h>
23#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/soc.h>
26#include <sound/pcm_params.h>
27#include <sound/jack.h>
28
29#include "../common/sst-dsp.h"
30#include "../haswell/sst-haswell-ipc.h"
31
32#include "../../codecs/rt5677.h"
33
34struct bdw_rt5677_priv {
35 struct gpio_desc *gpio_hp_en;
36 struct snd_soc_codec *codec;
37};
38
39static int bdw_rt5677_event_hp(struct snd_soc_dapm_widget *w,
40 struct snd_kcontrol *k, int event)
41{
42 struct snd_soc_dapm_context *dapm = w->dapm;
43 struct snd_soc_card *card = dapm->card;
44 struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card);
45
46 if (SND_SOC_DAPM_EVENT_ON(event))
47 msleep(70);
48
49 gpiod_set_value_cansleep(bdw_rt5677->gpio_hp_en,
50 SND_SOC_DAPM_EVENT_ON(event));
51
52 return 0;
53}
54
55static const struct snd_soc_dapm_widget bdw_rt5677_widgets[] = {
56 SND_SOC_DAPM_HP("Headphone", bdw_rt5677_event_hp),
57 SND_SOC_DAPM_SPK("Speaker", NULL),
58 SND_SOC_DAPM_MIC("Headset Mic", NULL),
59 SND_SOC_DAPM_MIC("Local DMICs", NULL),
60 SND_SOC_DAPM_MIC("Remote DMICs", NULL),
61};
62
63static const struct snd_soc_dapm_route bdw_rt5677_map[] = {
64 /* Speakers */
65 {"Speaker", NULL, "PDM1L"},
66 {"Speaker", NULL, "PDM1R"},
67
68 /* Headset jack connectors */
69 {"Headphone", NULL, "LOUT1"},
70 {"Headphone", NULL, "LOUT2"},
71 {"IN1P", NULL, "Headset Mic"},
72 {"IN1N", NULL, "Headset Mic"},
73
74 /* Digital MICs
75 * Local DMICs: the two DMICs on the mainboard
76 * Remote DMICs: the two DMICs on the camera module
77 */
78 {"DMIC L1", NULL, "Remote DMICs"},
79 {"DMIC R1", NULL, "Remote DMICs"},
80 {"DMIC L2", NULL, "Local DMICs"},
81 {"DMIC R2", NULL, "Local DMICs"},
82
83 /* CODEC BE connections */
84 {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
85 {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
86};
87
88static const struct snd_kcontrol_new bdw_rt5677_controls[] = {
89 SOC_DAPM_PIN_SWITCH("Speaker"),
90 SOC_DAPM_PIN_SWITCH("Headphone"),
91 SOC_DAPM_PIN_SWITCH("Headset Mic"),
92 SOC_DAPM_PIN_SWITCH("Local DMICs"),
93 SOC_DAPM_PIN_SWITCH("Remote DMICs"),
94};
95
96
97static struct snd_soc_jack headphone_jack;
98static struct snd_soc_jack mic_jack;
99
100static struct snd_soc_jack_pin headphone_jack_pin = {
101 .pin = "Headphone",
102 .mask = SND_JACK_HEADPHONE,
103};
104
105static struct snd_soc_jack_pin mic_jack_pin = {
106 .pin = "Headset Mic",
107 .mask = SND_JACK_MICROPHONE,
108};
109
110static struct snd_soc_jack_gpio headphone_jack_gpio = {
111 .name = "plug-det",
112 .report = SND_JACK_HEADPHONE,
113 .debounce_time = 200,
114};
115
116static struct snd_soc_jack_gpio mic_jack_gpio = {
117 .name = "mic-present",
118 .report = SND_JACK_MICROPHONE,
119 .debounce_time = 200,
120 .invert = 1,
121};
122
123static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
124 struct snd_pcm_hw_params *params)
125{
126 struct snd_interval *rate = hw_param_interval(params,
127 SNDRV_PCM_HW_PARAM_RATE);
128 struct snd_interval *channels = hw_param_interval(params,
129 SNDRV_PCM_HW_PARAM_CHANNELS);
130
131 /* The ADSP will covert the FE rate to 48k, stereo */
132 rate->min = rate->max = 48000;
133 channels->min = channels->max = 2;
134
135 /* set SSP0 to 16 bit */
136 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
137 SNDRV_PCM_HW_PARAM_FIRST_MASK],
138 SNDRV_PCM_FORMAT_S16_LE);
139 return 0;
140}
141
142static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream,
143 struct snd_pcm_hw_params *params)
144{
145 struct snd_soc_pcm_runtime *rtd = substream->private_data;
146 struct snd_soc_dai *codec_dai = rtd->codec_dai;
147 int ret;
148
149 ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, 24576000,
150 SND_SOC_CLOCK_IN);
151 if (ret < 0) {
152 dev_err(rtd->dev, "can't set codec sysclk configuration\n");
153 return ret;
154 }
155
156 return ret;
157}
158
159static struct snd_soc_ops bdw_rt5677_ops = {
160 .hw_params = bdw_rt5677_hw_params,
161};
162
163static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd)
164{
165 struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
166 struct sst_hsw *broadwell = pdata->dsp;
167 int ret;
168
169 /* Set ADSP SSP port settings */
170 ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
171 SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
172 SST_HSW_DEVICE_CLOCK_MASTER, 9);
173 if (ret < 0) {
174 dev_err(rtd->dev, "error: failed to set device config\n");
175 return ret;
176 }
177
178 return 0;
179}
180
181static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
182{
183 struct bdw_rt5677_priv *bdw_rt5677 =
184 snd_soc_card_get_drvdata(rtd->card);
185 struct snd_soc_codec *codec = rtd->codec;
186 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
187
188 /* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1.
189 * The ASRC clock source is clk_i2s1_asrc.
190 */
191 rt5677_sel_asrc_clk_src(codec, RT5677_DA_STEREO_FILTER |
192 RT5677_AD_STEREO1_FILTER | RT5677_I2S1_SOURCE,
193 RT5677_CLK_SEL_I2S1_ASRC);
194
195 /* Request rt5677 GPIO for headphone amp control */
196 bdw_rt5677->gpio_hp_en = devm_gpiod_get_index(codec->dev,
197 "headphone-enable", 0, 0);
198 if (IS_ERR(bdw_rt5677->gpio_hp_en)) {
199 dev_err(codec->dev, "Can't find HP_AMP_SHDN_L gpio\n");
200 return PTR_ERR(bdw_rt5677->gpio_hp_en);
201 }
202 gpiod_direction_output(bdw_rt5677->gpio_hp_en, 0);
203
204 /* Create and initialize headphone jack */
205 if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack",
206 SND_JACK_HEADPHONE, &headphone_jack,
207 &headphone_jack_pin, 1)) {
208 headphone_jack_gpio.gpiod_dev = codec->dev;
209 if (snd_soc_jack_add_gpios(&headphone_jack, 1,
210 &headphone_jack_gpio))
211 dev_err(codec->dev, "Can't add headphone jack gpio\n");
212 } else {
213 dev_err(codec->dev, "Can't create headphone jack\n");
214 }
215
216 /* Create and initialize mic jack */
217 if (!snd_soc_card_jack_new(rtd->card, "Mic Jack",
218 SND_JACK_MICROPHONE, &mic_jack,
219 &mic_jack_pin, 1)) {
220 mic_jack_gpio.gpiod_dev = codec->dev;
221 if (snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio))
222 dev_err(codec->dev, "Can't add mic jack gpio\n");
223 } else {
224 dev_err(codec->dev, "Can't create mic jack\n");
225 }
226 bdw_rt5677->codec = codec;
227
228 snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
229 return 0;
230}
231
232/* broadwell digital audio interface glue - connects codec <--> CPU */
233static struct snd_soc_dai_link bdw_rt5677_dais[] = {
234 /* Front End DAI links */
235 {
236 .name = "System PCM",
237 .stream_name = "System Playback/Capture",
238 .cpu_dai_name = "System Pin",
239 .platform_name = "haswell-pcm-audio",
240 .dynamic = 1,
241 .codec_name = "snd-soc-dummy",
242 .codec_dai_name = "snd-soc-dummy-dai",
243 .init = bdw_rt5677_rtd_init,
244 .trigger = {
245 SND_SOC_DPCM_TRIGGER_POST,
246 SND_SOC_DPCM_TRIGGER_POST
247 },
248 .dpcm_capture = 1,
249 .dpcm_playback = 1,
250 },
251
252 /* Back End DAI links */
253 {
254 /* SSP0 - Codec */
255 .name = "Codec",
256 .id = 0,
257 .cpu_dai_name = "snd-soc-dummy-dai",
258 .platform_name = "snd-soc-dummy",
259 .no_pcm = 1,
260 .codec_name = "i2c-RT5677CE:00",
261 .codec_dai_name = "rt5677-aif1",
262 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
263 SND_SOC_DAIFMT_CBS_CFS,
264 .ignore_suspend = 1,
265 .ignore_pmdown_time = 1,
266 .be_hw_params_fixup = broadwell_ssp0_fixup,
267 .ops = &bdw_rt5677_ops,
268 .dpcm_playback = 1,
269 .dpcm_capture = 1,
270 .init = bdw_rt5677_init,
271 },
272};
273
274static int bdw_rt5677_suspend_pre(struct snd_soc_card *card)
275{
276 struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card);
277 struct snd_soc_dapm_context *dapm;
278
279 if (bdw_rt5677->codec) {
280 dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec);
281 snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
282 }
283 return 0;
284}
285
286static int bdw_rt5677_resume_post(struct snd_soc_card *card)
287{
288 struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card);
289 struct snd_soc_dapm_context *dapm;
290
291 if (bdw_rt5677->codec) {
292 dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec);
293 snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
294 }
295 return 0;
296}
297
298/* ASoC machine driver for Broadwell DSP + RT5677 */
299static struct snd_soc_card bdw_rt5677_card = {
300 .name = "bdw-rt5677",
301 .owner = THIS_MODULE,
302 .dai_link = bdw_rt5677_dais,
303 .num_links = ARRAY_SIZE(bdw_rt5677_dais),
304 .dapm_widgets = bdw_rt5677_widgets,
305 .num_dapm_widgets = ARRAY_SIZE(bdw_rt5677_widgets),
306 .dapm_routes = bdw_rt5677_map,
307 .num_dapm_routes = ARRAY_SIZE(bdw_rt5677_map),
308 .controls = bdw_rt5677_controls,
309 .num_controls = ARRAY_SIZE(bdw_rt5677_controls),
310 .fully_routed = true,
311 .suspend_pre = bdw_rt5677_suspend_pre,
312 .resume_post = bdw_rt5677_resume_post,
313};
314
315static int bdw_rt5677_probe(struct platform_device *pdev)
316{
317 struct bdw_rt5677_priv *bdw_rt5677;
318
319 bdw_rt5677_card.dev = &pdev->dev;
320
321 /* Allocate driver private struct */
322 bdw_rt5677 = devm_kzalloc(&pdev->dev, sizeof(struct bdw_rt5677_priv),
323 GFP_KERNEL);
324 if (!bdw_rt5677) {
325 dev_err(&pdev->dev, "Can't allocate bdw_rt5677\n");
326 return -ENOMEM;
327 }
328
329 snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677);
330
331 return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card);
332}
333
334static struct platform_driver bdw_rt5677_audio = {
335 .probe = bdw_rt5677_probe,
336 .driver = {
337 .name = "bdw-rt5677",
338 },
339};
340
341module_platform_driver(bdw_rt5677_audio)
342
343/* Module information */
344MODULE_AUTHOR("Ben Zhang");
345MODULE_DESCRIPTION("Intel Broadwell RT5677 machine driver");
346MODULE_LICENSE("GPL v2");
347MODULE_ALIAS("platform:bdw-rt5677");
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c
index 2c5eda14d510..1285cc597b6b 100644
--- a/sound/soc/intel/common/sst-acpi.c
+++ b/sound/soc/intel/common/sst-acpi.c
@@ -199,6 +199,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = {
199 199
200static struct sst_acpi_mach broadwell_machines[] = { 200static struct sst_acpi_mach broadwell_machines[] = {
201 { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL }, 201 { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL },
202 { "RT5677CE", "bdw-rt5677", "intel/IntcSST2.bin", NULL, NULL, NULL },
202 {} 203 {}
203}; 204};
204 205