2 * IMG I2S input controller driver
4 * Copyright (C) 2015 Imagination Technologies Ltd.
6 * Author: Damien Horsley <Damien.Horsley@imgtec.com>
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.
13 #include <linux/clk.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/reset.h>
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>
28 #define IMG_I2S_IN_RX_FIFO 0x0
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)
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)
52 #define IMG_I2S_IN_CH_STRIDE 0x20
57 struct snd_dmaengine_dai_dma_data dma_data
;
59 unsigned int max_i2s_chan
;
60 void __iomem
*channel_base
;
61 unsigned int active_channels
;
62 struct snd_soc_dai_driver dai_driver
;
65 static inline void img_i2s_in_writel(struct img_i2s_in
*i2s
, u32 val
, u32 reg
)
67 writel(val
, i2s
->base
+ reg
);
70 static inline u32
img_i2s_in_readl(struct img_i2s_in
*i2s
, u32 reg
)
72 return readl(i2s
->base
+ reg
);
75 static inline void img_i2s_in_ch_writel(struct img_i2s_in
*i2s
, u32 chan
,
78 writel(val
, i2s
->channel_base
+ (chan
* IMG_I2S_IN_CH_STRIDE
) + reg
);
81 static inline u32
img_i2s_in_ch_readl(struct img_i2s_in
*i2s
, u32 chan
,
84 return readl(i2s
->channel_base
+ (chan
* IMG_I2S_IN_CH_STRIDE
) + reg
);
87 static inline void img_i2s_in_ch_disable(struct img_i2s_in
*i2s
, u32 chan
)
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
);
96 static inline void img_i2s_in_ch_enable(struct img_i2s_in
*i2s
, u32 chan
)
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
);
105 static inline void img_i2s_in_disable(struct img_i2s_in
*i2s
)
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
);
114 static inline void img_i2s_in_enable(struct img_i2s_in
*i2s
)
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
);
123 static inline void img_i2s_in_flush(struct img_i2s_in
*i2s
)
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
);
137 static int img_i2s_in_trigger(struct snd_pcm_substream
*substream
, int cmd
,
138 struct snd_soc_dai
*dai
)
140 struct img_i2s_in
*i2s
= snd_soc_dai_get_drvdata(dai
);
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
);
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
);
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
)
166 unsigned int bclk_freq
, cur_freq
;
168 bclk_freq
= sample_rate
* frame_size
;
170 cur_freq
= clk_get_rate(i2s
->clk_sys
);
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;
183 "Sys clock rate %u insufficient for sample rate %u\n",
184 cur_freq
, sample_rate
);
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
)
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
;
198 u32 reg
, control_mask
, chan_control_mask
;
199 u32 control_set
= 0, chan_control_set
= 0;
200 snd_pcm_format_t format
;
202 rate
= params_rate(params
);
203 format
= params_format(params
);
204 channels
= params_channels(params
);
205 i2s_channels
= channels
/ 2;
208 case SNDRV_PCM_FORMAT_S32_LE
:
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
;
214 case SNDRV_PCM_FORMAT_S24_LE
:
216 chan_control_set
|= IMG_I2S_IN_CH_CTL_SW_MASK
;
217 chan_control_set
|= IMG_I2S_IN_CH_CTL_FW_MASK
;
219 case SNDRV_PCM_FORMAT_S16_LE
:
221 control_set
|= IMG_I2S_IN_CTL_16PACK_MASK
;
222 chan_control_set
|= IMG_I2S_IN_CH_CTL_16PACK_MASK
;
228 if ((channels
< 2) ||
229 (channels
> (i2s
->max_i2s_chan
* 2)) ||
233 control_set
|= ((i2s_channels
- 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT
);
235 ret
= img_i2s_in_check_rate(i2s
, rate
, frame_size
,
236 &bclk_filter_enable
, &bclk_filter_value
);
240 if (bclk_filter_enable
)
241 chan_control_set
|= IMG_I2S_IN_CH_CTL_FEN_MASK
;
243 if (bclk_filter_value
)
244 chan_control_set
|= IMG_I2S_IN_CH_CTL_FMODE_MASK
;
246 control_mask
= IMG_I2S_IN_CTL_16PACK_MASK
|
247 IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK
;
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
;
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
);
260 for (i
= 0; i
< i2s
->active_channels
; i
++)
261 img_i2s_in_ch_disable(i2s
, i
);
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
);
269 i2s
->active_channels
= i2s_channels
;
271 img_i2s_in_flush(i2s
);
273 for (i
= 0; i
< i2s
->active_channels
; i
++)
274 img_i2s_in_ch_enable(i2s
, i
);
279 static int img_i2s_in_set_fmt(struct snd_soc_dai
*dai
, unsigned int fmt
)
281 struct img_i2s_in
*i2s
= snd_soc_dai_get_drvdata(dai
);
283 u32 chan_control_mask
, lrd_set
= 0, blkp_set
= 0, chan_control_set
= 0;
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
;
290 case SND_SOC_DAIFMT_NB_IF
:
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
;
296 case SND_SOC_DAIFMT_IB_IF
:
297 blkp_set
|= IMG_I2S_IN_CH_CTL_BLKP_MASK
;
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
;
307 case SND_SOC_DAIFMT_LEFT_J
:
313 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
314 case SND_SOC_DAIFMT_CBM_CFM
:
320 chan_control_mask
= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK
;
322 for (i
= 0; i
< i2s
->active_channels
; i
++)
323 img_i2s_in_ch_disable(i2s
, i
);
326 * BLKP and LRD must be set during separate register writes
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
);
338 for (i
= 0; i
< i2s
->active_channels
; i
++)
339 img_i2s_in_ch_enable(i2s
, i
);
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
350 static int img_i2s_in_dai_probe(struct snd_soc_dai
*dai
)
352 struct img_i2s_in
*i2s
= snd_soc_dai_get_drvdata(dai
);
354 snd_soc_dai_init_dma_data(dai
, NULL
, &i2s
->dma_data
);
359 static const struct snd_soc_component_driver img_i2s_in_component
= {
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
)
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
;
371 dma_data
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, st
);
373 ret
= snd_hwparams_to_dma_slave_config(st
, params
, sc
);
377 sc
->src_addr
= dma_data
->addr
;
378 sc
->src_addr_width
= dma_data
->addr_width
;
379 sc
->src_maxburst
= 4 * i2s_channels
;
384 static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config
= {
385 .prepare_slave_config
= img_i2s_in_dma_prepare_slave_config
388 static int img_i2s_in_probe(struct platform_device
*pdev
)
390 struct img_i2s_in
*i2s
;
391 struct resource
*res
;
394 struct reset_control
*rst
;
395 unsigned int max_i2s_chan_pow_2
;
396 struct device
*dev
= &pdev
->dev
;
398 i2s
= devm_kzalloc(dev
, sizeof(*i2s
), GFP_KERNEL
);
402 platform_set_drvdata(pdev
, i2s
);
406 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
407 base
= devm_ioremap_resource(dev
, res
);
409 return PTR_ERR(base
);
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");
419 max_i2s_chan_pow_2
= 1 << get_count_order(i2s
->max_i2s_chan
);
421 i2s
->channel_base
= base
+ (max_i2s_chan_pow_2
* 0x20);
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
);
430 ret
= clk_prepare_enable(i2s
->clk_sys
);
434 i2s
->active_channels
= 1;
435 i2s
->dma_data
.addr
= res
->start
+ IMG_I2S_IN_RX_FIFO
;
436 i2s
->dma_data
.addr_width
= 4;
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
;
446 rst
= devm_reset_control_get(dev
, "rst");
448 if (PTR_ERR(rst
) == -EPROBE_DEFER
) {
450 goto err_clk_disable
;
453 dev_dbg(dev
, "No top level reset found\n");
455 img_i2s_in_disable(i2s
);
457 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++)
458 img_i2s_in_ch_disable(i2s
, i
);
460 reset_control_assert(rst
);
461 reset_control_deassert(rst
);
464 img_i2s_in_writel(i2s
, 0, IMG_I2S_IN_CTL
);
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
);
472 ret
= devm_snd_soc_register_component(dev
, &img_i2s_in_component
,
473 &i2s
->dai_driver
, 1);
475 goto err_clk_disable
;
477 ret
= devm_snd_dmaengine_pcm_register(dev
, &img_i2s_in_dma_config
, 0);
479 goto err_clk_disable
;
484 clk_disable_unprepare(i2s
->clk_sys
);
489 static int img_i2s_in_dev_remove(struct platform_device
*pdev
)
491 struct img_i2s_in
*i2s
= platform_get_drvdata(pdev
);
493 clk_disable_unprepare(i2s
->clk_sys
);
498 static const struct of_device_id img_i2s_in_of_match
[] = {
499 { .compatible
= "img,i2s-in" },
502 MODULE_DEVICE_TABLE(of
, img_i2s_in_of_match
);
504 static struct platform_driver img_i2s_in_driver
= {
506 .name
= "img-i2s-in",
507 .of_match_table
= img_i2s_in_of_match
509 .probe
= img_i2s_in_probe
,
510 .remove
= img_i2s_in_dev_remove
512 module_platform_driver(img_i2s_in_driver
);
514 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
515 MODULE_DESCRIPTION("IMG I2S Input Driver");
516 MODULE_LICENSE("GPL v2");