linux/sound/soc/sunxi/sun4i-i2s.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Andrea Venturi
   3 * Andrea Venturi <be17068@iperbole.bo.it>
   4 *
   5 * Copyright (C) 2016 Maxime Ripard
   6 * Maxime Ripard <maxime.ripard@free-electrons.com>
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/dmaengine.h>
  16#include <linux/module.h>
  17#include <linux/platform_device.h>
  18#include <linux/pm_runtime.h>
  19#include <linux/regmap.h>
  20
  21#include <sound/dmaengine_pcm.h>
  22#include <sound/pcm_params.h>
  23#include <sound/soc.h>
  24#include <sound/soc-dai.h>
  25
  26#define SUN4I_I2S_CTRL_REG              0x00
  27#define SUN4I_I2S_CTRL_SDO_EN_MASK              GENMASK(11, 8)
  28#define SUN4I_I2S_CTRL_SDO_EN(sdo)                      BIT(8 + (sdo))
  29#define SUN4I_I2S_CTRL_MODE_MASK                BIT(5)
  30#define SUN4I_I2S_CTRL_MODE_SLAVE                       (1 << 5)
  31#define SUN4I_I2S_CTRL_MODE_MASTER                      (0 << 5)
  32#define SUN4I_I2S_CTRL_TX_EN                    BIT(2)
  33#define SUN4I_I2S_CTRL_RX_EN                    BIT(1)
  34#define SUN4I_I2S_CTRL_GL_EN                    BIT(0)
  35
  36#define SUN4I_I2S_FMT0_REG              0x04
  37#define SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK      BIT(7)
  38#define SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED          (1 << 7)
  39#define SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL            (0 << 7)
  40#define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK       BIT(6)
  41#define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED           (1 << 6)
  42#define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL             (0 << 6)
  43#define SUN4I_I2S_FMT0_SR_MASK                  GENMASK(5, 4)
  44#define SUN4I_I2S_FMT0_SR(sr)                           ((sr) << 4)
  45#define SUN4I_I2S_FMT0_WSS_MASK                 GENMASK(3, 2)
  46#define SUN4I_I2S_FMT0_WSS(wss)                         ((wss) << 2)
  47#define SUN4I_I2S_FMT0_FMT_MASK                 GENMASK(1, 0)
  48#define SUN4I_I2S_FMT0_FMT_RIGHT_J                      (2 << 0)
  49#define SUN4I_I2S_FMT0_FMT_LEFT_J                       (1 << 0)
  50#define SUN4I_I2S_FMT0_FMT_I2S                          (0 << 0)
  51
  52#define SUN4I_I2S_FMT1_REG              0x08
  53#define SUN4I_I2S_FIFO_TX_REG           0x0c
  54#define SUN4I_I2S_FIFO_RX_REG           0x10
  55
  56#define SUN4I_I2S_FIFO_CTRL_REG         0x14
  57#define SUN4I_I2S_FIFO_CTRL_FLUSH_TX            BIT(25)
  58#define SUN4I_I2S_FIFO_CTRL_FLUSH_RX            BIT(24)
  59#define SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK        BIT(2)
  60#define SUN4I_I2S_FIFO_CTRL_TX_MODE(mode)               ((mode) << 2)
  61#define SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK        GENMASK(1, 0)
  62#define SUN4I_I2S_FIFO_CTRL_RX_MODE(mode)               (mode)
  63
  64#define SUN4I_I2S_FIFO_STA_REG          0x18
  65
  66#define SUN4I_I2S_DMA_INT_CTRL_REG      0x1c
  67#define SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN        BIT(7)
  68#define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN        BIT(3)
  69
  70#define SUN4I_I2S_INT_STA_REG           0x20
  71
  72#define SUN4I_I2S_CLK_DIV_REG           0x24
  73#define SUN4I_I2S_CLK_DIV_MCLK_EN               BIT(7)
  74#define SUN4I_I2S_CLK_DIV_BCLK_MASK             GENMASK(6, 4)
  75#define SUN4I_I2S_CLK_DIV_BCLK(bclk)                    ((bclk) << 4)
  76#define SUN4I_I2S_CLK_DIV_MCLK_MASK             GENMASK(3, 0)
  77#define SUN4I_I2S_CLK_DIV_MCLK(mclk)                    ((mclk) << 0)
  78
  79#define SUN4I_I2S_RX_CNT_REG            0x28
  80#define SUN4I_I2S_TX_CNT_REG            0x2c
  81
  82#define SUN4I_I2S_TX_CHAN_SEL_REG       0x30
  83#define SUN4I_I2S_TX_CHAN_SEL(num_chan)         (((num_chan) - 1) << 0)
  84
  85#define SUN4I_I2S_TX_CHAN_MAP_REG       0x34
  86#define SUN4I_I2S_TX_CHAN_MAP(chan, sample)     ((sample) << (chan << 2))
  87
  88#define SUN4I_I2S_RX_CHAN_SEL_REG       0x38
  89#define SUN4I_I2S_RX_CHAN_MAP_REG       0x3c
  90
  91struct sun4i_i2s {
  92        struct clk      *bus_clk;
  93        struct clk      *mod_clk;
  94        struct regmap   *regmap;
  95
  96        struct snd_dmaengine_dai_dma_data       playback_dma_data;
  97};
  98
  99struct sun4i_i2s_clk_div {
 100        u8      div;
 101        u8      val;
 102};
 103
 104static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = {
 105        { .div = 2, .val = 0 },
 106        { .div = 4, .val = 1 },
 107        { .div = 6, .val = 2 },
 108        { .div = 8, .val = 3 },
 109        { .div = 12, .val = 4 },
 110        { .div = 16, .val = 5 },
 111};
 112
 113static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
 114        { .div = 1, .val = 0 },
 115        { .div = 2, .val = 1 },
 116        { .div = 4, .val = 2 },
 117        { .div = 6, .val = 3 },
 118        { .div = 8, .val = 4 },
 119        { .div = 12, .val = 5 },
 120        { .div = 16, .val = 6 },
 121        { .div = 24, .val = 7 },
 122};
 123
 124static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
 125                                  unsigned int oversample_rate,
 126                                  unsigned int word_size)
 127{
 128        int div = oversample_rate / word_size / 2;
 129        int i;
 130
 131        for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) {
 132                const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i];
 133
 134                if (bdiv->div == div)
 135                        return bdiv->val;
 136        }
 137
 138        return -EINVAL;
 139}
 140
 141static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
 142                                  unsigned int oversample_rate,
 143                                  unsigned int module_rate,
 144                                  unsigned int sampling_rate)
 145{
 146        int div = module_rate / sampling_rate / oversample_rate;
 147        int i;
 148
 149        for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) {
 150                const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i];
 151
 152                if (mdiv->div == div)
 153                        return mdiv->val;
 154        }
 155
 156        return -EINVAL;
 157}
 158
 159static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 };
 160
 161static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
 162                                  unsigned int rate,
 163                                  unsigned int word_size)
 164{
 165        unsigned int clk_rate;
 166        int bclk_div, mclk_div;
 167        int ret, i;
 168
 169        switch (rate) {
 170        case 176400:
 171        case 88200:
 172        case 44100:
 173        case 22050:
 174        case 11025:
 175                clk_rate = 22579200;
 176                break;
 177
 178        case 192000:
 179        case 128000:
 180        case 96000:
 181        case 64000:
 182        case 48000:
 183        case 32000:
 184        case 24000:
 185        case 16000:
 186        case 12000:
 187        case 8000:
 188                clk_rate = 24576000;
 189                break;
 190
 191        default:
 192                return -EINVAL;
 193        }
 194
 195        ret = clk_set_rate(i2s->mod_clk, clk_rate);
 196        if (ret)
 197                return ret;
 198
 199        /* Always favor the highest oversampling rate */
 200        for (i = (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >= 0; i--) {
 201                unsigned int oversample_rate = sun4i_i2s_oversample_rates[i];
 202
 203                bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
 204                                                  word_size);
 205                mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
 206                                                  clk_rate,
 207                                                  rate);
 208
 209                if ((bclk_div >= 0) && (mclk_div >= 0))
 210                        break;
 211        }
 212
 213        if ((bclk_div < 0) || (mclk_div < 0))
 214                return -EINVAL;
 215
 216        regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
 217                     SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
 218                     SUN4I_I2S_CLK_DIV_MCLK(mclk_div) |
 219                     SUN4I_I2S_CLK_DIV_MCLK_EN);
 220
 221        return 0;
 222}
 223
 224static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
 225                               struct snd_pcm_hw_params *params,
 226                               struct snd_soc_dai *dai)
 227{
 228        struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 229        int sr, wss;
 230        u32 width;
 231
 232        if (params_channels(params) != 2)
 233                return -EINVAL;
 234
 235        switch (params_physical_width(params)) {
 236        case 16:
 237                width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 238                break;
 239        default:
 240                return -EINVAL;
 241        }
 242        i2s->playback_dma_data.addr_width = width;
 243
 244        switch (params_width(params)) {
 245        case 16:
 246                sr = 0;
 247                wss = 0;
 248                break;
 249
 250        default:
 251                return -EINVAL;
 252        }
 253
 254        regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
 255                           SUN4I_I2S_FMT0_WSS_MASK | SUN4I_I2S_FMT0_SR_MASK,
 256                           SUN4I_I2S_FMT0_WSS(wss) | SUN4I_I2S_FMT0_SR(sr));
 257
 258        return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
 259                                      params_width(params));
 260}
 261
 262static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 263{
 264        struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 265        u32 val;
 266
 267        /* DAI Mode */
 268        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 269        case SND_SOC_DAIFMT_I2S:
 270                val = SUN4I_I2S_FMT0_FMT_I2S;
 271                break;
 272        case SND_SOC_DAIFMT_LEFT_J:
 273                val = SUN4I_I2S_FMT0_FMT_LEFT_J;
 274                break;
 275        case SND_SOC_DAIFMT_RIGHT_J:
 276                val = SUN4I_I2S_FMT0_FMT_RIGHT_J;
 277                break;
 278        default:
 279                return -EINVAL;
 280        }
 281
 282        regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
 283                           SUN4I_I2S_FMT0_FMT_MASK,
 284                           val);
 285
 286        /* DAI clock polarity */
 287        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 288        case SND_SOC_DAIFMT_IB_IF:
 289                /* Invert both clocks */
 290                val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
 291                        SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
 292                break;
 293        case SND_SOC_DAIFMT_IB_NF:
 294                /* Invert bit clock */
 295                val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
 296                        SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
 297                break;
 298        case SND_SOC_DAIFMT_NB_IF:
 299                /* Invert frame clock */
 300                val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED |
 301                        SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL;
 302                break;
 303        case SND_SOC_DAIFMT_NB_NF:
 304                /* Nothing to do for both normal cases */
 305                val = SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL |
 306                        SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
 307                break;
 308        default:
 309                return -EINVAL;
 310        }
 311
 312        regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
 313                           SUN4I_I2S_FMT0_BCLK_POLARITY_MASK |
 314                           SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK,
 315                           val);
 316
 317        /* DAI clock master masks */
 318        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 319        case SND_SOC_DAIFMT_CBS_CFS:
 320                /* BCLK and LRCLK master */
 321                val = SUN4I_I2S_CTRL_MODE_MASTER;
 322                break;
 323        case SND_SOC_DAIFMT_CBM_CFM:
 324                /* BCLK and LRCLK slave */
 325                val = SUN4I_I2S_CTRL_MODE_SLAVE;
 326                break;
 327        default:
 328                return -EINVAL;
 329        }
 330
 331        regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
 332                           SUN4I_I2S_CTRL_MODE_MASK,
 333                           val);
 334
 335        /* Set significant bits in our FIFOs */
 336        regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
 337                           SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
 338                           SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
 339                           SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
 340                           SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
 341        return 0;
 342}
 343
 344static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
 345{
 346        /* Flush TX FIFO */
 347        regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
 348                           SUN4I_I2S_FIFO_CTRL_FLUSH_TX,
 349                           SUN4I_I2S_FIFO_CTRL_FLUSH_TX);
 350
 351        /* Clear TX counter */
 352        regmap_write(i2s->regmap, SUN4I_I2S_TX_CNT_REG, 0);
 353
 354        /* Enable TX Block */
 355        regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
 356                           SUN4I_I2S_CTRL_TX_EN,
 357                           SUN4I_I2S_CTRL_TX_EN);
 358
 359        /* Enable TX DRQ */
 360        regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
 361                           SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN,
 362                           SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN);
 363}
 364
 365
 366static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s)
 367{
 368        /* Disable TX Block */
 369        regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
 370                           SUN4I_I2S_CTRL_TX_EN,
 371                           0);
 372
 373        /* Disable TX DRQ */
 374        regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
 375                           SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN,
 376                           0);
 377}
 378
 379static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 380                             struct snd_soc_dai *dai)
 381{
 382        struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 383
 384        switch (cmd) {
 385        case SNDRV_PCM_TRIGGER_START:
 386        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 387        case SNDRV_PCM_TRIGGER_RESUME:
 388                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 389                        sun4i_i2s_start_playback(i2s);
 390                else
 391                        return -EINVAL;
 392                break;
 393
 394        case SNDRV_PCM_TRIGGER_STOP:
 395        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 396        case SNDRV_PCM_TRIGGER_SUSPEND:
 397                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 398                        sun4i_i2s_stop_playback(i2s);
 399                else
 400                        return -EINVAL;
 401                break;
 402
 403        default:
 404                return -EINVAL;
 405        }
 406
 407        return 0;
 408}
 409
 410static int sun4i_i2s_startup(struct snd_pcm_substream *substream,
 411                             struct snd_soc_dai *dai)
 412{
 413        struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 414
 415        /* Enable the whole hardware block */
 416        regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG,
 417                     SUN4I_I2S_CTRL_GL_EN);
 418
 419        /* Enable the first output line */
 420        regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
 421                           SUN4I_I2S_CTRL_SDO_EN_MASK,
 422                           SUN4I_I2S_CTRL_SDO_EN(0));
 423
 424        /* Enable the first two channels */
 425        regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
 426                     SUN4I_I2S_TX_CHAN_SEL(2));
 427
 428        /* Map them to the two first samples coming in */
 429        regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG,
 430                     SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1));
 431
 432        return clk_prepare_enable(i2s->mod_clk);
 433}
 434
 435static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream,
 436                               struct snd_soc_dai *dai)
 437{
 438        struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 439
 440        clk_disable_unprepare(i2s->mod_clk);
 441
 442        /* Disable our output lines */
 443        regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
 444                           SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
 445
 446        /* Disable the whole hardware block */
 447        regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);
 448}
 449
 450static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
 451        .hw_params      = sun4i_i2s_hw_params,
 452        .set_fmt        = sun4i_i2s_set_fmt,
 453        .shutdown       = sun4i_i2s_shutdown,
 454        .startup        = sun4i_i2s_startup,
 455        .trigger        = sun4i_i2s_trigger,
 456};
 457
 458static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
 459{
 460        struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 461
 462        snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, NULL);
 463
 464        snd_soc_dai_set_drvdata(dai, i2s);
 465
 466        return 0;
 467}
 468
 469static struct snd_soc_dai_driver sun4i_i2s_dai = {
 470        .probe = sun4i_i2s_dai_probe,
 471        .playback = {
 472                .stream_name = "Playback",
 473                .channels_min = 2,
 474                .channels_max = 2,
 475                .rates = SNDRV_PCM_RATE_8000_192000,
 476                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 477        },
 478        .ops = &sun4i_i2s_dai_ops,
 479        .symmetric_rates = 1,
 480};
 481
 482static const struct snd_soc_component_driver sun4i_i2s_component = {
 483        .name   = "sun4i-dai",
 484};
 485
 486static bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg)
 487{
 488        switch (reg) {
 489        case SUN4I_I2S_FIFO_TX_REG:
 490                return false;
 491
 492        default:
 493                return true;
 494        }
 495}
 496
 497static bool sun4i_i2s_wr_reg(struct device *dev, unsigned int reg)
 498{
 499        switch (reg) {
 500        case SUN4I_I2S_FIFO_RX_REG:
 501        case SUN4I_I2S_FIFO_STA_REG:
 502                return false;
 503
 504        default:
 505                return true;
 506        }
 507}
 508
 509static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg)
 510{
 511        switch (reg) {
 512        case SUN4I_I2S_FIFO_RX_REG:
 513        case SUN4I_I2S_INT_STA_REG:
 514        case SUN4I_I2S_RX_CNT_REG:
 515        case SUN4I_I2S_TX_CNT_REG:
 516                return true;
 517
 518        default:
 519                return false;
 520        }
 521}
 522
 523static const struct reg_default sun4i_i2s_reg_defaults[] = {
 524        { SUN4I_I2S_CTRL_REG, 0x00000000 },
 525        { SUN4I_I2S_FMT0_REG, 0x0000000c },
 526        { SUN4I_I2S_FMT1_REG, 0x00004020 },
 527        { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
 528        { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
 529        { SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
 530        { SUN4I_I2S_TX_CHAN_SEL_REG, 0x00000001 },
 531        { SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210 },
 532        { SUN4I_I2S_RX_CHAN_SEL_REG, 0x00000001 },
 533        { SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 },
 534};
 535
 536static const struct regmap_config sun4i_i2s_regmap_config = {
 537        .reg_bits       = 32,
 538        .reg_stride     = 4,
 539        .val_bits       = 32,
 540        .max_register   = SUN4I_I2S_RX_CHAN_MAP_REG,
 541
 542        .cache_type     = REGCACHE_FLAT,
 543        .reg_defaults   = sun4i_i2s_reg_defaults,
 544        .num_reg_defaults       = ARRAY_SIZE(sun4i_i2s_reg_defaults),
 545        .writeable_reg  = sun4i_i2s_wr_reg,
 546        .readable_reg   = sun4i_i2s_rd_reg,
 547        .volatile_reg   = sun4i_i2s_volatile_reg,
 548};
 549
 550static int sun4i_i2s_runtime_resume(struct device *dev)
 551{
 552        struct sun4i_i2s *i2s = dev_get_drvdata(dev);
 553        int ret;
 554
 555        ret = clk_prepare_enable(i2s->bus_clk);
 556        if (ret) {
 557                dev_err(dev, "Failed to enable bus clock\n");
 558                return ret;
 559        }
 560
 561        regcache_cache_only(i2s->regmap, false);
 562        regcache_mark_dirty(i2s->regmap);
 563
 564        ret = regcache_sync(i2s->regmap);
 565        if (ret) {
 566                dev_err(dev, "Failed to sync regmap cache\n");
 567                goto err_disable_clk;
 568        }
 569
 570        return 0;
 571
 572err_disable_clk:
 573        clk_disable_unprepare(i2s->bus_clk);
 574        return ret;
 575}
 576
 577static int sun4i_i2s_runtime_suspend(struct device *dev)
 578{
 579        struct sun4i_i2s *i2s = dev_get_drvdata(dev);
 580
 581        regcache_cache_only(i2s->regmap, true);
 582
 583        clk_disable_unprepare(i2s->bus_clk);
 584
 585        return 0;
 586}
 587
 588static int sun4i_i2s_probe(struct platform_device *pdev)
 589{
 590        struct sun4i_i2s *i2s;
 591        struct resource *res;
 592        void __iomem *regs;
 593        int irq, ret;
 594
 595        i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
 596        if (!i2s)
 597                return -ENOMEM;
 598        platform_set_drvdata(pdev, i2s);
 599
 600        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 601        regs = devm_ioremap_resource(&pdev->dev, res);
 602        if (IS_ERR(regs))
 603                return PTR_ERR(regs);
 604
 605        irq = platform_get_irq(pdev, 0);
 606        if (irq < 0) {
 607                dev_err(&pdev->dev, "Can't retrieve our interrupt\n");
 608                return irq;
 609        }
 610
 611        i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");
 612        if (IS_ERR(i2s->bus_clk)) {
 613                dev_err(&pdev->dev, "Can't get our bus clock\n");
 614                return PTR_ERR(i2s->bus_clk);
 615        }
 616
 617        i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
 618                                            &sun4i_i2s_regmap_config);
 619        if (IS_ERR(i2s->regmap)) {
 620                dev_err(&pdev->dev, "Regmap initialisation failed\n");
 621                return PTR_ERR(i2s->regmap);
 622        }
 623
 624        i2s->mod_clk = devm_clk_get(&pdev->dev, "mod");
 625        if (IS_ERR(i2s->mod_clk)) {
 626                dev_err(&pdev->dev, "Can't get our mod clock\n");
 627                return PTR_ERR(i2s->mod_clk);
 628        }
 629        
 630        i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
 631        i2s->playback_dma_data.maxburst = 4;
 632
 633        pm_runtime_enable(&pdev->dev);
 634        if (!pm_runtime_enabled(&pdev->dev)) {
 635                ret = sun4i_i2s_runtime_resume(&pdev->dev);
 636                if (ret)
 637                        goto err_pm_disable;
 638        }
 639
 640        ret = devm_snd_soc_register_component(&pdev->dev,
 641                                              &sun4i_i2s_component,
 642                                              &sun4i_i2s_dai, 1);
 643        if (ret) {
 644                dev_err(&pdev->dev, "Could not register DAI\n");
 645                goto err_suspend;
 646        }
 647
 648        ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
 649        if (ret) {
 650                dev_err(&pdev->dev, "Could not register PCM\n");
 651                goto err_suspend;
 652        }
 653
 654        return 0;
 655
 656err_suspend:
 657        if (!pm_runtime_status_suspended(&pdev->dev))
 658                sun4i_i2s_runtime_suspend(&pdev->dev);
 659err_pm_disable:
 660        pm_runtime_disable(&pdev->dev);
 661
 662        return ret;
 663}
 664
 665static int sun4i_i2s_remove(struct platform_device *pdev)
 666{
 667        snd_dmaengine_pcm_unregister(&pdev->dev);
 668
 669        pm_runtime_disable(&pdev->dev);
 670        if (!pm_runtime_status_suspended(&pdev->dev))
 671                sun4i_i2s_runtime_suspend(&pdev->dev);
 672
 673        return 0;
 674}
 675
 676static const struct of_device_id sun4i_i2s_match[] = {
 677        { .compatible = "allwinner,sun4i-a10-i2s", },
 678        {}
 679};
 680MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
 681
 682static const struct dev_pm_ops sun4i_i2s_pm_ops = {
 683        .runtime_resume         = sun4i_i2s_runtime_resume,
 684        .runtime_suspend        = sun4i_i2s_runtime_suspend,
 685};
 686
 687static struct platform_driver sun4i_i2s_driver = {
 688        .probe  = sun4i_i2s_probe,
 689        .remove = sun4i_i2s_remove,
 690        .driver = {
 691                .name           = "sun4i-i2s",
 692                .of_match_table = sun4i_i2s_match,
 693                .pm             = &sun4i_i2s_pm_ops,
 694        },
 695};
 696module_platform_driver(sun4i_i2s_driver);
 697
 698MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
 699MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
 700MODULE_DESCRIPTION("Allwinner A10 I2S driver");
 701MODULE_LICENSE("GPL");
 702