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

TOMOYO Linux Cross Reference
Linux/sound/soc/pxa/zylonite.c

Version: ~ [ linux-5.15-rc7 ] ~ [ linux-5.14.14 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.75 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.155 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.213 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.252 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.287 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.289 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ 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.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * zylonite.c  --  SoC audio for Zylonite
  4  *
  5  * Copyright 2008 Wolfson Microelectronics PLC.
  6  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  7  */
  8 
  9 #include <linux/module.h>
 10 #include <linux/moduleparam.h>
 11 #include <linux/device.h>
 12 #include <linux/clk.h>
 13 #include <linux/i2c.h>
 14 #include <sound/core.h>
 15 #include <sound/pcm.h>
 16 #include <sound/pcm_params.h>
 17 #include <sound/soc.h>
 18 
 19 #include "../codecs/wm9713.h"
 20 #include "pxa-ssp.h"
 21 
 22 /*
 23  * There is a physical switch SW15 on the board which changes the MCLK
 24  * for the WM9713 between the standard AC97 master clock and the
 25  * output of the CLK_POUT signal from the PXA.
 26  */
 27 static int clk_pout;
 28 module_param(clk_pout, int, 0);
 29 MODULE_PARM_DESC(clk_pout, "Use CLK_POUT as WM9713 MCLK (SW15 on board).");
 30 
 31 static struct clk *pout;
 32 
 33 static struct snd_soc_card zylonite;
 34 
 35 static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = {
 36         SND_SOC_DAPM_HP("Headphone", NULL),
 37         SND_SOC_DAPM_MIC("Headset Microphone", NULL),
 38         SND_SOC_DAPM_MIC("Handset Microphone", NULL),
 39         SND_SOC_DAPM_SPK("Multiactor", NULL),
 40         SND_SOC_DAPM_SPK("Headset Earpiece", NULL),
 41 };
 42 
 43 /* Currently supported audio map */
 44 static const struct snd_soc_dapm_route audio_map[] = {
 45 
 46         /* Headphone output connected to HPL/HPR */
 47         { "Headphone", NULL,  "HPL" },
 48         { "Headphone", NULL,  "HPR" },
 49 
 50         /* On-board earpiece */
 51         { "Headset Earpiece", NULL, "OUT3" },
 52 
 53         /* Headphone mic */
 54         { "MIC2A", NULL, "Mic Bias" },
 55         { "Mic Bias", NULL, "Headset Microphone" },
 56 
 57         /* On-board mic */
 58         { "MIC1", NULL, "Mic Bias" },
 59         { "Mic Bias", NULL, "Handset Microphone" },
 60 
 61         /* Multiactor differentially connected over SPKL/SPKR */
 62         { "Multiactor", NULL, "SPKL" },
 63         { "Multiactor", NULL, "SPKR" },
 64 };
 65 
 66 static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 67 {
 68         if (clk_pout)
 69                 snd_soc_dai_set_pll(rtd->codec_dai, 0, 0,
 70                                     clk_get_rate(pout), 0);
 71 
 72         return 0;
 73 }
 74 
 75 static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
 76                                     struct snd_pcm_hw_params *params)
 77 {
 78         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 79         struct snd_soc_dai *codec_dai = rtd->codec_dai;
 80         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 81         unsigned int wm9713_div = 0;
 82         int ret = 0;
 83         int rate = params_rate(params);
 84 
 85         /* Only support ratios that we can generate neatly from the AC97
 86          * based master clock - in particular, this excludes 44.1kHz.
 87          * In most applications the voice DAC will be used for telephony
 88          * data so multiples of 8kHz will be the common case.
 89          */
 90         switch (rate) {
 91         case 8000:
 92                 wm9713_div = 12;
 93                 break;
 94         case 16000:
 95                 wm9713_div = 6;
 96                 break;
 97         case 48000:
 98                 wm9713_div = 2;
 99                 break;
100         default:
101                 /* Don't support OSS emulation */
102                 return -EINVAL;
103         }
104 
105         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
106         if (ret < 0)
107                 return ret;
108 
109         if (clk_pout)
110                 ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV,
111                                              WM9713_PCMDIV(wm9713_div));
112         else
113                 ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV,
114                                              WM9713_PCMDIV(wm9713_div));
115         if (ret < 0)
116                 return ret;
117 
118         return 0;
119 }
120 
121 static const struct snd_soc_ops zylonite_voice_ops = {
122         .hw_params = zylonite_voice_hw_params,
123 };
124 
125 SND_SOC_DAILINK_DEFS(ac97,
126         DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
127         DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-hifi")),
128         DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
129 
130 SND_SOC_DAILINK_DEFS(ac97_aux,
131         DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
132         DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-aux")),
133         DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
134 
135 SND_SOC_DAILINK_DEFS(voice,
136         DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.2")),
137         DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-voice")),
138         DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
139 
140 static struct snd_soc_dai_link zylonite_dai[] = {
141 {
142         .name = "AC97",
143         .stream_name = "AC97 HiFi",
144         .init = zylonite_wm9713_init,
145         SND_SOC_DAILINK_REG(ac97),
146 },
147 {
148         .name = "AC97 Aux",
149         .stream_name = "AC97 Aux",
150         SND_SOC_DAILINK_REG(ac97_aux),
151 },
152 {
153         .name = "WM9713 Voice",
154         .stream_name = "WM9713 Voice",
155         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
156                    SND_SOC_DAIFMT_CBS_CFS,
157         .ops = &zylonite_voice_ops,
158         SND_SOC_DAILINK_REG(voice),
159 },
160 };
161 
162 static int zylonite_probe(struct snd_soc_card *card)
163 {
164         int ret;
165 
166         if (clk_pout) {
167                 pout = clk_get(NULL, "CLK_POUT");
168                 if (IS_ERR(pout)) {
169                         dev_err(card->dev, "Unable to obtain CLK_POUT: %ld\n",
170                                 PTR_ERR(pout));
171                         return PTR_ERR(pout);
172                 }
173 
174                 ret = clk_enable(pout);
175                 if (ret != 0) {
176                         dev_err(card->dev, "Unable to enable CLK_POUT: %d\n",
177                                 ret);
178                         clk_put(pout);
179                         return ret;
180                 }
181 
182                 dev_dbg(card->dev, "MCLK enabled at %luHz\n",
183                         clk_get_rate(pout));
184         }
185 
186         return 0;
187 }
188 
189 static int zylonite_remove(struct snd_soc_card *card)
190 {
191         if (clk_pout) {
192                 clk_disable(pout);
193                 clk_put(pout);
194         }
195 
196         return 0;
197 }
198 
199 static int zylonite_suspend_post(struct snd_soc_card *card)
200 {
201         if (clk_pout)
202                 clk_disable(pout);
203 
204         return 0;
205 }
206 
207 static int zylonite_resume_pre(struct snd_soc_card *card)
208 {
209         int ret = 0;
210 
211         if (clk_pout) {
212                 ret = clk_enable(pout);
213                 if (ret != 0)
214                         dev_err(card->dev, "Unable to enable CLK_POUT: %d\n",
215                                 ret);
216         }
217 
218         return ret;
219 }
220 
221 static struct snd_soc_card zylonite = {
222         .name = "Zylonite",
223         .owner = THIS_MODULE,
224         .probe = &zylonite_probe,
225         .remove = &zylonite_remove,
226         .suspend_post = &zylonite_suspend_post,
227         .resume_pre = &zylonite_resume_pre,
228         .dai_link = zylonite_dai,
229         .num_links = ARRAY_SIZE(zylonite_dai),
230 
231         .dapm_widgets = zylonite_dapm_widgets,
232         .num_dapm_widgets = ARRAY_SIZE(zylonite_dapm_widgets),
233         .dapm_routes = audio_map,
234         .num_dapm_routes = ARRAY_SIZE(audio_map),
235 };
236 
237 static struct platform_device *zylonite_snd_ac97_device;
238 
239 static int __init zylonite_init(void)
240 {
241         int ret;
242 
243         zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1);
244         if (!zylonite_snd_ac97_device)
245                 return -ENOMEM;
246 
247         platform_set_drvdata(zylonite_snd_ac97_device, &zylonite);
248 
249         ret = platform_device_add(zylonite_snd_ac97_device);
250         if (ret != 0)
251                 platform_device_put(zylonite_snd_ac97_device);
252 
253         return ret;
254 }
255 
256 static void __exit zylonite_exit(void)
257 {
258         platform_device_unregister(zylonite_snd_ac97_device);
259 }
260 
261 module_init(zylonite_init);
262 module_exit(zylonite_exit);
263 
264 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
265 MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite");
266 MODULE_LICENSE("GPL");
267 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp