blob: 26d9f5ed6959671d875f2b3d239452c8ec58160b [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
Xiubo Li13cde092014-02-25 17:54:51 +0800108 /* DAI mode */
Xiubo Li43550822013-12-17 11:24:38 +0800109 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
110 case SND_SOC_DAIFMT_I2S:
Xiubo Li13cde092014-02-25 17:54:51 +0800111 /* Data on rising edge of bclk, frame low, 1clk before data */
112 val_cr2 &= ~FSL_SAI_CR2_BCP;
113 val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP;
Xiubo Li43550822013-12-17 11:24:38 +0800114 break;
Xiubo Li13cde092014-02-25 17:54:51 +0800115 case SND_SOC_DAIFMT_LEFT_J:
116 /* Data on rising edge of bclk, frame high, 0clk before data */
117 val_cr2 &= ~FSL_SAI_CR2_BCP;
118 val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
119 break;
120 case SND_SOC_DAIFMT_RIGHT_J:
121 /* To be done */
Xiubo Li43550822013-12-17 11:24:38 +0800122 default:
123 return -EINVAL;
124 }
125
Xiubo Li13cde092014-02-25 17:54:51 +0800126 /* DAI clock inversion */
Xiubo Li43550822013-12-17 11:24:38 +0800127 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
128 case SND_SOC_DAIFMT_IB_IF:
Xiubo Li13cde092014-02-25 17:54:51 +0800129 /* Invert both clocks */
130 val_cr2 ^= FSL_SAI_CR2_BCP;
131 val_cr4 ^= FSL_SAI_CR4_FSP;
Xiubo Li43550822013-12-17 11:24:38 +0800132 break;
133 case SND_SOC_DAIFMT_IB_NF:
Xiubo Li13cde092014-02-25 17:54:51 +0800134 /* Invert bit clock */
135 val_cr2 ^= FSL_SAI_CR2_BCP;
Xiubo Li43550822013-12-17 11:24:38 +0800136 break;
137 case SND_SOC_DAIFMT_NB_IF:
Xiubo Li13cde092014-02-25 17:54:51 +0800138 /* Invert frame clock */
139 val_cr4 ^= FSL_SAI_CR4_FSP;
Xiubo Li43550822013-12-17 11:24:38 +0800140 break;
141 case SND_SOC_DAIFMT_NB_NF:
Xiubo Li13cde092014-02-25 17:54:51 +0800142 /* Nothing to do for both normal cases */
Xiubo Li43550822013-12-17 11:24:38 +0800143 break;
144 default:
145 return -EINVAL;
146 }
147
Xiubo Li13cde092014-02-25 17:54:51 +0800148 /* DAI clock master masks */
Xiubo Li43550822013-12-17 11:24:38 +0800149 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
150 case SND_SOC_DAIFMT_CBS_CFS:
151 val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
152 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
153 break;
154 case SND_SOC_DAIFMT_CBM_CFM:
155 val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
156 val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
157 break;
Xiubo Li13cde092014-02-25 17:54:51 +0800158 case SND_SOC_DAIFMT_CBS_CFM:
159 val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
160 val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
161 break;
162 case SND_SOC_DAIFMT_CBM_CFS:
163 val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
164 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
165 break;
Xiubo Li43550822013-12-17 11:24:38 +0800166 default:
167 return -EINVAL;
168 }
169
Xiubo Li78957fc2014-02-08 14:38:28 +0800170 regmap_write(sai->regmap, reg_cr2, val_cr2);
171 regmap_write(sai->regmap, reg_cr4, val_cr4);
Xiubo Li43550822013-12-17 11:24:38 +0800172
173 return 0;
174}
175
176static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
177{
Nicolin Chen4e3a99f2013-12-20 16:41:05 +0800178 int ret;
Xiubo Li43550822013-12-17 11:24:38 +0800179
Xiubo Li43550822013-12-17 11:24:38 +0800180 ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
181 if (ret) {
Nicolin Chen190af122013-12-20 16:41:04 +0800182 dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
Xiubo Li78957fc2014-02-08 14:38:28 +0800183 return ret;
Xiubo Li43550822013-12-17 11:24:38 +0800184 }
185
186 ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
Xiubo Li78957fc2014-02-08 14:38:28 +0800187 if (ret)
Nicolin Chen190af122013-12-20 16:41:04 +0800188 dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
Xiubo Li43550822013-12-17 11:24:38 +0800189
Nicolin Chen1fb2d9d2013-12-20 16:41:00 +0800190 return ret;
Xiubo Li43550822013-12-17 11:24:38 +0800191}
192
193static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
194 struct snd_pcm_hw_params *params,
195 struct snd_soc_dai *cpu_dai)
196{
Nicolin Chen4e3a99f2013-12-20 16:41:05 +0800197 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Nicolin Chen1d700302013-12-20 16:41:01 +0800198 u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
Xiubo Li43550822013-12-17 11:24:38 +0800199 unsigned int channels = params_channels(params);
Nicolin Chen1d700302013-12-20 16:41:01 +0800200 u32 word_width = snd_pcm_format_width(params_format(params));
Xiubo Li43550822013-12-17 11:24:38 +0800201
202 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
203 reg_cr4 = FSL_SAI_TCR4;
204 reg_cr5 = FSL_SAI_TCR5;
205 reg_mr = FSL_SAI_TMR;
206 } else {
207 reg_cr4 = FSL_SAI_RCR4;
208 reg_cr5 = FSL_SAI_RCR5;
209 reg_mr = FSL_SAI_RMR;
210 }
211
Xiubo Li78957fc2014-02-08 14:38:28 +0800212 regmap_read(sai->regmap, reg_cr4, &val_cr4);
213 regmap_read(sai->regmap, reg_cr4, &val_cr5);
214
Xiubo Li43550822013-12-17 11:24:38 +0800215 val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
216 val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
217
Xiubo Li43550822013-12-17 11:24:38 +0800218 val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
219 val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
220 val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
221
Xiubo Li43550822013-12-17 11:24:38 +0800222 val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
223 val_cr5 |= FSL_SAI_CR5_WNW(word_width);
224 val_cr5 |= FSL_SAI_CR5_W0W(word_width);
225
Xiubo Li496a39d2013-12-31 15:33:21 +0800226 val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
Xiubo Li43550822013-12-17 11:24:38 +0800227 if (sai->big_endian_data)
Xiubo Li43550822013-12-17 11:24:38 +0800228 val_cr5 |= FSL_SAI_CR5_FBT(0);
Xiubo Li72aa62b2013-12-31 15:33:22 +0800229 else
230 val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
Xiubo Li43550822013-12-17 11:24:38 +0800231
232 val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
Nicolin Chend22e28c2013-12-20 16:41:02 +0800233 val_mr = ~0UL - ((1 << channels) - 1);
Xiubo Li43550822013-12-17 11:24:38 +0800234
Xiubo Li78957fc2014-02-08 14:38:28 +0800235 regmap_write(sai->regmap, reg_cr4, val_cr4);
236 regmap_write(sai->regmap, reg_cr5, val_cr5);
237 regmap_write(sai->regmap, reg_mr, val_mr);
Xiubo Li43550822013-12-17 11:24:38 +0800238
239 return 0;
240}
241
242static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
243 struct snd_soc_dai *cpu_dai)
244{
245 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Xiubo Li78957fc2014-02-08 14:38:28 +0800246 u32 tcsr, rcsr;
Xiubo Li496a39d2013-12-31 15:33:21 +0800247
Xiubo Li78957fc2014-02-08 14:38:28 +0800248 regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
249 ~FSL_SAI_CR2_SYNC);
250 regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
251 FSL_SAI_CR2_SYNC);
Xiubo Li496a39d2013-12-31 15:33:21 +0800252
Xiubo Li78957fc2014-02-08 14:38:28 +0800253 regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr);
254 regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr);
Xiubo Li43550822013-12-17 11:24:38 +0800255
256 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
257 tcsr |= FSL_SAI_CSR_FRDE;
258 rcsr &= ~FSL_SAI_CSR_FRDE;
259 } else {
260 rcsr |= FSL_SAI_CSR_FRDE;
261 tcsr &= ~FSL_SAI_CSR_FRDE;
262 }
263
264 switch (cmd) {
265 case SNDRV_PCM_TRIGGER_START:
266 case SNDRV_PCM_TRIGGER_RESUME:
267 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
268 tcsr |= FSL_SAI_CSR_TERE;
269 rcsr |= FSL_SAI_CSR_TERE;
Xiubo Lie5d0fa92013-12-25 12:40:04 +0800270
Xiubo Li78957fc2014-02-08 14:38:28 +0800271 regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
272 regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
Xiubo Li43550822013-12-17 11:24:38 +0800273 break;
Xiubo Li43550822013-12-17 11:24:38 +0800274 case SNDRV_PCM_TRIGGER_STOP:
275 case SNDRV_PCM_TRIGGER_SUSPEND:
276 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
277 if (!(cpu_dai->playback_active || cpu_dai->capture_active)) {
278 tcsr &= ~FSL_SAI_CSR_TERE;
279 rcsr &= ~FSL_SAI_CSR_TERE;
280 }
Xiubo Lie5d0fa92013-12-25 12:40:04 +0800281
Xiubo Li78957fc2014-02-08 14:38:28 +0800282 regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
283 regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
Xiubo Li43550822013-12-17 11:24:38 +0800284 break;
285 default:
286 return -EINVAL;
287 }
288
289 return 0;
290}
291
292static int fsl_sai_startup(struct snd_pcm_substream *substream,
293 struct snd_soc_dai *cpu_dai)
294{
Xiubo Li43550822013-12-17 11:24:38 +0800295 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Xiubo Li78957fc2014-02-08 14:38:28 +0800296 u32 reg;
Xiubo Li43550822013-12-17 11:24:38 +0800297
Xiubo Li78957fc2014-02-08 14:38:28 +0800298 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
299 reg = FSL_SAI_TCR3;
300 else
301 reg = FSL_SAI_RCR3;
302
303 regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
304 FSL_SAI_CR3_TRCE);
305
306 return 0;
Xiubo Li43550822013-12-17 11:24:38 +0800307}
308
309static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
310 struct snd_soc_dai *cpu_dai)
311{
312 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
Xiubo Li78957fc2014-02-08 14:38:28 +0800313 u32 reg;
Xiubo Li43550822013-12-17 11:24:38 +0800314
Xiubo Li78957fc2014-02-08 14:38:28 +0800315 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
316 reg = FSL_SAI_TCR3;
317 else
318 reg = FSL_SAI_RCR3;
319
320 regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
321 ~FSL_SAI_CR3_TRCE);
Xiubo Li43550822013-12-17 11:24:38 +0800322}
323
324static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
325 .set_sysclk = fsl_sai_set_dai_sysclk,
326 .set_fmt = fsl_sai_set_dai_fmt,
327 .hw_params = fsl_sai_hw_params,
328 .trigger = fsl_sai_trigger,
329 .startup = fsl_sai_startup,
330 .shutdown = fsl_sai_shutdown,
331};
332
333static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
334{
335 struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
Xiubo Lie6dc12d2013-12-25 11:20:14 +0800336
Xiubo Li78957fc2014-02-08 14:38:28 +0800337 regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
338 regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
339 regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
340 FSL_SAI_MAXBURST_TX * 2);
341 regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
342 FSL_SAI_MAXBURST_RX - 1);
Xiubo Li43550822013-12-17 11:24:38 +0800343
Xiubo Lidd9f4062013-12-20 12:35:33 +0800344 snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
345 &sai->dma_params_rx);
Xiubo Li43550822013-12-17 11:24:38 +0800346
347 snd_soc_dai_set_drvdata(cpu_dai, sai);
348
349 return 0;
350}
351
Xiubo Li43550822013-12-17 11:24:38 +0800352static struct snd_soc_dai_driver fsl_sai_dai = {
353 .probe = fsl_sai_dai_probe,
Xiubo Li43550822013-12-17 11:24:38 +0800354 .playback = {
355 .channels_min = 1,
356 .channels_max = 2,
357 .rates = SNDRV_PCM_RATE_8000_96000,
358 .formats = FSL_SAI_FORMATS,
359 },
360 .capture = {
361 .channels_min = 1,
362 .channels_max = 2,
363 .rates = SNDRV_PCM_RATE_8000_96000,
364 .formats = FSL_SAI_FORMATS,
365 },
366 .ops = &fsl_sai_pcm_dai_ops,
367};
368
369static const struct snd_soc_component_driver fsl_component = {
370 .name = "fsl-sai",
371};
372
Xiubo Li78957fc2014-02-08 14:38:28 +0800373static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
374{
375 switch (reg) {
376 case FSL_SAI_TCSR:
377 case FSL_SAI_TCR1:
378 case FSL_SAI_TCR2:
379 case FSL_SAI_TCR3:
380 case FSL_SAI_TCR4:
381 case FSL_SAI_TCR5:
382 case FSL_SAI_TFR:
383 case FSL_SAI_TMR:
384 case FSL_SAI_RCSR:
385 case FSL_SAI_RCR1:
386 case FSL_SAI_RCR2:
387 case FSL_SAI_RCR3:
388 case FSL_SAI_RCR4:
389 case FSL_SAI_RCR5:
390 case FSL_SAI_RDR:
391 case FSL_SAI_RFR:
392 case FSL_SAI_RMR:
393 return true;
394 default:
395 return false;
396 }
397}
398
399static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
400{
401 switch (reg) {
402 case FSL_SAI_TFR:
403 case FSL_SAI_RFR:
404 case FSL_SAI_TDR:
405 case FSL_SAI_RDR:
406 return true;
407 default:
408 return false;
409 }
410
411}
412
413static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
414{
415 switch (reg) {
416 case FSL_SAI_TCSR:
417 case FSL_SAI_TCR1:
418 case FSL_SAI_TCR2:
419 case FSL_SAI_TCR3:
420 case FSL_SAI_TCR4:
421 case FSL_SAI_TCR5:
422 case FSL_SAI_TDR:
423 case FSL_SAI_TMR:
424 case FSL_SAI_RCSR:
425 case FSL_SAI_RCR1:
426 case FSL_SAI_RCR2:
427 case FSL_SAI_RCR3:
428 case FSL_SAI_RCR4:
429 case FSL_SAI_RCR5:
430 case FSL_SAI_RMR:
431 return true;
432 default:
433 return false;
434 }
435}
436
437static struct regmap_config fsl_sai_regmap_config = {
438 .reg_bits = 32,
439 .reg_stride = 4,
440 .val_bits = 32,
441
442 .max_register = FSL_SAI_RMR,
443 .readable_reg = fsl_sai_readable_reg,
444 .volatile_reg = fsl_sai_volatile_reg,
445 .writeable_reg = fsl_sai_writeable_reg,
446};
447
Xiubo Li43550822013-12-17 11:24:38 +0800448static int fsl_sai_probe(struct platform_device *pdev)
449{
Nicolin Chen4e3a99f2013-12-20 16:41:05 +0800450 struct device_node *np = pdev->dev.of_node;
Xiubo Li43550822013-12-17 11:24:38 +0800451 struct fsl_sai *sai;
452 struct resource *res;
Xiubo Li78957fc2014-02-08 14:38:28 +0800453 void __iomem *base;
Nicolin Chen4e3a99f2013-12-20 16:41:05 +0800454 int ret;
Xiubo Li43550822013-12-17 11:24:38 +0800455
456 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
457 if (!sai)
458 return -ENOMEM;
459
Xiubo Li78957fc2014-02-08 14:38:28 +0800460 sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
461 if (sai->big_endian_regs)
462 fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
Xiubo Li43550822013-12-17 11:24:38 +0800463
Xiubo Li78957fc2014-02-08 14:38:28 +0800464 sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
465
466 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
467 base = devm_ioremap_resource(&pdev->dev, res);
468 if (IS_ERR(base))
469 return PTR_ERR(base);
470
471 sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
472 "sai", base, &fsl_sai_regmap_config);
473 if (IS_ERR(sai->regmap)) {
474 dev_err(&pdev->dev, "regmap init failed\n");
475 return PTR_ERR(sai->regmap);
Xiubo Li43550822013-12-17 11:24:38 +0800476 }
477
478 sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
479 sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
480 sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
481 sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
482
Xiubo Li43550822013-12-17 11:24:38 +0800483 platform_set_drvdata(pdev, sai);
484
485 ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
486 &fsl_sai_dai, 1);
487 if (ret)
488 return ret;
489
Xiubo Lie5180df32013-12-20 12:30:26 +0800490 return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
Xiubo Li43550822013-12-17 11:24:38 +0800491 SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
Xiubo Li43550822013-12-17 11:24:38 +0800492}
493
494static const struct of_device_id fsl_sai_ids[] = {
495 { .compatible = "fsl,vf610-sai", },
496 { /* sentinel */ }
497};
498
499static struct platform_driver fsl_sai_driver = {
500 .probe = fsl_sai_probe,
Xiubo Li43550822013-12-17 11:24:38 +0800501 .driver = {
502 .name = "fsl-sai",
503 .owner = THIS_MODULE,
504 .of_match_table = fsl_sai_ids,
505 },
506};
507module_platform_driver(fsl_sai_driver);
508
509MODULE_DESCRIPTION("Freescale Soc SAI Interface");
510MODULE_AUTHOR("Xiubo Li, <Li.Xiubo@freescale.com>");
511MODULE_ALIAS("platform:fsl-sai");
512MODULE_LICENSE("GPL");