1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> 4 */ 5 6#include <linux/init.h> 7#include <linux/io.h> 8#include <linux/of.h> 9#include <linux/of_device.h> 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/platform_device.h> 13#include <linux/slab.h> 14 15#include <linux/clk.h> 16#include <linux/delay.h> 17 18#include <linux/dma-mapping.h> 19 20#include <sound/core.h> 21#include <sound/pcm.h> 22#include <sound/pcm_params.h> 23#include <sound/soc.h> 24#include <sound/initval.h> 25#include <sound/dmaengine_pcm.h> 26 27#include "jz4740-i2s.h" 28 29#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24 30#define JZ4740_DMA_TYPE_AIC_RECEIVE 25 31 32#define JZ_REG_AIC_CONF 0x00 33#define JZ_REG_AIC_CTRL 0x04 34#define JZ_REG_AIC_I2S_FMT 0x10 35#define JZ_REG_AIC_FIFO_STATUS 0x14 36#define JZ_REG_AIC_I2S_STATUS 0x1c 37#define JZ_REG_AIC_CLK_DIV 0x30 38#define JZ_REG_AIC_FIFO 0x34 39 40#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12) 41#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf << 8) 42#define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6) 43#define JZ_AIC_CONF_INTERNAL_CODEC BIT(5) 44#define JZ_AIC_CONF_I2S BIT(4) 45#define JZ_AIC_CONF_RESET BIT(3) 46#define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2) 47#define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1) 48#define JZ_AIC_CONF_ENABLE BIT(0) 49 50#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12 51#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8 52#define JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24 53#define JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16 54 55#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19) 56#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16) 57#define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15) 58#define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14) 59#define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11) 60#define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10) 61#define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9) 62#define JZ_AIC_CTRL_TFLUSH BIT(8) 63#define JZ_AIC_CTRL_RFLUSH BIT(7) 64#define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6) 65#define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5) 66#define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4) 67#define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3) 68#define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2) 69#define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1) 70#define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0) 71 72#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19 73#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16 74 75#define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12) 76#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13) 77#define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4) 78#define JZ_AIC_I2S_FMT_MSB BIT(0) 79 80#define JZ_AIC_I2S_STATUS_BUSY BIT(2) 81 82#define JZ_AIC_CLK_DIV_MASK 0xf 83#define I2SDIV_DV_SHIFT 0 84#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT) 85#define I2SDIV_IDV_SHIFT 8 86#define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT) 87 88enum jz47xx_i2s_version { 89 JZ_I2S_JZ4740, 90 JZ_I2S_JZ4760, 91 JZ_I2S_JZ4770, 92 JZ_I2S_JZ4780, 93}; 94 95struct i2s_soc_info { 96 enum jz47xx_i2s_version version; 97 struct snd_soc_dai_driver *dai; 98 99 bool shared_fifo_flush; 100}; 101 102struct jz4740_i2s { 103 struct resource *mem; 104 void __iomem *base; 105 dma_addr_t phys_base; 106 107 struct clk *clk_aic; 108 struct clk *clk_i2s; 109 110 struct snd_dmaengine_dai_dma_data playback_dma_data; 111 struct snd_dmaengine_dai_dma_data capture_dma_data; 112 113 const struct i2s_soc_info *soc_info; 114}; 115 116static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s, 117 unsigned int reg) 118{ 119 return readl(i2s->base + reg); 120} 121 122static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s, 123 unsigned int reg, uint32_t value) 124{ 125 writel(value, i2s->base + reg); 126} 127 128static inline void jz4740_i2s_set_bits(const struct jz4740_i2s *i2s, 129 unsigned int reg, uint32_t bits) 130{ 131 uint32_t value = jz4740_i2s_read(i2s, reg); 132 value |= bits; 133 jz4740_i2s_write(i2s, reg, value); 134} 135 136static int jz4740_i2s_startup(struct snd_pcm_substream *substream, 137 struct snd_soc_dai *dai) 138{ 139 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 140 uint32_t conf; 141 int ret; 142 143 /* 144 * When we can flush FIFOs independently, only flush the FIFO 145 * that is starting up. We can do this when the DAI is active 146 * because it does not disturb other active substreams. 147 */ 148 if (!i2s->soc_info->shared_fifo_flush) { 149 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 150 jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH); 151 else 152 jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_RFLUSH); 153 } 154 155 if (snd_soc_dai_active(dai)) 156 return 0; 157 158 /* 159 * When there is a shared flush bit for both FIFOs, the TFLUSH 160 * bit flushes both FIFOs. Flushing while the DAI is active would 161 * cause FIFO underruns in other active substreams so we have to 162 * guard this behind the snd_soc_dai_active() check. 163 */ 164 if (i2s->soc_info->shared_fifo_flush) 165 jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH); 166 167 ret = clk_prepare_enable(i2s->clk_i2s); 168 if (ret) 169 return ret; 170 171 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 172 conf |= JZ_AIC_CONF_ENABLE; 173 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 174 175 return 0; 176} 177 178static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, 179 struct snd_soc_dai *dai) 180{ 181 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 182 uint32_t conf; 183 184 if (snd_soc_dai_active(dai)) 185 return; 186 187 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 188 conf &= ~JZ_AIC_CONF_ENABLE; 189 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 190 191 clk_disable_unprepare(i2s->clk_i2s); 192} 193 194static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 195 struct snd_soc_dai *dai) 196{ 197 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 198 199 uint32_t ctrl; 200 uint32_t mask; 201 202 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 203 mask = JZ_AIC_CTRL_ENABLE_PLAYBACK | JZ_AIC_CTRL_ENABLE_TX_DMA; 204 else 205 mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA; 206 207 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); 208 209 switch (cmd) { 210 case SNDRV_PCM_TRIGGER_START: 211 case SNDRV_PCM_TRIGGER_RESUME: 212 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 213 ctrl |= mask; 214 break; 215 case SNDRV_PCM_TRIGGER_STOP: 216 case SNDRV_PCM_TRIGGER_SUSPEND: 217 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 218 ctrl &= ~mask; 219 break; 220 default: 221 return -EINVAL; 222 } 223 224 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); 225 226 return 0; 227} 228 229static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 230{ 231 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 232 233 uint32_t format = 0; 234 uint32_t conf; 235 236 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 237 238 conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER); 239 240 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 241 case SND_SOC_DAIFMT_CBS_CFS: 242 conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER; 243 format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK; 244 break; 245 case SND_SOC_DAIFMT_CBM_CFS: 246 conf |= JZ_AIC_CONF_SYNC_CLK_MASTER; 247 break; 248 case SND_SOC_DAIFMT_CBS_CFM: 249 conf |= JZ_AIC_CONF_BIT_CLK_MASTER; 250 break; 251 case SND_SOC_DAIFMT_CBM_CFM: 252 break; 253 default: 254 return -EINVAL; 255 } 256 257 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 258 case SND_SOC_DAIFMT_MSB: 259 format |= JZ_AIC_I2S_FMT_MSB; 260 break; 261 case SND_SOC_DAIFMT_I2S: 262 break; 263 default: 264 return -EINVAL; 265 } 266 267 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 268 case SND_SOC_DAIFMT_NB_NF: 269 break; 270 default: 271 return -EINVAL; 272 } 273 274 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 275 jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format); 276 277 return 0; 278} 279 280static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, 281 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 282{ 283 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 284 unsigned int sample_size; 285 uint32_t ctrl, div_reg; 286 int div; 287 288 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); 289 290 div_reg = jz4740_i2s_read(i2s, JZ_REG_AIC_CLK_DIV); 291 div = clk_get_rate(i2s->clk_i2s) / (64 * params_rate(params)); 292 293 switch (params_format(params)) { 294 case SNDRV_PCM_FORMAT_S8: 295 sample_size = 0; 296 break; 297 case SNDRV_PCM_FORMAT_S16: 298 sample_size = 1; 299 break; 300 default: 301 return -EINVAL; 302 } 303 304 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 305 ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK; 306 ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET; 307 if (params_channels(params) == 1) 308 ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO; 309 else 310 ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO; 311 312 div_reg &= ~I2SDIV_DV_MASK; 313 div_reg |= (div - 1) << I2SDIV_DV_SHIFT; 314 } else { 315 ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK; 316 ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; 317 318 if (i2s->soc_info->version >= JZ_I2S_JZ4770) { 319 div_reg &= ~I2SDIV_IDV_MASK; 320 div_reg |= (div - 1) << I2SDIV_IDV_SHIFT; 321 } else { 322 div_reg &= ~I2SDIV_DV_MASK; 323 div_reg |= (div - 1) << I2SDIV_DV_SHIFT; 324 } 325 } 326 327 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); 328 jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg); 329 330 return 0; 331} 332 333static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, 334 unsigned int freq, int dir) 335{ 336 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 337 struct clk *parent; 338 int ret = 0; 339 340 switch (clk_id) { 341 case JZ4740_I2S_CLKSRC_EXT: 342 parent = clk_get(NULL, "ext"); 343 if (IS_ERR(parent)) 344 return PTR_ERR(parent); 345 clk_set_parent(i2s->clk_i2s, parent); 346 break; 347 case JZ4740_I2S_CLKSRC_PLL: 348 parent = clk_get(NULL, "pll half"); 349 if (IS_ERR(parent)) 350 return PTR_ERR(parent); 351 clk_set_parent(i2s->clk_i2s, parent); 352 ret = clk_set_rate(i2s->clk_i2s, freq); 353 break; 354 default: 355 return -EINVAL; 356 } 357 clk_put(parent); 358 359 return ret; 360} 361 362static int jz4740_i2s_suspend(struct snd_soc_component *component) 363{ 364 struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component); 365 uint32_t conf; 366 367 if (snd_soc_component_active(component)) { 368 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 369 conf &= ~JZ_AIC_CONF_ENABLE; 370 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 371 372 clk_disable_unprepare(i2s->clk_i2s); 373 } 374 375 clk_disable_unprepare(i2s->clk_aic); 376 377 return 0; 378} 379 380static int jz4740_i2s_resume(struct snd_soc_component *component) 381{ 382 struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component); 383 uint32_t conf; 384 int ret; 385 386 ret = clk_prepare_enable(i2s->clk_aic); 387 if (ret) 388 return ret; 389 390 if (snd_soc_component_active(component)) { 391 ret = clk_prepare_enable(i2s->clk_i2s); 392 if (ret) { 393 clk_disable_unprepare(i2s->clk_aic); 394 return ret; 395 } 396 397 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 398 conf |= JZ_AIC_CONF_ENABLE; 399 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 400 } 401 402 return 0; 403} 404 405static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s) 406{ 407 struct snd_dmaengine_dai_dma_data *dma_data; 408 409 /* Playback */ 410 dma_data = &i2s->playback_dma_data; 411 dma_data->maxburst = 16; 412 dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT; 413 dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; 414 415 /* Capture */ 416 dma_data = &i2s->capture_dma_data; 417 dma_data->maxburst = 16; 418 dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE; 419 dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; 420} 421 422static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) 423{ 424 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 425 uint32_t conf; 426 int ret; 427 428 ret = clk_prepare_enable(i2s->clk_aic); 429 if (ret) 430 return ret; 431 432 jz4740_i2c_init_pcm_config(i2s); 433 snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, 434 &i2s->capture_dma_data); 435 436 if (i2s->soc_info->version >= JZ_I2S_JZ4760) { 437 conf = (7 << JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | 438 (8 << JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | 439 JZ_AIC_CONF_OVERFLOW_PLAY_LAST | 440 JZ_AIC_CONF_I2S | 441 JZ_AIC_CONF_INTERNAL_CODEC; 442 } else { 443 conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | 444 (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | 445 JZ_AIC_CONF_OVERFLOW_PLAY_LAST | 446 JZ_AIC_CONF_I2S | 447 JZ_AIC_CONF_INTERNAL_CODEC; 448 } 449 450 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET); 451 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 452 453 return 0; 454} 455 456static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai) 457{ 458 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 459 460 clk_disable_unprepare(i2s->clk_aic); 461 return 0; 462} 463 464static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { 465 .startup = jz4740_i2s_startup, 466 .shutdown = jz4740_i2s_shutdown, 467 .trigger = jz4740_i2s_trigger, 468 .hw_params = jz4740_i2s_hw_params, 469 .set_fmt = jz4740_i2s_set_fmt, 470 .set_sysclk = jz4740_i2s_set_sysclk, 471}; 472 473#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ 474 SNDRV_PCM_FMTBIT_S16_LE) 475 476static struct snd_soc_dai_driver jz4740_i2s_dai = { 477 .probe = jz4740_i2s_dai_probe, 478 .remove = jz4740_i2s_dai_remove, 479 .playback = { 480 .channels_min = 1, 481 .channels_max = 2, 482 .rates = SNDRV_PCM_RATE_8000_48000, 483 .formats = JZ4740_I2S_FMTS, 484 }, 485 .capture = { 486 .channels_min = 2, 487 .channels_max = 2, 488 .rates = SNDRV_PCM_RATE_8000_48000, 489 .formats = JZ4740_I2S_FMTS, 490 }, 491 .symmetric_rates = 1, 492 .ops = &jz4740_i2s_dai_ops, 493}; 494 495static const struct i2s_soc_info jz4740_i2s_soc_info = { 496 .version = JZ_I2S_JZ4740, 497 .dai = &jz4740_i2s_dai, 498 .shared_fifo_flush = true, 499}; 500 501static const struct i2s_soc_info jz4760_i2s_soc_info = { 502 .version = JZ_I2S_JZ4760, 503 .dai = &jz4740_i2s_dai, 504}; 505 506static struct snd_soc_dai_driver jz4770_i2s_dai = { 507 .probe = jz4740_i2s_dai_probe, 508 .remove = jz4740_i2s_dai_remove, 509 .playback = { 510 .channels_min = 1, 511 .channels_max = 2, 512 .rates = SNDRV_PCM_RATE_8000_48000, 513 .formats = JZ4740_I2S_FMTS, 514 }, 515 .capture = { 516 .channels_min = 2, 517 .channels_max = 2, 518 .rates = SNDRV_PCM_RATE_8000_48000, 519 .formats = JZ4740_I2S_FMTS, 520 }, 521 .ops = &jz4740_i2s_dai_ops, 522}; 523 524static const struct i2s_soc_info jz4770_i2s_soc_info = { 525 .version = JZ_I2S_JZ4770, 526 .dai = &jz4770_i2s_dai, 527}; 528 529static const struct i2s_soc_info jz4780_i2s_soc_info = { 530 .version = JZ_I2S_JZ4780, 531 .dai = &jz4770_i2s_dai, 532}; 533 534static const struct snd_soc_component_driver jz4740_i2s_component = { 535 .name = "jz4740-i2s", 536 .suspend = jz4740_i2s_suspend, 537 .resume = jz4740_i2s_resume, 538}; 539 540static const struct of_device_id jz4740_of_matches[] = { 541 { .compatible = "ingenic,jz4740-i2s", .data = &jz4740_i2s_soc_info }, 542 { .compatible = "ingenic,jz4760-i2s", .data = &jz4760_i2s_soc_info }, 543 { .compatible = "ingenic,jz4770-i2s", .data = &jz4770_i2s_soc_info }, 544 { .compatible = "ingenic,jz4780-i2s", .data = &jz4780_i2s_soc_info }, 545 { /* sentinel */ } 546}; 547MODULE_DEVICE_TABLE(of, jz4740_of_matches); 548 549static int jz4740_i2s_dev_probe(struct platform_device *pdev) 550{ 551 struct device *dev = &pdev->dev; 552 struct jz4740_i2s *i2s; 553 struct resource *mem; 554 int ret; 555 556 i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); 557 if (!i2s) 558 return -ENOMEM; 559 560 i2s->soc_info = device_get_match_data(dev); 561 562 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 563 i2s->base = devm_ioremap_resource(dev, mem); 564 if (IS_ERR(i2s->base)) 565 return PTR_ERR(i2s->base); 566 567 i2s->phys_base = mem->start; 568 569 i2s->clk_aic = devm_clk_get(dev, "aic"); 570 if (IS_ERR(i2s->clk_aic)) 571 return PTR_ERR(i2s->clk_aic); 572 573 i2s->clk_i2s = devm_clk_get(dev, "i2s"); 574 if (IS_ERR(i2s->clk_i2s)) 575 return PTR_ERR(i2s->clk_i2s); 576 577 platform_set_drvdata(pdev, i2s); 578 579 ret = devm_snd_soc_register_component(dev, &jz4740_i2s_component, 580 i2s->soc_info->dai, 1); 581 if (ret) 582 return ret; 583 584 return devm_snd_dmaengine_pcm_register(dev, NULL, 585 SND_DMAENGINE_PCM_FLAG_COMPAT); 586} 587 588static struct platform_driver jz4740_i2s_driver = { 589 .probe = jz4740_i2s_dev_probe, 590 .driver = { 591 .name = "jz4740-i2s", 592 .of_match_table = jz4740_of_matches, 593 }, 594}; 595 596module_platform_driver(jz4740_i2s_driver); 597 598MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>"); 599MODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver"); 600MODULE_LICENSE("GPL"); 601MODULE_ALIAS("platform:jz4740-i2s"); 602