1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2021-2022 Intel Corporation 4 // 5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7 // 8 9 #include <linux/device.h> 10 #include <linux/module.h> 11 #include <sound/soc.h> 12 #include <sound/soc-acpi.h> 13 #include "../utils.h" 14 15 SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); 16 SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin"))); 17 18 static const struct snd_soc_dapm_widget card_widgets[] = { 19 SND_SOC_DAPM_MIC("SoC DMIC", NULL), 20 }; 21 22 static const struct snd_soc_dapm_route card_routes[] = { 23 {"DMic", NULL, "SoC DMIC"}, 24 }; 25 26 static int avs_create_dai_links(struct device *dev, const char *codec_name, 27 struct snd_soc_dai_link **links, int *num_links) 28 { 29 struct snd_soc_dai_link_component *platform; 30 struct snd_soc_dai_link *dl; 31 const int num_dl = 2; 32 33 dl = devm_kcalloc(dev, num_dl, sizeof(*dl), GFP_KERNEL); 34 platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); 35 if (!dl || !platform) 36 return -ENOMEM; 37 38 dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); 39 if (!dl->codecs) 40 return -ENOMEM; 41 42 dl->codecs->name = devm_kstrdup(dev, codec_name, GFP_KERNEL); 43 dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "dmic-hifi"); 44 if (!dl->codecs->name || !dl->codecs->dai_name) 45 return -ENOMEM; 46 47 platform->name = dev_name(dev); 48 dl[0].num_cpus = 1; 49 dl[0].num_codecs = 1; 50 dl[0].platforms = platform; 51 dl[0].num_platforms = 1; 52 dl[0].nonatomic = 1; 53 dl[0].no_pcm = 1; 54 dl[0].capture_only = 1; 55 memcpy(&dl[1], &dl[0], sizeof(*dl)); 56 57 dl[0].name = "DMIC"; 58 dl[0].cpus = dmic_pin; 59 dl[0].id = 0; 60 dl[1].name = "DMIC WoV"; 61 dl[1].cpus = dmic_wov_pin; 62 dl[1].id = 1; 63 dl[1].ignore_suspend = 1; 64 65 *links = dl; 66 *num_links = num_dl; 67 return 0; 68 } 69 70 static int avs_dmic_probe(struct platform_device *pdev) 71 { 72 struct device *dev = &pdev->dev; 73 struct snd_soc_acpi_mach *mach; 74 struct avs_mach_pdata *pdata; 75 struct snd_soc_card *card; 76 int ret; 77 78 mach = dev_get_platdata(dev); 79 pdata = mach->pdata; 80 81 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); 82 if (!card) 83 return -ENOMEM; 84 85 ret = avs_create_dai_links(dev, pdata->codec_name, &card->dai_link, &card->num_links); 86 if (ret) 87 return ret; 88 89 if (pdata->obsolete_card_names) { 90 card->name = "avs_dmic"; 91 } else { 92 card->driver_name = "avs_dmic"; 93 card->long_name = card->name = "AVS DMIC"; 94 } 95 card->dev = dev; 96 card->owner = THIS_MODULE; 97 card->dapm_widgets = card_widgets; 98 card->num_dapm_widgets = ARRAY_SIZE(card_widgets); 99 card->dapm_routes = card_routes; 100 card->num_dapm_routes = ARRAY_SIZE(card_routes); 101 card->fully_routed = true; 102 103 return devm_snd_soc_register_deferrable_card(dev, card); 104 } 105 106 static const struct platform_device_id avs_dmic_driver_ids[] = { 107 { 108 .name = "avs_dmic", 109 }, 110 {}, 111 }; 112 MODULE_DEVICE_TABLE(platform, avs_dmic_driver_ids); 113 114 static struct platform_driver avs_dmic_driver = { 115 .probe = avs_dmic_probe, 116 .driver = { 117 .name = "avs_dmic", 118 .pm = &snd_soc_pm_ops, 119 }, 120 .id_table = avs_dmic_driver_ids, 121 }; 122 123 module_platform_driver(avs_dmic_driver); 124 125 MODULE_DESCRIPTION("Intel DMIC machine driver"); 126 MODULE_LICENSE("GPL"); 127