ext2: fixed typo.
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / sound / soc / omap / omap-mcpdm.c
blobb7f4f7e015f3f4ef4c0dc91f46e1e4573ce39259
1 /*
2 * omap-mcpdm.c -- OMAP ALSA SoC DAI driver using McPDM port
4 * Copyright (C) 2009 Texas Instruments
6 * Author: Misael Lopez Cruz <x0052729@ti.com>
7 * Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
8 * Margarita Olaya <magi.olaya@ti.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
26 #include <linux/init.h>
27 #include <linux/module.h>
28 #include <linux/device.h>
29 #include <sound/core.h>
30 #include <sound/pcm.h>
31 #include <sound/pcm_params.h>
32 #include <sound/initval.h>
33 #include <sound/soc.h>
35 #include <plat/control.h>
36 #include <plat/dma.h>
37 #include <plat/mcbsp.h>
38 #include "mcpdm.h"
39 #include "omap-mcpdm.h"
40 #include "omap-pcm.h"
42 struct omap_mcpdm_data {
43 struct omap_mcpdm_link *links;
44 int active;
47 static struct omap_mcpdm_link omap_mcpdm_links[] = {
48 /* downlink */
50 .irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL,
51 .threshold = 1,
52 .format = PDMOUTFORMAT_LJUST,
54 /* uplink */
56 .irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL,
57 .threshold = 1,
58 .format = PDMOUTFORMAT_LJUST,
62 static struct omap_mcpdm_data mcpdm_data = {
63 .links = omap_mcpdm_links,
64 .active = 0,
68 * Stream DMA parameters
70 static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
72 .name = "Audio playback",
73 .dma_req = OMAP44XX_DMA_MCPDM_DL,
74 .data_type = OMAP_DMA_DATA_TYPE_S32,
75 .sync_mode = OMAP_DMA_SYNC_PACKET,
76 .packet_size = 16,
77 .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_DN_DATA,
80 .name = "Audio capture",
81 .dma_req = OMAP44XX_DMA_MCPDM_UP,
82 .data_type = OMAP_DMA_DATA_TYPE_S32,
83 .sync_mode = OMAP_DMA_SYNC_PACKET,
84 .packet_size = 16,
85 .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_UP_DATA,
89 static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
90 struct snd_soc_dai *dai)
92 struct snd_soc_pcm_runtime *rtd = substream->private_data;
93 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
94 int err = 0;
96 if (!cpu_dai->active)
97 err = omap_mcpdm_request();
99 return err;
102 static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
103 struct snd_soc_dai *dai)
105 struct snd_soc_pcm_runtime *rtd = substream->private_data;
106 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
108 if (!cpu_dai->active)
109 omap_mcpdm_free();
112 static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
113 struct snd_soc_dai *dai)
115 struct snd_soc_pcm_runtime *rtd = substream->private_data;
116 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
117 struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
118 int stream = substream->stream;
119 int err = 0;
121 switch (cmd) {
122 case SNDRV_PCM_TRIGGER_START:
123 case SNDRV_PCM_TRIGGER_RESUME:
124 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
125 if (!mcpdm_priv->active++)
126 omap_mcpdm_start(stream);
127 break;
129 case SNDRV_PCM_TRIGGER_STOP:
130 case SNDRV_PCM_TRIGGER_SUSPEND:
131 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
132 if (!--mcpdm_priv->active)
133 omap_mcpdm_stop(stream);
134 break;
135 default:
136 err = -EINVAL;
139 return err;
142 static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
143 struct snd_pcm_hw_params *params,
144 struct snd_soc_dai *dai)
146 struct snd_soc_pcm_runtime *rtd = substream->private_data;
147 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
148 struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
149 struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
150 int stream = substream->stream;
151 int channels, err, link_mask = 0;
153 snd_soc_dai_set_dma_data(cpu_dai, substream,
154 &omap_mcpdm_dai_dma_params[stream]);
156 channels = params_channels(params);
157 switch (channels) {
158 case 4:
159 if (stream == SNDRV_PCM_STREAM_CAPTURE)
160 /* up to 2 channels for capture */
161 return -EINVAL;
162 link_mask |= 1 << 3;
163 case 3:
164 if (stream == SNDRV_PCM_STREAM_CAPTURE)
165 /* up to 2 channels for capture */
166 return -EINVAL;
167 link_mask |= 1 << 2;
168 case 2:
169 link_mask |= 1 << 1;
170 case 1:
171 link_mask |= 1 << 0;
172 break;
173 default:
174 /* unsupported number of channels */
175 return -EINVAL;
178 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
179 mcpdm_links[stream].channels = link_mask << 3;
180 err = omap_mcpdm_playback_open(&mcpdm_links[stream]);
181 } else {
182 mcpdm_links[stream].channels = link_mask << 0;
183 err = omap_mcpdm_capture_open(&mcpdm_links[stream]);
186 return err;
189 static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
190 struct snd_soc_dai *dai)
192 struct snd_soc_pcm_runtime *rtd = substream->private_data;
193 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
194 struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
195 struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
196 int stream = substream->stream;
197 int err;
199 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
200 err = omap_mcpdm_playback_close(&mcpdm_links[stream]);
201 else
202 err = omap_mcpdm_capture_close(&mcpdm_links[stream]);
204 return err;
207 static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
208 .startup = omap_mcpdm_dai_startup,
209 .shutdown = omap_mcpdm_dai_shutdown,
210 .trigger = omap_mcpdm_dai_trigger,
211 .hw_params = omap_mcpdm_dai_hw_params,
212 .hw_free = omap_mcpdm_dai_hw_free,
215 #define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
216 #define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
218 struct snd_soc_dai omap_mcpdm_dai = {
219 .name = "omap-mcpdm",
220 .id = -1,
221 .playback = {
222 .channels_min = 1,
223 .channels_max = 4,
224 .rates = OMAP_MCPDM_RATES,
225 .formats = OMAP_MCPDM_FORMATS,
227 .capture = {
228 .channels_min = 1,
229 .channels_max = 2,
230 .rates = OMAP_MCPDM_RATES,
231 .formats = OMAP_MCPDM_FORMATS,
233 .ops = &omap_mcpdm_dai_ops,
234 .private_data = &mcpdm_data,
236 EXPORT_SYMBOL_GPL(omap_mcpdm_dai);
238 static int __init snd_omap_mcpdm_init(void)
240 return snd_soc_register_dai(&omap_mcpdm_dai);
242 module_init(snd_omap_mcpdm_init);
244 static void __exit snd_omap_mcpdm_exit(void)
246 snd_soc_unregister_dai(&omap_mcpdm_dai);
248 module_exit(snd_omap_mcpdm_exit);
250 MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
251 MODULE_DESCRIPTION("OMAP PDM SoC Interface");
252 MODULE_LICENSE("GPL");