linux/sound/soc/codecs/ak4104.c
<<
>>
Prefs
   1/*
   2 * AK4104 ALSA SoC (ASoC) driver
   3 *
   4 * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
   5 *
   6 *  This program is free software; you can redistribute  it and/or modify it
   7 *  under the terms of  the GNU General  Public License as published by the
   8 *  Free Software Foundation;  either version 2 of the  License, or (at your
   9 *  option) any later version.
  10 */
  11
  12#include <linux/module.h>
  13#include <sound/core.h>
  14#include <sound/soc.h>
  15#include <sound/initval.h>
  16#include <linux/spi/spi.h>
  17#include <sound/asoundef.h>
  18
  19#include "ak4104.h"
  20
  21/* AK4104 registers addresses */
  22#define AK4104_REG_CONTROL1             0x00
  23#define AK4104_REG_RESERVED             0x01
  24#define AK4104_REG_CONTROL2             0x02
  25#define AK4104_REG_TX                   0x03
  26#define AK4104_REG_CHN_STATUS(x)        ((x) + 0x04)
  27#define AK4104_NUM_REGS                 10
  28
  29#define AK4104_REG_MASK                 0x1f
  30#define AK4104_READ                     0xc0
  31#define AK4104_WRITE                    0xe0
  32#define AK4104_RESERVED_VAL             0x5b
  33
  34/* Bit masks for AK4104 registers */
  35#define AK4104_CONTROL1_RSTN            (1 << 0)
  36#define AK4104_CONTROL1_PW              (1 << 1)
  37#define AK4104_CONTROL1_DIF0            (1 << 2)
  38#define AK4104_CONTROL1_DIF1            (1 << 3)
  39
  40#define AK4104_CONTROL2_SEL0            (1 << 0)
  41#define AK4104_CONTROL2_SEL1            (1 << 1)
  42#define AK4104_CONTROL2_MODE            (1 << 2)
  43
  44#define AK4104_TX_TXE                   (1 << 0)
  45#define AK4104_TX_V                     (1 << 1)
  46
  47#define DRV_NAME "ak4104"
  48
  49struct ak4104_private {
  50        struct snd_soc_codec codec;
  51        u8 reg_cache[AK4104_NUM_REGS];
  52};
  53
  54static int ak4104_fill_cache(struct snd_soc_codec *codec)
  55{
  56        int i;
  57        u8 *reg_cache = codec->reg_cache;
  58        struct spi_device *spi = codec->control_data;
  59
  60        for (i = 0; i < codec->reg_cache_size; i++) {
  61                int ret = spi_w8r8(spi, i | AK4104_READ);
  62                if (ret < 0) {
  63                        dev_err(&spi->dev, "SPI write failure\n");
  64                        return ret;
  65                }
  66
  67                reg_cache[i] = ret;
  68        }
  69
  70        return 0;
  71}
  72
  73static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
  74                                          unsigned int reg)
  75{
  76        u8 *reg_cache = codec->reg_cache;
  77
  78        if (reg >= codec->reg_cache_size)
  79                return -EINVAL;
  80
  81        return reg_cache[reg];
  82}
  83
  84static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
  85                            unsigned int value)
  86{
  87        u8 *cache = codec->reg_cache;
  88        struct spi_device *spi = codec->control_data;
  89
  90        if (reg >= codec->reg_cache_size)
  91                return -EINVAL;
  92
  93        reg &= AK4104_REG_MASK;
  94        reg |= AK4104_WRITE;
  95
  96        /* only write to the hardware if value has changed */
  97        if (cache[reg] != value) {
  98                u8 tmp[2] = { reg, value };
  99                if (spi_write(spi, tmp, sizeof(tmp))) {
 100                        dev_err(&spi->dev, "SPI write failed\n");
 101                        return -EIO;
 102                }
 103
 104                cache[reg] = value;
 105        }
 106
 107        return 0;
 108}
 109
 110static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
 111                              unsigned int format)
 112{
 113        struct snd_soc_codec *codec = codec_dai->codec;
 114        int val = 0;
 115
 116        val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
 117        if (val < 0)
 118                return val;
 119
 120        val &= ~(AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1);
 121
 122        /* set DAI format */
 123        switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
 124        case SND_SOC_DAIFMT_RIGHT_J:
 125                break;
 126        case SND_SOC_DAIFMT_LEFT_J:
 127                val |= AK4104_CONTROL1_DIF0;
 128                break;
 129        case SND_SOC_DAIFMT_I2S:
 130                val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
 131                break;
 132        default:
 133                dev_err(codec->dev, "invalid dai format\n");
 134                return -EINVAL;
 135        }
 136
 137        /* This device can only be slave */
 138        if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
 139                return -EINVAL;
 140
 141        return ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
 142}
 143
 144static int ak4104_hw_params(struct snd_pcm_substream *substream,
 145                            struct snd_pcm_hw_params *params,
 146                            struct snd_soc_dai *dai)
 147{
 148        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 149        struct snd_soc_device *socdev = rtd->socdev;
 150        struct snd_soc_codec *codec = socdev->card->codec;
 151        int val = 0;
 152
 153        /* set the IEC958 bits: consumer mode, no copyright bit */
 154        val |= IEC958_AES0_CON_NOT_COPYRIGHT;
 155        ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(0), val);
 156
 157        val = 0;
 158
 159        switch (params_rate(params)) {
 160        case 44100:
 161                val |= IEC958_AES3_CON_FS_44100;
 162                break;
 163        case 48000:
 164                val |= IEC958_AES3_CON_FS_48000;
 165                break;
 166        case 32000:
 167                val |= IEC958_AES3_CON_FS_32000;
 168                break;
 169        default:
 170                dev_err(codec->dev, "unsupported sampling rate\n");
 171                return -EINVAL;
 172        }
 173
 174        return ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(3), val);
 175}
 176
 177static struct snd_soc_dai_ops ak4101_dai_ops = {
 178        .hw_params = ak4104_hw_params,
 179        .set_fmt = ak4104_set_dai_fmt,
 180};
 181
 182struct snd_soc_dai ak4104_dai = {
 183        .name = DRV_NAME,
 184        .playback = {
 185                .stream_name = "Playback",
 186                .channels_min = 2,
 187                .channels_max = 2,
 188                .rates = SNDRV_PCM_RATE_44100 |
 189                         SNDRV_PCM_RATE_48000 |
 190                         SNDRV_PCM_RATE_32000,
 191                .formats = SNDRV_PCM_FMTBIT_S16_LE  |
 192                           SNDRV_PCM_FMTBIT_S24_3LE |
 193                           SNDRV_PCM_FMTBIT_S24_LE
 194        },
 195        .ops = &ak4101_dai_ops,
 196};
 197
 198static struct snd_soc_codec *ak4104_codec;
 199
 200static int ak4104_spi_probe(struct spi_device *spi)
 201{
 202        struct snd_soc_codec *codec;
 203        struct ak4104_private *ak4104;
 204        int ret, val;
 205
 206        spi->bits_per_word = 8;
 207        spi->mode = SPI_MODE_0;
 208        ret = spi_setup(spi);
 209        if (ret < 0)
 210                return ret;
 211
 212        ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
 213        if (!ak4104) {
 214                dev_err(&spi->dev, "could not allocate codec\n");
 215                return -ENOMEM;
 216        }
 217
 218        codec = &ak4104->codec;
 219        mutex_init(&codec->mutex);
 220        INIT_LIST_HEAD(&codec->dapm_widgets);
 221        INIT_LIST_HEAD(&codec->dapm_paths);
 222
 223        codec->dev = &spi->dev;
 224        codec->name = DRV_NAME;
 225        codec->owner = THIS_MODULE;
 226        codec->dai = &ak4104_dai;
 227        codec->num_dai = 1;
 228        codec->private_data = ak4104;
 229        codec->control_data = spi;
 230        codec->reg_cache = ak4104->reg_cache;
 231        codec->reg_cache_size = AK4104_NUM_REGS;
 232
 233        /* read all regs and fill the cache */
 234        ret = ak4104_fill_cache(codec);
 235        if (ret < 0) {
 236                dev_err(&spi->dev, "failed to fill register cache\n");
 237                return ret;
 238        }
 239
 240        /* read the 'reserved' register - according to the datasheet, it
 241         * should contain 0x5b. Not a good way to verify the presence of
 242         * the device, but there is no hardware ID register. */
 243        if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
 244                                         AK4104_RESERVED_VAL) {
 245                ret = -ENODEV;
 246                goto error_free_codec;
 247        }
 248
 249        /* set power-up and non-reset bits */
 250        val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
 251        val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
 252        ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
 253        if (ret < 0)
 254                goto error_free_codec;
 255
 256        /* enable transmitter */
 257        val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
 258        val |= AK4104_TX_TXE;
 259        ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
 260        if (ret < 0)
 261                goto error_free_codec;
 262
 263        ak4104_codec = codec;
 264        ret = snd_soc_register_dai(&ak4104_dai);
 265        if (ret < 0) {
 266                dev_err(&spi->dev, "failed to register DAI\n");
 267                goto error_free_codec;
 268        }
 269
 270        spi_set_drvdata(spi, ak4104);
 271        dev_info(&spi->dev, "SPI device initialized\n");
 272        return 0;
 273
 274error_free_codec:
 275        kfree(ak4104);
 276        ak4104_dai.dev = NULL;
 277        return ret;
 278}
 279
 280static int __devexit ak4104_spi_remove(struct spi_device *spi)
 281{
 282        int ret, val;
 283        struct ak4104_private *ak4104 = spi_get_drvdata(spi);
 284
 285        val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
 286        if (val < 0)
 287                return val;
 288
 289        /* clear power-up and non-reset bits */
 290        val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
 291        ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
 292        if (ret < 0)
 293                return ret;
 294
 295        ak4104_codec = NULL;
 296        kfree(ak4104);
 297        return 0;
 298}
 299
 300static int ak4104_probe(struct platform_device *pdev)
 301{
 302        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 303        struct snd_soc_codec *codec = ak4104_codec;
 304        int ret;
 305
 306        /* Connect the codec to the socdev.  snd_soc_new_pcms() needs this. */
 307        socdev->card->codec = codec;
 308
 309        /* Register PCMs */
 310        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 311        if (ret < 0) {
 312                dev_err(codec->dev, "failed to create pcms\n");
 313                return ret;
 314        }
 315
 316        /* Register the socdev */
 317        ret = snd_soc_init_card(socdev);
 318        if (ret < 0) {
 319                dev_err(codec->dev, "failed to register card\n");
 320                snd_soc_free_pcms(socdev);
 321                return ret;
 322        }
 323
 324        return 0;
 325}
 326
 327static int ak4104_remove(struct platform_device *pdev)
 328{
 329        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 330        snd_soc_free_pcms(socdev);
 331        return 0;
 332};
 333
 334struct snd_soc_codec_device soc_codec_device_ak4104 = {
 335        .probe =        ak4104_probe,
 336        .remove =       ak4104_remove
 337};
 338EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
 339
 340static struct spi_driver ak4104_spi_driver = {
 341        .driver  = {
 342                .name   = DRV_NAME,
 343                .owner  = THIS_MODULE,
 344        },
 345        .probe  = ak4104_spi_probe,
 346        .remove = __devexit_p(ak4104_spi_remove),
 347};
 348
 349static int __init ak4104_init(void)
 350{
 351        pr_info("Asahi Kasei AK4104 ALSA SoC Codec Driver\n");
 352        return spi_register_driver(&ak4104_spi_driver);
 353}
 354module_init(ak4104_init);
 355
 356static void __exit ak4104_exit(void)
 357{
 358        spi_unregister_driver(&ak4104_spi_driver);
 359}
 360module_exit(ak4104_exit);
 361
 362MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 363MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
 364MODULE_LICENSE("GPL");
 365
 366