8450bff6fb1350c85b5a001f7b9d7bfaed1d60c6
[firefly-linux-kernel-4.4.55.git] / 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/slab.h>
19 #include <sound/core.h>
20 #include <sound/dmaengine_pcm.h>
21 #include <sound/pcm_params.h>
22
23 #include "fsl_sai.h"
24
25 static inline u32 sai_readl(struct fsl_sai *sai,
26                 const void __iomem *addr)
27 {
28         u32 val;
29
30         val = __raw_readl(addr);
31
32         if (likely(sai->big_endian_regs))
33                 val = be32_to_cpu(val);
34         else
35                 val = le32_to_cpu(val);
36         rmb();
37
38         return val;
39 }
40
41 static inline void sai_writel(struct fsl_sai *sai,
42                 u32 val, void __iomem *addr)
43 {
44         wmb();
45         if (likely(sai->big_endian_regs))
46                 val = cpu_to_be32(val);
47         else
48                 val = cpu_to_le32(val);
49
50         __raw_writel(val, addr);
51 }
52
53 static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
54                 int clk_id, unsigned int freq, int fsl_dir)
55 {
56         u32 val_cr2, reg_cr2;
57         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
58
59         if (fsl_dir == FSL_FMT_TRANSMITTER)
60                 reg_cr2 = FSL_SAI_TCR2;
61         else
62                 reg_cr2 = FSL_SAI_RCR2;
63
64         val_cr2 = sai_readl(sai, sai->base + reg_cr2);
65         switch (clk_id) {
66         case FSL_SAI_CLK_BUS:
67                 val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
68                 val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
69                 break;
70         case FSL_SAI_CLK_MAST1:
71                 val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
72                 val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
73                 break;
74         case FSL_SAI_CLK_MAST2:
75                 val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
76                 val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
77                 break;
78         case FSL_SAI_CLK_MAST3:
79                 val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
80                 val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
81                 break;
82         default:
83                 return -EINVAL;
84         }
85         sai_writel(sai, val_cr2, sai->base + reg_cr2);
86
87         return 0;
88 }
89
90 static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
91                 int clk_id, unsigned int freq, int dir)
92 {
93         int ret;
94         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
95
96         if (dir == SND_SOC_CLOCK_IN)
97                 return 0;
98
99         ret = clk_prepare_enable(sai->clk);
100         if (ret)
101                 return ret;
102
103         sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR);
104         sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR);
105         sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1);
106         sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1);
107
108         ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
109                                         FSL_FMT_TRANSMITTER);
110         if (ret) {
111                 dev_err(cpu_dai->dev,
112                                 "Cannot set SAI's transmitter sysclk: %d\n",
113                                 ret);
114                 goto err_clk;
115         }
116
117         ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
118                                         FSL_FMT_RECEIVER);
119         if (ret) {
120                 dev_err(cpu_dai->dev,
121                                 "Cannot set SAI's receiver sysclk: %d\n",
122                                 ret);
123                 goto err_clk;
124         }
125
126 err_clk:
127         clk_disable_unprepare(sai->clk);
128
129         return ret;
130 }
131
132 static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
133                                 unsigned int fmt, int fsl_dir)
134 {
135         u32 val_cr2, val_cr3, val_cr4, reg_cr2, reg_cr3, reg_cr4;
136         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
137
138         if (fsl_dir == FSL_FMT_TRANSMITTER) {
139                 reg_cr2 = FSL_SAI_TCR2;
140                 reg_cr3 = FSL_SAI_TCR3;
141                 reg_cr4 = FSL_SAI_TCR4;
142         } else {
143                 reg_cr2 = FSL_SAI_RCR2;
144                 reg_cr3 = FSL_SAI_RCR3;
145                 reg_cr4 = FSL_SAI_RCR4;
146         }
147
148         val_cr2 = sai_readl(sai, sai->base + reg_cr2);
149         val_cr3 = sai_readl(sai, sai->base + reg_cr3);
150         val_cr4 = sai_readl(sai, sai->base + reg_cr4);
151
152         if (sai->big_endian_data)
153                 val_cr4 |= FSL_SAI_CR4_MF;
154         else
155                 val_cr4 &= ~FSL_SAI_CR4_MF;
156
157         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
158         case SND_SOC_DAIFMT_I2S:
159                 val_cr4 |= FSL_SAI_CR4_FSE;
160                 val_cr4 |= FSL_SAI_CR4_FSP;
161                 break;
162         default:
163                 return -EINVAL;
164         }
165
166         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
167         case SND_SOC_DAIFMT_IB_IF:
168                 val_cr4 |= FSL_SAI_CR4_FSP;
169                 val_cr2 &= ~FSL_SAI_CR2_BCP;
170                 break;
171         case SND_SOC_DAIFMT_IB_NF:
172                 val_cr4 &= ~FSL_SAI_CR4_FSP;
173                 val_cr2 &= ~FSL_SAI_CR2_BCP;
174                 break;
175         case SND_SOC_DAIFMT_NB_IF:
176                 val_cr4 |= FSL_SAI_CR4_FSP;
177                 val_cr2 |= FSL_SAI_CR2_BCP;
178                 break;
179         case SND_SOC_DAIFMT_NB_NF:
180                 val_cr4 &= ~FSL_SAI_CR4_FSP;
181                 val_cr2 |= FSL_SAI_CR2_BCP;
182                 break;
183         default:
184                 return -EINVAL;
185         }
186
187         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
188         case SND_SOC_DAIFMT_CBS_CFS:
189                 val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
190                 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
191                 break;
192         case SND_SOC_DAIFMT_CBM_CFM:
193                 val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
194                 val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
195                 break;
196         default:
197                 return -EINVAL;
198         }
199
200         val_cr3 |= FSL_SAI_CR3_TRCE;
201
202         if (fsl_dir == FSL_FMT_RECEIVER)
203                 val_cr2 |= FSL_SAI_CR2_SYNC;
204
205         sai_writel(sai, val_cr2, sai->base + reg_cr2);
206         sai_writel(sai, val_cr3, sai->base + reg_cr3);
207         sai_writel(sai, val_cr4, sai->base + reg_cr4);
208
209         return 0;
210 }
211
212 static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
213 {
214         int ret;
215         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
216
217         ret = clk_prepare_enable(sai->clk);
218         if (ret)
219                 return ret;
220
221         ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
222         if (ret) {
223                 dev_err(cpu_dai->dev,
224                                 "Cannot set SAI's transmitter format: %d\n",
225                                 ret);
226                 goto err_clk;
227         }
228
229         ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
230         if (ret) {
231                 dev_err(cpu_dai->dev,
232                                 "Cannot set SAI's receiver format: %d\n",
233                                 ret);
234                 goto err_clk;
235         }
236
237 err_clk:
238         clk_disable_unprepare(sai->clk);
239
240         return ret;
241 }
242
243 static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
244                 struct snd_pcm_hw_params *params,
245                 struct snd_soc_dai *cpu_dai)
246 {
247         u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
248         unsigned int channels = params_channels(params);
249         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
250         u32 word_width = snd_pcm_format_width(params_format(params));
251
252         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
253                 reg_cr4 = FSL_SAI_TCR4;
254                 reg_cr5 = FSL_SAI_TCR5;
255                 reg_mr = FSL_SAI_TMR;
256         } else {
257                 reg_cr4 = FSL_SAI_RCR4;
258                 reg_cr5 = FSL_SAI_RCR5;
259                 reg_mr = FSL_SAI_RMR;
260         }
261
262         val_cr4 = sai_readl(sai, sai->base + reg_cr4);
263         val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
264         val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
265
266         val_cr5 = sai_readl(sai, sai->base + reg_cr5);
267         val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
268         val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
269         val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
270
271         val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
272         val_cr5 |= FSL_SAI_CR5_WNW(word_width);
273         val_cr5 |= FSL_SAI_CR5_W0W(word_width);
274
275         if (sai->big_endian_data)
276                 val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
277         else
278                 val_cr5 |= FSL_SAI_CR5_FBT(0);
279
280         val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
281         val_mr = ~0UL - ((1 << channels) - 1);
282
283         sai_writel(sai, val_cr4, sai->base + reg_cr4);
284         sai_writel(sai, val_cr5, sai->base + reg_cr5);
285         sai_writel(sai, val_mr, sai->base + reg_mr);
286
287         return 0;
288 }
289
290 static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
291                 struct snd_soc_dai *cpu_dai)
292 {
293         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
294         unsigned int tcsr, rcsr;
295
296         tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR);
297         rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR);
298
299         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
300                 tcsr |= FSL_SAI_CSR_FRDE;
301                 rcsr &= ~FSL_SAI_CSR_FRDE;
302         } else {
303                 rcsr |= FSL_SAI_CSR_FRDE;
304                 tcsr &= ~FSL_SAI_CSR_FRDE;
305         }
306
307         switch (cmd) {
308         case SNDRV_PCM_TRIGGER_START:
309         case SNDRV_PCM_TRIGGER_RESUME:
310         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
311                 tcsr |= FSL_SAI_CSR_TERE;
312                 rcsr |= FSL_SAI_CSR_TERE;
313                 sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
314                 sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
315                 break;
316
317         case SNDRV_PCM_TRIGGER_STOP:
318         case SNDRV_PCM_TRIGGER_SUSPEND:
319         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
320                 if (!(cpu_dai->playback_active || cpu_dai->capture_active)) {
321                         tcsr &= ~FSL_SAI_CSR_TERE;
322                         rcsr &= ~FSL_SAI_CSR_TERE;
323                 }
324                 sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
325                 sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
326                 break;
327         default:
328                 return -EINVAL;
329         }
330
331         return 0;
332 }
333
334 static int fsl_sai_startup(struct snd_pcm_substream *substream,
335                 struct snd_soc_dai *cpu_dai)
336 {
337         int ret;
338         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
339
340         ret = clk_prepare_enable(sai->clk);
341
342         return ret;
343 }
344
345 static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
346                 struct snd_soc_dai *cpu_dai)
347 {
348         struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
349
350         clk_disable_unprepare(sai->clk);
351 }
352
353 static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
354         .set_sysclk     = fsl_sai_set_dai_sysclk,
355         .set_fmt        = fsl_sai_set_dai_fmt,
356         .hw_params      = fsl_sai_hw_params,
357         .trigger        = fsl_sai_trigger,
358         .startup        = fsl_sai_startup,
359         .shutdown       = fsl_sai_shutdown,
360 };
361
362 static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
363 {
364         struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
365
366         snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
367                                 &sai->dma_params_rx);
368
369         snd_soc_dai_set_drvdata(cpu_dai, sai);
370
371         return 0;
372 }
373
374 static struct snd_soc_dai_driver fsl_sai_dai = {
375         .probe = fsl_sai_dai_probe,
376         .playback = {
377                 .channels_min = 1,
378                 .channels_max = 2,
379                 .rates = SNDRV_PCM_RATE_8000_96000,
380                 .formats = FSL_SAI_FORMATS,
381         },
382         .capture = {
383                 .channels_min = 1,
384                 .channels_max = 2,
385                 .rates = SNDRV_PCM_RATE_8000_96000,
386                 .formats = FSL_SAI_FORMATS,
387         },
388         .ops = &fsl_sai_pcm_dai_ops,
389 };
390
391 static const struct snd_soc_component_driver fsl_component = {
392         .name           = "fsl-sai",
393 };
394
395 static int fsl_sai_probe(struct platform_device *pdev)
396 {
397         int ret;
398         struct fsl_sai *sai;
399         struct resource *res;
400         struct device_node *np = pdev->dev.of_node;
401
402         sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
403         if (!sai)
404                 return -ENOMEM;
405
406         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
407         sai->base = devm_ioremap_resource(&pdev->dev, res);
408         if (IS_ERR(sai->base))
409                 return PTR_ERR(sai->base);
410
411         sai->clk = devm_clk_get(&pdev->dev, "sai");
412         if (IS_ERR(sai->clk)) {
413                 dev_err(&pdev->dev, "Cannot get SAI's clock\n");
414                 return PTR_ERR(sai->clk);
415         }
416
417         sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
418         sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
419         sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
420         sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
421
422         sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
423         sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
424
425         platform_set_drvdata(pdev, sai);
426
427         ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
428                         &fsl_sai_dai, 1);
429         if (ret)
430                 return ret;
431
432         return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
433                         SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
434 }
435
436 static const struct of_device_id fsl_sai_ids[] = {
437         { .compatible = "fsl,vf610-sai", },
438         { /* sentinel */ }
439 };
440
441 static struct platform_driver fsl_sai_driver = {
442         .probe = fsl_sai_probe,
443         .driver = {
444                 .name = "fsl-sai",
445                 .owner = THIS_MODULE,
446                 .of_match_table = fsl_sai_ids,
447         },
448 };
449 module_platform_driver(fsl_sai_driver);
450
451 MODULE_DESCRIPTION("Freescale Soc SAI Interface");
452 MODULE_AUTHOR("Xiubo Li, <Li.Xiubo@freescale.com>");
453 MODULE_ALIAS("platform:fsl-sai");
454 MODULE_LICENSE("GPL");