Linux-libre 4.9.18-gnu
[librecmc/linux-libre.git] / sound / soc / img / img-i2s-in.c
1 /*
2  * IMG I2S input controller driver
3  *
4  * Copyright (C) 2015 Imagination Technologies Ltd.
5  *
6  * Author: Damien Horsley <Damien.Horsley@imgtec.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  */
12
13 #include <linux/clk.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <linux/platform_device.h>
19 #include <linux/reset.h>
20
21 #include <sound/core.h>
22 #include <sound/dmaengine_pcm.h>
23 #include <sound/initval.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
26 #include <sound/soc.h>
27
28 #define IMG_I2S_IN_RX_FIFO                      0x0
29
30 #define IMG_I2S_IN_CTL                          0x4
31 #define IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK         0xfffffffc
32 #define IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT          2
33 #define IMG_I2S_IN_CTL_16PACK_MASK              BIT(1)
34 #define IMG_I2S_IN_CTL_ME_MASK                  BIT(0)
35
36 #define IMG_I2S_IN_CH_CTL                       0x4
37 #define IMG_I2S_IN_CH_CTL_CCDEL_MASK            0x38000
38 #define IMG_I2S_IN_CH_CTL_CCDEL_SHIFT           15
39 #define IMG_I2S_IN_CH_CTL_FEN_MASK              BIT(14)
40 #define IMG_I2S_IN_CH_CTL_FMODE_MASK            BIT(13)
41 #define IMG_I2S_IN_CH_CTL_16PACK_MASK           BIT(12)
42 #define IMG_I2S_IN_CH_CTL_JUST_MASK             BIT(10)
43 #define IMG_I2S_IN_CH_CTL_PACKH_MASK            BIT(9)
44 #define IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK        BIT(8)
45 #define IMG_I2S_IN_CH_CTL_BLKP_MASK             BIT(7)
46 #define IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK       BIT(6)
47 #define IMG_I2S_IN_CH_CTL_LRD_MASK              BIT(3)
48 #define IMG_I2S_IN_CH_CTL_FW_MASK               BIT(2)
49 #define IMG_I2S_IN_CH_CTL_SW_MASK               BIT(1)
50 #define IMG_I2S_IN_CH_CTL_ME_MASK               BIT(0)
51
52 #define IMG_I2S_IN_CH_STRIDE                    0x20
53
54 struct img_i2s_in {
55         void __iomem *base;
56         struct clk *clk_sys;
57         struct snd_dmaengine_dai_dma_data dma_data;
58         struct device *dev;
59         unsigned int max_i2s_chan;
60         void __iomem *channel_base;
61         unsigned int active_channels;
62         struct snd_soc_dai_driver dai_driver;
63 };
64
65 static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg)
66 {
67         writel(val, i2s->base + reg);
68 }
69
70 static inline u32 img_i2s_in_readl(struct img_i2s_in *i2s, u32 reg)
71 {
72         return readl(i2s->base + reg);
73 }
74
75 static inline void img_i2s_in_ch_writel(struct img_i2s_in *i2s, u32 chan,
76                                         u32 val, u32 reg)
77 {
78         writel(val, i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
79 }
80
81 static inline u32 img_i2s_in_ch_readl(struct img_i2s_in *i2s, u32 chan,
82                                         u32 reg)
83 {
84         return readl(i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
85 }
86
87 static inline void img_i2s_in_ch_disable(struct img_i2s_in *i2s, u32 chan)
88 {
89         u32 reg;
90
91         reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
92         reg &= ~IMG_I2S_IN_CH_CTL_ME_MASK;
93         img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
94 }
95
96 static inline void img_i2s_in_ch_enable(struct img_i2s_in *i2s, u32 chan)
97 {
98         u32 reg;
99
100         reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
101         reg |= IMG_I2S_IN_CH_CTL_ME_MASK;
102         img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
103 }
104
105 static inline void img_i2s_in_disable(struct img_i2s_in *i2s)
106 {
107         u32 reg;
108
109         reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
110         reg &= ~IMG_I2S_IN_CTL_ME_MASK;
111         img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
112 }
113
114 static inline void img_i2s_in_enable(struct img_i2s_in *i2s)
115 {
116         u32 reg;
117
118         reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
119         reg |= IMG_I2S_IN_CTL_ME_MASK;
120         img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
121 }
122
123 static inline void img_i2s_in_flush(struct img_i2s_in *i2s)
124 {
125         int i;
126         u32 reg;
127
128         for (i = 0; i < i2s->active_channels; i++) {
129                 reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
130                 reg |= IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
131                 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
132                 reg &= ~IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
133                 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
134         }
135 }
136
137 static int img_i2s_in_trigger(struct snd_pcm_substream *substream, int cmd,
138         struct snd_soc_dai *dai)
139 {
140         struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
141
142         switch (cmd) {
143         case SNDRV_PCM_TRIGGER_START:
144         case SNDRV_PCM_TRIGGER_RESUME:
145         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
146                 img_i2s_in_enable(i2s);
147                 break;
148
149         case SNDRV_PCM_TRIGGER_STOP:
150         case SNDRV_PCM_TRIGGER_SUSPEND:
151         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
152                 img_i2s_in_disable(i2s);
153                 break;
154         default:
155                 return -EINVAL;
156         }
157
158         return 0;
159 }
160
161 static int img_i2s_in_check_rate(struct img_i2s_in *i2s,
162                 unsigned int sample_rate, unsigned int frame_size,
163                 unsigned int *bclk_filter_enable,
164                 unsigned int *bclk_filter_value)
165 {
166         unsigned int bclk_freq, cur_freq;
167
168         bclk_freq = sample_rate * frame_size;
169
170         cur_freq = clk_get_rate(i2s->clk_sys);
171
172         if (cur_freq >= bclk_freq * 8) {
173                 *bclk_filter_enable = 1;
174                 *bclk_filter_value = 0;
175         } else if (cur_freq >= bclk_freq * 7) {
176                 *bclk_filter_enable = 1;
177                 *bclk_filter_value = 1;
178         } else if (cur_freq >= bclk_freq * 6) {
179                 *bclk_filter_enable = 0;
180                 *bclk_filter_value = 0;
181         } else {
182                 dev_err(i2s->dev,
183                         "Sys clock rate %u insufficient for sample rate %u\n",
184                         cur_freq, sample_rate);
185                 return -EINVAL;
186         }
187
188         return 0;
189 }
190
191 static int img_i2s_in_hw_params(struct snd_pcm_substream *substream,
192         struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
193 {
194         struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
195         unsigned int rate, channels, i2s_channels, frame_size;
196         unsigned int bclk_filter_enable, bclk_filter_value;
197         int i, ret = 0;
198         u32 reg, control_mask, chan_control_mask;
199         u32 control_set = 0, chan_control_set = 0;
200         snd_pcm_format_t format;
201
202         rate = params_rate(params);
203         format = params_format(params);
204         channels = params_channels(params);
205         i2s_channels = channels / 2;
206
207         switch (format) {
208         case SNDRV_PCM_FORMAT_S32_LE:
209                 frame_size = 64;
210                 chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
211                 chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
212                 chan_control_set |= IMG_I2S_IN_CH_CTL_PACKH_MASK;
213                 break;
214         case SNDRV_PCM_FORMAT_S24_LE:
215                 frame_size = 64;
216                 chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
217                 chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
218                 break;
219         case SNDRV_PCM_FORMAT_S16_LE:
220                 frame_size = 32;
221                 control_set |= IMG_I2S_IN_CTL_16PACK_MASK;
222                 chan_control_set |= IMG_I2S_IN_CH_CTL_16PACK_MASK;
223                 break;
224         default:
225                 return -EINVAL;
226         }
227
228         if ((channels < 2) ||
229             (channels > (i2s->max_i2s_chan * 2)) ||
230             (channels % 2))
231                 return -EINVAL;
232
233         control_set |= ((i2s_channels - 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT);
234
235         ret = img_i2s_in_check_rate(i2s, rate, frame_size,
236                         &bclk_filter_enable, &bclk_filter_value);
237         if (ret < 0)
238                 return ret;
239
240         if (bclk_filter_enable)
241                 chan_control_set |= IMG_I2S_IN_CH_CTL_FEN_MASK;
242
243         if (bclk_filter_value)
244                 chan_control_set |= IMG_I2S_IN_CH_CTL_FMODE_MASK;
245
246         control_mask = IMG_I2S_IN_CTL_16PACK_MASK |
247                        IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK;
248
249         chan_control_mask = IMG_I2S_IN_CH_CTL_16PACK_MASK |
250                             IMG_I2S_IN_CH_CTL_FEN_MASK |
251                             IMG_I2S_IN_CH_CTL_FMODE_MASK |
252                             IMG_I2S_IN_CH_CTL_SW_MASK |
253                             IMG_I2S_IN_CH_CTL_FW_MASK |
254                             IMG_I2S_IN_CH_CTL_PACKH_MASK;
255
256         reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
257         reg = (reg & ~control_mask) | control_set;
258         img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
259
260         for (i = 0; i < i2s->active_channels; i++)
261                 img_i2s_in_ch_disable(i2s, i);
262
263         for (i = 0; i < i2s->max_i2s_chan; i++) {
264                 reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
265                 reg = (reg & ~chan_control_mask) | chan_control_set;
266                 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
267         }
268
269         i2s->active_channels = i2s_channels;
270
271         img_i2s_in_flush(i2s);
272
273         for (i = 0; i < i2s->active_channels; i++)
274                 img_i2s_in_ch_enable(i2s, i);
275
276         return 0;
277 }
278
279 static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
280 {
281         struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
282         int i;
283         u32 chan_control_mask, lrd_set = 0, blkp_set = 0, chan_control_set = 0;
284         u32 reg;
285
286         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
287         case SND_SOC_DAIFMT_NB_NF:
288                 lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
289                 break;
290         case SND_SOC_DAIFMT_NB_IF:
291                 break;
292         case SND_SOC_DAIFMT_IB_NF:
293                 lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
294                 blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
295                 break;
296         case SND_SOC_DAIFMT_IB_IF:
297                 blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
298                 break;
299         default:
300                 return -EINVAL;
301         }
302
303         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
304         case SND_SOC_DAIFMT_I2S:
305                 chan_control_set |= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
306                 break;
307         case SND_SOC_DAIFMT_LEFT_J:
308                 break;
309         default:
310                 return -EINVAL;
311         }
312
313         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
314         case SND_SOC_DAIFMT_CBM_CFM:
315                 break;
316         default:
317                 return -EINVAL;
318         }
319
320         chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
321
322         for (i = 0; i < i2s->active_channels; i++)
323                 img_i2s_in_ch_disable(i2s, i);
324
325         /*
326          * BLKP and LRD must be set during separate register writes
327          */
328         for (i = 0; i < i2s->max_i2s_chan; i++) {
329                 reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
330                 reg = (reg & ~chan_control_mask) | chan_control_set;
331                 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
332                 reg = (reg & ~IMG_I2S_IN_CH_CTL_BLKP_MASK) | blkp_set;
333                 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
334                 reg = (reg & ~IMG_I2S_IN_CH_CTL_LRD_MASK) | lrd_set;
335                 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
336         }
337
338         for (i = 0; i < i2s->active_channels; i++)
339                 img_i2s_in_ch_enable(i2s, i);
340
341         return 0;
342 }
343
344 static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
345         .trigger = img_i2s_in_trigger,
346         .hw_params = img_i2s_in_hw_params,
347         .set_fmt = img_i2s_in_set_fmt
348 };
349
350 static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
351 {
352         struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
353
354         snd_soc_dai_init_dma_data(dai, NULL, &i2s->dma_data);
355
356         return 0;
357 }
358
359 static const struct snd_soc_component_driver img_i2s_in_component = {
360         .name = "img-i2s-in"
361 };
362
363 static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st,
364         struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
365 {
366         unsigned int i2s_channels = params_channels(params) / 2;
367         struct snd_soc_pcm_runtime *rtd = st->private_data;
368         struct snd_dmaengine_dai_dma_data *dma_data;
369         int ret;
370
371         dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st);
372
373         ret = snd_hwparams_to_dma_slave_config(st, params, sc);
374         if (ret)
375                 return ret;
376
377         sc->src_addr = dma_data->addr;
378         sc->src_addr_width = dma_data->addr_width;
379         sc->src_maxburst = 4 * i2s_channels;
380
381         return 0;
382 }
383
384 static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = {
385         .prepare_slave_config = img_i2s_in_dma_prepare_slave_config
386 };
387
388 static int img_i2s_in_probe(struct platform_device *pdev)
389 {
390         struct img_i2s_in *i2s;
391         struct resource *res;
392         void __iomem *base;
393         int ret, i;
394         struct reset_control *rst;
395         unsigned int max_i2s_chan_pow_2;
396         struct device *dev = &pdev->dev;
397
398         i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
399         if (!i2s)
400                 return -ENOMEM;
401
402         platform_set_drvdata(pdev, i2s);
403
404         i2s->dev = dev;
405
406         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
407         base = devm_ioremap_resource(dev, res);
408         if (IS_ERR(base))
409                 return PTR_ERR(base);
410
411         i2s->base = base;
412
413         if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
414                         &i2s->max_i2s_chan)) {
415                 dev_err(dev, "No img,i2s-channels property\n");
416                 return -EINVAL;
417         }
418
419         max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
420
421         i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
422
423         i2s->clk_sys = devm_clk_get(dev, "sys");
424         if (IS_ERR(i2s->clk_sys)) {
425                 if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER)
426                         dev_err(dev, "Failed to acquire clock 'sys'\n");
427                 return PTR_ERR(i2s->clk_sys);
428         }
429
430         ret = clk_prepare_enable(i2s->clk_sys);
431         if (ret)
432                 return ret;
433
434         i2s->active_channels = 1;
435         i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
436         i2s->dma_data.addr_width = 4;
437
438         i2s->dai_driver.probe = img_i2s_in_dai_probe;
439         i2s->dai_driver.capture.channels_min = 2;
440         i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
441         i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
442         i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE |
443                 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE;
444         i2s->dai_driver.ops = &img_i2s_in_dai_ops;
445
446         rst = devm_reset_control_get(dev, "rst");
447         if (IS_ERR(rst)) {
448                 if (PTR_ERR(rst) == -EPROBE_DEFER) {
449                         ret = -EPROBE_DEFER;
450                         goto err_clk_disable;
451                 }
452
453                 dev_dbg(dev, "No top level reset found\n");
454
455                 img_i2s_in_disable(i2s);
456
457                 for (i = 0; i < i2s->max_i2s_chan; i++)
458                         img_i2s_in_ch_disable(i2s, i);
459         } else {
460                 reset_control_assert(rst);
461                 reset_control_deassert(rst);
462         }
463
464         img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL);
465
466         for (i = 0; i < i2s->max_i2s_chan; i++)
467                 img_i2s_in_ch_writel(i2s, i,
468                         (4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) |
469                         IMG_I2S_IN_CH_CTL_JUST_MASK |
470                         IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL);
471
472         ret = devm_snd_soc_register_component(dev, &img_i2s_in_component,
473                                                 &i2s->dai_driver, 1);
474         if (ret)
475                 goto err_clk_disable;
476
477         ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0);
478         if (ret)
479                 goto err_clk_disable;
480
481         return 0;
482
483 err_clk_disable:
484         clk_disable_unprepare(i2s->clk_sys);
485
486         return ret;
487 }
488
489 static int img_i2s_in_dev_remove(struct platform_device *pdev)
490 {
491         struct img_i2s_in *i2s = platform_get_drvdata(pdev);
492
493         clk_disable_unprepare(i2s->clk_sys);
494
495         return 0;
496 }
497
498 static const struct of_device_id img_i2s_in_of_match[] = {
499         { .compatible = "img,i2s-in" },
500         {}
501 };
502 MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
503
504 static struct platform_driver img_i2s_in_driver = {
505         .driver = {
506                 .name = "img-i2s-in",
507                 .of_match_table = img_i2s_in_of_match
508         },
509         .probe = img_i2s_in_probe,
510         .remove = img_i2s_in_dev_remove
511 };
512 module_platform_driver(img_i2s_in_driver);
513
514 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
515 MODULE_DESCRIPTION("IMG I2S Input Driver");
516 MODULE_LICENSE("GPL v2");