aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/intel/boards
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/boards')
-rw-r--r--sound/soc/intel/boards/Makefile15
-rw-r--r--sound/soc/intel/boards/broadwell.c292
-rw-r--r--sound/soc/intel/boards/byt-max98090.c187
-rw-r--r--sound/soc/intel/boards/byt-rt5640.c229
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c227
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c324
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c366
-rw-r--r--sound/soc/intel/boards/haswell.c209
-rw-r--r--sound/soc/intel/boards/mfld_machine.c430
9 files changed, 2279 insertions, 0 deletions
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
new file mode 100644
index 000000000000..f8237f0044eb
--- /dev/null
+++ b/sound/soc/intel/boards/Makefile
@@ -0,0 +1,15 @@
1snd-soc-sst-haswell-objs := haswell.o
2snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
3snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
4snd-soc-sst-broadwell-objs := broadwell.o
5snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
6snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
7snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
8
9obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
10obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
11obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
12obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
13obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
14obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
15obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
new file mode 100644
index 000000000000..8bafaf6ceab1
--- /dev/null
+++ b/sound/soc/intel/boards/broadwell.c
@@ -0,0 +1,292 @@
1/*
2 * Intel Broadwell Wildcatpoint SST Audio
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/soc.h>
22#include <sound/jack.h>
23#include <sound/pcm_params.h>
24
25#include "../common/sst-dsp.h"
26#include "../haswell/sst-haswell-ipc.h"
27
28#include "../../codecs/rt286.h"
29
30static struct snd_soc_jack broadwell_headset;
31/* Headset jack detection DAPM pins */
32static struct snd_soc_jack_pin broadwell_headset_pins[] = {
33 {
34 .pin = "Mic Jack",
35 .mask = SND_JACK_MICROPHONE,
36 },
37 {
38 .pin = "Headphone Jack",
39 .mask = SND_JACK_HEADPHONE,
40 },
41};
42
43static const struct snd_kcontrol_new broadwell_controls[] = {
44 SOC_DAPM_PIN_SWITCH("Speaker"),
45 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
46};
47
48static const struct snd_soc_dapm_widget broadwell_widgets[] = {
49 SND_SOC_DAPM_HP("Headphone Jack", NULL),
50 SND_SOC_DAPM_SPK("Speaker", NULL),
51 SND_SOC_DAPM_MIC("Mic Jack", NULL),
52 SND_SOC_DAPM_MIC("DMIC1", NULL),
53 SND_SOC_DAPM_MIC("DMIC2", NULL),
54 SND_SOC_DAPM_LINE("Line Jack", NULL),
55};
56
57static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
58
59 /* speaker */
60 {"Speaker", NULL, "SPOR"},
61 {"Speaker", NULL, "SPOL"},
62
63 /* HP jack connectors - unknown if we have jack deteck */
64 {"Headphone Jack", NULL, "HPO Pin"},
65
66 /* other jacks */
67 {"MIC1", NULL, "Mic Jack"},
68 {"LINE1", NULL, "Line Jack"},
69
70 /* digital mics */
71 {"DMIC1 Pin", NULL, "DMIC1"},
72 {"DMIC2 Pin", NULL, "DMIC2"},
73
74 /* CODEC BE connections */
75 {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
76 {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
77};
78
79static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
80{
81 struct snd_soc_codec *codec = rtd->codec;
82 int ret = 0;
83 ret = snd_soc_card_jack_new(rtd->card, "Headset",
84 SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
85 broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins));
86 if (ret)
87 return ret;
88
89 rt286_mic_detect(codec, &broadwell_headset);
90 return 0;
91}
92
93
94static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
95 struct snd_pcm_hw_params *params)
96{
97 struct snd_interval *rate = hw_param_interval(params,
98 SNDRV_PCM_HW_PARAM_RATE);
99 struct snd_interval *channels = hw_param_interval(params,
100 SNDRV_PCM_HW_PARAM_CHANNELS);
101
102 /* The ADSP will covert the FE rate to 48k, stereo */
103 rate->min = rate->max = 48000;
104 channels->min = channels->max = 2;
105
106 /* set SSP0 to 16 bit */
107 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
108 return 0;
109}
110
111static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream,
112 struct snd_pcm_hw_params *params)
113{
114 struct snd_soc_pcm_runtime *rtd = substream->private_data;
115 struct snd_soc_dai *codec_dai = rtd->codec_dai;
116 int ret;
117
118 ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
119 SND_SOC_CLOCK_IN);
120
121 if (ret < 0) {
122 dev_err(rtd->dev, "can't set codec sysclk configuration\n");
123 return ret;
124 }
125
126 return ret;
127}
128
129static struct snd_soc_ops broadwell_rt286_ops = {
130 .hw_params = broadwell_rt286_hw_params,
131};
132
133static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
134{
135 struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
136 struct sst_hsw *broadwell = pdata->dsp;
137 int ret;
138
139 /* Set ADSP SSP port settings */
140 ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
141 SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
142 SST_HSW_DEVICE_CLOCK_MASTER, 9);
143 if (ret < 0) {
144 dev_err(rtd->dev, "error: failed to set device config\n");
145 return ret;
146 }
147
148 return 0;
149}
150
151/* broadwell digital audio interface glue - connects codec <--> CPU */
152static struct snd_soc_dai_link broadwell_rt286_dais[] = {
153 /* Front End DAI links */
154 {
155 .name = "System PCM",
156 .stream_name = "System Playback/Capture",
157 .cpu_dai_name = "System Pin",
158 .platform_name = "haswell-pcm-audio",
159 .dynamic = 1,
160 .codec_name = "snd-soc-dummy",
161 .codec_dai_name = "snd-soc-dummy-dai",
162 .init = broadwell_rtd_init,
163 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
164 .dpcm_playback = 1,
165 .dpcm_capture = 1,
166 },
167 {
168 .name = "Offload0",
169 .stream_name = "Offload0 Playback",
170 .cpu_dai_name = "Offload0 Pin",
171 .platform_name = "haswell-pcm-audio",
172 .dynamic = 1,
173 .codec_name = "snd-soc-dummy",
174 .codec_dai_name = "snd-soc-dummy-dai",
175 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
176 .dpcm_playback = 1,
177 },
178 {
179 .name = "Offload1",
180 .stream_name = "Offload1 Playback",
181 .cpu_dai_name = "Offload1 Pin",
182 .platform_name = "haswell-pcm-audio",
183 .dynamic = 1,
184 .codec_name = "snd-soc-dummy",
185 .codec_dai_name = "snd-soc-dummy-dai",
186 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
187 .dpcm_playback = 1,
188 },
189 {
190 .name = "Loopback PCM",
191 .stream_name = "Loopback",
192 .cpu_dai_name = "Loopback Pin",
193 .platform_name = "haswell-pcm-audio",
194 .dynamic = 0,
195 .codec_name = "snd-soc-dummy",
196 .codec_dai_name = "snd-soc-dummy-dai",
197 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
198 .dpcm_capture = 1,
199 },
200 /* Back End DAI links */
201 {
202 /* SSP0 - Codec */
203 .name = "Codec",
204 .be_id = 0,
205 .cpu_dai_name = "snd-soc-dummy-dai",
206 .platform_name = "snd-soc-dummy",
207 .no_pcm = 1,
208 .codec_name = "i2c-INT343A:00",
209 .codec_dai_name = "rt286-aif1",
210 .init = broadwell_rt286_codec_init,
211 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
212 SND_SOC_DAIFMT_CBS_CFS,
213 .ignore_suspend = 1,
214 .ignore_pmdown_time = 1,
215 .be_hw_params_fixup = broadwell_ssp0_fixup,
216 .ops = &broadwell_rt286_ops,
217 .dpcm_playback = 1,
218 .dpcm_capture = 1,
219 },
220};
221
222static int broadwell_suspend(struct snd_soc_card *card){
223 struct snd_soc_codec *codec;
224
225 list_for_each_entry(codec, &card->codec_dev_list, card_list) {
226 if (!strcmp(codec->component.name, "i2c-INT343A:00")) {
227 dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");
228 rt286_mic_detect(codec, NULL);
229 break;
230 }
231 }
232 return 0;
233}
234
235static int broadwell_resume(struct snd_soc_card *card){
236 struct snd_soc_codec *codec;
237
238 list_for_each_entry(codec, &card->codec_dev_list, card_list) {
239 if (!strcmp(codec->component.name, "i2c-INT343A:00")) {
240 dev_dbg(codec->dev, "enabling jack detect for resume.\n");
241 rt286_mic_detect(codec, &broadwell_headset);
242 break;
243 }
244 }
245 return 0;
246}
247
248/* broadwell audio machine driver for WPT + RT286S */
249static struct snd_soc_card broadwell_rt286 = {
250 .name = "broadwell-rt286",
251 .owner = THIS_MODULE,
252 .dai_link = broadwell_rt286_dais,
253 .num_links = ARRAY_SIZE(broadwell_rt286_dais),
254 .controls = broadwell_controls,
255 .num_controls = ARRAY_SIZE(broadwell_controls),
256 .dapm_widgets = broadwell_widgets,
257 .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
258 .dapm_routes = broadwell_rt286_map,
259 .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map),
260 .fully_routed = true,
261 .suspend_pre = broadwell_suspend,
262 .resume_post = broadwell_resume,
263};
264
265static int broadwell_audio_probe(struct platform_device *pdev)
266{
267 broadwell_rt286.dev = &pdev->dev;
268
269 return snd_soc_register_card(&broadwell_rt286);
270}
271
272static int broadwell_audio_remove(struct platform_device *pdev)
273{
274 snd_soc_unregister_card(&broadwell_rt286);
275 return 0;
276}
277
278static struct platform_driver broadwell_audio = {
279 .probe = broadwell_audio_probe,
280 .remove = broadwell_audio_remove,
281 .driver = {
282 .name = "broadwell-audio",
283 },
284};
285
286module_platform_driver(broadwell_audio)
287
288/* Module information */
289MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
290MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell");
291MODULE_LICENSE("GPL v2");
292MODULE_ALIAS("platform:broadwell-audio");
diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c
new file mode 100644
index 000000000000..7ab8cc9fbfd5
--- /dev/null
+++ b/sound/soc/intel/boards/byt-max98090.c
@@ -0,0 +1,187 @@
1/*
2 * Intel Baytrail SST MAX98090 machine driver
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/acpi.h>
19#include <linux/device.h>
20#include <linux/gpio.h>
21#include <linux/gpio/consumer.h>
22#include <linux/slab.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
26#include <sound/jack.h>
27#include "../../codecs/max98090.h"
28
29struct byt_max98090_private {
30 struct snd_soc_jack jack;
31};
32
33static const struct snd_soc_dapm_widget byt_max98090_widgets[] = {
34 SND_SOC_DAPM_HP("Headphone", NULL),
35 SND_SOC_DAPM_MIC("Headset Mic", NULL),
36 SND_SOC_DAPM_MIC("Int Mic", NULL),
37 SND_SOC_DAPM_SPK("Ext Spk", NULL),
38};
39
40static const struct snd_soc_dapm_route byt_max98090_audio_map[] = {
41 {"IN34", NULL, "Headset Mic"},
42 {"Headset Mic", NULL, "MICBIAS"},
43 {"DMICL", NULL, "Int Mic"},
44 {"Headphone", NULL, "HPL"},
45 {"Headphone", NULL, "HPR"},
46 {"Ext Spk", NULL, "SPKL"},
47 {"Ext Spk", NULL, "SPKR"},
48};
49
50static const struct snd_kcontrol_new byt_max98090_controls[] = {
51 SOC_DAPM_PIN_SWITCH("Headphone"),
52 SOC_DAPM_PIN_SWITCH("Headset Mic"),
53 SOC_DAPM_PIN_SWITCH("Int Mic"),
54 SOC_DAPM_PIN_SWITCH("Ext Spk"),
55};
56
57static struct snd_soc_jack_pin hs_jack_pins[] = {
58 {
59 .pin = "Headphone",
60 .mask = SND_JACK_HEADPHONE,
61 },
62 {
63 .pin = "Headset Mic",
64 .mask = SND_JACK_MICROPHONE,
65 },
66};
67
68static struct snd_soc_jack_gpio hs_jack_gpios[] = {
69 {
70 .name = "hp-gpio",
71 .idx = 0,
72 .report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
73 .debounce_time = 200,
74 },
75 {
76 .name = "mic-gpio",
77 .idx = 1,
78 .invert = 1,
79 .report = SND_JACK_MICROPHONE,
80 .debounce_time = 200,
81 },
82};
83
84static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
85{
86 int ret;
87 struct snd_soc_card *card = runtime->card;
88 struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card);
89 struct snd_soc_jack *jack = &drv->jack;
90
91 card->dapm.idle_bias_off = true;
92
93 ret = snd_soc_dai_set_sysclk(runtime->codec_dai,
94 M98090_REG_SYSTEM_CLOCK,
95 25000000, SND_SOC_CLOCK_IN);
96 if (ret < 0) {
97 dev_err(card->dev, "Can't set codec clock %d\n", ret);
98 return ret;
99 }
100
101 /* Enable jack detection */
102 ret = snd_soc_card_jack_new(runtime->card, "Headset",
103 SND_JACK_LINEOUT | SND_JACK_HEADSET, jack,
104 hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
105 if (ret)
106 return ret;
107
108 return snd_soc_jack_add_gpiods(card->dev->parent, jack,
109 ARRAY_SIZE(hs_jack_gpios),
110 hs_jack_gpios);
111}
112
113static struct snd_soc_dai_link byt_max98090_dais[] = {
114 {
115 .name = "Baytrail Audio",
116 .stream_name = "Audio",
117 .cpu_dai_name = "baytrail-pcm-audio",
118 .codec_dai_name = "HiFi",
119 .codec_name = "i2c-193C9890:00",
120 .platform_name = "baytrail-pcm-audio",
121 .init = byt_max98090_init,
122 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
123 SND_SOC_DAIFMT_CBS_CFS,
124 },
125};
126
127static struct snd_soc_card byt_max98090_card = {
128 .name = "byt-max98090",
129 .dai_link = byt_max98090_dais,
130 .num_links = ARRAY_SIZE(byt_max98090_dais),
131 .dapm_widgets = byt_max98090_widgets,
132 .num_dapm_widgets = ARRAY_SIZE(byt_max98090_widgets),
133 .dapm_routes = byt_max98090_audio_map,
134 .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map),
135 .controls = byt_max98090_controls,
136 .num_controls = ARRAY_SIZE(byt_max98090_controls),
137 .fully_routed = true,
138};
139
140static int byt_max98090_probe(struct platform_device *pdev)
141{
142 int ret_val = 0;
143 struct byt_max98090_private *priv;
144
145 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
146 if (!priv) {
147 dev_err(&pdev->dev, "allocation failed\n");
148 return -ENOMEM;
149 }
150
151 byt_max98090_card.dev = &pdev->dev;
152 snd_soc_card_set_drvdata(&byt_max98090_card, priv);
153 ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_max98090_card);
154 if (ret_val) {
155 dev_err(&pdev->dev,
156 "snd_soc_register_card failed %d\n", ret_val);
157 return ret_val;
158 }
159
160 return ret_val;
161}
162
163static int byt_max98090_remove(struct platform_device *pdev)
164{
165 struct snd_soc_card *card = platform_get_drvdata(pdev);
166 struct byt_max98090_private *priv = snd_soc_card_get_drvdata(card);
167
168 snd_soc_jack_free_gpios(&priv->jack, ARRAY_SIZE(hs_jack_gpios),
169 hs_jack_gpios);
170
171 return 0;
172}
173
174static struct platform_driver byt_max98090_driver = {
175 .probe = byt_max98090_probe,
176 .remove = byt_max98090_remove,
177 .driver = {
178 .name = "byt-max98090",
179 .pm = &snd_soc_pm_ops,
180 },
181};
182module_platform_driver(byt_max98090_driver)
183
184MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
185MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
186MODULE_LICENSE("GPL v2");
187MODULE_ALIAS("platform:byt-max98090");
diff --git a/sound/soc/intel/boards/byt-rt5640.c b/sound/soc/intel/boards/byt-rt5640.c
new file mode 100644
index 000000000000..ae89b9b966d9
--- /dev/null
+++ b/sound/soc/intel/boards/byt-rt5640.c
@@ -0,0 +1,229 @@
1/*
2 * Intel Baytrail SST RT5640 machine driver
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/acpi.h>
19#include <linux/device.h>
20#include <linux/dmi.h>
21#include <linux/slab.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/soc.h>
25#include <sound/jack.h>
26#include "../../codecs/rt5640.h"
27
28#include "../common/sst-dsp.h"
29
30static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
31 SND_SOC_DAPM_HP("Headphone", NULL),
32 SND_SOC_DAPM_MIC("Headset Mic", NULL),
33 SND_SOC_DAPM_MIC("Internal Mic", NULL),
34 SND_SOC_DAPM_SPK("Speaker", NULL),
35};
36
37static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
38 {"Headset Mic", NULL, "MICBIAS1"},
39 {"IN2P", NULL, "Headset Mic"},
40 {"Headphone", NULL, "HPOL"},
41 {"Headphone", NULL, "HPOR"},
42 {"Speaker", NULL, "SPOLP"},
43 {"Speaker", NULL, "SPOLN"},
44 {"Speaker", NULL, "SPORP"},
45 {"Speaker", NULL, "SPORN"},
46};
47
48static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
49 {"DMIC1", NULL, "Internal Mic"},
50};
51
52static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
53 {"DMIC2", NULL, "Internal Mic"},
54};
55
56static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
57 {"Internal Mic", NULL, "MICBIAS1"},
58 {"IN1P", NULL, "Internal Mic"},
59};
60
61enum {
62 BYT_RT5640_DMIC1_MAP,
63 BYT_RT5640_DMIC2_MAP,
64 BYT_RT5640_IN1_MAP,
65};
66
67#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
68#define BYT_RT5640_DMIC_EN BIT(16)
69
70static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
71 BYT_RT5640_DMIC_EN;
72
73static const struct snd_kcontrol_new byt_rt5640_controls[] = {
74 SOC_DAPM_PIN_SWITCH("Headphone"),
75 SOC_DAPM_PIN_SWITCH("Headset Mic"),
76 SOC_DAPM_PIN_SWITCH("Internal Mic"),
77 SOC_DAPM_PIN_SWITCH("Speaker"),
78};
79
80static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
81 struct snd_pcm_hw_params *params)
82{
83 struct snd_soc_pcm_runtime *rtd = substream->private_data;
84 struct snd_soc_dai *codec_dai = rtd->codec_dai;
85 int ret;
86
87 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
88 params_rate(params) * 256,
89 SND_SOC_CLOCK_IN);
90 if (ret < 0) {
91 dev_err(codec_dai->dev, "can't set codec clock %d\n", ret);
92 return ret;
93 }
94 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
95 params_rate(params) * 64,
96 params_rate(params) * 256);
97 if (ret < 0) {
98 dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
99 return ret;
100 }
101 return 0;
102}
103
104static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
105{
106 byt_rt5640_quirk = (unsigned long)id->driver_data;
107 return 1;
108}
109
110static const struct dmi_system_id byt_rt5640_quirk_table[] = {
111 {
112 .callback = byt_rt5640_quirk_cb,
113 .matches = {
114 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
115 DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
116 },
117 .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
118 },
119 {
120 .callback = byt_rt5640_quirk_cb,
121 .matches = {
122 DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
123 DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
124 },
125 .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
126 BYT_RT5640_DMIC_EN),
127 },
128 {}
129};
130
131static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
132{
133 int ret;
134 struct snd_soc_codec *codec = runtime->codec;
135 struct snd_soc_card *card = runtime->card;
136 const struct snd_soc_dapm_route *custom_map;
137 int num_routes;
138
139 card->dapm.idle_bias_off = true;
140
141 ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
142 ARRAY_SIZE(byt_rt5640_controls));
143 if (ret) {
144 dev_err(card->dev, "unable to add card controls\n");
145 return ret;
146 }
147
148 dmi_check_system(byt_rt5640_quirk_table);
149 switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
150 case BYT_RT5640_IN1_MAP:
151 custom_map = byt_rt5640_intmic_in1_map;
152 num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
153 break;
154 case BYT_RT5640_DMIC2_MAP:
155 custom_map = byt_rt5640_intmic_dmic2_map;
156 num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
157 break;
158 default:
159 custom_map = byt_rt5640_intmic_dmic1_map;
160 num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
161 }
162
163 ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
164 if (ret)
165 return ret;
166
167 if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
168 ret = rt5640_dmic_enable(codec, 0, 0);
169 if (ret)
170 return ret;
171 }
172
173 snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
174 snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
175
176 return ret;
177}
178
179static struct snd_soc_ops byt_rt5640_ops = {
180 .hw_params = byt_rt5640_hw_params,
181};
182
183static struct snd_soc_dai_link byt_rt5640_dais[] = {
184 {
185 .name = "Baytrail Audio",
186 .stream_name = "Audio",
187 .cpu_dai_name = "baytrail-pcm-audio",
188 .codec_dai_name = "rt5640-aif1",
189 .codec_name = "i2c-10EC5640:00",
190 .platform_name = "baytrail-pcm-audio",
191 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
192 SND_SOC_DAIFMT_CBS_CFS,
193 .init = byt_rt5640_init,
194 .ops = &byt_rt5640_ops,
195 },
196};
197
198static struct snd_soc_card byt_rt5640_card = {
199 .name = "byt-rt5640",
200 .dai_link = byt_rt5640_dais,
201 .num_links = ARRAY_SIZE(byt_rt5640_dais),
202 .dapm_widgets = byt_rt5640_widgets,
203 .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
204 .dapm_routes = byt_rt5640_audio_map,
205 .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
206 .fully_routed = true,
207};
208
209static int byt_rt5640_probe(struct platform_device *pdev)
210{
211 struct snd_soc_card *card = &byt_rt5640_card;
212
213 card->dev = &pdev->dev;
214 return devm_snd_soc_register_card(&pdev->dev, card);
215}
216
217static struct platform_driver byt_rt5640_audio = {
218 .probe = byt_rt5640_probe,
219 .driver = {
220 .name = "byt-rt5640",
221 .pm = &snd_soc_pm_ops,
222 },
223};
224module_platform_driver(byt_rt5640_audio)
225
226MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
227MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
228MODULE_LICENSE("GPL v2");
229MODULE_ALIAS("platform:byt-rt5640");
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
new file mode 100644
index 000000000000..7f55d59024a8
--- /dev/null
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -0,0 +1,227 @@
1/*
2 * byt_cr_dpcm_rt5640.c - ASoc Machine driver for Intel Byt CR platform
3 *
4 * Copyright (C) 2014 Intel Corp
5 * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18 */
19
20#include <linux/init.h>
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/device.h>
24#include <linux/slab.h>
25#include <linux/input.h>
26#include <sound/pcm.h>
27#include <sound/pcm_params.h>
28#include <sound/soc.h>
29#include "../../codecs/rt5640.h"
30#include "../atom/sst-atom-controls.h"
31
32static const struct snd_soc_dapm_widget byt_dapm_widgets[] = {
33 SND_SOC_DAPM_HP("Headphone", NULL),
34 SND_SOC_DAPM_MIC("Headset Mic", NULL),
35 SND_SOC_DAPM_MIC("Int Mic", NULL),
36 SND_SOC_DAPM_SPK("Ext Spk", NULL),
37};
38
39static const struct snd_soc_dapm_route byt_audio_map[] = {
40 {"IN2P", NULL, "Headset Mic"},
41 {"IN2N", NULL, "Headset Mic"},
42 {"Headset Mic", NULL, "MICBIAS1"},
43 {"IN1P", NULL, "MICBIAS1"},
44 {"LDO2", NULL, "Int Mic"},
45 {"Headphone", NULL, "HPOL"},
46 {"Headphone", NULL, "HPOR"},
47 {"Ext Spk", NULL, "SPOLP"},
48 {"Ext Spk", NULL, "SPOLN"},
49 {"Ext Spk", NULL, "SPORP"},
50 {"Ext Spk", NULL, "SPORN"},
51
52 {"AIF1 Playback", NULL, "ssp2 Tx"},
53 {"ssp2 Tx", NULL, "codec_out0"},
54 {"ssp2 Tx", NULL, "codec_out1"},
55 {"codec_in0", NULL, "ssp2 Rx"},
56 {"codec_in1", NULL, "ssp2 Rx"},
57 {"ssp2 Rx", NULL, "AIF1 Capture"},
58};
59
60static const struct snd_kcontrol_new byt_mc_controls[] = {
61 SOC_DAPM_PIN_SWITCH("Headphone"),
62 SOC_DAPM_PIN_SWITCH("Headset Mic"),
63 SOC_DAPM_PIN_SWITCH("Int Mic"),
64 SOC_DAPM_PIN_SWITCH("Ext Spk"),
65};
66
67static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
68 struct snd_pcm_hw_params *params)
69{
70 struct snd_soc_pcm_runtime *rtd = substream->private_data;
71 struct snd_soc_dai *codec_dai = rtd->codec_dai;
72 int ret;
73
74 snd_soc_dai_set_bclk_ratio(codec_dai, 50);
75
76 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
77 params_rate(params) * 512,
78 SND_SOC_CLOCK_IN);
79 if (ret < 0) {
80 dev_err(rtd->dev, "can't set codec clock %d\n", ret);
81 return ret;
82 }
83
84 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
85 params_rate(params) * 50,
86 params_rate(params) * 512);
87 if (ret < 0) {
88 dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
89 return ret;
90 }
91
92 return 0;
93}
94
95static const struct snd_soc_pcm_stream byt_dai_params = {
96 .formats = SNDRV_PCM_FMTBIT_S24_LE,
97 .rate_min = 48000,
98 .rate_max = 48000,
99 .channels_min = 2,
100 .channels_max = 2,
101};
102
103static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
104 struct snd_pcm_hw_params *params)
105{
106 struct snd_interval *rate = hw_param_interval(params,
107 SNDRV_PCM_HW_PARAM_RATE);
108 struct snd_interval *channels = hw_param_interval(params,
109 SNDRV_PCM_HW_PARAM_CHANNELS);
110
111 /* The DSP will covert the FE rate to 48k, stereo, 24bits */
112 rate->min = rate->max = 48000;
113 channels->min = channels->max = 2;
114
115 /* set SSP2 to 24-bit */
116 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
117 return 0;
118}
119
120static unsigned int rates_48000[] = {
121 48000,
122};
123
124static struct snd_pcm_hw_constraint_list constraints_48000 = {
125 .count = ARRAY_SIZE(rates_48000),
126 .list = rates_48000,
127};
128
129static int byt_aif1_startup(struct snd_pcm_substream *substream)
130{
131 return snd_pcm_hw_constraint_list(substream->runtime, 0,
132 SNDRV_PCM_HW_PARAM_RATE,
133 &constraints_48000);
134}
135
136static struct snd_soc_ops byt_aif1_ops = {
137 .startup = byt_aif1_startup,
138};
139
140static struct snd_soc_ops byt_be_ssp2_ops = {
141 .hw_params = byt_aif1_hw_params,
142};
143
144static struct snd_soc_dai_link byt_dailink[] = {
145 [MERR_DPCM_AUDIO] = {
146 .name = "Baytrail Audio Port",
147 .stream_name = "Baytrail Audio",
148 .cpu_dai_name = "media-cpu-dai",
149 .codec_dai_name = "snd-soc-dummy-dai",
150 .codec_name = "snd-soc-dummy",
151 .platform_name = "sst-mfld-platform",
152 .ignore_suspend = 1,
153 .dynamic = 1,
154 .dpcm_playback = 1,
155 .dpcm_capture = 1,
156 .ops = &byt_aif1_ops,
157 },
158 [MERR_DPCM_COMPR] = {
159 .name = "Baytrail Compressed Port",
160 .stream_name = "Baytrail Compress",
161 .cpu_dai_name = "compress-cpu-dai",
162 .codec_dai_name = "snd-soc-dummy-dai",
163 .codec_name = "snd-soc-dummy",
164 .platform_name = "sst-mfld-platform",
165 },
166 /* back ends */
167 {
168 .name = "SSP2-Codec",
169 .be_id = 1,
170 .cpu_dai_name = "ssp2-port",
171 .platform_name = "sst-mfld-platform",
172 .no_pcm = 1,
173 .codec_dai_name = "rt5640-aif1",
174 .codec_name = "i2c-10EC5640:00",
175 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
176 | SND_SOC_DAIFMT_CBS_CFS,
177 .be_hw_params_fixup = byt_codec_fixup,
178 .ignore_suspend = 1,
179 .dpcm_playback = 1,
180 .dpcm_capture = 1,
181 .ops = &byt_be_ssp2_ops,
182 },
183};
184
185/* SoC card */
186static struct snd_soc_card snd_soc_card_byt = {
187 .name = "baytrailcraudio",
188 .dai_link = byt_dailink,
189 .num_links = ARRAY_SIZE(byt_dailink),
190 .dapm_widgets = byt_dapm_widgets,
191 .num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets),
192 .dapm_routes = byt_audio_map,
193 .num_dapm_routes = ARRAY_SIZE(byt_audio_map),
194 .controls = byt_mc_controls,
195 .num_controls = ARRAY_SIZE(byt_mc_controls),
196};
197
198static int snd_byt_mc_probe(struct platform_device *pdev)
199{
200 int ret_val = 0;
201
202 /* register the soc card */
203 snd_soc_card_byt.dev = &pdev->dev;
204
205 ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt);
206 if (ret_val) {
207 dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val);
208 return ret_val;
209 }
210 platform_set_drvdata(pdev, &snd_soc_card_byt);
211 return ret_val;
212}
213
214static struct platform_driver snd_byt_mc_driver = {
215 .driver = {
216 .name = "bytt100_rt5640",
217 .pm = &snd_soc_pm_ops,
218 },
219 .probe = snd_byt_mc_probe,
220};
221
222module_platform_driver(snd_byt_mc_driver);
223
224MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
225MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
226MODULE_LICENSE("GPL v2");
227MODULE_ALIAS("platform:bytt100_rt5640");
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
new file mode 100644
index 000000000000..20a28b22e30f
--- /dev/null
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -0,0 +1,324 @@
1/*
2 * cht-bsw-rt5645.c - ASoc Machine driver for Intel Cherryview-based platforms
3 * Cherrytrail and Braswell, with RT5645 codec.
4 *
5 * Copyright (C) 2015 Intel Corp
6 * Author: Fang, Yang A <yang.a.fang@intel.com>
7 * N,Harshapriya <harshapriya.n@intel.com>
8 * This file is modified from cht_bsw_rt5672.c
9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21 */
22
23#include <linux/module.h>
24#include <linux/platform_device.h>
25#include <linux/slab.h>
26#include <sound/pcm.h>
27#include <sound/pcm_params.h>
28#include <sound/soc.h>
29#include <sound/jack.h>
30#include "../../codecs/rt5645.h"
31#include "../atom/sst-atom-controls.h"
32
33#define CHT_PLAT_CLK_3_HZ 19200000
34#define CHT_CODEC_DAI "rt5645-aif1"
35
36struct cht_mc_private {
37 struct snd_soc_jack hp_jack;
38 struct snd_soc_jack mic_jack;
39};
40
41static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
42{
43 int i;
44
45 for (i = 0; i < card->num_rtd; i++) {
46 struct snd_soc_pcm_runtime *rtd;
47
48 rtd = card->rtd + i;
49 if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
50 strlen(CHT_CODEC_DAI)))
51 return rtd->codec_dai;
52 }
53 return NULL;
54}
55
56static int platform_clock_control(struct snd_soc_dapm_widget *w,
57 struct snd_kcontrol *k, int event)
58{
59 struct snd_soc_dapm_context *dapm = w->dapm;
60 struct snd_soc_card *card = dapm->card;
61 struct snd_soc_dai *codec_dai;
62 int ret;
63
64 codec_dai = cht_get_codec_dai(card);
65 if (!codec_dai) {
66 dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
67 return -EIO;
68 }
69
70 if (!SND_SOC_DAPM_EVENT_OFF(event))
71 return 0;
72
73 /* Set codec sysclk source to its internal clock because codec PLL will
74 * be off when idle and MCLK will also be off by ACPI when codec is
75 * runtime suspended. Codec needs clock for jack detection and button
76 * press.
77 */
78 ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK,
79 0, SND_SOC_CLOCK_IN);
80 if (ret < 0) {
81 dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
82 return ret;
83 }
84
85 return 0;
86}
87
88static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
89 SND_SOC_DAPM_HP("Headphone", NULL),
90 SND_SOC_DAPM_MIC("Headset Mic", NULL),
91 SND_SOC_DAPM_MIC("Int Mic", NULL),
92 SND_SOC_DAPM_SPK("Ext Spk", NULL),
93 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
94 platform_clock_control, SND_SOC_DAPM_POST_PMD),
95};
96
97static const struct snd_soc_dapm_route cht_audio_map[] = {
98 {"IN1P", NULL, "Headset Mic"},
99 {"IN1N", NULL, "Headset Mic"},
100 {"DMIC L1", NULL, "Int Mic"},
101 {"DMIC R1", NULL, "Int Mic"},
102 {"Headphone", NULL, "HPOL"},
103 {"Headphone", NULL, "HPOR"},
104 {"Ext Spk", NULL, "SPOL"},
105 {"Ext Spk", NULL, "SPOR"},
106 {"AIF1 Playback", NULL, "ssp2 Tx"},
107 {"ssp2 Tx", NULL, "codec_out0"},
108 {"ssp2 Tx", NULL, "codec_out1"},
109 {"codec_in0", NULL, "ssp2 Rx" },
110 {"codec_in1", NULL, "ssp2 Rx" },
111 {"ssp2 Rx", NULL, "AIF1 Capture"},
112 {"Headphone", NULL, "Platform Clock"},
113 {"Headset Mic", NULL, "Platform Clock"},
114 {"Int Mic", NULL, "Platform Clock"},
115 {"Ext Spk", NULL, "Platform Clock"},
116};
117
118static const struct snd_kcontrol_new cht_mc_controls[] = {
119 SOC_DAPM_PIN_SWITCH("Headphone"),
120 SOC_DAPM_PIN_SWITCH("Headset Mic"),
121 SOC_DAPM_PIN_SWITCH("Int Mic"),
122 SOC_DAPM_PIN_SWITCH("Ext Spk"),
123};
124
125static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
126 struct snd_pcm_hw_params *params)
127{
128 struct snd_soc_pcm_runtime *rtd = substream->private_data;
129 struct snd_soc_dai *codec_dai = rtd->codec_dai;
130 int ret;
131
132 /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
133 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
134 CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
135 if (ret < 0) {
136 dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
137 return ret;
138 }
139
140 ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1,
141 params_rate(params) * 512, SND_SOC_CLOCK_IN);
142 if (ret < 0) {
143 dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
144 return ret;
145 }
146
147 return 0;
148}
149
150static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
151{
152 int ret;
153 struct snd_soc_codec *codec = runtime->codec;
154 struct snd_soc_dai *codec_dai = runtime->codec_dai;
155 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
156
157 /* Select clk_i2s1_asrc as ASRC clock source */
158 rt5645_sel_asrc_clk_src(codec,
159 RT5645_DA_STEREO_FILTER |
160 RT5645_DA_MONO_L_FILTER |
161 RT5645_DA_MONO_R_FILTER |
162 RT5645_AD_STEREO_FILTER,
163 RT5645_CLK_SEL_I2S1_ASRC);
164
165 /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
166 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
167 if (ret < 0) {
168 dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
169 return ret;
170 }
171
172 ret = snd_soc_card_jack_new(runtime->card, "Headphone Jack",
173 SND_JACK_HEADPHONE, &ctx->hp_jack,
174 NULL, 0);
175 if (ret) {
176 dev_err(runtime->dev, "HP jack creation failed %d\n", ret);
177 return ret;
178 }
179
180 ret = snd_soc_card_jack_new(runtime->card, "Mic Jack",
181 SND_JACK_MICROPHONE, &ctx->mic_jack,
182 NULL, 0);
183 if (ret) {
184 dev_err(runtime->dev, "Mic jack creation failed %d\n", ret);
185 return ret;
186 }
187
188 rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack);
189
190 return ret;
191}
192
193static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
194 struct snd_pcm_hw_params *params)
195{
196 struct snd_interval *rate = hw_param_interval(params,
197 SNDRV_PCM_HW_PARAM_RATE);
198 struct snd_interval *channels = hw_param_interval(params,
199 SNDRV_PCM_HW_PARAM_CHANNELS);
200
201 /* The DSP will covert the FE rate to 48k, stereo, 24bits */
202 rate->min = rate->max = 48000;
203 channels->min = channels->max = 2;
204
205 /* set SSP2 to 24-bit */
206 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
207 return 0;
208}
209
210static unsigned int rates_48000[] = {
211 48000,
212};
213
214static struct snd_pcm_hw_constraint_list constraints_48000 = {
215 .count = ARRAY_SIZE(rates_48000),
216 .list = rates_48000,
217};
218
219static int cht_aif1_startup(struct snd_pcm_substream *substream)
220{
221 return snd_pcm_hw_constraint_list(substream->runtime, 0,
222 SNDRV_PCM_HW_PARAM_RATE,
223 &constraints_48000);
224}
225
226static struct snd_soc_ops cht_aif1_ops = {
227 .startup = cht_aif1_startup,
228};
229
230static struct snd_soc_ops cht_be_ssp2_ops = {
231 .hw_params = cht_aif1_hw_params,
232};
233
234static struct snd_soc_dai_link cht_dailink[] = {
235 [MERR_DPCM_AUDIO] = {
236 .name = "Audio Port",
237 .stream_name = "Audio",
238 .cpu_dai_name = "media-cpu-dai",
239 .codec_dai_name = "snd-soc-dummy-dai",
240 .codec_name = "snd-soc-dummy",
241 .platform_name = "sst-mfld-platform",
242 .ignore_suspend = 1,
243 .dynamic = 1,
244 .dpcm_playback = 1,
245 .dpcm_capture = 1,
246 .ops = &cht_aif1_ops,
247 },
248 [MERR_DPCM_COMPR] = {
249 .name = "Compressed Port",
250 .stream_name = "Compress",
251 .cpu_dai_name = "compress-cpu-dai",
252 .codec_dai_name = "snd-soc-dummy-dai",
253 .codec_name = "snd-soc-dummy",
254 .platform_name = "sst-mfld-platform",
255 },
256 /* CODEC<->CODEC link */
257 /* back ends */
258 {
259 .name = "SSP2-Codec",
260 .be_id = 1,
261 .cpu_dai_name = "ssp2-port",
262 .platform_name = "sst-mfld-platform",
263 .no_pcm = 1,
264 .codec_dai_name = "rt5645-aif1",
265 .codec_name = "i2c-10EC5645:00",
266 .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
267 | SND_SOC_DAIFMT_CBS_CFS,
268 .init = cht_codec_init,
269 .be_hw_params_fixup = cht_codec_fixup,
270 .ignore_suspend = 1,
271 .dpcm_playback = 1,
272 .dpcm_capture = 1,
273 .ops = &cht_be_ssp2_ops,
274 },
275};
276
277/* SoC card */
278static struct snd_soc_card snd_soc_card_cht = {
279 .name = "chtrt5645",
280 .dai_link = cht_dailink,
281 .num_links = ARRAY_SIZE(cht_dailink),
282 .dapm_widgets = cht_dapm_widgets,
283 .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
284 .dapm_routes = cht_audio_map,
285 .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
286 .controls = cht_mc_controls,
287 .num_controls = ARRAY_SIZE(cht_mc_controls),
288};
289
290static int snd_cht_mc_probe(struct platform_device *pdev)
291{
292 int ret_val = 0;
293 struct cht_mc_private *drv;
294
295 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
296 if (!drv)
297 return -ENOMEM;
298
299 snd_soc_card_cht.dev = &pdev->dev;
300 snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
301 ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
302 if (ret_val) {
303 dev_err(&pdev->dev,
304 "snd_soc_register_card failed %d\n", ret_val);
305 return ret_val;
306 }
307 platform_set_drvdata(pdev, &snd_soc_card_cht);
308 return ret_val;
309}
310
311static struct platform_driver snd_cht_mc_driver = {
312 .driver = {
313 .name = "cht-bsw-rt5645",
314 .pm = &snd_soc_pm_ops,
315 },
316 .probe = snd_cht_mc_probe,
317};
318
319module_platform_driver(snd_cht_mc_driver)
320
321MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");
322MODULE_AUTHOR("Fang, Yang A,N,Harshapriya");
323MODULE_LICENSE("GPL v2");
324MODULE_ALIAS("platform:cht-bsw-rt5645");
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
new file mode 100644
index 000000000000..2c9cc5be439e
--- /dev/null
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -0,0 +1,366 @@
1/*
2 * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms
3 * Cherrytrail and Braswell, with RT5672 codec.
4 *
5 * Copyright (C) 2014 Intel Corp
6 * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
7 * Mengdong Lin <mengdong.lin@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 */
18
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/soc.h>
25#include <sound/jack.h>
26#include "../../codecs/rt5670.h"
27#include "../atom/sst-atom-controls.h"
28
29/* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */
30#define CHT_PLAT_CLK_3_HZ 19200000
31#define CHT_CODEC_DAI "rt5670-aif1"
32
33static struct snd_soc_jack cht_bsw_headset;
34
35/* Headset jack detection DAPM pins */
36static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
37 {
38 .pin = "Headset Mic",
39 .mask = SND_JACK_MICROPHONE,
40 },
41 {
42 .pin = "Headphone",
43 .mask = SND_JACK_HEADPHONE,
44 },
45};
46
47static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
48{
49 int i;
50
51 for (i = 0; i < card->num_rtd; i++) {
52 struct snd_soc_pcm_runtime *rtd;
53
54 rtd = card->rtd + i;
55 if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
56 strlen(CHT_CODEC_DAI)))
57 return rtd->codec_dai;
58 }
59 return NULL;
60}
61
62static int platform_clock_control(struct snd_soc_dapm_widget *w,
63 struct snd_kcontrol *k, int event)
64{
65 struct snd_soc_dapm_context *dapm = w->dapm;
66 struct snd_soc_card *card = dapm->card;
67 struct snd_soc_dai *codec_dai;
68 int ret;
69
70 codec_dai = cht_get_codec_dai(card);
71 if (!codec_dai) {
72 dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
73 return -EIO;
74 }
75
76 if (SND_SOC_DAPM_EVENT_ON(event)) {
77 /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
78 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
79 CHT_PLAT_CLK_3_HZ, 48000 * 512);
80 if (ret < 0) {
81 dev_err(card->dev, "can't set codec pll: %d\n", ret);
82 return ret;
83 }
84
85 /* set codec sysclk source to PLL */
86 ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
87 48000 * 512, SND_SOC_CLOCK_IN);
88 if (ret < 0) {
89 dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
90 return ret;
91 }
92 } else {
93 /* Set codec sysclk source to its internal clock because codec
94 * PLL will be off when idle and MCLK will also be off by ACPI
95 * when codec is runtime suspended. Codec needs clock for jack
96 * detection and button press.
97 */
98 snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
99 48000 * 512, SND_SOC_CLOCK_IN);
100 }
101 return 0;
102}
103
104static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
105 SND_SOC_DAPM_HP("Headphone", NULL),
106 SND_SOC_DAPM_MIC("Headset Mic", NULL),
107 SND_SOC_DAPM_MIC("Int Mic", NULL),
108 SND_SOC_DAPM_SPK("Ext Spk", NULL),
109 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
110 platform_clock_control, SND_SOC_DAPM_PRE_PMU |
111 SND_SOC_DAPM_POST_PMD),
112};
113
114static const struct snd_soc_dapm_route cht_audio_map[] = {
115 {"IN1P", NULL, "Headset Mic"},
116 {"IN1N", NULL, "Headset Mic"},
117 {"DMIC L1", NULL, "Int Mic"},
118 {"DMIC R1", NULL, "Int Mic"},
119 {"Headphone", NULL, "HPOL"},
120 {"Headphone", NULL, "HPOR"},
121 {"Ext Spk", NULL, "SPOLP"},
122 {"Ext Spk", NULL, "SPOLN"},
123 {"Ext Spk", NULL, "SPORP"},
124 {"Ext Spk", NULL, "SPORN"},
125 {"AIF1 Playback", NULL, "ssp2 Tx"},
126 {"ssp2 Tx", NULL, "codec_out0"},
127 {"ssp2 Tx", NULL, "codec_out1"},
128 {"codec_in0", NULL, "ssp2 Rx"},
129 {"codec_in1", NULL, "ssp2 Rx"},
130 {"ssp2 Rx", NULL, "AIF1 Capture"},
131 {"Headphone", NULL, "Platform Clock"},
132 {"Headset Mic", NULL, "Platform Clock"},
133 {"Int Mic", NULL, "Platform Clock"},
134 {"Ext Spk", NULL, "Platform Clock"},
135};
136
137static const struct snd_kcontrol_new cht_mc_controls[] = {
138 SOC_DAPM_PIN_SWITCH("Headphone"),
139 SOC_DAPM_PIN_SWITCH("Headset Mic"),
140 SOC_DAPM_PIN_SWITCH("Int Mic"),
141 SOC_DAPM_PIN_SWITCH("Ext Spk"),
142};
143
144static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
145 struct snd_pcm_hw_params *params)
146{
147 struct snd_soc_pcm_runtime *rtd = substream->private_data;
148 struct snd_soc_dai *codec_dai = rtd->codec_dai;
149 int ret;
150
151 /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
152 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
153 CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
154 if (ret < 0) {
155 dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
156 return ret;
157 }
158
159 /* set codec sysclk source to PLL */
160 ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
161 params_rate(params) * 512,
162 SND_SOC_CLOCK_IN);
163 if (ret < 0) {
164 dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
165 return ret;
166 }
167 return 0;
168}
169
170static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
171{
172 int ret;
173 struct snd_soc_dai *codec_dai = runtime->codec_dai;
174 struct snd_soc_codec *codec = codec_dai->codec;
175
176 /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
177 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
178 if (ret < 0) {
179 dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
180 return ret;
181 }
182
183 /* Select codec ASRC clock source to track I2S1 clock, because codec
184 * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot
185 * be supported by RT5672. Otherwise, ASRC will be disabled and cause
186 * noise.
187 */
188 rt5670_sel_asrc_clk_src(codec,
189 RT5670_DA_STEREO_FILTER
190 | RT5670_DA_MONO_L_FILTER
191 | RT5670_DA_MONO_R_FILTER
192 | RT5670_AD_STEREO_FILTER
193 | RT5670_AD_MONO_L_FILTER
194 | RT5670_AD_MONO_R_FILTER,
195 RT5670_CLK_SEL_I2S1_ASRC);
196
197 ret = snd_soc_card_jack_new(runtime->card, "Headset",
198 SND_JACK_HEADSET | SND_JACK_BTN_0 |
199 SND_JACK_BTN_1 | SND_JACK_BTN_2, &cht_bsw_headset,
200 cht_bsw_headset_pins, ARRAY_SIZE(cht_bsw_headset_pins));
201 if (ret)
202 return ret;
203
204 rt5670_set_jack_detect(codec, &cht_bsw_headset);
205 return 0;
206}
207
208static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
209 struct snd_pcm_hw_params *params)
210{
211 struct snd_interval *rate = hw_param_interval(params,
212 SNDRV_PCM_HW_PARAM_RATE);
213 struct snd_interval *channels = hw_param_interval(params,
214 SNDRV_PCM_HW_PARAM_CHANNELS);
215
216 /* The DSP will covert the FE rate to 48k, stereo, 24bits */
217 rate->min = rate->max = 48000;
218 channels->min = channels->max = 2;
219
220 /* set SSP2 to 24-bit */
221 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
222 return 0;
223}
224
225static unsigned int rates_48000[] = {
226 48000,
227};
228
229static struct snd_pcm_hw_constraint_list constraints_48000 = {
230 .count = ARRAY_SIZE(rates_48000),
231 .list = rates_48000,
232};
233
234static int cht_aif1_startup(struct snd_pcm_substream *substream)
235{
236 return snd_pcm_hw_constraint_list(substream->runtime, 0,
237 SNDRV_PCM_HW_PARAM_RATE,
238 &constraints_48000);
239}
240
241static struct snd_soc_ops cht_aif1_ops = {
242 .startup = cht_aif1_startup,
243};
244
245static struct snd_soc_ops cht_be_ssp2_ops = {
246 .hw_params = cht_aif1_hw_params,
247};
248
249static struct snd_soc_dai_link cht_dailink[] = {
250 /* Front End DAI links */
251 [MERR_DPCM_AUDIO] = {
252 .name = "Audio Port",
253 .stream_name = "Audio",
254 .cpu_dai_name = "media-cpu-dai",
255 .codec_dai_name = "snd-soc-dummy-dai",
256 .codec_name = "snd-soc-dummy",
257 .platform_name = "sst-mfld-platform",
258 .nonatomic = true,
259 .dynamic = 1,
260 .dpcm_playback = 1,
261 .dpcm_capture = 1,
262 .ops = &cht_aif1_ops,
263 },
264 [MERR_DPCM_COMPR] = {
265 .name = "Compressed Port",
266 .stream_name = "Compress",
267 .cpu_dai_name = "compress-cpu-dai",
268 .codec_dai_name = "snd-soc-dummy-dai",
269 .codec_name = "snd-soc-dummy",
270 .platform_name = "sst-mfld-platform",
271 },
272
273 /* Back End DAI links */
274 {
275 /* SSP2 - Codec */
276 .name = "SSP2-Codec",
277 .be_id = 1,
278 .cpu_dai_name = "ssp2-port",
279 .platform_name = "sst-mfld-platform",
280 .no_pcm = 1,
281 .nonatomic = true,
282 .codec_dai_name = "rt5670-aif1",
283 .codec_name = "i2c-10EC5670:00",
284 .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
285 | SND_SOC_DAIFMT_CBS_CFS,
286 .init = cht_codec_init,
287 .be_hw_params_fixup = cht_codec_fixup,
288 .dpcm_playback = 1,
289 .dpcm_capture = 1,
290 .ops = &cht_be_ssp2_ops,
291 },
292};
293
294static int cht_suspend_pre(struct snd_soc_card *card)
295{
296 struct snd_soc_codec *codec;
297
298 list_for_each_entry(codec, &card->codec_dev_list, card_list) {
299 if (!strcmp(codec->component.name, "i2c-10EC5670:00")) {
300 dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");
301 rt5670_jack_suspend(codec);
302 break;
303 }
304 }
305 return 0;
306}
307
308static int cht_resume_post(struct snd_soc_card *card)
309{
310 struct snd_soc_codec *codec;
311
312 list_for_each_entry(codec, &card->codec_dev_list, card_list) {
313 if (!strcmp(codec->component.name, "i2c-10EC5670:00")) {
314 dev_dbg(codec->dev, "enabling jack detect for resume.\n");
315 rt5670_jack_resume(codec);
316 break;
317 }
318 }
319
320 return 0;
321}
322
323/* SoC card */
324static struct snd_soc_card snd_soc_card_cht = {
325 .name = "cherrytrailcraudio",
326 .dai_link = cht_dailink,
327 .num_links = ARRAY_SIZE(cht_dailink),
328 .dapm_widgets = cht_dapm_widgets,
329 .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
330 .dapm_routes = cht_audio_map,
331 .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
332 .controls = cht_mc_controls,
333 .num_controls = ARRAY_SIZE(cht_mc_controls),
334 .suspend_pre = cht_suspend_pre,
335 .resume_post = cht_resume_post,
336};
337
338static int snd_cht_mc_probe(struct platform_device *pdev)
339{
340 int ret_val = 0;
341
342 /* register the soc card */
343 snd_soc_card_cht.dev = &pdev->dev;
344 ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
345 if (ret_val) {
346 dev_err(&pdev->dev,
347 "snd_soc_register_card failed %d\n", ret_val);
348 return ret_val;
349 }
350 platform_set_drvdata(pdev, &snd_soc_card_cht);
351 return ret_val;
352}
353
354static struct platform_driver snd_cht_mc_driver = {
355 .driver = {
356 .name = "cht-bsw-rt5672",
357 },
358 .probe = snd_cht_mc_probe,
359};
360
361module_platform_driver(snd_cht_mc_driver);
362
363MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
364MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin");
365MODULE_LICENSE("GPL v2");
366MODULE_ALIAS("platform:cht-bsw-rt5672");
diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c
new file mode 100644
index 000000000000..22558572cb9c
--- /dev/null
+++ b/sound/soc/intel/boards/haswell.c
@@ -0,0 +1,209 @@
1/*
2 * Intel Haswell Lynxpoint SST Audio
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/soc.h>
22#include <sound/pcm_params.h>
23
24#include "../common/sst-dsp.h"
25#include "../haswell/sst-haswell-ipc.h"
26
27#include "../../codecs/rt5640.h"
28
29/* Haswell ULT platforms have a Headphone and Mic jack */
30static const struct snd_soc_dapm_widget haswell_widgets[] = {
31 SND_SOC_DAPM_HP("Headphones", NULL),
32 SND_SOC_DAPM_MIC("Mic", NULL),
33};
34
35static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
36
37 {"Headphones", NULL, "HPOR"},
38 {"Headphones", NULL, "HPOL"},
39 {"IN2P", NULL, "Mic"},
40
41 /* CODEC BE connections */
42 {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
43 {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
44};
45
46static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
47 struct snd_pcm_hw_params *params)
48{
49 struct snd_interval *rate = hw_param_interval(params,
50 SNDRV_PCM_HW_PARAM_RATE);
51 struct snd_interval *channels = hw_param_interval(params,
52 SNDRV_PCM_HW_PARAM_CHANNELS);
53
54 /* The ADSP will covert the FE rate to 48k, stereo */
55 rate->min = rate->max = 48000;
56 channels->min = channels->max = 2;
57
58 /* set SSP0 to 16 bit */
59 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
60 return 0;
61}
62
63static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
64 struct snd_pcm_hw_params *params)
65{
66 struct snd_soc_pcm_runtime *rtd = substream->private_data;
67 struct snd_soc_dai *codec_dai = rtd->codec_dai;
68 int ret;
69
70 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
71 SND_SOC_CLOCK_IN);
72
73 if (ret < 0) {
74 dev_err(rtd->dev, "can't set codec sysclk configuration\n");
75 return ret;
76 }
77
78 /* set correct codec filter for DAI format and clock config */
79 snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
80
81 return ret;
82}
83
84static struct snd_soc_ops haswell_rt5640_ops = {
85 .hw_params = haswell_rt5640_hw_params,
86};
87
88static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
89{
90 struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
91 struct sst_hsw *haswell = pdata->dsp;
92 int ret;
93
94 /* Set ADSP SSP port settings */
95 ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0,
96 SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
97 SST_HSW_DEVICE_CLOCK_MASTER, 9);
98 if (ret < 0) {
99 dev_err(rtd->dev, "failed to set device config\n");
100 return ret;
101 }
102
103 return 0;
104}
105
106static struct snd_soc_dai_link haswell_rt5640_dais[] = {
107 /* Front End DAI links */
108 {
109 .name = "System",
110 .stream_name = "System Playback/Capture",
111 .cpu_dai_name = "System Pin",
112 .platform_name = "haswell-pcm-audio",
113 .dynamic = 1,
114 .codec_name = "snd-soc-dummy",
115 .codec_dai_name = "snd-soc-dummy-dai",
116 .init = haswell_rtd_init,
117 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
118 .dpcm_playback = 1,
119 .dpcm_capture = 1,
120 },
121 {
122 .name = "Offload0",
123 .stream_name = "Offload0 Playback",
124 .cpu_dai_name = "Offload0 Pin",
125 .platform_name = "haswell-pcm-audio",
126 .dynamic = 1,
127 .codec_name = "snd-soc-dummy",
128 .codec_dai_name = "snd-soc-dummy-dai",
129 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
130 .dpcm_playback = 1,
131 },
132 {
133 .name = "Offload1",
134 .stream_name = "Offload1 Playback",
135 .cpu_dai_name = "Offload1 Pin",
136 .platform_name = "haswell-pcm-audio",
137 .dynamic = 1,
138 .codec_name = "snd-soc-dummy",
139 .codec_dai_name = "snd-soc-dummy-dai",
140 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
141 .dpcm_playback = 1,
142 },
143 {
144 .name = "Loopback",
145 .stream_name = "Loopback",
146 .cpu_dai_name = "Loopback Pin",
147 .platform_name = "haswell-pcm-audio",
148 .dynamic = 0,
149 .codec_name = "snd-soc-dummy",
150 .codec_dai_name = "snd-soc-dummy-dai",
151 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
152 .dpcm_capture = 1,
153 },
154
155 /* Back End DAI links */
156 {
157 /* SSP0 - Codec */
158 .name = "Codec",
159 .be_id = 0,
160 .cpu_dai_name = "snd-soc-dummy-dai",
161 .platform_name = "snd-soc-dummy",
162 .no_pcm = 1,
163 .codec_name = "i2c-INT33CA:00",
164 .codec_dai_name = "rt5640-aif1",
165 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
166 SND_SOC_DAIFMT_CBS_CFS,
167 .ignore_suspend = 1,
168 .ignore_pmdown_time = 1,
169 .be_hw_params_fixup = haswell_ssp0_fixup,
170 .ops = &haswell_rt5640_ops,
171 .dpcm_playback = 1,
172 .dpcm_capture = 1,
173 },
174};
175
176/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
177static struct snd_soc_card haswell_rt5640 = {
178 .name = "haswell-rt5640",
179 .owner = THIS_MODULE,
180 .dai_link = haswell_rt5640_dais,
181 .num_links = ARRAY_SIZE(haswell_rt5640_dais),
182 .dapm_widgets = haswell_widgets,
183 .num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
184 .dapm_routes = haswell_rt5640_map,
185 .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
186 .fully_routed = true,
187};
188
189static int haswell_audio_probe(struct platform_device *pdev)
190{
191 haswell_rt5640.dev = &pdev->dev;
192
193 return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640);
194}
195
196static struct platform_driver haswell_audio = {
197 .probe = haswell_audio_probe,
198 .driver = {
199 .name = "haswell-audio",
200 },
201};
202
203module_platform_driver(haswell_audio)
204
205/* Module information */
206MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
207MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
208MODULE_LICENSE("GPL v2");
209MODULE_ALIAS("platform:haswell-audio");
diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c
new file mode 100644
index 000000000000..49c09a0add79
--- /dev/null
+++ b/sound/soc/intel/boards/mfld_machine.c
@@ -0,0 +1,430 @@
1/*
2 * mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform
3 *
4 * Copyright (C) 2010 Intel Corp
5 * Author: Vinod Koul <vinod.koul@intel.com>
6 * Author: Harsha Priya <priya.harsha@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */
24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/init.h>
28#include <linux/device.h>
29#include <linux/slab.h>
30#include <linux/io.h>
31#include <linux/module.h>
32#include <sound/pcm.h>
33#include <sound/pcm_params.h>
34#include <sound/soc.h>
35#include <sound/jack.h>
36#include "../codecs/sn95031.h"
37
38#define MID_MONO 1
39#define MID_STEREO 2
40#define MID_MAX_CAP 5
41#define MFLD_JACK_INSERT 0x04
42
43enum soc_mic_bias_zones {
44 MFLD_MV_START = 0,
45 /* mic bias volutage range for Headphones*/
46 MFLD_MV_HP = 400,
47 /* mic bias volutage range for American Headset*/
48 MFLD_MV_AM_HS = 650,
49 /* mic bias volutage range for Headset*/
50 MFLD_MV_HS = 2000,
51 MFLD_MV_UNDEFINED,
52};
53
54static unsigned int hs_switch;
55static unsigned int lo_dac;
56static struct snd_soc_codec *mfld_codec;
57
58struct mfld_mc_private {
59 void __iomem *int_base;
60 u8 interrupt_status;
61};
62
63struct snd_soc_jack mfld_jack;
64
65/*Headset jack detection DAPM pins */
66static struct snd_soc_jack_pin mfld_jack_pins[] = {
67 {
68 .pin = "Headphones",
69 .mask = SND_JACK_HEADPHONE,
70 },
71 {
72 .pin = "AMIC1",
73 .mask = SND_JACK_MICROPHONE,
74 },
75};
76
77/* jack detection voltage zones */
78static struct snd_soc_jack_zone mfld_zones[] = {
79 {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE},
80 {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET},
81};
82
83/* sound card controls */
84static const char *headset_switch_text[] = {"Earpiece", "Headset"};
85
86static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"};
87
88static const struct soc_enum headset_enum =
89 SOC_ENUM_SINGLE_EXT(2, headset_switch_text);
90
91static const struct soc_enum lo_enum =
92 SOC_ENUM_SINGLE_EXT(4, lo_text);
93
94static int headset_get_switch(struct snd_kcontrol *kcontrol,
95 struct snd_ctl_elem_value *ucontrol)
96{
97 ucontrol->value.integer.value[0] = hs_switch;
98 return 0;
99}
100
101static int headset_set_switch(struct snd_kcontrol *kcontrol,
102 struct snd_ctl_elem_value *ucontrol)
103{
104 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
105 struct snd_soc_dapm_context *dapm = &card->dapm;
106
107 if (ucontrol->value.integer.value[0] == hs_switch)
108 return 0;
109
110 snd_soc_dapm_mutex_lock(dapm);
111
112 if (ucontrol->value.integer.value[0]) {
113 pr_debug("hs_set HS path\n");
114 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
115 snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
116 } else {
117 pr_debug("hs_set EP path\n");
118 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
119 snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
120 }
121
122 snd_soc_dapm_sync_unlocked(dapm);
123
124 snd_soc_dapm_mutex_unlock(dapm);
125
126 hs_switch = ucontrol->value.integer.value[0];
127
128 return 0;
129}
130
131static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
132{
133 snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
134 snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
135 snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
136 snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR");
137 snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT");
138 snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT");
139 if (hs_switch) {
140 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
141 snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
142 } else {
143 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
144 snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
145 }
146}
147
148static int lo_get_switch(struct snd_kcontrol *kcontrol,
149 struct snd_ctl_elem_value *ucontrol)
150{
151 ucontrol->value.integer.value[0] = lo_dac;
152 return 0;
153}
154
155static int lo_set_switch(struct snd_kcontrol *kcontrol,
156 struct snd_ctl_elem_value *ucontrol)
157{
158 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
159 struct snd_soc_dapm_context *dapm = &card->dapm;
160
161 if (ucontrol->value.integer.value[0] == lo_dac)
162 return 0;
163
164 snd_soc_dapm_mutex_lock(dapm);
165
166 /* we dont want to work with last state of lineout so just enable all
167 * pins and then disable pins not required
168 */
169 lo_enable_out_pins(dapm);
170
171 switch (ucontrol->value.integer.value[0]) {
172 case 0:
173 pr_debug("set vibra path\n");
174 snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
175 snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
176 snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
177 break;
178
179 case 1:
180 pr_debug("set hs path\n");
181 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
182 snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
183 snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
184 break;
185
186 case 2:
187 pr_debug("set spkr path\n");
188 snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
189 snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
190 snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
191 break;
192
193 case 3:
194 pr_debug("set null path\n");
195 snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
196 snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
197 snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
198 break;
199 }
200
201 snd_soc_dapm_sync_unlocked(dapm);
202
203 snd_soc_dapm_mutex_unlock(dapm);
204
205 lo_dac = ucontrol->value.integer.value[0];
206 return 0;
207}
208
209static const struct snd_kcontrol_new mfld_snd_controls[] = {
210 SOC_ENUM_EXT("Playback Switch", headset_enum,
211 headset_get_switch, headset_set_switch),
212 SOC_ENUM_EXT("Lineout Mux", lo_enum,
213 lo_get_switch, lo_set_switch),
214};
215
216static const struct snd_soc_dapm_widget mfld_widgets[] = {
217 SND_SOC_DAPM_HP("Headphones", NULL),
218 SND_SOC_DAPM_MIC("Mic", NULL),
219};
220
221static const struct snd_soc_dapm_route mfld_map[] = {
222 {"Headphones", NULL, "HPOUTR"},
223 {"Headphones", NULL, "HPOUTL"},
224 {"Mic", NULL, "AMIC1"},
225};
226
227static void mfld_jack_check(unsigned int intr_status)
228{
229 struct mfld_jack_data jack_data;
230
231 if (!mfld_codec)
232 return;
233
234 jack_data.mfld_jack = &mfld_jack;
235 jack_data.intr_id = intr_status;
236
237 sn95031_jack_detection(mfld_codec, &jack_data);
238 /* TODO: add american headset detection post gpiolib support */
239}
240
241static int mfld_init(struct snd_soc_pcm_runtime *runtime)
242{
243 struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
244 int ret_val;
245
246 /* default is earpiece pin, userspace sets it explcitly */
247 snd_soc_dapm_disable_pin(dapm, "Headphones");
248 /* default is lineout NC, userspace sets it explcitly */
249 snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
250 snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
251 lo_dac = 3;
252 hs_switch = 0;
253 /* we dont use linein in this so set to NC */
254 snd_soc_dapm_disable_pin(dapm, "LINEINL");
255 snd_soc_dapm_disable_pin(dapm, "LINEINR");
256
257 /* Headset and button jack detection */
258 ret_val = snd_soc_card_jack_new(runtime->card,
259 "Intel(R) MID Audio Jack", SND_JACK_HEADSET |
260 SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack,
261 mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins));
262 if (ret_val) {
263 pr_err("jack creation failed\n");
264 return ret_val;
265 }
266
267 ret_val = snd_soc_jack_add_zones(&mfld_jack,
268 ARRAY_SIZE(mfld_zones), mfld_zones);
269 if (ret_val) {
270 pr_err("adding jack zones failed\n");
271 return ret_val;
272 }
273
274 mfld_codec = runtime->codec;
275
276 /* we want to check if anything is inserted at boot,
277 * so send a fake event to codec and it will read adc
278 * to find if anything is there or not */
279 mfld_jack_check(MFLD_JACK_INSERT);
280 return ret_val;
281}
282
283static struct snd_soc_dai_link mfld_msic_dailink[] = {
284 {
285 .name = "Medfield Headset",
286 .stream_name = "Headset",
287 .cpu_dai_name = "Headset-cpu-dai",
288 .codec_dai_name = "SN95031 Headset",
289 .codec_name = "sn95031",
290 .platform_name = "sst-platform",
291 .init = mfld_init,
292 },
293 {
294 .name = "Medfield Speaker",
295 .stream_name = "Speaker",
296 .cpu_dai_name = "Speaker-cpu-dai",
297 .codec_dai_name = "SN95031 Speaker",
298 .codec_name = "sn95031",
299 .platform_name = "sst-platform",
300 .init = NULL,
301 },
302 {
303 .name = "Medfield Vibra",
304 .stream_name = "Vibra1",
305 .cpu_dai_name = "Vibra1-cpu-dai",
306 .codec_dai_name = "SN95031 Vibra1",
307 .codec_name = "sn95031",
308 .platform_name = "sst-platform",
309 .init = NULL,
310 },
311 {
312 .name = "Medfield Haptics",
313 .stream_name = "Vibra2",
314 .cpu_dai_name = "Vibra2-cpu-dai",
315 .codec_dai_name = "SN95031 Vibra2",
316 .codec_name = "sn95031",
317 .platform_name = "sst-platform",
318 .init = NULL,
319 },
320 {
321 .name = "Medfield Compress",
322 .stream_name = "Speaker",
323 .cpu_dai_name = "Compress-cpu-dai",
324 .codec_dai_name = "SN95031 Speaker",
325 .codec_name = "sn95031",
326 .platform_name = "sst-platform",
327 .init = NULL,
328 },
329};
330
331/* SoC card */
332static struct snd_soc_card snd_soc_card_mfld = {
333 .name = "medfield_audio",
334 .owner = THIS_MODULE,
335 .dai_link = mfld_msic_dailink,
336 .num_links = ARRAY_SIZE(mfld_msic_dailink),
337
338 .controls = mfld_snd_controls,
339 .num_controls = ARRAY_SIZE(mfld_snd_controls),
340 .dapm_widgets = mfld_widgets,
341 .num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
342 .dapm_routes = mfld_map,
343 .num_dapm_routes = ARRAY_SIZE(mfld_map),
344};
345
346static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
347{
348 struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev;
349
350 memcpy_fromio(&mc_private->interrupt_status,
351 ((void *)(mc_private->int_base)),
352 sizeof(u8));
353 return IRQ_WAKE_THREAD;
354}
355
356static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
357{
358 struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
359
360 mfld_jack_check(mc_drv_ctx->interrupt_status);
361
362 return IRQ_HANDLED;
363}
364
365static int snd_mfld_mc_probe(struct platform_device *pdev)
366{
367 int ret_val = 0, irq;
368 struct mfld_mc_private *mc_drv_ctx;
369 struct resource *irq_mem;
370
371 pr_debug("snd_mfld_mc_probe called\n");
372
373 /* retrive the irq number */
374 irq = platform_get_irq(pdev, 0);
375
376 /* audio interrupt base of SRAM location where
377 * interrupts are stored by System FW */
378 mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
379 if (!mc_drv_ctx) {
380 pr_err("allocation failed\n");
381 return -ENOMEM;
382 }
383
384 irq_mem = platform_get_resource_byname(
385 pdev, IORESOURCE_MEM, "IRQ_BASE");
386 if (!irq_mem) {
387 pr_err("no mem resource given\n");
388 return -ENODEV;
389 }
390 mc_drv_ctx->int_base = devm_ioremap_nocache(&pdev->dev, irq_mem->start,
391 resource_size(irq_mem));
392 if (!mc_drv_ctx->int_base) {
393 pr_err("Mapping of cache failed\n");
394 return -ENOMEM;
395 }
396 /* register for interrupt */
397 ret_val = devm_request_threaded_irq(&pdev->dev, irq,
398 snd_mfld_jack_intr_handler,
399 snd_mfld_jack_detection,
400 IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
401 if (ret_val) {
402 pr_err("cannot register IRQ\n");
403 return ret_val;
404 }
405 /* register the soc card */
406 snd_soc_card_mfld.dev = &pdev->dev;
407 ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld);
408 if (ret_val) {
409 pr_debug("snd_soc_register_card failed %d\n", ret_val);
410 return ret_val;
411 }
412 platform_set_drvdata(pdev, mc_drv_ctx);
413 pr_debug("successfully exited probe\n");
414 return 0;
415}
416
417static struct platform_driver snd_mfld_mc_driver = {
418 .driver = {
419 .name = "msic_audio",
420 },
421 .probe = snd_mfld_mc_probe,
422};
423
424module_platform_driver(snd_mfld_mc_driver);
425
426MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
427MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
428MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
429MODULE_LICENSE("GPL v2");
430MODULE_ALIAS("platform:msic-audio");