1*2b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2f2055e14SPeter Ujfalusi /* 3f2055e14SPeter Ujfalusi * omap-abe-twl6040.c -- SoC audio for TI OMAP based boards with ABE and 4f2055e14SPeter Ujfalusi * twl6040 codec 5f2055e14SPeter Ujfalusi * 6f2055e14SPeter Ujfalusi * Author: Misael Lopez Cruz <misael.lopez@ti.com> 7f2055e14SPeter Ujfalusi */ 8f2055e14SPeter Ujfalusi 9f2055e14SPeter Ujfalusi #include <linux/clk.h> 10f2055e14SPeter Ujfalusi #include <linux/platform_device.h> 11f2055e14SPeter Ujfalusi #include <linux/mfd/twl6040.h> 12f2055e14SPeter Ujfalusi #include <linux/module.h> 13f2055e14SPeter Ujfalusi #include <linux/of.h> 14f2055e14SPeter Ujfalusi 15f2055e14SPeter Ujfalusi #include <sound/core.h> 16f2055e14SPeter Ujfalusi #include <sound/pcm.h> 17f2055e14SPeter Ujfalusi #include <sound/soc.h> 18f2055e14SPeter Ujfalusi #include <sound/jack.h> 19f2055e14SPeter Ujfalusi 20f2055e14SPeter Ujfalusi #include "omap-dmic.h" 21f2055e14SPeter Ujfalusi #include "omap-mcpdm.h" 22f2055e14SPeter Ujfalusi #include "../codecs/twl6040.h" 23f2055e14SPeter Ujfalusi 24f2055e14SPeter Ujfalusi struct abe_twl6040 { 25f2055e14SPeter Ujfalusi struct snd_soc_card card; 26f2055e14SPeter Ujfalusi struct snd_soc_dai_link dai_links[2]; 27f2055e14SPeter Ujfalusi int jack_detection; /* board can detect jack events */ 28f2055e14SPeter Ujfalusi int mclk_freq; /* MCLK frequency speed for twl6040 */ 29f2055e14SPeter Ujfalusi }; 30f2055e14SPeter Ujfalusi 31f2055e14SPeter Ujfalusi static struct platform_device *dmic_codec_dev; 32f2055e14SPeter Ujfalusi 33f2055e14SPeter Ujfalusi static int omap_abe_hw_params(struct snd_pcm_substream *substream, 34f2055e14SPeter Ujfalusi struct snd_pcm_hw_params *params) 35f2055e14SPeter Ujfalusi { 36f2055e14SPeter Ujfalusi struct snd_soc_pcm_runtime *rtd = substream->private_data; 37f2055e14SPeter Ujfalusi struct snd_soc_dai *codec_dai = rtd->codec_dai; 38f2055e14SPeter Ujfalusi struct snd_soc_card *card = rtd->card; 39f2055e14SPeter Ujfalusi struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); 40f2055e14SPeter Ujfalusi int clk_id, freq; 41f2055e14SPeter Ujfalusi int ret; 42f2055e14SPeter Ujfalusi 43f2055e14SPeter Ujfalusi clk_id = twl6040_get_clk_id(codec_dai->component); 44f2055e14SPeter Ujfalusi if (clk_id == TWL6040_SYSCLK_SEL_HPPLL) 45f2055e14SPeter Ujfalusi freq = priv->mclk_freq; 46f2055e14SPeter Ujfalusi else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL) 47f2055e14SPeter Ujfalusi freq = 32768; 48f2055e14SPeter Ujfalusi else 49f2055e14SPeter Ujfalusi return -EINVAL; 50f2055e14SPeter Ujfalusi 51f2055e14SPeter Ujfalusi /* set the codec mclk */ 52f2055e14SPeter Ujfalusi ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq, 53f2055e14SPeter Ujfalusi SND_SOC_CLOCK_IN); 54f2055e14SPeter Ujfalusi if (ret) { 55f2055e14SPeter Ujfalusi printk(KERN_ERR "can't set codec system clock\n"); 56f2055e14SPeter Ujfalusi return ret; 57f2055e14SPeter Ujfalusi } 58f2055e14SPeter Ujfalusi return ret; 59f2055e14SPeter Ujfalusi } 60f2055e14SPeter Ujfalusi 61f2055e14SPeter Ujfalusi static const struct snd_soc_ops omap_abe_ops = { 62f2055e14SPeter Ujfalusi .hw_params = omap_abe_hw_params, 63f2055e14SPeter Ujfalusi }; 64f2055e14SPeter Ujfalusi 65f2055e14SPeter Ujfalusi static int omap_abe_dmic_hw_params(struct snd_pcm_substream *substream, 66f2055e14SPeter Ujfalusi struct snd_pcm_hw_params *params) 67f2055e14SPeter Ujfalusi { 68f2055e14SPeter Ujfalusi struct snd_soc_pcm_runtime *rtd = substream->private_data; 69f2055e14SPeter Ujfalusi struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 70f2055e14SPeter Ujfalusi int ret = 0; 71f2055e14SPeter Ujfalusi 72f2055e14SPeter Ujfalusi ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS, 73f2055e14SPeter Ujfalusi 19200000, SND_SOC_CLOCK_IN); 74f2055e14SPeter Ujfalusi if (ret < 0) { 75f2055e14SPeter Ujfalusi printk(KERN_ERR "can't set DMIC cpu system clock\n"); 76f2055e14SPeter Ujfalusi return ret; 77f2055e14SPeter Ujfalusi } 78f2055e14SPeter Ujfalusi ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000, 79f2055e14SPeter Ujfalusi SND_SOC_CLOCK_OUT); 80f2055e14SPeter Ujfalusi if (ret < 0) { 81f2055e14SPeter Ujfalusi printk(KERN_ERR "can't set DMIC output clock\n"); 82f2055e14SPeter Ujfalusi return ret; 83f2055e14SPeter Ujfalusi } 84f2055e14SPeter Ujfalusi return 0; 85f2055e14SPeter Ujfalusi } 86f2055e14SPeter Ujfalusi 87f2055e14SPeter Ujfalusi static struct snd_soc_ops omap_abe_dmic_ops = { 88f2055e14SPeter Ujfalusi .hw_params = omap_abe_dmic_hw_params, 89f2055e14SPeter Ujfalusi }; 90f2055e14SPeter Ujfalusi 91f2055e14SPeter Ujfalusi /* Headset jack */ 92f2055e14SPeter Ujfalusi static struct snd_soc_jack hs_jack; 93f2055e14SPeter Ujfalusi 94f2055e14SPeter Ujfalusi /*Headset jack detection DAPM pins */ 95f2055e14SPeter Ujfalusi static struct snd_soc_jack_pin hs_jack_pins[] = { 96f2055e14SPeter Ujfalusi { 97f2055e14SPeter Ujfalusi .pin = "Headset Mic", 98f2055e14SPeter Ujfalusi .mask = SND_JACK_MICROPHONE, 99f2055e14SPeter Ujfalusi }, 100f2055e14SPeter Ujfalusi { 101f2055e14SPeter Ujfalusi .pin = "Headset Stereophone", 102f2055e14SPeter Ujfalusi .mask = SND_JACK_HEADPHONE, 103f2055e14SPeter Ujfalusi }, 104f2055e14SPeter Ujfalusi }; 105f2055e14SPeter Ujfalusi 106f2055e14SPeter Ujfalusi /* SDP4430 machine DAPM */ 107f2055e14SPeter Ujfalusi static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { 108f2055e14SPeter Ujfalusi /* Outputs */ 109f2055e14SPeter Ujfalusi SND_SOC_DAPM_HP("Headset Stereophone", NULL), 110f2055e14SPeter Ujfalusi SND_SOC_DAPM_SPK("Earphone Spk", NULL), 111f2055e14SPeter Ujfalusi SND_SOC_DAPM_SPK("Ext Spk", NULL), 112f2055e14SPeter Ujfalusi SND_SOC_DAPM_LINE("Line Out", NULL), 113f2055e14SPeter Ujfalusi SND_SOC_DAPM_SPK("Vibrator", NULL), 114f2055e14SPeter Ujfalusi 115f2055e14SPeter Ujfalusi /* Inputs */ 116f2055e14SPeter Ujfalusi SND_SOC_DAPM_MIC("Headset Mic", NULL), 117f2055e14SPeter Ujfalusi SND_SOC_DAPM_MIC("Main Handset Mic", NULL), 118f2055e14SPeter Ujfalusi SND_SOC_DAPM_MIC("Sub Handset Mic", NULL), 119f2055e14SPeter Ujfalusi SND_SOC_DAPM_LINE("Line In", NULL), 120f2055e14SPeter Ujfalusi 121f2055e14SPeter Ujfalusi /* Digital microphones */ 122f2055e14SPeter Ujfalusi SND_SOC_DAPM_MIC("Digital Mic", NULL), 123f2055e14SPeter Ujfalusi }; 124f2055e14SPeter Ujfalusi 125f2055e14SPeter Ujfalusi static const struct snd_soc_dapm_route audio_map[] = { 126f2055e14SPeter Ujfalusi /* Routings for outputs */ 127f2055e14SPeter Ujfalusi {"Headset Stereophone", NULL, "HSOL"}, 128f2055e14SPeter Ujfalusi {"Headset Stereophone", NULL, "HSOR"}, 129f2055e14SPeter Ujfalusi 130f2055e14SPeter Ujfalusi {"Earphone Spk", NULL, "EP"}, 131f2055e14SPeter Ujfalusi 132f2055e14SPeter Ujfalusi {"Ext Spk", NULL, "HFL"}, 133f2055e14SPeter Ujfalusi {"Ext Spk", NULL, "HFR"}, 134f2055e14SPeter Ujfalusi 135f2055e14SPeter Ujfalusi {"Line Out", NULL, "AUXL"}, 136f2055e14SPeter Ujfalusi {"Line Out", NULL, "AUXR"}, 137f2055e14SPeter Ujfalusi 138f2055e14SPeter Ujfalusi {"Vibrator", NULL, "VIBRAL"}, 139f2055e14SPeter Ujfalusi {"Vibrator", NULL, "VIBRAR"}, 140f2055e14SPeter Ujfalusi 141f2055e14SPeter Ujfalusi /* Routings for inputs */ 142f2055e14SPeter Ujfalusi {"HSMIC", NULL, "Headset Mic"}, 143f2055e14SPeter Ujfalusi {"Headset Mic", NULL, "Headset Mic Bias"}, 144f2055e14SPeter Ujfalusi 145f2055e14SPeter Ujfalusi {"MAINMIC", NULL, "Main Handset Mic"}, 146f2055e14SPeter Ujfalusi {"Main Handset Mic", NULL, "Main Mic Bias"}, 147f2055e14SPeter Ujfalusi 148f2055e14SPeter Ujfalusi {"SUBMIC", NULL, "Sub Handset Mic"}, 149f2055e14SPeter Ujfalusi {"Sub Handset Mic", NULL, "Main Mic Bias"}, 150f2055e14SPeter Ujfalusi 151f2055e14SPeter Ujfalusi {"AFML", NULL, "Line In"}, 152f2055e14SPeter Ujfalusi {"AFMR", NULL, "Line In"}, 153f2055e14SPeter Ujfalusi }; 154f2055e14SPeter Ujfalusi 155f2055e14SPeter Ujfalusi static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) 156f2055e14SPeter Ujfalusi { 157f2055e14SPeter Ujfalusi struct snd_soc_component *component = rtd->codec_dai->component; 158f2055e14SPeter Ujfalusi struct snd_soc_card *card = rtd->card; 159f2055e14SPeter Ujfalusi struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); 160f2055e14SPeter Ujfalusi int hs_trim; 161f2055e14SPeter Ujfalusi int ret = 0; 162f2055e14SPeter Ujfalusi 163f2055e14SPeter Ujfalusi /* 164f2055e14SPeter Ujfalusi * Configure McPDM offset cancellation based on the HSOTRIM value from 165f2055e14SPeter Ujfalusi * twl6040. 166f2055e14SPeter Ujfalusi */ 167f2055e14SPeter Ujfalusi hs_trim = twl6040_get_trim_value(component, TWL6040_TRIM_HSOTRIM); 168f2055e14SPeter Ujfalusi omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim), 169f2055e14SPeter Ujfalusi TWL6040_HSF_TRIM_RIGHT(hs_trim)); 170f2055e14SPeter Ujfalusi 171f2055e14SPeter Ujfalusi /* Headset jack detection only if it is supported */ 172f2055e14SPeter Ujfalusi if (priv->jack_detection) { 173f2055e14SPeter Ujfalusi ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", 174f2055e14SPeter Ujfalusi SND_JACK_HEADSET, &hs_jack, 175f2055e14SPeter Ujfalusi hs_jack_pins, 176f2055e14SPeter Ujfalusi ARRAY_SIZE(hs_jack_pins)); 177f2055e14SPeter Ujfalusi if (ret) 178f2055e14SPeter Ujfalusi return ret; 179f2055e14SPeter Ujfalusi 180f2055e14SPeter Ujfalusi twl6040_hs_jack_detect(component, &hs_jack, SND_JACK_HEADSET); 181f2055e14SPeter Ujfalusi } 182f2055e14SPeter Ujfalusi 183f2055e14SPeter Ujfalusi return 0; 184f2055e14SPeter Ujfalusi } 185f2055e14SPeter Ujfalusi 186f2055e14SPeter Ujfalusi static const struct snd_soc_dapm_route dmic_audio_map[] = { 187f2055e14SPeter Ujfalusi {"DMic", NULL, "Digital Mic"}, 188f2055e14SPeter Ujfalusi {"Digital Mic", NULL, "Digital Mic1 Bias"}, 189f2055e14SPeter Ujfalusi }; 190f2055e14SPeter Ujfalusi 191f2055e14SPeter Ujfalusi static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd) 192f2055e14SPeter Ujfalusi { 193f2055e14SPeter Ujfalusi struct snd_soc_dapm_context *dapm = &rtd->card->dapm; 194f2055e14SPeter Ujfalusi 195f2055e14SPeter Ujfalusi return snd_soc_dapm_add_routes(dapm, dmic_audio_map, 196f2055e14SPeter Ujfalusi ARRAY_SIZE(dmic_audio_map)); 197f2055e14SPeter Ujfalusi } 198f2055e14SPeter Ujfalusi 199f2055e14SPeter Ujfalusi static int omap_abe_probe(struct platform_device *pdev) 200f2055e14SPeter Ujfalusi { 201f2055e14SPeter Ujfalusi struct device_node *node = pdev->dev.of_node; 202f2055e14SPeter Ujfalusi struct snd_soc_card *card; 203f2055e14SPeter Ujfalusi struct device_node *dai_node; 204f2055e14SPeter Ujfalusi struct abe_twl6040 *priv; 205f2055e14SPeter Ujfalusi int num_links = 0; 206f2055e14SPeter Ujfalusi int ret = 0; 207f2055e14SPeter Ujfalusi 208f2055e14SPeter Ujfalusi if (!node) { 209f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "of node is missing.\n"); 210f2055e14SPeter Ujfalusi return -ENODEV; 211f2055e14SPeter Ujfalusi } 212f2055e14SPeter Ujfalusi 213f2055e14SPeter Ujfalusi priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); 214f2055e14SPeter Ujfalusi if (priv == NULL) 215f2055e14SPeter Ujfalusi return -ENOMEM; 216f2055e14SPeter Ujfalusi 217f2055e14SPeter Ujfalusi card = &priv->card; 218f2055e14SPeter Ujfalusi card->dev = &pdev->dev; 219f2055e14SPeter Ujfalusi card->owner = THIS_MODULE; 220f2055e14SPeter Ujfalusi card->dapm_widgets = twl6040_dapm_widgets; 221f2055e14SPeter Ujfalusi card->num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets); 222f2055e14SPeter Ujfalusi card->dapm_routes = audio_map; 223f2055e14SPeter Ujfalusi card->num_dapm_routes = ARRAY_SIZE(audio_map); 224f2055e14SPeter Ujfalusi 225f2055e14SPeter Ujfalusi if (snd_soc_of_parse_card_name(card, "ti,model")) { 226f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "Card name is not provided\n"); 227f2055e14SPeter Ujfalusi return -ENODEV; 228f2055e14SPeter Ujfalusi } 229f2055e14SPeter Ujfalusi 230f2055e14SPeter Ujfalusi ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing"); 231f2055e14SPeter Ujfalusi if (ret) { 232f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "Error while parsing DAPM routing\n"); 233f2055e14SPeter Ujfalusi return ret; 234f2055e14SPeter Ujfalusi } 235f2055e14SPeter Ujfalusi 236f2055e14SPeter Ujfalusi dai_node = of_parse_phandle(node, "ti,mcpdm", 0); 237f2055e14SPeter Ujfalusi if (!dai_node) { 238f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "McPDM node is not provided\n"); 239f2055e14SPeter Ujfalusi return -EINVAL; 240f2055e14SPeter Ujfalusi } 241f2055e14SPeter Ujfalusi 242f2055e14SPeter Ujfalusi priv->dai_links[0].name = "DMIC"; 243f2055e14SPeter Ujfalusi priv->dai_links[0].stream_name = "TWL6040"; 244f2055e14SPeter Ujfalusi priv->dai_links[0].cpu_of_node = dai_node; 245f2055e14SPeter Ujfalusi priv->dai_links[0].platform_of_node = dai_node; 246f2055e14SPeter Ujfalusi priv->dai_links[0].codec_dai_name = "twl6040-legacy"; 247f2055e14SPeter Ujfalusi priv->dai_links[0].codec_name = "twl6040-codec"; 248f2055e14SPeter Ujfalusi priv->dai_links[0].init = omap_abe_twl6040_init; 249f2055e14SPeter Ujfalusi priv->dai_links[0].ops = &omap_abe_ops; 250f2055e14SPeter Ujfalusi 251f2055e14SPeter Ujfalusi dai_node = of_parse_phandle(node, "ti,dmic", 0); 252f2055e14SPeter Ujfalusi if (dai_node) { 253f2055e14SPeter Ujfalusi num_links = 2; 254f2055e14SPeter Ujfalusi priv->dai_links[1].name = "TWL6040"; 255f2055e14SPeter Ujfalusi priv->dai_links[1].stream_name = "DMIC Capture"; 256f2055e14SPeter Ujfalusi priv->dai_links[1].cpu_of_node = dai_node; 257f2055e14SPeter Ujfalusi priv->dai_links[1].platform_of_node = dai_node; 258f2055e14SPeter Ujfalusi priv->dai_links[1].codec_dai_name = "dmic-hifi"; 259f2055e14SPeter Ujfalusi priv->dai_links[1].codec_name = "dmic-codec"; 260f2055e14SPeter Ujfalusi priv->dai_links[1].init = omap_abe_dmic_init; 261f2055e14SPeter Ujfalusi priv->dai_links[1].ops = &omap_abe_dmic_ops; 262f2055e14SPeter Ujfalusi } else { 263f2055e14SPeter Ujfalusi num_links = 1; 264f2055e14SPeter Ujfalusi } 265f2055e14SPeter Ujfalusi 266f2055e14SPeter Ujfalusi priv->jack_detection = of_property_read_bool(node, "ti,jack-detection"); 267f2055e14SPeter Ujfalusi of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq); 268f2055e14SPeter Ujfalusi if (!priv->mclk_freq) { 269f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "MCLK frequency not provided\n"); 270f2055e14SPeter Ujfalusi return -EINVAL; 271f2055e14SPeter Ujfalusi } 272f2055e14SPeter Ujfalusi 273f2055e14SPeter Ujfalusi card->fully_routed = 1; 274f2055e14SPeter Ujfalusi 275f2055e14SPeter Ujfalusi if (!priv->mclk_freq) { 276f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "MCLK frequency missing\n"); 277f2055e14SPeter Ujfalusi return -ENODEV; 278f2055e14SPeter Ujfalusi } 279f2055e14SPeter Ujfalusi 280f2055e14SPeter Ujfalusi card->dai_link = priv->dai_links; 281f2055e14SPeter Ujfalusi card->num_links = num_links; 282f2055e14SPeter Ujfalusi 283f2055e14SPeter Ujfalusi snd_soc_card_set_drvdata(card, priv); 284f2055e14SPeter Ujfalusi 285f2055e14SPeter Ujfalusi ret = devm_snd_soc_register_card(&pdev->dev, card); 286f2055e14SPeter Ujfalusi if (ret) 287f2055e14SPeter Ujfalusi dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", 288f2055e14SPeter Ujfalusi ret); 289f2055e14SPeter Ujfalusi 290f2055e14SPeter Ujfalusi return ret; 291f2055e14SPeter Ujfalusi } 292f2055e14SPeter Ujfalusi 293f2055e14SPeter Ujfalusi static const struct of_device_id omap_abe_of_match[] = { 294f2055e14SPeter Ujfalusi {.compatible = "ti,abe-twl6040", }, 295f2055e14SPeter Ujfalusi { }, 296f2055e14SPeter Ujfalusi }; 297f2055e14SPeter Ujfalusi MODULE_DEVICE_TABLE(of, omap_abe_of_match); 298f2055e14SPeter Ujfalusi 299f2055e14SPeter Ujfalusi static struct platform_driver omap_abe_driver = { 300f2055e14SPeter Ujfalusi .driver = { 301f2055e14SPeter Ujfalusi .name = "omap-abe-twl6040", 302f2055e14SPeter Ujfalusi .pm = &snd_soc_pm_ops, 303f2055e14SPeter Ujfalusi .of_match_table = omap_abe_of_match, 304f2055e14SPeter Ujfalusi }, 305f2055e14SPeter Ujfalusi .probe = omap_abe_probe, 306f2055e14SPeter Ujfalusi }; 307f2055e14SPeter Ujfalusi 308f2055e14SPeter Ujfalusi static int __init omap_abe_init(void) 309f2055e14SPeter Ujfalusi { 310f2055e14SPeter Ujfalusi int ret; 311f2055e14SPeter Ujfalusi 312f2055e14SPeter Ujfalusi dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL, 313f2055e14SPeter Ujfalusi 0); 314f2055e14SPeter Ujfalusi if (IS_ERR(dmic_codec_dev)) { 315f2055e14SPeter Ujfalusi pr_err("%s: dmic-codec device registration failed\n", __func__); 316f2055e14SPeter Ujfalusi return PTR_ERR(dmic_codec_dev); 317f2055e14SPeter Ujfalusi } 318f2055e14SPeter Ujfalusi 319f2055e14SPeter Ujfalusi ret = platform_driver_register(&omap_abe_driver); 320f2055e14SPeter Ujfalusi if (ret) { 321f2055e14SPeter Ujfalusi pr_err("%s: platform driver registration failed\n", __func__); 322f2055e14SPeter Ujfalusi platform_device_unregister(dmic_codec_dev); 323f2055e14SPeter Ujfalusi } 324f2055e14SPeter Ujfalusi 325f2055e14SPeter Ujfalusi return ret; 326f2055e14SPeter Ujfalusi } 327f2055e14SPeter Ujfalusi module_init(omap_abe_init); 328f2055e14SPeter Ujfalusi 329f2055e14SPeter Ujfalusi static void __exit omap_abe_exit(void) 330f2055e14SPeter Ujfalusi { 331f2055e14SPeter Ujfalusi platform_driver_unregister(&omap_abe_driver); 332f2055e14SPeter Ujfalusi platform_device_unregister(dmic_codec_dev); 333f2055e14SPeter Ujfalusi } 334f2055e14SPeter Ujfalusi module_exit(omap_abe_exit); 335f2055e14SPeter Ujfalusi 336f2055e14SPeter Ujfalusi MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); 337f2055e14SPeter Ujfalusi MODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec"); 338f2055e14SPeter Ujfalusi MODULE_LICENSE("GPL"); 339f2055e14SPeter Ujfalusi MODULE_ALIAS("platform:omap-abe-twl6040"); 340