~ubuntu-branches/ubuntu/precise/alsa-driver/precise

« back to all changes in this revision

Viewing changes to alsa-kernel/soc/imx/mxc-ssi.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-11-04 16:28:58 UTC
  • mfrom: (1.1.12 upstream) (3.1.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091104162858-7ky0tu33d7mn6oys
Tags: 1.0.21+dfsg-3ubuntu1
* Merge from debian unstable, remaining changes:
  - Script paths (/usr/sbin -> /sbin, /usr/bin -> /bin);
  - debian/rules:
    + Don't install snddevices and program-wrapper
    + install alsa-base apport hook
    + Package separate USB card list file
  - Vcs and maintainer fields mangling
  - Rename blacklist files in /etc/modprobe.d to be consistant with the rest
    of the distro
  - debian/alsa-base.init:
    + create /var/run/alsa if it doesn't exist
    + Run alsactl store before force unloading modules
    + Run alsactl restore after reloading unloaded modules
  - debian/linux-sound-base.postrm: Remove /etc/modprobe.d/blacklist* files
    on package removal
  - Add missing $CMDLINE_OPTS to all install rules.
  - Replace -Q with --quiet.
  - Add --use-blacklist to all rules so the blacklist still takes effect.
  - debian/alsa-base.postinst: Do not run snddevices
  - retain patches:
    + add_suspend_quirk_hp_nc6220_nw8240.patch,
    + refix_lp_68659_by_disabling_dxs_for_0x1458a002.patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * mxc-ssi.c  --  SSI driver for Freescale IMX
 
3
 *
 
4
 * Copyright 2006 Wolfson Microelectronics PLC.
 
5
 * Author: Liam Girdwood
 
6
 *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
 
7
 *
 
8
 *  Based on mxc-alsa-mc13783 (C) 2006 Freescale.
 
9
 *
 
10
 *  This program is free software; you can redistribute  it and/or modify it
 
11
 *  under  the terms of  the GNU General  Public License as published by the
 
12
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 
13
 *  option) any later version.
 
14
 *
 
15
 * TODO:
 
16
 *   Need to rework SSI register defs when new defs go into mainline.
 
17
 *   Add support for TDM and FIFO 1.
 
18
 *   Add support for i.mx3x DMA interface.
 
19
 *
 
20
 */
 
21
 
 
22
 
 
23
#include <linux/module.h>
 
24
#include <linux/init.h>
 
25
#include <linux/platform_device.h>
 
26
#include <linux/slab.h>
 
27
#include <linux/dma-mapping.h>
 
28
#include <linux/clk.h>
 
29
#include <sound/core.h>
 
30
#include <sound/pcm.h>
 
31
#include <sound/pcm_params.h>
 
32
#include <sound/soc.h>
 
33
#include <mach/dma-mx1-mx2.h>
 
34
#include <asm/mach-types.h>
 
35
 
 
36
#include "mxc-ssi.h"
 
37
#include "mx1_mx2-pcm.h"
 
38
 
 
39
#define SSI1_PORT       0
 
40
#define SSI2_PORT       1
 
41
 
 
42
static int ssi_active[2] = {0, 0};
 
43
 
 
44
/* DMA information for mx1_mx2 platforms */
 
45
static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out0 = {
 
46
        .name                   = "SSI1 PCM Stereo out 0",
 
47
        .transfer_type = DMA_MODE_WRITE,
 
48
        .per_address = SSI1_BASE_ADDR + STX0,
 
49
        .event_id = DMA_REQ_SSI1_TX0,
 
50
        .watermark_level = TXFIFO_WATERMARK,
 
51
        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 
52
        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 
53
};
 
54
 
 
55
static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out1 = {
 
56
        .name                   = "SSI1 PCM Stereo out 1",
 
57
        .transfer_type = DMA_MODE_WRITE,
 
58
        .per_address = SSI1_BASE_ADDR + STX1,
 
59
        .event_id = DMA_REQ_SSI1_TX1,
 
60
        .watermark_level = TXFIFO_WATERMARK,
 
61
        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 
62
        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 
63
};
 
64
 
 
65
static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in0 = {
 
66
        .name                   = "SSI1 PCM Stereo in 0",
 
67
        .transfer_type = DMA_MODE_READ,
 
68
        .per_address = SSI1_BASE_ADDR + SRX0,
 
69
        .event_id = DMA_REQ_SSI1_RX0,
 
70
        .watermark_level = RXFIFO_WATERMARK,
 
71
        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 
72
        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 
73
};
 
74
 
 
75
static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in1 = {
 
76
        .name                   = "SSI1 PCM Stereo in 1",
 
77
        .transfer_type = DMA_MODE_READ,
 
78
        .per_address = SSI1_BASE_ADDR + SRX1,
 
79
        .event_id = DMA_REQ_SSI1_RX1,
 
80
        .watermark_level = RXFIFO_WATERMARK,
 
81
        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 
82
        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 
83
};
 
84
 
 
85
static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out0 = {
 
86
        .name                   = "SSI2 PCM Stereo out 0",
 
87
        .transfer_type = DMA_MODE_WRITE,
 
88
        .per_address = SSI2_BASE_ADDR + STX0,
 
89
        .event_id = DMA_REQ_SSI2_TX0,
 
90
        .watermark_level = TXFIFO_WATERMARK,
 
91
        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 
92
        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 
93
};
 
94
 
 
95
static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out1 = {
 
96
        .name                   = "SSI2 PCM Stereo out 1",
 
97
        .transfer_type = DMA_MODE_WRITE,
 
98
        .per_address = SSI2_BASE_ADDR + STX1,
 
99
        .event_id = DMA_REQ_SSI2_TX1,
 
100
        .watermark_level = TXFIFO_WATERMARK,
 
101
        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 
102
        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 
103
};
 
104
 
 
105
static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in0 = {
 
106
        .name                   = "SSI2 PCM Stereo in 0",
 
107
        .transfer_type = DMA_MODE_READ,
 
108
        .per_address = SSI2_BASE_ADDR + SRX0,
 
109
        .event_id = DMA_REQ_SSI2_RX0,
 
110
        .watermark_level = RXFIFO_WATERMARK,
 
111
        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 
112
        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 
113
};
 
114
 
 
115
static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in1 = {
 
116
        .name                   = "SSI2 PCM Stereo in 1",
 
117
        .transfer_type = DMA_MODE_READ,
 
118
        .per_address = SSI2_BASE_ADDR + SRX1,
 
119
        .event_id = DMA_REQ_SSI2_RX1,
 
120
        .watermark_level = RXFIFO_WATERMARK,
 
121
        .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
 
122
        .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
 
123
};
 
124
 
 
125
static struct clk *ssi_clk0, *ssi_clk1;
 
126
 
 
127
int get_ssi_clk(int ssi, struct device *dev)
 
128
{
 
129
        switch (ssi) {
 
130
        case 0:
 
131
                ssi_clk0 = clk_get(dev, "ssi1");
 
132
                if (IS_ERR(ssi_clk0))
 
133
                        return PTR_ERR(ssi_clk0);
 
134
                return 0;
 
135
        case 1:
 
136
                ssi_clk1 = clk_get(dev, "ssi2");
 
137
                if (IS_ERR(ssi_clk1))
 
138
                        return PTR_ERR(ssi_clk1);
 
139
                return 0;
 
140
        default:
 
141
                return -EINVAL;
 
142
        }
 
143
}
 
144
EXPORT_SYMBOL(get_ssi_clk);
 
145
 
 
146
void put_ssi_clk(int ssi)
 
147
{
 
148
        switch (ssi) {
 
149
        case 0:
 
150
                clk_put(ssi_clk0);
 
151
                ssi_clk0 = NULL;
 
152
                break;
 
153
        case 1:
 
154
                clk_put(ssi_clk1);
 
155
                ssi_clk1 = NULL;
 
156
                break;
 
157
        }
 
158
}
 
159
EXPORT_SYMBOL(put_ssi_clk);
 
160
 
 
161
/*
 
162
 * SSI system clock configuration.
 
163
 * Should only be called when port is inactive (i.e. SSIEN = 0).
 
164
 */
 
165
static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 
166
        int clk_id, unsigned int freq, int dir)
 
167
{
 
168
        u32 scr;
 
169
 
 
170
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
171
                scr = SSI1_SCR;
 
172
                pr_debug("%s: SCR for SSI1 is %x\n", __func__, scr);
 
173
        } else {
 
174
                scr = SSI2_SCR;
 
175
                pr_debug("%s: SCR for SSI2 is %x\n", __func__, scr);
 
176
        }
 
177
 
 
178
        if (scr & SSI_SCR_SSIEN) {
 
179
                printk(KERN_WARNING "Warning ssi already enabled\n");
 
180
                return 0;
 
181
        }
 
182
 
 
183
        switch (clk_id) {
 
184
        case IMX_SSP_SYS_CLK:
 
185
                if (dir == SND_SOC_CLOCK_OUT) {
 
186
                        scr |= SSI_SCR_SYS_CLK_EN;
 
187
                        pr_debug("%s: clk of is output\n", __func__);
 
188
                } else {
 
189
                        scr &= ~SSI_SCR_SYS_CLK_EN;
 
190
                        pr_debug("%s: clk of is input\n", __func__);
 
191
                }
 
192
                break;
 
193
        default:
 
194
                return -EINVAL;
 
195
        }
 
196
 
 
197
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
198
                pr_debug("%s: writeback of SSI1_SCR\n", __func__);
 
199
                SSI1_SCR = scr;
 
200
        } else {
 
201
                pr_debug("%s: writeback of SSI2_SCR\n", __func__);
 
202
                SSI2_SCR = scr;
 
203
        }
 
204
 
 
205
        return 0;
 
206
}
 
207
 
 
208
/*
 
209
 * SSI Clock dividers
 
210
 * Should only be called when port is inactive (i.e. SSIEN = 0).
 
211
 */
 
212
static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 
213
        int div_id, int div)
 
214
{
 
215
        u32 stccr, srccr;
 
216
 
 
217
        pr_debug("%s\n", __func__);
 
218
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
219
                if (SSI1_SCR & SSI_SCR_SSIEN)
 
220
                        return 0;
 
221
                srccr = SSI1_STCCR;
 
222
                stccr = SSI1_STCCR;
 
223
        } else {
 
224
                if (SSI2_SCR & SSI_SCR_SSIEN)
 
225
                        return 0;
 
226
                srccr = SSI2_STCCR;
 
227
                stccr = SSI2_STCCR;
 
228
        }
 
229
 
 
230
        switch (div_id) {
 
231
        case IMX_SSI_TX_DIV_2:
 
232
                stccr &= ~SSI_STCCR_DIV2;
 
233
                stccr |= div;
 
234
                break;
 
235
        case IMX_SSI_TX_DIV_PSR:
 
236
                stccr &= ~SSI_STCCR_PSR;
 
237
                stccr |= div;
 
238
                break;
 
239
        case IMX_SSI_TX_DIV_PM:
 
240
                stccr &= ~0xff;
 
241
                stccr |= SSI_STCCR_PM(div);
 
242
                break;
 
243
        case IMX_SSI_RX_DIV_2:
 
244
                stccr &= ~SSI_STCCR_DIV2;
 
245
                stccr |= div;
 
246
                break;
 
247
        case IMX_SSI_RX_DIV_PSR:
 
248
                stccr &= ~SSI_STCCR_PSR;
 
249
                stccr |= div;
 
250
                break;
 
251
        case IMX_SSI_RX_DIV_PM:
 
252
                stccr &= ~0xff;
 
253
                stccr |= SSI_STCCR_PM(div);
 
254
                break;
 
255
        default:
 
256
                return -EINVAL;
 
257
        }
 
258
 
 
259
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
260
                SSI1_STCCR = stccr;
 
261
                SSI1_SRCCR = srccr;
 
262
        } else {
 
263
                SSI2_STCCR = stccr;
 
264
                SSI2_SRCCR = srccr;
 
265
        }
 
266
        return 0;
 
267
}
 
268
 
 
269
/*
 
270
 * SSI Network Mode or TDM slots configuration.
 
271
 * Should only be called when port is inactive (i.e. SSIEN = 0).
 
272
 */
 
273
static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 
274
        unsigned int mask, int slots)
 
275
{
 
276
        u32 stmsk, srmsk, stccr;
 
277
 
 
278
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
279
                if (SSI1_SCR & SSI_SCR_SSIEN) {
 
280
                        printk(KERN_WARNING "Warning ssi already enabled\n");
 
281
                        return 0;
 
282
                }
 
283
                stccr = SSI1_STCCR;
 
284
        } else {
 
285
                if (SSI2_SCR & SSI_SCR_SSIEN) {
 
286
                        printk(KERN_WARNING "Warning ssi already enabled\n");
 
287
                        return 0;
 
288
                }
 
289
                stccr = SSI2_STCCR;
 
290
        }
 
291
 
 
292
        stmsk = srmsk = mask;
 
293
        stccr &= ~SSI_STCCR_DC_MASK;
 
294
        stccr |= SSI_STCCR_DC(slots - 1);
 
295
 
 
296
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
297
                SSI1_STMSK = stmsk;
 
298
                SSI1_SRMSK = srmsk;
 
299
                SSI1_SRCCR = SSI1_STCCR = stccr;
 
300
        } else {
 
301
                SSI2_STMSK = stmsk;
 
302
                SSI2_SRMSK = srmsk;
 
303
                SSI2_SRCCR = SSI2_STCCR = stccr;
 
304
        }
 
305
 
 
306
        return 0;
 
307
}
 
308
 
 
309
/*
 
310
 * SSI DAI format configuration.
 
311
 * Should only be called when port is inactive (i.e. SSIEN = 0).
 
312
 * Note: We don't use the I2S modes but instead manually configure the
 
313
 * SSI for I2S.
 
314
 */
 
315
static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
316
                unsigned int fmt)
 
317
{
 
318
        u32 stcr = 0, srcr = 0, scr;
 
319
 
 
320
        /*
 
321
         * This is done to avoid this function to modify
 
322
         * previous set values in stcr
 
323
         */
 
324
        stcr = SSI1_STCR;
 
325
 
 
326
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 
327
                scr = SSI1_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET);
 
328
        else
 
329
                scr = SSI2_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET);
 
330
 
 
331
        if (scr & SSI_SCR_SSIEN) {
 
332
                printk(KERN_WARNING "Warning ssi already enabled\n");
 
333
                return 0;
 
334
        }
 
335
 
 
336
        /* DAI mode */
 
337
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 
338
        case SND_SOC_DAIFMT_I2S:
 
339
                /* data on rising edge of bclk, frame low 1clk before data */
 
340
                stcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
 
341
                srcr |= SSI_SRCR_RFSI | SSI_SRCR_REFS | SSI_SRCR_RXBIT0;
 
342
                break;
 
343
        case SND_SOC_DAIFMT_LEFT_J:
 
344
                /* data on rising edge of bclk, frame high with data */
 
345
                stcr |= SSI_STCR_TXBIT0;
 
346
                srcr |= SSI_SRCR_RXBIT0;
 
347
                break;
 
348
        case SND_SOC_DAIFMT_DSP_B:
 
349
                /* data on rising edge of bclk, frame high with data */
 
350
                stcr |= SSI_STCR_TFSL;
 
351
                srcr |= SSI_SRCR_RFSL;
 
352
                break;
 
353
        case SND_SOC_DAIFMT_DSP_A:
 
354
                /* data on rising edge of bclk, frame high 1clk before data */
 
355
                stcr |= SSI_STCR_TFSL | SSI_STCR_TEFS;
 
356
                srcr |= SSI_SRCR_RFSL | SSI_SRCR_REFS;
 
357
                break;
 
358
        }
 
359
 
 
360
        /* DAI clock inversion */
 
361
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 
362
        case SND_SOC_DAIFMT_IB_IF:
 
363
                stcr |= SSI_STCR_TFSI;
 
364
                stcr &= ~SSI_STCR_TSCKP;
 
365
                srcr |= SSI_SRCR_RFSI;
 
366
                srcr &= ~SSI_SRCR_RSCKP;
 
367
                break;
 
368
        case SND_SOC_DAIFMT_IB_NF:
 
369
                stcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
 
370
                srcr &= ~(SSI_SRCR_RSCKP | SSI_SRCR_RFSI);
 
371
                break;
 
372
        case SND_SOC_DAIFMT_NB_IF:
 
373
                stcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
 
374
                srcr |= SSI_SRCR_RFSI | SSI_SRCR_RSCKP;
 
375
                break;
 
376
        case SND_SOC_DAIFMT_NB_NF:
 
377
                stcr &= ~SSI_STCR_TFSI;
 
378
                stcr |= SSI_STCR_TSCKP;
 
379
                srcr &= ~SSI_SRCR_RFSI;
 
380
                srcr |= SSI_SRCR_RSCKP;
 
381
                break;
 
382
        }
 
383
 
 
384
        /* DAI clock master masks */
 
385
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 
386
        case SND_SOC_DAIFMT_CBS_CFS:
 
387
                stcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR;
 
388
                srcr |= SSI_SRCR_RFDIR | SSI_SRCR_RXDIR;
 
389
                break;
 
390
        case SND_SOC_DAIFMT_CBM_CFS:
 
391
                stcr |= SSI_STCR_TFDIR;
 
392
                srcr |= SSI_SRCR_RFDIR;
 
393
                break;
 
394
        case SND_SOC_DAIFMT_CBS_CFM:
 
395
                stcr |= SSI_STCR_TXDIR;
 
396
                srcr |= SSI_SRCR_RXDIR;
 
397
                break;
 
398
        }
 
399
 
 
400
        /* sync */
 
401
        if (!(fmt & SND_SOC_DAIFMT_ASYNC))
 
402
                scr |= SSI_SCR_SYN;
 
403
 
 
404
        /* tdm - only for stereo atm */
 
405
        if (fmt & SND_SOC_DAIFMT_TDM)
 
406
                scr |= SSI_SCR_NET;
 
407
 
 
408
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
409
                SSI1_STCR = stcr;
 
410
                SSI1_SRCR = srcr;
 
411
                SSI1_SCR = scr;
 
412
        } else {
 
413
                SSI2_STCR = stcr;
 
414
                SSI2_SRCR = srcr;
 
415
                SSI2_SCR = scr;
 
416
        }
 
417
 
 
418
        return 0;
 
419
}
 
420
 
 
421
static int imx_ssi_startup(struct snd_pcm_substream *substream,
 
422
                        struct snd_soc_dai *dai)
 
423
{
 
424
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
425
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
426
 
 
427
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 
428
                /* set up TX DMA params */
 
429
                switch (cpu_dai->id) {
 
430
                case IMX_DAI_SSI0:
 
431
                        cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out0;
 
432
                        break;
 
433
                case IMX_DAI_SSI1:
 
434
                        cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out1;
 
435
                        break;
 
436
                case IMX_DAI_SSI2:
 
437
                        cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out0;
 
438
                        break;
 
439
                case IMX_DAI_SSI3:
 
440
                        cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out1;
 
441
                }
 
442
                pr_debug("%s: (playback)\n", __func__);
 
443
        } else {
 
444
                /* set up RX DMA params */
 
445
                switch (cpu_dai->id) {
 
446
                case IMX_DAI_SSI0:
 
447
                        cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in0;
 
448
                        break;
 
449
                case IMX_DAI_SSI1:
 
450
                        cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in1;
 
451
                        break;
 
452
                case IMX_DAI_SSI2:
 
453
                        cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in0;
 
454
                        break;
 
455
                case IMX_DAI_SSI3:
 
456
                        cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in1;
 
457
                }
 
458
                pr_debug("%s: (capture)\n", __func__);
 
459
        }
 
460
 
 
461
        /*
 
462
         * we cant really change any SSI values after SSI is enabled
 
463
         * need to fix in software for max flexibility - lrg
 
464
         */
 
465
        if (cpu_dai->active) {
 
466
                printk(KERN_WARNING "Warning ssi already enabled\n");
 
467
                return 0;
 
468
        }
 
469
 
 
470
        /* reset the SSI port - Sect 45.4.4 */
 
471
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
472
 
 
473
                if (!ssi_clk0)
 
474
                        return -EINVAL;
 
475
 
 
476
                if (ssi_active[SSI1_PORT]++) {
 
477
                        pr_debug("%s: exit before reset\n", __func__);
 
478
                        return 0;
 
479
                }
 
480
 
 
481
                /* SSI1 Reset */
 
482
                SSI1_SCR = 0;
 
483
 
 
484
                SSI1_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) |
 
485
                        SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) |
 
486
                        SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) |
 
487
                        SSI_SFCSR_TFWM0(TXFIFO_WATERMARK);
 
488
        } else {
 
489
 
 
490
                if (!ssi_clk1)
 
491
                        return -EINVAL;
 
492
 
 
493
                if (ssi_active[SSI2_PORT]++) {
 
494
                        pr_debug("%s: exit before reset\n", __func__);
 
495
                        return 0;
 
496
                }
 
497
 
 
498
                /* SSI2 Reset */
 
499
                SSI2_SCR = 0;
 
500
 
 
501
                SSI2_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) |
 
502
                        SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) |
 
503
                        SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) |
 
504
                        SSI_SFCSR_TFWM0(TXFIFO_WATERMARK);
 
505
        }
 
506
 
 
507
        return 0;
 
508
}
 
509
 
 
510
int imx_ssi_hw_tx_params(struct snd_pcm_substream *substream,
 
511
                                struct snd_pcm_hw_params *params)
 
512
{
 
513
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
514
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
515
        u32 stccr, stcr, sier;
 
516
 
 
517
        pr_debug("%s\n", __func__);
 
518
 
 
519
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
520
                stccr = SSI1_STCCR & ~SSI_STCCR_WL_MASK;
 
521
                stcr = SSI1_STCR;
 
522
                sier = SSI1_SIER;
 
523
        } else {
 
524
                stccr = SSI2_STCCR & ~SSI_STCCR_WL_MASK;
 
525
                stcr = SSI2_STCR;
 
526
                sier = SSI2_SIER;
 
527
        }
 
528
 
 
529
        /* DAI data (word) size */
 
530
        switch (params_format(params)) {
 
531
        case SNDRV_PCM_FORMAT_S16_LE:
 
532
                stccr |= SSI_STCCR_WL(16);
 
533
                break;
 
534
        case SNDRV_PCM_FORMAT_S20_3LE:
 
535
                stccr |= SSI_STCCR_WL(20);
 
536
                break;
 
537
        case SNDRV_PCM_FORMAT_S24_LE:
 
538
                stccr |= SSI_STCCR_WL(24);
 
539
                break;
 
540
        }
 
541
 
 
542
        /* enable interrupts */
 
543
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 
544
                stcr |= SSI_STCR_TFEN0;
 
545
        else
 
546
                stcr |= SSI_STCR_TFEN1;
 
547
        sier |= SSI_SIER_TDMAE;
 
548
 
 
549
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
550
                SSI1_STCR = stcr;
 
551
                SSI1_STCCR = stccr;
 
552
                SSI1_SIER = sier;
 
553
        } else {
 
554
                SSI2_STCR = stcr;
 
555
                SSI2_STCCR = stccr;
 
556
                SSI2_SIER = sier;
 
557
        }
 
558
 
 
559
        return 0;
 
560
}
 
561
 
 
562
int imx_ssi_hw_rx_params(struct snd_pcm_substream *substream,
 
563
                                struct snd_pcm_hw_params *params)
 
564
{
 
565
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
566
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
567
        u32 srccr, srcr, sier;
 
568
 
 
569
        pr_debug("%s\n", __func__);
 
570
 
 
571
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
572
                srccr = SSI1_SRCCR & ~SSI_SRCCR_WL_MASK;
 
573
                srcr = SSI1_SRCR;
 
574
                sier = SSI1_SIER;
 
575
        } else {
 
576
                srccr = SSI2_SRCCR & ~SSI_SRCCR_WL_MASK;
 
577
                srcr = SSI2_SRCR;
 
578
                sier = SSI2_SIER;
 
579
        }
 
580
 
 
581
        /* DAI data (word) size */
 
582
        switch (params_format(params)) {
 
583
        case SNDRV_PCM_FORMAT_S16_LE:
 
584
                srccr |= SSI_SRCCR_WL(16);
 
585
                break;
 
586
        case SNDRV_PCM_FORMAT_S20_3LE:
 
587
                srccr |= SSI_SRCCR_WL(20);
 
588
                break;
 
589
        case SNDRV_PCM_FORMAT_S24_LE:
 
590
                srccr |= SSI_SRCCR_WL(24);
 
591
                break;
 
592
        }
 
593
 
 
594
        /* enable interrupts */
 
595
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 
596
                srcr |= SSI_SRCR_RFEN0;
 
597
        else
 
598
                srcr |= SSI_SRCR_RFEN1;
 
599
        sier |= SSI_SIER_RDMAE;
 
600
 
 
601
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
602
                SSI1_SRCR = srcr;
 
603
                SSI1_SRCCR = srccr;
 
604
                SSI1_SIER = sier;
 
605
        } else {
 
606
                SSI2_SRCR = srcr;
 
607
                SSI2_SRCCR = srccr;
 
608
                SSI2_SIER = sier;
 
609
        }
 
610
 
 
611
        return 0;
 
612
}
 
613
 
 
614
/*
 
615
 * Should only be called when port is inactive (i.e. SSIEN = 0),
 
616
 * although can be called multiple times by upper layers.
 
617
 */
 
618
int imx_ssi_hw_params(struct snd_pcm_substream *substream,
 
619
                                struct snd_pcm_hw_params *params,
 
620
                                struct snd_soc_dai *dai)
 
621
{
 
622
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
623
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
624
 
 
625
        int ret;
 
626
 
 
627
        /* cant change any parameters when SSI is running */
 
628
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
629
                if (SSI1_SCR & SSI_SCR_SSIEN) {
 
630
                        printk(KERN_WARNING "Warning ssi already enabled\n");
 
631
                        return 0;
 
632
                }
 
633
        } else {
 
634
                if (SSI2_SCR & SSI_SCR_SSIEN) {
 
635
                        printk(KERN_WARNING "Warning ssi already enabled\n");
 
636
                        return 0;
 
637
                }
 
638
        }
 
639
 
 
640
        /*
 
641
         * Configure both tx and rx params with the same settings. This is
 
642
         * really a harware restriction because SSI must be disabled until
 
643
         * we can change those values. If there is an active audio stream in
 
644
         * one direction, enabling the other direction with different
 
645
         * settings would mean disturbing the running one.
 
646
         */
 
647
        ret = imx_ssi_hw_tx_params(substream, params);
 
648
        if (ret < 0)
 
649
                return ret;
 
650
        return imx_ssi_hw_rx_params(substream, params);
 
651
}
 
652
 
 
653
int imx_ssi_prepare(struct snd_pcm_substream *substream,
 
654
                        struct snd_soc_dai *dai)
 
655
{
 
656
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
657
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
658
        int ret;
 
659
 
 
660
        pr_debug("%s\n", __func__);
 
661
 
 
662
        /* Enable clks here to follow SSI recommended init sequence */
 
663
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
 
664
                ret = clk_enable(ssi_clk0);
 
665
                if (ret < 0)
 
666
                        printk(KERN_ERR "Unable to enable ssi_clk0\n");
 
667
        } else {
 
668
                ret = clk_enable(ssi_clk1);
 
669
                if (ret < 0)
 
670
                        printk(KERN_ERR "Unable to enable ssi_clk1\n");
 
671
        }
 
672
 
 
673
        return 0;
 
674
}
 
675
 
 
676
static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
 
677
                        struct snd_soc_dai *dai)
 
678
{
 
679
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
680
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
681
        u32 scr;
 
682
 
 
683
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 
684
                scr = SSI1_SCR;
 
685
        else
 
686
                scr = SSI2_SCR;
 
687
 
 
688
        switch (cmd) {
 
689
        case SNDRV_PCM_TRIGGER_START:
 
690
        case SNDRV_PCM_TRIGGER_RESUME:
 
691
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 
692
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 
693
                        scr |= SSI_SCR_TE | SSI_SCR_SSIEN;
 
694
                else
 
695
                        scr |= SSI_SCR_RE | SSI_SCR_SSIEN;
 
696
                break;
 
697
        case SNDRV_PCM_TRIGGER_SUSPEND:
 
698
        case SNDRV_PCM_TRIGGER_STOP:
 
699
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 
700
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 
701
                        scr &= ~SSI_SCR_TE;
 
702
                else
 
703
                        scr &= ~SSI_SCR_RE;
 
704
                break;
 
705
        default:
 
706
                return -EINVAL;
 
707
        }
 
708
 
 
709
        if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
 
710
                SSI1_SCR = scr;
 
711
        else
 
712
                SSI2_SCR = scr;
 
713
 
 
714
        return 0;
 
715
}
 
716
 
 
717
static void imx_ssi_shutdown(struct snd_pcm_substream *substream,
 
718
                        struct snd_soc_dai *dai)
 
719
{
 
720
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
721
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
722
 
 
723
        /* shutdown SSI if neither Tx or Rx is active */
 
724
        if (!cpu_dai->active) {
 
725
 
 
726
                if (cpu_dai->id == IMX_DAI_SSI0 ||
 
727
                        cpu_dai->id == IMX_DAI_SSI2) {
 
728
 
 
729
                        if (--ssi_active[SSI1_PORT] > 1)
 
730
                                return;
 
731
 
 
732
                        SSI1_SCR = 0;
 
733
                        clk_disable(ssi_clk0);
 
734
                } else {
 
735
                        if (--ssi_active[SSI2_PORT])
 
736
                                return;
 
737
                        SSI2_SCR = 0;
 
738
                        clk_disable(ssi_clk1);
 
739
                }
 
740
        }
 
741
}
 
742
 
 
743
#ifdef CONFIG_PM
 
744
static int imx_ssi_suspend(struct platform_device *dev,
 
745
        struct snd_soc_dai *dai)
 
746
{
 
747
        return 0;
 
748
}
 
749
 
 
750
static int imx_ssi_resume(struct platform_device *pdev,
 
751
        struct snd_soc_dai *dai)
 
752
{
 
753
        return 0;
 
754
}
 
755
 
 
756
#else
 
757
#define imx_ssi_suspend NULL
 
758
#define imx_ssi_resume  NULL
 
759
#endif
 
760
 
 
761
#define IMX_SSI_RATES \
 
762
        (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
 
763
        SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
 
764
        SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
 
765
        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
 
766
        SNDRV_PCM_RATE_96000)
 
767
 
 
768
#define IMX_SSI_BITS \
 
769
        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 
770
        SNDRV_PCM_FMTBIT_S24_LE)
 
771
 
 
772
static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
 
773
        .startup = imx_ssi_startup,
 
774
        .shutdown = imx_ssi_shutdown,
 
775
        .trigger = imx_ssi_trigger,
 
776
        .prepare = imx_ssi_prepare,
 
777
        .hw_params = imx_ssi_hw_params,
 
778
        .set_sysclk = imx_ssi_set_dai_sysclk,
 
779
        .set_clkdiv = imx_ssi_set_dai_clkdiv,
 
780
        .set_fmt = imx_ssi_set_dai_fmt,
 
781
        .set_tdm_slot = imx_ssi_set_dai_tdm_slot,
 
782
};
 
783
 
 
784
struct snd_soc_dai imx_ssi_pcm_dai[] = {
 
785
{
 
786
        .name = "imx-i2s-1-0",
 
787
        .id = IMX_DAI_SSI0,
 
788
        .suspend = imx_ssi_suspend,
 
789
        .resume = imx_ssi_resume,
 
790
        .playback = {
 
791
                .channels_min = 1,
 
792
                .channels_max = 2,
 
793
                .formats = IMX_SSI_BITS,
 
794
                .rates = IMX_SSI_RATES,},
 
795
        .capture = {
 
796
                .channels_min = 1,
 
797
                .channels_max = 2,
 
798
                .formats = IMX_SSI_BITS,
 
799
                .rates = IMX_SSI_RATES,},
 
800
        .ops = &imx_ssi_pcm_dai_ops,
 
801
},
 
802
{
 
803
        .name = "imx-i2s-2-0",
 
804
        .id = IMX_DAI_SSI1,
 
805
        .playback = {
 
806
                .channels_min = 1,
 
807
                .channels_max = 2,
 
808
                .formats = IMX_SSI_BITS,
 
809
                .rates = IMX_SSI_RATES,},
 
810
        .capture = {
 
811
                .channels_min = 1,
 
812
                .channels_max = 2,
 
813
                .formats = IMX_SSI_BITS,
 
814
                .rates = IMX_SSI_RATES,},
 
815
        .ops = &imx_ssi_pcm_dai_ops,
 
816
},
 
817
{
 
818
        .name = "imx-i2s-1-1",
 
819
        .id = IMX_DAI_SSI2,
 
820
        .suspend = imx_ssi_suspend,
 
821
        .resume = imx_ssi_resume,
 
822
        .playback = {
 
823
                .channels_min = 1,
 
824
                .channels_max = 2,
 
825
                .formats = IMX_SSI_BITS,
 
826
                .rates = IMX_SSI_RATES,},
 
827
        .capture = {
 
828
                .channels_min = 1,
 
829
                .channels_max = 2,
 
830
                .formats = IMX_SSI_BITS,
 
831
                .rates = IMX_SSI_RATES,},
 
832
        .ops = &imx_ssi_pcm_dai_ops,
 
833
},
 
834
{
 
835
        .name = "imx-i2s-2-1",
 
836
        .id = IMX_DAI_SSI3,
 
837
        .playback = {
 
838
                .channels_min = 1,
 
839
                .channels_max = 2,
 
840
                .formats = IMX_SSI_BITS,
 
841
                .rates = IMX_SSI_RATES,},
 
842
        .capture = {
 
843
                .channels_min = 1,
 
844
                .channels_max = 2,
 
845
                .formats = IMX_SSI_BITS,
 
846
                .rates = IMX_SSI_RATES,},
 
847
        .ops = &imx_ssi_pcm_dai_ops,
 
848
},
 
849
};
 
850
EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
 
851
 
 
852
static int __init imx_ssi_init(void)
 
853
{
 
854
        return snd_soc_register_dais(imx_ssi_pcm_dai,
 
855
                                ARRAY_SIZE(imx_ssi_pcm_dai));
 
856
}
 
857
 
 
858
static void __exit imx_ssi_exit(void)
 
859
{
 
860
        snd_soc_unregister_dais(imx_ssi_pcm_dai,
 
861
                                ARRAY_SIZE(imx_ssi_pcm_dai));
 
862
}
 
863
 
 
864
module_init(imx_ssi_init);
 
865
module_exit(imx_ssi_exit);
 
866
MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com");
 
867
MODULE_DESCRIPTION("i.MX ASoC I2S driver");
 
868
MODULE_LICENSE("GPL");