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/pm_runtime.h>
20 #include <linux/reset.h>
22 #include <sound/core.h>
23 #include <sound/dmaengine_pcm.h>
24 #include <sound/initval.h>
25 #include <sound/pcm.h>
26 #include <sound/pcm_params.h>
27 #include <sound/soc.h>
29 #define IMG_I2S_IN_RX_FIFO 0x0
31 #define IMG_I2S_IN_CTL 0x4
32 #define IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK 0xfffffffc
33 #define IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT 2
34 #define IMG_I2S_IN_CTL_16PACK_MASK BIT(1)
35 #define IMG_I2S_IN_CTL_ME_MASK BIT(0)
37 #define IMG_I2S_IN_CH_CTL 0x4
38 #define IMG_I2S_IN_CH_CTL_CCDEL_MASK 0x38000
39 #define IMG_I2S_IN_CH_CTL_CCDEL_SHIFT 15
40 #define IMG_I2S_IN_CH_CTL_FEN_MASK BIT(14)
41 #define IMG_I2S_IN_CH_CTL_FMODE_MASK BIT(13)
42 #define IMG_I2S_IN_CH_CTL_16PACK_MASK BIT(12)
43 #define IMG_I2S_IN_CH_CTL_JUST_MASK BIT(10)
44 #define IMG_I2S_IN_CH_CTL_PACKH_MASK BIT(9)
45 #define IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK BIT(8)
46 #define IMG_I2S_IN_CH_CTL_BLKP_MASK BIT(7)
47 #define IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK BIT(6)
48 #define IMG_I2S_IN_CH_CTL_LRD_MASK BIT(3)
49 #define IMG_I2S_IN_CH_CTL_FW_MASK BIT(2)
50 #define IMG_I2S_IN_CH_CTL_SW_MASK BIT(1)
51 #define IMG_I2S_IN_CH_CTL_ME_MASK BIT(0)
53 #define IMG_I2S_IN_CH_STRIDE 0x20
58 struct snd_dmaengine_dai_dma_data dma_data
;
60 unsigned int max_i2s_chan
;
61 void __iomem
*channel_base
;
62 unsigned int active_channels
;
63 struct snd_soc_dai_driver dai_driver
;
68 static int img_i2s_in_runtime_suspend(struct device
*dev
)
70 struct img_i2s_in
*i2s
= dev_get_drvdata(dev
);
72 clk_disable_unprepare(i2s
->clk_sys
);
77 static int img_i2s_in_runtime_resume(struct device
*dev
)
79 struct img_i2s_in
*i2s
= dev_get_drvdata(dev
);
82 ret
= clk_prepare_enable(i2s
->clk_sys
);
84 dev_err(dev
, "Unable to enable sys clock\n");
91 static inline void img_i2s_in_writel(struct img_i2s_in
*i2s
, u32 val
, u32 reg
)
93 writel(val
, i2s
->base
+ reg
);
96 static inline u32
img_i2s_in_readl(struct img_i2s_in
*i2s
, u32 reg
)
98 return readl(i2s
->base
+ reg
);
101 static inline void img_i2s_in_ch_writel(struct img_i2s_in
*i2s
, u32 chan
,
104 writel(val
, i2s
->channel_base
+ (chan
* IMG_I2S_IN_CH_STRIDE
) + reg
);
107 static inline u32
img_i2s_in_ch_readl(struct img_i2s_in
*i2s
, u32 chan
,
110 return readl(i2s
->channel_base
+ (chan
* IMG_I2S_IN_CH_STRIDE
) + reg
);
113 static inline void img_i2s_in_ch_disable(struct img_i2s_in
*i2s
, u32 chan
)
117 reg
= img_i2s_in_ch_readl(i2s
, chan
, IMG_I2S_IN_CH_CTL
);
118 reg
&= ~IMG_I2S_IN_CH_CTL_ME_MASK
;
119 img_i2s_in_ch_writel(i2s
, chan
, reg
, IMG_I2S_IN_CH_CTL
);
122 static inline void img_i2s_in_ch_enable(struct img_i2s_in
*i2s
, u32 chan
)
126 reg
= img_i2s_in_ch_readl(i2s
, chan
, IMG_I2S_IN_CH_CTL
);
127 reg
|= IMG_I2S_IN_CH_CTL_ME_MASK
;
128 img_i2s_in_ch_writel(i2s
, chan
, reg
, IMG_I2S_IN_CH_CTL
);
131 static inline void img_i2s_in_disable(struct img_i2s_in
*i2s
)
135 reg
= img_i2s_in_readl(i2s
, IMG_I2S_IN_CTL
);
136 reg
&= ~IMG_I2S_IN_CTL_ME_MASK
;
137 img_i2s_in_writel(i2s
, reg
, IMG_I2S_IN_CTL
);
140 static inline void img_i2s_in_enable(struct img_i2s_in
*i2s
)
144 reg
= img_i2s_in_readl(i2s
, IMG_I2S_IN_CTL
);
145 reg
|= IMG_I2S_IN_CTL_ME_MASK
;
146 img_i2s_in_writel(i2s
, reg
, IMG_I2S_IN_CTL
);
149 static inline void img_i2s_in_flush(struct img_i2s_in
*i2s
)
154 for (i
= 0; i
< i2s
->active_channels
; i
++) {
155 reg
= img_i2s_in_ch_readl(i2s
, i
, IMG_I2S_IN_CH_CTL
);
156 reg
|= IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK
;
157 img_i2s_in_ch_writel(i2s
, i
, reg
, IMG_I2S_IN_CH_CTL
);
158 reg
&= ~IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK
;
159 img_i2s_in_ch_writel(i2s
, i
, reg
, IMG_I2S_IN_CH_CTL
);
163 static int img_i2s_in_trigger(struct snd_pcm_substream
*substream
, int cmd
,
164 struct snd_soc_dai
*dai
)
166 struct img_i2s_in
*i2s
= snd_soc_dai_get_drvdata(dai
);
169 case SNDRV_PCM_TRIGGER_START
:
170 case SNDRV_PCM_TRIGGER_RESUME
:
171 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
172 img_i2s_in_enable(i2s
);
175 case SNDRV_PCM_TRIGGER_STOP
:
176 case SNDRV_PCM_TRIGGER_SUSPEND
:
177 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
178 img_i2s_in_disable(i2s
);
187 static int img_i2s_in_check_rate(struct img_i2s_in
*i2s
,
188 unsigned int sample_rate
, unsigned int frame_size
,
189 unsigned int *bclk_filter_enable
,
190 unsigned int *bclk_filter_value
)
192 unsigned int bclk_freq
, cur_freq
;
194 bclk_freq
= sample_rate
* frame_size
;
196 cur_freq
= clk_get_rate(i2s
->clk_sys
);
198 if (cur_freq
>= bclk_freq
* 8) {
199 *bclk_filter_enable
= 1;
200 *bclk_filter_value
= 0;
201 } else if (cur_freq
>= bclk_freq
* 7) {
202 *bclk_filter_enable
= 1;
203 *bclk_filter_value
= 1;
204 } else if (cur_freq
>= bclk_freq
* 6) {
205 *bclk_filter_enable
= 0;
206 *bclk_filter_value
= 0;
209 "Sys clock rate %u insufficient for sample rate %u\n",
210 cur_freq
, sample_rate
);
217 static int img_i2s_in_hw_params(struct snd_pcm_substream
*substream
,
218 struct snd_pcm_hw_params
*params
, struct snd_soc_dai
*dai
)
220 struct img_i2s_in
*i2s
= snd_soc_dai_get_drvdata(dai
);
221 unsigned int rate
, channels
, i2s_channels
, frame_size
;
222 unsigned int bclk_filter_enable
, bclk_filter_value
;
224 u32 reg
, control_mask
, chan_control_mask
;
225 u32 control_set
= 0, chan_control_set
= 0;
226 snd_pcm_format_t format
;
228 rate
= params_rate(params
);
229 format
= params_format(params
);
230 channels
= params_channels(params
);
231 i2s_channels
= channels
/ 2;
234 case SNDRV_PCM_FORMAT_S32_LE
:
236 chan_control_set
|= IMG_I2S_IN_CH_CTL_SW_MASK
;
237 chan_control_set
|= IMG_I2S_IN_CH_CTL_FW_MASK
;
238 chan_control_set
|= IMG_I2S_IN_CH_CTL_PACKH_MASK
;
240 case SNDRV_PCM_FORMAT_S24_LE
:
242 chan_control_set
|= IMG_I2S_IN_CH_CTL_SW_MASK
;
243 chan_control_set
|= IMG_I2S_IN_CH_CTL_FW_MASK
;
245 case SNDRV_PCM_FORMAT_S16_LE
:
247 control_set
|= IMG_I2S_IN_CTL_16PACK_MASK
;
248 chan_control_set
|= IMG_I2S_IN_CH_CTL_16PACK_MASK
;
254 if ((channels
< 2) ||
255 (channels
> (i2s
->max_i2s_chan
* 2)) ||
259 control_set
|= ((i2s_channels
- 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT
);
261 ret
= img_i2s_in_check_rate(i2s
, rate
, frame_size
,
262 &bclk_filter_enable
, &bclk_filter_value
);
266 if (bclk_filter_enable
)
267 chan_control_set
|= IMG_I2S_IN_CH_CTL_FEN_MASK
;
269 if (bclk_filter_value
)
270 chan_control_set
|= IMG_I2S_IN_CH_CTL_FMODE_MASK
;
272 control_mask
= IMG_I2S_IN_CTL_16PACK_MASK
|
273 IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK
;
275 chan_control_mask
= IMG_I2S_IN_CH_CTL_16PACK_MASK
|
276 IMG_I2S_IN_CH_CTL_FEN_MASK
|
277 IMG_I2S_IN_CH_CTL_FMODE_MASK
|
278 IMG_I2S_IN_CH_CTL_SW_MASK
|
279 IMG_I2S_IN_CH_CTL_FW_MASK
|
280 IMG_I2S_IN_CH_CTL_PACKH_MASK
;
282 reg
= img_i2s_in_readl(i2s
, IMG_I2S_IN_CTL
);
283 reg
= (reg
& ~control_mask
) | control_set
;
284 img_i2s_in_writel(i2s
, reg
, IMG_I2S_IN_CTL
);
286 for (i
= 0; i
< i2s
->active_channels
; i
++)
287 img_i2s_in_ch_disable(i2s
, i
);
289 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++) {
290 reg
= img_i2s_in_ch_readl(i2s
, i
, IMG_I2S_IN_CH_CTL
);
291 reg
= (reg
& ~chan_control_mask
) | chan_control_set
;
292 img_i2s_in_ch_writel(i2s
, i
, reg
, IMG_I2S_IN_CH_CTL
);
295 i2s
->active_channels
= i2s_channels
;
297 img_i2s_in_flush(i2s
);
299 for (i
= 0; i
< i2s
->active_channels
; i
++)
300 img_i2s_in_ch_enable(i2s
, i
);
305 static int img_i2s_in_set_fmt(struct snd_soc_dai
*dai
, unsigned int fmt
)
307 struct img_i2s_in
*i2s
= snd_soc_dai_get_drvdata(dai
);
309 u32 chan_control_mask
, lrd_set
= 0, blkp_set
= 0, chan_control_set
= 0;
312 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
313 case SND_SOC_DAIFMT_NB_NF
:
314 lrd_set
|= IMG_I2S_IN_CH_CTL_LRD_MASK
;
316 case SND_SOC_DAIFMT_NB_IF
:
318 case SND_SOC_DAIFMT_IB_NF
:
319 lrd_set
|= IMG_I2S_IN_CH_CTL_LRD_MASK
;
320 blkp_set
|= IMG_I2S_IN_CH_CTL_BLKP_MASK
;
322 case SND_SOC_DAIFMT_IB_IF
:
323 blkp_set
|= IMG_I2S_IN_CH_CTL_BLKP_MASK
;
329 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
330 case SND_SOC_DAIFMT_I2S
:
331 chan_control_set
|= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK
;
333 case SND_SOC_DAIFMT_LEFT_J
:
339 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
340 case SND_SOC_DAIFMT_CBM_CFM
:
346 chan_control_mask
= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK
;
348 ret
= pm_runtime_get_sync(i2s
->dev
);
352 for (i
= 0; i
< i2s
->active_channels
; i
++)
353 img_i2s_in_ch_disable(i2s
, i
);
356 * BLKP and LRD must be set during separate register writes
358 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++) {
359 reg
= img_i2s_in_ch_readl(i2s
, i
, IMG_I2S_IN_CH_CTL
);
360 reg
= (reg
& ~chan_control_mask
) | chan_control_set
;
361 img_i2s_in_ch_writel(i2s
, i
, reg
, IMG_I2S_IN_CH_CTL
);
362 reg
= (reg
& ~IMG_I2S_IN_CH_CTL_BLKP_MASK
) | blkp_set
;
363 img_i2s_in_ch_writel(i2s
, i
, reg
, IMG_I2S_IN_CH_CTL
);
364 reg
= (reg
& ~IMG_I2S_IN_CH_CTL_LRD_MASK
) | lrd_set
;
365 img_i2s_in_ch_writel(i2s
, i
, reg
, IMG_I2S_IN_CH_CTL
);
368 for (i
= 0; i
< i2s
->active_channels
; i
++)
369 img_i2s_in_ch_enable(i2s
, i
);
371 pm_runtime_put(i2s
->dev
);
376 static const struct snd_soc_dai_ops img_i2s_in_dai_ops
= {
377 .trigger
= img_i2s_in_trigger
,
378 .hw_params
= img_i2s_in_hw_params
,
379 .set_fmt
= img_i2s_in_set_fmt
382 static int img_i2s_in_dai_probe(struct snd_soc_dai
*dai
)
384 struct img_i2s_in
*i2s
= snd_soc_dai_get_drvdata(dai
);
386 snd_soc_dai_init_dma_data(dai
, NULL
, &i2s
->dma_data
);
391 static const struct snd_soc_component_driver img_i2s_in_component
= {
395 static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream
*st
,
396 struct snd_pcm_hw_params
*params
, struct dma_slave_config
*sc
)
398 unsigned int i2s_channels
= params_channels(params
) / 2;
399 struct snd_soc_pcm_runtime
*rtd
= st
->private_data
;
400 struct snd_dmaengine_dai_dma_data
*dma_data
;
403 dma_data
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, st
);
405 ret
= snd_hwparams_to_dma_slave_config(st
, params
, sc
);
409 sc
->src_addr
= dma_data
->addr
;
410 sc
->src_addr_width
= dma_data
->addr_width
;
411 sc
->src_maxburst
= 4 * i2s_channels
;
416 static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config
= {
417 .prepare_slave_config
= img_i2s_in_dma_prepare_slave_config
420 static int img_i2s_in_probe(struct platform_device
*pdev
)
422 struct img_i2s_in
*i2s
;
423 struct resource
*res
;
426 struct reset_control
*rst
;
427 unsigned int max_i2s_chan_pow_2
;
428 struct device
*dev
= &pdev
->dev
;
430 i2s
= devm_kzalloc(dev
, sizeof(*i2s
), GFP_KERNEL
);
434 platform_set_drvdata(pdev
, i2s
);
438 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
439 base
= devm_ioremap_resource(dev
, res
);
441 return PTR_ERR(base
);
445 if (of_property_read_u32(pdev
->dev
.of_node
, "img,i2s-channels",
446 &i2s
->max_i2s_chan
)) {
447 dev_err(dev
, "No img,i2s-channels property\n");
451 max_i2s_chan_pow_2
= 1 << get_count_order(i2s
->max_i2s_chan
);
453 i2s
->channel_base
= base
+ (max_i2s_chan_pow_2
* 0x20);
455 i2s
->clk_sys
= devm_clk_get(dev
, "sys");
456 if (IS_ERR(i2s
->clk_sys
)) {
457 if (PTR_ERR(i2s
->clk_sys
) != -EPROBE_DEFER
)
458 dev_err(dev
, "Failed to acquire clock 'sys'\n");
459 return PTR_ERR(i2s
->clk_sys
);
462 pm_runtime_enable(&pdev
->dev
);
463 if (!pm_runtime_enabled(&pdev
->dev
)) {
464 ret
= img_i2s_in_runtime_resume(&pdev
->dev
);
468 ret
= pm_runtime_get_sync(&pdev
->dev
);
472 i2s
->active_channels
= 1;
473 i2s
->dma_data
.addr
= res
->start
+ IMG_I2S_IN_RX_FIFO
;
474 i2s
->dma_data
.addr_width
= 4;
476 i2s
->dai_driver
.probe
= img_i2s_in_dai_probe
;
477 i2s
->dai_driver
.capture
.channels_min
= 2;
478 i2s
->dai_driver
.capture
.channels_max
= i2s
->max_i2s_chan
* 2;
479 i2s
->dai_driver
.capture
.rates
= SNDRV_PCM_RATE_8000_192000
;
480 i2s
->dai_driver
.capture
.formats
= SNDRV_PCM_FMTBIT_S32_LE
|
481 SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S16_LE
;
482 i2s
->dai_driver
.ops
= &img_i2s_in_dai_ops
;
484 rst
= devm_reset_control_get_exclusive(dev
, "rst");
486 if (PTR_ERR(rst
) == -EPROBE_DEFER
) {
491 dev_dbg(dev
, "No top level reset found\n");
493 img_i2s_in_disable(i2s
);
495 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++)
496 img_i2s_in_ch_disable(i2s
, i
);
498 reset_control_assert(rst
);
499 reset_control_deassert(rst
);
502 img_i2s_in_writel(i2s
, 0, IMG_I2S_IN_CTL
);
504 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++)
505 img_i2s_in_ch_writel(i2s
, i
,
506 (4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT
) |
507 IMG_I2S_IN_CH_CTL_JUST_MASK
|
508 IMG_I2S_IN_CH_CTL_FW_MASK
, IMG_I2S_IN_CH_CTL
);
510 pm_runtime_put(&pdev
->dev
);
512 i2s
->suspend_ch_ctl
= devm_kzalloc(dev
,
513 sizeof(*i2s
->suspend_ch_ctl
) * i2s
->max_i2s_chan
, GFP_KERNEL
);
514 if (!i2s
->suspend_ch_ctl
) {
519 ret
= devm_snd_soc_register_component(dev
, &img_i2s_in_component
,
520 &i2s
->dai_driver
, 1);
524 ret
= devm_snd_dmaengine_pcm_register(dev
, &img_i2s_in_dma_config
, 0);
531 if (!pm_runtime_enabled(&pdev
->dev
))
532 img_i2s_in_runtime_suspend(&pdev
->dev
);
534 pm_runtime_disable(&pdev
->dev
);
539 static int img_i2s_in_dev_remove(struct platform_device
*pdev
)
541 pm_runtime_disable(&pdev
->dev
);
542 if (!pm_runtime_status_suspended(&pdev
->dev
))
543 img_i2s_in_runtime_suspend(&pdev
->dev
);
548 #ifdef CONFIG_PM_SLEEP
549 static int img_i2s_in_suspend(struct device
*dev
)
551 struct img_i2s_in
*i2s
= dev_get_drvdata(dev
);
555 if (pm_runtime_status_suspended(dev
)) {
556 ret
= img_i2s_in_runtime_resume(dev
);
561 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++) {
562 reg
= img_i2s_in_ch_readl(i2s
, i
, IMG_I2S_IN_CH_CTL
);
563 i2s
->suspend_ch_ctl
[i
] = reg
;
566 i2s
->suspend_ctl
= img_i2s_in_readl(i2s
, IMG_I2S_IN_CTL
);
568 img_i2s_in_runtime_suspend(dev
);
573 static int img_i2s_in_resume(struct device
*dev
)
575 struct img_i2s_in
*i2s
= dev_get_drvdata(dev
);
579 ret
= img_i2s_in_runtime_resume(dev
);
583 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++) {
584 reg
= i2s
->suspend_ch_ctl
[i
];
585 img_i2s_in_ch_writel(i2s
, i
, reg
, IMG_I2S_IN_CH_CTL
);
588 img_i2s_in_writel(i2s
, i2s
->suspend_ctl
, IMG_I2S_IN_CTL
);
590 if (pm_runtime_status_suspended(dev
))
591 img_i2s_in_runtime_suspend(dev
);
597 static const struct of_device_id img_i2s_in_of_match
[] = {
598 { .compatible
= "img,i2s-in" },
601 MODULE_DEVICE_TABLE(of
, img_i2s_in_of_match
);
603 static const struct dev_pm_ops img_i2s_in_pm_ops
= {
604 SET_RUNTIME_PM_OPS(img_i2s_in_runtime_suspend
,
605 img_i2s_in_runtime_resume
, NULL
)
606 SET_SYSTEM_SLEEP_PM_OPS(img_i2s_in_suspend
, img_i2s_in_resume
)
609 static struct platform_driver img_i2s_in_driver
= {
611 .name
= "img-i2s-in",
612 .of_match_table
= img_i2s_in_of_match
,
613 .pm
= &img_i2s_in_pm_ops
615 .probe
= img_i2s_in_probe
,
616 .remove
= img_i2s_in_dev_remove
618 module_platform_driver(img_i2s_in_driver
);
620 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
621 MODULE_DESCRIPTION("IMG I2S Input Driver");
622 MODULE_LICENSE("GPL v2");