linux/sound/soc/sunxi/sun8i-codec.c
<<
>>
Prefs
   1/*
   2 * This driver supports the digital controls for the internal codec
   3 * found in Allwinner's A33 SoCs.
   4 *
   5 * (C) Copyright 2010-2016
   6 * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
   7 * huangxin <huangxin@Reuuimllatech.com>
   8 * Mylène Josserand <mylene.josserand@free-electrons.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or
  13 * (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 */
  20
  21#include <linux/module.h>
  22#include <linux/delay.h>
  23#include <linux/clk.h>
  24#include <linux/io.h>
  25#include <linux/pm_runtime.h>
  26#include <linux/regmap.h>
  27
  28#include <sound/pcm_params.h>
  29#include <sound/soc.h>
  30#include <sound/soc-dapm.h>
  31
  32#define SUN8I_SYSCLK_CTL                                0x00c
  33#define SUN8I_SYSCLK_CTL_AIF1CLK_ENA                    11
  34#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL                9
  35#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC                    8
  36#define SUN8I_SYSCLK_CTL_SYSCLK_ENA                     3
  37#define SUN8I_SYSCLK_CTL_SYSCLK_SRC                     0
  38#define SUN8I_MOD_CLK_ENA                               0x010
  39#define SUN8I_MOD_CLK_ENA_AIF1                          15
  40#define SUN8I_MOD_CLK_ENA_DAC                           2
  41#define SUN8I_MOD_RST_CTL                               0x014
  42#define SUN8I_MOD_RST_CTL_AIF1                          15
  43#define SUN8I_MOD_RST_CTL_DAC                           2
  44#define SUN8I_SYS_SR_CTRL                               0x018
  45#define SUN8I_SYS_SR_CTRL_AIF1_FS                       12
  46#define SUN8I_SYS_SR_CTRL_AIF2_FS                       8
  47#define SUN8I_AIF1CLK_CTRL                              0x040
  48#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD                15
  49#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV                14
  50#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV                13
  51#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV                9
  52#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV                6
  53#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16             (1 << 6)
  54#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ                4
  55#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16             (1 << 4)
  56#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT                2
  57#define SUN8I_AIF1_DACDAT_CTRL                          0x048
  58#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA            15
  59#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA            14
  60#define SUN8I_DAC_DIG_CTRL                              0x120
  61#define SUN8I_DAC_DIG_CTRL_ENDA                 15
  62#define SUN8I_DAC_MXR_SRC                               0x130
  63#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
  64#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
  65#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
  66#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL             12
  67#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
  68#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
  69#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
  70#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR             8
  71
  72#define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK          GENMASK(15, 12)
  73#define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK          GENMASK(11, 8)
  74#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK   GENMASK(5, 4)
  75#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK   GENMASK(8, 6)
  76#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK   GENMASK(12, 9)
  77
  78struct sun8i_codec {
  79        struct device   *dev;
  80        struct regmap   *regmap;
  81        struct clk      *clk_module;
  82        struct clk      *clk_bus;
  83};
  84
  85static int sun8i_codec_runtime_resume(struct device *dev)
  86{
  87        struct sun8i_codec *scodec = dev_get_drvdata(dev);
  88        int ret;
  89
  90        ret = clk_prepare_enable(scodec->clk_module);
  91        if (ret) {
  92                dev_err(dev, "Failed to enable the module clock\n");
  93                return ret;
  94        }
  95
  96        ret = clk_prepare_enable(scodec->clk_bus);
  97        if (ret) {
  98                dev_err(dev, "Failed to enable the bus clock\n");
  99                goto err_disable_modclk;
 100        }
 101
 102        regcache_cache_only(scodec->regmap, false);
 103
 104        ret = regcache_sync(scodec->regmap);
 105        if (ret) {
 106                dev_err(dev, "Failed to sync regmap cache\n");
 107                goto err_disable_clk;
 108        }
 109
 110        return 0;
 111
 112err_disable_clk:
 113        clk_disable_unprepare(scodec->clk_bus);
 114
 115err_disable_modclk:
 116        clk_disable_unprepare(scodec->clk_module);
 117
 118        return ret;
 119}
 120
 121static int sun8i_codec_runtime_suspend(struct device *dev)
 122{
 123        struct sun8i_codec *scodec = dev_get_drvdata(dev);
 124
 125        regcache_cache_only(scodec->regmap, true);
 126        regcache_mark_dirty(scodec->regmap);
 127
 128        clk_disable_unprepare(scodec->clk_module);
 129        clk_disable_unprepare(scodec->clk_bus);
 130
 131        return 0;
 132}
 133
 134static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 135{
 136        unsigned int rate = params_rate(params);
 137
 138        switch (rate) {
 139        case 8000:
 140        case 7350:
 141                return 0x0;
 142        case 11025:
 143                return 0x1;
 144        case 12000:
 145                return 0x2;
 146        case 16000:
 147                return 0x3;
 148        case 22050:
 149                return 0x4;
 150        case 24000:
 151                return 0x5;
 152        case 32000:
 153                return 0x6;
 154        case 44100:
 155                return 0x7;
 156        case 48000:
 157                return 0x8;
 158        case 96000:
 159                return 0x9;
 160        case 192000:
 161                return 0xa;
 162        default:
 163                return -EINVAL;
 164        }
 165}
 166
 167static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 168{
 169        struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
 170        u32 value;
 171
 172        /* clock masters */
 173        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 174        case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
 175                value = 0x1;
 176                break;
 177        case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
 178                value = 0x0;
 179                break;
 180        default:
 181                return -EINVAL;
 182        }
 183        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 184                           BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
 185                           value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
 186
 187        /* clock inversion */
 188        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 189        case SND_SOC_DAIFMT_NB_NF: /* Normal */
 190                value = 0x0;
 191                break;
 192        case SND_SOC_DAIFMT_IB_IF: /* Inversion */
 193                value = 0x1;
 194                break;
 195        default:
 196                return -EINVAL;
 197        }
 198        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 199                           BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
 200                           value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
 201
 202        /*
 203         * It appears that the DAI and the codec don't share the same
 204         * polarity for the LRCK signal when they mean 'normal' and
 205         * 'inverted' in the datasheet.
 206         *
 207         * Since the DAI here is our regular i2s driver that have been
 208         * tested with way more codecs than just this one, it means
 209         * that the codec probably gets it backward, and we have to
 210         * invert the value here.
 211         */
 212        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 213                           BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV),
 214                           !value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
 215
 216        /* DAI format */
 217        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 218        case SND_SOC_DAIFMT_I2S:
 219                value = 0x0;
 220                break;
 221        case SND_SOC_DAIFMT_LEFT_J:
 222                value = 0x1;
 223                break;
 224        case SND_SOC_DAIFMT_RIGHT_J:
 225                value = 0x2;
 226                break;
 227        case SND_SOC_DAIFMT_DSP_A:
 228        case SND_SOC_DAIFMT_DSP_B:
 229                value = 0x3;
 230                break;
 231        default:
 232                return -EINVAL;
 233        }
 234        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 235                           BIT(SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT),
 236                           value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
 237
 238        return 0;
 239}
 240
 241struct sun8i_codec_clk_div {
 242        u8      div;
 243        u8      val;
 244};
 245
 246static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
 247        { .div = 1,     .val = 0 },
 248        { .div = 2,     .val = 1 },
 249        { .div = 4,     .val = 2 },
 250        { .div = 6,     .val = 3 },
 251        { .div = 8,     .val = 4 },
 252        { .div = 12,    .val = 5 },
 253        { .div = 16,    .val = 6 },
 254        { .div = 24,    .val = 7 },
 255        { .div = 32,    .val = 8 },
 256        { .div = 48,    .val = 9 },
 257        { .div = 64,    .val = 10 },
 258        { .div = 96,    .val = 11 },
 259        { .div = 128,   .val = 12 },
 260        { .div = 192,   .val = 13 },
 261};
 262
 263static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
 264                                   unsigned int rate,
 265                                   unsigned int word_size)
 266{
 267        unsigned long clk_rate = clk_get_rate(scodec->clk_module);
 268        unsigned int div = clk_rate / rate / word_size / 2;
 269        unsigned int best_val = 0, best_diff = ~0;
 270        int i;
 271
 272        for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
 273                const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
 274                unsigned int diff = abs(bdiv->div - div);
 275
 276                if (diff < best_diff) {
 277                        best_diff = diff;
 278                        best_val = bdiv->val;
 279                }
 280        }
 281
 282        return best_val;
 283}
 284
 285static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 286                                 struct snd_pcm_hw_params *params,
 287                                 struct snd_soc_dai *dai)
 288{
 289        struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
 290        int sample_rate;
 291        u8 bclk_div;
 292
 293        /*
 294         * The CPU DAI handles only a sample of 16 bits. Configure the
 295         * codec to handle this type of sample resolution.
 296         */
 297        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 298                           SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
 299                           SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
 300
 301        bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
 302        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 303                           SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
 304                           bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
 305
 306        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
 307                           SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
 308                           SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
 309
 310        sample_rate = sun8i_codec_get_hw_rate(params);
 311        if (sample_rate < 0)
 312                return sample_rate;
 313
 314        regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
 315                           SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
 316                           sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
 317        regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
 318                           SUN8I_SYS_SR_CTRL_AIF2_FS_MASK,
 319                           sample_rate << SUN8I_SYS_SR_CTRL_AIF2_FS);
 320
 321        return 0;
 322}
 323
 324static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
 325        SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
 326                        SUN8I_DAC_MXR_SRC,
 327                        SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
 328                        SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
 329        SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
 330                        SUN8I_DAC_MXR_SRC,
 331                        SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
 332                        SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0),
 333        SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
 334                        SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
 335                        SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
 336        SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
 337                        SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
 338                        SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
 339};
 340
 341static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
 342        /* Digital parts of the DACs */
 343        SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA,
 344                            0, NULL, 0),
 345
 346        /* Analog DAC AIF */
 347        SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left", "Playback", 0,
 348                            SUN8I_AIF1_DACDAT_CTRL,
 349                            SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
 350        SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right", "Playback", 0,
 351                            SUN8I_AIF1_DACDAT_CTRL,
 352                            SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
 353
 354        /* DAC Mixers */
 355        SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
 356                        sun8i_dac_mixer_controls),
 357        SOC_MIXER_ARRAY("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
 358                        sun8i_dac_mixer_controls),
 359
 360        /* Clocks */
 361        SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA,
 362                            SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
 363        SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA,
 364                            SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
 365        SND_SOC_DAPM_SUPPLY("AIF1", SUN8I_SYSCLK_CTL,
 366                            SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
 367        SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL,
 368                            SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
 369
 370        SND_SOC_DAPM_SUPPLY("AIF1 PLL", SUN8I_SYSCLK_CTL,
 371                            SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL, 0, NULL, 0),
 372        /* Inversion as 0=AIF1, 1=AIF2 */
 373        SND_SOC_DAPM_SUPPLY("SYSCLK AIF1", SUN8I_SYSCLK_CTL,
 374                            SUN8I_SYSCLK_CTL_SYSCLK_SRC, 1, NULL, 0),
 375
 376        /* Module reset */
 377        SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL,
 378                            SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
 379        SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL,
 380                            SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
 381};
 382
 383static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
 384        /* Clock Routes */
 385        { "AIF1", NULL, "SYSCLK AIF1" },
 386        { "AIF1 PLL", NULL, "AIF1" },
 387        { "RST AIF1", NULL, "AIF1 PLL" },
 388        { "MODCLK AFI1", NULL, "RST AIF1" },
 389        { "DAC", NULL, "MODCLK AFI1" },
 390
 391        { "RST DAC", NULL, "SYSCLK" },
 392        { "MODCLK DAC", NULL, "RST DAC" },
 393        { "DAC", NULL, "MODCLK DAC" },
 394
 395        /* DAC Routes */
 396        { "AIF1 Slot 0 Right", NULL, "DAC" },
 397        { "AIF1 Slot 0 Left", NULL, "DAC" },
 398
 399        /* DAC Mixer Routes */
 400        { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
 401          "AIF1 Slot 0 Left"},
 402        { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
 403          "AIF1 Slot 0 Right"},
 404};
 405
 406static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
 407        .hw_params = sun8i_codec_hw_params,
 408        .set_fmt = sun8i_set_fmt,
 409};
 410
 411static struct snd_soc_dai_driver sun8i_codec_dai = {
 412        .name = "sun8i",
 413        /* playback capabilities */
 414        .playback = {
 415                .stream_name = "Playback",
 416                .channels_min = 1,
 417                .channels_max = 2,
 418                .rates = SNDRV_PCM_RATE_8000_192000,
 419                .formats = SNDRV_PCM_FMTBIT_S16_LE,
 420        },
 421        /* pcm operations */
 422        .ops = &sun8i_codec_dai_ops,
 423};
 424
 425static const struct snd_soc_codec_driver sun8i_soc_codec = {
 426        .component_driver = {
 427                .dapm_widgets           = sun8i_codec_dapm_widgets,
 428                .num_dapm_widgets       = ARRAY_SIZE(sun8i_codec_dapm_widgets),
 429                .dapm_routes            = sun8i_codec_dapm_routes,
 430                .num_dapm_routes        = ARRAY_SIZE(sun8i_codec_dapm_routes),
 431        },
 432};
 433
 434static const struct regmap_config sun8i_codec_regmap_config = {
 435        .reg_bits       = 32,
 436        .reg_stride     = 4,
 437        .val_bits       = 32,
 438        .max_register   = SUN8I_DAC_MXR_SRC,
 439
 440        .cache_type     = REGCACHE_FLAT,
 441};
 442
 443static int sun8i_codec_probe(struct platform_device *pdev)
 444{
 445        struct resource *res_base;
 446        struct sun8i_codec *scodec;
 447        void __iomem *base;
 448        int ret;
 449
 450        scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
 451        if (!scodec)
 452                return -ENOMEM;
 453
 454        scodec->dev = &pdev->dev;
 455
 456        scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
 457        if (IS_ERR(scodec->clk_module)) {
 458                dev_err(&pdev->dev, "Failed to get the module clock\n");
 459                return PTR_ERR(scodec->clk_module);
 460        }
 461
 462        scodec->clk_bus = devm_clk_get(&pdev->dev, "bus");
 463        if (IS_ERR(scodec->clk_bus)) {
 464                dev_err(&pdev->dev, "Failed to get the bus clock\n");
 465                return PTR_ERR(scodec->clk_bus);
 466        }
 467
 468        res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 469        base = devm_ioremap_resource(&pdev->dev, res_base);
 470        if (IS_ERR(base)) {
 471                dev_err(&pdev->dev, "Failed to map the registers\n");
 472                return PTR_ERR(base);
 473        }
 474
 475        scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
 476                                               &sun8i_codec_regmap_config);
 477        if (IS_ERR(scodec->regmap)) {
 478                dev_err(&pdev->dev, "Failed to create our regmap\n");
 479                return PTR_ERR(scodec->regmap);
 480        }
 481
 482        platform_set_drvdata(pdev, scodec);
 483
 484        pm_runtime_enable(&pdev->dev);
 485        if (!pm_runtime_enabled(&pdev->dev)) {
 486                ret = sun8i_codec_runtime_resume(&pdev->dev);
 487                if (ret)
 488                        goto err_pm_disable;
 489        }
 490
 491        ret = snd_soc_register_codec(&pdev->dev, &sun8i_soc_codec,
 492                                     &sun8i_codec_dai, 1);
 493        if (ret) {
 494                dev_err(&pdev->dev, "Failed to register codec\n");
 495                goto err_suspend;
 496        }
 497
 498        return ret;
 499
 500err_suspend:
 501        if (!pm_runtime_status_suspended(&pdev->dev))
 502                sun8i_codec_runtime_suspend(&pdev->dev);
 503
 504err_pm_disable:
 505        pm_runtime_disable(&pdev->dev);
 506
 507        return ret;
 508}
 509
 510static int sun8i_codec_remove(struct platform_device *pdev)
 511{
 512        struct snd_soc_card *card = platform_get_drvdata(pdev);
 513        struct sun8i_codec *scodec = snd_soc_card_get_drvdata(card);
 514
 515        pm_runtime_disable(&pdev->dev);
 516        if (!pm_runtime_status_suspended(&pdev->dev))
 517                sun8i_codec_runtime_suspend(&pdev->dev);
 518
 519        snd_soc_unregister_codec(&pdev->dev);
 520        clk_disable_unprepare(scodec->clk_module);
 521        clk_disable_unprepare(scodec->clk_bus);
 522
 523        return 0;
 524}
 525
 526static const struct of_device_id sun8i_codec_of_match[] = {
 527        { .compatible = "allwinner,sun8i-a33-codec" },
 528        {}
 529};
 530MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
 531
 532static const struct dev_pm_ops sun8i_codec_pm_ops = {
 533        SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
 534                           sun8i_codec_runtime_resume, NULL)
 535};
 536
 537static struct platform_driver sun8i_codec_driver = {
 538        .driver = {
 539                .name = "sun8i-codec",
 540                .of_match_table = sun8i_codec_of_match,
 541                .pm = &sun8i_codec_pm_ops,
 542        },
 543        .probe = sun8i_codec_probe,
 544        .remove = sun8i_codec_remove,
 545};
 546module_platform_driver(sun8i_codec_driver);
 547
 548MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
 549MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
 550MODULE_LICENSE("GPL");
 551MODULE_ALIAS("platform:sun8i-codec");
 552