• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Intel Haswell Lynxpoint SST Audio
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/pcm.h>
12 #include <sound/soc.h>
13 #include <sound/soc-acpi.h>
14 #include <sound/pcm_params.h>
15 
16 #include "../../codecs/rt5640.h"
17 
18 /* Haswell ULT platforms have a Headphone and Mic jack */
19 static const struct snd_soc_dapm_widget haswell_widgets[] = {
20 	SND_SOC_DAPM_HP("Headphones", NULL),
21 	SND_SOC_DAPM_MIC("Mic", NULL),
22 };
23 
24 static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
25 
26 	{"Headphones", NULL, "HPOR"},
27 	{"Headphones", NULL, "HPOL"},
28 	{"IN2P", NULL, "Mic"},
29 
30 	/* CODEC BE connections */
31 	{"SSP0 CODEC IN", NULL, "AIF1 Capture"},
32 	{"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
33 };
34 
haswell_ssp0_fixup(struct snd_soc_pcm_runtime * rtd,struct snd_pcm_hw_params * params)35 static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
36 			struct snd_pcm_hw_params *params)
37 {
38 	struct snd_interval *rate = hw_param_interval(params,
39 			SNDRV_PCM_HW_PARAM_RATE);
40 	struct snd_interval *channels = hw_param_interval(params,
41 						SNDRV_PCM_HW_PARAM_CHANNELS);
42 
43 	/* The ADSP will covert the FE rate to 48k, stereo */
44 	rate->min = rate->max = 48000;
45 	channels->min = channels->max = 2;
46 
47 	/* set SSP0 to 16 bit */
48 	params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
49 	return 0;
50 }
51 
haswell_rt5640_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)52 static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
53 	struct snd_pcm_hw_params *params)
54 {
55 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
56 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
57 	int ret;
58 
59 	ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
60 		SND_SOC_CLOCK_IN);
61 
62 	if (ret < 0) {
63 		dev_err(rtd->dev, "can't set codec sysclk configuration\n");
64 		return ret;
65 	}
66 
67 	/* set correct codec filter for DAI format and clock config */
68 	snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
69 
70 	return ret;
71 }
72 
73 static const struct snd_soc_ops haswell_rt5640_ops = {
74 	.hw_params = haswell_rt5640_hw_params,
75 };
76 
77 SND_SOC_DAILINK_DEF(dummy,
78 	DAILINK_COMP_ARRAY(COMP_DUMMY()));
79 
80 SND_SOC_DAILINK_DEF(system,
81 	DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
82 
83 SND_SOC_DAILINK_DEF(offload0,
84 	DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
85 
86 SND_SOC_DAILINK_DEF(offload1,
87 	DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
88 
89 SND_SOC_DAILINK_DEF(loopback,
90 	DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
91 
92 SND_SOC_DAILINK_DEF(codec,
93 	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1")));
94 
95 SND_SOC_DAILINK_DEF(platform,
96 	DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
97 
98 SND_SOC_DAILINK_DEF(ssp0_port,
99 	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
100 
101 static struct snd_soc_dai_link haswell_rt5640_dais[] = {
102 	/* Front End DAI links */
103 	{
104 		.name = "System",
105 		.stream_name = "System Playback/Capture",
106 		.nonatomic = 1,
107 		.dynamic = 1,
108 		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
109 		.dpcm_playback = 1,
110 		.dpcm_capture = 1,
111 		SND_SOC_DAILINK_REG(system, dummy, platform),
112 	},
113 	{
114 		.name = "Offload0",
115 		.stream_name = "Offload0 Playback",
116 		.nonatomic = 1,
117 		.dynamic = 1,
118 		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
119 		.dpcm_playback = 1,
120 		SND_SOC_DAILINK_REG(offload0, dummy, platform),
121 	},
122 	{
123 		.name = "Offload1",
124 		.stream_name = "Offload1 Playback",
125 		.nonatomic = 1,
126 		.dynamic = 1,
127 		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
128 		.dpcm_playback = 1,
129 		SND_SOC_DAILINK_REG(offload1, dummy, platform),
130 	},
131 	{
132 		.name = "Loopback",
133 		.stream_name = "Loopback",
134 		.nonatomic = 1,
135 		.dynamic = 1,
136 		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
137 		.dpcm_capture = 1,
138 		SND_SOC_DAILINK_REG(loopback, dummy, platform),
139 	},
140 
141 	/* Back End DAI links */
142 	{
143 		/* SSP0 - Codec */
144 		.name = "Codec",
145 		.id = 0,
146 		.no_pcm = 1,
147 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
148 			SND_SOC_DAIFMT_CBS_CFS,
149 		.ignore_pmdown_time = 1,
150 		.be_hw_params_fixup = haswell_ssp0_fixup,
151 		.ops = &haswell_rt5640_ops,
152 		.dpcm_playback = 1,
153 		.dpcm_capture = 1,
154 		SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
155 	},
156 };
157 
158 /* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
159 static struct snd_soc_card haswell_rt5640 = {
160 	.name = "haswell-rt5640",
161 	.owner = THIS_MODULE,
162 	.dai_link = haswell_rt5640_dais,
163 	.num_links = ARRAY_SIZE(haswell_rt5640_dais),
164 	.dapm_widgets = haswell_widgets,
165 	.num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
166 	.dapm_routes = haswell_rt5640_map,
167 	.num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
168 	.fully_routed = true,
169 };
170 
haswell_audio_probe(struct platform_device * pdev)171 static int haswell_audio_probe(struct platform_device *pdev)
172 {
173 	struct snd_soc_acpi_mach *mach;
174 	int ret;
175 
176 	haswell_rt5640.dev = &pdev->dev;
177 
178 	/* override platform name, if required */
179 	mach = pdev->dev.platform_data;
180 	ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640,
181 						    mach->mach_params.platform);
182 	if (ret)
183 		return ret;
184 
185 	return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640);
186 }
187 
188 static struct platform_driver haswell_audio = {
189 	.probe = haswell_audio_probe,
190 	.driver = {
191 		.name = "haswell-audio",
192 		.pm = &snd_soc_pm_ops,
193 	},
194 };
195 
196 module_platform_driver(haswell_audio)
197 
198 /* Module information */
199 MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
200 MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
201 MODULE_LICENSE("GPL v2");
202 MODULE_ALIAS("platform:haswell-audio");
203