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