blob: faa65afb6951a10c1fc0fee29452d243654ad7ac [file] [log] [blame]
Xiubo Li43550822013-12-17 11:24:38 +08001/*
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>
Xiubo Li78957fc2014-02-08 14:38:28 +080018#include <linux/regmap.h>
Xiubo Li43550822013-12-17 11:24:38 +080019#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
Xiubo Li43550822013-12-17 11:24:38 +080026static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
27 int clk_id, unsigned int freq, int fsl_dir)
28{
Xiubo Li43550822013-12-17 11:24:38 +080029 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Nicolin Chen4e3a99f2013-12-20 16:41:05 +080030 u32 val_cr2, reg_cr2;
Xiubo Li43550822013-12-17 11:24:38 +080031
32 if (fsl_dir == FSL_FMT_TRANSMITTER)
33 reg_cr2 = FSL_SAI_TCR2;
34 else
35 reg_cr2 = FSL_SAI_RCR2;
36
Xiubo Li78957fc2014-02-08 14:38:28 +080037 regmap_read(sai->regmap, reg_cr2, &val_cr2);
38
Xiubo Li633ff8f2014-01-08 16:13:05 +080039 val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
40
Xiubo Li43550822013-12-17 11:24:38 +080041 switch (clk_id) {
42 case FSL_SAI_CLK_BUS:
Xiubo Li43550822013-12-17 11:24:38 +080043 val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
44 break;
45 case FSL_SAI_CLK_MAST1:
Xiubo Li43550822013-12-17 11:24:38 +080046 val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
47 break;
48 case FSL_SAI_CLK_MAST2:
Xiubo Li43550822013-12-17 11:24:38 +080049 val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
50 break;
51 case FSL_SAI_CLK_MAST3:
Xiubo Li43550822013-12-17 11:24:38 +080052 val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
53 break;
54 default:
55 return -EINVAL;
56 }
Xiubo Li633ff8f2014-01-08 16:13:05 +080057
Xiubo Li78957fc2014-02-08 14:38:28 +080058 regmap_write(sai->regmap, reg_cr2, val_cr2);
Xiubo Li43550822013-12-17 11:24:38 +080059
60 return 0;
61}
62
63static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
64 int clk_id, unsigned int freq, int dir)
65{
Nicolin Chen4e3a99f2013-12-20 16:41:05 +080066 int ret;
Xiubo Li43550822013-12-17 11:24:38 +080067
68 if (dir == SND_SOC_CLOCK_IN)
69 return 0;
70
Xiubo Li43550822013-12-17 11:24:38 +080071 ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
72 FSL_FMT_TRANSMITTER);
73 if (ret) {
Nicolin Chen190af122013-12-20 16:41:04 +080074 dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
Xiubo Li78957fc2014-02-08 14:38:28 +080075 return ret;
Xiubo Li43550822013-12-17 11:24:38 +080076 }
77
78 ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
79 FSL_FMT_RECEIVER);
Xiubo Li78957fc2014-02-08 14:38:28 +080080 if (ret)
Nicolin Chen190af122013-12-20 16:41:04 +080081 dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
Xiubo Li43550822013-12-17 11:24:38 +080082
Nicolin Chen1fb2d9d2013-12-20 16:41:00 +080083 return ret;
Xiubo Li43550822013-12-17 11:24:38 +080084}
85
86static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
87 unsigned int fmt, int fsl_dir)
88{
Xiubo Li43550822013-12-17 11:24:38 +080089 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Xiubo Lie5d0fa92013-12-25 12:40:04 +080090 u32 val_cr2, val_cr4, reg_cr2, reg_cr4;
Xiubo Li43550822013-12-17 11:24:38 +080091
92 if (fsl_dir == FSL_FMT_TRANSMITTER) {
93 reg_cr2 = FSL_SAI_TCR2;
Xiubo Li43550822013-12-17 11:24:38 +080094 reg_cr4 = FSL_SAI_TCR4;
95 } else {
96 reg_cr2 = FSL_SAI_RCR2;
Xiubo Li43550822013-12-17 11:24:38 +080097 reg_cr4 = FSL_SAI_RCR4;
98 }
99
Xiubo Li78957fc2014-02-08 14:38:28 +0800100 regmap_read(sai->regmap, reg_cr2, &val_cr2);
101 regmap_read(sai->regmap, reg_cr4, &val_cr4);
Xiubo Li43550822013-12-17 11:24:38 +0800102
103 if (sai->big_endian_data)
Xiubo Li43550822013-12-17 11:24:38 +0800104 val_cr4 &= ~FSL_SAI_CR4_MF;
Xiubo Li72aa62b2013-12-31 15:33:22 +0800105 else
106 val_cr4 |= FSL_SAI_CR4_MF;
Xiubo Li43550822013-12-17 11:24:38 +0800107
108 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
109 case SND_SOC_DAIFMT_I2S:
110 val_cr4 |= FSL_SAI_CR4_FSE;
Xiubo Li43550822013-12-17 11:24:38 +0800111 break;
112 default:
113 return -EINVAL;
114 }
115
116 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
117 case SND_SOC_DAIFMT_IB_IF:
118 val_cr4 |= FSL_SAI_CR4_FSP;
119 val_cr2 &= ~FSL_SAI_CR2_BCP;
120 break;
121 case SND_SOC_DAIFMT_IB_NF:
122 val_cr4 &= ~FSL_SAI_CR4_FSP;
123 val_cr2 &= ~FSL_SAI_CR2_BCP;
124 break;
125 case SND_SOC_DAIFMT_NB_IF:
126 val_cr4 |= FSL_SAI_CR4_FSP;
127 val_cr2 |= FSL_SAI_CR2_BCP;
128 break;
129 case SND_SOC_DAIFMT_NB_NF:
130 val_cr4 &= ~FSL_SAI_CR4_FSP;
131 val_cr2 |= FSL_SAI_CR2_BCP;
132 break;
133 default:
134 return -EINVAL;
135 }
136
137 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
138 case SND_SOC_DAIFMT_CBS_CFS:
139 val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
140 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
141 break;
142 case SND_SOC_DAIFMT_CBM_CFM:
143 val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
144 val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
145 break;
146 default:
147 return -EINVAL;
148 }
149
Xiubo Li78957fc2014-02-08 14:38:28 +0800150 regmap_write(sai->regmap, reg_cr2, val_cr2);
151 regmap_write(sai->regmap, reg_cr4, val_cr4);
Xiubo Li43550822013-12-17 11:24:38 +0800152
153 return 0;
154}
155
156static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
157{
Nicolin Chen4e3a99f2013-12-20 16:41:05 +0800158 int ret;
Xiubo Li43550822013-12-17 11:24:38 +0800159
Xiubo Li43550822013-12-17 11:24:38 +0800160 ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
161 if (ret) {
Nicolin Chen190af122013-12-20 16:41:04 +0800162 dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
Xiubo Li78957fc2014-02-08 14:38:28 +0800163 return ret;
Xiubo Li43550822013-12-17 11:24:38 +0800164 }
165
166 ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
Xiubo Li78957fc2014-02-08 14:38:28 +0800167 if (ret)
Nicolin Chen190af122013-12-20 16:41:04 +0800168 dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
Xiubo Li43550822013-12-17 11:24:38 +0800169
Nicolin Chen1fb2d9d2013-12-20 16:41:00 +0800170 return ret;
Xiubo Li43550822013-12-17 11:24:38 +0800171}
172
173static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
174 struct snd_pcm_hw_params *params,
175 struct snd_soc_dai *cpu_dai)
176{
Nicolin Chen4e3a99f2013-12-20 16:41:05 +0800177 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Nicolin Chen1d700302013-12-20 16:41:01 +0800178 u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
Xiubo Li43550822013-12-17 11:24:38 +0800179 unsigned int channels = params_channels(params);
Nicolin Chen1d700302013-12-20 16:41:01 +0800180 u32 word_width = snd_pcm_format_width(params_format(params));
Xiubo Li43550822013-12-17 11:24:38 +0800181
182 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
183 reg_cr4 = FSL_SAI_TCR4;
184 reg_cr5 = FSL_SAI_TCR5;
185 reg_mr = FSL_SAI_TMR;
186 } else {
187 reg_cr4 = FSL_SAI_RCR4;
188 reg_cr5 = FSL_SAI_RCR5;
189 reg_mr = FSL_SAI_RMR;
190 }
191
Xiubo Li78957fc2014-02-08 14:38:28 +0800192 regmap_read(sai->regmap, reg_cr4, &val_cr4);
193 regmap_read(sai->regmap, reg_cr4, &val_cr5);
194
Xiubo Li43550822013-12-17 11:24:38 +0800195 val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
196 val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
197
Xiubo Li43550822013-12-17 11:24:38 +0800198 val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
199 val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
200 val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
201
Xiubo Li43550822013-12-17 11:24:38 +0800202 val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
203 val_cr5 |= FSL_SAI_CR5_WNW(word_width);
204 val_cr5 |= FSL_SAI_CR5_W0W(word_width);
205
Xiubo Li496a39d2013-12-31 15:33:21 +0800206 val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
Xiubo Li43550822013-12-17 11:24:38 +0800207 if (sai->big_endian_data)
Xiubo Li43550822013-12-17 11:24:38 +0800208 val_cr5 |= FSL_SAI_CR5_FBT(0);
Xiubo Li72aa62b2013-12-31 15:33:22 +0800209 else
210 val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
Xiubo Li43550822013-12-17 11:24:38 +0800211
212 val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
Nicolin Chend22e28c2013-12-20 16:41:02 +0800213 val_mr = ~0UL - ((1 << channels) - 1);
Xiubo Li43550822013-12-17 11:24:38 +0800214
Xiubo Li78957fc2014-02-08 14:38:28 +0800215 regmap_write(sai->regmap, reg_cr4, val_cr4);
216 regmap_write(sai->regmap, reg_cr5, val_cr5);
217 regmap_write(sai->regmap, reg_mr, val_mr);
Xiubo Li43550822013-12-17 11:24:38 +0800218
219 return 0;
220}
221
222static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
223 struct snd_soc_dai *cpu_dai)
224{
225 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Xiubo Li78957fc2014-02-08 14:38:28 +0800226 u32 tcsr, rcsr;
Xiubo Li496a39d2013-12-31 15:33:21 +0800227
Xiubo Li78957fc2014-02-08 14:38:28 +0800228 regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
229 ~FSL_SAI_CR2_SYNC);
230 regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
231 FSL_SAI_CR2_SYNC);
Xiubo Li496a39d2013-12-31 15:33:21 +0800232
Xiubo Li78957fc2014-02-08 14:38:28 +0800233 regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr);
234 regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr);
Xiubo Li43550822013-12-17 11:24:38 +0800235
236 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
237 tcsr |= FSL_SAI_CSR_FRDE;
238 rcsr &= ~FSL_SAI_CSR_FRDE;
239 } else {
240 rcsr |= FSL_SAI_CSR_FRDE;
241 tcsr &= ~FSL_SAI_CSR_FRDE;
242 }
243
244 switch (cmd) {
245 case SNDRV_PCM_TRIGGER_START:
246 case SNDRV_PCM_TRIGGER_RESUME:
247 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
248 tcsr |= FSL_SAI_CSR_TERE;
249 rcsr |= FSL_SAI_CSR_TERE;
Xiubo Lie5d0fa92013-12-25 12:40:04 +0800250
Xiubo Li78957fc2014-02-08 14:38:28 +0800251 regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
252 regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
Xiubo Li43550822013-12-17 11:24:38 +0800253 break;
Xiubo Li43550822013-12-17 11:24:38 +0800254 case SNDRV_PCM_TRIGGER_STOP:
255 case SNDRV_PCM_TRIGGER_SUSPEND:
256 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
257 if (!(cpu_dai->playback_active || cpu_dai->capture_active)) {
258 tcsr &= ~FSL_SAI_CSR_TERE;
259 rcsr &= ~FSL_SAI_CSR_TERE;
260 }
Xiubo Lie5d0fa92013-12-25 12:40:04 +0800261
Xiubo Li78957fc2014-02-08 14:38:28 +0800262 regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
263 regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
Xiubo Li43550822013-12-17 11:24:38 +0800264 break;
265 default:
266 return -EINVAL;
267 }
268
269 return 0;
270}
271
272static int fsl_sai_startup(struct snd_pcm_substream *substream,
273 struct snd_soc_dai *cpu_dai)
274{
Xiubo Li43550822013-12-17 11:24:38 +0800275 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Xiubo Li78957fc2014-02-08 14:38:28 +0800276 u32 reg;
Xiubo Li43550822013-12-17 11:24:38 +0800277
Xiubo Li78957fc2014-02-08 14:38:28 +0800278 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
279 reg = FSL_SAI_TCR3;
280 else
281 reg = FSL_SAI_RCR3;
282
283 regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
284 FSL_SAI_CR3_TRCE);
285
286 return 0;
Xiubo Li43550822013-12-17 11:24:38 +0800287}
288
289static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
290 struct snd_soc_dai *cpu_dai)
291{
292 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Xiubo Li78957fc2014-02-08 14:38:28 +0800293 u32 reg;
Xiubo Li43550822013-12-17 11:24:38 +0800294
Xiubo Li78957fc2014-02-08 14:38:28 +0800295 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
296 reg = FSL_SAI_TCR3;
297 else
298 reg = FSL_SAI_RCR3;
299
300 regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
301 ~FSL_SAI_CR3_TRCE);
Xiubo Li43550822013-12-17 11:24:38 +0800302}
303
304static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
305 .set_sysclk = fsl_sai_set_dai_sysclk,
306 .set_fmt = fsl_sai_set_dai_fmt,
307 .hw_params = fsl_sai_hw_params,
308 .trigger = fsl_sai_trigger,
309 .startup = fsl_sai_startup,
310 .shutdown = fsl_sai_shutdown,
311};
312
313static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
314{
315 struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
Xiubo Lie6dc12d2013-12-25 11:20:14 +0800316
Xiubo Li78957fc2014-02-08 14:38:28 +0800317 regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
318 regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
319 regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
320 FSL_SAI_MAXBURST_TX * 2);
321 regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
322 FSL_SAI_MAXBURST_RX - 1);
Xiubo Li43550822013-12-17 11:24:38 +0800323
Xiubo Lidd9f4062013-12-20 12:35:33 +0800324 snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
325 &sai->dma_params_rx);
Xiubo Li43550822013-12-17 11:24:38 +0800326
327 snd_soc_dai_set_drvdata(cpu_dai, sai);
328
329 return 0;
330}
331
Xiubo Li43550822013-12-17 11:24:38 +0800332static struct snd_soc_dai_driver fsl_sai_dai = {
333 .probe = fsl_sai_dai_probe,
Xiubo Li43550822013-12-17 11:24:38 +0800334 .playback = {
335 .channels_min = 1,
336 .channels_max = 2,
337 .rates = SNDRV_PCM_RATE_8000_96000,
338 .formats = FSL_SAI_FORMATS,
339 },
340 .capture = {
341 .channels_min = 1,
342 .channels_max = 2,
343 .rates = SNDRV_PCM_RATE_8000_96000,
344 .formats = FSL_SAI_FORMATS,
345 },
346 .ops = &fsl_sai_pcm_dai_ops,
347};
348
349static const struct snd_soc_component_driver fsl_component = {
350 .name = "fsl-sai",
351};
352
Xiubo Li78957fc2014-02-08 14:38:28 +0800353static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
354{
355 switch (reg) {
356 case FSL_SAI_TCSR:
357 case FSL_SAI_TCR1:
358 case FSL_SAI_TCR2:
359 case FSL_SAI_TCR3:
360 case FSL_SAI_TCR4:
361 case FSL_SAI_TCR5:
362 case FSL_SAI_TFR:
363 case FSL_SAI_TMR:
364 case FSL_SAI_RCSR:
365 case FSL_SAI_RCR1:
366 case FSL_SAI_RCR2:
367 case FSL_SAI_RCR3:
368 case FSL_SAI_RCR4:
369 case FSL_SAI_RCR5:
370 case FSL_SAI_RDR:
371 case FSL_SAI_RFR:
372 case FSL_SAI_RMR:
373 return true;
374 default:
375 return false;
376 }
377}
378
379static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
380{
381 switch (reg) {
382 case FSL_SAI_TFR:
383 case FSL_SAI_RFR:
384 case FSL_SAI_TDR:
385 case FSL_SAI_RDR:
386 return true;
387 default:
388 return false;
389 }
390
391}
392
393static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
394{
395 switch (reg) {
396 case FSL_SAI_TCSR:
397 case FSL_SAI_TCR1:
398 case FSL_SAI_TCR2:
399 case FSL_SAI_TCR3:
400 case FSL_SAI_TCR4:
401 case FSL_SAI_TCR5:
402 case FSL_SAI_TDR:
403 case FSL_SAI_TMR:
404 case FSL_SAI_RCSR:
405 case FSL_SAI_RCR1:
406 case FSL_SAI_RCR2:
407 case FSL_SAI_RCR3:
408 case FSL_SAI_RCR4:
409 case FSL_SAI_RCR5:
410 case FSL_SAI_RMR:
411 return true;
412 default:
413 return false;
414 }
415}
416
417static struct regmap_config fsl_sai_regmap_config = {
418 .reg_bits = 32,
419 .reg_stride = 4,
420 .val_bits = 32,
421
422 .max_register = FSL_SAI_RMR,
423 .readable_reg = fsl_sai_readable_reg,
424 .volatile_reg = fsl_sai_volatile_reg,
425 .writeable_reg = fsl_sai_writeable_reg,
426};
427
Xiubo Li43550822013-12-17 11:24:38 +0800428static int fsl_sai_probe(struct platform_device *pdev)
429{
Nicolin Chen4e3a99f2013-12-20 16:41:05 +0800430 struct device_node *np = pdev->dev.of_node;
Xiubo Li43550822013-12-17 11:24:38 +0800431 struct fsl_sai *sai;
432 struct resource *res;
Xiubo Li78957fc2014-02-08 14:38:28 +0800433 void __iomem *base;
Nicolin Chen4e3a99f2013-12-20 16:41:05 +0800434 int ret;
Xiubo Li43550822013-12-17 11:24:38 +0800435
436 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
437 if (!sai)
438 return -ENOMEM;
439
Xiubo Li78957fc2014-02-08 14:38:28 +0800440 sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
441 if (sai->big_endian_regs)
442 fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
Xiubo Li43550822013-12-17 11:24:38 +0800443
Xiubo Li78957fc2014-02-08 14:38:28 +0800444 sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
445
446 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
447 base = devm_ioremap_resource(&pdev->dev, res);
448 if (IS_ERR(base))
449 return PTR_ERR(base);
450
451 sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
452 "sai", base, &fsl_sai_regmap_config);
453 if (IS_ERR(sai->regmap)) {
454 dev_err(&pdev->dev, "regmap init failed\n");
455 return PTR_ERR(sai->regmap);
Xiubo Li43550822013-12-17 11:24:38 +0800456 }
457
458 sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
459 sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
460 sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
461 sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
462
Xiubo Li43550822013-12-17 11:24:38 +0800463 platform_set_drvdata(pdev, sai);
464
465 ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
466 &fsl_sai_dai, 1);
467 if (ret)
468 return ret;
469
Xiubo Lie5180df32013-12-20 12:30:26 +0800470 return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
Xiubo Li43550822013-12-17 11:24:38 +0800471 SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
Xiubo Li43550822013-12-17 11:24:38 +0800472}
473
474static const struct of_device_id fsl_sai_ids[] = {
475 { .compatible = "fsl,vf610-sai", },
476 { /* sentinel */ }
477};
478
479static struct platform_driver fsl_sai_driver = {
480 .probe = fsl_sai_probe,
Xiubo Li43550822013-12-17 11:24:38 +0800481 .driver = {
482 .name = "fsl-sai",
483 .owner = THIS_MODULE,
484 .of_match_table = fsl_sai_ids,
485 },
486};
487module_platform_driver(fsl_sai_driver);
488
489MODULE_DESCRIPTION("Freescale Soc SAI Interface");
490MODULE_AUTHOR("Xiubo Li, <Li.Xiubo@freescale.com>");
491MODULE_ALIAS("platform:fsl-sai");
492MODULE_LICENSE("GPL");