Merge tag 'asm-generic-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd...
[deliverable/linux.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");
This page took 0.043571 seconds and 5 git commands to generate.