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 | }; |
61 | |
62 | static struct acp_card_drvdata max_nau8825_data = { |
63 | .hs_cpu_id = I2S_HS, |
64 | .amp_cpu_id = I2S_HS, |
65 | .dmic_cpu_id = DMIC, |
66 | .hs_codec_id = NAU8825, |
67 | .amp_codec_id = MAX98360A, |
68 | .dmic_codec_id = DMIC, |
69 | .soc_mclk = true, |
70 | .tdm_mode = false, |
71 | }; |
72 | |
73 | static struct acp_card_drvdata rt5682s_rt1019_rmb_data = { |
74 | .hs_cpu_id = I2S_HS, |
75 | .amp_cpu_id = I2S_HS, |
76 | .dmic_cpu_id = DMIC, |
77 | .hs_codec_id = RT5682S, |
78 | .amp_codec_id = RT1019, |
79 | .dmic_codec_id = DMIC, |
80 | .soc_mclk = true, |
81 | .tdm_mode = false, |
82 | }; |
83 | |
84 | static struct acp_card_drvdata acp_dmic_data = { |
85 | .dmic_cpu_id = DMIC, |
86 | .dmic_codec_id = DMIC, |
87 | }; |
88 | |
89 | static bool acp_asoc_init_ops(struct acp_card_drvdata *priv) |
90 | { |
91 | bool has_ops = false; |
92 | |
93 | if (priv->hs_codec_id == ES83XX) { |
94 | has_ops = true; |
95 | acp3x_es83xx_init_ops(ops: &priv->ops); |
96 | } |
97 | return has_ops; |
98 | } |
99 | |
100 | static int acp_asoc_suspend_pre(struct snd_soc_card *card) |
101 | { |
102 | int ret; |
103 | |
104 | ret = acp_ops_suspend_pre(card); |
105 | if (ret == 1) |
106 | return 0; |
107 | else |
108 | return ret; |
109 | } |
110 | |
111 | static int acp_asoc_resume_post(struct snd_soc_card *card) |
112 | { |
113 | int ret; |
114 | |
115 | ret = acp_ops_resume_post(card); |
116 | if (ret == 1) |
117 | return 0; |
118 | else |
119 | return ret; |
120 | } |
121 | |
122 | static int acp_asoc_probe(struct platform_device *pdev) |
123 | { |
124 | struct snd_soc_card *card = NULL; |
125 | struct device *dev = &pdev->dev; |
126 | struct snd_soc_acpi_mach *mach = dev_get_platdata(dev: &pdev->dev); |
127 | const struct dmi_system_id *dmi_id; |
128 | struct acp_card_drvdata *acp_card_drvdata; |
129 | int ret; |
130 | |
131 | if (!pdev->id_entry) { |
132 | ret = -EINVAL; |
133 | goto out; |
134 | } |
135 | |
136 | card = devm_kzalloc(dev, size: sizeof(*card), GFP_KERNEL); |
137 | if (!card) { |
138 | ret = -ENOMEM; |
139 | goto out; |
140 | } |
141 | |
142 | card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; |
143 | acp_card_drvdata = card->drvdata; |
144 | acp_card_drvdata->acpi_mach = (struct snd_soc_acpi_mach *)pdev->dev.platform_data; |
145 | card->dev = dev; |
146 | card->owner = THIS_MODULE; |
147 | card->name = pdev->id_entry->name; |
148 | |
149 | acp_asoc_init_ops(priv: card->drvdata); |
150 | |
151 | /* If widgets and controls are not set in specific callback, |
152 | * they will be added per-codec in acp-mach-common.c |
153 | */ |
154 | ret = acp_ops_configure_widgets(card); |
155 | if (ret < 0) { |
156 | dev_err(&pdev->dev, |
157 | "Cannot configure widgets for card (%s): %d\n" , |
158 | card->name, ret); |
159 | goto out; |
160 | } |
161 | card->suspend_pre = acp_asoc_suspend_pre; |
162 | card->resume_post = acp_asoc_resume_post; |
163 | |
164 | ret = acp_ops_probe(card); |
165 | if (ret < 0) { |
166 | dev_err(&pdev->dev, |
167 | "Cannot probe card (%s): %d\n" , |
168 | card->name, ret); |
169 | goto out; |
170 | } |
171 | if (!strcmp(pdev->name, "acp-pdm-mach" )) |
172 | acp_card_drvdata->acp_rev = *((int *)dev->platform_data); |
173 | else |
174 | acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; |
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 | MODULE_DEVICE_TABLE(platform, board_ids); |
231 | |
232 | static struct platform_driver acp_asoc_audio = { |
233 | .driver = { |
234 | .pm = &snd_soc_pm_ops, |
235 | .name = "acp_mach" , |
236 | }, |
237 | .probe = acp_asoc_probe, |
238 | .id_table = board_ids, |
239 | }; |
240 | |
241 | module_platform_driver(acp_asoc_audio); |
242 | |
243 | MODULE_IMPORT_NS("SND_SOC_AMD_MACH" ); |
244 | MODULE_DESCRIPTION("ACP chrome audio support" ); |
245 | MODULE_LICENSE("GPL v2" ); |
246 | |