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(&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(&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, 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(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(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(&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