1 // SPDX-License-Identifier: GPL-2.0-only
3 * IMG I2S output controller driver
5 * Copyright (C) 2015 Imagination Technologies Ltd.
7 * Author: Damien Horsley <Damien.Horsley@imgtec.com>
10 #include <linux/clk.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/reset.h>
19 #include <sound/core.h>
20 #include <sound/dmaengine_pcm.h>
21 #include <sound/initval.h>
22 #include <sound/pcm.h>
23 #include <sound/pcm_params.h>
24 #include <sound/soc.h>
26 #define IMG_I2S_OUT_TX_FIFO 0x0
28 #define IMG_I2S_OUT_CTL 0x4
29 #define IMG_I2S_OUT_CTL_DATA_EN_MASK BIT(24)
30 #define IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK 0xffe000
31 #define IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT 13
32 #define IMG_I2S_OUT_CTL_FRM_SIZE_MASK BIT(8)
33 #define IMG_I2S_OUT_CTL_MASTER_MASK BIT(6)
34 #define IMG_I2S_OUT_CTL_CLK_MASK BIT(5)
35 #define IMG_I2S_OUT_CTL_CLK_EN_MASK BIT(4)
36 #define IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK BIT(3)
37 #define IMG_I2S_OUT_CTL_BCLK_POL_MASK BIT(2)
38 #define IMG_I2S_OUT_CTL_ME_MASK BIT(0)
40 #define IMG_I2S_OUT_CH_CTL 0x4
41 #define IMG_I2S_OUT_CHAN_CTL_CH_MASK BIT(11)
42 #define IMG_I2S_OUT_CHAN_CTL_LT_MASK BIT(10)
43 #define IMG_I2S_OUT_CHAN_CTL_FMT_MASK 0xf0
44 #define IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT 4
45 #define IMG_I2S_OUT_CHAN_CTL_JUST_MASK BIT(3)
46 #define IMG_I2S_OUT_CHAN_CTL_CLKT_MASK BIT(1)
47 #define IMG_I2S_OUT_CHAN_CTL_ME_MASK BIT(0)
49 #define IMG_I2S_OUT_CH_STRIDE 0x20
55 struct snd_dmaengine_dai_dma_data dma_data
;
57 unsigned int max_i2s_chan
;
58 void __iomem
*channel_base
;
59 bool force_clk_active
;
60 unsigned int active_channels
;
61 struct reset_control
*rst
;
62 struct snd_soc_dai_driver dai_driver
;
67 static int img_i2s_out_runtime_suspend(struct device
*dev
)
69 struct img_i2s_out
*i2s
= dev_get_drvdata(dev
);
71 clk_disable_unprepare(i2s
->clk_ref
);
72 clk_disable_unprepare(i2s
->clk_sys
);
77 static int img_i2s_out_runtime_resume(struct device
*dev
)
79 struct img_i2s_out
*i2s
= dev_get_drvdata(dev
);
82 ret
= clk_prepare_enable(i2s
->clk_sys
);
84 dev_err(dev
, "clk_enable failed: %d\n", ret
);
88 ret
= clk_prepare_enable(i2s
->clk_ref
);
90 dev_err(dev
, "clk_enable failed: %d\n", ret
);
91 clk_disable_unprepare(i2s
->clk_sys
);
98 static inline void img_i2s_out_writel(struct img_i2s_out
*i2s
, u32 val
,
101 writel(val
, i2s
->base
+ reg
);
104 static inline u32
img_i2s_out_readl(struct img_i2s_out
*i2s
, u32 reg
)
106 return readl(i2s
->base
+ reg
);
109 static inline void img_i2s_out_ch_writel(struct img_i2s_out
*i2s
,
110 u32 chan
, u32 val
, u32 reg
)
112 writel(val
, i2s
->channel_base
+ (chan
* IMG_I2S_OUT_CH_STRIDE
) + reg
);
115 static inline u32
img_i2s_out_ch_readl(struct img_i2s_out
*i2s
, u32 chan
,
118 return readl(i2s
->channel_base
+ (chan
* IMG_I2S_OUT_CH_STRIDE
) + reg
);
121 static inline void img_i2s_out_ch_disable(struct img_i2s_out
*i2s
, u32 chan
)
125 reg
= img_i2s_out_ch_readl(i2s
, chan
, IMG_I2S_OUT_CH_CTL
);
126 reg
&= ~IMG_I2S_OUT_CHAN_CTL_ME_MASK
;
127 img_i2s_out_ch_writel(i2s
, chan
, reg
, IMG_I2S_OUT_CH_CTL
);
130 static inline void img_i2s_out_ch_enable(struct img_i2s_out
*i2s
, u32 chan
)
134 reg
= img_i2s_out_ch_readl(i2s
, chan
, IMG_I2S_OUT_CH_CTL
);
135 reg
|= IMG_I2S_OUT_CHAN_CTL_ME_MASK
;
136 img_i2s_out_ch_writel(i2s
, chan
, reg
, IMG_I2S_OUT_CH_CTL
);
139 static inline void img_i2s_out_disable(struct img_i2s_out
*i2s
)
143 reg
= img_i2s_out_readl(i2s
, IMG_I2S_OUT_CTL
);
144 reg
&= ~IMG_I2S_OUT_CTL_ME_MASK
;
145 img_i2s_out_writel(i2s
, reg
, IMG_I2S_OUT_CTL
);
148 static inline void img_i2s_out_enable(struct img_i2s_out
*i2s
)
152 reg
= img_i2s_out_readl(i2s
, IMG_I2S_OUT_CTL
);
153 reg
|= IMG_I2S_OUT_CTL_ME_MASK
;
154 img_i2s_out_writel(i2s
, reg
, IMG_I2S_OUT_CTL
);
157 static void img_i2s_out_reset(struct img_i2s_out
*i2s
)
160 u32 core_ctl
, chan_ctl
;
162 core_ctl
= img_i2s_out_readl(i2s
, IMG_I2S_OUT_CTL
) &
163 ~IMG_I2S_OUT_CTL_ME_MASK
&
164 ~IMG_I2S_OUT_CTL_DATA_EN_MASK
;
166 if (!i2s
->force_clk_active
)
167 core_ctl
&= ~IMG_I2S_OUT_CTL_CLK_EN_MASK
;
169 chan_ctl
= img_i2s_out_ch_readl(i2s
, 0, IMG_I2S_OUT_CH_CTL
) &
170 ~IMG_I2S_OUT_CHAN_CTL_ME_MASK
;
172 reset_control_assert(i2s
->rst
);
173 reset_control_deassert(i2s
->rst
);
175 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++)
176 img_i2s_out_ch_writel(i2s
, i
, chan_ctl
, IMG_I2S_OUT_CH_CTL
);
178 for (i
= 0; i
< i2s
->active_channels
; i
++)
179 img_i2s_out_ch_enable(i2s
, i
);
181 img_i2s_out_writel(i2s
, core_ctl
, IMG_I2S_OUT_CTL
);
182 img_i2s_out_enable(i2s
);
185 static int img_i2s_out_trigger(struct snd_pcm_substream
*substream
, int cmd
,
186 struct snd_soc_dai
*dai
)
188 struct img_i2s_out
*i2s
= snd_soc_dai_get_drvdata(dai
);
192 case SNDRV_PCM_TRIGGER_START
:
193 case SNDRV_PCM_TRIGGER_RESUME
:
194 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
195 reg
= img_i2s_out_readl(i2s
, IMG_I2S_OUT_CTL
);
196 if (!i2s
->force_clk_active
)
197 reg
|= IMG_I2S_OUT_CTL_CLK_EN_MASK
;
198 reg
|= IMG_I2S_OUT_CTL_DATA_EN_MASK
;
199 img_i2s_out_writel(i2s
, reg
, IMG_I2S_OUT_CTL
);
201 case SNDRV_PCM_TRIGGER_STOP
:
202 case SNDRV_PCM_TRIGGER_SUSPEND
:
203 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
204 img_i2s_out_reset(i2s
);
213 static int img_i2s_out_hw_params(struct snd_pcm_substream
*substream
,
214 struct snd_pcm_hw_params
*params
, struct snd_soc_dai
*dai
)
216 struct img_i2s_out
*i2s
= snd_soc_dai_get_drvdata(dai
);
217 unsigned int channels
, i2s_channels
;
218 long pre_div_a
, pre_div_b
, diff_a
, diff_b
, rate
, clk_rate
;
220 u32 reg
, control_mask
, control_set
= 0;
221 snd_pcm_format_t format
;
223 rate
= params_rate(params
);
224 format
= params_format(params
);
225 channels
= params_channels(params
);
226 i2s_channels
= channels
/ 2;
228 if (format
!= SNDRV_PCM_FORMAT_S32_LE
)
231 if ((channels
< 2) ||
232 (channels
> (i2s
->max_i2s_chan
* 2)) ||
236 pre_div_a
= clk_round_rate(i2s
->clk_ref
, rate
* 256);
239 pre_div_b
= clk_round_rate(i2s
->clk_ref
, rate
* 384);
243 diff_a
= abs((pre_div_a
/ 256) - rate
);
244 diff_b
= abs((pre_div_b
/ 384) - rate
);
246 /* If diffs are equal, use lower clock rate */
248 clk_set_rate(i2s
->clk_ref
, pre_div_b
);
250 clk_set_rate(i2s
->clk_ref
, pre_div_a
);
253 * Another driver (eg alsa machine driver) may have rejected the above
254 * change. Get the current rate and set the register bit according to
255 * the new minimum diff
257 clk_rate
= clk_get_rate(i2s
->clk_ref
);
259 diff_a
= abs((clk_rate
/ 256) - rate
);
260 diff_b
= abs((clk_rate
/ 384) - rate
);
263 control_set
|= IMG_I2S_OUT_CTL_CLK_MASK
;
265 control_set
|= ((i2s_channels
- 1) <<
266 IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT
) &
267 IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK
;
269 control_mask
= IMG_I2S_OUT_CTL_CLK_MASK
|
270 IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK
;
272 img_i2s_out_disable(i2s
);
274 reg
= img_i2s_out_readl(i2s
, IMG_I2S_OUT_CTL
);
275 reg
= (reg
& ~control_mask
) | control_set
;
276 img_i2s_out_writel(i2s
, reg
, IMG_I2S_OUT_CTL
);
278 for (i
= 0; i
< i2s_channels
; i
++)
279 img_i2s_out_ch_enable(i2s
, i
);
281 for (; i
< i2s
->max_i2s_chan
; i
++)
282 img_i2s_out_ch_disable(i2s
, i
);
284 img_i2s_out_enable(i2s
);
286 i2s
->active_channels
= i2s_channels
;
291 static int img_i2s_out_set_fmt(struct snd_soc_dai
*dai
, unsigned int fmt
)
293 struct img_i2s_out
*i2s
= snd_soc_dai_get_drvdata(dai
);
295 bool force_clk_active
;
296 u32 chan_control_mask
, control_mask
, chan_control_set
= 0;
297 u32 reg
, control_set
= 0;
299 force_clk_active
= ((fmt
& SND_SOC_DAIFMT_CLOCK_MASK
) ==
300 SND_SOC_DAIFMT_CONT
);
302 if (force_clk_active
)
303 control_set
|= IMG_I2S_OUT_CTL_CLK_EN_MASK
;
305 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
306 case SND_SOC_DAIFMT_CBM_CFM
:
308 case SND_SOC_DAIFMT_CBS_CFS
:
309 control_set
|= IMG_I2S_OUT_CTL_MASTER_MASK
;
315 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
316 case SND_SOC_DAIFMT_NB_NF
:
317 control_set
|= IMG_I2S_OUT_CTL_BCLK_POL_MASK
;
319 case SND_SOC_DAIFMT_NB_IF
:
320 control_set
|= IMG_I2S_OUT_CTL_BCLK_POL_MASK
;
321 control_set
|= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK
;
323 case SND_SOC_DAIFMT_IB_NF
:
325 case SND_SOC_DAIFMT_IB_IF
:
326 control_set
|= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK
;
332 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
333 case SND_SOC_DAIFMT_I2S
:
334 chan_control_set
|= IMG_I2S_OUT_CHAN_CTL_CLKT_MASK
;
336 case SND_SOC_DAIFMT_LEFT_J
:
342 control_mask
= IMG_I2S_OUT_CTL_CLK_EN_MASK
|
343 IMG_I2S_OUT_CTL_MASTER_MASK
|
344 IMG_I2S_OUT_CTL_BCLK_POL_MASK
|
345 IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK
;
347 chan_control_mask
= IMG_I2S_OUT_CHAN_CTL_CLKT_MASK
;
349 ret
= pm_runtime_get_sync(i2s
->dev
);
353 img_i2s_out_disable(i2s
);
355 reg
= img_i2s_out_readl(i2s
, IMG_I2S_OUT_CTL
);
356 reg
= (reg
& ~control_mask
) | control_set
;
357 img_i2s_out_writel(i2s
, reg
, IMG_I2S_OUT_CTL
);
359 for (i
= 0; i
< i2s
->active_channels
; i
++)
360 img_i2s_out_ch_disable(i2s
, i
);
362 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++) {
363 reg
= img_i2s_out_ch_readl(i2s
, i
, IMG_I2S_OUT_CH_CTL
);
364 reg
= (reg
& ~chan_control_mask
) | chan_control_set
;
365 img_i2s_out_ch_writel(i2s
, i
, reg
, IMG_I2S_OUT_CH_CTL
);
368 for (i
= 0; i
< i2s
->active_channels
; i
++)
369 img_i2s_out_ch_enable(i2s
, i
);
371 img_i2s_out_enable(i2s
);
372 pm_runtime_put(i2s
->dev
);
374 i2s
->force_clk_active
= force_clk_active
;
379 static const struct snd_soc_dai_ops img_i2s_out_dai_ops
= {
380 .trigger
= img_i2s_out_trigger
,
381 .hw_params
= img_i2s_out_hw_params
,
382 .set_fmt
= img_i2s_out_set_fmt
385 static int img_i2s_out_dai_probe(struct snd_soc_dai
*dai
)
387 struct img_i2s_out
*i2s
= snd_soc_dai_get_drvdata(dai
);
389 snd_soc_dai_init_dma_data(dai
, &i2s
->dma_data
, NULL
);
394 static const struct snd_soc_component_driver img_i2s_out_component
= {
395 .name
= "img-i2s-out"
398 static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream
*st
,
399 struct snd_pcm_hw_params
*params
, struct dma_slave_config
*sc
)
401 unsigned int i2s_channels
= params_channels(params
) / 2;
402 struct snd_soc_pcm_runtime
*rtd
= st
->private_data
;
403 struct snd_dmaengine_dai_dma_data
*dma_data
;
406 dma_data
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, st
);
408 ret
= snd_hwparams_to_dma_slave_config(st
, params
, sc
);
412 sc
->dst_addr
= dma_data
->addr
;
413 sc
->dst_addr_width
= dma_data
->addr_width
;
414 sc
->dst_maxburst
= 4 * i2s_channels
;
419 static const struct snd_dmaengine_pcm_config img_i2s_out_dma_config
= {
420 .prepare_slave_config
= img_i2s_out_dma_prepare_slave_config
423 static int img_i2s_out_probe(struct platform_device
*pdev
)
425 struct img_i2s_out
*i2s
;
426 struct resource
*res
;
429 unsigned int max_i2s_chan_pow_2
;
431 struct device
*dev
= &pdev
->dev
;
433 i2s
= devm_kzalloc(&pdev
->dev
, sizeof(*i2s
), GFP_KERNEL
);
437 platform_set_drvdata(pdev
, i2s
);
439 i2s
->dev
= &pdev
->dev
;
441 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
442 base
= devm_ioremap_resource(&pdev
->dev
, res
);
444 return PTR_ERR(base
);
448 if (of_property_read_u32(pdev
->dev
.of_node
, "img,i2s-channels",
449 &i2s
->max_i2s_chan
)) {
450 dev_err(&pdev
->dev
, "No img,i2s-channels property\n");
454 max_i2s_chan_pow_2
= 1 << get_count_order(i2s
->max_i2s_chan
);
456 i2s
->channel_base
= base
+ (max_i2s_chan_pow_2
* 0x20);
458 i2s
->rst
= devm_reset_control_get_exclusive(&pdev
->dev
, "rst");
459 if (IS_ERR(i2s
->rst
)) {
460 if (PTR_ERR(i2s
->rst
) != -EPROBE_DEFER
)
461 dev_err(&pdev
->dev
, "No top level reset found\n");
462 return PTR_ERR(i2s
->rst
);
465 i2s
->clk_sys
= devm_clk_get(&pdev
->dev
, "sys");
466 if (IS_ERR(i2s
->clk_sys
)) {
467 if (PTR_ERR(i2s
->clk_sys
) != -EPROBE_DEFER
)
468 dev_err(dev
, "Failed to acquire clock 'sys'\n");
469 return PTR_ERR(i2s
->clk_sys
);
472 i2s
->clk_ref
= devm_clk_get(&pdev
->dev
, "ref");
473 if (IS_ERR(i2s
->clk_ref
)) {
474 if (PTR_ERR(i2s
->clk_ref
) != -EPROBE_DEFER
)
475 dev_err(dev
, "Failed to acquire clock 'ref'\n");
476 return PTR_ERR(i2s
->clk_ref
);
479 i2s
->suspend_ch_ctl
= devm_kcalloc(dev
,
480 i2s
->max_i2s_chan
, sizeof(*i2s
->suspend_ch_ctl
), GFP_KERNEL
);
481 if (!i2s
->suspend_ch_ctl
)
484 pm_runtime_enable(&pdev
->dev
);
485 if (!pm_runtime_enabled(&pdev
->dev
)) {
486 ret
= img_i2s_out_runtime_resume(&pdev
->dev
);
490 ret
= pm_runtime_get_sync(&pdev
->dev
);
494 reg
= IMG_I2S_OUT_CTL_FRM_SIZE_MASK
;
495 img_i2s_out_writel(i2s
, reg
, IMG_I2S_OUT_CTL
);
497 reg
= IMG_I2S_OUT_CHAN_CTL_JUST_MASK
|
498 IMG_I2S_OUT_CHAN_CTL_LT_MASK
|
499 IMG_I2S_OUT_CHAN_CTL_CH_MASK
|
500 (8 << IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT
);
502 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++)
503 img_i2s_out_ch_writel(i2s
, i
, reg
, IMG_I2S_OUT_CH_CTL
);
505 img_i2s_out_reset(i2s
);
506 pm_runtime_put(&pdev
->dev
);
508 i2s
->active_channels
= 1;
509 i2s
->dma_data
.addr
= res
->start
+ IMG_I2S_OUT_TX_FIFO
;
510 i2s
->dma_data
.addr_width
= 4;
511 i2s
->dma_data
.maxburst
= 4;
513 i2s
->dai_driver
.probe
= img_i2s_out_dai_probe
;
514 i2s
->dai_driver
.playback
.channels_min
= 2;
515 i2s
->dai_driver
.playback
.channels_max
= i2s
->max_i2s_chan
* 2;
516 i2s
->dai_driver
.playback
.rates
= SNDRV_PCM_RATE_8000_192000
;
517 i2s
->dai_driver
.playback
.formats
= SNDRV_PCM_FMTBIT_S32_LE
;
518 i2s
->dai_driver
.ops
= &img_i2s_out_dai_ops
;
520 ret
= devm_snd_soc_register_component(&pdev
->dev
,
521 &img_i2s_out_component
, &i2s
->dai_driver
, 1);
525 ret
= devm_snd_dmaengine_pcm_register(&pdev
->dev
,
526 &img_i2s_out_dma_config
, 0);
533 if (!pm_runtime_status_suspended(&pdev
->dev
))
534 img_i2s_out_runtime_suspend(&pdev
->dev
);
536 pm_runtime_disable(&pdev
->dev
);
541 static int img_i2s_out_dev_remove(struct platform_device
*pdev
)
543 pm_runtime_disable(&pdev
->dev
);
544 if (!pm_runtime_status_suspended(&pdev
->dev
))
545 img_i2s_out_runtime_suspend(&pdev
->dev
);
550 #ifdef CONFIG_PM_SLEEP
551 static int img_i2s_out_suspend(struct device
*dev
)
553 struct img_i2s_out
*i2s
= dev_get_drvdata(dev
);
557 if (pm_runtime_status_suspended(dev
)) {
558 ret
= img_i2s_out_runtime_resume(dev
);
563 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++) {
564 reg
= img_i2s_out_ch_readl(i2s
, i
, IMG_I2S_OUT_CH_CTL
);
565 i2s
->suspend_ch_ctl
[i
] = reg
;
568 i2s
->suspend_ctl
= img_i2s_out_readl(i2s
, IMG_I2S_OUT_CTL
);
570 img_i2s_out_runtime_suspend(dev
);
575 static int img_i2s_out_resume(struct device
*dev
)
577 struct img_i2s_out
*i2s
= dev_get_drvdata(dev
);
581 ret
= img_i2s_out_runtime_resume(dev
);
585 for (i
= 0; i
< i2s
->max_i2s_chan
; i
++) {
586 reg
= i2s
->suspend_ch_ctl
[i
];
587 img_i2s_out_ch_writel(i2s
, i
, reg
, IMG_I2S_OUT_CH_CTL
);
590 img_i2s_out_writel(i2s
, i2s
->suspend_ctl
, IMG_I2S_OUT_CTL
);
592 if (pm_runtime_status_suspended(dev
))
593 img_i2s_out_runtime_suspend(dev
);
599 static const struct of_device_id img_i2s_out_of_match
[] = {
600 { .compatible
= "img,i2s-out" },
603 MODULE_DEVICE_TABLE(of
, img_i2s_out_of_match
);
605 static const struct dev_pm_ops img_i2s_out_pm_ops
= {
606 SET_RUNTIME_PM_OPS(img_i2s_out_runtime_suspend
,
607 img_i2s_out_runtime_resume
, NULL
)
608 SET_SYSTEM_SLEEP_PM_OPS(img_i2s_out_suspend
, img_i2s_out_resume
)
611 static struct platform_driver img_i2s_out_driver
= {
613 .name
= "img-i2s-out",
614 .of_match_table
= img_i2s_out_of_match
,
615 .pm
= &img_i2s_out_pm_ops
617 .probe
= img_i2s_out_probe
,
618 .remove
= img_i2s_out_dev_remove
620 module_platform_driver(img_i2s_out_driver
);
622 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
623 MODULE_DESCRIPTION("IMG I2S Output Driver");
624 MODULE_LICENSE("GPL v2");