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