~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/samsung/arndale.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0+
  2 //
  3 // Copyright (c) 2014, Insignal Co., Ltd.
  4 //
  5 //  Author: Claude <claude@insginal.co.kr>
  6 
  7 #include <linux/module.h>
  8 #include <linux/of.h>
  9 #include <linux/platform_device.h>
 10 #include <linux/clk.h>
 11 
 12 #include <sound/soc.h>
 13 #include <sound/soc-dapm.h>
 14 #include <sound/pcm.h>
 15 #include <sound/pcm_params.h>
 16 
 17 #include "../codecs/wm8994.h"
 18 #include "i2s.h"
 19 
 20 static int arndale_rt5631_hw_params(struct snd_pcm_substream *substream,
 21                                     struct snd_pcm_hw_params *params)
 22 {
 23         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 24         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
 25         struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
 26         int rfs, ret;
 27         unsigned long rclk;
 28 
 29         rfs = 256;
 30 
 31         rclk = params_rate(params) * rfs;
 32 
 33         ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
 34                                         0, SND_SOC_CLOCK_OUT);
 35         if (ret < 0)
 36                 return ret;
 37 
 38         ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
 39                                         0, SND_SOC_CLOCK_OUT);
 40 
 41         if (ret < 0)
 42                 return ret;
 43 
 44         ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT);
 45         if (ret < 0)
 46                 return ret;
 47 
 48         return 0;
 49 }
 50 
 51 static const struct snd_soc_ops arndale_rt5631_ops = {
 52         .hw_params = arndale_rt5631_hw_params,
 53 };
 54 
 55 static int arndale_wm1811_hw_params(struct snd_pcm_substream *substream,
 56                                     struct snd_pcm_hw_params *params)
 57 {
 58         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 59         struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
 60         unsigned int rfs, rclk;
 61 
 62         /* Ensure AIF1CLK is >= 3 MHz for optimal performance */
 63         if (params_width(params) == 24)
 64                 rfs = 384;
 65         else if (params_rate(params) == 8000 || params_rate(params) == 11025)
 66                 rfs = 512;
 67         else
 68                 rfs = 256;
 69 
 70         rclk = params_rate(params) * rfs;
 71 
 72         /*
 73          * We add 1 to the frequency value to ensure proper EPLL setting
 74          * for each audio sampling rate (see epll_24mhz_tbl in drivers/clk/
 75          * samsung/clk-exynos5250.c for list of available EPLL rates).
 76          * The CODEC uses clk API and the value will be rounded hence the MCLK1
 77          * clock's frequency will still be exact multiple of the sample rate.
 78          */
 79         return snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1,
 80                                         rclk + 1, SND_SOC_CLOCK_IN);
 81 }
 82 
 83 static const struct snd_soc_ops arndale_wm1811_ops = {
 84         .hw_params = arndale_wm1811_hw_params,
 85 };
 86 
 87 SND_SOC_DAILINK_DEFS(rt5631_hifi,
 88         DAILINK_COMP_ARRAY(COMP_EMPTY()),
 89         DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-aif1")),
 90         DAILINK_COMP_ARRAY(COMP_EMPTY()));
 91 
 92 static struct snd_soc_dai_link arndale_rt5631_dai[] = {
 93         {
 94                 .name = "RT5631 HiFi",
 95                 .stream_name = "Primary",
 96                 .dai_fmt = SND_SOC_DAIFMT_I2S
 97                         | SND_SOC_DAIFMT_NB_NF
 98                         | SND_SOC_DAIFMT_CBS_CFS,
 99                 .ops = &arndale_rt5631_ops,
100                 SND_SOC_DAILINK_REG(rt5631_hifi),
101         },
102 };
103 
104 SND_SOC_DAILINK_DEFS(wm1811_hifi,
105         DAILINK_COMP_ARRAY(COMP_EMPTY()),
106         DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")),
107         DAILINK_COMP_ARRAY(COMP_EMPTY()));
108 
109 static struct snd_soc_dai_link arndale_wm1811_dai[] = {
110         {
111                 .name = "WM1811 HiFi",
112                 .stream_name = "Primary",
113                 .dai_fmt = SND_SOC_DAIFMT_I2S
114                         | SND_SOC_DAIFMT_NB_NF
115                         | SND_SOC_DAIFMT_CBM_CFM,
116                 .ops = &arndale_wm1811_ops,
117                 SND_SOC_DAILINK_REG(wm1811_hifi),
118         },
119 };
120 
121 static struct snd_soc_card arndale_rt5631 = {
122         .name = "Arndale RT5631",
123         .owner = THIS_MODULE,
124         .dai_link = arndale_rt5631_dai,
125         .num_links = ARRAY_SIZE(arndale_rt5631_dai),
126 };
127 
128 static struct snd_soc_card arndale_wm1811 = {
129         .name = "Arndale WM1811",
130         .owner = THIS_MODULE,
131         .dai_link = arndale_wm1811_dai,
132         .num_links = ARRAY_SIZE(arndale_wm1811_dai),
133 };
134 
135 static void arndale_put_of_nodes(struct snd_soc_card *card)
136 {
137         struct snd_soc_dai_link *dai_link;
138         int i;
139 
140         for_each_card_prelinks(card, i, dai_link) {
141                 of_node_put(dai_link->cpus->of_node);
142                 of_node_put(dai_link->codecs->of_node);
143         }
144 }
145 
146 static int arndale_audio_probe(struct platform_device *pdev)
147 {
148         struct device_node *np = pdev->dev.of_node;
149         struct snd_soc_card *card;
150         struct snd_soc_dai_link *dai_link;
151         int ret;
152 
153         card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev);
154         card->dev = &pdev->dev;
155         dai_link = card->dai_link;
156 
157         dai_link->cpus->of_node = of_parse_phandle(np, "samsung,audio-cpu", 0);
158         if (!dai_link->cpus->of_node) {
159                 dev_err(&pdev->dev,
160                         "Property 'samsung,audio-cpu' missing or invalid\n");
161                 return -EINVAL;
162         }
163 
164         if (!dai_link->platforms->name)
165                 dai_link->platforms->of_node = dai_link->cpus->of_node;
166 
167         dai_link->codecs->of_node = of_parse_phandle(np, "samsung,audio-codec", 0);
168         if (!dai_link->codecs->of_node) {
169                 dev_err(&pdev->dev,
170                         "Property 'samsung,audio-codec' missing or invalid\n");
171                 ret = -EINVAL;
172                 goto err_put_of_nodes;
173         }
174 
175         ret = devm_snd_soc_register_card(card->dev, card);
176         if (ret) {
177                 dev_err_probe(&pdev->dev, ret,
178                               "snd_soc_register_card() failed\n");
179                 goto err_put_of_nodes;
180         }
181         return 0;
182 
183 err_put_of_nodes:
184         arndale_put_of_nodes(card);
185         return ret;
186 }
187 
188 static void arndale_audio_remove(struct platform_device *pdev)
189 {
190         struct snd_soc_card *card = platform_get_drvdata(pdev);
191 
192         arndale_put_of_nodes(card);
193 }
194 
195 static const struct of_device_id arndale_audio_of_match[] = {
196         { .compatible = "samsung,arndale-rt5631",  .data = &arndale_rt5631 },
197         { .compatible = "samsung,arndale-alc5631", .data = &arndale_rt5631 },
198         { .compatible = "samsung,arndale-wm1811",  .data = &arndale_wm1811 },
199         {},
200 };
201 MODULE_DEVICE_TABLE(of, arndale_audio_of_match);
202 
203 static struct platform_driver arndale_audio_driver = {
204         .driver = {
205                 .name = "arndale-audio",
206                 .pm = &snd_soc_pm_ops,
207                 .of_match_table = arndale_audio_of_match,
208         },
209         .probe = arndale_audio_probe,
210         .remove_new = arndale_audio_remove,
211 };
212 
213 module_platform_driver(arndale_audio_driver);
214 
215 MODULE_AUTHOR("Claude <claude@insignal.co.kr>");
216 MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board");
217 MODULE_LICENSE("GPL");
218 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php