brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · 58db09d Raw
264 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Sound card driver for Intel Broadwell Wildcat Point with Realtek 2864 *5 * Copyright (C) 2013, Intel Corporation6 */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_ops255	},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");264