Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * jh7110_tdm.c -- StarFive JH7110 TDM driver
  4 *
  5 * Copyright (C) 2023 StarFive Technology Co., Ltd.
  6 *
  7 * Author: Walker Chen <walker.chen@starfivetech.com>
  8 */
  9
 10#include <linux/clk.h>
 11#include <linux/device.h>
 12#include <linux/dmaengine.h>
 13#include <linux/module.h>
 14#include <linux/of_irq.h>
 15#include <linux/of_platform.h>
 16#include <linux/pm_runtime.h>
 17#include <linux/regmap.h>
 18#include <linux/reset.h>
 19#include <linux/types.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>
 25#include <sound/soc-dai.h>
 26
 27#define TDM_PCMGBCR			0x00
 28	#define PCMGBCR_ENABLE		BIT(0)
 29	#define CLKPOL_BIT		5
 30	#define ELM_BIT			3
 31	#define SYNCM_BIT		2
 32	#define MS_BIT			1
 33#define TDM_PCMTXCR			0x04
 34	#define PCMTXCR_TXEN		BIT(0)
 35	#define IFL_BIT			11
 36	#define WL_BIT			8
 37	#define SSCALE_BIT		4
 38	#define SL_BIT			2
 39	#define LRJ_BIT			1
 40#define TDM_PCMRXCR			0x08
 41	#define PCMRXCR_RXEN		BIT(0)
 42#define TDM_PCMDIV			0x0c
 43
 44#define JH7110_TDM_FIFO			0x170c0000
 45#define JH7110_TDM_FIFO_DEPTH		32
 46
 47enum TDM_MASTER_SLAVE_MODE {
 48	TDM_AS_MASTER = 0,
 49	TDM_AS_SLAVE,
 50};
 51
 52enum TDM_CLKPOL {
 53	/* tx raising and rx falling */
 54	TDM_TX_RASING_RX_FALLING = 0,
 55	/* tx falling and rx raising */
 56	TDM_TX_FALLING_RX_RASING,
 57};
 58
 59enum TDM_ELM {
 60	/* only work while SYNCM=0 */
 61	TDM_ELM_LATE = 0,
 62	TDM_ELM_EARLY,
 63};
 64
 65enum TDM_SYNCM {
 66	/* short frame sync */
 67	TDM_SYNCM_SHORT = 0,
 68	/* long frame sync */
 69	TDM_SYNCM_LONG,
 70};
 71
 72enum TDM_IFL {
 73	/* FIFO to send or received : half-1/2, Quarter-1/4 */
 74	TDM_FIFO_HALF = 0,
 75	TDM_FIFO_QUARTER,
 76};
 77
 78enum TDM_WL {
 79	/* send or received word length */
 80	TDM_8BIT_WORD_LEN = 0,
 81	TDM_16BIT_WORD_LEN,
 82	TDM_20BIT_WORD_LEN,
 83	TDM_24BIT_WORD_LEN,
 84	TDM_32BIT_WORD_LEN,
 85};
 86
 87enum TDM_SL {
 88	/* send or received slot length */
 89	TDM_8BIT_SLOT_LEN = 0,
 90	TDM_16BIT_SLOT_LEN,
 91	TDM_32BIT_SLOT_LEN,
 92};
 93
 94enum TDM_LRJ {
 95	/* left-justify or right-justify */
 96	TDM_RIGHT_JUSTIFY = 0,
 97	TDM_LEFT_JUSTIFT,
 98};
 99
100struct tdm_chan_cfg {
101	enum TDM_IFL ifl;
102	enum TDM_WL  wl;
103	unsigned char sscale;
104	enum TDM_SL  sl;
105	enum TDM_LRJ lrj;
106	unsigned char enable;
107};
108
109struct jh7110_tdm_dev {
110	void __iomem *tdm_base;
111	struct device *dev;
112	struct clk_bulk_data clks[6];
113	struct reset_control *resets;
114
115	enum TDM_CLKPOL clkpolity;
116	enum TDM_ELM	elm;
117	enum TDM_SYNCM	syncm;
118	enum TDM_MASTER_SLAVE_MODE ms_mode;
119
120	struct tdm_chan_cfg tx;
121	struct tdm_chan_cfg rx;
122
123	u16 syncdiv;
124	u32 samplerate;
125	u32 pcmclk;
126
127	/* data related to DMA transfers b/w tdm and DMAC */
128	struct snd_dmaengine_dai_dma_data play_dma_data;
129	struct snd_dmaengine_dai_dma_data capture_dma_data;
130	u32 saved_pcmgbcr;
131	u32 saved_pcmtxcr;
132	u32 saved_pcmrxcr;
133	u32 saved_pcmdiv;
134};
135
136static inline u32 jh7110_tdm_readl(struct jh7110_tdm_dev *tdm, u16 reg)
137{
138	return readl_relaxed(tdm->tdm_base + reg);
139}
140
141static inline void jh7110_tdm_writel(struct jh7110_tdm_dev *tdm, u16 reg, u32 val)
142{
143	writel_relaxed(val, tdm->tdm_base + reg);
144}
145
146static void jh7110_tdm_save_context(struct jh7110_tdm_dev *tdm,
147				    struct snd_pcm_substream *substream)
148{
149	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
150		tdm->saved_pcmtxcr = jh7110_tdm_readl(tdm, TDM_PCMTXCR);
151	else
152		tdm->saved_pcmrxcr = jh7110_tdm_readl(tdm, TDM_PCMRXCR);
153}
154
155static void jh7110_tdm_start(struct jh7110_tdm_dev *tdm,
156			     struct snd_pcm_substream *substream)
157{
158	u32 data;
159
160	data = jh7110_tdm_readl(tdm, TDM_PCMGBCR);
161	jh7110_tdm_writel(tdm, TDM_PCMGBCR, data | PCMGBCR_ENABLE);
162
163	/* restore context */
164	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
165		jh7110_tdm_writel(tdm, TDM_PCMTXCR, tdm->saved_pcmtxcr | PCMTXCR_TXEN);
166	else
167		jh7110_tdm_writel(tdm, TDM_PCMRXCR, tdm->saved_pcmrxcr | PCMRXCR_RXEN);
168}
169
170static void jh7110_tdm_stop(struct jh7110_tdm_dev *tdm,
171			    struct snd_pcm_substream *substream)
172{
173	unsigned int val;
174
175	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
176		val = jh7110_tdm_readl(tdm, TDM_PCMTXCR);
177		val &= ~PCMTXCR_TXEN;
178		jh7110_tdm_writel(tdm, TDM_PCMTXCR, val);
179	} else {
180		val = jh7110_tdm_readl(tdm, TDM_PCMRXCR);
181		val &= ~PCMRXCR_RXEN;
182		jh7110_tdm_writel(tdm, TDM_PCMRXCR, val);
183	}
184}
185
186static int jh7110_tdm_syncdiv(struct jh7110_tdm_dev *tdm)
187{
188	u32 sl, sscale, syncdiv;
189
190	if (tdm->rx.sl >= tdm->tx.sl)
191		sl = tdm->rx.sl;
192	else
193		sl = tdm->tx.sl;
194
195	if (tdm->rx.sscale >= tdm->tx.sscale)
196		sscale = tdm->rx.sscale;
197	else
198		sscale = tdm->tx.sscale;
199
200	syncdiv = tdm->pcmclk / tdm->samplerate - 1;
201
202	if ((syncdiv + 1) < (sl * sscale)) {
203		dev_err(tdm->dev, "Failed to set syncdiv!\n");
204		return -EINVAL;
205	}
206
207	if (tdm->syncm == TDM_SYNCM_LONG &&
208	    (tdm->rx.sscale <= 1 || tdm->tx.sscale <= 1) &&
209	    ((syncdiv + 1) <= sl)) {
210		dev_err(tdm->dev, "Wrong syncdiv! It must be (syncdiv+1) > max[tx.sl, rx.sl]\n");
211		return -EINVAL;
212	}
213
214	jh7110_tdm_writel(tdm, TDM_PCMDIV, syncdiv);
215	return 0;
216}
217
218static int jh7110_tdm_config(struct jh7110_tdm_dev *tdm,
219			     struct snd_pcm_substream *substream)
220{
221	u32 datarx, datatx;
222	int ret;
223
224	ret = jh7110_tdm_syncdiv(tdm);
225	if (ret)
226		return ret;
227
228	datarx = (tdm->rx.ifl << IFL_BIT) |
229		  (tdm->rx.wl << WL_BIT) |
230		  (tdm->rx.sscale << SSCALE_BIT) |
231		  (tdm->rx.sl << SL_BIT) |
232		  (tdm->rx.lrj << LRJ_BIT);
233
234	datatx = (tdm->tx.ifl << IFL_BIT) |
235		  (tdm->tx.wl << WL_BIT) |
236		  (tdm->tx.sscale << SSCALE_BIT) |
237		  (tdm->tx.sl << SL_BIT) |
238		  (tdm->tx.lrj << LRJ_BIT);
239
240	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
241		jh7110_tdm_writel(tdm, TDM_PCMTXCR, datatx);
242	else
243		jh7110_tdm_writel(tdm, TDM_PCMRXCR, datarx);
244
245	return 0;
246}
247
248static void jh7110_tdm_clk_disable(struct jh7110_tdm_dev *tdm)
249{
250	clk_bulk_disable_unprepare(ARRAY_SIZE(tdm->clks), tdm->clks);
251}
252
253static int jh7110_tdm_clk_enable(struct jh7110_tdm_dev *tdm)
254{
255	int ret;
256
257	ret = clk_bulk_prepare_enable(ARRAY_SIZE(tdm->clks), tdm->clks);
258	if (ret) {
259		dev_err(tdm->dev, "Failed to enable tdm clocks\n");
260		return ret;
261	}
262
263	ret = reset_control_deassert(tdm->resets);
264	if (ret) {
265		dev_err(tdm->dev, "Failed to deassert tdm resets\n");
266		goto dis_tdm_clk;
267	}
268
269	/* select tdm_ext clock as the clock source for tdm */
270	ret = clk_set_parent(tdm->clks[5].clk, tdm->clks[4].clk);
271	if (ret) {
272		dev_err(tdm->dev, "Can't set extern clock source for clk_tdm\n");
273		goto dis_tdm_clk;
274	}
275
276	return 0;
277
278dis_tdm_clk:
279	clk_bulk_disable_unprepare(ARRAY_SIZE(tdm->clks), tdm->clks);
280
281	return ret;
282}
283
284static int jh7110_tdm_runtime_suspend(struct device *dev)
285{
286	struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev);
287
288	jh7110_tdm_clk_disable(tdm);
289	return 0;
290}
291
292static int jh7110_tdm_runtime_resume(struct device *dev)
293{
294	struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev);
295
296	return jh7110_tdm_clk_enable(tdm);
297}
298
299static int jh7110_tdm_system_suspend(struct device *dev)
300{
301	struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev);
302
303	/* save context */
304	tdm->saved_pcmgbcr = jh7110_tdm_readl(tdm, TDM_PCMGBCR);
305	tdm->saved_pcmdiv = jh7110_tdm_readl(tdm, TDM_PCMDIV);
306
307	return pm_runtime_force_suspend(dev);
308}
309
310static int jh7110_tdm_system_resume(struct device *dev)
311{
312	struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev);
313
314	/* restore context */
315	jh7110_tdm_writel(tdm, TDM_PCMGBCR, tdm->saved_pcmgbcr);
316	jh7110_tdm_writel(tdm, TDM_PCMDIV, tdm->saved_pcmdiv);
317
318	return pm_runtime_force_resume(dev);
319}
320
321static const struct snd_soc_component_driver jh7110_tdm_component = {
322	.name = "jh7110-tdm",
323};
324
325static int jh7110_tdm_startup(struct snd_pcm_substream *substream,
326			      struct snd_soc_dai *cpu_dai)
327{
328	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
329	struct snd_soc_dai_link *dai_link = rtd->dai_link;
330
331	dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC;
332
333	return 0;
334}
335
336static int jh7110_tdm_hw_params(struct snd_pcm_substream *substream,
337				struct snd_pcm_hw_params *params,
338				struct snd_soc_dai *dai)
339{
340	struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai);
341	int chan_wl, chan_sl, chan_nr;
342	unsigned int data_width;
343	unsigned int dma_bus_width;
344	struct snd_dmaengine_dai_dma_data *dma_data = NULL;
345	int ret;
346
347	data_width = params_width(params);
348
349	tdm->samplerate = params_rate(params);
350	tdm->pcmclk = params_channels(params) * tdm->samplerate * data_width;
351
352	switch (params_format(params)) {
353	case SNDRV_PCM_FORMAT_S16_LE:
354		chan_wl = TDM_16BIT_WORD_LEN;
355		chan_sl = TDM_16BIT_SLOT_LEN;
356		dma_bus_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
357		break;
358
359	case SNDRV_PCM_FORMAT_S32_LE:
360		chan_wl = TDM_32BIT_WORD_LEN;
361		chan_sl = TDM_32BIT_SLOT_LEN;
362		dma_bus_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
363		break;
364
365	default:
366		dev_err(tdm->dev, "tdm: unsupported PCM fmt");
367		return -EINVAL;
368	}
369
370	chan_nr = params_channels(params);
371	switch (chan_nr) {
372	case 1:
373	case 2:
374	case 4:
375	case 6:
376	case 8:
377		break;
378	default:
379		dev_err(tdm->dev, "channel not supported\n");
380		return -EINVAL;
381	}
382
383	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
384		tdm->tx.wl = chan_wl;
385		tdm->tx.sl = chan_sl;
386		tdm->tx.sscale = chan_nr;
387		tdm->play_dma_data.addr_width = dma_bus_width;
388		dma_data = &tdm->play_dma_data;
389	} else {
390		tdm->rx.wl = chan_wl;
391		tdm->rx.sl = chan_sl;
392		tdm->rx.sscale = chan_nr;
393		tdm->capture_dma_data.addr_width = dma_bus_width;
394		dma_data = &tdm->capture_dma_data;
395	}
396
397	snd_soc_dai_set_dma_data(dai, substream, dma_data);
398
399	ret = jh7110_tdm_config(tdm, substream);
400	if (ret)
401		return ret;
402
403	jh7110_tdm_save_context(tdm, substream);
404	return 0;
405}
406
407static int jh7110_tdm_trigger(struct snd_pcm_substream *substream,
408			      int cmd, struct snd_soc_dai *dai)
409{
410	struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai);
411	int ret = 0;
412
413	switch (cmd) {
414	case SNDRV_PCM_TRIGGER_START:
415	case SNDRV_PCM_TRIGGER_RESUME:
416	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
417		jh7110_tdm_start(tdm, substream);
418		break;
419
420	case SNDRV_PCM_TRIGGER_STOP:
421	case SNDRV_PCM_TRIGGER_SUSPEND:
422	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
423		jh7110_tdm_stop(tdm, substream);
424		break;
425	default:
426		ret = -EINVAL;
427		break;
428	}
429
430	return ret;
431}
432
433static int jh7110_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
434				  unsigned int fmt)
435{
436	struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(cpu_dai);
437	unsigned int gbcr;
438
439	/* set master/slave audio interface */
440	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
441	case SND_SOC_DAIFMT_BP_FP:
442		/* cpu is master */
443		tdm->ms_mode = TDM_AS_MASTER;
444		break;
445	case SND_SOC_DAIFMT_BC_FC:
446		/* codec is master */
447		tdm->ms_mode = TDM_AS_SLAVE;
448		break;
449	case SND_SOC_DAIFMT_BC_FP:
450	case SND_SOC_DAIFMT_BP_FC:
451		return -EINVAL;
452	default:
453		dev_dbg(tdm->dev, "dwc : Invalid clock provider format\n");
454		return -EINVAL;
455	}
456
457	gbcr = (tdm->clkpolity << CLKPOL_BIT) |
458		(tdm->elm << ELM_BIT) |
459		(tdm->syncm << SYNCM_BIT) |
460		(tdm->ms_mode << MS_BIT);
461	jh7110_tdm_writel(tdm, TDM_PCMGBCR, gbcr);
462
463	return 0;
464}
465
466static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai)
467{
468	struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai);
469
470	snd_soc_dai_init_dma_data(dai, &tdm->play_dma_data, &tdm->capture_dma_data);
471	snd_soc_dai_set_drvdata(dai, tdm);
472	return 0;
473}
474
475static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = {
476	.probe		= jh7110_tdm_dai_probe,
477	.startup	= jh7110_tdm_startup,
478	.hw_params	= jh7110_tdm_hw_params,
479	.trigger	= jh7110_tdm_trigger,
480	.set_fmt	= jh7110_tdm_set_dai_fmt,
481};
482
483#define JH7110_TDM_RATES	SNDRV_PCM_RATE_8000_48000
484
485#define JH7110_TDM_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
486				 SNDRV_PCM_FMTBIT_S32_LE)
487
488static struct snd_soc_dai_driver jh7110_tdm_dai = {
489	.name = "sf_tdm",
490	.id = 0,
491	.playback = {
492		.stream_name    = "Playback",
493		.channels_min   = 1,
494		.channels_max   = 8,
495		.rates          = JH7110_TDM_RATES,
496		.formats        = JH7110_TDM_FORMATS,
497	},
498	.capture = {
499		.stream_name    = "Capture",
500		.channels_min   = 1,
501		.channels_max   = 8,
502		.rates          = JH7110_TDM_RATES,
503		.formats        = JH7110_TDM_FORMATS,
504	},
505	.ops = &jh7110_tdm_dai_ops,
506	.symmetric_rate = 1,
507};
508
509static const struct snd_pcm_hardware jh7110_pcm_hardware = {
510	.info			= (SNDRV_PCM_INFO_MMAP		|
511				   SNDRV_PCM_INFO_MMAP_VALID	|
512				   SNDRV_PCM_INFO_PAUSE		|
513				   SNDRV_PCM_INFO_RESUME	|
514				   SNDRV_PCM_INFO_INTERLEAVED	|
515				   SNDRV_PCM_INFO_BLOCK_TRANSFER),
516	.buffer_bytes_max	= 192512,
517	.period_bytes_min	= 4096,
518	.period_bytes_max	= 32768,
519	.periods_min		= 1,
520	.periods_max		= 48,
521	.fifo_size		= 16,
522};
523
524static const struct snd_dmaengine_pcm_config jh7110_dmaengine_pcm_config = {
525	.pcm_hardware = &jh7110_pcm_hardware,
526	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
527	.prealloc_buffer_size = 192512,
528};
529
530static void jh7110_tdm_init_params(struct jh7110_tdm_dev *tdm)
531{
532	tdm->clkpolity = TDM_TX_RASING_RX_FALLING;
533	tdm->elm = TDM_ELM_LATE;
534	tdm->syncm = TDM_SYNCM_SHORT;
535
536	tdm->rx.ifl = TDM_FIFO_HALF;
537	tdm->tx.ifl = TDM_FIFO_HALF;
538	tdm->rx.wl = TDM_16BIT_WORD_LEN;
539	tdm->tx.wl = TDM_16BIT_WORD_LEN;
540	tdm->rx.sscale = 2;
541	tdm->tx.sscale = 2;
542	tdm->rx.lrj = TDM_LEFT_JUSTIFT;
543	tdm->tx.lrj = TDM_LEFT_JUSTIFT;
544
545	tdm->play_dma_data.addr = JH7110_TDM_FIFO;
546	tdm->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
547	tdm->play_dma_data.fifo_size = JH7110_TDM_FIFO_DEPTH / 2;
548	tdm->play_dma_data.maxburst = 16;
549
550	tdm->capture_dma_data.addr = JH7110_TDM_FIFO;
551	tdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
552	tdm->capture_dma_data.fifo_size = JH7110_TDM_FIFO_DEPTH / 2;
553	tdm->capture_dma_data.maxburst = 8;
554}
555
556static int jh7110_tdm_clk_reset_get(struct platform_device *pdev,
557				    struct jh7110_tdm_dev *tdm)
558{
559	int ret;
560
561	tdm->clks[0].id = "mclk_inner";
562	tdm->clks[1].id = "tdm_ahb";
563	tdm->clks[2].id = "tdm_apb";
564	tdm->clks[3].id = "tdm_internal";
565	tdm->clks[4].id = "tdm_ext";
566	tdm->clks[5].id = "tdm";
567
568	ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(tdm->clks), tdm->clks);
569	if (ret) {
570		dev_err(&pdev->dev, "Failed to get tdm clocks\n");
571		return ret;
572	}
573
574	tdm->resets = devm_reset_control_array_get_exclusive(&pdev->dev);
575	if (IS_ERR(tdm->resets)) {
576		dev_err(&pdev->dev, "Failed to get tdm resets\n");
577		return PTR_ERR(tdm->resets);
578	}
579
580	return 0;
581}
582
583static int jh7110_tdm_probe(struct platform_device *pdev)
584{
585	struct jh7110_tdm_dev *tdm;
586	int ret;
587
588	tdm = devm_kzalloc(&pdev->dev, sizeof(*tdm), GFP_KERNEL);
589	if (!tdm)
590		return -ENOMEM;
591
592	tdm->tdm_base = devm_platform_ioremap_resource(pdev, 0);
593	if (IS_ERR(tdm->tdm_base))
594		return PTR_ERR(tdm->tdm_base);
595
596	tdm->dev = &pdev->dev;
597
598	ret = jh7110_tdm_clk_reset_get(pdev, tdm);
599	if (ret) {
600		dev_err(&pdev->dev, "Failed to enable audio-tdm clock\n");
601		return ret;
602	}
603
604	jh7110_tdm_init_params(tdm);
605
606	dev_set_drvdata(&pdev->dev, tdm);
607	ret = devm_snd_soc_register_component(&pdev->dev, &jh7110_tdm_component,
608					      &jh7110_tdm_dai, 1);
609	if (ret) {
610		dev_err(&pdev->dev, "Failed to register dai\n");
611		return ret;
612	}
613
614	ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
615					      &jh7110_dmaengine_pcm_config,
616					      SND_DMAENGINE_PCM_FLAG_COMPAT);
617	if (ret) {
618		dev_err(&pdev->dev, "Could not register pcm: %d\n", ret);
619		return ret;
620	}
621
622	pm_runtime_enable(&pdev->dev);
623	if (!pm_runtime_enabled(&pdev->dev)) {
624		ret = jh7110_tdm_runtime_resume(&pdev->dev);
625		if (ret)
626			goto err_pm_disable;
627	}
628
629	return 0;
630
631err_pm_disable:
632	pm_runtime_disable(&pdev->dev);
633
634	return ret;
635}
636
637static void jh7110_tdm_dev_remove(struct platform_device *pdev)
638{
639	pm_runtime_disable(&pdev->dev);
640}
641
642static const struct of_device_id jh7110_tdm_of_match[] = {
643	{ .compatible = "starfive,jh7110-tdm", },
644	{}
645};
646
647MODULE_DEVICE_TABLE(of, jh7110_tdm_of_match);
648
649static const struct dev_pm_ops jh7110_tdm_pm_ops = {
650	RUNTIME_PM_OPS(jh7110_tdm_runtime_suspend,
651		       jh7110_tdm_runtime_resume, NULL)
652	SYSTEM_SLEEP_PM_OPS(jh7110_tdm_system_suspend,
653			    jh7110_tdm_system_resume)
654};
655
656static struct platform_driver jh7110_tdm_driver = {
657	.driver = {
658		.name = "jh7110-tdm",
659		.of_match_table = jh7110_tdm_of_match,
660		.pm = pm_ptr(&jh7110_tdm_pm_ops),
661	},
662	.probe = jh7110_tdm_probe,
663	.remove = jh7110_tdm_dev_remove,
664};
665module_platform_driver(jh7110_tdm_driver);
666
667MODULE_DESCRIPTION("StarFive JH7110 TDM ASoC Driver");
668MODULE_AUTHOR("Walker Chen <walker.chen@starfivetech.com>");
669MODULE_LICENSE("GPL");
v6.9.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * jh7110_tdm.c -- StarFive JH7110 TDM driver
  4 *
  5 * Copyright (C) 2023 StarFive Technology Co., Ltd.
  6 *
  7 * Author: Walker Chen <walker.chen@starfivetech.com>
  8 */
  9
 10#include <linux/clk.h>
 11#include <linux/device.h>
 12#include <linux/dmaengine.h>
 13#include <linux/module.h>
 14#include <linux/of_irq.h>
 15#include <linux/of_platform.h>
 16#include <linux/pm_runtime.h>
 17#include <linux/regmap.h>
 18#include <linux/reset.h>
 19#include <linux/types.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>
 25#include <sound/soc-dai.h>
 26
 27#define TDM_PCMGBCR			0x00
 28	#define PCMGBCR_ENABLE		BIT(0)
 29	#define CLKPOL_BIT		5
 30	#define ELM_BIT			3
 31	#define SYNCM_BIT		2
 32	#define MS_BIT			1
 33#define TDM_PCMTXCR			0x04
 34	#define PCMTXCR_TXEN		BIT(0)
 35	#define IFL_BIT			11
 36	#define WL_BIT			8
 37	#define SSCALE_BIT		4
 38	#define SL_BIT			2
 39	#define LRJ_BIT			1
 40#define TDM_PCMRXCR			0x08
 41	#define PCMRXCR_RXEN		BIT(0)
 42#define TDM_PCMDIV			0x0c
 43
 44#define JH7110_TDM_FIFO			0x170c0000
 45#define JH7110_TDM_FIFO_DEPTH		32
 46
 47enum TDM_MASTER_SLAVE_MODE {
 48	TDM_AS_MASTER = 0,
 49	TDM_AS_SLAVE,
 50};
 51
 52enum TDM_CLKPOL {
 53	/* tx raising and rx falling */
 54	TDM_TX_RASING_RX_FALLING = 0,
 55	/* tx falling and rx raising */
 56	TDM_TX_FALLING_RX_RASING,
 57};
 58
 59enum TDM_ELM {
 60	/* only work while SYNCM=0 */
 61	TDM_ELM_LATE = 0,
 62	TDM_ELM_EARLY,
 63};
 64
 65enum TDM_SYNCM {
 66	/* short frame sync */
 67	TDM_SYNCM_SHORT = 0,
 68	/* long frame sync */
 69	TDM_SYNCM_LONG,
 70};
 71
 72enum TDM_IFL {
 73	/* FIFO to send or received : half-1/2, Quarter-1/4 */
 74	TDM_FIFO_HALF = 0,
 75	TDM_FIFO_QUARTER,
 76};
 77
 78enum TDM_WL {
 79	/* send or received word length */
 80	TDM_8BIT_WORD_LEN = 0,
 81	TDM_16BIT_WORD_LEN,
 82	TDM_20BIT_WORD_LEN,
 83	TDM_24BIT_WORD_LEN,
 84	TDM_32BIT_WORD_LEN,
 85};
 86
 87enum TDM_SL {
 88	/* send or received slot length */
 89	TDM_8BIT_SLOT_LEN = 0,
 90	TDM_16BIT_SLOT_LEN,
 91	TDM_32BIT_SLOT_LEN,
 92};
 93
 94enum TDM_LRJ {
 95	/* left-justify or right-justify */
 96	TDM_RIGHT_JUSTIFY = 0,
 97	TDM_LEFT_JUSTIFT,
 98};
 99
100struct tdm_chan_cfg {
101	enum TDM_IFL ifl;
102	enum TDM_WL  wl;
103	unsigned char sscale;
104	enum TDM_SL  sl;
105	enum TDM_LRJ lrj;
106	unsigned char enable;
107};
108
109struct jh7110_tdm_dev {
110	void __iomem *tdm_base;
111	struct device *dev;
112	struct clk_bulk_data clks[6];
113	struct reset_control *resets;
114
115	enum TDM_CLKPOL clkpolity;
116	enum TDM_ELM	elm;
117	enum TDM_SYNCM	syncm;
118	enum TDM_MASTER_SLAVE_MODE ms_mode;
119
120	struct tdm_chan_cfg tx;
121	struct tdm_chan_cfg rx;
122
123	u16 syncdiv;
124	u32 samplerate;
125	u32 pcmclk;
126
127	/* data related to DMA transfers b/w tdm and DMAC */
128	struct snd_dmaengine_dai_dma_data play_dma_data;
129	struct snd_dmaengine_dai_dma_data capture_dma_data;
130	u32 saved_pcmgbcr;
131	u32 saved_pcmtxcr;
132	u32 saved_pcmrxcr;
133	u32 saved_pcmdiv;
134};
135
136static inline u32 jh7110_tdm_readl(struct jh7110_tdm_dev *tdm, u16 reg)
137{
138	return readl_relaxed(tdm->tdm_base + reg);
139}
140
141static inline void jh7110_tdm_writel(struct jh7110_tdm_dev *tdm, u16 reg, u32 val)
142{
143	writel_relaxed(val, tdm->tdm_base + reg);
144}
145
146static void jh7110_tdm_save_context(struct jh7110_tdm_dev *tdm,
147				    struct snd_pcm_substream *substream)
148{
149	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
150		tdm->saved_pcmtxcr = jh7110_tdm_readl(tdm, TDM_PCMTXCR);
151	else
152		tdm->saved_pcmrxcr = jh7110_tdm_readl(tdm, TDM_PCMRXCR);
153}
154
155static void jh7110_tdm_start(struct jh7110_tdm_dev *tdm,
156			     struct snd_pcm_substream *substream)
157{
158	u32 data;
159
160	data = jh7110_tdm_readl(tdm, TDM_PCMGBCR);
161	jh7110_tdm_writel(tdm, TDM_PCMGBCR, data | PCMGBCR_ENABLE);
162
163	/* restore context */
164	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
165		jh7110_tdm_writel(tdm, TDM_PCMTXCR, tdm->saved_pcmtxcr | PCMTXCR_TXEN);
166	else
167		jh7110_tdm_writel(tdm, TDM_PCMRXCR, tdm->saved_pcmrxcr | PCMRXCR_RXEN);
168}
169
170static void jh7110_tdm_stop(struct jh7110_tdm_dev *tdm,
171			    struct snd_pcm_substream *substream)
172{
173	unsigned int val;
174
175	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
176		val = jh7110_tdm_readl(tdm, TDM_PCMTXCR);
177		val &= ~PCMTXCR_TXEN;
178		jh7110_tdm_writel(tdm, TDM_PCMTXCR, val);
179	} else {
180		val = jh7110_tdm_readl(tdm, TDM_PCMRXCR);
181		val &= ~PCMRXCR_RXEN;
182		jh7110_tdm_writel(tdm, TDM_PCMRXCR, val);
183	}
184}
185
186static int jh7110_tdm_syncdiv(struct jh7110_tdm_dev *tdm)
187{
188	u32 sl, sscale, syncdiv;
189
190	if (tdm->rx.sl >= tdm->tx.sl)
191		sl = tdm->rx.sl;
192	else
193		sl = tdm->tx.sl;
194
195	if (tdm->rx.sscale >= tdm->tx.sscale)
196		sscale = tdm->rx.sscale;
197	else
198		sscale = tdm->tx.sscale;
199
200	syncdiv = tdm->pcmclk / tdm->samplerate - 1;
201
202	if ((syncdiv + 1) < (sl * sscale)) {
203		dev_err(tdm->dev, "Failed to set syncdiv!\n");
204		return -EINVAL;
205	}
206
207	if (tdm->syncm == TDM_SYNCM_LONG &&
208	    (tdm->rx.sscale <= 1 || tdm->tx.sscale <= 1) &&
209	    ((syncdiv + 1) <= sl)) {
210		dev_err(tdm->dev, "Wrong syncdiv! It must be (syncdiv+1) > max[tx.sl, rx.sl]\n");
211		return -EINVAL;
212	}
213
214	jh7110_tdm_writel(tdm, TDM_PCMDIV, syncdiv);
215	return 0;
216}
217
218static int jh7110_tdm_config(struct jh7110_tdm_dev *tdm,
219			     struct snd_pcm_substream *substream)
220{
221	u32 datarx, datatx;
222	int ret;
223
224	ret = jh7110_tdm_syncdiv(tdm);
225	if (ret)
226		return ret;
227
228	datarx = (tdm->rx.ifl << IFL_BIT) |
229		  (tdm->rx.wl << WL_BIT) |
230		  (tdm->rx.sscale << SSCALE_BIT) |
231		  (tdm->rx.sl << SL_BIT) |
232		  (tdm->rx.lrj << LRJ_BIT);
233
234	datatx = (tdm->tx.ifl << IFL_BIT) |
235		  (tdm->tx.wl << WL_BIT) |
236		  (tdm->tx.sscale << SSCALE_BIT) |
237		  (tdm->tx.sl << SL_BIT) |
238		  (tdm->tx.lrj << LRJ_BIT);
239
240	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
241		jh7110_tdm_writel(tdm, TDM_PCMTXCR, datatx);
242	else
243		jh7110_tdm_writel(tdm, TDM_PCMRXCR, datarx);
244
245	return 0;
246}
247
248static void jh7110_tdm_clk_disable(struct jh7110_tdm_dev *tdm)
249{
250	clk_bulk_disable_unprepare(ARRAY_SIZE(tdm->clks), tdm->clks);
251}
252
253static int jh7110_tdm_clk_enable(struct jh7110_tdm_dev *tdm)
254{
255	int ret;
256
257	ret = clk_bulk_prepare_enable(ARRAY_SIZE(tdm->clks), tdm->clks);
258	if (ret) {
259		dev_err(tdm->dev, "Failed to enable tdm clocks\n");
260		return ret;
261	}
262
263	ret = reset_control_deassert(tdm->resets);
264	if (ret) {
265		dev_err(tdm->dev, "Failed to deassert tdm resets\n");
266		goto dis_tdm_clk;
267	}
268
269	/* select tdm_ext clock as the clock source for tdm */
270	ret = clk_set_parent(tdm->clks[5].clk, tdm->clks[4].clk);
271	if (ret) {
272		dev_err(tdm->dev, "Can't set extern clock source for clk_tdm\n");
273		goto dis_tdm_clk;
274	}
275
276	return 0;
277
278dis_tdm_clk:
279	clk_bulk_disable_unprepare(ARRAY_SIZE(tdm->clks), tdm->clks);
280
281	return ret;
282}
283
284static int jh7110_tdm_runtime_suspend(struct device *dev)
285{
286	struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev);
287
288	jh7110_tdm_clk_disable(tdm);
289	return 0;
290}
291
292static int jh7110_tdm_runtime_resume(struct device *dev)
293{
294	struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev);
295
296	return jh7110_tdm_clk_enable(tdm);
297}
298
299static int jh7110_tdm_system_suspend(struct device *dev)
300{
301	struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev);
302
303	/* save context */
304	tdm->saved_pcmgbcr = jh7110_tdm_readl(tdm, TDM_PCMGBCR);
305	tdm->saved_pcmdiv = jh7110_tdm_readl(tdm, TDM_PCMDIV);
306
307	return pm_runtime_force_suspend(dev);
308}
309
310static int jh7110_tdm_system_resume(struct device *dev)
311{
312	struct jh7110_tdm_dev *tdm = dev_get_drvdata(dev);
313
314	/* restore context */
315	jh7110_tdm_writel(tdm, TDM_PCMGBCR, tdm->saved_pcmgbcr);
316	jh7110_tdm_writel(tdm, TDM_PCMDIV, tdm->saved_pcmdiv);
317
318	return pm_runtime_force_resume(dev);
319}
320
321static const struct snd_soc_component_driver jh7110_tdm_component = {
322	.name = "jh7110-tdm",
323};
324
325static int jh7110_tdm_startup(struct snd_pcm_substream *substream,
326			      struct snd_soc_dai *cpu_dai)
327{
328	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
329	struct snd_soc_dai_link *dai_link = rtd->dai_link;
330
331	dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC;
332
333	return 0;
334}
335
336static int jh7110_tdm_hw_params(struct snd_pcm_substream *substream,
337				struct snd_pcm_hw_params *params,
338				struct snd_soc_dai *dai)
339{
340	struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai);
341	int chan_wl, chan_sl, chan_nr;
342	unsigned int data_width;
343	unsigned int dma_bus_width;
344	struct snd_dmaengine_dai_dma_data *dma_data = NULL;
345	int ret;
346
347	data_width = params_width(params);
348
349	tdm->samplerate = params_rate(params);
350	tdm->pcmclk = params_channels(params) * tdm->samplerate * data_width;
351
352	switch (params_format(params)) {
353	case SNDRV_PCM_FORMAT_S16_LE:
354		chan_wl = TDM_16BIT_WORD_LEN;
355		chan_sl = TDM_16BIT_SLOT_LEN;
356		dma_bus_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
357		break;
358
359	case SNDRV_PCM_FORMAT_S32_LE:
360		chan_wl = TDM_32BIT_WORD_LEN;
361		chan_sl = TDM_32BIT_SLOT_LEN;
362		dma_bus_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
363		break;
364
365	default:
366		dev_err(tdm->dev, "tdm: unsupported PCM fmt");
367		return -EINVAL;
368	}
369
370	chan_nr = params_channels(params);
371	switch (chan_nr) {
372	case 1:
373	case 2:
374	case 4:
375	case 6:
376	case 8:
377		break;
378	default:
379		dev_err(tdm->dev, "channel not supported\n");
380		return -EINVAL;
381	}
382
383	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
384		tdm->tx.wl = chan_wl;
385		tdm->tx.sl = chan_sl;
386		tdm->tx.sscale = chan_nr;
387		tdm->play_dma_data.addr_width = dma_bus_width;
388		dma_data = &tdm->play_dma_data;
389	} else {
390		tdm->rx.wl = chan_wl;
391		tdm->rx.sl = chan_sl;
392		tdm->rx.sscale = chan_nr;
393		tdm->capture_dma_data.addr_width = dma_bus_width;
394		dma_data = &tdm->capture_dma_data;
395	}
396
397	snd_soc_dai_set_dma_data(dai, substream, dma_data);
398
399	ret = jh7110_tdm_config(tdm, substream);
400	if (ret)
401		return ret;
402
403	jh7110_tdm_save_context(tdm, substream);
404	return 0;
405}
406
407static int jh7110_tdm_trigger(struct snd_pcm_substream *substream,
408			      int cmd, struct snd_soc_dai *dai)
409{
410	struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai);
411	int ret = 0;
412
413	switch (cmd) {
414	case SNDRV_PCM_TRIGGER_START:
415	case SNDRV_PCM_TRIGGER_RESUME:
416	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
417		jh7110_tdm_start(tdm, substream);
418		break;
419
420	case SNDRV_PCM_TRIGGER_STOP:
421	case SNDRV_PCM_TRIGGER_SUSPEND:
422	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
423		jh7110_tdm_stop(tdm, substream);
424		break;
425	default:
426		ret = -EINVAL;
427		break;
428	}
429
430	return ret;
431}
432
433static int jh7110_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
434				  unsigned int fmt)
435{
436	struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(cpu_dai);
437	unsigned int gbcr;
438
439	/* set master/slave audio interface */
440	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
441	case SND_SOC_DAIFMT_BP_FP:
442		/* cpu is master */
443		tdm->ms_mode = TDM_AS_MASTER;
444		break;
445	case SND_SOC_DAIFMT_BC_FC:
446		/* codec is master */
447		tdm->ms_mode = TDM_AS_SLAVE;
448		break;
449	case SND_SOC_DAIFMT_BC_FP:
450	case SND_SOC_DAIFMT_BP_FC:
451		return -EINVAL;
452	default:
453		dev_dbg(tdm->dev, "dwc : Invalid clock provider format\n");
454		return -EINVAL;
455	}
456
457	gbcr = (tdm->clkpolity << CLKPOL_BIT) |
458		(tdm->elm << ELM_BIT) |
459		(tdm->syncm << SYNCM_BIT) |
460		(tdm->ms_mode << MS_BIT);
461	jh7110_tdm_writel(tdm, TDM_PCMGBCR, gbcr);
462
463	return 0;
464}
465
466static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai)
467{
468	struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai);
469
470	snd_soc_dai_init_dma_data(dai, &tdm->play_dma_data, &tdm->capture_dma_data);
471	snd_soc_dai_set_drvdata(dai, tdm);
472	return 0;
473}
474
475static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = {
476	.probe		= jh7110_tdm_dai_probe,
477	.startup	= jh7110_tdm_startup,
478	.hw_params	= jh7110_tdm_hw_params,
479	.trigger	= jh7110_tdm_trigger,
480	.set_fmt	= jh7110_tdm_set_dai_fmt,
481};
482
483#define JH7110_TDM_RATES	SNDRV_PCM_RATE_8000_48000
484
485#define JH7110_TDM_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
486				 SNDRV_PCM_FMTBIT_S32_LE)
487
488static struct snd_soc_dai_driver jh7110_tdm_dai = {
489	.name = "sf_tdm",
490	.id = 0,
491	.playback = {
492		.stream_name    = "Playback",
493		.channels_min   = 1,
494		.channels_max   = 8,
495		.rates          = JH7110_TDM_RATES,
496		.formats        = JH7110_TDM_FORMATS,
497	},
498	.capture = {
499		.stream_name    = "Capture",
500		.channels_min   = 1,
501		.channels_max   = 8,
502		.rates          = JH7110_TDM_RATES,
503		.formats        = JH7110_TDM_FORMATS,
504	},
505	.ops = &jh7110_tdm_dai_ops,
506	.symmetric_rate = 1,
507};
508
509static const struct snd_pcm_hardware jh7110_pcm_hardware = {
510	.info			= (SNDRV_PCM_INFO_MMAP		|
511				   SNDRV_PCM_INFO_MMAP_VALID	|
512				   SNDRV_PCM_INFO_PAUSE		|
513				   SNDRV_PCM_INFO_RESUME	|
514				   SNDRV_PCM_INFO_INTERLEAVED	|
515				   SNDRV_PCM_INFO_BLOCK_TRANSFER),
516	.buffer_bytes_max	= 192512,
517	.period_bytes_min	= 4096,
518	.period_bytes_max	= 32768,
519	.periods_min		= 1,
520	.periods_max		= 48,
521	.fifo_size		= 16,
522};
523
524static const struct snd_dmaengine_pcm_config jh7110_dmaengine_pcm_config = {
525	.pcm_hardware = &jh7110_pcm_hardware,
526	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
527	.prealloc_buffer_size = 192512,
528};
529
530static void jh7110_tdm_init_params(struct jh7110_tdm_dev *tdm)
531{
532	tdm->clkpolity = TDM_TX_RASING_RX_FALLING;
533	tdm->elm = TDM_ELM_LATE;
534	tdm->syncm = TDM_SYNCM_SHORT;
535
536	tdm->rx.ifl = TDM_FIFO_HALF;
537	tdm->tx.ifl = TDM_FIFO_HALF;
538	tdm->rx.wl = TDM_16BIT_WORD_LEN;
539	tdm->tx.wl = TDM_16BIT_WORD_LEN;
540	tdm->rx.sscale = 2;
541	tdm->tx.sscale = 2;
542	tdm->rx.lrj = TDM_LEFT_JUSTIFT;
543	tdm->tx.lrj = TDM_LEFT_JUSTIFT;
544
545	tdm->play_dma_data.addr = JH7110_TDM_FIFO;
546	tdm->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
547	tdm->play_dma_data.fifo_size = JH7110_TDM_FIFO_DEPTH / 2;
548	tdm->play_dma_data.maxburst = 16;
549
550	tdm->capture_dma_data.addr = JH7110_TDM_FIFO;
551	tdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
552	tdm->capture_dma_data.fifo_size = JH7110_TDM_FIFO_DEPTH / 2;
553	tdm->capture_dma_data.maxburst = 8;
554}
555
556static int jh7110_tdm_clk_reset_get(struct platform_device *pdev,
557				    struct jh7110_tdm_dev *tdm)
558{
559	int ret;
560
561	tdm->clks[0].id = "mclk_inner";
562	tdm->clks[1].id = "tdm_ahb";
563	tdm->clks[2].id = "tdm_apb";
564	tdm->clks[3].id = "tdm_internal";
565	tdm->clks[4].id = "tdm_ext";
566	tdm->clks[5].id = "tdm";
567
568	ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(tdm->clks), tdm->clks);
569	if (ret) {
570		dev_err(&pdev->dev, "Failed to get tdm clocks\n");
571		return ret;
572	}
573
574	tdm->resets = devm_reset_control_array_get_exclusive(&pdev->dev);
575	if (IS_ERR(tdm->resets)) {
576		dev_err(&pdev->dev, "Failed to get tdm resets\n");
577		return PTR_ERR(tdm->resets);
578	}
579
580	return 0;
581}
582
583static int jh7110_tdm_probe(struct platform_device *pdev)
584{
585	struct jh7110_tdm_dev *tdm;
586	int ret;
587
588	tdm = devm_kzalloc(&pdev->dev, sizeof(*tdm), GFP_KERNEL);
589	if (!tdm)
590		return -ENOMEM;
591
592	tdm->tdm_base = devm_platform_ioremap_resource(pdev, 0);
593	if (IS_ERR(tdm->tdm_base))
594		return PTR_ERR(tdm->tdm_base);
595
596	tdm->dev = &pdev->dev;
597
598	ret = jh7110_tdm_clk_reset_get(pdev, tdm);
599	if (ret) {
600		dev_err(&pdev->dev, "Failed to enable audio-tdm clock\n");
601		return ret;
602	}
603
604	jh7110_tdm_init_params(tdm);
605
606	dev_set_drvdata(&pdev->dev, tdm);
607	ret = devm_snd_soc_register_component(&pdev->dev, &jh7110_tdm_component,
608					      &jh7110_tdm_dai, 1);
609	if (ret) {
610		dev_err(&pdev->dev, "Failed to register dai\n");
611		return ret;
612	}
613
614	ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
615					      &jh7110_dmaengine_pcm_config,
616					      SND_DMAENGINE_PCM_FLAG_COMPAT);
617	if (ret) {
618		dev_err(&pdev->dev, "Could not register pcm: %d\n", ret);
619		return ret;
620	}
621
622	pm_runtime_enable(&pdev->dev);
623	if (!pm_runtime_enabled(&pdev->dev)) {
624		ret = jh7110_tdm_runtime_resume(&pdev->dev);
625		if (ret)
626			goto err_pm_disable;
627	}
628
629	return 0;
630
631err_pm_disable:
632	pm_runtime_disable(&pdev->dev);
633
634	return ret;
635}
636
637static void jh7110_tdm_dev_remove(struct platform_device *pdev)
638{
639	pm_runtime_disable(&pdev->dev);
640}
641
642static const struct of_device_id jh7110_tdm_of_match[] = {
643	{ .compatible = "starfive,jh7110-tdm", },
644	{}
645};
646
647MODULE_DEVICE_TABLE(of, jh7110_tdm_of_match);
648
649static const struct dev_pm_ops jh7110_tdm_pm_ops = {
650	RUNTIME_PM_OPS(jh7110_tdm_runtime_suspend,
651		       jh7110_tdm_runtime_resume, NULL)
652	SYSTEM_SLEEP_PM_OPS(jh7110_tdm_system_suspend,
653			    jh7110_tdm_system_resume)
654};
655
656static struct platform_driver jh7110_tdm_driver = {
657	.driver = {
658		.name = "jh7110-tdm",
659		.of_match_table = jh7110_tdm_of_match,
660		.pm = pm_ptr(&jh7110_tdm_pm_ops),
661	},
662	.probe = jh7110_tdm_probe,
663	.remove_new = jh7110_tdm_dev_remove,
664};
665module_platform_driver(jh7110_tdm_driver);
666
667MODULE_DESCRIPTION("StarFive JH7110 TDM ASoC Driver");
668MODULE_AUTHOR("Walker Chen <walker.chen@starfivetech.com>");
669MODULE_LICENSE("GPL");