Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/sound/soc/fsl/fsl_sai.c

  1 /*
  2  * Freescale ALSA SoC Digital Audio Interface (SAI) driver.
  3  *
  4  * Copyright 2012-2013 Freescale Semiconductor, Inc.
  5  *
  6  * This program is free software, you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License as published by the
  8  * Free Software Foundation, either version 2 of the License, or(at your
  9  * option) any later version.
 10  *
 11  */
 12 
 13 #include <linux/clk.h>
 14 #include <linux/delay.h>
 15 #include <linux/dmaengine.h>
 16 #include <linux/module.h>
 17 #include <linux/of_address.h>
 18 #include <linux/regmap.h>
 19 #include <linux/slab.h>
 20 #include <sound/core.h>
 21 #include <sound/dmaengine_pcm.h>
 22 #include <sound/pcm_params.h>
 23 
 24 #include "fsl_sai.h"
 25 
 26 #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
 27                        FSL_SAI_CSR_FEIE)
 28 
 29 static irqreturn_t fsl_sai_isr(int irq, void *devid)
 30 {
 31         struct fsl_sai *sai = (struct fsl_sai *)devid;
 32         struct device *dev = &sai->pdev->dev;
 33         u32 xcsr, mask;
 34 
 35         /* Only handle those what we enabled */
 36         mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
 37 
 38         /* Tx IRQ */
 39         regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
 40         xcsr &= mask;
 41 
 42         if (xcsr & FSL_SAI_CSR_WSF)
 43                 dev_dbg(dev, "isr: Start of Tx word detected\n");
 44 
 45         if (xcsr & FSL_SAI_CSR_SEF)
 46                 dev_warn(dev, "isr: Tx Frame sync error detected\n");
 47 
 48         if (xcsr & FSL_SAI_CSR_FEF) {
 49                 dev_warn(dev, "isr: Transmit underrun detected\n");
 50                 /* FIFO reset for safety */
 51                 xcsr |= FSL_SAI_CSR_FR;
 52         }
 53 
 54         if (xcsr & FSL_SAI_CSR_FWF)
 55                 dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");
 56 
 57         if (xcsr & FSL_SAI_CSR_FRF)
 58                 dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");
 59 
 60         regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
 61                            FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
 62 
 63         /* Rx IRQ */
 64         regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
 65         xcsr &= mask;
 66 
 67         if (xcsr & FSL_SAI_CSR_WSF)
 68                 dev_dbg(dev, "isr: Start of Rx word detected\n");
 69 
 70         if (xcsr & FSL_SAI_CSR_SEF)
 71                 dev_warn(dev, "isr: Rx Frame sync error detected\n");
 72 
 73         if (xcsr & FSL_SAI_CSR_FEF) {
 74                 dev_warn(dev, "isr: Receive overflow detected\n");
 75                 /* FIFO reset for safety */
 76                 xcsr |= FSL_SAI_CSR_FR;
 77         }
 78 
 79         if (xcsr & FSL_SAI_CSR_FWF)
 80                 dev_dbg(dev, "isr: Enabled receive FIFO is full\n");
 81 
 82         if (xcsr & FSL_SAI_CSR_FRF)
 83                 dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");
 84 
 85         regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
 86                            FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
 87 
 88         return IRQ_HANDLED;
 89 }
 90 
 91 static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
 92                 int clk_id, unsigned int freq, int fsl_dir)
 93 {
 94         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
 95         u32 val_cr2, reg_cr2;
 96 
 97         if (fsl_dir == FSL_FMT_TRANSMITTER)
 98                 reg_cr2 = FSL_SAI_TCR2;
 99         else
100                 reg_cr2 = FSL_SAI_RCR2;
101 
102         regmap_read(sai->regmap, reg_cr2, &val_cr2);
103 
104         val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
105 
106         switch (clk_id) {
107         case FSL_SAI_CLK_BUS:
108                 val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
109                 break;
110         case FSL_SAI_CLK_MAST1:
111                 val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
112                 break;
113         case FSL_SAI_CLK_MAST2:
114                 val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
115                 break;
116         case FSL_SAI_CLK_MAST3:
117                 val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
118                 break;
119         default:
120                 return -EINVAL;
121         }
122 
123         regmap_write(sai->regmap, reg_cr2, val_cr2);
124 
125         return 0;
126 }
127 
128 static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
129                 int clk_id, unsigned int freq, int dir)
130 {
131         int ret;
132 
133         if (dir == SND_SOC_CLOCK_IN)
134                 return 0;
135 
136         ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
137                                         FSL_FMT_TRANSMITTER);
138         if (ret) {
139                 dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
140                 return ret;
141         }
142 
143         ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
144                                         FSL_FMT_RECEIVER);
145         if (ret)
146                 dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
147 
148         return ret;
149 }
150 
151 static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
152                                 unsigned int fmt, int fsl_dir)
153 {
154         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
155         u32 val_cr2, val_cr4, reg_cr2, reg_cr4;
156 
157         if (fsl_dir == FSL_FMT_TRANSMITTER) {
158                 reg_cr2 = FSL_SAI_TCR2;
159                 reg_cr4 = FSL_SAI_TCR4;
160         } else {
161                 reg_cr2 = FSL_SAI_RCR2;
162                 reg_cr4 = FSL_SAI_RCR4;
163         }
164 
165         regmap_read(sai->regmap, reg_cr2, &val_cr2);
166         regmap_read(sai->regmap, reg_cr4, &val_cr4);
167 
168         if (sai->big_endian_data)
169                 val_cr4 &= ~FSL_SAI_CR4_MF;
170         else
171                 val_cr4 |= FSL_SAI_CR4_MF;
172 
173         /* DAI mode */
174         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
175         case SND_SOC_DAIFMT_I2S:
176                 /*
177                  * Frame low, 1clk before data, one word length for frame sync,
178                  * frame sync starts one serial clock cycle earlier,
179                  * that is, together with the last bit of the previous
180                  * data word.
181                  */
182                 val_cr2 |= FSL_SAI_CR2_BCP;
183                 val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP;
184                 break;
185         case SND_SOC_DAIFMT_LEFT_J:
186                 /*
187                  * Frame high, one word length for frame sync,
188                  * frame sync asserts with the first bit of the frame.
189                  */
190                 val_cr2 |= FSL_SAI_CR2_BCP;
191                 val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
192                 break;
193         case SND_SOC_DAIFMT_DSP_A:
194                 /*
195                  * Frame high, 1clk before data, one bit for frame sync,
196                  * frame sync starts one serial clock cycle earlier,
197                  * that is, together with the last bit of the previous
198                  * data word.
199                  */
200                 val_cr2 |= FSL_SAI_CR2_BCP;
201                 val_cr4 &= ~FSL_SAI_CR4_FSP;
202                 val_cr4 |= FSL_SAI_CR4_FSE;
203                 sai->is_dsp_mode = true;
204                 break;
205         case SND_SOC_DAIFMT_DSP_B:
206                 /*
207                  * Frame high, one bit for frame sync,
208                  * frame sync asserts with the first bit of the frame.
209                  */
210                 val_cr2 |= FSL_SAI_CR2_BCP;
211                 val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
212                 sai->is_dsp_mode = true;
213                 break;
214         case SND_SOC_DAIFMT_RIGHT_J:
215                 /* To be done */
216         default:
217                 return -EINVAL;
218         }
219 
220         /* DAI clock inversion */
221         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
222         case SND_SOC_DAIFMT_IB_IF:
223                 /* Invert both clocks */
224                 val_cr2 ^= FSL_SAI_CR2_BCP;
225                 val_cr4 ^= FSL_SAI_CR4_FSP;
226                 break;
227         case SND_SOC_DAIFMT_IB_NF:
228                 /* Invert bit clock */
229                 val_cr2 ^= FSL_SAI_CR2_BCP;
230                 break;
231         case SND_SOC_DAIFMT_NB_IF:
232                 /* Invert frame clock */
233                 val_cr4 ^= FSL_SAI_CR4_FSP;
234                 break;
235         case SND_SOC_DAIFMT_NB_NF:
236                 /* Nothing to do for both normal cases */
237                 break;
238         default:
239                 return -EINVAL;
240         }
241 
242         /* DAI clock master masks */
243         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
244         case SND_SOC_DAIFMT_CBS_CFS:
245                 val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
246                 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
247                 break;
248         case SND_SOC_DAIFMT_CBM_CFM:
249                 val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
250                 val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
251                 break;
252         case SND_SOC_DAIFMT_CBS_CFM:
253                 val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
254                 val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
255                 break;
256         case SND_SOC_DAIFMT_CBM_CFS:
257                 val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
258                 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
259                 break;
260         default:
261                 return -EINVAL;
262         }
263 
264         regmap_write(sai->regmap, reg_cr2, val_cr2);
265         regmap_write(sai->regmap, reg_cr4, val_cr4);
266 
267         return 0;
268 }
269 
270 static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
271 {
272         int ret;
273 
274         ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
275         if (ret) {
276                 dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
277                 return ret;
278         }
279 
280         ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
281         if (ret)
282                 dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
283 
284         return ret;
285 }
286 
287 static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
288                 struct snd_pcm_hw_params *params,
289                 struct snd_soc_dai *cpu_dai)
290 {
291         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
292         u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
293         unsigned int channels = params_channels(params);
294         u32 word_width = snd_pcm_format_width(params_format(params));
295 
296         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
297                 reg_cr4 = FSL_SAI_TCR4;
298                 reg_cr5 = FSL_SAI_TCR5;
299                 reg_mr = FSL_SAI_TMR;
300         } else {
301                 reg_cr4 = FSL_SAI_RCR4;
302                 reg_cr5 = FSL_SAI_RCR5;
303                 reg_mr = FSL_SAI_RMR;
304         }
305 
306         regmap_read(sai->regmap, reg_cr4, &val_cr4);
307         regmap_read(sai->regmap, reg_cr4, &val_cr5);
308 
309         val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
310         val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
311 
312         val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
313         val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
314         val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
315 
316         if (!sai->is_dsp_mode)
317                 val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
318 
319         val_cr5 |= FSL_SAI_CR5_WNW(word_width);
320         val_cr5 |= FSL_SAI_CR5_W0W(word_width);
321 
322         val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
323         if (sai->big_endian_data)
324                 val_cr5 |= FSL_SAI_CR5_FBT(0);
325         else
326                 val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
327 
328         val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
329         val_mr = ~0UL - ((1 << channels) - 1);
330 
331         regmap_write(sai->regmap, reg_cr4, val_cr4);
332         regmap_write(sai->regmap, reg_cr5, val_cr5);
333         regmap_write(sai->regmap, reg_mr, val_mr);
334 
335         return 0;
336 }
337 
338 static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
339                 struct snd_soc_dai *cpu_dai)
340 {
341         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
342         u32 tcsr, rcsr;
343 
344         /*
345          * The transmitter bit clock and frame sync are to be
346          * used by both the transmitter and receiver.
347          */
348         regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
349                            ~FSL_SAI_CR2_SYNC);
350         regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
351                            FSL_SAI_CR2_SYNC);
352 
353         regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr);
354         regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr);
355 
356         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
357                 tcsr |= FSL_SAI_CSR_FRDE;
358                 rcsr &= ~FSL_SAI_CSR_FRDE;
359         } else {
360                 rcsr |= FSL_SAI_CSR_FRDE;
361                 tcsr &= ~FSL_SAI_CSR_FRDE;
362         }
363 
364         /*
365          * It is recommended that the transmitter is the last enabled
366          * and the first disabled.
367          */
368         switch (cmd) {
369         case SNDRV_PCM_TRIGGER_START:
370         case SNDRV_PCM_TRIGGER_RESUME:
371         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
372                 tcsr |= FSL_SAI_CSR_TERE;
373                 rcsr |= FSL_SAI_CSR_TERE;
374 
375                 regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
376                 regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
377                 break;
378         case SNDRV_PCM_TRIGGER_STOP:
379         case SNDRV_PCM_TRIGGER_SUSPEND:
380         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
381                 if (!(cpu_dai->playback_active || cpu_dai->capture_active)) {
382                         tcsr &= ~FSL_SAI_CSR_TERE;
383                         rcsr &= ~FSL_SAI_CSR_TERE;
384                 }
385 
386                 regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
387                 regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
388                 break;
389         default:
390                 return -EINVAL;
391         }
392 
393         return 0;
394 }
395 
396 static int fsl_sai_startup(struct snd_pcm_substream *substream,
397                 struct snd_soc_dai *cpu_dai)
398 {
399         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
400         u32 reg;
401 
402         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
403                 reg = FSL_SAI_TCR3;
404         else
405                 reg = FSL_SAI_RCR3;
406 
407         regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
408                            FSL_SAI_CR3_TRCE);
409 
410         return 0;
411 }
412 
413 static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
414                 struct snd_soc_dai *cpu_dai)
415 {
416         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
417         u32 reg;
418 
419         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
420                 reg = FSL_SAI_TCR3;
421         else
422                 reg = FSL_SAI_RCR3;
423 
424         regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
425                            ~FSL_SAI_CR3_TRCE);
426 }
427 
428 static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
429         .set_sysclk     = fsl_sai_set_dai_sysclk,
430         .set_fmt        = fsl_sai_set_dai_fmt,
431         .hw_params      = fsl_sai_hw_params,
432         .trigger        = fsl_sai_trigger,
433         .startup        = fsl_sai_startup,
434         .shutdown       = fsl_sai_shutdown,
435 };
436 
437 static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
438 {
439         struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
440 
441         regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS);
442         regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS);
443         regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
444                            FSL_SAI_MAXBURST_TX * 2);
445         regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
446                            FSL_SAI_MAXBURST_RX - 1);
447 
448         snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
449                                 &sai->dma_params_rx);
450 
451         snd_soc_dai_set_drvdata(cpu_dai, sai);
452 
453         return 0;
454 }
455 
456 static struct snd_soc_dai_driver fsl_sai_dai = {
457         .probe = fsl_sai_dai_probe,
458         .playback = {
459                 .channels_min = 1,
460                 .channels_max = 2,
461                 .rates = SNDRV_PCM_RATE_8000_96000,
462                 .formats = FSL_SAI_FORMATS,
463         },
464         .capture = {
465                 .channels_min = 1,
466                 .channels_max = 2,
467                 .rates = SNDRV_PCM_RATE_8000_96000,
468                 .formats = FSL_SAI_FORMATS,
469         },
470         .ops = &fsl_sai_pcm_dai_ops,
471 };
472 
473 static const struct snd_soc_component_driver fsl_component = {
474         .name           = "fsl-sai",
475 };
476 
477 static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
478 {
479         switch (reg) {
480         case FSL_SAI_TCSR:
481         case FSL_SAI_TCR1:
482         case FSL_SAI_TCR2:
483         case FSL_SAI_TCR3:
484         case FSL_SAI_TCR4:
485         case FSL_SAI_TCR5:
486         case FSL_SAI_TFR:
487         case FSL_SAI_TMR:
488         case FSL_SAI_RCSR:
489         case FSL_SAI_RCR1:
490         case FSL_SAI_RCR2:
491         case FSL_SAI_RCR3:
492         case FSL_SAI_RCR4:
493         case FSL_SAI_RCR5:
494         case FSL_SAI_RDR:
495         case FSL_SAI_RFR:
496         case FSL_SAI_RMR:
497                 return true;
498         default:
499                 return false;
500         }
501 }
502 
503 static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
504 {
505         switch (reg) {
506         case FSL_SAI_TFR:
507         case FSL_SAI_RFR:
508         case FSL_SAI_TDR:
509         case FSL_SAI_RDR:
510                 return true;
511         default:
512                 return false;
513         }
514 
515 }
516 
517 static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
518 {
519         switch (reg) {
520         case FSL_SAI_TCSR:
521         case FSL_SAI_TCR1:
522         case FSL_SAI_TCR2:
523         case FSL_SAI_TCR3:
524         case FSL_SAI_TCR4:
525         case FSL_SAI_TCR5:
526         case FSL_SAI_TDR:
527         case FSL_SAI_TMR:
528         case FSL_SAI_RCSR:
529         case FSL_SAI_RCR1:
530         case FSL_SAI_RCR2:
531         case FSL_SAI_RCR3:
532         case FSL_SAI_RCR4:
533         case FSL_SAI_RCR5:
534         case FSL_SAI_RMR:
535                 return true;
536         default:
537                 return false;
538         }
539 }
540 
541 static struct regmap_config fsl_sai_regmap_config = {
542         .reg_bits = 32,
543         .reg_stride = 4,
544         .val_bits = 32,
545 
546         .max_register = FSL_SAI_RMR,
547         .readable_reg = fsl_sai_readable_reg,
548         .volatile_reg = fsl_sai_volatile_reg,
549         .writeable_reg = fsl_sai_writeable_reg,
550 };
551 
552 static int fsl_sai_probe(struct platform_device *pdev)
553 {
554         struct device_node *np = pdev->dev.of_node;
555         struct fsl_sai *sai;
556         struct resource *res;
557         void __iomem *base;
558         int irq, ret;
559 
560         sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
561         if (!sai)
562                 return -ENOMEM;
563 
564         sai->pdev = pdev;
565 
566         sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
567         if (sai->big_endian_regs)
568                 fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
569 
570         sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
571 
572         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
573         base = devm_ioremap_resource(&pdev->dev, res);
574         if (IS_ERR(base))
575                 return PTR_ERR(base);
576 
577         sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
578                         "sai", base, &fsl_sai_regmap_config);
579         if (IS_ERR(sai->regmap)) {
580                 dev_err(&pdev->dev, "regmap init failed\n");
581                 return PTR_ERR(sai->regmap);
582         }
583 
584         irq = platform_get_irq(pdev, 0);
585         if (irq < 0) {
586                 dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
587                 return irq;
588         }
589 
590         ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
591         if (ret) {
592                 dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
593                 return ret;
594         }
595 
596         sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
597         sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
598         sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
599         sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
600 
601         platform_set_drvdata(pdev, sai);
602 
603         ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
604                         &fsl_sai_dai, 1);
605         if (ret)
606                 return ret;
607 
608         return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
609                         SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
610 }
611 
612 static const struct of_device_id fsl_sai_ids[] = {
613         { .compatible = "fsl,vf610-sai", },
614         { /* sentinel */ }
615 };
616 
617 static struct platform_driver fsl_sai_driver = {
618         .probe = fsl_sai_probe,
619         .driver = {
620                 .name = "fsl-sai",
621                 .owner = THIS_MODULE,
622                 .of_match_table = fsl_sai_ids,
623         },
624 };
625 module_platform_driver(fsl_sai_driver);
626 
627 MODULE_DESCRIPTION("Freescale Soc SAI Interface");
628 MODULE_AUTHOR("Xiubo Li, <Li.Xiubo@freescale.com>");
629 MODULE_ALIAS("platform:fsl-sai");
630 MODULE_LICENSE("GPL");
631 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us