Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/soc/imx/imx-ssi.c
10817 views
1
/*
2
* imx-ssi.c -- ALSA Soc Audio Layer
3
*
4
* Copyright 2009 Sascha Hauer <[email protected]>
5
*
6
* This code is based on code copyrighted by Freescale,
7
* Liam Girdwood, Javier Martin and probably others.
8
*
9
* This program is free software; you can redistribute it and/or modify it
10
* under the terms of the GNU General Public License as published by the
11
* Free Software Foundation; either version 2 of the License, or (at your
12
* option) any later version.
13
*
14
*
15
* The i.MX SSI core has some nasty limitations in AC97 mode. While most
16
* sane processor vendors have a FIFO per AC97 slot, the i.MX has only
17
* one FIFO which combines all valid receive slots. We cannot even select
18
* which slots we want to receive. The WM9712 with which this driver
19
* was developed with always sends GPIO status data in slot 12 which
20
* we receive in our (PCM-) data stream. The only chance we have is to
21
* manually skip this data in the FIQ handler. With sampling rates different
22
* from 48000Hz not every frame has valid receive data, so the ratio
23
* between pcm data and GPIO status data changes. Our FIQ handler is not
24
* able to handle this, hence this driver only works with 48000Hz sampling
25
* rate.
26
* Reading and writing AC97 registers is another challenge. The core
27
* provides us status bits when the read register is updated with *another*
28
* value. When we read the same register two times (and the register still
29
* contains the same value) these status bits are not set. We work
30
* around this by not polling these bits but only wait a fixed delay.
31
*
32
*/
33
34
#include <linux/clk.h>
35
#include <linux/delay.h>
36
#include <linux/device.h>
37
#include <linux/dma-mapping.h>
38
#include <linux/init.h>
39
#include <linux/interrupt.h>
40
#include <linux/module.h>
41
#include <linux/platform_device.h>
42
#include <linux/slab.h>
43
44
#include <sound/core.h>
45
#include <sound/initval.h>
46
#include <sound/pcm.h>
47
#include <sound/pcm_params.h>
48
#include <sound/soc.h>
49
50
#include <mach/ssi.h>
51
#include <mach/hardware.h>
52
53
#include "imx-ssi.h"
54
55
#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
56
57
/*
58
* SSI Network Mode or TDM slots configuration.
59
* Should only be called when port is inactive (i.e. SSIEN = 0).
60
*/
61
static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
62
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
63
{
64
struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
65
u32 sccr;
66
67
sccr = readl(ssi->base + SSI_STCCR);
68
sccr &= ~SSI_STCCR_DC_MASK;
69
sccr |= SSI_STCCR_DC(slots - 1);
70
writel(sccr, ssi->base + SSI_STCCR);
71
72
sccr = readl(ssi->base + SSI_SRCCR);
73
sccr &= ~SSI_STCCR_DC_MASK;
74
sccr |= SSI_STCCR_DC(slots - 1);
75
writel(sccr, ssi->base + SSI_SRCCR);
76
77
writel(tx_mask, ssi->base + SSI_STMSK);
78
writel(rx_mask, ssi->base + SSI_SRMSK);
79
80
return 0;
81
}
82
83
/*
84
* SSI DAI format configuration.
85
* Should only be called when port is inactive (i.e. SSIEN = 0).
86
*/
87
static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
88
{
89
struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
90
u32 strcr = 0, scr;
91
92
scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
93
94
/* DAI mode */
95
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
96
case SND_SOC_DAIFMT_I2S:
97
/* data on rising edge of bclk, frame low 1clk before data */
98
strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
99
scr |= SSI_SCR_NET;
100
if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
101
scr &= ~SSI_I2S_MODE_MASK;
102
scr |= SSI_SCR_I2S_MODE_SLAVE;
103
}
104
break;
105
case SND_SOC_DAIFMT_LEFT_J:
106
/* data on rising edge of bclk, frame high with data */
107
strcr |= SSI_STCR_TXBIT0;
108
break;
109
case SND_SOC_DAIFMT_DSP_B:
110
/* data on rising edge of bclk, frame high with data */
111
strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0;
112
break;
113
case SND_SOC_DAIFMT_DSP_A:
114
/* data on rising edge of bclk, frame high 1clk before data */
115
strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS;
116
break;
117
}
118
119
/* DAI clock inversion */
120
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
121
case SND_SOC_DAIFMT_IB_IF:
122
strcr |= SSI_STCR_TFSI;
123
strcr &= ~SSI_STCR_TSCKP;
124
break;
125
case SND_SOC_DAIFMT_IB_NF:
126
strcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
127
break;
128
case SND_SOC_DAIFMT_NB_IF:
129
strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
130
break;
131
case SND_SOC_DAIFMT_NB_NF:
132
strcr &= ~SSI_STCR_TFSI;
133
strcr |= SSI_STCR_TSCKP;
134
break;
135
}
136
137
/* DAI clock master masks */
138
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
139
case SND_SOC_DAIFMT_CBM_CFM:
140
break;
141
default:
142
/* Master mode not implemented, needs handling of clocks. */
143
return -EINVAL;
144
}
145
146
strcr |= SSI_STCR_TFEN0;
147
148
if (ssi->flags & IMX_SSI_NET)
149
scr |= SSI_SCR_NET;
150
if (ssi->flags & IMX_SSI_SYN)
151
scr |= SSI_SCR_SYN;
152
153
writel(strcr, ssi->base + SSI_STCR);
154
writel(strcr, ssi->base + SSI_SRCR);
155
writel(scr, ssi->base + SSI_SCR);
156
157
return 0;
158
}
159
160
/*
161
* SSI system clock configuration.
162
* Should only be called when port is inactive (i.e. SSIEN = 0).
163
*/
164
static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
165
int clk_id, unsigned int freq, int dir)
166
{
167
struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
168
u32 scr;
169
170
scr = readl(ssi->base + SSI_SCR);
171
172
switch (clk_id) {
173
case IMX_SSP_SYS_CLK:
174
if (dir == SND_SOC_CLOCK_OUT)
175
scr |= SSI_SCR_SYS_CLK_EN;
176
else
177
scr &= ~SSI_SCR_SYS_CLK_EN;
178
break;
179
default:
180
return -EINVAL;
181
}
182
183
writel(scr, ssi->base + SSI_SCR);
184
185
return 0;
186
}
187
188
/*
189
* SSI Clock dividers
190
* Should only be called when port is inactive (i.e. SSIEN = 0).
191
*/
192
static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
193
int div_id, int div)
194
{
195
struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
196
u32 stccr, srccr;
197
198
stccr = readl(ssi->base + SSI_STCCR);
199
srccr = readl(ssi->base + SSI_SRCCR);
200
201
switch (div_id) {
202
case IMX_SSI_TX_DIV_2:
203
stccr &= ~SSI_STCCR_DIV2;
204
stccr |= div;
205
break;
206
case IMX_SSI_TX_DIV_PSR:
207
stccr &= ~SSI_STCCR_PSR;
208
stccr |= div;
209
break;
210
case IMX_SSI_TX_DIV_PM:
211
stccr &= ~0xff;
212
stccr |= SSI_STCCR_PM(div);
213
break;
214
case IMX_SSI_RX_DIV_2:
215
stccr &= ~SSI_STCCR_DIV2;
216
stccr |= div;
217
break;
218
case IMX_SSI_RX_DIV_PSR:
219
stccr &= ~SSI_STCCR_PSR;
220
stccr |= div;
221
break;
222
case IMX_SSI_RX_DIV_PM:
223
stccr &= ~0xff;
224
stccr |= SSI_STCCR_PM(div);
225
break;
226
default:
227
return -EINVAL;
228
}
229
230
writel(stccr, ssi->base + SSI_STCCR);
231
writel(srccr, ssi->base + SSI_SRCCR);
232
233
return 0;
234
}
235
236
/*
237
* Should only be called when port is inactive (i.e. SSIEN = 0),
238
* although can be called multiple times by upper layers.
239
*/
240
static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
241
struct snd_pcm_hw_params *params,
242
struct snd_soc_dai *cpu_dai)
243
{
244
struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
245
struct imx_pcm_dma_params *dma_data;
246
u32 reg, sccr;
247
248
/* Tx/Rx config */
249
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
250
reg = SSI_STCCR;
251
dma_data = &ssi->dma_params_tx;
252
} else {
253
reg = SSI_SRCCR;
254
dma_data = &ssi->dma_params_rx;
255
}
256
257
if (ssi->flags & IMX_SSI_SYN)
258
reg = SSI_STCCR;
259
260
snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
261
262
sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
263
264
/* DAI data (word) size */
265
switch (params_format(params)) {
266
case SNDRV_PCM_FORMAT_S16_LE:
267
sccr |= SSI_SRCCR_WL(16);
268
break;
269
case SNDRV_PCM_FORMAT_S20_3LE:
270
sccr |= SSI_SRCCR_WL(20);
271
break;
272
case SNDRV_PCM_FORMAT_S24_LE:
273
sccr |= SSI_SRCCR_WL(24);
274
break;
275
}
276
277
writel(sccr, ssi->base + reg);
278
279
return 0;
280
}
281
282
static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
283
struct snd_soc_dai *dai)
284
{
285
struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
286
unsigned int sier_bits, sier;
287
unsigned int scr;
288
289
scr = readl(ssi->base + SSI_SCR);
290
sier = readl(ssi->base + SSI_SIER);
291
292
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
293
if (ssi->flags & IMX_SSI_DMA)
294
sier_bits = SSI_SIER_TDMAE;
295
else
296
sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
297
} else {
298
if (ssi->flags & IMX_SSI_DMA)
299
sier_bits = SSI_SIER_RDMAE;
300
else
301
sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
302
}
303
304
switch (cmd) {
305
case SNDRV_PCM_TRIGGER_START:
306
case SNDRV_PCM_TRIGGER_RESUME:
307
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
308
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
309
scr |= SSI_SCR_TE;
310
else
311
scr |= SSI_SCR_RE;
312
sier |= sier_bits;
313
314
if (++ssi->enabled == 1)
315
scr |= SSI_SCR_SSIEN;
316
317
break;
318
319
case SNDRV_PCM_TRIGGER_STOP:
320
case SNDRV_PCM_TRIGGER_SUSPEND:
321
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
322
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
323
scr &= ~SSI_SCR_TE;
324
else
325
scr &= ~SSI_SCR_RE;
326
sier &= ~sier_bits;
327
328
if (--ssi->enabled == 0)
329
scr &= ~SSI_SCR_SSIEN;
330
331
break;
332
default:
333
return -EINVAL;
334
}
335
336
if (!(ssi->flags & IMX_SSI_USE_AC97))
337
/* rx/tx are always enabled to access ac97 registers */
338
writel(scr, ssi->base + SSI_SCR);
339
340
writel(sier, ssi->base + SSI_SIER);
341
342
return 0;
343
}
344
345
static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
346
.hw_params = imx_ssi_hw_params,
347
.set_fmt = imx_ssi_set_dai_fmt,
348
.set_clkdiv = imx_ssi_set_dai_clkdiv,
349
.set_sysclk = imx_ssi_set_dai_sysclk,
350
.set_tdm_slot = imx_ssi_set_dai_tdm_slot,
351
.trigger = imx_ssi_trigger,
352
};
353
354
int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
355
struct vm_area_struct *vma)
356
{
357
struct snd_pcm_runtime *runtime = substream->runtime;
358
int ret;
359
360
ret = dma_mmap_coherent(NULL, vma, runtime->dma_area,
361
runtime->dma_addr, runtime->dma_bytes);
362
363
pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
364
runtime->dma_area,
365
runtime->dma_addr,
366
runtime->dma_bytes);
367
return ret;
368
}
369
EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
370
371
static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
372
{
373
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
374
struct snd_dma_buffer *buf = &substream->dma_buffer;
375
size_t size = IMX_SSI_DMABUF_SIZE;
376
377
buf->dev.type = SNDRV_DMA_TYPE_DEV;
378
buf->dev.dev = pcm->card->dev;
379
buf->private_data = NULL;
380
buf->area = dma_alloc_writecombine(pcm->card->dev, size,
381
&buf->addr, GFP_KERNEL);
382
if (!buf->area)
383
return -ENOMEM;
384
buf->bytes = size;
385
386
return 0;
387
}
388
389
static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
390
391
int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
392
struct snd_pcm *pcm)
393
{
394
395
int ret = 0;
396
397
if (!card->dev->dma_mask)
398
card->dev->dma_mask = &imx_pcm_dmamask;
399
if (!card->dev->coherent_dma_mask)
400
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
401
if (dai->driver->playback.channels_min) {
402
ret = imx_pcm_preallocate_dma_buffer(pcm,
403
SNDRV_PCM_STREAM_PLAYBACK);
404
if (ret)
405
goto out;
406
}
407
408
if (dai->driver->capture.channels_min) {
409
ret = imx_pcm_preallocate_dma_buffer(pcm,
410
SNDRV_PCM_STREAM_CAPTURE);
411
if (ret)
412
goto out;
413
}
414
415
out:
416
return ret;
417
}
418
EXPORT_SYMBOL_GPL(imx_pcm_new);
419
420
void imx_pcm_free(struct snd_pcm *pcm)
421
{
422
struct snd_pcm_substream *substream;
423
struct snd_dma_buffer *buf;
424
int stream;
425
426
for (stream = 0; stream < 2; stream++) {
427
substream = pcm->streams[stream].substream;
428
if (!substream)
429
continue;
430
431
buf = &substream->dma_buffer;
432
if (!buf->area)
433
continue;
434
435
dma_free_writecombine(pcm->card->dev, buf->bytes,
436
buf->area, buf->addr);
437
buf->area = NULL;
438
}
439
}
440
EXPORT_SYMBOL_GPL(imx_pcm_free);
441
442
static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
443
{
444
struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
445
uint32_t val;
446
447
snd_soc_dai_set_drvdata(dai, ssi);
448
449
val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
450
SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
451
writel(val, ssi->base + SSI_SFCSR);
452
453
return 0;
454
}
455
456
static struct snd_soc_dai_driver imx_ssi_dai = {
457
.probe = imx_ssi_dai_probe,
458
.playback = {
459
.channels_min = 1,
460
.channels_max = 2,
461
.rates = SNDRV_PCM_RATE_8000_96000,
462
.formats = SNDRV_PCM_FMTBIT_S16_LE,
463
},
464
.capture = {
465
.channels_min = 1,
466
.channels_max = 2,
467
.rates = SNDRV_PCM_RATE_8000_96000,
468
.formats = SNDRV_PCM_FMTBIT_S16_LE,
469
},
470
.ops = &imx_ssi_pcm_dai_ops,
471
};
472
473
static struct snd_soc_dai_driver imx_ac97_dai = {
474
.probe = imx_ssi_dai_probe,
475
.ac97_control = 1,
476
.playback = {
477
.stream_name = "AC97 Playback",
478
.channels_min = 2,
479
.channels_max = 2,
480
.rates = SNDRV_PCM_RATE_48000,
481
.formats = SNDRV_PCM_FMTBIT_S16_LE,
482
},
483
.capture = {
484
.stream_name = "AC97 Capture",
485
.channels_min = 2,
486
.channels_max = 2,
487
.rates = SNDRV_PCM_RATE_48000,
488
.formats = SNDRV_PCM_FMTBIT_S16_LE,
489
},
490
.ops = &imx_ssi_pcm_dai_ops,
491
};
492
493
static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
494
{
495
void __iomem *base = imx_ssi->base;
496
497
writel(0x0, base + SSI_SCR);
498
writel(0x0, base + SSI_STCR);
499
writel(0x0, base + SSI_SRCR);
500
501
writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
502
503
writel(SSI_SFCSR_RFWM0(8) |
504
SSI_SFCSR_TFWM0(8) |
505
SSI_SFCSR_RFWM1(8) |
506
SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
507
508
writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
509
writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
510
511
writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
512
writel(SSI_SOR_WAIT(3), base + SSI_SOR);
513
514
writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
515
SSI_SCR_TE | SSI_SCR_RE,
516
base + SSI_SCR);
517
518
writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
519
writel(0xff, base + SSI_SACCDIS);
520
writel(0x300, base + SSI_SACCEN);
521
}
522
523
static struct imx_ssi *ac97_ssi;
524
525
static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
526
unsigned short val)
527
{
528
struct imx_ssi *imx_ssi = ac97_ssi;
529
void __iomem *base = imx_ssi->base;
530
unsigned int lreg;
531
unsigned int lval;
532
533
if (reg > 0x7f)
534
return;
535
536
pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
537
538
lreg = reg << 12;
539
writel(lreg, base + SSI_SACADD);
540
541
lval = val << 4;
542
writel(lval , base + SSI_SACDAT);
543
544
writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
545
udelay(100);
546
}
547
548
static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
549
unsigned short reg)
550
{
551
struct imx_ssi *imx_ssi = ac97_ssi;
552
void __iomem *base = imx_ssi->base;
553
554
unsigned short val = -1;
555
unsigned int lreg;
556
557
lreg = (reg & 0x7f) << 12 ;
558
writel(lreg, base + SSI_SACADD);
559
writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
560
561
udelay(100);
562
563
val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
564
565
pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
566
567
return val;
568
}
569
570
static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
571
{
572
struct imx_ssi *imx_ssi = ac97_ssi;
573
574
if (imx_ssi->ac97_reset)
575
imx_ssi->ac97_reset(ac97);
576
}
577
578
static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
579
{
580
struct imx_ssi *imx_ssi = ac97_ssi;
581
582
if (imx_ssi->ac97_warm_reset)
583
imx_ssi->ac97_warm_reset(ac97);
584
}
585
586
struct snd_ac97_bus_ops soc_ac97_ops = {
587
.read = imx_ssi_ac97_read,
588
.write = imx_ssi_ac97_write,
589
.reset = imx_ssi_ac97_reset,
590
.warm_reset = imx_ssi_ac97_warm_reset
591
};
592
EXPORT_SYMBOL_GPL(soc_ac97_ops);
593
594
static int imx_ssi_probe(struct platform_device *pdev)
595
{
596
struct resource *res;
597
struct imx_ssi *ssi;
598
struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
599
int ret = 0;
600
struct snd_soc_dai_driver *dai;
601
602
ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
603
if (!ssi)
604
return -ENOMEM;
605
dev_set_drvdata(&pdev->dev, ssi);
606
607
if (pdata) {
608
ssi->ac97_reset = pdata->ac97_reset;
609
ssi->ac97_warm_reset = pdata->ac97_warm_reset;
610
ssi->flags = pdata->flags;
611
}
612
613
ssi->irq = platform_get_irq(pdev, 0);
614
615
ssi->clk = clk_get(&pdev->dev, NULL);
616
if (IS_ERR(ssi->clk)) {
617
ret = PTR_ERR(ssi->clk);
618
dev_err(&pdev->dev, "Cannot get the clock: %d\n",
619
ret);
620
goto failed_clk;
621
}
622
clk_enable(ssi->clk);
623
624
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
625
if (!res) {
626
ret = -ENODEV;
627
goto failed_get_resource;
628
}
629
630
if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
631
dev_err(&pdev->dev, "request_mem_region failed\n");
632
ret = -EBUSY;
633
goto failed_get_resource;
634
}
635
636
ssi->base = ioremap(res->start, resource_size(res));
637
if (!ssi->base) {
638
dev_err(&pdev->dev, "ioremap failed\n");
639
ret = -ENODEV;
640
goto failed_ioremap;
641
}
642
643
if (ssi->flags & IMX_SSI_USE_AC97) {
644
if (ac97_ssi) {
645
ret = -EBUSY;
646
goto failed_ac97;
647
}
648
ac97_ssi = ssi;
649
setup_channel_to_ac97(ssi);
650
dai = &imx_ac97_dai;
651
} else
652
dai = &imx_ssi_dai;
653
654
writel(0x0, ssi->base + SSI_SIER);
655
656
ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
657
ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
658
659
ssi->dma_params_tx.burstsize = 4;
660
ssi->dma_params_rx.burstsize = 4;
661
662
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
663
if (res)
664
ssi->dma_params_tx.dma = res->start;
665
666
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
667
if (res)
668
ssi->dma_params_rx.dma = res->start;
669
670
platform_set_drvdata(pdev, ssi);
671
672
ret = snd_soc_register_dai(&pdev->dev, dai);
673
if (ret) {
674
dev_err(&pdev->dev, "register DAI failed\n");
675
goto failed_register;
676
}
677
678
ssi->soc_platform_pdev_fiq = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
679
if (!ssi->soc_platform_pdev_fiq) {
680
ret = -ENOMEM;
681
goto failed_pdev_fiq_alloc;
682
}
683
684
platform_set_drvdata(ssi->soc_platform_pdev_fiq, ssi);
685
ret = platform_device_add(ssi->soc_platform_pdev_fiq);
686
if (ret) {
687
dev_err(&pdev->dev, "failed to add platform device\n");
688
goto failed_pdev_fiq_add;
689
}
690
691
ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", pdev->id);
692
if (!ssi->soc_platform_pdev) {
693
ret = -ENOMEM;
694
goto failed_pdev_alloc;
695
}
696
697
platform_set_drvdata(ssi->soc_platform_pdev, ssi);
698
ret = platform_device_add(ssi->soc_platform_pdev);
699
if (ret) {
700
dev_err(&pdev->dev, "failed to add platform device\n");
701
goto failed_pdev_add;
702
}
703
704
return 0;
705
706
failed_pdev_add:
707
platform_device_put(ssi->soc_platform_pdev);
708
failed_pdev_alloc:
709
platform_device_del(ssi->soc_platform_pdev_fiq);
710
failed_pdev_fiq_add:
711
platform_device_put(ssi->soc_platform_pdev_fiq);
712
failed_pdev_fiq_alloc:
713
snd_soc_unregister_dai(&pdev->dev);
714
failed_register:
715
failed_ac97:
716
iounmap(ssi->base);
717
failed_ioremap:
718
release_mem_region(res->start, resource_size(res));
719
failed_get_resource:
720
clk_disable(ssi->clk);
721
clk_put(ssi->clk);
722
failed_clk:
723
kfree(ssi);
724
725
return ret;
726
}
727
728
static int __devexit imx_ssi_remove(struct platform_device *pdev)
729
{
730
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
731
struct imx_ssi *ssi = platform_get_drvdata(pdev);
732
733
platform_device_unregister(ssi->soc_platform_pdev);
734
platform_device_unregister(ssi->soc_platform_pdev_fiq);
735
736
snd_soc_unregister_dai(&pdev->dev);
737
738
if (ssi->flags & IMX_SSI_USE_AC97)
739
ac97_ssi = NULL;
740
741
iounmap(ssi->base);
742
release_mem_region(res->start, resource_size(res));
743
clk_disable(ssi->clk);
744
clk_put(ssi->clk);
745
kfree(ssi);
746
747
return 0;
748
}
749
750
static struct platform_driver imx_ssi_driver = {
751
.probe = imx_ssi_probe,
752
.remove = __devexit_p(imx_ssi_remove),
753
754
.driver = {
755
.name = "imx-ssi",
756
.owner = THIS_MODULE,
757
},
758
};
759
760
static int __init imx_ssi_init(void)
761
{
762
return platform_driver_register(&imx_ssi_driver);
763
}
764
765
static void __exit imx_ssi_exit(void)
766
{
767
platform_driver_unregister(&imx_ssi_driver);
768
}
769
770
module_init(imx_ssi_init);
771
module_exit(imx_ssi_exit);
772
773
/* Module information */
774
MODULE_AUTHOR("Sascha Hauer, <[email protected]>");
775
MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
776
MODULE_LICENSE("GPL");
777
MODULE_ALIAS("platform:imx-ssi");
778
779