ASoC: Rename controls with a / in wm_hubs
[safe/jmp/linux-2.6] / sound / soc / s3c24xx / smdk64xx_wm8580.c
1 /*
2  *  smdk64xx_wm8580.c
3  *
4  *  Copyright (c) 2009 Samsung Electronics Co. Ltd
5  *  Author: Jaswinder Singh <jassi.brar@samsung.com>
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  */
12
13 #include <linux/platform_device.h>
14 #include <linux/clk.h>
15 #include <sound/core.h>
16 #include <sound/pcm.h>
17 #include <sound/pcm_params.h>
18 #include <sound/soc.h>
19 #include <sound/soc-dapm.h>
20
21 #include "../codecs/wm8580.h"
22 #include "s3c-dma.h"
23 #include "s3c64xx-i2s.h"
24
25 #define S3C64XX_I2S_V4 2
26
27 /* SMDK64XX has a 12MHZ crystal attached to WM8580 */
28 #define SMDK64XX_WM8580_FREQ 12000000
29
30 static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
31         struct snd_pcm_hw_params *params)
32 {
33         struct snd_soc_pcm_runtime *rtd = substream->private_data;
34         struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
35         struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
36         unsigned int pll_out;
37         int bfs, rfs, ret;
38
39         switch (params_format(params)) {
40         case SNDRV_PCM_FORMAT_U8:
41         case SNDRV_PCM_FORMAT_S8:
42                 bfs = 16;
43                 break;
44         case SNDRV_PCM_FORMAT_U16_LE:
45         case SNDRV_PCM_FORMAT_S16_LE:
46                 bfs = 32;
47                 break;
48         default:
49                 return -EINVAL;
50         }
51
52         /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
53          * This criterion can't be met if we request PLL output
54          * as {8000x256, 64000x256, 11025x256}Hz.
55          * As a wayout, we rather change rfs to a minimum value that
56          * results in (params_rate(params) * rfs), and itself, acceptable
57          * to both - the CODEC and the CPU.
58          */
59         switch (params_rate(params)) {
60         case 16000:
61         case 22050:
62         case 32000:
63         case 44100:
64         case 48000:
65         case 88200:
66         case 96000:
67                 rfs = 256;
68                 break;
69         case 64000:
70                 rfs = 384;
71                 break;
72         case 8000:
73         case 11025:
74                 rfs = 512;
75                 break;
76         default:
77                 return -EINVAL;
78         }
79         pll_out = params_rate(params) * rfs;
80
81         /* Set the Codec DAI configuration */
82         ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
83                                          | SND_SOC_DAIFMT_NB_NF
84                                          | SND_SOC_DAIFMT_CBM_CFM);
85         if (ret < 0)
86                 return ret;
87
88         /* Set the AP DAI configuration */
89         ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
90                                          | SND_SOC_DAIFMT_NB_NF
91                                          | SND_SOC_DAIFMT_CBM_CFM);
92         if (ret < 0)
93                 return ret;
94
95         ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK,
96                                         0, SND_SOC_CLOCK_IN);
97         if (ret < 0)
98                 return ret;
99
100         /* We use PCLK for basic ops in SoC-Slave mode */
101         ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
102                                         0, SND_SOC_CLOCK_IN);
103         if (ret < 0)
104                 return ret;
105
106         /* Set WM8580 to drive MCLK from its PLLA */
107         ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
108                                         WM8580_CLKSRC_PLLA);
109         if (ret < 0)
110                 return ret;
111
112         /* Explicitly set WM8580-DAC to source from MCLK */
113         ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL,
114                                         WM8580_CLKSRC_MCLK);
115         if (ret < 0)
116                 return ret;
117
118         ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
119                                         SMDK64XX_WM8580_FREQ, pll_out);
120         if (ret < 0)
121                 return ret;
122
123         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs);
124         if (ret < 0)
125                 return ret;
126
127         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs);
128         if (ret < 0)
129                 return ret;
130
131         return 0;
132 }
133
134 /*
135  * SMDK64XX WM8580 DAI operations.
136  */
137 static struct snd_soc_ops smdk64xx_ops = {
138         .hw_params = smdk64xx_hw_params,
139 };
140
141 /* SMDK64xx Playback widgets */
142 static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
143         SND_SOC_DAPM_HP("Front-L/R", NULL),
144         SND_SOC_DAPM_HP("Center/Sub", NULL),
145         SND_SOC_DAPM_HP("Rear-L/R", NULL),
146 };
147
148 /* SMDK64xx Capture widgets */
149 static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
150         SND_SOC_DAPM_MIC("MicIn", NULL),
151         SND_SOC_DAPM_LINE("LineIn", NULL),
152 };
153
154 /* SMDK-PAIFTX connections */
155 static const struct snd_soc_dapm_route audio_map_tx[] = {
156         /* MicIn feeds AINL */
157         {"AINL", NULL, "MicIn"},
158
159         /* LineIn feeds AINL/R */
160         {"AINL", NULL, "LineIn"},
161         {"AINR", NULL, "LineIn"},
162 };
163
164 /* SMDK-PAIFRX connections */
165 static const struct snd_soc_dapm_route audio_map_rx[] = {
166         /* Front Left/Right are fed VOUT1L/R */
167         {"Front-L/R", NULL, "VOUT1L"},
168         {"Front-L/R", NULL, "VOUT1R"},
169
170         /* Center/Sub are fed VOUT2L/R */
171         {"Center/Sub", NULL, "VOUT2L"},
172         {"Center/Sub", NULL, "VOUT2R"},
173
174         /* Rear Left/Right are fed VOUT3L/R */
175         {"Rear-L/R", NULL, "VOUT3L"},
176         {"Rear-L/R", NULL, "VOUT3R"},
177 };
178
179 static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
180 {
181         /* Add smdk64xx specific Capture widgets */
182         snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
183                                   ARRAY_SIZE(wm8580_dapm_widgets_cpt));
184
185         /* Set up PAIFTX audio path */
186         snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
187
188         /* Enabling the microphone requires the fitting of a 0R
189          * resistor to connect the line from the microphone jack.
190          */
191         snd_soc_dapm_disable_pin(codec, "MicIn");
192
193         /* signal a DAPM event */
194         snd_soc_dapm_sync(codec);
195
196         return 0;
197 }
198
199 static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
200 {
201         /* Add smdk64xx specific Playback widgets */
202         snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
203                                   ARRAY_SIZE(wm8580_dapm_widgets_pbk));
204
205         /* Set up PAIFRX audio path */
206         snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
207
208         /* signal a DAPM event */
209         snd_soc_dapm_sync(codec);
210
211         return 0;
212 }
213
214 static struct snd_soc_dai_link smdk64xx_dai[] = {
215 { /* Primary Playback i/f */
216         .name = "WM8580 PAIF RX",
217         .stream_name = "Playback",
218         .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
219         .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
220         .init = smdk64xx_wm8580_init_paifrx,
221         .ops = &smdk64xx_ops,
222 },
223 { /* Primary Capture i/f */
224         .name = "WM8580 PAIF TX",
225         .stream_name = "Capture",
226         .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
227         .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
228         .init = smdk64xx_wm8580_init_paiftx,
229         .ops = &smdk64xx_ops,
230 },
231 };
232
233 static struct snd_soc_card smdk64xx = {
234         .name = "smdk64xx",
235         .platform = &s3c24xx_soc_platform,
236         .dai_link = smdk64xx_dai,
237         .num_links = ARRAY_SIZE(smdk64xx_dai),
238 };
239
240 static struct snd_soc_device smdk64xx_snd_devdata = {
241         .card = &smdk64xx,
242         .codec_dev = &soc_codec_dev_wm8580,
243 };
244
245 static struct platform_device *smdk64xx_snd_device;
246
247 static int __init smdk64xx_audio_init(void)
248 {
249         int ret;
250
251         smdk64xx_snd_device = platform_device_alloc("soc-audio", -1);
252         if (!smdk64xx_snd_device)
253                 return -ENOMEM;
254
255         platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata);
256         smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev;
257         ret = platform_device_add(smdk64xx_snd_device);
258
259         if (ret)
260                 platform_device_put(smdk64xx_snd_device);
261
262         return ret;
263 }
264 module_init(smdk64xx_audio_init);
265
266 MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com");
267 MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580");
268 MODULE_LICENSE("GPL");