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 <linux/of_device.h>
  19#include <linux/of_gpio.h>
  20#include <sound/asoundef.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
  48struct ak4104_private {
  49        struct regmap *regmap;
  50};
  51
  52static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
  53SND_SOC_DAPM_PGA("TXE", AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0),
  54
  55SND_SOC_DAPM_OUTPUT("TX"),
  56};
  57
  58static const struct snd_soc_dapm_route ak4104_dapm_routes[] = {
  59        { "TXE", NULL, "Playback" },
  60        { "TX", NULL, "TXE" },
  61};
  62
  63static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
  64                              unsigned int format)
  65{
  66        struct snd_soc_codec *codec = codec_dai->codec;
  67        struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
  68        int val = 0;
  69        int ret;
  70
  71        /* set DAI format */
  72        switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
  73        case SND_SOC_DAIFMT_RIGHT_J:
  74                break;
  75        case SND_SOC_DAIFMT_LEFT_J:
  76                val |= AK4104_CONTROL1_DIF0;
  77                break;
  78        case SND_SOC_DAIFMT_I2S:
  79                val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
  80                break;
  81        default:
  82                dev_err(codec->dev, "invalid dai format\n");
  83                return -EINVAL;
  84        }
  85
  86        /* This device can only be slave */
  87        if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
  88                return -EINVAL;
  89
  90        ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
  91                                 AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
  92                                 val);
  93        if (ret < 0)
  94                return ret;
  95
  96        return 0;
  97}
  98
  99static int ak4104_hw_params(struct snd_pcm_substream *substream,
 100                            struct snd_pcm_hw_params *params,
 101                            struct snd_soc_dai *dai)
 102{
 103        struct snd_soc_codec *codec = dai->codec;
 104        struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
 105        int ret, val = 0;
 106
 107        /* set the IEC958 bits: consumer mode, no copyright bit */
 108        val |= IEC958_AES0_CON_NOT_COPYRIGHT;
 109        regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val);
 110
 111        val = 0;
 112
 113        switch (params_rate(params)) {
 114        case 22050:
 115                val |= IEC958_AES3_CON_FS_22050;
 116                break;
 117        case 24000:
 118                val |= IEC958_AES3_CON_FS_24000;
 119                break;
 120        case 32000:
 121                val |= IEC958_AES3_CON_FS_32000;
 122                break;
 123        case 44100:
 124                val |= IEC958_AES3_CON_FS_44100;
 125                break;
 126        case 48000:
 127                val |= IEC958_AES3_CON_FS_48000;
 128                break;
 129        case 88200:
 130                val |= IEC958_AES3_CON_FS_88200;
 131                break;
 132        case 96000:
 133                val |= IEC958_AES3_CON_FS_96000;
 134                break;
 135        case 176400:
 136                val |= IEC958_AES3_CON_FS_176400;
 137                break;
 138        case 192000:
 139                val |= IEC958_AES3_CON_FS_192000;
 140                break;
 141        default:
 142                dev_err(codec->dev, "unsupported sampling rate\n");
 143                return -EINVAL;
 144        }
 145
 146        ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val);
 147        if (ret < 0)
 148                return ret;
 149
 150        return 0;
 151}
 152
 153static const struct snd_soc_dai_ops ak4101_dai_ops = {
 154        .hw_params = ak4104_hw_params,
 155        .set_fmt = ak4104_set_dai_fmt,
 156};
 157
 158static struct snd_soc_dai_driver ak4104_dai = {
 159        .name = "ak4104-hifi",
 160        .playback = {
 161                .stream_name = "Playback",
 162                .channels_min = 2,
 163                .channels_max = 2,
 164                .rates = SNDRV_PCM_RATE_8000_192000,
 165                .formats = SNDRV_PCM_FMTBIT_S16_LE  |
 166                           SNDRV_PCM_FMTBIT_S24_3LE |
 167                           SNDRV_PCM_FMTBIT_S24_LE
 168        },
 169        .ops = &ak4101_dai_ops,
 170};
 171
 172static int ak4104_probe(struct snd_soc_codec *codec)
 173{
 174        struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
 175        int ret;
 176
 177        codec->control_data = ak4104->regmap;
 178
 179        /* set power-up and non-reset bits */
 180        ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
 181                                 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
 182                                 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
 183        if (ret < 0)
 184                return ret;
 185
 186        /* enable transmitter */
 187        ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
 188                                 AK4104_TX_TXE, AK4104_TX_TXE);
 189        if (ret < 0)
 190                return ret;
 191
 192        return 0;
 193}
 194
 195static int ak4104_remove(struct snd_soc_codec *codec)
 196{
 197        struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
 198
 199        regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
 200                           AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
 201
 202        return 0;
 203}
 204
 205static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
 206        .probe =        ak4104_probe,
 207        .remove =       ak4104_remove,
 208
 209        .dapm_widgets = ak4104_dapm_widgets,
 210        .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
 211        .dapm_routes = ak4104_dapm_routes,
 212        .num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes),
 213};
 214
 215static const struct regmap_config ak4104_regmap = {
 216        .reg_bits = 8,
 217        .val_bits = 8,
 218
 219        .max_register = AK4104_NUM_REGS - 1,
 220        .read_flag_mask = AK4104_READ,
 221        .write_flag_mask = AK4104_WRITE,
 222
 223        .cache_type = REGCACHE_RBTREE,
 224};
 225
 226static int ak4104_spi_probe(struct spi_device *spi)
 227{
 228        struct device_node *np = spi->dev.of_node;
 229        struct ak4104_private *ak4104;
 230        unsigned int val;
 231        int ret;
 232
 233        spi->bits_per_word = 8;
 234        spi->mode = SPI_MODE_0;
 235        ret = spi_setup(spi);
 236        if (ret < 0)
 237                return ret;
 238
 239        ak4104 = devm_kzalloc(&spi->dev, sizeof(struct ak4104_private),
 240                              GFP_KERNEL);
 241        if (ak4104 == NULL)
 242                return -ENOMEM;
 243
 244        ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);
 245        if (IS_ERR(ak4104->regmap)) {
 246                ret = PTR_ERR(ak4104->regmap);
 247                return ret;
 248        }
 249
 250        if (np) {
 251                enum of_gpio_flags flags;
 252                int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
 253
 254                if (gpio_is_valid(gpio)) {
 255                        ret = devm_gpio_request_one(&spi->dev, gpio,
 256                                     flags & OF_GPIO_ACTIVE_LOW ?
 257                                        GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
 258                                     "ak4104 reset");
 259                        if (ret < 0)
 260                                return ret;
 261                }
 262        }
 263
 264        /* read the 'reserved' register - according to the datasheet, it
 265         * should contain 0x5b. Not a good way to verify the presence of
 266         * the device, but there is no hardware ID register. */
 267        ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val);
 268        if (ret != 0)
 269                return ret;
 270        if (val != AK4104_RESERVED_VAL)
 271                return -ENODEV;
 272
 273        spi_set_drvdata(spi, ak4104);
 274
 275        ret = snd_soc_register_codec(&spi->dev,
 276                        &soc_codec_device_ak4104, &ak4104_dai, 1);
 277        return ret;
 278}
 279
 280static int ak4104_spi_remove(struct spi_device *spi)
 281{
 282        snd_soc_unregister_codec(&spi->dev);
 283        return 0;
 284}
 285
 286static const struct of_device_id ak4104_of_match[] = {
 287        { .compatible = "asahi-kasei,ak4104", },
 288        { }
 289};
 290MODULE_DEVICE_TABLE(of, ak4104_of_match);
 291
 292static const struct spi_device_id ak4104_id_table[] = {
 293        { "ak4104", 0 },
 294        { }
 295};
 296MODULE_DEVICE_TABLE(spi, ak4104_id_table);
 297
 298static struct spi_driver ak4104_spi_driver = {
 299        .driver  = {
 300                .name   = "ak4104",
 301                .owner  = THIS_MODULE,
 302                .of_match_table = ak4104_of_match,
 303        },
 304        .id_table = ak4104_id_table,
 305        .probe  = ak4104_spi_probe,
 306        .remove = ak4104_spi_remove,
 307};
 308
 309module_spi_driver(ak4104_spi_driver);
 310
 311MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 312MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
 313MODULE_LICENSE("GPL");
 314
 315