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