linux/sound/soc/sunxi/sun4i-codec.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2014 Emilio López <emilio@elopez.com.ar>
   4 * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
   5 * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
   6 * Copyright 2015 Adam Sampson <ats@offog.org>
   7 * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
   8 *
   9 * Based on the Allwinner SDK driver, released under the GPL.
  10 */
  11
  12#include <linux/init.h>
  13#include <linux/kernel.h>
  14#include <linux/module.h>
  15#include <linux/platform_device.h>
  16#include <linux/delay.h>
  17#include <linux/slab.h>
  18#include <linux/of.h>
  19#include <linux/of_address.h>
  20#include <linux/of_device.h>
  21#include <linux/of_platform.h>
  22#include <linux/clk.h>
  23#include <linux/regmap.h>
  24#include <linux/reset.h>
  25#include <linux/gpio/consumer.h>
  26
  27#include <sound/core.h>
  28#include <sound/pcm.h>
  29#include <sound/pcm_params.h>
  30#include <sound/soc.h>
  31#include <sound/tlv.h>
  32#include <sound/initval.h>
  33#include <sound/dmaengine_pcm.h>
  34
  35/* Codec DAC digital controls and FIFO registers */
  36#define SUN4I_CODEC_DAC_DPC                     (0x00)
  37#define SUN4I_CODEC_DAC_DPC_EN_DA                       (31)
  38#define SUN4I_CODEC_DAC_DPC_DVOL                        (12)
  39#define SUN4I_CODEC_DAC_FIFOC                   (0x04)
  40#define SUN4I_CODEC_DAC_FIFOC_DAC_FS                    (29)
  41#define SUN4I_CODEC_DAC_FIFOC_FIR_VERSION               (28)
  42#define SUN4I_CODEC_DAC_FIFOC_SEND_LASAT                (26)
  43#define SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE              (24)
  44#define SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT               (21)
  45#define SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL             (8)
  46#define SUN4I_CODEC_DAC_FIFOC_MONO_EN                   (6)
  47#define SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS            (5)
  48#define SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN                (4)
  49#define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH                (0)
  50#define SUN4I_CODEC_DAC_FIFOS                   (0x08)
  51#define SUN4I_CODEC_DAC_TXDATA                  (0x0c)
  52
  53/* Codec DAC side analog signal controls */
  54#define SUN4I_CODEC_DAC_ACTL                    (0x10)
  55#define SUN4I_CODEC_DAC_ACTL_DACAENR                    (31)
  56#define SUN4I_CODEC_DAC_ACTL_DACAENL                    (30)
  57#define SUN4I_CODEC_DAC_ACTL_MIXEN                      (29)
  58#define SUN4I_CODEC_DAC_ACTL_LNG                        (26)
  59#define SUN4I_CODEC_DAC_ACTL_FMG                        (23)
  60#define SUN4I_CODEC_DAC_ACTL_MICG                       (20)
  61#define SUN4I_CODEC_DAC_ACTL_LLNS                       (19)
  62#define SUN4I_CODEC_DAC_ACTL_RLNS                       (18)
  63#define SUN4I_CODEC_DAC_ACTL_LFMS                       (17)
  64#define SUN4I_CODEC_DAC_ACTL_RFMS                       (16)
  65#define SUN4I_CODEC_DAC_ACTL_LDACLMIXS                  (15)
  66#define SUN4I_CODEC_DAC_ACTL_RDACRMIXS                  (14)
  67#define SUN4I_CODEC_DAC_ACTL_LDACRMIXS                  (13)
  68#define SUN4I_CODEC_DAC_ACTL_MIC1LS                     (12)
  69#define SUN4I_CODEC_DAC_ACTL_MIC1RS                     (11)
  70#define SUN4I_CODEC_DAC_ACTL_MIC2LS                     (10)
  71#define SUN4I_CODEC_DAC_ACTL_MIC2RS                     (9)
  72#define SUN4I_CODEC_DAC_ACTL_DACPAS                     (8)
  73#define SUN4I_CODEC_DAC_ACTL_MIXPAS                     (7)
  74#define SUN4I_CODEC_DAC_ACTL_PA_MUTE                    (6)
  75#define SUN4I_CODEC_DAC_ACTL_PA_VOL                     (0)
  76#define SUN4I_CODEC_DAC_TUNE                    (0x14)
  77#define SUN4I_CODEC_DAC_DEBUG                   (0x18)
  78
  79/* Codec ADC digital controls and FIFO registers */
  80#define SUN4I_CODEC_ADC_FIFOC                   (0x1c)
  81#define SUN4I_CODEC_ADC_FIFOC_ADC_FS                    (29)
  82#define SUN4I_CODEC_ADC_FIFOC_EN_AD                     (28)
  83#define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE              (24)
  84#define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL             (8)
  85#define SUN4I_CODEC_ADC_FIFOC_MONO_EN                   (7)
  86#define SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS            (6)
  87#define SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN                (4)
  88#define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH                (0)
  89#define SUN4I_CODEC_ADC_FIFOS                   (0x20)
  90#define SUN4I_CODEC_ADC_RXDATA                  (0x24)
  91
  92/* Codec ADC side analog signal controls */
  93#define SUN4I_CODEC_ADC_ACTL                    (0x28)
  94#define SUN4I_CODEC_ADC_ACTL_ADC_R_EN                   (31)
  95#define SUN4I_CODEC_ADC_ACTL_ADC_L_EN                   (30)
  96#define SUN4I_CODEC_ADC_ACTL_PREG1EN                    (29)
  97#define SUN4I_CODEC_ADC_ACTL_PREG2EN                    (28)
  98#define SUN4I_CODEC_ADC_ACTL_VMICEN                     (27)
  99#define SUN4I_CODEC_ADC_ACTL_PREG1                      (25)
 100#define SUN4I_CODEC_ADC_ACTL_PREG2                      (23)
 101#define SUN4I_CODEC_ADC_ACTL_VADCG                      (20)
 102#define SUN4I_CODEC_ADC_ACTL_ADCIS                      (17)
 103#define SUN4I_CODEC_ADC_ACTL_LNPREG                     (13)
 104#define SUN4I_CODEC_ADC_ACTL_PA_EN                      (4)
 105#define SUN4I_CODEC_ADC_ACTL_DDE                        (3)
 106#define SUN4I_CODEC_ADC_DEBUG                   (0x2c)
 107
 108/* FIFO counters */
 109#define SUN4I_CODEC_DAC_TXCNT                   (0x30)
 110#define SUN4I_CODEC_ADC_RXCNT                   (0x34)
 111
 112/* Calibration register (sun7i only) */
 113#define SUN7I_CODEC_AC_DAC_CAL                  (0x38)
 114
 115/* Microphone controls (sun7i only) */
 116#define SUN7I_CODEC_AC_MIC_PHONE_CAL            (0x3c)
 117
 118#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1              (29)
 119#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2              (26)
 120
 121/*
 122 * sun6i specific registers
 123 *
 124 * sun6i shares the same digital control and FIFO registers as sun4i,
 125 * but only the DAC digital controls are at the same offset. The others
 126 * have been moved around to accommodate extra analog controls.
 127 */
 128
 129/* Codec DAC digital controls and FIFO registers */
 130#define SUN6I_CODEC_ADC_FIFOC                   (0x10)
 131#define SUN6I_CODEC_ADC_FIFOC_EN_AD                     (28)
 132#define SUN6I_CODEC_ADC_FIFOS                   (0x14)
 133#define SUN6I_CODEC_ADC_RXDATA                  (0x18)
 134
 135/* Output mixer and gain controls */
 136#define SUN6I_CODEC_OM_DACA_CTRL                (0x20)
 137#define SUN6I_CODEC_OM_DACA_CTRL_DACAREN                (31)
 138#define SUN6I_CODEC_OM_DACA_CTRL_DACALEN                (30)
 139#define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN                 (29)
 140#define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN                 (28)
 141#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1              (23)
 142#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2              (22)
 143#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE             (21)
 144#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP            (20)
 145#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR           (19)
 146#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR              (18)
 147#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL              (17)
 148#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1              (16)
 149#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2              (15)
 150#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE             (14)
 151#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN            (13)
 152#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL           (12)
 153#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL              (11)
 154#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR              (10)
 155#define SUN6I_CODEC_OM_DACA_CTRL_RHPIS                  (9)
 156#define SUN6I_CODEC_OM_DACA_CTRL_LHPIS                  (8)
 157#define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE              (7)
 158#define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE              (6)
 159#define SUN6I_CODEC_OM_DACA_CTRL_HPVOL                  (0)
 160#define SUN6I_CODEC_OM_PA_CTRL                  (0x24)
 161#define SUN6I_CODEC_OM_PA_CTRL_HPPAEN                   (31)
 162#define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL                (29)
 163#define SUN6I_CODEC_OM_PA_CTRL_COMPTEN                  (28)
 164#define SUN6I_CODEC_OM_PA_CTRL_MIC1G                    (15)
 165#define SUN6I_CODEC_OM_PA_CTRL_MIC2G                    (12)
 166#define SUN6I_CODEC_OM_PA_CTRL_LINEING                  (9)
 167#define SUN6I_CODEC_OM_PA_CTRL_PHONEG                   (6)
 168#define SUN6I_CODEC_OM_PA_CTRL_PHONEPG                  (3)
 169#define SUN6I_CODEC_OM_PA_CTRL_PHONENG                  (0)
 170
 171/* Microphone, line out and phone out controls */
 172#define SUN6I_CODEC_MIC_CTRL                    (0x28)
 173#define SUN6I_CODEC_MIC_CTRL_HBIASEN                    (31)
 174#define SUN6I_CODEC_MIC_CTRL_MBIASEN                    (30)
 175#define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN                  (28)
 176#define SUN6I_CODEC_MIC_CTRL_MIC1BOOST                  (25)
 177#define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN                  (24)
 178#define SUN6I_CODEC_MIC_CTRL_MIC2BOOST                  (21)
 179#define SUN6I_CODEC_MIC_CTRL_MIC2SLT                    (20)
 180#define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN                 (19)
 181#define SUN6I_CODEC_MIC_CTRL_LINEOUTREN                 (18)
 182#define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC                (17)
 183#define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC                (16)
 184#define SUN6I_CODEC_MIC_CTRL_LINEOUTVC                  (11)
 185#define SUN6I_CODEC_MIC_CTRL_PHONEPREG                  (8)
 186
 187/* ADC mixer controls */
 188#define SUN6I_CODEC_ADC_ACTL                    (0x2c)
 189#define SUN6I_CODEC_ADC_ACTL_ADCREN                     (31)
 190#define SUN6I_CODEC_ADC_ACTL_ADCLEN                     (30)
 191#define SUN6I_CODEC_ADC_ACTL_ADCRG                      (27)
 192#define SUN6I_CODEC_ADC_ACTL_ADCLG                      (24)
 193#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1               (13)
 194#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2               (12)
 195#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE              (11)
 196#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP             (10)
 197#define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR            (9)
 198#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR              (8)
 199#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL              (7)
 200#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1               (6)
 201#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2               (5)
 202#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE              (4)
 203#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN             (3)
 204#define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL            (2)
 205#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL              (1)
 206#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR              (0)
 207
 208/* Analog performance tuning controls */
 209#define SUN6I_CODEC_ADDA_TUNE                   (0x30)
 210
 211/* Calibration controls */
 212#define SUN6I_CODEC_CALIBRATION                 (0x34)
 213
 214/* FIFO counters */
 215#define SUN6I_CODEC_DAC_TXCNT                   (0x40)
 216#define SUN6I_CODEC_ADC_RXCNT                   (0x44)
 217
 218/* headset jack detection and button support registers */
 219#define SUN6I_CODEC_HMIC_CTL                    (0x50)
 220#define SUN6I_CODEC_HMIC_DATA                   (0x54)
 221
 222/* TODO sun6i DAP (Digital Audio Processing) bits */
 223
 224/* FIFO counters moved on A23 */
 225#define SUN8I_A23_CODEC_DAC_TXCNT               (0x1c)
 226#define SUN8I_A23_CODEC_ADC_RXCNT               (0x20)
 227
 228/* TX FIFO moved on H3 */
 229#define SUN8I_H3_CODEC_DAC_TXDATA               (0x20)
 230#define SUN8I_H3_CODEC_DAC_DBG                  (0x48)
 231#define SUN8I_H3_CODEC_ADC_DBG                  (0x4c)
 232
 233/* TODO H3 DAP (Digital Audio Processing) bits */
 234
 235struct sun4i_codec {
 236        struct device   *dev;
 237        struct regmap   *regmap;
 238        struct clk      *clk_apb;
 239        struct clk      *clk_module;
 240        struct reset_control *rst;
 241        struct gpio_desc *gpio_pa;
 242
 243        /* ADC_FIFOC register is at different offset on different SoCs */
 244        struct regmap_field *reg_adc_fifoc;
 245
 246        struct snd_dmaengine_dai_dma_data       capture_dma_data;
 247        struct snd_dmaengine_dai_dma_data       playback_dma_data;
 248};
 249
 250static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
 251{
 252        /* Flush TX FIFO */
 253        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 254                           BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
 255                           BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
 256
 257        /* Enable DAC DRQ */
 258        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 259                           BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
 260                           BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
 261}
 262
 263static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
 264{
 265        /* Disable DAC DRQ */
 266        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 267                           BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
 268                           0);
 269}
 270
 271static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
 272{
 273        /* Enable ADC DRQ */
 274        regmap_field_update_bits(scodec->reg_adc_fifoc,
 275                                 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
 276                                 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
 277}
 278
 279static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
 280{
 281        /* Disable ADC DRQ */
 282        regmap_field_update_bits(scodec->reg_adc_fifoc,
 283                                 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
 284}
 285
 286static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
 287                               struct snd_soc_dai *dai)
 288{
 289        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 290        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
 291
 292        switch (cmd) {
 293        case SNDRV_PCM_TRIGGER_START:
 294        case SNDRV_PCM_TRIGGER_RESUME:
 295        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 296                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 297                        sun4i_codec_start_playback(scodec);
 298                else
 299                        sun4i_codec_start_capture(scodec);
 300                break;
 301
 302        case SNDRV_PCM_TRIGGER_STOP:
 303        case SNDRV_PCM_TRIGGER_SUSPEND:
 304        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 305                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 306                        sun4i_codec_stop_playback(scodec);
 307                else
 308                        sun4i_codec_stop_capture(scodec);
 309                break;
 310
 311        default:
 312                return -EINVAL;
 313        }
 314
 315        return 0;
 316}
 317
 318static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
 319                                       struct snd_soc_dai *dai)
 320{
 321        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 322        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
 323
 324
 325        /* Flush RX FIFO */
 326        regmap_field_update_bits(scodec->reg_adc_fifoc,
 327                                 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
 328                                 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
 329
 330
 331        /* Set RX FIFO trigger level */
 332        regmap_field_update_bits(scodec->reg_adc_fifoc,
 333                                 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
 334                                 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
 335
 336        /*
 337         * FIXME: Undocumented in the datasheet, but
 338         *        Allwinner's code mentions that it is
 339         *        related to microphone gain
 340         */
 341        if (of_device_is_compatible(scodec->dev->of_node,
 342                                    "allwinner,sun4i-a10-codec") ||
 343            of_device_is_compatible(scodec->dev->of_node,
 344                                    "allwinner,sun7i-a20-codec")) {
 345                regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
 346                                   0x3 << 25,
 347                                   0x1 << 25);
 348        }
 349
 350        if (of_device_is_compatible(scodec->dev->of_node,
 351                                    "allwinner,sun7i-a20-codec"))
 352                /* FIXME: Undocumented bits */
 353                regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE,
 354                                   0x3 << 8,
 355                                   0x1 << 8);
 356
 357        return 0;
 358}
 359
 360static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
 361                                        struct snd_soc_dai *dai)
 362{
 363        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 364        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
 365        u32 val;
 366
 367        /* Flush the TX FIFO */
 368        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 369                           BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
 370                           BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
 371
 372        /* Set TX FIFO Empty Trigger Level */
 373        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 374                           0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
 375                           0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
 376
 377        if (substream->runtime->rate > 32000)
 378                /* Use 64 bits FIR filter */
 379                val = 0;
 380        else
 381                /* Use 32 bits FIR filter */
 382                val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION);
 383
 384        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 385                           BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION),
 386                           val);
 387
 388        /* Send zeros when we have an underrun */
 389        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 390                           BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT),
 391                           0);
 392
 393        return 0;
 394};
 395
 396static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
 397                               struct snd_soc_dai *dai)
 398{
 399        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 400                return sun4i_codec_prepare_playback(substream, dai);
 401
 402        return sun4i_codec_prepare_capture(substream, dai);
 403}
 404
 405static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
 406{
 407        unsigned int rate = params_rate(params);
 408
 409        switch (rate) {
 410        case 176400:
 411        case 88200:
 412        case 44100:
 413        case 33075:
 414        case 22050:
 415        case 14700:
 416        case 11025:
 417        case 7350:
 418                return 22579200;
 419
 420        case 192000:
 421        case 96000:
 422        case 48000:
 423        case 32000:
 424        case 24000:
 425        case 16000:
 426        case 12000:
 427        case 8000:
 428                return 24576000;
 429
 430        default:
 431                return 0;
 432        }
 433}
 434
 435static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 436{
 437        unsigned int rate = params_rate(params);
 438
 439        switch (rate) {
 440        case 192000:
 441        case 176400:
 442                return 6;
 443
 444        case 96000:
 445        case 88200:
 446                return 7;
 447
 448        case 48000:
 449        case 44100:
 450                return 0;
 451
 452        case 32000:
 453        case 33075:
 454                return 1;
 455
 456        case 24000:
 457        case 22050:
 458                return 2;
 459
 460        case 16000:
 461        case 14700:
 462                return 3;
 463
 464        case 12000:
 465        case 11025:
 466                return 4;
 467
 468        case 8000:
 469        case 7350:
 470                return 5;
 471
 472        default:
 473                return -EINVAL;
 474        }
 475}
 476
 477static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
 478                                         struct snd_pcm_hw_params *params,
 479                                         unsigned int hwrate)
 480{
 481        /* Set ADC sample rate */
 482        regmap_field_update_bits(scodec->reg_adc_fifoc,
 483                                 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
 484                                 hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
 485
 486        /* Set the number of channels we want to use */
 487        if (params_channels(params) == 1)
 488                regmap_field_update_bits(scodec->reg_adc_fifoc,
 489                                         BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
 490                                         BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
 491        else
 492                regmap_field_update_bits(scodec->reg_adc_fifoc,
 493                                         BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
 494                                         0);
 495
 496        /* Set the number of sample bits to either 16 or 24 bits */
 497        if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
 498                regmap_field_update_bits(scodec->reg_adc_fifoc,
 499                                   BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
 500                                   BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
 501
 502                regmap_field_update_bits(scodec->reg_adc_fifoc,
 503                                   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
 504                                   0);
 505
 506                scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 507        } else {
 508                regmap_field_update_bits(scodec->reg_adc_fifoc,
 509                                   BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
 510                                   0);
 511
 512                /* Fill most significant bits with valid data MSB */
 513                regmap_field_update_bits(scodec->reg_adc_fifoc,
 514                                   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
 515                                   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
 516
 517                scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 518        }
 519
 520        return 0;
 521}
 522
 523static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec,
 524                                          struct snd_pcm_hw_params *params,
 525                                          unsigned int hwrate)
 526{
 527        u32 val;
 528
 529        /* Set DAC sample rate */
 530        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 531                           7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
 532                           hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
 533
 534        /* Set the number of channels we want to use */
 535        if (params_channels(params) == 1)
 536                val = BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN);
 537        else
 538                val = 0;
 539
 540        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 541                           BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN),
 542                           val);
 543
 544        /* Set the number of sample bits to either 16 or 24 bits */
 545        if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
 546                regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 547                                   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
 548                                   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
 549
 550                /* Set TX FIFO mode to padding the LSBs with 0 */
 551                regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 552                                   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
 553                                   0);
 554
 555                scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 556        } else {
 557                regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 558                                   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
 559                                   0);
 560
 561                /* Set TX FIFO mode to repeat the MSB */
 562                regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 563                                   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
 564                                   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
 565
 566                scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 567        }
 568
 569        return 0;
 570}
 571
 572static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
 573                                 struct snd_pcm_hw_params *params,
 574                                 struct snd_soc_dai *dai)
 575{
 576        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 577        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
 578        unsigned long clk_freq;
 579        int ret, hwrate;
 580
 581        clk_freq = sun4i_codec_get_mod_freq(params);
 582        if (!clk_freq)
 583                return -EINVAL;
 584
 585        ret = clk_set_rate(scodec->clk_module, clk_freq);
 586        if (ret)
 587                return ret;
 588
 589        hwrate = sun4i_codec_get_hw_rate(params);
 590        if (hwrate < 0)
 591                return hwrate;
 592
 593        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 594                return sun4i_codec_hw_params_playback(scodec, params,
 595                                                      hwrate);
 596
 597        return sun4i_codec_hw_params_capture(scodec, params,
 598                                             hwrate);
 599}
 600
 601
 602static unsigned int sun4i_codec_src_rates[] = {
 603        8000, 11025, 12000, 16000, 22050, 24000, 32000,
 604        44100, 48000, 96000, 192000
 605};
 606
 607
 608static struct snd_pcm_hw_constraint_list sun4i_codec_constraints = {
 609        .count  = ARRAY_SIZE(sun4i_codec_src_rates),
 610        .list   = sun4i_codec_src_rates,
 611};
 612
 613
 614static int sun4i_codec_startup(struct snd_pcm_substream *substream,
 615                               struct snd_soc_dai *dai)
 616{
 617        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 618        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
 619
 620        snd_pcm_hw_constraint_list(substream->runtime, 0,
 621                                SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints);
 622
 623        /*
 624         * Stop issuing DRQ when we have room for less than 16 samples
 625         * in our TX FIFO
 626         */
 627        regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 628                           3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT,
 629                           3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
 630
 631        return clk_prepare_enable(scodec->clk_module);
 632}
 633
 634static void sun4i_codec_shutdown(struct snd_pcm_substream *substream,
 635                                 struct snd_soc_dai *dai)
 636{
 637        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 638        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
 639
 640        clk_disable_unprepare(scodec->clk_module);
 641}
 642
 643static const struct snd_soc_dai_ops sun4i_codec_dai_ops = {
 644        .startup        = sun4i_codec_startup,
 645        .shutdown       = sun4i_codec_shutdown,
 646        .trigger        = sun4i_codec_trigger,
 647        .hw_params      = sun4i_codec_hw_params,
 648        .prepare        = sun4i_codec_prepare,
 649};
 650
 651static struct snd_soc_dai_driver sun4i_codec_dai = {
 652        .name   = "Codec",
 653        .ops    = &sun4i_codec_dai_ops,
 654        .playback = {
 655                .stream_name    = "Codec Playback",
 656                .channels_min   = 1,
 657                .channels_max   = 2,
 658                .rate_min       = 8000,
 659                .rate_max       = 192000,
 660                .rates          = SNDRV_PCM_RATE_CONTINUOUS,
 661                .formats        = SNDRV_PCM_FMTBIT_S16_LE |
 662                                  SNDRV_PCM_FMTBIT_S32_LE,
 663                .sig_bits       = 24,
 664        },
 665        .capture = {
 666                .stream_name    = "Codec Capture",
 667                .channels_min   = 1,
 668                .channels_max   = 2,
 669                .rate_min       = 8000,
 670                .rate_max       = 48000,
 671                .rates          = SNDRV_PCM_RATE_CONTINUOUS,
 672                .formats        = SNDRV_PCM_FMTBIT_S16_LE |
 673                                  SNDRV_PCM_FMTBIT_S32_LE,
 674                .sig_bits       = 24,
 675        },
 676};
 677
 678/*** sun4i Codec ***/
 679static const struct snd_kcontrol_new sun4i_codec_pa_mute =
 680        SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
 681                        SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
 682
 683static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
 684static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_loopback_gain_scale, -150, 150,
 685                            0);
 686static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_preamp_gain_scale, -1200, 300,
 687                            0);
 688static DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150,
 689                            0);
 690static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150,
 691                            0);
 692static DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale,
 693                            0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
 694                            1, 7, TLV_DB_SCALE_ITEM(3500, 300, 0));
 695static DECLARE_TLV_DB_RANGE(sun7i_codec_micin_preamp_gain_scale,
 696                            0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
 697                            1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0));
 698
 699static const struct snd_kcontrol_new sun4i_codec_controls[] = {
 700        SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
 701                       SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
 702                       sun4i_codec_pa_volume_scale),
 703        SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
 704                       SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
 705                       sun4i_codec_linein_loopback_gain_scale),
 706        SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
 707                       SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
 708                       sun4i_codec_linein_preamp_gain_scale),
 709        SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
 710                       SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
 711                       sun4i_codec_fmin_loopback_gain_scale),
 712        SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
 713                       SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
 714                       sun4i_codec_micin_loopback_gain_scale),
 715        SOC_SINGLE_TLV("Mic1 Boost Volume", SUN4I_CODEC_ADC_ACTL,
 716                       SUN4I_CODEC_ADC_ACTL_PREG1, 3, 0,
 717                       sun4i_codec_micin_preamp_gain_scale),
 718        SOC_SINGLE_TLV("Mic2 Boost Volume", SUN4I_CODEC_ADC_ACTL,
 719                       SUN4I_CODEC_ADC_ACTL_PREG2, 3, 0,
 720                       sun4i_codec_micin_preamp_gain_scale),
 721};
 722
 723static const struct snd_kcontrol_new sun7i_codec_controls[] = {
 724        SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
 725                       SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
 726                       sun4i_codec_pa_volume_scale),
 727        SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
 728                       SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
 729                       sun4i_codec_linein_loopback_gain_scale),
 730        SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
 731                       SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
 732                       sun4i_codec_linein_preamp_gain_scale),
 733        SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
 734                       SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
 735                       sun4i_codec_fmin_loopback_gain_scale),
 736        SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
 737                       SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
 738                       sun4i_codec_micin_loopback_gain_scale),
 739        SOC_SINGLE_TLV("Mic1 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
 740                       SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1, 7, 0,
 741                       sun7i_codec_micin_preamp_gain_scale),
 742        SOC_SINGLE_TLV("Mic2 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
 743                       SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2, 7, 0,
 744                       sun7i_codec_micin_preamp_gain_scale),
 745};
 746
 747static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = {
 748        SOC_DAPM_SINGLE("Left Mixer Left DAC Playback Switch",
 749                        SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS,
 750                        1, 0),
 751        SOC_DAPM_SINGLE("Right Mixer Right DAC Playback Switch",
 752                        SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_RDACRMIXS,
 753                        1, 0),
 754        SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch",
 755                        SUN4I_CODEC_DAC_ACTL,
 756                        SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0),
 757        SOC_DAPM_DOUBLE("Line Playback Switch", SUN4I_CODEC_DAC_ACTL,
 758                        SUN4I_CODEC_DAC_ACTL_LLNS,
 759                        SUN4I_CODEC_DAC_ACTL_RLNS, 1, 0),
 760        SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL,
 761                        SUN4I_CODEC_DAC_ACTL_LFMS,
 762                        SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0),
 763        SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL,
 764                        SUN4I_CODEC_DAC_ACTL_MIC1LS,
 765                        SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0),
 766        SOC_DAPM_DOUBLE("Mic2 Playback Switch", SUN4I_CODEC_DAC_ACTL,
 767                        SUN4I_CODEC_DAC_ACTL_MIC2LS,
 768                        SUN4I_CODEC_DAC_ACTL_MIC2RS, 1, 0),
 769};
 770
 771static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
 772        SOC_DAPM_SINGLE("DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
 773                        SUN4I_CODEC_DAC_ACTL_DACPAS, 1, 0),
 774        SOC_DAPM_SINGLE("Mixer Playback Switch", SUN4I_CODEC_DAC_ACTL,
 775                        SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
 776};
 777
 778static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = {
 779        /* Digital parts of the ADCs */
 780        SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC,
 781                            SUN4I_CODEC_ADC_FIFOC_EN_AD, 0,
 782                            NULL, 0),
 783
 784        /* Digital parts of the DACs */
 785        SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
 786                            SUN4I_CODEC_DAC_DPC_EN_DA, 0,
 787                            NULL, 0),
 788
 789        /* Analog parts of the ADCs */
 790        SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
 791                         SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0),
 792        SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
 793                         SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0),
 794
 795        /* Analog parts of the DACs */
 796        SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
 797                         SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
 798        SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
 799                         SUN4I_CODEC_DAC_ACTL_DACAENR, 0),
 800
 801        /* Mixers */
 802        SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
 803                           sun4i_codec_mixer_controls,
 804                           ARRAY_SIZE(sun4i_codec_mixer_controls)),
 805        SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
 806                           sun4i_codec_mixer_controls,
 807                           ARRAY_SIZE(sun4i_codec_mixer_controls)),
 808
 809        /* Global Mixer Enable */
 810        SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
 811                            SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
 812
 813        /* VMIC */
 814        SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL,
 815                            SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0),
 816
 817        /* Mic Pre-Amplifiers */
 818        SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
 819                         SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0),
 820        SND_SOC_DAPM_PGA("MIC2 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
 821                         SUN4I_CODEC_ADC_ACTL_PREG2EN, 0, NULL, 0),
 822
 823        /* Power Amplifier */
 824        SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL,
 825                           SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
 826                           sun4i_codec_pa_mixer_controls,
 827                           ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
 828        SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0,
 829                            &sun4i_codec_pa_mute),
 830
 831        SND_SOC_DAPM_INPUT("Line Right"),
 832        SND_SOC_DAPM_INPUT("Line Left"),
 833        SND_SOC_DAPM_INPUT("FM Right"),
 834        SND_SOC_DAPM_INPUT("FM Left"),
 835        SND_SOC_DAPM_INPUT("Mic1"),
 836        SND_SOC_DAPM_INPUT("Mic2"),
 837
 838        SND_SOC_DAPM_OUTPUT("HP Right"),
 839        SND_SOC_DAPM_OUTPUT("HP Left"),
 840};
 841
 842static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
 843        /* Left ADC / DAC Routes */
 844        { "Left ADC", NULL, "ADC" },
 845        { "Left DAC", NULL, "DAC" },
 846
 847        /* Right ADC / DAC Routes */
 848        { "Right ADC", NULL, "ADC" },
 849        { "Right DAC", NULL, "DAC" },
 850
 851        /* Right Mixer Routes */
 852        { "Right Mixer", NULL, "Mixer Enable" },
 853        { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" },
 854        { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" },
 855        { "Right Mixer", "Line Playback Switch", "Line Right" },
 856        { "Right Mixer", "FM Playback Switch", "FM Right" },
 857        { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
 858        { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
 859
 860        /* Left Mixer Routes */
 861        { "Left Mixer", NULL, "Mixer Enable" },
 862        { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" },
 863        { "Left Mixer", "Line Playback Switch", "Line Left" },
 864        { "Left Mixer", "FM Playback Switch", "FM Left" },
 865        { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
 866        { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
 867
 868        /* Power Amplifier Routes */
 869        { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" },
 870        { "Power Amplifier", "Mixer Playback Switch", "Right Mixer" },
 871        { "Power Amplifier", "DAC Playback Switch", "Left DAC" },
 872        { "Power Amplifier", "DAC Playback Switch", "Right DAC" },
 873
 874        /* Headphone Output Routes */
 875        { "Power Amplifier Mute", "Switch", "Power Amplifier" },
 876        { "HP Right", NULL, "Power Amplifier Mute" },
 877        { "HP Left", NULL, "Power Amplifier Mute" },
 878
 879        /* Mic1 Routes */
 880        { "Left ADC", NULL, "MIC1 Pre-Amplifier" },
 881        { "Right ADC", NULL, "MIC1 Pre-Amplifier" },
 882        { "MIC1 Pre-Amplifier", NULL, "Mic1"},
 883        { "Mic1", NULL, "VMIC" },
 884
 885        /* Mic2 Routes */
 886        { "Left ADC", NULL, "MIC2 Pre-Amplifier" },
 887        { "Right ADC", NULL, "MIC2 Pre-Amplifier" },
 888        { "MIC2 Pre-Amplifier", NULL, "Mic2"},
 889        { "Mic2", NULL, "VMIC" },
 890};
 891
 892static const struct snd_soc_component_driver sun4i_codec_codec = {
 893        .controls               = sun4i_codec_controls,
 894        .num_controls           = ARRAY_SIZE(sun4i_codec_controls),
 895        .dapm_widgets           = sun4i_codec_codec_dapm_widgets,
 896        .num_dapm_widgets       = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
 897        .dapm_routes            = sun4i_codec_codec_dapm_routes,
 898        .num_dapm_routes        = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
 899        .idle_bias_on           = 1,
 900        .use_pmdown_time        = 1,
 901        .endianness             = 1,
 902        .non_legacy_dai_naming  = 1,
 903};
 904
 905static const struct snd_soc_component_driver sun7i_codec_codec = {
 906        .controls               = sun7i_codec_controls,
 907        .num_controls           = ARRAY_SIZE(sun7i_codec_controls),
 908        .dapm_widgets           = sun4i_codec_codec_dapm_widgets,
 909        .num_dapm_widgets       = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
 910        .dapm_routes            = sun4i_codec_codec_dapm_routes,
 911        .num_dapm_routes        = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
 912        .idle_bias_on           = 1,
 913        .use_pmdown_time        = 1,
 914        .endianness             = 1,
 915        .non_legacy_dai_naming  = 1,
 916};
 917
 918/*** sun6i Codec ***/
 919
 920/* mixer controls */
 921static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
 922        SOC_DAPM_DOUBLE("DAC Playback Switch",
 923                        SUN6I_CODEC_OM_DACA_CTRL,
 924                        SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL,
 925                        SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0),
 926        SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
 927                        SUN6I_CODEC_OM_DACA_CTRL,
 928                        SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR,
 929                        SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0),
 930        SOC_DAPM_DOUBLE("Line In Playback Switch",
 931                        SUN6I_CODEC_OM_DACA_CTRL,
 932                        SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL,
 933                        SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0),
 934        SOC_DAPM_DOUBLE("Mic1 Playback Switch",
 935                        SUN6I_CODEC_OM_DACA_CTRL,
 936                        SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1,
 937                        SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0),
 938        SOC_DAPM_DOUBLE("Mic2 Playback Switch",
 939                        SUN6I_CODEC_OM_DACA_CTRL,
 940                        SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2,
 941                        SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0),
 942};
 943
 944/* ADC mixer controls */
 945static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = {
 946        SOC_DAPM_DOUBLE("Mixer Capture Switch",
 947                        SUN6I_CODEC_ADC_ACTL,
 948                        SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL,
 949                        SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0),
 950        SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch",
 951                        SUN6I_CODEC_ADC_ACTL,
 952                        SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR,
 953                        SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0),
 954        SOC_DAPM_DOUBLE("Line In Capture Switch",
 955                        SUN6I_CODEC_ADC_ACTL,
 956                        SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL,
 957                        SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0),
 958        SOC_DAPM_DOUBLE("Mic1 Capture Switch",
 959                        SUN6I_CODEC_ADC_ACTL,
 960                        SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1,
 961                        SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0),
 962        SOC_DAPM_DOUBLE("Mic2 Capture Switch",
 963                        SUN6I_CODEC_ADC_ACTL,
 964                        SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2,
 965                        SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0),
 966};
 967
 968/* headphone controls */
 969static const char * const sun6i_codec_hp_src_enum_text[] = {
 970        "DAC", "Mixer",
 971};
 972
 973static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
 974                            SUN6I_CODEC_OM_DACA_CTRL,
 975                            SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
 976                            SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
 977                            sun6i_codec_hp_src_enum_text);
 978
 979static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
 980        SOC_DAPM_ENUM("Headphone Source Playback Route",
 981                      sun6i_codec_hp_src_enum),
 982};
 983
 984/* microphone controls */
 985static const char * const sun6i_codec_mic2_src_enum_text[] = {
 986        "Mic2", "Mic3",
 987};
 988
 989static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum,
 990                            SUN6I_CODEC_MIC_CTRL,
 991                            SUN6I_CODEC_MIC_CTRL_MIC2SLT,
 992                            sun6i_codec_mic2_src_enum_text);
 993
 994static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = {
 995        SOC_DAPM_ENUM("Mic2 Amplifier Source Route",
 996                      sun6i_codec_mic2_src_enum),
 997};
 998
 999/* line out controls */
1000static const char * const sun6i_codec_lineout_src_enum_text[] = {
1001        "Stereo", "Mono Differential",
1002};
1003
1004static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum,
1005                            SUN6I_CODEC_MIC_CTRL,
1006                            SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC,
1007                            SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC,
1008                            sun6i_codec_lineout_src_enum_text);
1009
1010static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = {
1011        SOC_DAPM_ENUM("Line Out Source Playback Route",
1012                      sun6i_codec_lineout_src_enum),
1013};
1014
1015/* volume / mute controls */
1016static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
1017static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
1018static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale,
1019                                  -450, 150, 0);
1020static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale,
1021        0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
1022        2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
1023);
1024static const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale,
1025        0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1026        1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
1027);
1028
1029static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
1030        SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
1031                       SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
1032                       sun6i_codec_dvol_scale),
1033        SOC_SINGLE_TLV("Headphone Playback Volume",
1034                       SUN6I_CODEC_OM_DACA_CTRL,
1035                       SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
1036                       sun6i_codec_hp_vol_scale),
1037        SOC_SINGLE_TLV("Line Out Playback Volume",
1038                       SUN6I_CODEC_MIC_CTRL,
1039                       SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0,
1040                       sun6i_codec_lineout_vol_scale),
1041        SOC_DOUBLE("Headphone Playback Switch",
1042                   SUN6I_CODEC_OM_DACA_CTRL,
1043                   SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
1044                   SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
1045        SOC_DOUBLE("Line Out Playback Switch",
1046                   SUN6I_CODEC_MIC_CTRL,
1047                   SUN6I_CODEC_MIC_CTRL_LINEOUTLEN,
1048                   SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0),
1049        /* Mixer pre-gains */
1050        SOC_SINGLE_TLV("Line In Playback Volume",
1051                       SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
1052                       0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1053        SOC_SINGLE_TLV("Mic1 Playback Volume",
1054                       SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G,
1055                       0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1056        SOC_SINGLE_TLV("Mic2 Playback Volume",
1057                       SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G,
1058                       0x7, 0, sun6i_codec_out_mixer_pregain_scale),
1059
1060        /* Microphone Amp boost gains */
1061        SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL,
1062                       SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0,
1063                       sun6i_codec_mic_gain_scale),
1064        SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL,
1065                       SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0,
1066                       sun6i_codec_mic_gain_scale),
1067        SOC_DOUBLE_TLV("ADC Capture Volume",
1068                       SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG,
1069                       SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0,
1070                       sun6i_codec_out_mixer_pregain_scale),
1071};
1072
1073static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
1074        /* Microphone inputs */
1075        SND_SOC_DAPM_INPUT("MIC1"),
1076        SND_SOC_DAPM_INPUT("MIC2"),
1077        SND_SOC_DAPM_INPUT("MIC3"),
1078
1079        /* Microphone Bias */
1080        SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL,
1081                            SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0),
1082        SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL,
1083                            SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0),
1084
1085        /* Mic input path */
1086        SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route",
1087                         SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src),
1088        SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL,
1089                         SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0),
1090        SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL,
1091                         SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0),
1092
1093        /* Line In */
1094        SND_SOC_DAPM_INPUT("LINEIN"),
1095
1096        /* Digital parts of the ADCs */
1097        SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
1098                            SUN6I_CODEC_ADC_FIFOC_EN_AD, 0,
1099                            NULL, 0),
1100
1101        /* Analog parts of the ADCs */
1102        SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
1103                         SUN6I_CODEC_ADC_ACTL_ADCLEN, 0),
1104        SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
1105                         SUN6I_CODEC_ADC_ACTL_ADCREN, 0),
1106
1107        /* ADC Mixers */
1108        SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
1109                        sun6i_codec_adc_mixer_controls),
1110        SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
1111                        sun6i_codec_adc_mixer_controls),
1112
1113        /* Digital parts of the DACs */
1114        SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
1115                            SUN4I_CODEC_DAC_DPC_EN_DA, 0,
1116                            NULL, 0),
1117
1118        /* Analog parts of the DACs */
1119        SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
1120                         SUN6I_CODEC_OM_DACA_CTRL,
1121                         SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0),
1122        SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
1123                         SUN6I_CODEC_OM_DACA_CTRL,
1124                         SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0),
1125
1126        /* Mixers */
1127        SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL,
1128                        SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0,
1129                        sun6i_codec_mixer_controls),
1130        SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL,
1131                        SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0,
1132                        sun6i_codec_mixer_controls),
1133
1134        /* Headphone output path */
1135        SND_SOC_DAPM_MUX("Headphone Source Playback Route",
1136                         SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),
1137        SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL,
1138                             SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0),
1139        SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL,
1140                            SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0),
1141        SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
1142                         SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
1143        SND_SOC_DAPM_OUTPUT("HP"),
1144
1145        /* Line Out path */
1146        SND_SOC_DAPM_MUX("Line Out Source Playback Route",
1147                         SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src),
1148        SND_SOC_DAPM_OUTPUT("LINEOUT"),
1149};
1150
1151static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
1152        /* DAC Routes */
1153        { "Left DAC", NULL, "DAC Enable" },
1154        { "Right DAC", NULL, "DAC Enable" },
1155
1156        /* Microphone Routes */
1157        { "Mic1 Amplifier", NULL, "MIC1"},
1158        { "Mic2 Amplifier Source Route", "Mic2", "MIC2" },
1159        { "Mic2 Amplifier Source Route", "Mic3", "MIC3" },
1160        { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"},
1161
1162        /* Left Mixer Routes */
1163        { "Left Mixer", "DAC Playback Switch", "Left DAC" },
1164        { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
1165        { "Left Mixer", "Line In Playback Switch", "LINEIN" },
1166        { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1167        { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1168
1169        /* Right Mixer Routes */
1170        { "Right Mixer", "DAC Playback Switch", "Right DAC" },
1171        { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
1172        { "Right Mixer", "Line In Playback Switch", "LINEIN" },
1173        { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1174        { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1175
1176        /* Left ADC Mixer Routes */
1177        { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
1178        { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
1179        { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
1180        { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1181        { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1182
1183        /* Right ADC Mixer Routes */
1184        { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
1185        { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
1186        { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
1187        { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1188        { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1189
1190        /* Headphone Routes */
1191        { "Headphone Source Playback Route", "DAC", "Left DAC" },
1192        { "Headphone Source Playback Route", "DAC", "Right DAC" },
1193        { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
1194        { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
1195        { "Headphone Amp", NULL, "Headphone Source Playback Route" },
1196        { "HP", NULL, "Headphone Amp" },
1197        { "HPCOM", NULL, "HPCOM Protection" },
1198
1199        /* Line Out Routes */
1200        { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
1201        { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
1202        { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
1203        { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
1204        { "LINEOUT", NULL, "Line Out Source Playback Route" },
1205
1206        /* ADC Routes */
1207        { "Left ADC", NULL, "ADC Enable" },
1208        { "Right ADC", NULL, "ADC Enable" },
1209        { "Left ADC", NULL, "Left ADC Mixer" },
1210        { "Right ADC", NULL, "Right ADC Mixer" },
1211};
1212
1213static const struct snd_soc_component_driver sun6i_codec_codec = {
1214        .controls               = sun6i_codec_codec_widgets,
1215        .num_controls           = ARRAY_SIZE(sun6i_codec_codec_widgets),
1216        .dapm_widgets           = sun6i_codec_codec_dapm_widgets,
1217        .num_dapm_widgets       = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
1218        .dapm_routes            = sun6i_codec_codec_dapm_routes,
1219        .num_dapm_routes        = ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
1220        .idle_bias_on           = 1,
1221        .use_pmdown_time        = 1,
1222        .endianness             = 1,
1223        .non_legacy_dai_naming  = 1,
1224};
1225
1226/* sun8i A23 codec */
1227static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = {
1228        SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
1229                       SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
1230                       sun6i_codec_dvol_scale),
1231};
1232
1233static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
1234        /* Digital parts of the ADCs */
1235        SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
1236                            SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0),
1237        /* Digital parts of the DACs */
1238        SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
1239                            SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0),
1240
1241};
1242
1243static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
1244        .controls               = sun8i_a23_codec_codec_controls,
1245        .num_controls           = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
1246        .dapm_widgets           = sun8i_a23_codec_codec_widgets,
1247        .num_dapm_widgets       = ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
1248        .idle_bias_on           = 1,
1249        .use_pmdown_time        = 1,
1250        .endianness             = 1,
1251        .non_legacy_dai_naming  = 1,
1252};
1253
1254static const struct snd_soc_component_driver sun4i_codec_component = {
1255        .name = "sun4i-codec",
1256};
1257
1258#define SUN4I_CODEC_RATES       SNDRV_PCM_RATE_CONTINUOUS
1259#define SUN4I_CODEC_FORMATS     (SNDRV_PCM_FMTBIT_S16_LE | \
1260                                 SNDRV_PCM_FMTBIT_S32_LE)
1261
1262static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
1263{
1264        struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
1265        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
1266
1267        snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
1268                                  &scodec->capture_dma_data);
1269
1270        return 0;
1271}
1272
1273static struct snd_soc_dai_driver dummy_cpu_dai = {
1274        .name   = "sun4i-codec-cpu-dai",
1275        .probe  = sun4i_codec_dai_probe,
1276        .playback = {
1277                .stream_name    = "Playback",
1278                .channels_min   = 1,
1279                .channels_max   = 2,
1280                .rates          = SUN4I_CODEC_RATES,
1281                .formats        = SUN4I_CODEC_FORMATS,
1282                .sig_bits       = 24,
1283        },
1284        .capture = {
1285                .stream_name    = "Capture",
1286                .channels_min   = 1,
1287                .channels_max   = 2,
1288                .rates          = SUN4I_CODEC_RATES,
1289                .formats        = SUN4I_CODEC_FORMATS,
1290                .sig_bits       = 24,
1291         },
1292};
1293
1294static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
1295                                                        int *num_links)
1296{
1297        struct snd_soc_dai_link *link = devm_kzalloc(dev, sizeof(*link),
1298                                                     GFP_KERNEL);
1299        struct snd_soc_dai_link_component *dlc = devm_kzalloc(dev,
1300                                                3 * sizeof(*dlc), GFP_KERNEL);
1301        if (!link || !dlc)
1302                return NULL;
1303
1304        link->cpus      = &dlc[0];
1305        link->codecs    = &dlc[1];
1306        link->platforms = &dlc[2];
1307
1308        link->num_cpus          = 1;
1309        link->num_codecs        = 1;
1310        link->num_platforms     = 1;
1311
1312        link->name              = "cdc";
1313        link->stream_name       = "CDC PCM";
1314        link->codecs->dai_name  = "Codec";
1315        link->cpus->dai_name    = dev_name(dev);
1316        link->codecs->name      = dev_name(dev);
1317        link->platforms->name   = dev_name(dev);
1318        link->dai_fmt           = SND_SOC_DAIFMT_I2S;
1319
1320        *num_links = 1;
1321
1322        return link;
1323};
1324
1325static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
1326                                 struct snd_kcontrol *k, int event)
1327{
1328        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
1329
1330        gpiod_set_value_cansleep(scodec->gpio_pa,
1331                                 !!SND_SOC_DAPM_EVENT_ON(event));
1332
1333        if (SND_SOC_DAPM_EVENT_ON(event)) {
1334                /*
1335                 * Need a delay to wait for DAC to push the data. 700ms seems
1336                 * to be the best compromise not to feel this delay while
1337                 * playing a sound.
1338                 */
1339                msleep(700);
1340        }
1341
1342        return 0;
1343}
1344
1345static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = {
1346        SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
1347};
1348
1349static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = {
1350        { "Speaker", NULL, "HP Right" },
1351        { "Speaker", NULL, "HP Left" },
1352};
1353
1354static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
1355{
1356        struct snd_soc_card *card;
1357
1358        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1359        if (!card)
1360                return ERR_PTR(-ENOMEM);
1361
1362        card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1363        if (!card->dai_link)
1364                return ERR_PTR(-ENOMEM);
1365
1366        card->dev               = dev;
1367        card->name              = "sun4i-codec";
1368        card->dapm_widgets      = sun4i_codec_card_dapm_widgets;
1369        card->num_dapm_widgets  = ARRAY_SIZE(sun4i_codec_card_dapm_widgets);
1370        card->dapm_routes       = sun4i_codec_card_dapm_routes;
1371        card->num_dapm_routes   = ARRAY_SIZE(sun4i_codec_card_dapm_routes);
1372
1373        return card;
1374};
1375
1376static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = {
1377        SND_SOC_DAPM_HP("Headphone", NULL),
1378        SND_SOC_DAPM_LINE("Line In", NULL),
1379        SND_SOC_DAPM_LINE("Line Out", NULL),
1380        SND_SOC_DAPM_MIC("Headset Mic", NULL),
1381        SND_SOC_DAPM_MIC("Mic", NULL),
1382        SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
1383};
1384
1385static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
1386{
1387        struct snd_soc_card *card;
1388        int ret;
1389
1390        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1391        if (!card)
1392                return ERR_PTR(-ENOMEM);
1393
1394        card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1395        if (!card->dai_link)
1396                return ERR_PTR(-ENOMEM);
1397
1398        card->dev               = dev;
1399        card->name              = "A31 Audio Codec";
1400        card->dapm_widgets      = sun6i_codec_card_dapm_widgets;
1401        card->num_dapm_widgets  = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1402        card->fully_routed      = true;
1403
1404        ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1405        if (ret)
1406                dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1407
1408        return card;
1409};
1410
1411/* Connect digital side enables to analog side widgets */
1412static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = {
1413        /* ADC Routes */
1414        { "Left ADC", NULL, "ADC Enable" },
1415        { "Right ADC", NULL, "ADC Enable" },
1416        { "Codec Capture", NULL, "Left ADC" },
1417        { "Codec Capture", NULL, "Right ADC" },
1418
1419        /* DAC Routes */
1420        { "Left DAC", NULL, "DAC Enable" },
1421        { "Right DAC", NULL, "DAC Enable" },
1422        { "Left DAC", NULL, "Codec Playback" },
1423        { "Right DAC", NULL, "Codec Playback" },
1424};
1425
1426static struct snd_soc_aux_dev aux_dev = {
1427        .dlc = COMP_EMPTY(),
1428};
1429
1430static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev)
1431{
1432        struct snd_soc_card *card;
1433        int ret;
1434
1435        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1436        if (!card)
1437                return ERR_PTR(-ENOMEM);
1438
1439        aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1440                                                 "allwinner,codec-analog-controls",
1441                                                 0);
1442        if (!aux_dev.dlc.of_node) {
1443                dev_err(dev, "Can't find analog controls for codec.\n");
1444                return ERR_PTR(-EINVAL);
1445        }
1446
1447        card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1448        if (!card->dai_link)
1449                return ERR_PTR(-ENOMEM);
1450
1451        card->dev               = dev;
1452        card->name              = "A23 Audio Codec";
1453        card->dapm_widgets      = sun6i_codec_card_dapm_widgets;
1454        card->num_dapm_widgets  = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1455        card->dapm_routes       = sun8i_codec_card_routes;
1456        card->num_dapm_routes   = ARRAY_SIZE(sun8i_codec_card_routes);
1457        card->aux_dev           = &aux_dev;
1458        card->num_aux_devs      = 1;
1459        card->fully_routed      = true;
1460
1461        ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1462        if (ret)
1463                dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1464
1465        return card;
1466};
1467
1468static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev)
1469{
1470        struct snd_soc_card *card;
1471        int ret;
1472
1473        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1474        if (!card)
1475                return ERR_PTR(-ENOMEM);
1476
1477        aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1478                                                 "allwinner,codec-analog-controls",
1479                                                 0);
1480        if (!aux_dev.dlc.of_node) {
1481                dev_err(dev, "Can't find analog controls for codec.\n");
1482                return ERR_PTR(-EINVAL);
1483        }
1484
1485        card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1486        if (!card->dai_link)
1487                return ERR_PTR(-ENOMEM);
1488
1489        card->dev               = dev;
1490        card->name              = "H3 Audio Codec";
1491        card->dapm_widgets      = sun6i_codec_card_dapm_widgets;
1492        card->num_dapm_widgets  = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1493        card->dapm_routes       = sun8i_codec_card_routes;
1494        card->num_dapm_routes   = ARRAY_SIZE(sun8i_codec_card_routes);
1495        card->aux_dev           = &aux_dev;
1496        card->num_aux_devs      = 1;
1497        card->fully_routed      = true;
1498
1499        ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1500        if (ret)
1501                dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1502
1503        return card;
1504};
1505
1506static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev)
1507{
1508        struct snd_soc_card *card;
1509        int ret;
1510
1511        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1512        if (!card)
1513                return ERR_PTR(-ENOMEM);
1514
1515        aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
1516                                                 "allwinner,codec-analog-controls",
1517                                                 0);
1518        if (!aux_dev.dlc.of_node) {
1519                dev_err(dev, "Can't find analog controls for codec.\n");
1520                return ERR_PTR(-EINVAL);
1521        }
1522
1523        card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1524        if (!card->dai_link)
1525                return ERR_PTR(-ENOMEM);
1526
1527        card->dev               = dev;
1528        card->name              = "V3s Audio Codec";
1529        card->dapm_widgets      = sun6i_codec_card_dapm_widgets;
1530        card->num_dapm_widgets  = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1531        card->dapm_routes       = sun8i_codec_card_routes;
1532        card->num_dapm_routes   = ARRAY_SIZE(sun8i_codec_card_routes);
1533        card->aux_dev           = &aux_dev;
1534        card->num_aux_devs      = 1;
1535        card->fully_routed      = true;
1536
1537        ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1538        if (ret)
1539                dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1540
1541        return card;
1542};
1543
1544static const struct regmap_config sun4i_codec_regmap_config = {
1545        .reg_bits       = 32,
1546        .reg_stride     = 4,
1547        .val_bits       = 32,
1548        .max_register   = SUN4I_CODEC_ADC_RXCNT,
1549};
1550
1551static const struct regmap_config sun6i_codec_regmap_config = {
1552        .reg_bits       = 32,
1553        .reg_stride     = 4,
1554        .val_bits       = 32,
1555        .max_register   = SUN6I_CODEC_HMIC_DATA,
1556};
1557
1558static const struct regmap_config sun7i_codec_regmap_config = {
1559        .reg_bits       = 32,
1560        .reg_stride     = 4,
1561        .val_bits       = 32,
1562        .max_register   = SUN7I_CODEC_AC_MIC_PHONE_CAL,
1563};
1564
1565static const struct regmap_config sun8i_a23_codec_regmap_config = {
1566        .reg_bits       = 32,
1567        .reg_stride     = 4,
1568        .val_bits       = 32,
1569        .max_register   = SUN8I_A23_CODEC_ADC_RXCNT,
1570};
1571
1572static const struct regmap_config sun8i_h3_codec_regmap_config = {
1573        .reg_bits       = 32,
1574        .reg_stride     = 4,
1575        .val_bits       = 32,
1576        .max_register   = SUN8I_H3_CODEC_ADC_DBG,
1577};
1578
1579static const struct regmap_config sun8i_v3s_codec_regmap_config = {
1580        .reg_bits       = 32,
1581        .reg_stride     = 4,
1582        .val_bits       = 32,
1583        .max_register   = SUN8I_H3_CODEC_ADC_DBG,
1584};
1585
1586struct sun4i_codec_quirks {
1587        const struct regmap_config *regmap_config;
1588        const struct snd_soc_component_driver *codec;
1589        struct snd_soc_card * (*create_card)(struct device *dev);
1590        struct reg_field reg_adc_fifoc; /* used for regmap_field */
1591        unsigned int reg_dac_txdata;    /* TX FIFO offset for DMA config */
1592        unsigned int reg_adc_rxdata;    /* RX FIFO offset for DMA config */
1593        bool has_reset;
1594};
1595
1596static const struct sun4i_codec_quirks sun4i_codec_quirks = {
1597        .regmap_config  = &sun4i_codec_regmap_config,
1598        .codec          = &sun4i_codec_codec,
1599        .create_card    = sun4i_codec_create_card,
1600        .reg_adc_fifoc  = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1601        .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1602        .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1603};
1604
1605static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
1606        .regmap_config  = &sun6i_codec_regmap_config,
1607        .codec          = &sun6i_codec_codec,
1608        .create_card    = sun6i_codec_create_card,
1609        .reg_adc_fifoc  = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1610        .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1611        .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1612        .has_reset      = true,
1613};
1614
1615static const struct sun4i_codec_quirks sun7i_codec_quirks = {
1616        .regmap_config  = &sun7i_codec_regmap_config,
1617        .codec          = &sun7i_codec_codec,
1618        .create_card    = sun4i_codec_create_card,
1619        .reg_adc_fifoc  = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1620        .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1621        .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1622};
1623
1624static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
1625        .regmap_config  = &sun8i_a23_codec_regmap_config,
1626        .codec          = &sun8i_a23_codec_codec,
1627        .create_card    = sun8i_a23_codec_create_card,
1628        .reg_adc_fifoc  = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1629        .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1630        .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1631        .has_reset      = true,
1632};
1633
1634static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
1635        .regmap_config  = &sun8i_h3_codec_regmap_config,
1636        /*
1637         * TODO Share the codec structure with A23 for now.
1638         * This should be split out when adding digital audio
1639         * processing support for the H3.
1640         */
1641        .codec          = &sun8i_a23_codec_codec,
1642        .create_card    = sun8i_h3_codec_create_card,
1643        .reg_adc_fifoc  = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1644        .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
1645        .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1646        .has_reset      = true,
1647};
1648
1649static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
1650        .regmap_config  = &sun8i_v3s_codec_regmap_config,
1651        /*
1652         * TODO The codec structure should be split out, like
1653         * H3, when adding digital audio processing support.
1654         */
1655        .codec          = &sun8i_a23_codec_codec,
1656        .create_card    = sun8i_v3s_codec_create_card,
1657        .reg_adc_fifoc  = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1658        .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
1659        .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1660        .has_reset      = true,
1661};
1662
1663static const struct of_device_id sun4i_codec_of_match[] = {
1664        {
1665                .compatible = "allwinner,sun4i-a10-codec",
1666                .data = &sun4i_codec_quirks,
1667        },
1668        {
1669                .compatible = "allwinner,sun6i-a31-codec",
1670                .data = &sun6i_a31_codec_quirks,
1671        },
1672        {
1673                .compatible = "allwinner,sun7i-a20-codec",
1674                .data = &sun7i_codec_quirks,
1675        },
1676        {
1677                .compatible = "allwinner,sun8i-a23-codec",
1678                .data = &sun8i_a23_codec_quirks,
1679        },
1680        {
1681                .compatible = "allwinner,sun8i-h3-codec",
1682                .data = &sun8i_h3_codec_quirks,
1683        },
1684        {
1685                .compatible = "allwinner,sun8i-v3s-codec",
1686                .data = &sun8i_v3s_codec_quirks,
1687        },
1688        {}
1689};
1690MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
1691
1692static int sun4i_codec_probe(struct platform_device *pdev)
1693{
1694        struct snd_soc_card *card;
1695        struct sun4i_codec *scodec;
1696        const struct sun4i_codec_quirks *quirks;
1697        struct resource *res;
1698        void __iomem *base;
1699        int ret;
1700
1701        scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
1702        if (!scodec)
1703                return -ENOMEM;
1704
1705        scodec->dev = &pdev->dev;
1706
1707        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1708        base = devm_ioremap_resource(&pdev->dev, res);
1709        if (IS_ERR(base)) {
1710                dev_err(&pdev->dev, "Failed to map the registers\n");
1711                return PTR_ERR(base);
1712        }
1713
1714        quirks = of_device_get_match_data(&pdev->dev);
1715        if (quirks == NULL) {
1716                dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
1717                return -ENODEV;
1718        }
1719
1720        scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
1721                                               quirks->regmap_config);
1722        if (IS_ERR(scodec->regmap)) {
1723                dev_err(&pdev->dev, "Failed to create our regmap\n");
1724                return PTR_ERR(scodec->regmap);
1725        }
1726
1727        /* Get the clocks from the DT */
1728        scodec->clk_apb = devm_clk_get(&pdev->dev, "apb");
1729        if (IS_ERR(scodec->clk_apb)) {
1730                dev_err(&pdev->dev, "Failed to get the APB clock\n");
1731                return PTR_ERR(scodec->clk_apb);
1732        }
1733
1734        scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
1735        if (IS_ERR(scodec->clk_module)) {
1736                dev_err(&pdev->dev, "Failed to get the module clock\n");
1737                return PTR_ERR(scodec->clk_module);
1738        }
1739
1740        if (quirks->has_reset) {
1741                scodec->rst = devm_reset_control_get_exclusive(&pdev->dev,
1742                                                               NULL);
1743                if (IS_ERR(scodec->rst)) {
1744                        dev_err(&pdev->dev, "Failed to get reset control\n");
1745                        return PTR_ERR(scodec->rst);
1746                }
1747        }
1748
1749        scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
1750                                                  GPIOD_OUT_LOW);
1751        if (IS_ERR(scodec->gpio_pa)) {
1752                ret = PTR_ERR(scodec->gpio_pa);
1753                if (ret != -EPROBE_DEFER)
1754                        dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret);
1755                return ret;
1756        }
1757
1758        /* reg_field setup */
1759        scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
1760                                                        scodec->regmap,
1761                                                        quirks->reg_adc_fifoc);
1762        if (IS_ERR(scodec->reg_adc_fifoc)) {
1763                ret = PTR_ERR(scodec->reg_adc_fifoc);
1764                dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
1765                        ret);
1766                return ret;
1767        }
1768
1769        /* Enable the bus clock */
1770        if (clk_prepare_enable(scodec->clk_apb)) {
1771                dev_err(&pdev->dev, "Failed to enable the APB clock\n");
1772                return -EINVAL;
1773        }
1774
1775        /* Deassert the reset control */
1776        if (scodec->rst) {
1777                ret = reset_control_deassert(scodec->rst);
1778                if (ret) {
1779                        dev_err(&pdev->dev,
1780                                "Failed to deassert the reset control\n");
1781                        goto err_clk_disable;
1782                }
1783        }
1784
1785        /* DMA configuration for TX FIFO */
1786        scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
1787        scodec->playback_dma_data.maxburst = 8;
1788        scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
1789
1790        /* DMA configuration for RX FIFO */
1791        scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
1792        scodec->capture_dma_data.maxburst = 8;
1793        scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
1794
1795        ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
1796                                     &sun4i_codec_dai, 1);
1797        if (ret) {
1798                dev_err(&pdev->dev, "Failed to register our codec\n");
1799                goto err_assert_reset;
1800        }
1801
1802        ret = devm_snd_soc_register_component(&pdev->dev,
1803                                              &sun4i_codec_component,
1804                                              &dummy_cpu_dai, 1);
1805        if (ret) {
1806                dev_err(&pdev->dev, "Failed to register our DAI\n");
1807                goto err_assert_reset;
1808        }
1809
1810        ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
1811        if (ret) {
1812                dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
1813                goto err_assert_reset;
1814        }
1815
1816        card = quirks->create_card(&pdev->dev);
1817        if (IS_ERR(card)) {
1818                ret = PTR_ERR(card);
1819                dev_err(&pdev->dev, "Failed to create our card\n");
1820                goto err_assert_reset;
1821        }
1822
1823        snd_soc_card_set_drvdata(card, scodec);
1824
1825        ret = snd_soc_register_card(card);
1826        if (ret) {
1827                dev_err(&pdev->dev, "Failed to register our card\n");
1828                goto err_assert_reset;
1829        }
1830
1831        return 0;
1832
1833err_assert_reset:
1834        if (scodec->rst)
1835                reset_control_assert(scodec->rst);
1836err_clk_disable:
1837        clk_disable_unprepare(scodec->clk_apb);
1838        return ret;
1839}
1840
1841static int sun4i_codec_remove(struct platform_device *pdev)
1842{
1843        struct snd_soc_card *card = platform_get_drvdata(pdev);
1844        struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
1845
1846        snd_soc_unregister_card(card);
1847        if (scodec->rst)
1848                reset_control_assert(scodec->rst);
1849        clk_disable_unprepare(scodec->clk_apb);
1850
1851        return 0;
1852}
1853
1854static struct platform_driver sun4i_codec_driver = {
1855        .driver = {
1856                .name = "sun4i-codec",
1857                .of_match_table = sun4i_codec_of_match,
1858        },
1859        .probe = sun4i_codec_probe,
1860        .remove = sun4i_codec_remove,
1861};
1862module_platform_driver(sun4i_codec_driver);
1863
1864MODULE_DESCRIPTION("Allwinner A10 codec driver");
1865MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
1866MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
1867MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1868MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
1869MODULE_LICENSE("GPL");
1870