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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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