1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) |
2 | // |
3 | // This file is provided under a dual BSD/GPLv2 license. When using or |
4 | // redistributing this file, you may do so under either license. |
5 | // |
6 | // Copyright(c) 2021 Advanced Micro Devices, Inc. |
7 | // |
8 | // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> |
9 | // |
10 | |
11 | /* |
12 | * Machine Driver Legacy Support for ACP HW block |
13 | */ |
14 | |
15 | #include <sound/core.h> |
16 | #include <sound/pcm_params.h> |
17 | #include <sound/soc-acpi.h> |
18 | #include <sound/soc-dapm.h> |
19 | #include <linux/dmi.h> |
20 | #include <linux/module.h> |
21 | |
22 | #include "acp-mach.h" |
23 | #include "acp3x-es83xx/acp3x-es83xx.h" |
24 | |
25 | static struct acp_card_drvdata rt5682_rt1019_data = { |
26 | .hs_cpu_id = I2S_SP, |
27 | .amp_cpu_id = I2S_SP, |
28 | .dmic_cpu_id = DMIC, |
29 | .hs_codec_id = RT5682, |
30 | .amp_codec_id = RT1019, |
31 | .dmic_codec_id = DMIC, |
32 | .tdm_mode = false, |
33 | }; |
34 | |
35 | static struct acp_card_drvdata rt5682s_max_data = { |
36 | .hs_cpu_id = I2S_SP, |
37 | .amp_cpu_id = I2S_SP, |
38 | .dmic_cpu_id = DMIC, |
39 | .hs_codec_id = RT5682S, |
40 | .amp_codec_id = MAX98360A, |
41 | .dmic_codec_id = DMIC, |
42 | .tdm_mode = false, |
43 | }; |
44 | |
45 | static struct acp_card_drvdata rt5682s_rt1019_data = { |
46 | .hs_cpu_id = I2S_SP, |
47 | .amp_cpu_id = I2S_SP, |
48 | .dmic_cpu_id = DMIC, |
49 | .hs_codec_id = RT5682S, |
50 | .amp_codec_id = RT1019, |
51 | .dmic_codec_id = DMIC, |
52 | .tdm_mode = false, |
53 | }; |
54 | |
55 | static struct acp_card_drvdata es83xx_rn_data = { |
56 | .hs_cpu_id = I2S_SP, |
57 | .dmic_cpu_id = DMIC, |
58 | .hs_codec_id = ES83XX, |
59 | .dmic_codec_id = DMIC, |
60 | .platform = RENOIR, |
61 | }; |
62 | |
63 | static struct acp_card_drvdata max_nau8825_data = { |
64 | .hs_cpu_id = I2S_HS, |
65 | .amp_cpu_id = I2S_HS, |
66 | .dmic_cpu_id = DMIC, |
67 | .hs_codec_id = NAU8825, |
68 | .amp_codec_id = MAX98360A, |
69 | .dmic_codec_id = DMIC, |
70 | .soc_mclk = true, |
71 | .platform = REMBRANDT, |
72 | .tdm_mode = false, |
73 | }; |
74 | |
75 | static struct acp_card_drvdata rt5682s_rt1019_rmb_data = { |
76 | .hs_cpu_id = I2S_HS, |
77 | .amp_cpu_id = I2S_HS, |
78 | .dmic_cpu_id = DMIC, |
79 | .hs_codec_id = RT5682S, |
80 | .amp_codec_id = RT1019, |
81 | .dmic_codec_id = DMIC, |
82 | .soc_mclk = true, |
83 | .platform = REMBRANDT, |
84 | .tdm_mode = false, |
85 | }; |
86 | |
87 | static struct acp_card_drvdata acp_dmic_data = { |
88 | .dmic_cpu_id = DMIC, |
89 | .dmic_codec_id = DMIC, |
90 | }; |
91 | |
92 | static bool acp_asoc_init_ops(struct acp_card_drvdata *priv) |
93 | { |
94 | bool has_ops = false; |
95 | |
96 | if (priv->hs_codec_id == ES83XX) { |
97 | has_ops = true; |
98 | acp3x_es83xx_init_ops(ops: &priv->ops); |
99 | } |
100 | return has_ops; |
101 | } |
102 | |
103 | static int acp_asoc_suspend_pre(struct snd_soc_card *card) |
104 | { |
105 | int ret; |
106 | |
107 | ret = acp_ops_suspend_pre(card); |
108 | if (ret == 1) |
109 | return 0; |
110 | else |
111 | return ret; |
112 | } |
113 | |
114 | static int acp_asoc_resume_post(struct snd_soc_card *card) |
115 | { |
116 | int ret; |
117 | |
118 | ret = acp_ops_resume_post(card); |
119 | if (ret == 1) |
120 | return 0; |
121 | else |
122 | return ret; |
123 | } |
124 | |
125 | static int acp_asoc_probe(struct platform_device *pdev) |
126 | { |
127 | struct snd_soc_card *card = NULL; |
128 | struct device *dev = &pdev->dev; |
129 | const struct dmi_system_id *dmi_id; |
130 | struct acp_card_drvdata *acp_card_drvdata; |
131 | int ret; |
132 | |
133 | if (!pdev->id_entry) { |
134 | ret = -EINVAL; |
135 | goto out; |
136 | } |
137 | |
138 | card = devm_kzalloc(dev, size: sizeof(*card), GFP_KERNEL); |
139 | if (!card) { |
140 | ret = -ENOMEM; |
141 | goto out; |
142 | } |
143 | |
144 | card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; |
145 | acp_card_drvdata = card->drvdata; |
146 | acp_card_drvdata->acpi_mach = (struct snd_soc_acpi_mach *)pdev->dev.platform_data; |
147 | card->dev = dev; |
148 | card->owner = THIS_MODULE; |
149 | card->name = pdev->id_entry->name; |
150 | |
151 | acp_asoc_init_ops(priv: card->drvdata); |
152 | |
153 | /* If widgets and controls are not set in specific callback, |
154 | * they will be added per-codec in acp-mach-common.c |
155 | */ |
156 | ret = acp_ops_configure_widgets(card); |
157 | if (ret < 0) { |
158 | dev_err(&pdev->dev, |
159 | "Cannot configure widgets for card (%s): %d\n" , |
160 | card->name, ret); |
161 | goto out; |
162 | } |
163 | card->suspend_pre = acp_asoc_suspend_pre; |
164 | card->resume_post = acp_asoc_resume_post; |
165 | |
166 | ret = acp_ops_probe(card); |
167 | if (ret < 0) { |
168 | dev_err(&pdev->dev, |
169 | "Cannot probe card (%s): %d\n" , |
170 | card->name, ret); |
171 | goto out; |
172 | } |
173 | if (!strcmp(pdev->name, "acp-pdm-mach" )) |
174 | acp_card_drvdata->platform = *((int *)dev->platform_data); |
175 | |
176 | dmi_id = dmi_first_match(list: acp_quirk_table); |
177 | if (dmi_id && dmi_id->driver_data) |
178 | acp_card_drvdata->tdm_mode = dmi_id->driver_data; |
179 | |
180 | ret = acp_legacy_dai_links_create(card); |
181 | if (ret) { |
182 | dev_err(&pdev->dev, |
183 | "Cannot create dai links for card (%s): %d\n" , |
184 | card->name, ret); |
185 | goto out; |
186 | } |
187 | |
188 | ret = devm_snd_soc_register_card(dev: &pdev->dev, card); |
189 | if (ret) { |
190 | dev_err(&pdev->dev, |
191 | "devm_snd_soc_register_card(%s) failed: %d\n" , |
192 | card->name, ret); |
193 | goto out; |
194 | } |
195 | out: |
196 | return ret; |
197 | } |
198 | |
199 | static const struct platform_device_id board_ids[] = { |
200 | { |
201 | .name = "acp3xalc56821019" , |
202 | .driver_data = (kernel_ulong_t)&rt5682_rt1019_data, |
203 | }, |
204 | { |
205 | .name = "acp3xalc5682sm98360" , |
206 | .driver_data = (kernel_ulong_t)&rt5682s_max_data, |
207 | }, |
208 | { |
209 | .name = "acp3xalc5682s1019" , |
210 | .driver_data = (kernel_ulong_t)&rt5682s_rt1019_data, |
211 | }, |
212 | { |
213 | .name = "acp3x-es83xx" , |
214 | .driver_data = (kernel_ulong_t)&es83xx_rn_data, |
215 | }, |
216 | { |
217 | .name = "rmb-nau8825-max" , |
218 | .driver_data = (kernel_ulong_t)&max_nau8825_data, |
219 | }, |
220 | { |
221 | .name = "rmb-rt5682s-rt1019" , |
222 | .driver_data = (kernel_ulong_t)&rt5682s_rt1019_rmb_data, |
223 | }, |
224 | { |
225 | .name = "acp-pdm-mach" , |
226 | .driver_data = (kernel_ulong_t)&acp_dmic_data, |
227 | }, |
228 | { } |
229 | }; |
230 | static struct platform_driver acp_asoc_audio = { |
231 | .driver = { |
232 | .pm = &snd_soc_pm_ops, |
233 | .name = "acp_mach" , |
234 | }, |
235 | .probe = acp_asoc_probe, |
236 | .id_table = board_ids, |
237 | }; |
238 | |
239 | module_platform_driver(acp_asoc_audio); |
240 | |
241 | MODULE_IMPORT_NS(SND_SOC_AMD_MACH); |
242 | MODULE_DESCRIPTION("ACP chrome audio support" ); |
243 | MODULE_ALIAS("platform:acp3xalc56821019" ); |
244 | MODULE_ALIAS("platform:acp3xalc5682sm98360" ); |
245 | MODULE_ALIAS("platform:acp3xalc5682s1019" ); |
246 | MODULE_ALIAS("platform:acp3x-es83xx" ); |
247 | MODULE_ALIAS("platform:rmb-nau8825-max" ); |
248 | MODULE_ALIAS("platform:rmb-rt5682s-rt1019" ); |
249 | MODULE_ALIAS("platform:acp-pdm-mach" ); |
250 | MODULE_LICENSE("GPL v2" ); |
251 | |