linux/sound/soc/codecs/pcm3008.c
<<
>>
Prefs
   1/*
   2 * ALSA Soc PCM3008 codec support
   3 *
   4 * Author:      Hugo Villeneuve
   5 * Copyright (C) 2008 Lyrtech inc
   6 *
   7 * Based on AC97 Soc codec, original copyright follow:
   8 * Copyright 2005 Wolfson Microelectronics PLC.
   9 *
  10 *  This program is free software; you can redistribute  it and/or modify it
  11 *  under  the terms of  the GNU General  Public License as published by the
  12 *  Free Software Foundation;  either version 2 of the  License, or (at your
  13 *  option) any later version.
  14 *
  15 * Generic PCM3008 support.
  16 */
  17
  18#include <linux/init.h>
  19#include <linux/kernel.h>
  20#include <linux/device.h>
  21#include <linux/gpio.h>
  22#include <sound/core.h>
  23#include <sound/pcm.h>
  24#include <sound/initval.h>
  25#include <sound/soc.h>
  26
  27#include "pcm3008.h"
  28
  29#define PCM3008_VERSION "0.2"
  30
  31#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |    \
  32                       SNDRV_PCM_RATE_48000)
  33
  34struct snd_soc_dai pcm3008_dai = {
  35        .name = "PCM3008 HiFi",
  36        .playback = {
  37                .stream_name = "PCM3008 Playback",
  38                .channels_min = 1,
  39                .channels_max = 2,
  40                .rates = PCM3008_RATES,
  41                .formats = SNDRV_PCM_FMTBIT_S16_LE,
  42        },
  43        .capture = {
  44                .stream_name = "PCM3008 Capture",
  45                .channels_min = 1,
  46                .channels_max = 2,
  47                .rates = PCM3008_RATES,
  48                .formats = SNDRV_PCM_FMTBIT_S16_LE,
  49        },
  50};
  51EXPORT_SYMBOL_GPL(pcm3008_dai);
  52
  53static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
  54{
  55        gpio_free(setup->dem0_pin);
  56        gpio_free(setup->dem1_pin);
  57        gpio_free(setup->pdad_pin);
  58        gpio_free(setup->pdda_pin);
  59}
  60
  61static int pcm3008_soc_probe(struct platform_device *pdev)
  62{
  63        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
  64        struct snd_soc_codec *codec;
  65        struct pcm3008_setup_data *setup = socdev->codec_data;
  66        int ret = 0;
  67
  68        printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
  69
  70        socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
  71        if (!socdev->card->codec)
  72                return -ENOMEM;
  73
  74        codec = socdev->card->codec;
  75        mutex_init(&codec->mutex);
  76
  77        codec->name = "PCM3008";
  78        codec->owner = THIS_MODULE;
  79        codec->dai = &pcm3008_dai;
  80        codec->num_dai = 1;
  81        codec->write = NULL;
  82        codec->read = NULL;
  83        INIT_LIST_HEAD(&codec->dapm_widgets);
  84        INIT_LIST_HEAD(&codec->dapm_paths);
  85
  86        /* Register PCMs. */
  87        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
  88        if (ret < 0) {
  89                printk(KERN_ERR "pcm3008: failed to create pcms\n");
  90                goto pcm_err;
  91        }
  92
  93        /* Register Card. */
  94        ret = snd_soc_init_card(socdev);
  95        if (ret < 0) {
  96                printk(KERN_ERR "pcm3008: failed to register card\n");
  97                goto card_err;
  98        }
  99
 100        /* DEM1  DEM0  DE-EMPHASIS_MODE
 101         * Low   Low   De-emphasis 44.1 kHz ON
 102         * Low   High  De-emphasis OFF
 103         * High  Low   De-emphasis 48 kHz ON
 104         * High  High  De-emphasis 32 kHz ON
 105         */
 106
 107        /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
 108        ret = gpio_request(setup->dem0_pin, "codec_dem0");
 109        if (ret == 0)
 110                ret = gpio_direction_output(setup->dem0_pin, 1);
 111        if (ret != 0)
 112                goto gpio_err;
 113
 114        /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
 115        ret = gpio_request(setup->dem1_pin, "codec_dem1");
 116        if (ret == 0)
 117                ret = gpio_direction_output(setup->dem1_pin, 0);
 118        if (ret != 0)
 119                goto gpio_err;
 120
 121        /* Configure PDAD GPIO. */
 122        ret = gpio_request(setup->pdad_pin, "codec_pdad");
 123        if (ret == 0)
 124                ret = gpio_direction_output(setup->pdad_pin, 1);
 125        if (ret != 0)
 126                goto gpio_err;
 127
 128        /* Configure PDDA GPIO. */
 129        ret = gpio_request(setup->pdda_pin, "codec_pdda");
 130        if (ret == 0)
 131                ret = gpio_direction_output(setup->pdda_pin, 1);
 132        if (ret != 0)
 133                goto gpio_err;
 134
 135        return ret;
 136
 137gpio_err:
 138        pcm3008_gpio_free(setup);
 139card_err:
 140        snd_soc_free_pcms(socdev);
 141pcm_err:
 142        kfree(socdev->card->codec);
 143
 144        return ret;
 145}
 146
 147static int pcm3008_soc_remove(struct platform_device *pdev)
 148{
 149        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 150        struct snd_soc_codec *codec = socdev->card->codec;
 151        struct pcm3008_setup_data *setup = socdev->codec_data;
 152
 153        if (!codec)
 154                return 0;
 155
 156        pcm3008_gpio_free(setup);
 157        snd_soc_free_pcms(socdev);
 158        kfree(socdev->card->codec);
 159
 160        return 0;
 161}
 162
 163#ifdef CONFIG_PM
 164static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
 165{
 166        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 167        struct pcm3008_setup_data *setup = socdev->codec_data;
 168
 169        gpio_set_value(setup->pdad_pin, 0);
 170        gpio_set_value(setup->pdda_pin, 0);
 171
 172        return 0;
 173}
 174
 175static int pcm3008_soc_resume(struct platform_device *pdev)
 176{
 177        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 178        struct pcm3008_setup_data *setup = socdev->codec_data;
 179
 180        gpio_set_value(setup->pdad_pin, 1);
 181        gpio_set_value(setup->pdda_pin, 1);
 182
 183        return 0;
 184}
 185#else
 186#define pcm3008_soc_suspend NULL
 187#define pcm3008_soc_resume NULL
 188#endif
 189
 190struct snd_soc_codec_device soc_codec_dev_pcm3008 = {
 191        .probe =        pcm3008_soc_probe,
 192        .remove =       pcm3008_soc_remove,
 193        .suspend =      pcm3008_soc_suspend,
 194        .resume =       pcm3008_soc_resume,
 195};
 196EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008);
 197
 198static int __init pcm3008_init(void)
 199{
 200        return snd_soc_register_dai(&pcm3008_dai);
 201}
 202module_init(pcm3008_init);
 203
 204static void __exit pcm3008_exit(void)
 205{
 206        snd_soc_unregister_dai(&pcm3008_dai);
 207}
 208module_exit(pcm3008_exit);
 209
 210MODULE_DESCRIPTION("Soc PCM3008 driver");
 211MODULE_AUTHOR("Hugo Villeneuve");
 212MODULE_LICENSE("GPL");
 213