linux/sound/soc/codecs/ad1938.c
<<
>>
Prefs
   1/*
   2 * File:         sound/soc/codecs/ad1938.c
   3 * Author:       Barry Song <Barry.Song@analog.com>
   4 *
   5 * Created:      June 04 2009
   6 * Description:  Driver for AD1938 sound chip
   7 *
   8 * Modified:
   9 *               Copyright 2009 Analog Devices Inc.
  10 *
  11 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License as published by
  15 * the Free Software Foundation; either version 2 of the License, or
  16 * (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, see the file COPYING, or write
  25 * to the Free Software Foundation, Inc.,
  26 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  27 */
  28
  29#include <linux/init.h>
  30#include <linux/module.h>
  31#include <linux/kernel.h>
  32#include <linux/device.h>
  33#include <sound/core.h>
  34#include <sound/pcm.h>
  35#include <sound/pcm_params.h>
  36#include <sound/initval.h>
  37#include <sound/soc.h>
  38#include <sound/tlv.h>
  39#include <sound/soc-dapm.h>
  40#include <linux/spi/spi.h>
  41#include "ad1938.h"
  42
  43/* codec private data */
  44struct ad1938_priv {
  45        struct snd_soc_codec codec;
  46        u8 reg_cache[AD1938_NUM_REGS];
  47};
  48
  49static struct snd_soc_codec *ad1938_codec;
  50struct snd_soc_codec_device soc_codec_dev_ad1938;
  51static int ad1938_register(struct ad1938_priv *ad1938);
  52static void ad1938_unregister(struct ad1938_priv *ad1938);
  53
  54/*
  55 * AD1938 volume/mute/de-emphasis etc. controls
  56 */
  57static const char *ad1938_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
  58
  59static const struct soc_enum ad1938_deemp_enum =
  60        SOC_ENUM_SINGLE(AD1938_DAC_CTRL2, 1, 4, ad1938_deemp);
  61
  62static const struct snd_kcontrol_new ad1938_snd_controls[] = {
  63        /* DAC volume control */
  64        SOC_DOUBLE_R("DAC1  Volume", AD1938_DAC_L1_VOL,
  65                        AD1938_DAC_R1_VOL, 0, 0xFF, 1),
  66        SOC_DOUBLE_R("DAC2  Volume", AD1938_DAC_L2_VOL,
  67                        AD1938_DAC_R2_VOL, 0, 0xFF, 1),
  68        SOC_DOUBLE_R("DAC3  Volume", AD1938_DAC_L3_VOL,
  69                        AD1938_DAC_R3_VOL, 0, 0xFF, 1),
  70        SOC_DOUBLE_R("DAC4  Volume", AD1938_DAC_L4_VOL,
  71                        AD1938_DAC_R4_VOL, 0, 0xFF, 1),
  72
  73        /* ADC switch control */
  74        SOC_DOUBLE("ADC1 Switch", AD1938_ADC_CTRL0, AD1938_ADCL1_MUTE,
  75                AD1938_ADCR1_MUTE, 1, 1),
  76        SOC_DOUBLE("ADC2 Switch", AD1938_ADC_CTRL0, AD1938_ADCL2_MUTE,
  77                AD1938_ADCR2_MUTE, 1, 1),
  78
  79        /* DAC switch control */
  80        SOC_DOUBLE("DAC1 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL1_MUTE,
  81                AD1938_DACR1_MUTE, 1, 1),
  82        SOC_DOUBLE("DAC2 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL2_MUTE,
  83                AD1938_DACR2_MUTE, 1, 1),
  84        SOC_DOUBLE("DAC3 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL3_MUTE,
  85                AD1938_DACR3_MUTE, 1, 1),
  86        SOC_DOUBLE("DAC4 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL4_MUTE,
  87                AD1938_DACR4_MUTE, 1, 1),
  88
  89        /* ADC high-pass filter */
  90        SOC_SINGLE("ADC High Pass Filter Switch", AD1938_ADC_CTRL0,
  91                        AD1938_ADC_HIGHPASS_FILTER, 1, 0),
  92
  93        /* DAC de-emphasis */
  94        SOC_ENUM("Playback Deemphasis", ad1938_deemp_enum),
  95};
  96
  97static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
  98        SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1),
  99        SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
 100        SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0),
 101        SND_SOC_DAPM_OUTPUT("DAC1OUT"),
 102        SND_SOC_DAPM_OUTPUT("DAC2OUT"),
 103        SND_SOC_DAPM_OUTPUT("DAC3OUT"),
 104        SND_SOC_DAPM_OUTPUT("DAC4OUT"),
 105        SND_SOC_DAPM_INPUT("ADC1IN"),
 106        SND_SOC_DAPM_INPUT("ADC2IN"),
 107};
 108
 109static const struct snd_soc_dapm_route audio_paths[] = {
 110        { "DAC", NULL, "ADC_PWR" },
 111        { "ADC", NULL, "ADC_PWR" },
 112        { "DAC1OUT", "DAC1 Switch", "DAC" },
 113        { "DAC2OUT", "DAC2 Switch", "DAC" },
 114        { "DAC3OUT", "DAC3 Switch", "DAC" },
 115        { "DAC4OUT", "DAC4 Switch", "DAC" },
 116        { "ADC", "ADC1 Switch", "ADC1IN" },
 117        { "ADC", "ADC2 Switch", "ADC2IN" },
 118};
 119
 120/*
 121 * DAI ops entries
 122 */
 123
 124static int ad1938_mute(struct snd_soc_dai *dai, int mute)
 125{
 126        struct snd_soc_codec *codec = dai->codec;
 127        int reg;
 128
 129        reg = codec->read(codec, AD1938_DAC_CTRL2);
 130        reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg &
 131                (~AD1938_DAC_MASTER_MUTE);
 132        codec->write(codec, AD1938_DAC_CTRL2, reg);
 133
 134        return 0;
 135}
 136
 137static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd)
 138{
 139        int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0);
 140        reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg |
 141                AD1938_PLL_POWERDOWN;
 142        codec->write(codec, AD1938_PLL_CLK_CTRL0, reg);
 143
 144        return 0;
 145}
 146
 147static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 148                               unsigned int mask, int slots, int width)
 149{
 150        struct snd_soc_codec *codec = dai->codec;
 151        int dac_reg = codec->read(codec, AD1938_DAC_CTRL1);
 152        int adc_reg = codec->read(codec, AD1938_ADC_CTRL2);
 153
 154        dac_reg &= ~AD1938_DAC_CHAN_MASK;
 155        adc_reg &= ~AD1938_ADC_CHAN_MASK;
 156
 157        switch (slots) {
 158        case 2:
 159                dac_reg |= AD1938_DAC_2_CHANNELS << AD1938_DAC_CHAN_SHFT;
 160                adc_reg |= AD1938_ADC_2_CHANNELS << AD1938_ADC_CHAN_SHFT;
 161                break;
 162        case 4:
 163                dac_reg |= AD1938_DAC_4_CHANNELS << AD1938_DAC_CHAN_SHFT;
 164                adc_reg |= AD1938_ADC_4_CHANNELS << AD1938_ADC_CHAN_SHFT;
 165                break;
 166        case 8:
 167                dac_reg |= AD1938_DAC_8_CHANNELS << AD1938_DAC_CHAN_SHFT;
 168                adc_reg |= AD1938_ADC_8_CHANNELS << AD1938_ADC_CHAN_SHFT;
 169                break;
 170        case 16:
 171                dac_reg |= AD1938_DAC_16_CHANNELS << AD1938_DAC_CHAN_SHFT;
 172                adc_reg |= AD1938_ADC_16_CHANNELS << AD1938_ADC_CHAN_SHFT;
 173                break;
 174        default:
 175                return -EINVAL;
 176        }
 177
 178        codec->write(codec, AD1938_DAC_CTRL1, dac_reg);
 179        codec->write(codec, AD1938_ADC_CTRL2, adc_reg);
 180
 181        return 0;
 182}
 183
 184static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,
 185                unsigned int fmt)
 186{
 187        struct snd_soc_codec *codec = codec_dai->codec;
 188        int adc_reg, dac_reg;
 189
 190        adc_reg = codec->read(codec, AD1938_ADC_CTRL2);
 191        dac_reg = codec->read(codec, AD1938_DAC_CTRL1);
 192
 193        /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S
 194         * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A)
 195         */
 196        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 197        case SND_SOC_DAIFMT_I2S:
 198                adc_reg &= ~AD1938_ADC_SERFMT_MASK;
 199                adc_reg |= AD1938_ADC_SERFMT_TDM;
 200                break;
 201        case SND_SOC_DAIFMT_DSP_A:
 202                adc_reg &= ~AD1938_ADC_SERFMT_MASK;
 203                adc_reg |= AD1938_ADC_SERFMT_AUX;
 204                break;
 205        default:
 206                return -EINVAL;
 207        }
 208
 209        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 210        case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
 211                adc_reg &= ~AD1938_ADC_LEFT_HIGH;
 212                adc_reg &= ~AD1938_ADC_BCLK_INV;
 213                dac_reg &= ~AD1938_DAC_LEFT_HIGH;
 214                dac_reg &= ~AD1938_DAC_BCLK_INV;
 215                break;
 216        case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */
 217                adc_reg |= AD1938_ADC_LEFT_HIGH;
 218                adc_reg &= ~AD1938_ADC_BCLK_INV;
 219                dac_reg |= AD1938_DAC_LEFT_HIGH;
 220                dac_reg &= ~AD1938_DAC_BCLK_INV;
 221                break;
 222        case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */
 223                adc_reg &= ~AD1938_ADC_LEFT_HIGH;
 224                adc_reg |= AD1938_ADC_BCLK_INV;
 225                dac_reg &= ~AD1938_DAC_LEFT_HIGH;
 226                dac_reg |= AD1938_DAC_BCLK_INV;
 227                break;
 228
 229        case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
 230                adc_reg |= AD1938_ADC_LEFT_HIGH;
 231                adc_reg |= AD1938_ADC_BCLK_INV;
 232                dac_reg |= AD1938_DAC_LEFT_HIGH;
 233                dac_reg |= AD1938_DAC_BCLK_INV;
 234                break;
 235        default:
 236                return -EINVAL;
 237        }
 238
 239        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 240        case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
 241                adc_reg |= AD1938_ADC_LCR_MASTER;
 242                adc_reg |= AD1938_ADC_BCLK_MASTER;
 243                dac_reg |= AD1938_DAC_LCR_MASTER;
 244                dac_reg |= AD1938_DAC_BCLK_MASTER;
 245                break;
 246        case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */
 247                adc_reg |= AD1938_ADC_LCR_MASTER;
 248                adc_reg &= ~AD1938_ADC_BCLK_MASTER;
 249                dac_reg |= AD1938_DAC_LCR_MASTER;
 250                dac_reg &= ~AD1938_DAC_BCLK_MASTER;
 251                break;
 252        case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
 253                adc_reg &= ~AD1938_ADC_LCR_MASTER;
 254                adc_reg |= AD1938_ADC_BCLK_MASTER;
 255                dac_reg &= ~AD1938_DAC_LCR_MASTER;
 256                dac_reg |= AD1938_DAC_BCLK_MASTER;
 257                break;
 258        case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
 259                adc_reg &= ~AD1938_ADC_LCR_MASTER;
 260                adc_reg &= ~AD1938_ADC_BCLK_MASTER;
 261                dac_reg &= ~AD1938_DAC_LCR_MASTER;
 262                dac_reg &= ~AD1938_DAC_BCLK_MASTER;
 263                break;
 264        default:
 265                return -EINVAL;
 266        }
 267
 268        codec->write(codec, AD1938_ADC_CTRL2, adc_reg);
 269        codec->write(codec, AD1938_DAC_CTRL1, dac_reg);
 270
 271        return 0;
 272}
 273
 274static int ad1938_hw_params(struct snd_pcm_substream *substream,
 275                struct snd_pcm_hw_params *params,
 276                struct snd_soc_dai *dai)
 277{
 278        int word_len = 0, reg = 0;
 279
 280        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 281        struct snd_soc_device *socdev = rtd->socdev;
 282        struct snd_soc_codec *codec = socdev->card->codec;
 283
 284        /* bit size */
 285        switch (params_format(params)) {
 286        case SNDRV_PCM_FORMAT_S16_LE:
 287                word_len = 3;
 288                break;
 289        case SNDRV_PCM_FORMAT_S20_3LE:
 290                word_len = 1;
 291                break;
 292        case SNDRV_PCM_FORMAT_S24_LE:
 293        case SNDRV_PCM_FORMAT_S32_LE:
 294                word_len = 0;
 295                break;
 296        }
 297
 298        reg = codec->read(codec, AD1938_DAC_CTRL2);
 299        reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len;
 300        codec->write(codec, AD1938_DAC_CTRL2, reg);
 301
 302        reg = codec->read(codec, AD1938_ADC_CTRL1);
 303        reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len;
 304        codec->write(codec, AD1938_ADC_CTRL1, reg);
 305
 306        return 0;
 307}
 308
 309static int ad1938_set_bias_level(struct snd_soc_codec *codec,
 310                enum snd_soc_bias_level level)
 311{
 312        switch (level) {
 313        case SND_SOC_BIAS_ON:
 314                ad1938_pll_powerctrl(codec, 1);
 315                break;
 316        case SND_SOC_BIAS_PREPARE:
 317                break;
 318        case SND_SOC_BIAS_STANDBY:
 319        case SND_SOC_BIAS_OFF:
 320                ad1938_pll_powerctrl(codec, 0);
 321                break;
 322        }
 323        codec->bias_level = level;
 324        return 0;
 325}
 326
 327/*
 328 * interface to read/write ad1938 register
 329 */
 330
 331#define AD1938_SPI_ADDR    0x4
 332#define AD1938_SPI_READ    0x1
 333#define AD1938_SPI_BUFLEN  3
 334
 335/*
 336 * write to the ad1938 register space
 337 */
 338
 339static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg,
 340                unsigned int value)
 341{
 342        u8 *reg_cache = codec->reg_cache;
 343        int ret = 0;
 344
 345        if (value != reg_cache[reg]) {
 346                uint8_t buf[AD1938_SPI_BUFLEN];
 347                struct spi_transfer t = {
 348                        .tx_buf = buf,
 349                        .len = AD1938_SPI_BUFLEN,
 350                };
 351                struct spi_message m;
 352
 353                buf[0] = AD1938_SPI_ADDR << 1;
 354                buf[1] = reg;
 355                buf[2] = value;
 356                spi_message_init(&m);
 357                spi_message_add_tail(&t, &m);
 358                ret = spi_sync(codec->control_data, &m);
 359                if (ret == 0)
 360                        reg_cache[reg] = value;
 361        }
 362
 363        return ret;
 364}
 365
 366/*
 367 * read from the ad1938 register space cache
 368 */
 369
 370static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec,
 371                                          unsigned int reg)
 372{
 373        u8 *reg_cache = codec->reg_cache;
 374
 375        if (reg >= codec->reg_cache_size)
 376                return -EINVAL;
 377
 378        return reg_cache[reg];
 379}
 380
 381/*
 382 * read from the ad1938 register space
 383 */
 384
 385static unsigned int ad1938_read_reg(struct snd_soc_codec *codec,
 386                                                unsigned int reg)
 387{
 388        char w_buf[AD1938_SPI_BUFLEN];
 389        char r_buf[AD1938_SPI_BUFLEN];
 390        int ret;
 391
 392        struct spi_transfer t = {
 393                .tx_buf = w_buf,
 394                .rx_buf = r_buf,
 395                .len = AD1938_SPI_BUFLEN,
 396        };
 397        struct spi_message m;
 398
 399        w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ;
 400        w_buf[1] = reg;
 401        w_buf[2] = 0;
 402
 403        spi_message_init(&m);
 404        spi_message_add_tail(&t, &m);
 405        ret = spi_sync(codec->control_data, &m);
 406        if (ret == 0)
 407                return  r_buf[2];
 408        else
 409                return -EIO;
 410}
 411
 412static int ad1938_fill_cache(struct snd_soc_codec *codec)
 413{
 414        int i;
 415        u8 *reg_cache = codec->reg_cache;
 416        struct spi_device *spi = codec->control_data;
 417
 418        for (i = 0; i < codec->reg_cache_size; i++) {
 419                int ret = ad1938_read_reg(codec, i);
 420                if (ret == -EIO) {
 421                        dev_err(&spi->dev, "AD1938 SPI read failure\n");
 422                        return ret;
 423                }
 424                reg_cache[i] = ret;
 425        }
 426
 427        return 0;
 428}
 429
 430static int __devinit ad1938_spi_probe(struct spi_device *spi)
 431{
 432        struct snd_soc_codec *codec;
 433        struct ad1938_priv *ad1938;
 434
 435        ad1938 = kzalloc(sizeof(struct ad1938_priv), GFP_KERNEL);
 436        if (ad1938 == NULL)
 437                return -ENOMEM;
 438
 439        codec = &ad1938->codec;
 440        codec->control_data = spi;
 441        codec->dev = &spi->dev;
 442
 443        dev_set_drvdata(&spi->dev, ad1938);
 444
 445        return ad1938_register(ad1938);
 446}
 447
 448static int __devexit ad1938_spi_remove(struct spi_device *spi)
 449{
 450        struct ad1938_priv *ad1938 = dev_get_drvdata(&spi->dev);
 451
 452        ad1938_unregister(ad1938);
 453        return 0;
 454}
 455
 456static struct spi_driver ad1938_spi_driver = {
 457        .driver = {
 458                .name   = "ad1938",
 459                .owner  = THIS_MODULE,
 460        },
 461        .probe          = ad1938_spi_probe,
 462        .remove         = __devexit_p(ad1938_spi_remove),
 463};
 464
 465static struct snd_soc_dai_ops ad1938_dai_ops = {
 466        .hw_params = ad1938_hw_params,
 467        .digital_mute = ad1938_mute,
 468        .set_tdm_slot = ad1938_set_tdm_slot,
 469        .set_fmt = ad1938_set_dai_fmt,
 470};
 471
 472/* codec DAI instance */
 473struct snd_soc_dai ad1938_dai = {
 474        .name = "AD1938",
 475        .playback = {
 476                .stream_name = "Playback",
 477                .channels_min = 2,
 478                .channels_max = 8,
 479                .rates = SNDRV_PCM_RATE_48000,
 480                .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
 481                        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
 482        },
 483        .capture = {
 484                .stream_name = "Capture",
 485                .channels_min = 2,
 486                .channels_max = 4,
 487                .rates = SNDRV_PCM_RATE_48000,
 488                .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
 489                        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
 490        },
 491        .ops = &ad1938_dai_ops,
 492};
 493EXPORT_SYMBOL_GPL(ad1938_dai);
 494
 495static int ad1938_register(struct ad1938_priv *ad1938)
 496{
 497        int ret;
 498        struct snd_soc_codec *codec = &ad1938->codec;
 499
 500        if (ad1938_codec) {
 501                dev_err(codec->dev, "Another ad1938 is registered\n");
 502                return -EINVAL;
 503        }
 504
 505        mutex_init(&codec->mutex);
 506        INIT_LIST_HEAD(&codec->dapm_widgets);
 507        INIT_LIST_HEAD(&codec->dapm_paths);
 508        codec->private_data = ad1938;
 509        codec->reg_cache = ad1938->reg_cache;
 510        codec->reg_cache_size = AD1938_NUM_REGS;
 511        codec->name = "AD1938";
 512        codec->owner = THIS_MODULE;
 513        codec->dai = &ad1938_dai;
 514        codec->num_dai = 1;
 515        codec->write = ad1938_write_reg;
 516        codec->read = ad1938_read_reg_cache;
 517        codec->set_bias_level = ad1938_set_bias_level;
 518        INIT_LIST_HEAD(&codec->dapm_widgets);
 519        INIT_LIST_HEAD(&codec->dapm_paths);
 520
 521        ad1938_dai.dev = codec->dev;
 522        ad1938_codec = codec;
 523
 524        /* default setting for ad1938 */
 525
 526        /* unmute dac channels */
 527        codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0);
 528        /* de-emphasis: 48kHz, powedown dac */
 529        codec->write(codec, AD1938_DAC_CTRL2, 0x1A);
 530        /* powerdown dac, dac in tdm mode */
 531        codec->write(codec, AD1938_DAC_CTRL0, 0x41);
 532        /* high-pass filter enable */
 533        codec->write(codec, AD1938_ADC_CTRL0, 0x3);
 534        /* sata delay=1, adc aux mode */
 535        codec->write(codec, AD1938_ADC_CTRL1, 0x43);
 536        /* pll input: mclki/xi */
 537        codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D);
 538        codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04);
 539
 540        ad1938_fill_cache(codec);
 541
 542        ret = snd_soc_register_codec(codec);
 543        if (ret != 0) {
 544                dev_err(codec->dev, "Failed to register codec: %d\n", ret);
 545                kfree(ad1938);
 546                return ret;
 547        }
 548
 549        ret = snd_soc_register_dai(&ad1938_dai);
 550        if (ret != 0) {
 551                dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
 552                snd_soc_unregister_codec(codec);
 553                kfree(ad1938);
 554                return ret;
 555        }
 556
 557        return 0;
 558}
 559
 560static void ad1938_unregister(struct ad1938_priv *ad1938)
 561{
 562        ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF);
 563        snd_soc_unregister_dai(&ad1938_dai);
 564        snd_soc_unregister_codec(&ad1938->codec);
 565        kfree(ad1938);
 566        ad1938_codec = NULL;
 567}
 568
 569static int ad1938_probe(struct platform_device *pdev)
 570{
 571        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 572        struct snd_soc_codec *codec;
 573        int ret = 0;
 574
 575        if (ad1938_codec == NULL) {
 576                dev_err(&pdev->dev, "Codec device not registered\n");
 577                return -ENODEV;
 578        }
 579
 580        socdev->card->codec = ad1938_codec;
 581        codec = ad1938_codec;
 582
 583        /* register pcms */
 584        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 585        if (ret < 0) {
 586                dev_err(codec->dev, "failed to create pcms: %d\n", ret);
 587                goto pcm_err;
 588        }
 589
 590        snd_soc_add_controls(codec, ad1938_snd_controls,
 591                             ARRAY_SIZE(ad1938_snd_controls));
 592        snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets,
 593                                  ARRAY_SIZE(ad1938_dapm_widgets));
 594        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 595        snd_soc_dapm_new_widgets(codec);
 596
 597        ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 598
 599        ret = snd_soc_init_card(socdev);
 600        if (ret < 0) {
 601                dev_err(codec->dev, "failed to register card: %d\n", ret);
 602                goto card_err;
 603        }
 604
 605        return ret;
 606
 607card_err:
 608        snd_soc_free_pcms(socdev);
 609        snd_soc_dapm_free(socdev);
 610pcm_err:
 611        return ret;
 612}
 613
 614/* power down chip */
 615static int ad1938_remove(struct platform_device *pdev)
 616{
 617        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 618
 619        snd_soc_free_pcms(socdev);
 620        snd_soc_dapm_free(socdev);
 621
 622        return 0;
 623}
 624
 625#ifdef CONFIG_PM
 626static int ad1938_suspend(struct platform_device *pdev,
 627                pm_message_t state)
 628{
 629        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 630        struct snd_soc_codec *codec = socdev->card->codec;
 631
 632        ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF);
 633        return 0;
 634}
 635
 636static int ad1938_resume(struct platform_device *pdev)
 637{
 638        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 639        struct snd_soc_codec *codec = socdev->card->codec;
 640
 641        if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
 642                ad1938_set_bias_level(codec, SND_SOC_BIAS_ON);
 643
 644        return 0;
 645}
 646#else
 647#define ad1938_suspend NULL
 648#define ad1938_resume NULL
 649#endif
 650
 651struct snd_soc_codec_device soc_codec_dev_ad1938 = {
 652        .probe =        ad1938_probe,
 653        .remove =       ad1938_remove,
 654        .suspend =      ad1938_suspend,
 655        .resume =       ad1938_resume,
 656};
 657EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938);
 658
 659static int __init ad1938_init(void)
 660{
 661        int ret;
 662
 663        ret = spi_register_driver(&ad1938_spi_driver);
 664        if (ret != 0) {
 665                printk(KERN_ERR "Failed to register ad1938 SPI driver: %d\n",
 666                                ret);
 667        }
 668
 669        return ret;
 670}
 671module_init(ad1938_init);
 672
 673static void __exit ad1938_exit(void)
 674{
 675        spi_unregister_driver(&ad1938_spi_driver);
 676}
 677module_exit(ad1938_exit);
 678
 679MODULE_DESCRIPTION("ASoC ad1938 driver");
 680MODULE_AUTHOR("Barry Song ");
 681MODULE_LICENSE("GPL");
 682
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.