]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - sound/soc/fsl/fsl_ssi.c
Merge branch 'linus' into core/softlockup
[mirror_ubuntu-hirsute-kernel.git] / sound / soc / fsl / fsl_ssi.c
CommitLineData
17467f23
TT
1/*
2 * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
3 *
4 * Author: Timur Tabi <timur@freescale.com>
5 *
6 * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
7 * under the terms of the GNU General Public License version 2. This
8 * program is licensed "as is" without any warranty of any kind, whether
9 * express or implied.
10 */
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/interrupt.h>
15#include <linux/device.h>
16#include <linux/delay.h>
17
17467f23
TT
18#include <sound/core.h>
19#include <sound/pcm.h>
20#include <sound/pcm_params.h>
21#include <sound/initval.h>
22#include <sound/soc.h>
23
24#include <asm/immap_86xx.h>
25
26#include "fsl_ssi.h"
27
28/**
29 * FSLSSI_I2S_RATES: sample rates supported by the I2S
30 *
31 * This driver currently only supports the SSI running in I2S slave mode,
32 * which means the codec determines the sample rate. Therefore, we tell
33 * ALSA that we support all rates and let the codec driver decide what rates
34 * are really supported.
35 */
36#define FSLSSI_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
37 SNDRV_PCM_RATE_CONTINUOUS)
38
39/**
40 * FSLSSI_I2S_FORMATS: audio formats supported by the SSI
41 *
42 * This driver currently only supports the SSI running in I2S slave mode.
43 *
44 * The SSI has a limitation in that the samples must be in the same byte
45 * order as the host CPU. This is because when multiple bytes are written
46 * to the STX register, the bytes and bits must be written in the same
47 * order. The STX is a shift register, so all the bits need to be aligned
48 * (bit-endianness must match byte-endianness). Processors typically write
49 * the bits within a byte in the same order that the bytes of a word are
50 * written in. So if the host CPU is big-endian, then only big-endian
51 * samples will be written to STX properly.
52 */
53#ifdef __BIG_ENDIAN
54#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
55 SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \
56 SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE)
57#else
58#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
59 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \
60 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
61#endif
62
63/**
64 * fsl_ssi_private: per-SSI private data
65 *
66 * @name: short name for this device ("SSI0", "SSI1", etc)
67 * @ssi: pointer to the SSI's registers
68 * @ssi_phys: physical address of the SSI registers
69 * @irq: IRQ of this SSI
70 * @dev: struct device pointer
71 * @playback: the number of playback streams opened
72 * @capture: the number of capture streams opened
73 * @cpu_dai: the CPU DAI for this device
74 * @dev_attr: the sysfs device attribute structure
75 * @stats: SSI statistics
76 */
77struct fsl_ssi_private {
78 char name[8];
79 struct ccsr_ssi __iomem *ssi;
80 dma_addr_t ssi_phys;
81 unsigned int irq;
82 struct device *dev;
83 unsigned int playback;
84 unsigned int capture;
8cf7b2b3 85 struct snd_soc_dai cpu_dai;
17467f23
TT
86 struct device_attribute dev_attr;
87
88 struct {
89 unsigned int rfrc;
90 unsigned int tfrc;
91 unsigned int cmdau;
92 unsigned int cmddu;
93 unsigned int rxt;
94 unsigned int rdr1;
95 unsigned int rdr0;
96 unsigned int tde1;
97 unsigned int tde0;
98 unsigned int roe1;
99 unsigned int roe0;
100 unsigned int tue1;
101 unsigned int tue0;
102 unsigned int tfs;
103 unsigned int rfs;
104 unsigned int tls;
105 unsigned int rls;
106 unsigned int rff1;
107 unsigned int rff0;
108 unsigned int tfe1;
109 unsigned int tfe0;
110 } stats;
111};
112
113/**
114 * fsl_ssi_isr: SSI interrupt handler
115 *
116 * Although it's possible to use the interrupt handler to send and receive
117 * data to/from the SSI, we use the DMA instead. Programming is more
118 * complicated, but the performance is much better.
119 *
120 * This interrupt handler is used only to gather statistics.
121 *
122 * @irq: IRQ of the SSI device
123 * @dev_id: pointer to the ssi_private structure for this SSI device
124 */
125static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
126{
127 struct fsl_ssi_private *ssi_private = dev_id;
128 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
129 irqreturn_t ret = IRQ_NONE;
130 __be32 sisr;
131 __be32 sisr2 = 0;
132
133 /* We got an interrupt, so read the status register to see what we
134 were interrupted for. We mask it with the Interrupt Enable register
135 so that we only check for events that we're interested in.
136 */
137 sisr = in_be32(&ssi->sisr) & in_be32(&ssi->sier);
138
139 if (sisr & CCSR_SSI_SISR_RFRC) {
140 ssi_private->stats.rfrc++;
141 sisr2 |= CCSR_SSI_SISR_RFRC;
142 ret = IRQ_HANDLED;
143 }
144
145 if (sisr & CCSR_SSI_SISR_TFRC) {
146 ssi_private->stats.tfrc++;
147 sisr2 |= CCSR_SSI_SISR_TFRC;
148 ret = IRQ_HANDLED;
149 }
150
151 if (sisr & CCSR_SSI_SISR_CMDAU) {
152 ssi_private->stats.cmdau++;
153 ret = IRQ_HANDLED;
154 }
155
156 if (sisr & CCSR_SSI_SISR_CMDDU) {
157 ssi_private->stats.cmddu++;
158 ret = IRQ_HANDLED;
159 }
160
161 if (sisr & CCSR_SSI_SISR_RXT) {
162 ssi_private->stats.rxt++;
163 ret = IRQ_HANDLED;
164 }
165
166 if (sisr & CCSR_SSI_SISR_RDR1) {
167 ssi_private->stats.rdr1++;
168 ret = IRQ_HANDLED;
169 }
170
171 if (sisr & CCSR_SSI_SISR_RDR0) {
172 ssi_private->stats.rdr0++;
173 ret = IRQ_HANDLED;
174 }
175
176 if (sisr & CCSR_SSI_SISR_TDE1) {
177 ssi_private->stats.tde1++;
178 ret = IRQ_HANDLED;
179 }
180
181 if (sisr & CCSR_SSI_SISR_TDE0) {
182 ssi_private->stats.tde0++;
183 ret = IRQ_HANDLED;
184 }
185
186 if (sisr & CCSR_SSI_SISR_ROE1) {
187 ssi_private->stats.roe1++;
188 sisr2 |= CCSR_SSI_SISR_ROE1;
189 ret = IRQ_HANDLED;
190 }
191
192 if (sisr & CCSR_SSI_SISR_ROE0) {
193 ssi_private->stats.roe0++;
194 sisr2 |= CCSR_SSI_SISR_ROE0;
195 ret = IRQ_HANDLED;
196 }
197
198 if (sisr & CCSR_SSI_SISR_TUE1) {
199 ssi_private->stats.tue1++;
200 sisr2 |= CCSR_SSI_SISR_TUE1;
201 ret = IRQ_HANDLED;
202 }
203
204 if (sisr & CCSR_SSI_SISR_TUE0) {
205 ssi_private->stats.tue0++;
206 sisr2 |= CCSR_SSI_SISR_TUE0;
207 ret = IRQ_HANDLED;
208 }
209
210 if (sisr & CCSR_SSI_SISR_TFS) {
211 ssi_private->stats.tfs++;
212 ret = IRQ_HANDLED;
213 }
214
215 if (sisr & CCSR_SSI_SISR_RFS) {
216 ssi_private->stats.rfs++;
217 ret = IRQ_HANDLED;
218 }
219
220 if (sisr & CCSR_SSI_SISR_TLS) {
221 ssi_private->stats.tls++;
222 ret = IRQ_HANDLED;
223 }
224
225 if (sisr & CCSR_SSI_SISR_RLS) {
226 ssi_private->stats.rls++;
227 ret = IRQ_HANDLED;
228 }
229
230 if (sisr & CCSR_SSI_SISR_RFF1) {
231 ssi_private->stats.rff1++;
232 ret = IRQ_HANDLED;
233 }
234
235 if (sisr & CCSR_SSI_SISR_RFF0) {
236 ssi_private->stats.rff0++;
237 ret = IRQ_HANDLED;
238 }
239
240 if (sisr & CCSR_SSI_SISR_TFE1) {
241 ssi_private->stats.tfe1++;
242 ret = IRQ_HANDLED;
243 }
244
245 if (sisr & CCSR_SSI_SISR_TFE0) {
246 ssi_private->stats.tfe0++;
247 ret = IRQ_HANDLED;
248 }
249
250 /* Clear the bits that we set */
251 if (sisr2)
252 out_be32(&ssi->sisr, sisr2);
253
254 return ret;
255}
256
257/**
258 * fsl_ssi_startup: create a new substream
259 *
260 * This is the first function called when a stream is opened.
261 *
262 * If this is the first stream open, then grab the IRQ and program most of
263 * the SSI registers.
264 */
265static int fsl_ssi_startup(struct snd_pcm_substream *substream)
266{
267 struct snd_soc_pcm_runtime *rtd = substream->private_data;
268 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
269
270 /*
271 * If this is the first stream opened, then request the IRQ
272 * and initialize the SSI registers.
273 */
274 if (!ssi_private->playback && !ssi_private->capture) {
275 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
276 int ret;
277
278 ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
279 ssi_private->name, ssi_private);
280 if (ret < 0) {
281 dev_err(substream->pcm->card->dev,
282 "could not claim irq %u\n", ssi_private->irq);
283 return ret;
284 }
285
286 /*
287 * Section 16.5 of the MPC8610 reference manual says that the
288 * SSI needs to be disabled before updating the registers we set
289 * here.
290 */
291 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
292
293 /*
294 * Program the SSI into I2S Slave Non-Network Synchronous mode.
295 * Also enable the transmit and receive FIFO.
296 *
297 * FIXME: Little-endian samples require a different shift dir
298 */
299 clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK,
300 CCSR_SSI_SCR_TFR_CLK_DIS |
301 CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN);
302
303 out_be32(&ssi->stcr,
304 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
305 CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
306 CCSR_SSI_STCR_TSCKP);
307
308 out_be32(&ssi->srcr,
309 CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
310 CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
311 CCSR_SSI_SRCR_RSCKP);
312
313 /*
314 * The DC and PM bits are only used if the SSI is the clock
315 * master.
316 */
317
318 /* 4. Enable the interrupts and DMA requests */
319 out_be32(&ssi->sier,
320 CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE |
321 CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN |
322 CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN |
323 CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE |
324 CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN);
325
326 /*
327 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
328 * don't use FIFO 1. Since the SSI only supports stereo, the
329 * watermark should never be an odd number.
330 */
331 out_be32(&ssi->sfcsr,
332 CCSR_SSI_SFCSR_TFWM0(6) | CCSR_SSI_SFCSR_RFWM0(2));
333
334 /*
335 * We keep the SSI disabled because if we enable it, then the
336 * DMA controller will start. It's not supposed to start until
337 * the SCR.TE (or SCR.RE) bit is set, but it does anyway. The
338 * DMA controller will transfer one "BWC" of data (i.e. the
339 * amount of data that the MR.BWC bits are set to). The reason
340 * this is bad is because at this point, the PCM driver has not
341 * finished initializing the DMA controller.
342 */
343 }
344
345 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
346 ssi_private->playback++;
347
348 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
349 ssi_private->capture++;
350
351 return 0;
352}
353
354/**
355 * fsl_ssi_prepare: prepare the SSI.
356 *
357 * Most of the SSI registers have been programmed in the startup function,
358 * but the word length must be programmed here. Unfortunately, programming
359 * the SxCCR.WL bits requires the SSI to be temporarily disabled. This can
360 * cause a problem with supporting simultaneous playback and capture. If
361 * the SSI is already playing a stream, then that stream may be temporarily
362 * stopped when you start capture.
363 *
364 * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
365 * clock master.
366 */
367static int fsl_ssi_prepare(struct snd_pcm_substream *substream)
368{
369 struct snd_pcm_runtime *runtime = substream->runtime;
370 struct snd_soc_pcm_runtime *rtd = substream->private_data;
371 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
372
373 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
374 u32 wl;
375
376 wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
377
378 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
379
380 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
381 clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
382 else
383 clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
384
385 setbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
386
387 return 0;
388}
389
390/**
391 * fsl_ssi_trigger: start and stop the DMA transfer.
392 *
393 * This function is called by ALSA to start, stop, pause, and resume the DMA
394 * transfer of data.
395 *
396 * The DMA channel is in external master start and pause mode, which
397 * means the SSI completely controls the flow of data.
398 */
399static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd)
400{
401 struct snd_soc_pcm_runtime *rtd = substream->private_data;
402 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
403 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
404
405 switch (cmd) {
406 case SNDRV_PCM_TRIGGER_START:
407 case SNDRV_PCM_TRIGGER_RESUME:
408 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
409 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
410 setbits32(&ssi->scr, CCSR_SSI_SCR_TE);
411 } else {
412 setbits32(&ssi->scr, CCSR_SSI_SCR_RE);
413
414 /*
415 * I think we need this delay to allow time for the SSI
416 * to put data into its FIFO. Without it, ALSA starts
417 * to complain about overruns.
418 */
3a3bd960 419 mdelay(1);
17467f23
TT
420 }
421 break;
422
423 case SNDRV_PCM_TRIGGER_STOP:
424 case SNDRV_PCM_TRIGGER_SUSPEND:
425 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
426 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
427 clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
428 else
429 clrbits32(&ssi->scr, CCSR_SSI_SCR_RE);
430 break;
431
432 default:
433 return -EINVAL;
434 }
435
436 return 0;
437}
438
439/**
440 * fsl_ssi_shutdown: shutdown the SSI
441 *
442 * Shutdown the SSI if there are no other substreams open.
443 */
444static void fsl_ssi_shutdown(struct snd_pcm_substream *substream)
445{
446 struct snd_soc_pcm_runtime *rtd = substream->private_data;
447 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
448
449 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
450 ssi_private->playback--;
451
452 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
453 ssi_private->capture--;
454
455 /*
456 * If this is the last active substream, disable the SSI and release
457 * the IRQ.
458 */
459 if (!ssi_private->playback && !ssi_private->capture) {
460 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
461
462 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
463
464 free_irq(ssi_private->irq, ssi_private);
465 }
466}
467
468/**
469 * fsl_ssi_set_sysclk: set the clock frequency and direction
470 *
471 * This function is called by the machine driver to tell us what the clock
472 * frequency and direction are.
473 *
474 * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
475 * and we don't care about the frequency. Return an error if the direction
476 * is not SND_SOC_CLOCK_IN.
477 *
478 * @clk_id: reserved, should be zero
479 * @freq: the frequency of the given clock ID, currently ignored
480 * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
481 */
8cf7b2b3 482static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai,
17467f23
TT
483 int clk_id, unsigned int freq, int dir)
484{
485
486 return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
487}
488
489/**
490 * fsl_ssi_set_fmt: set the serial format.
491 *
492 * This function is called by the machine driver to tell us what serial
493 * format to use.
494 *
495 * Currently, we only support I2S mode. Return an error if the format is
496 * not SND_SOC_DAIFMT_I2S.
497 *
498 * @format: one of SND_SOC_DAIFMT_xxx
499 */
8cf7b2b3 500static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
17467f23
TT
501{
502 return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
503}
504
505/**
506 * fsl_ssi_dai_template: template CPU DAI for the SSI
507 */
8cf7b2b3 508static struct snd_soc_dai fsl_ssi_dai_template = {
17467f23
TT
509 .playback = {
510 /* The SSI does not support monaural audio. */
511 .channels_min = 2,
512 .channels_max = 2,
513 .rates = FSLSSI_I2S_RATES,
514 .formats = FSLSSI_I2S_FORMATS,
515 },
516 .capture = {
517 .channels_min = 2,
518 .channels_max = 2,
519 .rates = FSLSSI_I2S_RATES,
520 .formats = FSLSSI_I2S_FORMATS,
521 },
522 .ops = {
523 .startup = fsl_ssi_startup,
524 .prepare = fsl_ssi_prepare,
525 .shutdown = fsl_ssi_shutdown,
526 .trigger = fsl_ssi_trigger,
527 },
528 .dai_ops = {
529 .set_sysclk = fsl_ssi_set_sysclk,
530 .set_fmt = fsl_ssi_set_fmt,
531 },
532};
533
534/**
535 * fsl_sysfs_ssi_show: display SSI statistics
536 *
537 * Display the statistics for the current SSI device.
538 */
539static ssize_t fsl_sysfs_ssi_show(struct device *dev,
540 struct device_attribute *attr, char *buf)
541{
542 struct fsl_ssi_private *ssi_private =
543 container_of(attr, struct fsl_ssi_private, dev_attr);
544 ssize_t length;
545
546 length = sprintf(buf, "rfrc=%u", ssi_private->stats.rfrc);
547 length += sprintf(buf + length, "\ttfrc=%u", ssi_private->stats.tfrc);
548 length += sprintf(buf + length, "\tcmdau=%u", ssi_private->stats.cmdau);
549 length += sprintf(buf + length, "\tcmddu=%u", ssi_private->stats.cmddu);
550 length += sprintf(buf + length, "\trxt=%u", ssi_private->stats.rxt);
551 length += sprintf(buf + length, "\trdr1=%u", ssi_private->stats.rdr1);
552 length += sprintf(buf + length, "\trdr0=%u", ssi_private->stats.rdr0);
553 length += sprintf(buf + length, "\ttde1=%u", ssi_private->stats.tde1);
554 length += sprintf(buf + length, "\ttde0=%u", ssi_private->stats.tde0);
555 length += sprintf(buf + length, "\troe1=%u", ssi_private->stats.roe1);
556 length += sprintf(buf + length, "\troe0=%u", ssi_private->stats.roe0);
557 length += sprintf(buf + length, "\ttue1=%u", ssi_private->stats.tue1);
558 length += sprintf(buf + length, "\ttue0=%u", ssi_private->stats.tue0);
559 length += sprintf(buf + length, "\ttfs=%u", ssi_private->stats.tfs);
560 length += sprintf(buf + length, "\trfs=%u", ssi_private->stats.rfs);
561 length += sprintf(buf + length, "\ttls=%u", ssi_private->stats.tls);
562 length += sprintf(buf + length, "\trls=%u", ssi_private->stats.rls);
563 length += sprintf(buf + length, "\trff1=%u", ssi_private->stats.rff1);
564 length += sprintf(buf + length, "\trff0=%u", ssi_private->stats.rff0);
565 length += sprintf(buf + length, "\ttfe1=%u", ssi_private->stats.tfe1);
566 length += sprintf(buf + length, "\ttfe0=%u\n", ssi_private->stats.tfe0);
567
568 return length;
569}
570
571/**
8cf7b2b3 572 * fsl_ssi_create_dai: create a snd_soc_dai structure
17467f23 573 *
8cf7b2b3 574 * This function is called by the machine driver to create a snd_soc_dai
17467f23 575 * structure. The function creates an ssi_private object, which contains
8cf7b2b3 576 * the snd_soc_dai. It also creates the sysfs statistics device.
17467f23 577 */
8cf7b2b3 578struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
17467f23 579{
8cf7b2b3 580 struct snd_soc_dai *fsl_ssi_dai;
17467f23
TT
581 struct fsl_ssi_private *ssi_private;
582 int ret = 0;
583 struct device_attribute *dev_attr;
584
585 ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL);
586 if (!ssi_private) {
587 dev_err(ssi_info->dev, "could not allocate DAI object\n");
588 return NULL;
589 }
590 memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template,
8cf7b2b3 591 sizeof(struct snd_soc_dai));
17467f23
TT
592
593 fsl_ssi_dai = &ssi_private->cpu_dai;
594 dev_attr = &ssi_private->dev_attr;
595
596 sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id);
597 ssi_private->ssi = ssi_info->ssi;
598 ssi_private->ssi_phys = ssi_info->ssi_phys;
599 ssi_private->irq = ssi_info->irq;
600 ssi_private->dev = ssi_info->dev;
601
602 ssi_private->dev->driver_data = fsl_ssi_dai;
603
604 /* Initialize the the device_attribute structure */
605 dev_attr->attr.name = "ssi-stats";
606 dev_attr->attr.mode = S_IRUGO;
607 dev_attr->show = fsl_sysfs_ssi_show;
608
609 ret = device_create_file(ssi_private->dev, dev_attr);
610 if (ret) {
611 dev_err(ssi_info->dev, "could not create sysfs %s file\n",
612 ssi_private->dev_attr.attr.name);
613 kfree(fsl_ssi_dai);
614 return NULL;
615 }
616
617 fsl_ssi_dai->private_data = ssi_private;
618 fsl_ssi_dai->name = ssi_private->name;
619 fsl_ssi_dai->id = ssi_info->id;
620
621 return fsl_ssi_dai;
622}
623EXPORT_SYMBOL_GPL(fsl_ssi_create_dai);
624
625/**
8cf7b2b3 626 * fsl_ssi_destroy_dai: destroy the snd_soc_dai object
17467f23
TT
627 *
628 * This function undoes the operations of fsl_ssi_create_dai()
629 */
8cf7b2b3 630void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
17467f23
TT
631{
632 struct fsl_ssi_private *ssi_private =
633 container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai);
634
635 device_remove_file(ssi_private->dev, &ssi_private->dev_attr);
636
637 kfree(ssi_private);
638}
639EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
640
641MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
642MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
643MODULE_LICENSE("GPL");