aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFang, Yang A <yang.a.fang@intel.com>2015-05-01 14:42:03 -0400
committerMark Brown <broonie@kernel.org>2015-05-04 08:18:03 -0400
commit17119a4657066ccefd9a530ab1b07073d97776f8 (patch)
treef3e5b3cf2e97037c8f71bb4fce59905c80adc455
parentcde7fbfc8a2987796fb647e574242fa4bc5430f0 (diff)
ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_max98090_ti
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell. This machine driver will support max98090 codec as primary codec. it can also support TI jack detect chip as aux device if platform supports it. Signed-off-by: Fang, Yang A <yang.a.fang@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/intel/Kconfig12
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c320
3 files changed, 334 insertions, 0 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index ee03dbdda235..01b2b53be0b3 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -121,3 +121,15 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
121 This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell 121 This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
122 platforms with RT5645 audio codec. 122 platforms with RT5645 audio codec.
123 If unsure select "N". 123 If unsure select "N".
124
125config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
126 tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec"
127 depends on X86_INTEL_LPSS
128 select SND_SOC_MAX98090
129 select SND_SOC_TS3A227E
130 select SND_SST_MFLD_PLATFORM
131 select SND_SST_IPC_ACPI
132 help
133 This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
134 platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
135 If unsure select "N".
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index f8237f0044eb..cb94895c9edb 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -5,6 +5,7 @@ snd-soc-sst-broadwell-objs := broadwell.o
5snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o 5snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
6snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o 6snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
7snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o 7snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
8snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
8 9
9obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o 10obj-$(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_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
@@ -13,3 +14,4 @@ obj-$(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_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_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 16obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
17obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
new file mode 100644
index 000000000000..3c518b1ec49d
--- /dev/null
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -0,0 +1,320 @@
1/*
2 * cht-bsw-max98090.c - ASoc Machine driver for Intel Cherryview-based
3 * platforms Cherrytrail and Braswell, with max98090 & TI codec.
4 *
5 * Copyright (C) 2015 Intel Corp
6 * Author: Fang, Yang A <yang.a.fang@intel.com>
7 * This file is modified from cht_bsw_rt5645.c
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21
22#include <linux/module.h>
23#include <linux/platform_device.h>
24#include <linux/slab.h>
25#include <linux/acpi.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/max98090.h"
31#include "../atom/sst-atom-controls.h"
32#include "../../codecs/ts3a227e.h"
33
34#define CHT_PLAT_CLK_3_HZ 19200000
35#define CHT_CODEC_DAI "HiFi"
36
37struct cht_mc_private {
38 struct snd_soc_jack jack;
39 bool ts3a227e_present;
40};
41
42static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
43{
44 int i;
45
46 for (i = 0; i < card->num_rtd; i++) {
47 struct snd_soc_pcm_runtime *rtd;
48
49 rtd = card->rtd + i;
50 if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
51 strlen(CHT_CODEC_DAI)))
52 return rtd->codec_dai;
53 }
54 return NULL;
55}
56
57static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
58 SND_SOC_DAPM_HP("Headphone", NULL),
59 SND_SOC_DAPM_MIC("Headset Mic", NULL),
60 SND_SOC_DAPM_MIC("Int Mic", NULL),
61 SND_SOC_DAPM_SPK("Ext Spk", NULL),
62};
63
64static const struct snd_soc_dapm_route cht_audio_map[] = {
65 {"IN34", NULL, "Headset Mic"},
66 {"Headset Mic", NULL, "MICBIAS"},
67 {"DMICL", NULL, "Int Mic"},
68 {"Headphone", NULL, "HPL"},
69 {"Headphone", NULL, "HPR"},
70 {"Ext Spk", NULL, "SPKL"},
71 {"Ext Spk", NULL, "SPKR"},
72 {"AIF1 Playback", NULL, "ssp2 Tx"},
73 {"ssp2 Tx", NULL, "codec_out0"},
74 {"ssp2 Tx", NULL, "codec_out1"},
75 {"codec_in0", NULL, "ssp2 Rx" },
76 {"codec_in1", NULL, "ssp2 Rx" },
77 {"ssp2 Rx", NULL, "AIF1 Capture"},
78};
79
80static const struct snd_kcontrol_new cht_mc_controls[] = {
81 SOC_DAPM_PIN_SWITCH("Headphone"),
82 SOC_DAPM_PIN_SWITCH("Headset Mic"),
83 SOC_DAPM_PIN_SWITCH("Int Mic"),
84 SOC_DAPM_PIN_SWITCH("Ext Spk"),
85};
86
87static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
88 struct snd_pcm_hw_params *params)
89{
90 struct snd_soc_pcm_runtime *rtd = substream->private_data;
91 struct snd_soc_dai *codec_dai = rtd->codec_dai;
92 int ret;
93
94 ret = snd_soc_dai_set_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK,
95 CHT_PLAT_CLK_3_HZ, SND_SOC_CLOCK_IN);
96 if (ret < 0) {
97 dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
98 return ret;
99 }
100
101 return 0;
102}
103
104static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
105{
106 int ret;
107 int jack_type;
108 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
109 struct snd_soc_jack *jack = &ctx->jack;
110
111 /**
112 * TI supports 4 butons headset detection
113 * KEY_MEDIA
114 * KEY_VOICECOMMAND
115 * KEY_VOLUMEUP
116 * KEY_VOLUMEDOWN
117 */
118 if (ctx->ts3a227e_present)
119 jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
120 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
121 SND_JACK_BTN_2 | SND_JACK_BTN_3;
122 else
123 jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE;
124
125 ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
126 jack_type, jack, NULL, 0);
127
128 if (ret) {
129 dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret);
130 return ret;
131 }
132
133 return ret;
134}
135
136static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
137 struct snd_pcm_hw_params *params)
138{
139 struct snd_interval *rate = hw_param_interval(params,
140 SNDRV_PCM_HW_PARAM_RATE);
141 struct snd_interval *channels = hw_param_interval(params,
142 SNDRV_PCM_HW_PARAM_CHANNELS);
143 int ret = 0;
144 unsigned int fmt = 0;
145
146 ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16);
147 if (ret < 0) {
148 dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret);
149 return ret;
150 }
151
152 fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF
153 | SND_SOC_DAIFMT_CBS_CFS;
154
155 ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
156 if (ret < 0) {
157 dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret);
158 return ret;
159 }
160
161 /* The DSP will covert the FE rate to 48k, stereo, 24bits */
162 rate->min = rate->max = 48000;
163 channels->min = channels->max = 2;
164
165 /* set SSP2 to 24-bit */
166 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
167 SNDRV_PCM_HW_PARAM_FIRST_MASK],
168 SNDRV_PCM_FORMAT_S24_LE);
169 return 0;
170}
171
172static unsigned int rates_48000[] = {
173 48000,
174};
175
176static struct snd_pcm_hw_constraint_list constraints_48000 = {
177 .count = ARRAY_SIZE(rates_48000),
178 .list = rates_48000,
179};
180
181static int cht_aif1_startup(struct snd_pcm_substream *substream)
182{
183 return snd_pcm_hw_constraint_list(substream->runtime, 0,
184 SNDRV_PCM_HW_PARAM_RATE,
185 &constraints_48000);
186}
187
188static int cht_max98090_headset_init(struct snd_soc_component *component)
189{
190 struct snd_soc_card *card = component->card;
191 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
192
193 return ts3a227e_enable_jack_detect(component, &ctx->jack);
194}
195
196static struct snd_soc_ops cht_aif1_ops = {
197 .startup = cht_aif1_startup,
198};
199
200static struct snd_soc_ops cht_be_ssp2_ops = {
201 .hw_params = cht_aif1_hw_params,
202};
203
204static struct snd_soc_aux_dev cht_max98090_headset_dev = {
205 .name = "Headset Chip",
206 .init = cht_max98090_headset_init,
207 .codec_name = "i2c-104C227E:00",
208};
209
210static struct snd_soc_dai_link cht_dailink[] = {
211 [MERR_DPCM_AUDIO] = {
212 .name = "Audio Port",
213 .stream_name = "Audio",
214 .cpu_dai_name = "media-cpu-dai",
215 .codec_dai_name = "snd-soc-dummy-dai",
216 .codec_name = "snd-soc-dummy",
217 .platform_name = "sst-mfld-platform",
218 .nonatomic = true,
219 .dynamic = 1,
220 .dpcm_playback = 1,
221 .dpcm_capture = 1,
222 .ops = &cht_aif1_ops,
223 },
224 [MERR_DPCM_COMPR] = {
225 .name = "Compressed Port",
226 .stream_name = "Compress",
227 .cpu_dai_name = "compress-cpu-dai",
228 .codec_dai_name = "snd-soc-dummy-dai",
229 .codec_name = "snd-soc-dummy",
230 .platform_name = "sst-mfld-platform",
231 },
232 /* back ends */
233 {
234 .name = "SSP2-Codec",
235 .be_id = 1,
236 .cpu_dai_name = "ssp2-port",
237 .platform_name = "sst-mfld-platform",
238 .no_pcm = 1,
239 .codec_dai_name = "HiFi",
240 .codec_name = "i2c-193C9890:00",
241 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
242 | SND_SOC_DAIFMT_CBS_CFS,
243 .init = cht_codec_init,
244 .be_hw_params_fixup = cht_codec_fixup,
245 .dpcm_playback = 1,
246 .dpcm_capture = 1,
247 .ops = &cht_be_ssp2_ops,
248 },
249};
250
251/* SoC card */
252static struct snd_soc_card snd_soc_card_cht = {
253 .name = "chtmax98090",
254 .dai_link = cht_dailink,
255 .num_links = ARRAY_SIZE(cht_dailink),
256 .aux_dev = &cht_max98090_headset_dev,
257 .num_aux_devs = 1,
258 .dapm_widgets = cht_dapm_widgets,
259 .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
260 .dapm_routes = cht_audio_map,
261 .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
262 .controls = cht_mc_controls,
263 .num_controls = ARRAY_SIZE(cht_mc_controls),
264};
265
266static acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level,
267 void *context, void **ret)
268{
269 *(bool *)context = true;
270 return AE_OK;
271}
272
273static int snd_cht_mc_probe(struct platform_device *pdev)
274{
275 int ret_val = 0;
276 bool found = false;
277 struct cht_mc_private *drv;
278
279 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
280 if (!drv)
281 return -ENOMEM;
282
283 if (ACPI_SUCCESS(acpi_get_devices(
284 "104C227E",
285 snd_acpi_codec_match,
286 &found, NULL)) && found) {
287 drv->ts3a227e_present = true;
288 } else {
289 /* no need probe TI jack detection chip */
290 snd_soc_card_cht.aux_dev = NULL;
291 snd_soc_card_cht.num_aux_devs = 0;
292 drv->ts3a227e_present = false;
293 }
294
295 /* register the soc card */
296 snd_soc_card_cht.dev = &pdev->dev;
297 snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
298 ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
299 if (ret_val) {
300 dev_err(&pdev->dev,
301 "snd_soc_register_card failed %d\n", ret_val);
302 return ret_val;
303 }
304 platform_set_drvdata(pdev, &snd_soc_card_cht);
305 return ret_val;
306}
307
308static struct platform_driver snd_cht_mc_driver = {
309 .driver = {
310 .name = "cht-bsw-max98090",
311 },
312 .probe = snd_cht_mc_probe,
313};
314
315module_platform_driver(snd_cht_mc_driver)
316
317MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");
318MODULE_AUTHOR("Fang, Yang A <yang.a.fang@intel.com>");
319MODULE_LICENSE("GPL v2");
320MODULE_ALIAS("platform:cht-bsw-max98090");