root/sound/soc/pxa/poodle.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. poodle_ext_control
  2. poodle_startup
  3. poodle_shutdown
  4. poodle_hw_params
  5. poodle_get_jack
  6. poodle_set_jack
  7. poodle_get_spk
  8. poodle_set_spk
  9. poodle_amp_event
  10. poodle_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * poodle.c  --  SoC audio for Poodle
   4  *
   5  * Copyright 2005 Wolfson Microelectronics PLC.
   6  * Copyright 2005 Openedhand Ltd.
   7  *
   8  * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
   9  *          Richard Purdie <richard@openedhand.com>
  10  */
  11 
  12 #include <linux/module.h>
  13 #include <linux/moduleparam.h>
  14 #include <linux/timer.h>
  15 #include <linux/i2c.h>
  16 #include <linux/interrupt.h>
  17 #include <linux/platform_device.h>
  18 #include <sound/core.h>
  19 #include <sound/pcm.h>
  20 #include <sound/soc.h>
  21 
  22 #include <asm/mach-types.h>
  23 #include <asm/hardware/locomo.h>
  24 #include <mach/poodle.h>
  25 #include <mach/audio.h>
  26 
  27 #include "../codecs/wm8731.h"
  28 #include "pxa2xx-i2s.h"
  29 
  30 #define POODLE_HP        1
  31 #define POODLE_HP_OFF    0
  32 #define POODLE_SPK_ON    1
  33 #define POODLE_SPK_OFF   0
  34 
  35  /* audio clock in Hz - rounded from 12.235MHz */
  36 #define POODLE_AUDIO_CLOCK 12288000
  37 
  38 static int poodle_jack_func;
  39 static int poodle_spk_func;
  40 
  41 static void poodle_ext_control(struct snd_soc_dapm_context *dapm)
  42 {
  43         /* set up jack connection */
  44         if (poodle_jack_func == POODLE_HP) {
  45                 /* set = unmute headphone */
  46                 locomo_gpio_write(&poodle_locomo_device.dev,
  47                         POODLE_LOCOMO_GPIO_MUTE_L, 1);
  48                 locomo_gpio_write(&poodle_locomo_device.dev,
  49                         POODLE_LOCOMO_GPIO_MUTE_R, 1);
  50                 snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
  51         } else {
  52                 locomo_gpio_write(&poodle_locomo_device.dev,
  53                         POODLE_LOCOMO_GPIO_MUTE_L, 0);
  54                 locomo_gpio_write(&poodle_locomo_device.dev,
  55                         POODLE_LOCOMO_GPIO_MUTE_R, 0);
  56                 snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
  57         }
  58 
  59         /* set the enpoints to their new connetion states */
  60         if (poodle_spk_func == POODLE_SPK_ON)
  61                 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
  62         else
  63                 snd_soc_dapm_disable_pin(dapm, "Ext Spk");
  64 
  65         /* signal a DAPM event */
  66         snd_soc_dapm_sync(dapm);
  67 }
  68 
  69 static int poodle_startup(struct snd_pcm_substream *substream)
  70 {
  71         struct snd_soc_pcm_runtime *rtd = substream->private_data;
  72 
  73         /* check the jack status at stream startup */
  74         poodle_ext_control(&rtd->card->dapm);
  75 
  76         return 0;
  77 }
  78 
  79 /* we need to unmute the HP at shutdown as the mute burns power on poodle */
  80 static void poodle_shutdown(struct snd_pcm_substream *substream)
  81 {
  82         /* set = unmute headphone */
  83         locomo_gpio_write(&poodle_locomo_device.dev,
  84                 POODLE_LOCOMO_GPIO_MUTE_L, 1);
  85         locomo_gpio_write(&poodle_locomo_device.dev,
  86                 POODLE_LOCOMO_GPIO_MUTE_R, 1);
  87 }
  88 
  89 static int poodle_hw_params(struct snd_pcm_substream *substream,
  90         struct snd_pcm_hw_params *params)
  91 {
  92         struct snd_soc_pcm_runtime *rtd = substream->private_data;
  93         struct snd_soc_dai *codec_dai = rtd->codec_dai;
  94         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  95         unsigned int clk = 0;
  96         int ret = 0;
  97 
  98         switch (params_rate(params)) {
  99         case 8000:
 100         case 16000:
 101         case 48000:
 102         case 96000:
 103                 clk = 12288000;
 104                 break;
 105         case 11025:
 106         case 22050:
 107         case 44100:
 108                 clk = 11289600;
 109                 break;
 110         }
 111 
 112         /* set the codec system clock for DAC and ADC */
 113         ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
 114                 SND_SOC_CLOCK_IN);
 115         if (ret < 0)
 116                 return ret;
 117 
 118         /* set the I2S system clock as input (unused) */
 119         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
 120                 SND_SOC_CLOCK_IN);
 121         if (ret < 0)
 122                 return ret;
 123 
 124         return 0;
 125 }
 126 
 127 static const struct snd_soc_ops poodle_ops = {
 128         .startup = poodle_startup,
 129         .hw_params = poodle_hw_params,
 130         .shutdown = poodle_shutdown,
 131 };
 132 
 133 static int poodle_get_jack(struct snd_kcontrol *kcontrol,
 134         struct snd_ctl_elem_value *ucontrol)
 135 {
 136         ucontrol->value.enumerated.item[0] = poodle_jack_func;
 137         return 0;
 138 }
 139 
 140 static int poodle_set_jack(struct snd_kcontrol *kcontrol,
 141         struct snd_ctl_elem_value *ucontrol)
 142 {
 143         struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 144 
 145         if (poodle_jack_func == ucontrol->value.enumerated.item[0])
 146                 return 0;
 147 
 148         poodle_jack_func = ucontrol->value.enumerated.item[0];
 149         poodle_ext_control(&card->dapm);
 150         return 1;
 151 }
 152 
 153 static int poodle_get_spk(struct snd_kcontrol *kcontrol,
 154         struct snd_ctl_elem_value *ucontrol)
 155 {
 156         ucontrol->value.enumerated.item[0] = poodle_spk_func;
 157         return 0;
 158 }
 159 
 160 static int poodle_set_spk(struct snd_kcontrol *kcontrol,
 161         struct snd_ctl_elem_value *ucontrol)
 162 {
 163         struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 164 
 165         if (poodle_spk_func == ucontrol->value.enumerated.item[0])
 166                 return 0;
 167 
 168         poodle_spk_func = ucontrol->value.enumerated.item[0];
 169         poodle_ext_control(&card->dapm);
 170         return 1;
 171 }
 172 
 173 static int poodle_amp_event(struct snd_soc_dapm_widget *w,
 174         struct snd_kcontrol *k, int event)
 175 {
 176         if (SND_SOC_DAPM_EVENT_ON(event))
 177                 locomo_gpio_write(&poodle_locomo_device.dev,
 178                         POODLE_LOCOMO_GPIO_AMP_ON, 0);
 179         else
 180                 locomo_gpio_write(&poodle_locomo_device.dev,
 181                         POODLE_LOCOMO_GPIO_AMP_ON, 1);
 182 
 183         return 0;
 184 }
 185 
 186 /* poodle machine dapm widgets */
 187 static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
 188 SND_SOC_DAPM_HP("Headphone Jack", NULL),
 189 SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
 190 SND_SOC_DAPM_MIC("Microphone", NULL),
 191 };
 192 
 193 /* Corgi machine connections to the codec pins */
 194 static const struct snd_soc_dapm_route poodle_audio_map[] = {
 195 
 196         /* headphone connected to LHPOUT1, RHPOUT1 */
 197         {"Headphone Jack", NULL, "LHPOUT"},
 198         {"Headphone Jack", NULL, "RHPOUT"},
 199 
 200         /* speaker connected to LOUT, ROUT */
 201         {"Ext Spk", NULL, "ROUT"},
 202         {"Ext Spk", NULL, "LOUT"},
 203 
 204         {"MICIN", NULL, "Microphone"},
 205 };
 206 
 207 static const char * const jack_function[] = {"Off", "Headphone"};
 208 static const char * const spk_function[] = {"Off", "On"};
 209 static const struct soc_enum poodle_enum[] = {
 210         SOC_ENUM_SINGLE_EXT(2, jack_function),
 211         SOC_ENUM_SINGLE_EXT(2, spk_function),
 212 };
 213 
 214 static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
 215         SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack,
 216                 poodle_set_jack),
 217         SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk,
 218                 poodle_set_spk),
 219 };
 220 
 221 /* poodle digital audio interface glue - connects codec <--> CPU */
 222 SND_SOC_DAILINK_DEFS(wm8731,
 223         DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
 224         DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.0-001b", "wm8731-hifi")),
 225         DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
 226 
 227 static struct snd_soc_dai_link poodle_dai = {
 228         .name = "WM8731",
 229         .stream_name = "WM8731",
 230         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 231                    SND_SOC_DAIFMT_CBS_CFS,
 232         .ops = &poodle_ops,
 233         SND_SOC_DAILINK_REG(wm8731),
 234 };
 235 
 236 /* poodle audio machine driver */
 237 static struct snd_soc_card poodle = {
 238         .name = "Poodle",
 239         .dai_link = &poodle_dai,
 240         .num_links = 1,
 241         .owner = THIS_MODULE,
 242 
 243         .controls = wm8731_poodle_controls,
 244         .num_controls = ARRAY_SIZE(wm8731_poodle_controls),
 245         .dapm_widgets = wm8731_dapm_widgets,
 246         .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
 247         .dapm_routes = poodle_audio_map,
 248         .num_dapm_routes = ARRAY_SIZE(poodle_audio_map),
 249         .fully_routed = true,
 250 };
 251 
 252 static int poodle_probe(struct platform_device *pdev)
 253 {
 254         struct snd_soc_card *card = &poodle;
 255         int ret;
 256 
 257         locomo_gpio_set_dir(&poodle_locomo_device.dev,
 258                 POODLE_LOCOMO_GPIO_AMP_ON, 0);
 259         /* should we mute HP at startup - burning power ?*/
 260         locomo_gpio_set_dir(&poodle_locomo_device.dev,
 261                 POODLE_LOCOMO_GPIO_MUTE_L, 0);
 262         locomo_gpio_set_dir(&poodle_locomo_device.dev,
 263                 POODLE_LOCOMO_GPIO_MUTE_R, 0);
 264 
 265         card->dev = &pdev->dev;
 266 
 267         ret = devm_snd_soc_register_card(&pdev->dev, card);
 268         if (ret)
 269                 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 270                         ret);
 271         return ret;
 272 }
 273 
 274 static struct platform_driver poodle_driver = {
 275         .driver         = {
 276                 .name   = "poodle-audio",
 277                 .pm     = &snd_soc_pm_ops,
 278         },
 279         .probe          = poodle_probe,
 280 };
 281 
 282 module_platform_driver(poodle_driver);
 283 
 284 /* Module information */
 285 MODULE_AUTHOR("Richard Purdie");
 286 MODULE_DESCRIPTION("ALSA SoC Poodle");
 287 MODULE_LICENSE("GPL");
 288 MODULE_ALIAS("platform:poodle-audio");

/* [<][>][^][v][top][bottom][index][help] */