Lines Matching +full:i2s +full:- +full:out
1 // SPDX-License-Identifier: GPL-2.0-only
3 * IMG I2S output controller driver
69 struct img_i2s_out *i2s = dev_get_drvdata(dev); in img_i2s_out_runtime_suspend() local
71 clk_disable_unprepare(i2s->clk_ref); in img_i2s_out_runtime_suspend()
72 clk_disable_unprepare(i2s->clk_sys); in img_i2s_out_runtime_suspend()
79 struct img_i2s_out *i2s = dev_get_drvdata(dev); in img_i2s_out_runtime_resume() local
82 ret = clk_prepare_enable(i2s->clk_sys); in img_i2s_out_runtime_resume()
88 ret = clk_prepare_enable(i2s->clk_ref); in img_i2s_out_runtime_resume()
91 clk_disable_unprepare(i2s->clk_sys); in img_i2s_out_runtime_resume()
98 static inline void img_i2s_out_writel(struct img_i2s_out *i2s, u32 val, in img_i2s_out_writel() argument
101 writel(val, i2s->base + reg); in img_i2s_out_writel()
104 static inline u32 img_i2s_out_readl(struct img_i2s_out *i2s, u32 reg) in img_i2s_out_readl() argument
106 return readl(i2s->base + reg); in img_i2s_out_readl()
109 static inline void img_i2s_out_ch_writel(struct img_i2s_out *i2s, in img_i2s_out_ch_writel() argument
112 writel(val, i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); in img_i2s_out_ch_writel()
115 static inline u32 img_i2s_out_ch_readl(struct img_i2s_out *i2s, u32 chan, in img_i2s_out_ch_readl() argument
118 return readl(i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); in img_i2s_out_ch_readl()
121 static inline void img_i2s_out_ch_disable(struct img_i2s_out *i2s, u32 chan) in img_i2s_out_ch_disable() argument
125 reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); in img_i2s_out_ch_disable()
127 img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); in img_i2s_out_ch_disable()
130 static inline void img_i2s_out_ch_enable(struct img_i2s_out *i2s, u32 chan) in img_i2s_out_ch_enable() argument
134 reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); in img_i2s_out_ch_enable()
136 img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); in img_i2s_out_ch_enable()
139 static inline void img_i2s_out_disable(struct img_i2s_out *i2s) in img_i2s_out_disable() argument
143 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); in img_i2s_out_disable()
145 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); in img_i2s_out_disable()
148 static inline void img_i2s_out_enable(struct img_i2s_out *i2s) in img_i2s_out_enable() argument
152 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); in img_i2s_out_enable()
154 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); in img_i2s_out_enable()
157 static void img_i2s_out_reset(struct img_i2s_out *i2s) in img_i2s_out_reset() argument
162 core_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL) & in img_i2s_out_reset()
166 if (!i2s->force_clk_active) in img_i2s_out_reset()
169 chan_ctl = img_i2s_out_ch_readl(i2s, 0, IMG_I2S_OUT_CH_CTL) & in img_i2s_out_reset()
172 reset_control_assert(i2s->rst); in img_i2s_out_reset()
173 reset_control_deassert(i2s->rst); in img_i2s_out_reset()
175 for (i = 0; i < i2s->max_i2s_chan; i++) in img_i2s_out_reset()
176 img_i2s_out_ch_writel(i2s, i, chan_ctl, IMG_I2S_OUT_CH_CTL); in img_i2s_out_reset()
178 for (i = 0; i < i2s->active_channels; i++) in img_i2s_out_reset()
179 img_i2s_out_ch_enable(i2s, i); in img_i2s_out_reset()
181 img_i2s_out_writel(i2s, core_ctl, IMG_I2S_OUT_CTL); in img_i2s_out_reset()
182 img_i2s_out_enable(i2s); in img_i2s_out_reset()
188 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); in img_i2s_out_trigger() local
195 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); in img_i2s_out_trigger()
196 if (!i2s->force_clk_active) in img_i2s_out_trigger()
199 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); in img_i2s_out_trigger()
204 img_i2s_out_reset(i2s); in img_i2s_out_trigger()
207 return -EINVAL; in img_i2s_out_trigger()
216 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); in img_i2s_out_hw_params() local
229 return -EINVAL; in img_i2s_out_hw_params()
232 (channels > (i2s->max_i2s_chan * 2)) || in img_i2s_out_hw_params()
234 return -EINVAL; in img_i2s_out_hw_params()
236 pre_div_a = clk_round_rate(i2s->clk_ref, rate * 256); in img_i2s_out_hw_params()
239 pre_div_b = clk_round_rate(i2s->clk_ref, rate * 384); in img_i2s_out_hw_params()
243 diff_a = abs((pre_div_a / 256) - rate); in img_i2s_out_hw_params()
244 diff_b = abs((pre_div_b / 384) - rate); in img_i2s_out_hw_params()
248 clk_set_rate(i2s->clk_ref, pre_div_b); in img_i2s_out_hw_params()
250 clk_set_rate(i2s->clk_ref, pre_div_a); in img_i2s_out_hw_params()
257 clk_rate = clk_get_rate(i2s->clk_ref); in img_i2s_out_hw_params()
259 diff_a = abs((clk_rate / 256) - rate); in img_i2s_out_hw_params()
260 diff_b = abs((clk_rate / 384) - rate); in img_i2s_out_hw_params()
265 control_set |= ((i2s_channels - 1) << in img_i2s_out_hw_params()
272 img_i2s_out_disable(i2s); in img_i2s_out_hw_params()
274 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); in img_i2s_out_hw_params()
276 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); in img_i2s_out_hw_params()
279 img_i2s_out_ch_enable(i2s, i); in img_i2s_out_hw_params()
281 for (; i < i2s->max_i2s_chan; i++) in img_i2s_out_hw_params()
282 img_i2s_out_ch_disable(i2s, i); in img_i2s_out_hw_params()
284 img_i2s_out_enable(i2s); in img_i2s_out_hw_params()
286 i2s->active_channels = i2s_channels; in img_i2s_out_hw_params()
293 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); in img_i2s_out_set_fmt() local
312 return -EINVAL; in img_i2s_out_set_fmt()
329 return -EINVAL; in img_i2s_out_set_fmt()
339 return -EINVAL; in img_i2s_out_set_fmt()
349 ret = pm_runtime_resume_and_get(i2s->dev); in img_i2s_out_set_fmt()
353 img_i2s_out_disable(i2s); in img_i2s_out_set_fmt()
355 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); in img_i2s_out_set_fmt()
357 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); in img_i2s_out_set_fmt()
359 for (i = 0; i < i2s->active_channels; i++) in img_i2s_out_set_fmt()
360 img_i2s_out_ch_disable(i2s, i); in img_i2s_out_set_fmt()
362 for (i = 0; i < i2s->max_i2s_chan; i++) { in img_i2s_out_set_fmt()
363 reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL); in img_i2s_out_set_fmt()
365 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); in img_i2s_out_set_fmt()
368 for (i = 0; i < i2s->active_channels; i++) in img_i2s_out_set_fmt()
369 img_i2s_out_ch_enable(i2s, i); in img_i2s_out_set_fmt()
371 img_i2s_out_enable(i2s); in img_i2s_out_set_fmt()
372 pm_runtime_put(i2s->dev); in img_i2s_out_set_fmt()
374 i2s->force_clk_active = force_clk_active; in img_i2s_out_set_fmt()
381 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); in img_i2s_out_dai_probe() local
383 snd_soc_dai_init_dma_data(dai, &i2s->dma_data, NULL); in img_i2s_out_dai_probe()
396 .name = "img-i2s-out",
414 sc->dst_addr = dma_data->addr; in img_i2s_out_dma_prepare_slave_config()
415 sc->dst_addr_width = dma_data->addr_width; in img_i2s_out_dma_prepare_slave_config()
416 sc->dst_maxburst = 4 * i2s_channels; in img_i2s_out_dma_prepare_slave_config()
427 struct img_i2s_out *i2s; in img_i2s_out_probe() local
433 struct device *dev = &pdev->dev; in img_i2s_out_probe()
435 i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); in img_i2s_out_probe()
436 if (!i2s) in img_i2s_out_probe()
437 return -ENOMEM; in img_i2s_out_probe()
439 platform_set_drvdata(pdev, i2s); in img_i2s_out_probe()
441 i2s->dev = &pdev->dev; in img_i2s_out_probe()
447 i2s->base = base; in img_i2s_out_probe()
449 if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels", in img_i2s_out_probe()
450 &i2s->max_i2s_chan)) { in img_i2s_out_probe()
451 dev_err(&pdev->dev, "No img,i2s-channels property\n"); in img_i2s_out_probe()
452 return -EINVAL; in img_i2s_out_probe()
455 max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan); in img_i2s_out_probe()
457 i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); in img_i2s_out_probe()
459 i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst"); in img_i2s_out_probe()
460 if (IS_ERR(i2s->rst)) in img_i2s_out_probe()
461 return dev_err_probe(&pdev->dev, PTR_ERR(i2s->rst), in img_i2s_out_probe()
464 i2s->clk_sys = devm_clk_get(&pdev->dev, "sys"); in img_i2s_out_probe()
465 if (IS_ERR(i2s->clk_sys)) in img_i2s_out_probe()
466 return dev_err_probe(dev, PTR_ERR(i2s->clk_sys), in img_i2s_out_probe()
469 i2s->clk_ref = devm_clk_get(&pdev->dev, "ref"); in img_i2s_out_probe()
470 if (IS_ERR(i2s->clk_ref)) in img_i2s_out_probe()
471 return dev_err_probe(dev, PTR_ERR(i2s->clk_ref), in img_i2s_out_probe()
474 i2s->suspend_ch_ctl = devm_kcalloc(dev, in img_i2s_out_probe()
475 i2s->max_i2s_chan, sizeof(*i2s->suspend_ch_ctl), GFP_KERNEL); in img_i2s_out_probe()
476 if (!i2s->suspend_ch_ctl) in img_i2s_out_probe()
477 return -ENOMEM; in img_i2s_out_probe()
479 pm_runtime_enable(&pdev->dev); in img_i2s_out_probe()
480 if (!pm_runtime_enabled(&pdev->dev)) { in img_i2s_out_probe()
481 ret = img_i2s_out_runtime_resume(&pdev->dev); in img_i2s_out_probe()
485 ret = pm_runtime_resume_and_get(&pdev->dev); in img_i2s_out_probe()
490 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); in img_i2s_out_probe()
497 for (i = 0; i < i2s->max_i2s_chan; i++) in img_i2s_out_probe()
498 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); in img_i2s_out_probe()
500 img_i2s_out_reset(i2s); in img_i2s_out_probe()
501 pm_runtime_put(&pdev->dev); in img_i2s_out_probe()
503 i2s->active_channels = 1; in img_i2s_out_probe()
504 i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO; in img_i2s_out_probe()
505 i2s->dma_data.addr_width = 4; in img_i2s_out_probe()
506 i2s->dma_data.maxburst = 4; in img_i2s_out_probe()
508 i2s->dai_driver.playback.channels_min = 2; in img_i2s_out_probe()
509 i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2; in img_i2s_out_probe()
510 i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; in img_i2s_out_probe()
511 i2s->dai_driver.playback.formats = SNDRV_PCM_FMTBIT_S32_LE; in img_i2s_out_probe()
512 i2s->dai_driver.ops = &img_i2s_out_dai_ops; in img_i2s_out_probe()
514 ret = devm_snd_soc_register_component(&pdev->dev, in img_i2s_out_probe()
515 &img_i2s_out_component, &i2s->dai_driver, 1); in img_i2s_out_probe()
519 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, in img_i2s_out_probe()
527 if (!pm_runtime_status_suspended(&pdev->dev)) in img_i2s_out_probe()
528 img_i2s_out_runtime_suspend(&pdev->dev); in img_i2s_out_probe()
530 pm_runtime_disable(&pdev->dev); in img_i2s_out_probe()
537 pm_runtime_disable(&pdev->dev); in img_i2s_out_dev_remove()
538 if (!pm_runtime_status_suspended(&pdev->dev)) in img_i2s_out_dev_remove()
539 img_i2s_out_runtime_suspend(&pdev->dev); in img_i2s_out_dev_remove()
545 struct img_i2s_out *i2s = dev_get_drvdata(dev); in img_i2s_out_suspend() local
555 for (i = 0; i < i2s->max_i2s_chan; i++) { in img_i2s_out_suspend()
556 reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL); in img_i2s_out_suspend()
557 i2s->suspend_ch_ctl[i] = reg; in img_i2s_out_suspend()
560 i2s->suspend_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); in img_i2s_out_suspend()
569 struct img_i2s_out *i2s = dev_get_drvdata(dev); in img_i2s_out_resume() local
577 for (i = 0; i < i2s->max_i2s_chan; i++) { in img_i2s_out_resume()
578 reg = i2s->suspend_ch_ctl[i]; in img_i2s_out_resume()
579 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); in img_i2s_out_resume()
582 img_i2s_out_writel(i2s, i2s->suspend_ctl, IMG_I2S_OUT_CTL); in img_i2s_out_resume()
592 { .compatible = "img,i2s-out" },
605 .name = "img-i2s-out",
615 MODULE_DESCRIPTION("IMG I2S Output Driver");