Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Sound card driver for Intel Broadwell Wildcat Point with Realtek 286
  4 *
  5 * Copyright (C) 2013, Intel Corporation
  6 */
  7
  8#include <linux/module.h>
  9#include <linux/platform_device.h>
 10#include <sound/core.h>
 11#include <sound/jack.h>
 12#include <sound/pcm.h>
 13#include <sound/pcm_params.h>
 14#include <sound/soc.h>
 15#include <sound/soc-acpi.h>
 16#include "../../codecs/rt286.h"
 17
 18static struct snd_soc_jack card_headset;
 19
 20static struct snd_soc_jack_pin card_headset_pins[] = {
 21	{
 22		.pin = "Mic Jack",
 23		.mask = SND_JACK_MICROPHONE,
 24	},
 25	{
 26		.pin = "Headphone Jack",
 27		.mask = SND_JACK_HEADPHONE,
 28	},
 29};
 30
 31static const struct snd_kcontrol_new card_controls[] = {
 32	SOC_DAPM_PIN_SWITCH("Speaker"),
 33	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
 34};
 35
 36static const struct snd_soc_dapm_widget card_widgets[] = {
 37	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 38	SND_SOC_DAPM_SPK("Speaker", NULL),
 39	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 40	SND_SOC_DAPM_MIC("DMIC1", NULL),
 41	SND_SOC_DAPM_MIC("DMIC2", NULL),
 42	SND_SOC_DAPM_LINE("Line Jack", NULL),
 43};
 44
 45static const struct snd_soc_dapm_route card_routes[] = {
 46	{"Speaker", NULL, "SPOR"},
 47	{"Speaker", NULL, "SPOL"},
 48
 49	{"Headphone Jack", NULL, "HPO Pin"},
 50
 51	{"MIC1", NULL, "Mic Jack"},
 52	{"LINE1", NULL, "Line Jack"},
 53
 54	{"DMIC1 Pin", NULL, "DMIC1"},
 55	{"DMIC2 Pin", NULL, "DMIC2"},
 56
 57	/* CODEC BE connections */
 58	{"SSP0 CODEC IN", NULL, "AIF1 Capture"},
 59	{"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
 60};
 61
 62static int codec_link_init(struct snd_soc_pcm_runtime *rtd)
 63{
 64	struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
 65	int ret;
 66
 67	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0,
 68					 &card_headset, card_headset_pins,
 69					 ARRAY_SIZE(card_headset_pins));
 70	if (ret)
 71		return ret;
 72
 73	return snd_soc_component_set_jack(codec, &card_headset, NULL);
 74}
 75
 76static void codec_link_exit(struct snd_soc_pcm_runtime *rtd)
 77{
 78	struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
 79
 80	snd_soc_component_set_jack(codec, NULL, NULL);
 81}
 82
 83static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 84				      struct snd_pcm_hw_params *params)
 85{
 86	struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
 87	struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 88
 89	/* The ADSP will convert the FE rate to 48kHz, stereo. */
 90	rate->min = rate->max = 48000;
 91	channels->min = channels->max = 2;
 92	/* Set SSP0 to 16 bit. */
 93	params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
 94
 95	return 0;
 96}
 97
 98static int codec_link_hw_params(struct snd_pcm_substream *substream,
 99				struct snd_pcm_hw_params *params)
100{
101	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
102	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
103	int ret;
104
105	ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
106	if (ret < 0) {
107		dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
108		return ret;
109	}
110
111	return ret;
112}
113
114static const struct snd_soc_ops codec_link_ops = {
115	.hw_params = codec_link_hw_params,
116};
117
118SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
119SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
120SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
121SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
122
123SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
124SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
125SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
126SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
127
128static struct snd_soc_dai_link card_dai_links[] = {
129	/* Front End DAI links */
130	{
131		.name = "System PCM",
132		.stream_name = "System Playback/Capture",
133		.nonatomic = 1,
134		.dynamic = 1,
135		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
 
 
136		SND_SOC_DAILINK_REG(system, dummy, platform),
137	},
138	{
139		.name = "Offload0",
140		.stream_name = "Offload0 Playback",
141		.nonatomic = 1,
142		.dynamic = 1,
143		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
144		.playback_only = 1,
145		SND_SOC_DAILINK_REG(offload0, dummy, platform),
146	},
147	{
148		.name = "Offload1",
149		.stream_name = "Offload1 Playback",
150		.nonatomic = 1,
151		.dynamic = 1,
152		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
153		.playback_only = 1,
154		SND_SOC_DAILINK_REG(offload1, dummy, platform),
155	},
156	{
157		.name = "Loopback PCM",
158		.stream_name = "Loopback",
159		.nonatomic = 1,
160		.dynamic = 1,
161		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
162		.capture_only = 1,
163		SND_SOC_DAILINK_REG(loopback, dummy, platform),
164	},
165	/* Back End DAI links */
166	{
167		/* SSP0 - Codec */
168		.name = "Codec",
169		.id = 0,
170		.nonatomic = 1,
171		.no_pcm = 1,
172		.init = codec_link_init,
173		.exit = codec_link_exit,
174		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
175		.ignore_pmdown_time = 1,
176		.be_hw_params_fixup = codec_link_hw_params_fixup,
177		.ops = &codec_link_ops,
 
 
178		SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
179	},
180};
181
182static int card_suspend_pre(struct snd_soc_card *card)
183{
184	struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
185
186	if (!codec_dai)
187		return 0;
188
189	return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
190}
191
192static int card_resume_post(struct snd_soc_card *card)
193{
194	struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
195
196	if (!codec_dai)
197		return 0;
198
199	return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL);
200}
201
202static struct snd_soc_card bdw_rt286_card = {
203	.owner = THIS_MODULE,
204	.suspend_pre = card_suspend_pre,
205	.resume_post = card_resume_post,
206	.dai_link = card_dai_links,
207	.num_links = ARRAY_SIZE(card_dai_links),
208	.controls = card_controls,
209	.num_controls = ARRAY_SIZE(card_controls),
210	.dapm_widgets = card_widgets,
211	.num_dapm_widgets = ARRAY_SIZE(card_widgets),
212	.dapm_routes = card_routes,
213	.num_dapm_routes = ARRAY_SIZE(card_routes),
214	.fully_routed = true,
215};
216
217/* Use space before codec name to simplify card ID, and simplify driver name. */
218#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
219#define SOF_DRIVER_NAME "SOF"
220
221#define CARD_NAME "broadwell-rt286"
222
223static int bdw_rt286_probe(struct platform_device *pdev)
224{
225	struct snd_soc_acpi_mach *mach;
226	struct device *dev = &pdev->dev;
227	int ret;
228
229	bdw_rt286_card.dev = dev;
230	mach = dev_get_platdata(dev);
231
232	ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt286_card, mach->mach_params.platform);
233	if (ret)
234		return ret;
235
236	if (snd_soc_acpi_sof_parent(dev)) {
237		bdw_rt286_card.name = SOF_CARD_NAME;
238		bdw_rt286_card.driver_name = SOF_DRIVER_NAME;
239	} else {
240		bdw_rt286_card.name = CARD_NAME;
241	}
242
243	return devm_snd_soc_register_card(dev, &bdw_rt286_card);
244}
245
246static struct platform_driver bdw_rt286_driver = {
247	.probe = bdw_rt286_probe,
248	.driver = {
249		.name = "bdw_rt286",
250		.pm = &snd_soc_pm_ops
251	},
252};
253
254module_platform_driver(bdw_rt286_driver)
255
256MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
257MODULE_DESCRIPTION("Sound card driver for Intel Broadwell Wildcat Point with Realtek 286");
258MODULE_LICENSE("GPL");
259MODULE_ALIAS("platform:bdw_rt286");
v6.9.4
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Sound card driver for Intel Broadwell Wildcat Point with Realtek 286
  4 *
  5 * Copyright (C) 2013, Intel Corporation. All rights reserved.
  6 */
  7
  8#include <linux/module.h>
  9#include <linux/platform_device.h>
 10#include <sound/core.h>
 11#include <sound/jack.h>
 12#include <sound/pcm.h>
 13#include <sound/pcm_params.h>
 14#include <sound/soc.h>
 15#include <sound/soc-acpi.h>
 16#include "../../codecs/rt286.h"
 17
 18static struct snd_soc_jack card_headset;
 19
 20static struct snd_soc_jack_pin card_headset_pins[] = {
 21	{
 22		.pin = "Mic Jack",
 23		.mask = SND_JACK_MICROPHONE,
 24	},
 25	{
 26		.pin = "Headphone Jack",
 27		.mask = SND_JACK_HEADPHONE,
 28	},
 29};
 30
 31static const struct snd_kcontrol_new card_controls[] = {
 32	SOC_DAPM_PIN_SWITCH("Speaker"),
 33	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
 34};
 35
 36static const struct snd_soc_dapm_widget card_widgets[] = {
 37	SND_SOC_DAPM_HP("Headphone Jack", NULL),
 38	SND_SOC_DAPM_SPK("Speaker", NULL),
 39	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 40	SND_SOC_DAPM_MIC("DMIC1", NULL),
 41	SND_SOC_DAPM_MIC("DMIC2", NULL),
 42	SND_SOC_DAPM_LINE("Line Jack", NULL),
 43};
 44
 45static const struct snd_soc_dapm_route card_routes[] = {
 46	{"Speaker", NULL, "SPOR"},
 47	{"Speaker", NULL, "SPOL"},
 48
 49	{"Headphone Jack", NULL, "HPO Pin"},
 50
 51	{"MIC1", NULL, "Mic Jack"},
 52	{"LINE1", NULL, "Line Jack"},
 53
 54	{"DMIC1 Pin", NULL, "DMIC1"},
 55	{"DMIC2 Pin", NULL, "DMIC2"},
 56
 57	/* CODEC BE connections */
 58	{"SSP0 CODEC IN", NULL, "AIF1 Capture"},
 59	{"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
 60};
 61
 62static int codec_link_init(struct snd_soc_pcm_runtime *rtd)
 63{
 64	struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
 65	int ret;
 66
 67	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0,
 68					 &card_headset, card_headset_pins,
 69					 ARRAY_SIZE(card_headset_pins));
 70	if (ret)
 71		return ret;
 72
 73	return snd_soc_component_set_jack(codec, &card_headset, NULL);
 74}
 75
 76static void codec_link_exit(struct snd_soc_pcm_runtime *rtd)
 77{
 78	struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
 79
 80	snd_soc_component_set_jack(codec, NULL, NULL);
 81}
 82
 83static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 84				      struct snd_pcm_hw_params *params)
 85{
 86	struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
 87	struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 88
 89	/* The ADSP will convert the FE rate to 48kHz, stereo. */
 90	rate->min = rate->max = 48000;
 91	channels->min = channels->max = 2;
 92	/* Set SSP0 to 16 bit. */
 93	params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
 94
 95	return 0;
 96}
 97
 98static int codec_link_hw_params(struct snd_pcm_substream *substream,
 99				struct snd_pcm_hw_params *params)
100{
101	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
102	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
103	int ret;
104
105	ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
106	if (ret < 0) {
107		dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
108		return ret;
109	}
110
111	return ret;
112}
113
114static const struct snd_soc_ops codec_link_ops = {
115	.hw_params = codec_link_hw_params,
116};
117
118SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
119SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
120SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
121SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
122
123SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
124SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
125SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
126SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
127
128static struct snd_soc_dai_link card_dai_links[] = {
129	/* Front End DAI links */
130	{
131		.name = "System PCM",
132		.stream_name = "System Playback/Capture",
133		.nonatomic = 1,
134		.dynamic = 1,
135		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
136		.dpcm_playback = 1,
137		.dpcm_capture = 1,
138		SND_SOC_DAILINK_REG(system, dummy, platform),
139	},
140	{
141		.name = "Offload0",
142		.stream_name = "Offload0 Playback",
143		.nonatomic = 1,
144		.dynamic = 1,
145		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
146		.dpcm_playback = 1,
147		SND_SOC_DAILINK_REG(offload0, dummy, platform),
148	},
149	{
150		.name = "Offload1",
151		.stream_name = "Offload1 Playback",
152		.nonatomic = 1,
153		.dynamic = 1,
154		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
155		.dpcm_playback = 1,
156		SND_SOC_DAILINK_REG(offload1, dummy, platform),
157	},
158	{
159		.name = "Loopback PCM",
160		.stream_name = "Loopback",
161		.nonatomic = 1,
162		.dynamic = 1,
163		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
164		.dpcm_capture = 1,
165		SND_SOC_DAILINK_REG(loopback, dummy, platform),
166	},
167	/* Back End DAI links */
168	{
169		/* SSP0 - Codec */
170		.name = "Codec",
171		.id = 0,
172		.nonatomic = 1,
173		.no_pcm = 1,
174		.init = codec_link_init,
175		.exit = codec_link_exit,
176		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
177		.ignore_pmdown_time = 1,
178		.be_hw_params_fixup = codec_link_hw_params_fixup,
179		.ops = &codec_link_ops,
180		.dpcm_playback = 1,
181		.dpcm_capture = 1,
182		SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
183	},
184};
185
186static int card_suspend_pre(struct snd_soc_card *card)
187{
188	struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
189
190	if (!codec_dai)
191		return 0;
192
193	return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
194}
195
196static int card_resume_post(struct snd_soc_card *card)
197{
198	struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
199
200	if (!codec_dai)
201		return 0;
202
203	return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL);
204}
205
206static struct snd_soc_card bdw_rt286_card = {
207	.owner = THIS_MODULE,
208	.suspend_pre = card_suspend_pre,
209	.resume_post = card_resume_post,
210	.dai_link = card_dai_links,
211	.num_links = ARRAY_SIZE(card_dai_links),
212	.controls = card_controls,
213	.num_controls = ARRAY_SIZE(card_controls),
214	.dapm_widgets = card_widgets,
215	.num_dapm_widgets = ARRAY_SIZE(card_widgets),
216	.dapm_routes = card_routes,
217	.num_dapm_routes = ARRAY_SIZE(card_routes),
218	.fully_routed = true,
219};
220
221/* Use space before codec name to simplify card ID, and simplify driver name. */
222#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
223#define SOF_DRIVER_NAME "SOF"
224
225#define CARD_NAME "broadwell-rt286"
226
227static int bdw_rt286_probe(struct platform_device *pdev)
228{
229	struct snd_soc_acpi_mach *mach;
230	struct device *dev = &pdev->dev;
231	int ret;
232
233	bdw_rt286_card.dev = dev;
234	mach = dev_get_platdata(dev);
235
236	ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt286_card, mach->mach_params.platform);
237	if (ret)
238		return ret;
239
240	if (snd_soc_acpi_sof_parent(dev)) {
241		bdw_rt286_card.name = SOF_CARD_NAME;
242		bdw_rt286_card.driver_name = SOF_DRIVER_NAME;
243	} else {
244		bdw_rt286_card.name = CARD_NAME;
245	}
246
247	return devm_snd_soc_register_card(dev, &bdw_rt286_card);
248}
249
250static struct platform_driver bdw_rt286_driver = {
251	.probe = bdw_rt286_probe,
252	.driver = {
253		.name = "bdw_rt286",
254		.pm = &snd_soc_pm_ops
255	},
256};
257
258module_platform_driver(bdw_rt286_driver)
259
260MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
261MODULE_DESCRIPTION("Sound card driver for Intel Broadwell Wildcat Point with Realtek 286");
262MODULE_LICENSE("GPL");
263MODULE_ALIAS("platform:bdw_rt286");