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