1aba611fcSSylwester Nawrocki /* 2aba611fcSSylwester Nawrocki * Copyright (C) 2017 Samsung Electronics Co., Ltd. 3aba611fcSSylwester Nawrocki * 4aba611fcSSylwester Nawrocki * This program is free software; you can redistribute it and/or modify 5aba611fcSSylwester Nawrocki * it under the terms of the GNU General Public License version 2 as 6aba611fcSSylwester Nawrocki * published by the Free Software Foundation. 7aba611fcSSylwester Nawrocki */ 8aba611fcSSylwester Nawrocki 9aba611fcSSylwester Nawrocki #include <linux/clk.h> 10bc3cf17bSSylwester Nawrocki #include <linux/clk-provider.h> 11aba611fcSSylwester Nawrocki #include <linux/of.h> 12aba611fcSSylwester Nawrocki #include <linux/of_device.h> 13aba611fcSSylwester Nawrocki #include <linux/module.h> 14aba611fcSSylwester Nawrocki #include <sound/soc.h> 15aba611fcSSylwester Nawrocki #include <sound/pcm_params.h> 16aba611fcSSylwester Nawrocki #include "i2s.h" 17aba611fcSSylwester Nawrocki #include "i2s-regs.h" 18aba611fcSSylwester Nawrocki 19aba611fcSSylwester Nawrocki struct odroid_priv { 20aba611fcSSylwester Nawrocki struct snd_soc_card card; 21a8ad0c85SSylwester Nawrocki struct clk *clk_i2s_bus; 22a8ad0c85SSylwester Nawrocki struct clk *sclk_i2s; 23b5c16a24SSylwester Nawrocki 24b5c16a24SSylwester Nawrocki /* Spinlock protecting fields below */ 25b5c16a24SSylwester Nawrocki spinlock_t lock; 26b5c16a24SSylwester Nawrocki unsigned int be_sample_rate; 27b5c16a24SSylwester Nawrocki bool be_active; 28aba611fcSSylwester Nawrocki }; 29aba611fcSSylwester Nawrocki 30bc3cf17bSSylwester Nawrocki static int odroid_card_fe_startup(struct snd_pcm_substream *substream) 31aba611fcSSylwester Nawrocki { 32aba611fcSSylwester Nawrocki struct snd_pcm_runtime *runtime = substream->runtime; 33aba611fcSSylwester Nawrocki 34aba611fcSSylwester Nawrocki snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); 35bc3cf17bSSylwester Nawrocki 36aba611fcSSylwester Nawrocki return 0; 37aba611fcSSylwester Nawrocki } 38aba611fcSSylwester Nawrocki 39b5c16a24SSylwester Nawrocki static int odroid_card_fe_hw_params(struct snd_pcm_substream *substream, 40b5c16a24SSylwester Nawrocki struct snd_pcm_hw_params *params) 41b5c16a24SSylwester Nawrocki { 42b5c16a24SSylwester Nawrocki struct snd_soc_pcm_runtime *rtd = substream->private_data; 43b5c16a24SSylwester Nawrocki struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); 44b5c16a24SSylwester Nawrocki unsigned long flags; 45b5c16a24SSylwester Nawrocki int ret = 0; 46b5c16a24SSylwester Nawrocki 47b5c16a24SSylwester Nawrocki spin_lock_irqsave(&priv->lock, flags); 48b5c16a24SSylwester Nawrocki if (priv->be_active && priv->be_sample_rate != params_rate(params)) 49b5c16a24SSylwester Nawrocki ret = -EINVAL; 50b5c16a24SSylwester Nawrocki spin_unlock_irqrestore(&priv->lock, flags); 51b5c16a24SSylwester Nawrocki 52b5c16a24SSylwester Nawrocki return ret; 53b5c16a24SSylwester Nawrocki } 54b5c16a24SSylwester Nawrocki 55bc3cf17bSSylwester Nawrocki static const struct snd_soc_ops odroid_card_fe_ops = { 56bc3cf17bSSylwester Nawrocki .startup = odroid_card_fe_startup, 57b5c16a24SSylwester Nawrocki .hw_params = odroid_card_fe_hw_params, 58bc3cf17bSSylwester Nawrocki }; 59bc3cf17bSSylwester Nawrocki 60bc3cf17bSSylwester Nawrocki static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, 61aba611fcSSylwester Nawrocki struct snd_pcm_hw_params *params) 62aba611fcSSylwester Nawrocki { 63aba611fcSSylwester Nawrocki struct snd_soc_pcm_runtime *rtd = substream->private_data; 64aba611fcSSylwester Nawrocki struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); 651d22c337SSylwester Nawrocki unsigned int pll_freq, rclk_freq, rfs; 66b5c16a24SSylwester Nawrocki unsigned long flags; 67aba611fcSSylwester Nawrocki int ret; 68aba611fcSSylwester Nawrocki 69aba611fcSSylwester Nawrocki switch (params_rate(params)) { 70aba611fcSSylwester Nawrocki case 64000: 711d22c337SSylwester Nawrocki pll_freq = 196608001U; 721d22c337SSylwester Nawrocki rfs = 384; 73aba611fcSSylwester Nawrocki break; 74aba611fcSSylwester Nawrocki case 44100: 75aba611fcSSylwester Nawrocki case 88200: 769d154e42SSylwester Nawrocki pll_freq = 180633609U; 771d22c337SSylwester Nawrocki rfs = 512; 78aba611fcSSylwester Nawrocki break; 791d22c337SSylwester Nawrocki case 32000: 80aba611fcSSylwester Nawrocki case 48000: 81aba611fcSSylwester Nawrocki case 96000: 829d154e42SSylwester Nawrocki pll_freq = 196608001U; 831d22c337SSylwester Nawrocki rfs = 512; 84aba611fcSSylwester Nawrocki break; 85aba611fcSSylwester Nawrocki default: 86aba611fcSSylwester Nawrocki return -EINVAL; 87aba611fcSSylwester Nawrocki } 88aba611fcSSylwester Nawrocki 89a8ad0c85SSylwester Nawrocki ret = clk_set_rate(priv->clk_i2s_bus, pll_freq / 2 + 1); 90aba611fcSSylwester Nawrocki if (ret < 0) 91aba611fcSSylwester Nawrocki return ret; 92aba611fcSSylwester Nawrocki 93a8ad0c85SSylwester Nawrocki /* 94a8ad0c85SSylwester Nawrocki * We add 1 to the rclk_freq value in order to avoid too low clock 95a8ad0c85SSylwester Nawrocki * frequency values due to the EPLL output frequency not being exact 96a8ad0c85SSylwester Nawrocki * multiple of the audio sampling rate. 97a8ad0c85SSylwester Nawrocki */ 981d22c337SSylwester Nawrocki rclk_freq = params_rate(params) * rfs + 1; 99aba611fcSSylwester Nawrocki 100a8ad0c85SSylwester Nawrocki ret = clk_set_rate(priv->sclk_i2s, rclk_freq); 101aba611fcSSylwester Nawrocki if (ret < 0) 102aba611fcSSylwester Nawrocki return ret; 103aba611fcSSylwester Nawrocki 104aba611fcSSylwester Nawrocki if (rtd->num_codecs > 1) { 105aba611fcSSylwester Nawrocki struct snd_soc_dai *codec_dai = rtd->codec_dais[1]; 106aba611fcSSylwester Nawrocki 107aba611fcSSylwester Nawrocki ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk_freq, 108aba611fcSSylwester Nawrocki SND_SOC_CLOCK_IN); 109aba611fcSSylwester Nawrocki if (ret < 0) 110aba611fcSSylwester Nawrocki return ret; 111aba611fcSSylwester Nawrocki } 112aba611fcSSylwester Nawrocki 113b5c16a24SSylwester Nawrocki spin_lock_irqsave(&priv->lock, flags); 114b5c16a24SSylwester Nawrocki priv->be_sample_rate = params_rate(params); 115b5c16a24SSylwester Nawrocki spin_unlock_irqrestore(&priv->lock, flags); 116b5c16a24SSylwester Nawrocki 117b5c16a24SSylwester Nawrocki return 0; 118b5c16a24SSylwester Nawrocki } 119b5c16a24SSylwester Nawrocki 120b5c16a24SSylwester Nawrocki static int odroid_card_be_trigger(struct snd_pcm_substream *substream, int cmd) 121b5c16a24SSylwester Nawrocki { 122b5c16a24SSylwester Nawrocki struct snd_soc_pcm_runtime *rtd = substream->private_data; 123b5c16a24SSylwester Nawrocki struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); 124b5c16a24SSylwester Nawrocki unsigned long flags; 125b5c16a24SSylwester Nawrocki 126b5c16a24SSylwester Nawrocki spin_lock_irqsave(&priv->lock, flags); 127b5c16a24SSylwester Nawrocki 128b5c16a24SSylwester Nawrocki switch (cmd) { 129b5c16a24SSylwester Nawrocki case SNDRV_PCM_TRIGGER_START: 130b5c16a24SSylwester Nawrocki case SNDRV_PCM_TRIGGER_RESUME: 131b5c16a24SSylwester Nawrocki case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 132b5c16a24SSylwester Nawrocki priv->be_active = true; 133b5c16a24SSylwester Nawrocki break; 134b5c16a24SSylwester Nawrocki 135b5c16a24SSylwester Nawrocki case SNDRV_PCM_TRIGGER_STOP: 136b5c16a24SSylwester Nawrocki case SNDRV_PCM_TRIGGER_SUSPEND: 137b5c16a24SSylwester Nawrocki case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 138b5c16a24SSylwester Nawrocki priv->be_active = false; 139b5c16a24SSylwester Nawrocki break; 140b5c16a24SSylwester Nawrocki } 141b5c16a24SSylwester Nawrocki 142b5c16a24SSylwester Nawrocki spin_unlock_irqrestore(&priv->lock, flags); 143b5c16a24SSylwester Nawrocki 144aba611fcSSylwester Nawrocki return 0; 145aba611fcSSylwester Nawrocki } 146aba611fcSSylwester Nawrocki 147bc3cf17bSSylwester Nawrocki static const struct snd_soc_ops odroid_card_be_ops = { 148bc3cf17bSSylwester Nawrocki .hw_params = odroid_card_be_hw_params, 149b5c16a24SSylwester Nawrocki .trigger = odroid_card_be_trigger, 150bc3cf17bSSylwester Nawrocki }; 151bc3cf17bSSylwester Nawrocki 152f89aea0fSSylwester Nawrocki /* DAPM routes for backward compatibility with old DTS */ 153f89aea0fSSylwester Nawrocki static const struct snd_soc_dapm_route odroid_dapm_routes[] = { 154f89aea0fSSylwester Nawrocki { "I2S Playback", NULL, "Mixer DAI TX" }, 155f89aea0fSSylwester Nawrocki { "HiFi Playback", NULL, "Mixer DAI TX" }, 156f89aea0fSSylwester Nawrocki }; 157f89aea0fSSylwester Nawrocki 158bc3cf17bSSylwester Nawrocki static struct snd_soc_dai_link odroid_card_dais[] = { 159bc3cf17bSSylwester Nawrocki { 160bc3cf17bSSylwester Nawrocki /* Primary FE <-> BE link */ 161bc3cf17bSSylwester Nawrocki .codec_name = "snd-soc-dummy", 162bc3cf17bSSylwester Nawrocki .codec_dai_name = "snd-soc-dummy-dai", 163bc3cf17bSSylwester Nawrocki .ops = &odroid_card_fe_ops, 164bc3cf17bSSylwester Nawrocki .name = "Primary", 165bc3cf17bSSylwester Nawrocki .stream_name = "Primary", 166bc3cf17bSSylwester Nawrocki .platform_name = "3830000.i2s", 167bc3cf17bSSylwester Nawrocki .dynamic = 1, 168bc3cf17bSSylwester Nawrocki .dpcm_playback = 1, 169bc3cf17bSSylwester Nawrocki }, { 170bc3cf17bSSylwester Nawrocki /* BE <-> CODECs link */ 171bc3cf17bSSylwester Nawrocki .name = "I2S Mixer", 172bc3cf17bSSylwester Nawrocki .cpu_name = "snd-soc-dummy", 173bc3cf17bSSylwester Nawrocki .cpu_dai_name = "snd-soc-dummy-dai", 174bc3cf17bSSylwester Nawrocki .platform_name = "snd-soc-dummy", 175bc3cf17bSSylwester Nawrocki .ops = &odroid_card_be_ops, 176bc3cf17bSSylwester Nawrocki .no_pcm = 1, 177bc3cf17bSSylwester Nawrocki .dpcm_playback = 1, 178bc3cf17bSSylwester Nawrocki .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 179bc3cf17bSSylwester Nawrocki SND_SOC_DAIFMT_CBS_CFS, 180bc3cf17bSSylwester Nawrocki }, { 181bc3cf17bSSylwester Nawrocki /* Secondary FE <-> BE link */ 182bc3cf17bSSylwester Nawrocki .playback_only = 1, 183bc3cf17bSSylwester Nawrocki .codec_name = "snd-soc-dummy", 184bc3cf17bSSylwester Nawrocki .codec_dai_name = "snd-soc-dummy-dai", 185bc3cf17bSSylwester Nawrocki .ops = &odroid_card_fe_ops, 186bc3cf17bSSylwester Nawrocki .name = "Secondary", 187bc3cf17bSSylwester Nawrocki .stream_name = "Secondary", 188c6bebefaSSylwester Nawrocki .platform_name = "3830000.i2s-sec", 189bc3cf17bSSylwester Nawrocki .dynamic = 1, 190bc3cf17bSSylwester Nawrocki .dpcm_playback = 1, 191bc3cf17bSSylwester Nawrocki } 192aba611fcSSylwester Nawrocki }; 193aba611fcSSylwester Nawrocki 194aba611fcSSylwester Nawrocki static int odroid_audio_probe(struct platform_device *pdev) 195aba611fcSSylwester Nawrocki { 196aba611fcSSylwester Nawrocki struct device *dev = &pdev->dev; 197bc3cf17bSSylwester Nawrocki struct device_node *cpu, *cpu_dai, *codec; 198aba611fcSSylwester Nawrocki struct odroid_priv *priv; 199aba611fcSSylwester Nawrocki struct snd_soc_card *card; 200bc3cf17bSSylwester Nawrocki struct snd_soc_dai_link *link, *codec_link; 201bc3cf17bSSylwester Nawrocki int num_pcms, ret, i; 202bc3cf17bSSylwester Nawrocki struct of_phandle_args args = {}; 203aba611fcSSylwester Nawrocki 204aba611fcSSylwester Nawrocki priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 205aba611fcSSylwester Nawrocki if (!priv) 206aba611fcSSylwester Nawrocki return -ENOMEM; 207aba611fcSSylwester Nawrocki 208aba611fcSSylwester Nawrocki card = &priv->card; 209aba611fcSSylwester Nawrocki card->dev = dev; 210aba611fcSSylwester Nawrocki 211aba611fcSSylwester Nawrocki card->owner = THIS_MODULE; 212aba611fcSSylwester Nawrocki card->fully_routed = true; 213aba611fcSSylwester Nawrocki 214b5c16a24SSylwester Nawrocki spin_lock_init(&priv->lock); 215aba611fcSSylwester Nawrocki snd_soc_card_set_drvdata(card, priv); 216aba611fcSSylwester Nawrocki 217aba611fcSSylwester Nawrocki ret = snd_soc_of_parse_card_name(card, "model"); 218aba611fcSSylwester Nawrocki if (ret < 0) 219aba611fcSSylwester Nawrocki return ret; 220aba611fcSSylwester Nawrocki 221aba611fcSSylwester Nawrocki if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) { 222aba611fcSSylwester Nawrocki ret = snd_soc_of_parse_audio_simple_widgets(card, 223aba611fcSSylwester Nawrocki "samsung,audio-widgets"); 224aba611fcSSylwester Nawrocki if (ret < 0) 225aba611fcSSylwester Nawrocki return ret; 226aba611fcSSylwester Nawrocki } 227aba611fcSSylwester Nawrocki 228aba611fcSSylwester Nawrocki if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) { 229aba611fcSSylwester Nawrocki ret = snd_soc_of_parse_audio_routing(card, 230aba611fcSSylwester Nawrocki "samsung,audio-routing"); 231aba611fcSSylwester Nawrocki if (ret < 0) 232aba611fcSSylwester Nawrocki return ret; 233aba611fcSSylwester Nawrocki } 234aba611fcSSylwester Nawrocki 235bc3cf17bSSylwester Nawrocki card->dai_link = odroid_card_dais; 236bc3cf17bSSylwester Nawrocki card->num_links = ARRAY_SIZE(odroid_card_dais); 237aba611fcSSylwester Nawrocki 238aba611fcSSylwester Nawrocki cpu = of_get_child_by_name(dev->of_node, "cpu"); 239aba611fcSSylwester Nawrocki codec = of_get_child_by_name(dev->of_node, "codec"); 240bc3cf17bSSylwester Nawrocki link = card->dai_link; 241bc3cf17bSSylwester Nawrocki codec_link = &card->dai_link[1]; 242aba611fcSSylwester Nawrocki 243bc3cf17bSSylwester Nawrocki /* 244bc3cf17bSSylwester Nawrocki * For backwards compatibility create the secondary CPU DAI link only 245bc3cf17bSSylwester Nawrocki * if there are 2 CPU DAI entries in the cpu sound-dai property in DT. 246f89aea0fSSylwester Nawrocki * Also add required DAPM routes not available in old DTS. 247bc3cf17bSSylwester Nawrocki */ 248bc3cf17bSSylwester Nawrocki num_pcms = of_count_phandle_with_args(cpu, "sound-dai", 249bc3cf17bSSylwester Nawrocki "#sound-dai-cells"); 250f89aea0fSSylwester Nawrocki if (num_pcms == 1) { 251f89aea0fSSylwester Nawrocki card->dapm_routes = odroid_dapm_routes; 252f89aea0fSSylwester Nawrocki card->num_dapm_routes = ARRAY_SIZE(odroid_dapm_routes); 253bc3cf17bSSylwester Nawrocki card->num_links--; 254f89aea0fSSylwester Nawrocki } 255bc3cf17bSSylwester Nawrocki 256bc3cf17bSSylwester Nawrocki for (i = 0; i < num_pcms; i++, link += 2) { 257bc3cf17bSSylwester Nawrocki ret = of_parse_phandle_with_args(cpu, "sound-dai", 258bc3cf17bSSylwester Nawrocki "#sound-dai-cells", i, &args); 259bc3cf17bSSylwester Nawrocki if (ret < 0) 260bc3cf17bSSylwester Nawrocki return ret; 261bc3cf17bSSylwester Nawrocki 262bc3cf17bSSylwester Nawrocki if (!args.np) { 263bc3cf17bSSylwester Nawrocki dev_err(dev, "sound-dai property parse error: %d\n", ret); 264aba611fcSSylwester Nawrocki return -EINVAL; 265aba611fcSSylwester Nawrocki } 266aba611fcSSylwester Nawrocki 267bc3cf17bSSylwester Nawrocki ret = snd_soc_get_dai_name(&args, &link->cpu_dai_name); 268bc3cf17bSSylwester Nawrocki of_node_put(args.np); 269bc3cf17bSSylwester Nawrocki 270bc3cf17bSSylwester Nawrocki if (ret < 0) 271bc3cf17bSSylwester Nawrocki return ret; 272bc3cf17bSSylwester Nawrocki } 273bc3cf17bSSylwester Nawrocki 274bc3cf17bSSylwester Nawrocki cpu_dai = of_parse_phandle(cpu, "sound-dai", 0); 275bc3cf17bSSylwester Nawrocki of_node_put(cpu); 276bc3cf17bSSylwester Nawrocki of_node_put(codec); 277bc3cf17bSSylwester Nawrocki 278bc3cf17bSSylwester Nawrocki ret = snd_soc_of_get_dai_link_codecs(dev, codec, codec_link); 279aba611fcSSylwester Nawrocki if (ret < 0) 280aba611fcSSylwester Nawrocki goto err_put_codec_n; 281aba611fcSSylwester Nawrocki 282bc3cf17bSSylwester Nawrocki /* Set capture capability only for boards with the MAX98090 CODEC */ 283bc3cf17bSSylwester Nawrocki if (codec_link->num_codecs > 1) { 284bc3cf17bSSylwester Nawrocki card->dai_link[0].dpcm_capture = 1; 285bc3cf17bSSylwester Nawrocki card->dai_link[1].dpcm_capture = 1; 286a8ad0c85SSylwester Nawrocki } 287a8ad0c85SSylwester Nawrocki 288bc3cf17bSSylwester Nawrocki priv->sclk_i2s = of_clk_get_by_name(cpu_dai, "i2s_opclk1"); 289bc3cf17bSSylwester Nawrocki if (IS_ERR(priv->sclk_i2s)) { 290bc3cf17bSSylwester Nawrocki ret = PTR_ERR(priv->sclk_i2s); 291bc3cf17bSSylwester Nawrocki goto err_put_codec_n; 292bc3cf17bSSylwester Nawrocki } 293bc3cf17bSSylwester Nawrocki 294bc3cf17bSSylwester Nawrocki priv->clk_i2s_bus = of_clk_get_by_name(cpu_dai, "iis"); 295a8ad0c85SSylwester Nawrocki if (IS_ERR(priv->clk_i2s_bus)) { 296a8ad0c85SSylwester Nawrocki ret = PTR_ERR(priv->clk_i2s_bus); 297a8ad0c85SSylwester Nawrocki goto err_put_sclk; 298a8ad0c85SSylwester Nawrocki } 299bc3cf17bSSylwester Nawrocki of_node_put(cpu_dai); 300a8ad0c85SSylwester Nawrocki 301aba611fcSSylwester Nawrocki ret = devm_snd_soc_register_card(dev, card); 302aba611fcSSylwester Nawrocki if (ret < 0) { 303aba611fcSSylwester Nawrocki dev_err(dev, "snd_soc_register_card() failed: %d\n", ret); 304a8ad0c85SSylwester Nawrocki goto err_put_clk_i2s; 305aba611fcSSylwester Nawrocki } 306aba611fcSSylwester Nawrocki 307aba611fcSSylwester Nawrocki return 0; 308aba611fcSSylwester Nawrocki 309a8ad0c85SSylwester Nawrocki err_put_clk_i2s: 310a8ad0c85SSylwester Nawrocki clk_put(priv->clk_i2s_bus); 311a8ad0c85SSylwester Nawrocki err_put_sclk: 312a8ad0c85SSylwester Nawrocki clk_put(priv->sclk_i2s); 313aba611fcSSylwester Nawrocki err_put_codec_n: 314bc3cf17bSSylwester Nawrocki snd_soc_of_put_dai_link_codecs(codec_link); 315aba611fcSSylwester Nawrocki return ret; 316aba611fcSSylwester Nawrocki } 317aba611fcSSylwester Nawrocki 318aba611fcSSylwester Nawrocki static int odroid_audio_remove(struct platform_device *pdev) 319aba611fcSSylwester Nawrocki { 320aba611fcSSylwester Nawrocki struct odroid_priv *priv = platform_get_drvdata(pdev); 321aba611fcSSylwester Nawrocki 322bc3cf17bSSylwester Nawrocki snd_soc_of_put_dai_link_codecs(&priv->card.dai_link[1]); 323a8ad0c85SSylwester Nawrocki clk_put(priv->sclk_i2s); 324a8ad0c85SSylwester Nawrocki clk_put(priv->clk_i2s_bus); 325aba611fcSSylwester Nawrocki 326aba611fcSSylwester Nawrocki return 0; 327aba611fcSSylwester Nawrocki } 328aba611fcSSylwester Nawrocki 329aba611fcSSylwester Nawrocki static const struct of_device_id odroid_audio_of_match[] = { 330d9e57512SSylwester Nawrocki { .compatible = "hardkernel,odroid-xu3-audio" }, 331d9e57512SSylwester Nawrocki { .compatible = "hardkernel,odroid-xu4-audio" }, 332aba611fcSSylwester Nawrocki { .compatible = "samsung,odroid-xu3-audio" }, 333aba611fcSSylwester Nawrocki { .compatible = "samsung,odroid-xu4-audio" }, 334aba611fcSSylwester Nawrocki { }, 335aba611fcSSylwester Nawrocki }; 336aba611fcSSylwester Nawrocki MODULE_DEVICE_TABLE(of, odroid_audio_of_match); 337aba611fcSSylwester Nawrocki 338aba611fcSSylwester Nawrocki static struct platform_driver odroid_audio_driver = { 339aba611fcSSylwester Nawrocki .driver = { 340aba611fcSSylwester Nawrocki .name = "odroid-audio", 341aba611fcSSylwester Nawrocki .of_match_table = odroid_audio_of_match, 342aba611fcSSylwester Nawrocki .pm = &snd_soc_pm_ops, 343aba611fcSSylwester Nawrocki }, 344aba611fcSSylwester Nawrocki .probe = odroid_audio_probe, 345aba611fcSSylwester Nawrocki .remove = odroid_audio_remove, 346aba611fcSSylwester Nawrocki }; 347aba611fcSSylwester Nawrocki module_platform_driver(odroid_audio_driver); 348aba611fcSSylwester Nawrocki 349aba611fcSSylwester Nawrocki MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); 350aba611fcSSylwester Nawrocki MODULE_DESCRIPTION("Odroid XU3/XU4 audio support"); 351aba611fcSSylwester Nawrocki MODULE_LICENSE("GPL v2"); 352