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

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

Version: ~ [ linux-5.14-rc1 ] ~ [ linux-5.13.1 ] ~ [ linux-5.12.16 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.49 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.131 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.197 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.239 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.275 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.275 ] ~ [ 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 /*
  2  * raumfeld_audio.c  --  SoC audio for Raumfeld audio devices
  3  *
  4  * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
  5  *
  6  * based on code from:
  7  *
  8  *    Wolfson Microelectronics PLC.
  9  *    Openedhand Ltd.
 10  *    Liam Girdwood <lrg@slimlogic.co.uk>
 11  *    Richard Purdie <richard@openedhand.com>
 12  *
 13  * This program is free software; you can redistribute  it and/or modify it
 14  * under  the terms of  the GNU General  Public License as published by the
 15  * Free Software Foundation;  either version 2 of the  License, or (at your
 16  * option) any later version.
 17  */
 18 
 19 #include <linux/module.h>
 20 #include <linux/i2c.h>
 21 #include <linux/delay.h>
 22 #include <linux/gpio.h>
 23 #include <sound/pcm.h>
 24 #include <sound/soc.h>
 25 
 26 #include <asm/mach-types.h>
 27 
 28 #include "pxa-ssp.h"
 29 
 30 #define GPIO_SPDIF_RESET        (38)
 31 #define GPIO_MCLK_RESET         (111)
 32 #define GPIO_CODEC_RESET        (120)
 33 
 34 static struct i2c_client *max9486_client;
 35 static struct i2c_board_info max9486_hwmon_info = {
 36         I2C_BOARD_INFO("max9485", 0x63),
 37 };
 38 
 39 #define MAX9485_MCLK_FREQ_112896 0x22
 40 #define MAX9485_MCLK_FREQ_122880 0x23
 41 #define MAX9485_MCLK_FREQ_225792 0x32
 42 #define MAX9485_MCLK_FREQ_245760 0x33
 43 
 44 static void set_max9485_clk(char clk)
 45 {
 46         i2c_master_send(max9486_client, &clk, 1);
 47 }
 48 
 49 static void raumfeld_enable_audio(bool en)
 50 {
 51         if (en) {
 52                 gpio_set_value(GPIO_MCLK_RESET, 1);
 53 
 54                 /* wait some time to let the clocks become stable */
 55                 msleep(100);
 56 
 57                 gpio_set_value(GPIO_SPDIF_RESET, 1);
 58                 gpio_set_value(GPIO_CODEC_RESET, 1);
 59         } else {
 60                 gpio_set_value(GPIO_MCLK_RESET, 0);
 61                 gpio_set_value(GPIO_SPDIF_RESET, 0);
 62                 gpio_set_value(GPIO_CODEC_RESET, 0);
 63         }
 64 }
 65 
 66 /* CS4270 */
 67 static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
 68 {
 69         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 70         struct snd_soc_dai *codec_dai = rtd->codec_dai;
 71 
 72         /* set freq to 0 to enable all possible codec sample rates */
 73         return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
 74 }
 75 
 76 static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
 77 {
 78         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 79         struct snd_soc_dai *codec_dai = rtd->codec_dai;
 80 
 81         /* set freq to 0 to enable all possible codec sample rates */
 82         snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
 83 }
 84 
 85 static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
 86                                      struct snd_pcm_hw_params *params)
 87 {
 88         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 89         struct snd_soc_dai *codec_dai = rtd->codec_dai;
 90         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 91         unsigned int clk = 0;
 92         int ret = 0;
 93 
 94         switch (params_rate(params)) {
 95         case 44100:
 96                 set_max9485_clk(MAX9485_MCLK_FREQ_112896);
 97                 clk = 11289600;
 98                 break;
 99         case 48000:
100                 set_max9485_clk(MAX9485_MCLK_FREQ_122880);
101                 clk = 12288000;
102                 break;
103         case 88200:
104                 set_max9485_clk(MAX9485_MCLK_FREQ_225792);
105                 clk = 22579200;
106                 break;
107         case 96000:
108                 set_max9485_clk(MAX9485_MCLK_FREQ_245760);
109                 clk = 24576000;
110                 break;
111         default:
112                 return -EINVAL;
113         }
114 
115         ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
116         if (ret < 0)
117                 return ret;
118 
119         /* setup the CPU DAI */
120         ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
121         if (ret < 0)
122                 return ret;
123 
124         ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
125         if (ret < 0)
126                 return ret;
127 
128         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
129         if (ret < 0)
130                 return ret;
131 
132         return 0;
133 }
134 
135 static struct snd_soc_ops raumfeld_cs4270_ops = {
136         .startup = raumfeld_cs4270_startup,
137         .shutdown = raumfeld_cs4270_shutdown,
138         .hw_params = raumfeld_cs4270_hw_params,
139 };
140 
141 static int raumfeld_analog_suspend(struct snd_soc_card *card)
142 {
143         raumfeld_enable_audio(false);
144         return 0;
145 }
146 
147 static int raumfeld_analog_resume(struct snd_soc_card *card)
148 {
149         raumfeld_enable_audio(true);
150         return 0;
151 }
152 
153 /* AK4104 */
154 
155 static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
156                                      struct snd_pcm_hw_params *params)
157 {
158         struct snd_soc_pcm_runtime *rtd = substream->private_data;
159         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
160         int ret = 0, clk = 0;
161 
162         switch (params_rate(params)) {
163         case 44100:
164                 set_max9485_clk(MAX9485_MCLK_FREQ_112896);
165                 clk = 11289600;
166                 break;
167         case 48000:
168                 set_max9485_clk(MAX9485_MCLK_FREQ_122880);
169                 clk = 12288000;
170                 break;
171         case 88200:
172                 set_max9485_clk(MAX9485_MCLK_FREQ_225792);
173                 clk = 22579200;
174                 break;
175         case 96000:
176                 set_max9485_clk(MAX9485_MCLK_FREQ_245760);
177                 clk = 24576000;
178                 break;
179         default:
180                 return -EINVAL;
181         }
182 
183         /* setup the CPU DAI */
184         ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
185         if (ret < 0)
186                 return ret;
187 
188         ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
189         if (ret < 0)
190                 return ret;
191 
192         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
193         if (ret < 0)
194                 return ret;
195 
196         return 0;
197 }
198 
199 static struct snd_soc_ops raumfeld_ak4104_ops = {
200         .hw_params = raumfeld_ak4104_hw_params,
201 };
202 
203 #define DAI_LINK_CS4270         \
204 {                                                       \
205         .name           = "CS4270",                     \
206         .stream_name    = "CS4270",                     \
207         .cpu_dai_name   = "pxa-ssp-dai.0",              \
208         .platform_name  = "pxa-pcm-audio",              \
209         .codec_dai_name = "cs4270-hifi",                \
210         .codec_name     = "cs4270.0-0048",      \
211         .dai_fmt        = SND_SOC_DAIFMT_I2S |          \
212                           SND_SOC_DAIFMT_NB_NF |        \
213                           SND_SOC_DAIFMT_CBS_CFS,       \
214         .ops            = &raumfeld_cs4270_ops,         \
215 }
216 
217 #define DAI_LINK_AK4104         \
218 {                                                       \
219         .name           = "ak4104",                     \
220         .stream_name    = "Playback",                   \
221         .cpu_dai_name   = "pxa-ssp-dai.1",              \
222         .codec_dai_name = "ak4104-hifi",                \
223         .platform_name  = "pxa-pcm-audio",              \
224         .dai_fmt        = SND_SOC_DAIFMT_I2S |          \
225                           SND_SOC_DAIFMT_NB_NF |        \
226                           SND_SOC_DAIFMT_CBS_CFS,       \
227         .ops            = &raumfeld_ak4104_ops,         \
228         .codec_name     = "spi0.0",                     \
229 }
230 
231 static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] =
232 {
233         DAI_LINK_CS4270,
234         DAI_LINK_AK4104,
235 };
236 
237 static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] =
238 {
239         DAI_LINK_CS4270,
240 };
241 
242 static struct snd_soc_card snd_soc_raumfeld_connector = {
243         .name           = "Raumfeld Connector",
244         .owner          = THIS_MODULE,
245         .dai_link       = snd_soc_raumfeld_connector_dai,
246         .num_links      = ARRAY_SIZE(snd_soc_raumfeld_connector_dai),
247         .suspend_post   = raumfeld_analog_suspend,
248         .resume_pre     = raumfeld_analog_resume,
249 };
250 
251 static struct snd_soc_card snd_soc_raumfeld_speaker = {
252         .name           = "Raumfeld Speaker",
253         .owner          = THIS_MODULE,
254         .dai_link       = snd_soc_raumfeld_speaker_dai,
255         .num_links      = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai),
256         .suspend_post   = raumfeld_analog_suspend,
257         .resume_pre     = raumfeld_analog_resume,
258 };
259 
260 static struct platform_device *raumfeld_audio_device;
261 
262 static int __init raumfeld_audio_init(void)
263 {
264         int ret;
265 
266         if (!machine_is_raumfeld_speaker() &&
267             !machine_is_raumfeld_connector())
268                 return 0;
269 
270         max9486_client = i2c_new_device(i2c_get_adapter(0),
271                                         &max9486_hwmon_info);
272 
273         if (!max9486_client)
274                 return -ENOMEM;
275 
276         set_max9485_clk(MAX9485_MCLK_FREQ_122880);
277 
278         /* Register analog device */
279         raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
280         if (!raumfeld_audio_device)
281                 return -ENOMEM;
282 
283         if (machine_is_raumfeld_speaker())
284                 platform_set_drvdata(raumfeld_audio_device,
285                                      &snd_soc_raumfeld_speaker);
286 
287         if (machine_is_raumfeld_connector())
288                 platform_set_drvdata(raumfeld_audio_device,
289                                      &snd_soc_raumfeld_connector);
290 
291         ret = platform_device_add(raumfeld_audio_device);
292         if (ret < 0) {
293                 platform_device_put(raumfeld_audio_device);
294                 return ret;
295         }
296 
297         raumfeld_enable_audio(true);
298         return 0;
299 }
300 
301 static void __exit raumfeld_audio_exit(void)
302 {
303         raumfeld_enable_audio(false);
304 
305         platform_device_unregister(raumfeld_audio_device);
306 
307         i2c_unregister_device(max9486_client);
308 
309         gpio_free(GPIO_MCLK_RESET);
310         gpio_free(GPIO_CODEC_RESET);
311         gpio_free(GPIO_SPDIF_RESET);
312 }
313 
314 module_init(raumfeld_audio_init);
315 module_exit(raumfeld_audio_exit);
316 
317 /* Module information */
318 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
319 MODULE_DESCRIPTION("Raumfeld audio SoC");
320 MODULE_LICENSE("GPL");
321 

~ [ 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