18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * omap-abe-twl6040.c -- SoC audio for TI OMAP based boards with ABE and 48c2ecf20Sopenharmony_ci * twl6040 codec 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author: Misael Lopez Cruz <misael.lopez@ti.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 118c2ecf20Sopenharmony_ci#include <linux/mfd/twl6040.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <sound/core.h> 168c2ecf20Sopenharmony_ci#include <sound/pcm.h> 178c2ecf20Sopenharmony_ci#include <sound/soc.h> 188c2ecf20Sopenharmony_ci#include <sound/jack.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "omap-dmic.h" 218c2ecf20Sopenharmony_ci#include "omap-mcpdm.h" 228c2ecf20Sopenharmony_ci#include "../codecs/twl6040.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(link0, 258c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 268c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("twl6040-codec", 278c2ecf20Sopenharmony_ci "twl6040-legacy")), 288c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(link1, 318c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 328c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", 338c2ecf20Sopenharmony_ci "dmic-hifi")), 348c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct abe_twl6040 { 378c2ecf20Sopenharmony_ci struct snd_soc_card card; 388c2ecf20Sopenharmony_ci struct snd_soc_dai_link dai_links[2]; 398c2ecf20Sopenharmony_ci int jack_detection; /* board can detect jack events */ 408c2ecf20Sopenharmony_ci int mclk_freq; /* MCLK frequency speed for twl6040 */ 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic struct platform_device *dmic_codec_dev; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int omap_abe_hw_params(struct snd_pcm_substream *substream, 468c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 498c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 508c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 518c2ecf20Sopenharmony_ci struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); 528c2ecf20Sopenharmony_ci int clk_id, freq; 538c2ecf20Sopenharmony_ci int ret; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci clk_id = twl6040_get_clk_id(codec_dai->component); 568c2ecf20Sopenharmony_ci if (clk_id == TWL6040_SYSCLK_SEL_HPPLL) 578c2ecf20Sopenharmony_ci freq = priv->mclk_freq; 588c2ecf20Sopenharmony_ci else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL) 598c2ecf20Sopenharmony_ci freq = 32768; 608c2ecf20Sopenharmony_ci else 618c2ecf20Sopenharmony_ci return -EINVAL; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* set the codec mclk */ 648c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq, 658c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 668c2ecf20Sopenharmony_ci if (ret) { 678c2ecf20Sopenharmony_ci printk(KERN_ERR "can't set codec system clock\n"); 688c2ecf20Sopenharmony_ci return ret; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci return ret; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const struct snd_soc_ops omap_abe_ops = { 748c2ecf20Sopenharmony_ci .hw_params = omap_abe_hw_params, 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int omap_abe_dmic_hw_params(struct snd_pcm_substream *substream, 788c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 818c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 828c2ecf20Sopenharmony_ci int ret = 0; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS, 858c2ecf20Sopenharmony_ci 19200000, SND_SOC_CLOCK_IN); 868c2ecf20Sopenharmony_ci if (ret < 0) { 878c2ecf20Sopenharmony_ci printk(KERN_ERR "can't set DMIC cpu system clock\n"); 888c2ecf20Sopenharmony_ci return ret; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000, 918c2ecf20Sopenharmony_ci SND_SOC_CLOCK_OUT); 928c2ecf20Sopenharmony_ci if (ret < 0) { 938c2ecf20Sopenharmony_ci printk(KERN_ERR "can't set DMIC output clock\n"); 948c2ecf20Sopenharmony_ci return ret; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic struct snd_soc_ops omap_abe_dmic_ops = { 1008c2ecf20Sopenharmony_ci .hw_params = omap_abe_dmic_hw_params, 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* Headset jack */ 1048c2ecf20Sopenharmony_cistatic struct snd_soc_jack hs_jack; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/*Headset jack detection DAPM pins */ 1078c2ecf20Sopenharmony_cistatic struct snd_soc_jack_pin hs_jack_pins[] = { 1088c2ecf20Sopenharmony_ci { 1098c2ecf20Sopenharmony_ci .pin = "Headset Mic", 1108c2ecf20Sopenharmony_ci .mask = SND_JACK_MICROPHONE, 1118c2ecf20Sopenharmony_ci }, 1128c2ecf20Sopenharmony_ci { 1138c2ecf20Sopenharmony_ci .pin = "Headset Stereophone", 1148c2ecf20Sopenharmony_ci .mask = SND_JACK_HEADPHONE, 1158c2ecf20Sopenharmony_ci }, 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* SDP4430 machine DAPM */ 1198c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { 1208c2ecf20Sopenharmony_ci /* Outputs */ 1218c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headset Stereophone", NULL), 1228c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Earphone Spk", NULL), 1238c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Ext Spk", NULL), 1248c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("Line Out", NULL), 1258c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Vibrator", NULL), 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* Inputs */ 1288c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Headset Mic", NULL), 1298c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Main Handset Mic", NULL), 1308c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Sub Handset Mic", NULL), 1318c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("Line In", NULL), 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Digital microphones */ 1348c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Digital Mic", NULL), 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map[] = { 1388c2ecf20Sopenharmony_ci /* Routings for outputs */ 1398c2ecf20Sopenharmony_ci {"Headset Stereophone", NULL, "HSOL"}, 1408c2ecf20Sopenharmony_ci {"Headset Stereophone", NULL, "HSOR"}, 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci {"Earphone Spk", NULL, "EP"}, 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci {"Ext Spk", NULL, "HFL"}, 1458c2ecf20Sopenharmony_ci {"Ext Spk", NULL, "HFR"}, 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci {"Line Out", NULL, "AUXL"}, 1488c2ecf20Sopenharmony_ci {"Line Out", NULL, "AUXR"}, 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci {"Vibrator", NULL, "VIBRAL"}, 1518c2ecf20Sopenharmony_ci {"Vibrator", NULL, "VIBRAR"}, 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* Routings for inputs */ 1548c2ecf20Sopenharmony_ci {"HSMIC", NULL, "Headset Mic"}, 1558c2ecf20Sopenharmony_ci {"Headset Mic", NULL, "Headset Mic Bias"}, 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci {"MAINMIC", NULL, "Main Handset Mic"}, 1588c2ecf20Sopenharmony_ci {"Main Handset Mic", NULL, "Main Mic Bias"}, 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci {"SUBMIC", NULL, "Sub Handset Mic"}, 1618c2ecf20Sopenharmony_ci {"Sub Handset Mic", NULL, "Main Mic Bias"}, 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci {"AFML", NULL, "Line In"}, 1648c2ecf20Sopenharmony_ci {"AFMR", NULL, "Line In"}, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; 1708c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 1718c2ecf20Sopenharmony_ci struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); 1728c2ecf20Sopenharmony_ci int hs_trim; 1738c2ecf20Sopenharmony_ci int ret = 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* 1768c2ecf20Sopenharmony_ci * Configure McPDM offset cancellation based on the HSOTRIM value from 1778c2ecf20Sopenharmony_ci * twl6040. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci hs_trim = twl6040_get_trim_value(component, TWL6040_TRIM_HSOTRIM); 1808c2ecf20Sopenharmony_ci omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim), 1818c2ecf20Sopenharmony_ci TWL6040_HSF_TRIM_RIGHT(hs_trim)); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* Headset jack detection only if it is supported */ 1848c2ecf20Sopenharmony_ci if (priv->jack_detection) { 1858c2ecf20Sopenharmony_ci ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", 1868c2ecf20Sopenharmony_ci SND_JACK_HEADSET, &hs_jack, 1878c2ecf20Sopenharmony_ci hs_jack_pins, 1888c2ecf20Sopenharmony_ci ARRAY_SIZE(hs_jack_pins)); 1898c2ecf20Sopenharmony_ci if (ret) 1908c2ecf20Sopenharmony_ci return ret; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci twl6040_hs_jack_detect(component, &hs_jack, SND_JACK_HEADSET); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route dmic_audio_map[] = { 1998c2ecf20Sopenharmony_ci {"DMic", NULL, "Digital Mic"}, 2008c2ecf20Sopenharmony_ci {"Digital Mic", NULL, "Digital Mic1 Bias"}, 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = &rtd->card->dapm; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci return snd_soc_dapm_add_routes(dapm, dmic_audio_map, 2088c2ecf20Sopenharmony_ci ARRAY_SIZE(dmic_audio_map)); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int omap_abe_probe(struct platform_device *pdev) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 2148c2ecf20Sopenharmony_ci struct snd_soc_card *card; 2158c2ecf20Sopenharmony_ci struct device_node *dai_node; 2168c2ecf20Sopenharmony_ci struct abe_twl6040 *priv; 2178c2ecf20Sopenharmony_ci int num_links = 0; 2188c2ecf20Sopenharmony_ci int ret = 0; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (!node) { 2218c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "of node is missing.\n"); 2228c2ecf20Sopenharmony_ci return -ENODEV; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); 2268c2ecf20Sopenharmony_ci if (priv == NULL) 2278c2ecf20Sopenharmony_ci return -ENOMEM; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci card = &priv->card; 2308c2ecf20Sopenharmony_ci card->dev = &pdev->dev; 2318c2ecf20Sopenharmony_ci card->owner = THIS_MODULE; 2328c2ecf20Sopenharmony_ci card->dapm_widgets = twl6040_dapm_widgets; 2338c2ecf20Sopenharmony_ci card->num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets); 2348c2ecf20Sopenharmony_ci card->dapm_routes = audio_map; 2358c2ecf20Sopenharmony_ci card->num_dapm_routes = ARRAY_SIZE(audio_map); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (snd_soc_of_parse_card_name(card, "ti,model")) { 2388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Card name is not provided\n"); 2398c2ecf20Sopenharmony_ci return -ENODEV; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing"); 2438c2ecf20Sopenharmony_ci if (ret) { 2448c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error while parsing DAPM routing\n"); 2458c2ecf20Sopenharmony_ci return ret; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci dai_node = of_parse_phandle(node, "ti,mcpdm", 0); 2498c2ecf20Sopenharmony_ci if (!dai_node) { 2508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "McPDM node is not provided\n"); 2518c2ecf20Sopenharmony_ci return -EINVAL; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci priv->dai_links[0].name = "DMIC"; 2558c2ecf20Sopenharmony_ci priv->dai_links[0].stream_name = "TWL6040"; 2568c2ecf20Sopenharmony_ci priv->dai_links[0].cpus = link0_cpus; 2578c2ecf20Sopenharmony_ci priv->dai_links[0].num_cpus = 1; 2588c2ecf20Sopenharmony_ci priv->dai_links[0].cpus->of_node = dai_node; 2598c2ecf20Sopenharmony_ci priv->dai_links[0].platforms = link0_platforms; 2608c2ecf20Sopenharmony_ci priv->dai_links[0].num_platforms = 1; 2618c2ecf20Sopenharmony_ci priv->dai_links[0].platforms->of_node = dai_node; 2628c2ecf20Sopenharmony_ci priv->dai_links[0].codecs = link0_codecs; 2638c2ecf20Sopenharmony_ci priv->dai_links[0].num_codecs = 1; 2648c2ecf20Sopenharmony_ci priv->dai_links[0].init = omap_abe_twl6040_init; 2658c2ecf20Sopenharmony_ci priv->dai_links[0].ops = &omap_abe_ops; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci dai_node = of_parse_phandle(node, "ti,dmic", 0); 2688c2ecf20Sopenharmony_ci if (dai_node) { 2698c2ecf20Sopenharmony_ci num_links = 2; 2708c2ecf20Sopenharmony_ci priv->dai_links[1].name = "TWL6040"; 2718c2ecf20Sopenharmony_ci priv->dai_links[1].stream_name = "DMIC Capture"; 2728c2ecf20Sopenharmony_ci priv->dai_links[1].cpus = link1_cpus; 2738c2ecf20Sopenharmony_ci priv->dai_links[1].num_cpus = 1; 2748c2ecf20Sopenharmony_ci priv->dai_links[1].cpus->of_node = dai_node; 2758c2ecf20Sopenharmony_ci priv->dai_links[1].platforms = link1_platforms; 2768c2ecf20Sopenharmony_ci priv->dai_links[1].num_platforms = 1; 2778c2ecf20Sopenharmony_ci priv->dai_links[1].platforms->of_node = dai_node; 2788c2ecf20Sopenharmony_ci priv->dai_links[1].codecs = link1_codecs; 2798c2ecf20Sopenharmony_ci priv->dai_links[1].num_codecs = 1; 2808c2ecf20Sopenharmony_ci priv->dai_links[1].init = omap_abe_dmic_init; 2818c2ecf20Sopenharmony_ci priv->dai_links[1].ops = &omap_abe_dmic_ops; 2828c2ecf20Sopenharmony_ci } else { 2838c2ecf20Sopenharmony_ci num_links = 1; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci priv->jack_detection = of_property_read_bool(node, "ti,jack-detection"); 2878c2ecf20Sopenharmony_ci of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq); 2888c2ecf20Sopenharmony_ci if (!priv->mclk_freq) { 2898c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "MCLK frequency not provided\n"); 2908c2ecf20Sopenharmony_ci return -EINVAL; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci card->fully_routed = 1; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (!priv->mclk_freq) { 2968c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "MCLK frequency missing\n"); 2978c2ecf20Sopenharmony_ci return -ENODEV; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci card->dai_link = priv->dai_links; 3018c2ecf20Sopenharmony_ci card->num_links = num_links; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci snd_soc_card_set_drvdata(card, priv); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_card(&pdev->dev, card); 3068c2ecf20Sopenharmony_ci if (ret) 3078c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", 3088c2ecf20Sopenharmony_ci ret); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return ret; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic const struct of_device_id omap_abe_of_match[] = { 3148c2ecf20Sopenharmony_ci {.compatible = "ti,abe-twl6040", }, 3158c2ecf20Sopenharmony_ci { }, 3168c2ecf20Sopenharmony_ci}; 3178c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_abe_of_match); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic struct platform_driver omap_abe_driver = { 3208c2ecf20Sopenharmony_ci .driver = { 3218c2ecf20Sopenharmony_ci .name = "omap-abe-twl6040", 3228c2ecf20Sopenharmony_ci .pm = &snd_soc_pm_ops, 3238c2ecf20Sopenharmony_ci .of_match_table = omap_abe_of_match, 3248c2ecf20Sopenharmony_ci }, 3258c2ecf20Sopenharmony_ci .probe = omap_abe_probe, 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic int __init omap_abe_init(void) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci int ret; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL, 3338c2ecf20Sopenharmony_ci 0); 3348c2ecf20Sopenharmony_ci if (IS_ERR(dmic_codec_dev)) { 3358c2ecf20Sopenharmony_ci pr_err("%s: dmic-codec device registration failed\n", __func__); 3368c2ecf20Sopenharmony_ci return PTR_ERR(dmic_codec_dev); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci ret = platform_driver_register(&omap_abe_driver); 3408c2ecf20Sopenharmony_ci if (ret) { 3418c2ecf20Sopenharmony_ci pr_err("%s: platform driver registration failed\n", __func__); 3428c2ecf20Sopenharmony_ci platform_device_unregister(dmic_codec_dev); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return ret; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_cimodule_init(omap_abe_init); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void __exit omap_abe_exit(void) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci platform_driver_unregister(&omap_abe_driver); 3528c2ecf20Sopenharmony_ci platform_device_unregister(dmic_codec_dev); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_cimodule_exit(omap_abe_exit); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ciMODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); 3578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec"); 3588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3598c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:omap-abe-twl6040"); 360