~ubuntu-branches/ubuntu/maverick/linux-backports-modules-2.6.32/maverick

« back to all changes in this revision

Viewing changes to updates/alsa-driver/alsa-kernel/soc/omap/omap-mcbsp.c

  • Committer: Bazaar Package Importer
  • Author(s): Andy Whitcroft, Andy Whitcroft
  • Date: 2010-02-04 23:15:51 UTC
  • Revision ID: james.westby@ubuntu.com-20100204231551-vjz5pkvxclukjxm1
Tags: 2.6.32-12.1
[ Andy Whitcroft ]

* initial LBM for lucid
* drop generated files
* printchanges -- rebase tree does not have stable tags use changelog
* printenv -- add revisions to printenv output
* formally rename compat-wireless to linux-backports-modules-wireless
* Update to compat-wireless-2.6.33-rc5
* update nouveau to mainline 2.6.33-rc4
* add new LBM package for nouveau
* nouveau -- fix major numbers and proc entry names
* fix up firmware installs for -wireless
* clean up UPDATE-NOVEAU
* update Nouveau to v2.6.33-rc6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * omap-mcbsp.c  --  OMAP ALSA SoC DAI driver using McBSP port
 
3
 *
 
4
 * Copyright (C) 2008 Nokia Corporation
 
5
 *
 
6
 * Contact: Jarkko Nikula <jhnikula@gmail.com>
 
7
 *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU General Public License
 
11
 * version 2 as published by the Free Software Foundation.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful, but
 
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, write to the Free Software
 
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
21
 * 02110-1301 USA
 
22
 *
 
23
 */
 
24
 
 
25
#include <linux/init.h>
 
26
#include <linux/module.h>
 
27
#include <linux/device.h>
 
28
#include <sound/core.h>
 
29
#include <sound/pcm.h>
 
30
#include <sound/pcm_params.h>
 
31
#include <sound/initval.h>
 
32
#include <sound/soc.h>
 
33
 
 
34
#include <plat/control.h>
 
35
#include <plat/dma.h>
 
36
#include <plat/mcbsp.h>
 
37
#include "omap-mcbsp.h"
 
38
#include "omap-pcm.h"
 
39
 
 
40
#define OMAP_MCBSP_RATES        (SNDRV_PCM_RATE_8000_96000)
 
41
 
 
42
struct omap_mcbsp_data {
 
43
        unsigned int                    bus_id;
 
44
        struct omap_mcbsp_reg_cfg       regs;
 
45
        unsigned int                    fmt;
 
46
        /*
 
47
         * Flags indicating is the bus already activated and configured by
 
48
         * another substream
 
49
         */
 
50
        int                             active;
 
51
        int                             configured;
 
52
        unsigned int                    in_freq;
 
53
        int                             clk_div;
 
54
};
 
55
 
 
56
#define to_mcbsp(priv)  container_of((priv), struct omap_mcbsp_data, bus_id)
 
57
 
 
58
static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
 
59
 
 
60
/*
 
61
 * Stream DMA parameters. DMA request line and port address are set runtime
 
62
 * since they are different between OMAP1 and later OMAPs
 
63
 */
 
64
static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
 
65
 
 
66
#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
 
67
static const int omap1_dma_reqs[][2] = {
 
68
        { OMAP_DMA_MCBSP1_TX, OMAP_DMA_MCBSP1_RX },
 
69
        { OMAP_DMA_MCBSP2_TX, OMAP_DMA_MCBSP2_RX },
 
70
        { OMAP_DMA_MCBSP3_TX, OMAP_DMA_MCBSP3_RX },
 
71
};
 
72
static const unsigned long omap1_mcbsp_port[][2] = {
 
73
        { OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
 
74
          OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
 
75
        { OMAP1510_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1,
 
76
          OMAP1510_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
 
77
        { OMAP1510_MCBSP3_BASE + OMAP_MCBSP_REG_DXR1,
 
78
          OMAP1510_MCBSP3_BASE + OMAP_MCBSP_REG_DRR1 },
 
79
};
 
80
#else
 
81
static const int omap1_dma_reqs[][2] = {};
 
82
static const unsigned long omap1_mcbsp_port[][2] = {};
 
83
#endif
 
84
 
 
85
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 
86
static const int omap24xx_dma_reqs[][2] = {
 
87
        { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
 
88
        { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
 
89
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
 
90
        { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
 
91
        { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
 
92
        { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
 
93
#endif
 
94
};
 
95
#else
 
96
static const int omap24xx_dma_reqs[][2] = {};
 
97
#endif
 
98
 
 
99
#if defined(CONFIG_ARCH_OMAP2420)
 
100
static const unsigned long omap2420_mcbsp_port[][2] = {
 
101
        { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
 
102
          OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
 
103
        { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1,
 
104
          OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
 
105
};
 
106
#else
 
107
static const unsigned long omap2420_mcbsp_port[][2] = {};
 
108
#endif
 
109
 
 
110
#if defined(CONFIG_ARCH_OMAP2430)
 
111
static const unsigned long omap2430_mcbsp_port[][2] = {
 
112
        { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
 
113
          OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
 
114
        { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
 
115
          OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
 
116
        { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
 
117
          OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
 
118
        { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
 
119
          OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
 
120
        { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
 
121
          OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
 
122
};
 
123
#else
 
124
static const unsigned long omap2430_mcbsp_port[][2] = {};
 
125
#endif
 
126
 
 
127
#if defined(CONFIG_ARCH_OMAP34XX)
 
128
static const unsigned long omap34xx_mcbsp_port[][2] = {
 
129
        { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
 
130
          OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
 
131
        { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
 
132
          OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
 
133
        { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
 
134
          OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
 
135
        { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
 
136
          OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
 
137
        { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
 
138
          OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
 
139
};
 
140
#else
 
141
static const unsigned long omap34xx_mcbsp_port[][2] = {};
 
142
#endif
 
143
 
 
144
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
 
145
{
 
146
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
147
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
148
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 
149
        int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
 
150
        int samples;
 
151
 
 
152
        /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
 
153
        if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
 
154
                samples = snd_pcm_lib_period_bytes(substream) >> 1;
 
155
        else
 
156
                samples = 1;
 
157
 
 
158
        /* Configure McBSP internal buffer usage */
 
159
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 
160
                omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1);
 
161
        else
 
162
                omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1);
 
163
}
 
164
 
 
165
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
 
166
                                  struct snd_soc_dai *dai)
 
167
{
 
168
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
169
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
170
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 
171
        int bus_id = mcbsp_data->bus_id;
 
172
        int err = 0;
 
173
 
 
174
        if (!cpu_dai->active)
 
175
                err = omap_mcbsp_request(bus_id);
 
176
 
 
177
        if (cpu_is_omap343x()) {
 
178
                int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id);
 
179
                int max_period;
 
180
 
 
181
                /*
 
182
                 * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer.
 
183
                 * Set constraint for minimum buffer size to the same than FIFO
 
184
                 * size in order to avoid underruns in playback startup because
 
185
                 * HW is keeping the DMA request active until FIFO is filled.
 
186
                 */
 
187
                if (bus_id == 1)
 
188
                        snd_pcm_hw_constraint_minmax(substream->runtime,
 
189
                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 
190
                                        4096, UINT_MAX);
 
191
 
 
192
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 
193
                        max_period = omap_mcbsp_get_max_tx_threshold(bus_id);
 
194
                else
 
195
                        max_period = omap_mcbsp_get_max_rx_threshold(bus_id);
 
196
 
 
197
                max_period++;
 
198
                max_period <<= 1;
 
199
 
 
200
                if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
 
201
                        snd_pcm_hw_constraint_minmax(substream->runtime,
 
202
                                                SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 
203
                                                32, max_period);
 
204
        }
 
205
 
 
206
        return err;
 
207
}
 
208
 
 
209
static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
 
210
                                    struct snd_soc_dai *dai)
 
211
{
 
212
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
213
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
214
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 
215
 
 
216
        if (!cpu_dai->active) {
 
217
                omap_mcbsp_free(mcbsp_data->bus_id);
 
218
                mcbsp_data->configured = 0;
 
219
        }
 
220
}
 
221
 
 
222
static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 
223
                                  struct snd_soc_dai *dai)
 
224
{
 
225
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
226
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
227
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 
228
        int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
229
 
 
230
        switch (cmd) {
 
231
        case SNDRV_PCM_TRIGGER_START:
 
232
        case SNDRV_PCM_TRIGGER_RESUME:
 
233
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 
234
                mcbsp_data->active++;
 
235
                omap_mcbsp_start(mcbsp_data->bus_id, play, !play);
 
236
                break;
 
237
 
 
238
        case SNDRV_PCM_TRIGGER_STOP:
 
239
        case SNDRV_PCM_TRIGGER_SUSPEND:
 
240
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 
241
                omap_mcbsp_stop(mcbsp_data->bus_id, play, !play);
 
242
                mcbsp_data->active--;
 
243
                break;
 
244
        default:
 
245
                err = -EINVAL;
 
246
        }
 
247
 
 
248
        return err;
 
249
}
 
250
 
 
251
static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 
252
                                    struct snd_pcm_hw_params *params,
 
253
                                    struct snd_soc_dai *dai)
 
254
{
 
255
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
256
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
257
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 
258
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
 
259
        int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
 
260
        int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
 
261
        unsigned long port;
 
262
        unsigned int format, div, framesize, master;
 
263
 
 
264
        if (cpu_class_is_omap1()) {
 
265
                dma = omap1_dma_reqs[bus_id][substream->stream];
 
266
                port = omap1_mcbsp_port[bus_id][substream->stream];
 
267
        } else if (cpu_is_omap2420()) {
 
268
                dma = omap24xx_dma_reqs[bus_id][substream->stream];
 
269
                port = omap2420_mcbsp_port[bus_id][substream->stream];
 
270
        } else if (cpu_is_omap2430()) {
 
271
                dma = omap24xx_dma_reqs[bus_id][substream->stream];
 
272
                port = omap2430_mcbsp_port[bus_id][substream->stream];
 
273
        } else if (cpu_is_omap343x()) {
 
274
                dma = omap24xx_dma_reqs[bus_id][substream->stream];
 
275
                port = omap34xx_mcbsp_port[bus_id][substream->stream];
 
276
                omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold =
 
277
                                                omap_mcbsp_set_threshold;
 
278
                /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
 
279
                if (omap_mcbsp_get_dma_op_mode(bus_id) ==
 
280
                                                MCBSP_DMA_MODE_THRESHOLD)
 
281
                        sync_mode = OMAP_DMA_SYNC_FRAME;
 
282
        } else {
 
283
                return -ENODEV;
 
284
        }
 
285
        omap_mcbsp_dai_dma_params[id][substream->stream].name =
 
286
                substream->stream ? "Audio Capture" : "Audio Playback";
 
287
        omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
 
288
        omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
 
289
        omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode;
 
290
        cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
 
291
 
 
292
        if (mcbsp_data->configured) {
 
293
                /* McBSP already configured by another stream */
 
294
                return 0;
 
295
        }
 
296
 
 
297
        format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 
298
        wpf = channels = params_channels(params);
 
299
        if (channels == 2 && format == SND_SOC_DAIFMT_I2S) {
 
300
                /* Use dual-phase frames */
 
301
                regs->rcr2      |= RPHASE;
 
302
                regs->xcr2      |= XPHASE;
 
303
                /* Set 1 word per (McBSP) frame for phase1 and phase2 */
 
304
                wpf--;
 
305
                regs->rcr2      |= RFRLEN2(wpf - 1);
 
306
                regs->xcr2      |= XFRLEN2(wpf - 1);
 
307
        }
 
308
 
 
309
        regs->rcr1      |= RFRLEN1(wpf - 1);
 
310
        regs->xcr1      |= XFRLEN1(wpf - 1);
 
311
 
 
312
        switch (params_format(params)) {
 
313
        case SNDRV_PCM_FORMAT_S16_LE:
 
314
                /* Set word lengths */
 
315
                wlen = 16;
 
316
                regs->rcr2      |= RWDLEN2(OMAP_MCBSP_WORD_16);
 
317
                regs->rcr1      |= RWDLEN1(OMAP_MCBSP_WORD_16);
 
318
                regs->xcr2      |= XWDLEN2(OMAP_MCBSP_WORD_16);
 
319
                regs->xcr1      |= XWDLEN1(OMAP_MCBSP_WORD_16);
 
320
                break;
 
321
        default:
 
322
                /* Unsupported PCM format */
 
323
                return -EINVAL;
 
324
        }
 
325
 
 
326
        /* In McBSP master modes, FRAME (i.e. sample rate) is generated
 
327
         * by _counting_ BCLKs. Calculate frame size in BCLKs */
 
328
        master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK;
 
329
        if (master ==   SND_SOC_DAIFMT_CBS_CFS) {
 
330
                div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1;
 
331
                framesize = (mcbsp_data->in_freq / div) / params_rate(params);
 
332
 
 
333
                if (framesize < wlen * channels) {
 
334
                        printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
 
335
                                        "channels\n", __func__);
 
336
                        return -EINVAL;
 
337
                }
 
338
        } else
 
339
                framesize = wlen * channels;
 
340
 
 
341
        /* Set FS period and length in terms of bit clock periods */
 
342
        switch (format) {
 
343
        case SND_SOC_DAIFMT_I2S:
 
344
                regs->srgr2     |= FPER(framesize - 1);
 
345
                regs->srgr1     |= FWID((framesize >> 1) - 1);
 
346
                break;
 
347
        case SND_SOC_DAIFMT_DSP_A:
 
348
        case SND_SOC_DAIFMT_DSP_B:
 
349
                regs->srgr2     |= FPER(framesize - 1);
 
350
                regs->srgr1     |= FWID(0);
 
351
                break;
 
352
        }
 
353
 
 
354
        omap_mcbsp_config(bus_id, &mcbsp_data->regs);
 
355
        mcbsp_data->configured = 1;
 
356
 
 
357
        return 0;
 
358
}
 
359
 
 
360
/*
 
361
 * This must be called before _set_clkdiv and _set_sysclk since McBSP register
 
362
 * cache is initialized here
 
363
 */
 
364
static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
365
                                      unsigned int fmt)
 
366
{
 
367
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 
368
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
 
369
        unsigned int temp_fmt = fmt;
 
370
 
 
371
        if (mcbsp_data->configured)
 
372
                return 0;
 
373
 
 
374
        mcbsp_data->fmt = fmt;
 
375
        memset(regs, 0, sizeof(*regs));
 
376
        /* Generic McBSP register settings */
 
377
        regs->spcr2     |= XINTM(3) | FREE;
 
378
        regs->spcr1     |= RINTM(3);
 
379
        /* RFIG and XFIG are not defined in 34xx */
 
380
        if (!cpu_is_omap34xx()) {
 
381
                regs->rcr2      |= RFIG;
 
382
                regs->xcr2      |= XFIG;
 
383
        }
 
384
        if (cpu_is_omap2430() || cpu_is_omap34xx()) {
 
385
                regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE;
 
386
                regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE;
 
387
        }
 
388
 
 
389
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 
390
        case SND_SOC_DAIFMT_I2S:
 
391
                /* 1-bit data delay */
 
392
                regs->rcr2      |= RDATDLY(1);
 
393
                regs->xcr2      |= XDATDLY(1);
 
394
                break;
 
395
        case SND_SOC_DAIFMT_DSP_A:
 
396
                /* 1-bit data delay */
 
397
                regs->rcr2      |= RDATDLY(1);
 
398
                regs->xcr2      |= XDATDLY(1);
 
399
                /* Invert FS polarity configuration */
 
400
                temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
 
401
                break;
 
402
        case SND_SOC_DAIFMT_DSP_B:
 
403
                /* 0-bit data delay */
 
404
                regs->rcr2      |= RDATDLY(0);
 
405
                regs->xcr2      |= XDATDLY(0);
 
406
                /* Invert FS polarity configuration */
 
407
                temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
 
408
                break;
 
409
        default:
 
410
                /* Unsupported data format */
 
411
                return -EINVAL;
 
412
        }
 
413
 
 
414
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 
415
        case SND_SOC_DAIFMT_CBS_CFS:
 
416
                /* McBSP master. Set FS and bit clocks as outputs */
 
417
                regs->pcr0      |= FSXM | FSRM |
 
418
                                   CLKXM | CLKRM;
 
419
                /* Sample rate generator drives the FS */
 
420
                regs->srgr2     |= FSGM;
 
421
                break;
 
422
        case SND_SOC_DAIFMT_CBM_CFM:
 
423
                /* McBSP slave */
 
424
                break;
 
425
        default:
 
426
                /* Unsupported master/slave configuration */
 
427
                return -EINVAL;
 
428
        }
 
429
 
 
430
        /* Set bit clock (CLKX/CLKR) and FS polarities */
 
431
        switch (temp_fmt & SND_SOC_DAIFMT_INV_MASK) {
 
432
        case SND_SOC_DAIFMT_NB_NF:
 
433
                /*
 
434
                 * Normal BCLK + FS.
 
435
                 * FS active low. TX data driven on falling edge of bit clock
 
436
                 * and RX data sampled on rising edge of bit clock.
 
437
                 */
 
438
                regs->pcr0      |= FSXP | FSRP |
 
439
                                   CLKXP | CLKRP;
 
440
                break;
 
441
        case SND_SOC_DAIFMT_NB_IF:
 
442
                regs->pcr0      |= CLKXP | CLKRP;
 
443
                break;
 
444
        case SND_SOC_DAIFMT_IB_NF:
 
445
                regs->pcr0      |= FSXP | FSRP;
 
446
                break;
 
447
        case SND_SOC_DAIFMT_IB_IF:
 
448
                break;
 
449
        default:
 
450
                return -EINVAL;
 
451
        }
 
452
 
 
453
        return 0;
 
454
}
 
455
 
 
456
static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
 
457
                                     int div_id, int div)
 
458
{
 
459
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 
460
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
 
461
 
 
462
        if (div_id != OMAP_MCBSP_CLKGDV)
 
463
                return -ENODEV;
 
464
 
 
465
        mcbsp_data->clk_div = div;
 
466
        regs->srgr1     |= CLKGDV(div - 1);
 
467
 
 
468
        return 0;
 
469
}
 
470
 
 
471
static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
 
472
                                       int clk_id)
 
473
{
 
474
        int sel_bit;
 
475
        u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
 
476
 
 
477
        if (cpu_class_is_omap1()) {
 
478
                /* OMAP1's can use only external source clock */
 
479
                if (unlikely(clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK))
 
480
                        return -EINVAL;
 
481
                else
 
482
                        return 0;
 
483
        }
 
484
 
 
485
        if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
 
486
                return -EINVAL;
 
487
 
 
488
        if (cpu_is_omap343x())
 
489
                reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
 
490
 
 
491
        switch (mcbsp_data->bus_id) {
 
492
        case 0:
 
493
                reg = OMAP2_CONTROL_DEVCONF0;
 
494
                sel_bit = 2;
 
495
                break;
 
496
        case 1:
 
497
                reg = OMAP2_CONTROL_DEVCONF0;
 
498
                sel_bit = 6;
 
499
                break;
 
500
        case 2:
 
501
                reg = reg_devconf1;
 
502
                sel_bit = 0;
 
503
                break;
 
504
        case 3:
 
505
                reg = reg_devconf1;
 
506
                sel_bit = 2;
 
507
                break;
 
508
        case 4:
 
509
                reg = reg_devconf1;
 
510
                sel_bit = 4;
 
511
                break;
 
512
        default:
 
513
                return -EINVAL;
 
514
        }
 
515
 
 
516
        if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
 
517
                omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
 
518
        else
 
519
                omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
 
520
 
 
521
        return 0;
 
522
}
 
523
 
 
524
static int omap_mcbsp_dai_set_rcvr_src(struct omap_mcbsp_data *mcbsp_data,
 
525
                                       int clk_id)
 
526
{
 
527
        int sel_bit, set = 0;
 
528
        u16 reg = OMAP2_CONTROL_DEVCONF0;
 
529
 
 
530
        if (cpu_class_is_omap1())
 
531
                return -EINVAL; /* TODO: Can this be implemented for OMAP1? */
 
532
        if (mcbsp_data->bus_id != 0)
 
533
                return -EINVAL;
 
534
 
 
535
        switch (clk_id) {
 
536
        case OMAP_MCBSP_CLKR_SRC_CLKX:
 
537
                set = 1;
 
538
        case OMAP_MCBSP_CLKR_SRC_CLKR:
 
539
                sel_bit = 3;
 
540
                break;
 
541
        case OMAP_MCBSP_FSR_SRC_FSX:
 
542
                set = 1;
 
543
        case OMAP_MCBSP_FSR_SRC_FSR:
 
544
                sel_bit = 4;
 
545
                break;
 
546
        default:
 
547
                return -EINVAL;
 
548
        }
 
549
 
 
550
        if (set)
 
551
                omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
 
552
        else
 
553
                omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
 
554
 
 
555
        return 0;
 
556
}
 
557
 
 
558
static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 
559
                                         int clk_id, unsigned int freq,
 
560
                                         int dir)
 
561
{
 
562
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 
563
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
 
564
        int err = 0;
 
565
 
 
566
        mcbsp_data->in_freq = freq;
 
567
 
 
568
        switch (clk_id) {
 
569
        case OMAP_MCBSP_SYSCLK_CLK:
 
570
                regs->srgr2     |= CLKSM;
 
571
                break;
 
572
        case OMAP_MCBSP_SYSCLK_CLKS_FCLK:
 
573
        case OMAP_MCBSP_SYSCLK_CLKS_EXT:
 
574
                err = omap_mcbsp_dai_set_clks_src(mcbsp_data, clk_id);
 
575
                break;
 
576
 
 
577
        case OMAP_MCBSP_SYSCLK_CLKX_EXT:
 
578
                regs->srgr2     |= CLKSM;
 
579
        case OMAP_MCBSP_SYSCLK_CLKR_EXT:
 
580
                regs->pcr0      |= SCLKME;
 
581
                break;
 
582
 
 
583
        case OMAP_MCBSP_CLKR_SRC_CLKR:
 
584
        case OMAP_MCBSP_CLKR_SRC_CLKX:
 
585
        case OMAP_MCBSP_FSR_SRC_FSR:
 
586
        case OMAP_MCBSP_FSR_SRC_FSX:
 
587
                err = omap_mcbsp_dai_set_rcvr_src(mcbsp_data, clk_id);
 
588
                break;
 
589
        default:
 
590
                err = -ENODEV;
 
591
        }
 
592
 
 
593
        return err;
 
594
}
 
595
 
 
596
static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
 
597
        .startup        = omap_mcbsp_dai_startup,
 
598
        .shutdown       = omap_mcbsp_dai_shutdown,
 
599
        .trigger        = omap_mcbsp_dai_trigger,
 
600
        .hw_params      = omap_mcbsp_dai_hw_params,
 
601
        .set_fmt        = omap_mcbsp_dai_set_dai_fmt,
 
602
        .set_clkdiv     = omap_mcbsp_dai_set_clkdiv,
 
603
        .set_sysclk     = omap_mcbsp_dai_set_dai_sysclk,
 
604
};
 
605
 
 
606
#define OMAP_MCBSP_DAI_BUILDER(link_id)                         \
 
607
{                                                               \
 
608
        .name = "omap-mcbsp-dai-"#link_id,                      \
 
609
        .id = (link_id),                                        \
 
610
        .playback = {                                           \
 
611
                .channels_min = 1,                              \
 
612
                .channels_max = 16,                             \
 
613
                .rates = OMAP_MCBSP_RATES,                      \
 
614
                .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
 
615
        },                                                      \
 
616
        .capture = {                                            \
 
617
                .channels_min = 1,                              \
 
618
                .channels_max = 16,                             \
 
619
                .rates = OMAP_MCBSP_RATES,                      \
 
620
                .formats = SNDRV_PCM_FMTBIT_S16_LE,             \
 
621
        },                                                      \
 
622
        .ops = &omap_mcbsp_dai_ops,                             \
 
623
        .private_data = &mcbsp_data[(link_id)].bus_id,          \
 
624
}
 
625
 
 
626
struct snd_soc_dai omap_mcbsp_dai[] = {
 
627
        OMAP_MCBSP_DAI_BUILDER(0),
 
628
        OMAP_MCBSP_DAI_BUILDER(1),
 
629
#if NUM_LINKS >= 3
 
630
        OMAP_MCBSP_DAI_BUILDER(2),
 
631
#endif
 
632
#if NUM_LINKS == 5
 
633
        OMAP_MCBSP_DAI_BUILDER(3),
 
634
        OMAP_MCBSP_DAI_BUILDER(4),
 
635
#endif
 
636
};
 
637
 
 
638
EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
 
639
 
 
640
static int __init snd_omap_mcbsp_init(void)
 
641
{
 
642
        return snd_soc_register_dais(omap_mcbsp_dai,
 
643
                                     ARRAY_SIZE(omap_mcbsp_dai));
 
644
}
 
645
module_init(snd_omap_mcbsp_init);
 
646
 
 
647
static void __exit snd_omap_mcbsp_exit(void)
 
648
{
 
649
        snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai));
 
650
}
 
651
module_exit(snd_omap_mcbsp_exit);
 
652
 
 
653
MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
 
654
MODULE_DESCRIPTION("OMAP I2S SoC Interface");
 
655
MODULE_LICENSE("GPL");