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