Lines Matching full:tdm
3 * jh7110_tdm.c -- StarFive JH7110 TDM driver
128 /* data related to DMA transfers b/w tdm and DMAC */
137 static inline u32 jh7110_tdm_readl(struct jh7110_tdm_dev *tdm, u16 reg) in jh7110_tdm_readl() argument
139 return readl_relaxed(tdm->tdm_base + reg); in jh7110_tdm_readl()
142 static inline void jh7110_tdm_writel(struct jh7110_tdm_dev *tdm, u16 reg, u32 val) in jh7110_tdm_writel() argument
144 writel_relaxed(val, tdm->tdm_base + reg); in jh7110_tdm_writel()
147 static void jh7110_tdm_save_context(struct jh7110_tdm_dev *tdm, in jh7110_tdm_save_context() argument
151 tdm->saved_pcmtxcr = jh7110_tdm_readl(tdm, TDM_PCMTXCR); in jh7110_tdm_save_context()
153 tdm->saved_pcmrxcr = jh7110_tdm_readl(tdm, TDM_PCMRXCR); in jh7110_tdm_save_context()
156 static void jh7110_tdm_start(struct jh7110_tdm_dev *tdm, in jh7110_tdm_start() argument
161 data = jh7110_tdm_readl(tdm, TDM_PCMGBCR); in jh7110_tdm_start()
162 jh7110_tdm_writel(tdm, TDM_PCMGBCR, data | PCMGBCR_ENABLE); in jh7110_tdm_start()
166 jh7110_tdm_writel(tdm, TDM_PCMTXCR, tdm->saved_pcmtxcr | PCMTXCR_TXEN); in jh7110_tdm_start()
168 jh7110_tdm_writel(tdm, TDM_PCMRXCR, tdm->saved_pcmrxcr | PCMRXCR_RXEN); in jh7110_tdm_start()
171 static void jh7110_tdm_stop(struct jh7110_tdm_dev *tdm, in jh7110_tdm_stop() argument
177 val = jh7110_tdm_readl(tdm, TDM_PCMTXCR); in jh7110_tdm_stop()
179 jh7110_tdm_writel(tdm, TDM_PCMTXCR, val); in jh7110_tdm_stop()
181 val = jh7110_tdm_readl(tdm, TDM_PCMRXCR); in jh7110_tdm_stop()
183 jh7110_tdm_writel(tdm, TDM_PCMRXCR, val); in jh7110_tdm_stop()
187 static int jh7110_tdm_syncdiv(struct jh7110_tdm_dev *tdm) in jh7110_tdm_syncdiv() argument
191 sl = max(tdm->rx.sl, tdm->tx.sl); in jh7110_tdm_syncdiv()
192 sscale = max(tdm->rx.sscale, tdm->tx.sscale); in jh7110_tdm_syncdiv()
193 syncdiv = tdm->pcmclk / tdm->samplerate - 1; in jh7110_tdm_syncdiv()
196 dev_err(tdm->dev, "Failed to set syncdiv!\n"); in jh7110_tdm_syncdiv()
200 if (tdm->syncm == TDM_SYNCM_LONG && in jh7110_tdm_syncdiv()
201 (tdm->rx.sscale <= 1 || tdm->tx.sscale <= 1) && in jh7110_tdm_syncdiv()
203 dev_err(tdm->dev, "Wrong syncdiv! It must be (syncdiv+1) > max[tx.sl, rx.sl]\n"); in jh7110_tdm_syncdiv()
207 jh7110_tdm_writel(tdm, TDM_PCMDIV, syncdiv); in jh7110_tdm_syncdiv()
211 static int jh7110_tdm_config(struct jh7110_tdm_dev *tdm, in jh7110_tdm_config() argument
217 ret = jh7110_tdm_syncdiv(tdm); in jh7110_tdm_config()
221 datarx = (tdm->rx.ifl << IFL_BIT) | in jh7110_tdm_config()
222 (tdm->rx.wl << WL_BIT) | in jh7110_tdm_config()
223 (tdm->rx.sscale << SSCALE_BIT) | in jh7110_tdm_config()
224 (tdm->rx.sl << SL_BIT) | in jh7110_tdm_config()
225 (tdm->rx.lrj << LRJ_BIT); in jh7110_tdm_config()
227 datatx = (tdm->tx.ifl << IFL_BIT) | in jh7110_tdm_config()
228 (tdm->tx.wl << WL_BIT) | in jh7110_tdm_config()
229 (tdm->tx.sscale << SSCALE_BIT) | in jh7110_tdm_config()
230 (tdm->tx.sl << SL_BIT) | in jh7110_tdm_config()
231 (tdm->tx.lrj << LRJ_BIT); in jh7110_tdm_config()
234 jh7110_tdm_writel(tdm, TDM_PCMTXCR, datatx); in jh7110_tdm_config()
236 jh7110_tdm_writel(tdm, TDM_PCMRXCR, datarx); in jh7110_tdm_config()
241 static void jh7110_tdm_clk_disable(struct jh7110_tdm_dev *tdm) in jh7110_tdm_clk_disable() argument
243 clk_bulk_disable_unprepare(ARRAY_SIZE(tdm->clks), tdm->clks); in jh7110_tdm_clk_disable()
246 static int jh7110_tdm_clk_enable(struct jh7110_tdm_dev *tdm) in jh7110_tdm_clk_enable() argument
250 ret = clk_bulk_prepare_enable(ARRAY_SIZE(tdm->clks), tdm->clks); in jh7110_tdm_clk_enable()
252 dev_err(tdm->dev, "Failed to enable tdm clocks\n"); in jh7110_tdm_clk_enable()
256 ret = reset_control_deassert(tdm->resets); in jh7110_tdm_clk_enable()
258 dev_err(tdm->dev, "Failed to deassert tdm resets\n"); in jh7110_tdm_clk_enable()
262 /* select tdm_ext clock as the clock source for tdm */ in jh7110_tdm_clk_enable()
263 ret = clk_set_parent(tdm->clks[5].clk, tdm->clks[4].clk); in jh7110_tdm_clk_enable()
265 dev_err(tdm->dev, "Can't set extern clock source for clk_tdm\n"); in jh7110_tdm_clk_enable()
272 clk_bulk_disable_unprepare(ARRAY_SIZE(tdm->clks), tdm->clks); in jh7110_tdm_clk_enable()
279 struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev); in jh7110_tdm_runtime_suspend() local
281 jh7110_tdm_clk_disable(tdm); in jh7110_tdm_runtime_suspend()
287 struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev); in jh7110_tdm_runtime_resume() local
289 return jh7110_tdm_clk_enable(tdm); in jh7110_tdm_runtime_resume()
294 struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev); in jh7110_tdm_system_suspend() local
297 tdm->saved_pcmgbcr = jh7110_tdm_readl(tdm, TDM_PCMGBCR); in jh7110_tdm_system_suspend()
298 tdm->saved_pcmdiv = jh7110_tdm_readl(tdm, TDM_PCMDIV); in jh7110_tdm_system_suspend()
305 struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev); in jh7110_tdm_system_resume() local
308 jh7110_tdm_writel(tdm, TDM_PCMGBCR, tdm->saved_pcmgbcr); in jh7110_tdm_system_resume()
309 jh7110_tdm_writel(tdm, TDM_PCMDIV, tdm->saved_pcmdiv); in jh7110_tdm_system_resume()
315 .name = "jh7110-tdm",
333 struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); in jh7110_tdm_hw_params() local
342 tdm->samplerate = params_rate(params); in jh7110_tdm_hw_params()
343 tdm->pcmclk = params_channels(params) * tdm->samplerate * data_width; in jh7110_tdm_hw_params()
359 dev_err(tdm->dev, "tdm: unsupported PCM fmt"); in jh7110_tdm_hw_params()
372 dev_err(tdm->dev, "channel not supported\n"); in jh7110_tdm_hw_params()
377 tdm->tx.wl = chan_wl; in jh7110_tdm_hw_params()
378 tdm->tx.sl = chan_sl; in jh7110_tdm_hw_params()
379 tdm->tx.sscale = chan_nr; in jh7110_tdm_hw_params()
380 tdm->play_dma_data.addr_width = dma_bus_width; in jh7110_tdm_hw_params()
381 dma_data = &tdm->play_dma_data; in jh7110_tdm_hw_params()
383 tdm->rx.wl = chan_wl; in jh7110_tdm_hw_params()
384 tdm->rx.sl = chan_sl; in jh7110_tdm_hw_params()
385 tdm->rx.sscale = chan_nr; in jh7110_tdm_hw_params()
386 tdm->capture_dma_data.addr_width = dma_bus_width; in jh7110_tdm_hw_params()
387 dma_data = &tdm->capture_dma_data; in jh7110_tdm_hw_params()
392 ret = jh7110_tdm_config(tdm, substream); in jh7110_tdm_hw_params()
396 jh7110_tdm_save_context(tdm, substream); in jh7110_tdm_hw_params()
403 struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); in jh7110_tdm_trigger() local
410 jh7110_tdm_start(tdm, substream); in jh7110_tdm_trigger()
416 jh7110_tdm_stop(tdm, substream); in jh7110_tdm_trigger()
429 struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(cpu_dai); in jh7110_tdm_set_dai_fmt() local
436 tdm->ms_mode = TDM_AS_MASTER; in jh7110_tdm_set_dai_fmt()
440 tdm->ms_mode = TDM_AS_SLAVE; in jh7110_tdm_set_dai_fmt()
446 dev_dbg(tdm->dev, "dwc : Invalid clock provider format\n"); in jh7110_tdm_set_dai_fmt()
450 gbcr = (tdm->clkpolity << CLKPOL_BIT) | in jh7110_tdm_set_dai_fmt()
451 (tdm->elm << ELM_BIT) | in jh7110_tdm_set_dai_fmt()
452 (tdm->syncm << SYNCM_BIT) | in jh7110_tdm_set_dai_fmt()
453 (tdm->ms_mode << MS_BIT); in jh7110_tdm_set_dai_fmt()
454 jh7110_tdm_writel(tdm, TDM_PCMGBCR, gbcr); in jh7110_tdm_set_dai_fmt()
461 struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); in jh7110_tdm_dai_probe() local
463 snd_soc_dai_init_dma_data(dai, &tdm->play_dma_data, &tdm->capture_dma_data); in jh7110_tdm_dai_probe()
464 snd_soc_dai_set_drvdata(dai, tdm); in jh7110_tdm_dai_probe()
523 static void jh7110_tdm_init_params(struct jh7110_tdm_dev *tdm) in jh7110_tdm_init_params() argument
525 tdm->clkpolity = TDM_TX_RASING_RX_FALLING; in jh7110_tdm_init_params()
526 tdm->elm = TDM_ELM_LATE; in jh7110_tdm_init_params()
527 tdm->syncm = TDM_SYNCM_SHORT; in jh7110_tdm_init_params()
529 tdm->rx.ifl = TDM_FIFO_HALF; in jh7110_tdm_init_params()
530 tdm->tx.ifl = TDM_FIFO_HALF; in jh7110_tdm_init_params()
531 tdm->rx.wl = TDM_16BIT_WORD_LEN; in jh7110_tdm_init_params()
532 tdm->tx.wl = TDM_16BIT_WORD_LEN; in jh7110_tdm_init_params()
533 tdm->rx.sscale = 2; in jh7110_tdm_init_params()
534 tdm->tx.sscale = 2; in jh7110_tdm_init_params()
535 tdm->rx.lrj = TDM_LEFT_JUSTIFT; in jh7110_tdm_init_params()
536 tdm->tx.lrj = TDM_LEFT_JUSTIFT; in jh7110_tdm_init_params()
538 tdm->play_dma_data.addr = JH7110_TDM_FIFO; in jh7110_tdm_init_params()
539 tdm->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; in jh7110_tdm_init_params()
540 tdm->play_dma_data.fifo_size = JH7110_TDM_FIFO_DEPTH / 2; in jh7110_tdm_init_params()
541 tdm->play_dma_data.maxburst = 16; in jh7110_tdm_init_params()
543 tdm->capture_dma_data.addr = JH7110_TDM_FIFO; in jh7110_tdm_init_params()
544 tdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; in jh7110_tdm_init_params()
545 tdm->capture_dma_data.fifo_size = JH7110_TDM_FIFO_DEPTH / 2; in jh7110_tdm_init_params()
546 tdm->capture_dma_data.maxburst = 8; in jh7110_tdm_init_params()
550 struct jh7110_tdm_dev *tdm) in jh7110_tdm_clk_reset_get() argument
554 tdm->clks[0].id = "mclk_inner"; in jh7110_tdm_clk_reset_get()
555 tdm->clks[1].id = "tdm_ahb"; in jh7110_tdm_clk_reset_get()
556 tdm->clks[2].id = "tdm_apb"; in jh7110_tdm_clk_reset_get()
557 tdm->clks[3].id = "tdm_internal"; in jh7110_tdm_clk_reset_get()
558 tdm->clks[4].id = "tdm_ext"; in jh7110_tdm_clk_reset_get()
559 tdm->clks[5].id = "tdm"; in jh7110_tdm_clk_reset_get()
561 ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(tdm->clks), tdm->clks); in jh7110_tdm_clk_reset_get()
563 dev_err(&pdev->dev, "Failed to get tdm clocks\n"); in jh7110_tdm_clk_reset_get()
567 tdm->resets = devm_reset_control_array_get_exclusive(&pdev->dev); in jh7110_tdm_clk_reset_get()
568 if (IS_ERR(tdm->resets)) { in jh7110_tdm_clk_reset_get()
569 dev_err(&pdev->dev, "Failed to get tdm resets\n"); in jh7110_tdm_clk_reset_get()
570 return PTR_ERR(tdm->resets); in jh7110_tdm_clk_reset_get()
578 struct jh7110_tdm_dev *tdm; in jh7110_tdm_probe() local
581 tdm = devm_kzalloc(&pdev->dev, sizeof(*tdm), GFP_KERNEL); in jh7110_tdm_probe()
582 if (!tdm) in jh7110_tdm_probe()
585 tdm->tdm_base = devm_platform_ioremap_resource(pdev, 0); in jh7110_tdm_probe()
586 if (IS_ERR(tdm->tdm_base)) in jh7110_tdm_probe()
587 return PTR_ERR(tdm->tdm_base); in jh7110_tdm_probe()
589 tdm->dev = &pdev->dev; in jh7110_tdm_probe()
591 ret = jh7110_tdm_clk_reset_get(pdev, tdm); in jh7110_tdm_probe()
593 dev_err(&pdev->dev, "Failed to enable audio-tdm clock\n"); in jh7110_tdm_probe()
597 jh7110_tdm_init_params(tdm); in jh7110_tdm_probe()
599 dev_set_drvdata(&pdev->dev, tdm); in jh7110_tdm_probe()
636 { .compatible = "starfive,jh7110-tdm", },
651 .name = "jh7110-tdm",
660 MODULE_DESCRIPTION("StarFive JH7110 TDM ASoC Driver");