linux/sound/soc/codecs/pcm3008.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * ALSA Soc PCM3008 codec support
   4 *
   5 * Author:      Hugo Villeneuve
   6 * Copyright (C) 2008 Lyrtech inc
   7 *
   8 * Based on AC97 Soc codec, original copyright follow:
   9 * Copyright 2005 Wolfson Microelectronics PLC.
  10 *
  11 * Generic PCM3008 support.
  12 */
  13
  14#include <linux/init.h>
  15#include <linux/kernel.h>
  16#include <linux/device.h>
  17#include <linux/gpio.h>
  18#include <linux/slab.h>
  19#include <linux/module.h>
  20#include <sound/core.h>
  21#include <sound/pcm.h>
  22#include <sound/initval.h>
  23#include <sound/soc.h>
  24
  25#include "pcm3008.h"
  26
  27static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w,
  28                          struct snd_kcontrol *kcontrol,
  29                          int event)
  30{
  31        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
  32        struct pcm3008_setup_data *setup = component->dev->platform_data;
  33
  34        gpio_set_value_cansleep(setup->pdda_pin,
  35                                SND_SOC_DAPM_EVENT_ON(event));
  36
  37        return 0;
  38}
  39
  40static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w,
  41                          struct snd_kcontrol *kcontrol,
  42                          int event)
  43{
  44        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
  45        struct pcm3008_setup_data *setup = component->dev->platform_data;
  46
  47        gpio_set_value_cansleep(setup->pdad_pin,
  48                                SND_SOC_DAPM_EVENT_ON(event));
  49
  50        return 0;
  51}
  52
  53static const struct snd_soc_dapm_widget pcm3008_dapm_widgets[] = {
  54SND_SOC_DAPM_INPUT("VINL"),
  55SND_SOC_DAPM_INPUT("VINR"),
  56
  57SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_dac_ev,
  58                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
  59SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_adc_ev,
  60                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
  61
  62SND_SOC_DAPM_OUTPUT("VOUTL"),
  63SND_SOC_DAPM_OUTPUT("VOUTR"),
  64};
  65
  66static const struct snd_soc_dapm_route pcm3008_dapm_routes[] = {
  67        { "PCM3008 Capture", NULL, "ADC" },
  68        { "ADC", NULL, "VINL" },
  69        { "ADC", NULL, "VINR" },
  70
  71        { "DAC", NULL, "PCM3008 Playback" },
  72        { "VOUTL", NULL, "DAC" },
  73        { "VOUTR", NULL, "DAC" },
  74};
  75
  76#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |    \
  77                       SNDRV_PCM_RATE_48000)
  78
  79static struct snd_soc_dai_driver pcm3008_dai = {
  80        .name = "pcm3008-hifi",
  81        .playback = {
  82                .stream_name = "PCM3008 Playback",
  83                .channels_min = 1,
  84                .channels_max = 2,
  85                .rates = PCM3008_RATES,
  86                .formats = SNDRV_PCM_FMTBIT_S16_LE,
  87        },
  88        .capture = {
  89                .stream_name = "PCM3008 Capture",
  90                .channels_min = 1,
  91                .channels_max = 2,
  92                .rates = PCM3008_RATES,
  93                .formats = SNDRV_PCM_FMTBIT_S16_LE,
  94        },
  95};
  96
  97static const struct snd_soc_component_driver soc_component_dev_pcm3008 = {
  98        .dapm_widgets           = pcm3008_dapm_widgets,
  99        .num_dapm_widgets       = ARRAY_SIZE(pcm3008_dapm_widgets),
 100        .dapm_routes            = pcm3008_dapm_routes,
 101        .num_dapm_routes        = ARRAY_SIZE(pcm3008_dapm_routes),
 102        .idle_bias_on           = 1,
 103        .use_pmdown_time        = 1,
 104        .endianness             = 1,
 105        .non_legacy_dai_naming  = 1,
 106};
 107
 108static int pcm3008_codec_probe(struct platform_device *pdev)
 109{
 110        struct pcm3008_setup_data *setup = pdev->dev.platform_data;
 111        int ret;
 112
 113        if (!setup)
 114                return -EINVAL;
 115
 116        /* DEM1  DEM0  DE-EMPHASIS_MODE
 117         * Low   Low   De-emphasis 44.1 kHz ON
 118         * Low   High  De-emphasis OFF
 119         * High  Low   De-emphasis 48 kHz ON
 120         * High  High  De-emphasis 32 kHz ON
 121         */
 122
 123        /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
 124        ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin,
 125                                    GPIOF_OUT_INIT_HIGH, "codec_dem0");
 126        if (ret != 0)
 127                return ret;
 128
 129        /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
 130        ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin,
 131                                    GPIOF_OUT_INIT_LOW, "codec_dem1");
 132        if (ret != 0)
 133                return ret;
 134
 135        /* Configure PDAD GPIO. */
 136        ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin,
 137                                    GPIOF_OUT_INIT_LOW, "codec_pdad");
 138        if (ret != 0)
 139                return ret;
 140
 141        /* Configure PDDA GPIO. */
 142        ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin,
 143                                    GPIOF_OUT_INIT_LOW, "codec_pdda");
 144        if (ret != 0)
 145                return ret;
 146
 147        return devm_snd_soc_register_component(&pdev->dev,
 148                        &soc_component_dev_pcm3008, &pcm3008_dai, 1);
 149}
 150
 151MODULE_ALIAS("platform:pcm3008-codec");
 152
 153static struct platform_driver pcm3008_codec_driver = {
 154        .probe          = pcm3008_codec_probe,
 155        .driver         = {
 156                .name   = "pcm3008-codec",
 157        },
 158};
 159
 160module_platform_driver(pcm3008_codec_driver);
 161
 162MODULE_DESCRIPTION("Soc PCM3008 driver");
 163MODULE_AUTHOR("Hugo Villeneuve");
 164MODULE_LICENSE("GPL");
 165