root/sound/soc/pxa/corgi.c

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

DEFINITIONS

This source file includes following definitions.
  1. corgi_ext_control
  2. corgi_startup
  3. corgi_shutdown
  4. corgi_hw_params
  5. corgi_get_jack
  6. corgi_set_jack
  7. corgi_get_spk
  8. corgi_set_spk
  9. corgi_amp_event
  10. corgi_mic_event
  11. corgi_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * corgi.c  --  SoC audio for Corgi
   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 <linux/gpio.h>
  19 #include <sound/core.h>
  20 #include <sound/pcm.h>
  21 #include <sound/soc.h>
  22 
  23 #include <asm/mach-types.h>
  24 #include <mach/corgi.h>
  25 #include <mach/audio.h>
  26 
  27 #include "../codecs/wm8731.h"
  28 #include "pxa2xx-i2s.h"
  29 
  30 #define CORGI_HP        0
  31 #define CORGI_MIC       1
  32 #define CORGI_LINE      2
  33 #define CORGI_HEADSET   3
  34 #define CORGI_HP_OFF    4
  35 #define CORGI_SPK_ON    0
  36 #define CORGI_SPK_OFF   1
  37 
  38  /* audio clock in Hz - rounded from 12.235MHz */
  39 #define CORGI_AUDIO_CLOCK 12288000
  40 
  41 static int corgi_jack_func;
  42 static int corgi_spk_func;
  43 
  44 static void corgi_ext_control(struct snd_soc_dapm_context *dapm)
  45 {
  46         snd_soc_dapm_mutex_lock(dapm);
  47 
  48         /* set up jack connection */
  49         switch (corgi_jack_func) {
  50         case CORGI_HP:
  51                 /* set = unmute headphone */
  52                 gpio_set_value(CORGI_GPIO_MUTE_L, 1);
  53                 gpio_set_value(CORGI_GPIO_MUTE_R, 1);
  54                 snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
  55                 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
  56                 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
  57                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
  58                 break;
  59         case CORGI_MIC:
  60                 /* reset = mute headphone */
  61                 gpio_set_value(CORGI_GPIO_MUTE_L, 0);
  62                 gpio_set_value(CORGI_GPIO_MUTE_R, 0);
  63                 snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
  64                 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
  65                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
  66                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
  67                 break;
  68         case CORGI_LINE:
  69                 gpio_set_value(CORGI_GPIO_MUTE_L, 0);
  70                 gpio_set_value(CORGI_GPIO_MUTE_R, 0);
  71                 snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
  72                 snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
  73                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
  74                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
  75                 break;
  76         case CORGI_HEADSET:
  77                 gpio_set_value(CORGI_GPIO_MUTE_L, 0);
  78                 gpio_set_value(CORGI_GPIO_MUTE_R, 1);
  79                 snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
  80                 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
  81                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
  82                 snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
  83                 break;
  84         }
  85 
  86         if (corgi_spk_func == CORGI_SPK_ON)
  87                 snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
  88         else
  89                 snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
  90 
  91         /* signal a DAPM event */
  92         snd_soc_dapm_sync_unlocked(dapm);
  93 
  94         snd_soc_dapm_mutex_unlock(dapm);
  95 }
  96 
  97 static int corgi_startup(struct snd_pcm_substream *substream)
  98 {
  99         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 100 
 101         /* check the jack status at stream startup */
 102         corgi_ext_control(&rtd->card->dapm);
 103 
 104         return 0;
 105 }
 106 
 107 /* we need to unmute the HP at shutdown as the mute burns power on corgi */
 108 static void corgi_shutdown(struct snd_pcm_substream *substream)
 109 {
 110         /* set = unmute headphone */
 111         gpio_set_value(CORGI_GPIO_MUTE_L, 1);
 112         gpio_set_value(CORGI_GPIO_MUTE_R, 1);
 113 }
 114 
 115 static int corgi_hw_params(struct snd_pcm_substream *substream,
 116         struct snd_pcm_hw_params *params)
 117 {
 118         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 119         struct snd_soc_dai *codec_dai = rtd->codec_dai;
 120         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 121         unsigned int clk = 0;
 122         int ret = 0;
 123 
 124         switch (params_rate(params)) {
 125         case 8000:
 126         case 16000:
 127         case 48000:
 128         case 96000:
 129                 clk = 12288000;
 130                 break;
 131         case 11025:
 132         case 22050:
 133         case 44100:
 134                 clk = 11289600;
 135                 break;
 136         }
 137 
 138         /* set the codec system clock for DAC and ADC */
 139         ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
 140                 SND_SOC_CLOCK_IN);
 141         if (ret < 0)
 142                 return ret;
 143 
 144         /* set the I2S system clock as input (unused) */
 145         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
 146                 SND_SOC_CLOCK_IN);
 147         if (ret < 0)
 148                 return ret;
 149 
 150         return 0;
 151 }
 152 
 153 static const struct snd_soc_ops corgi_ops = {
 154         .startup = corgi_startup,
 155         .hw_params = corgi_hw_params,
 156         .shutdown = corgi_shutdown,
 157 };
 158 
 159 static int corgi_get_jack(struct snd_kcontrol *kcontrol,
 160         struct snd_ctl_elem_value *ucontrol)
 161 {
 162         ucontrol->value.enumerated.item[0] = corgi_jack_func;
 163         return 0;
 164 }
 165 
 166 static int corgi_set_jack(struct snd_kcontrol *kcontrol,
 167         struct snd_ctl_elem_value *ucontrol)
 168 {
 169         struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
 170 
 171         if (corgi_jack_func == ucontrol->value.enumerated.item[0])
 172                 return 0;
 173 
 174         corgi_jack_func = ucontrol->value.enumerated.item[0];
 175         corgi_ext_control(&card->dapm);
 176         return 1;
 177 }
 178 
 179 static int corgi_get_spk(struct snd_kcontrol *kcontrol,
 180         struct snd_ctl_elem_value *ucontrol)
 181 {
 182         ucontrol->value.enumerated.item[0] = corgi_spk_func;
 183         return 0;
 184 }
 185 
 186 static int corgi_set_spk(struct snd_kcontrol *kcontrol,
 187         struct snd_ctl_elem_value *ucontrol)
 188 {
 189         struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 190 
 191         if (corgi_spk_func == ucontrol->value.enumerated.item[0])
 192                 return 0;
 193 
 194         corgi_spk_func = ucontrol->value.enumerated.item[0];
 195         corgi_ext_control(&card->dapm);
 196         return 1;
 197 }
 198 
 199 static int corgi_amp_event(struct snd_soc_dapm_widget *w,
 200         struct snd_kcontrol *k, int event)
 201 {
 202         gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event));
 203         return 0;
 204 }
 205 
 206 static int corgi_mic_event(struct snd_soc_dapm_widget *w,
 207         struct snd_kcontrol *k, int event)
 208 {
 209         gpio_set_value(CORGI_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event));
 210         return 0;
 211 }
 212 
 213 /* corgi machine dapm widgets */
 214 static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
 215 SND_SOC_DAPM_HP("Headphone Jack", NULL),
 216 SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event),
 217 SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event),
 218 SND_SOC_DAPM_LINE("Line Jack", NULL),
 219 SND_SOC_DAPM_HP("Headset Jack", NULL),
 220 };
 221 
 222 /* Corgi machine audio map (connections to the codec pins) */
 223 static const struct snd_soc_dapm_route corgi_audio_map[] = {
 224 
 225         /* headset Jack  - in = micin, out = LHPOUT*/
 226         {"Headset Jack", NULL, "LHPOUT"},
 227 
 228         /* headphone connected to LHPOUT1, RHPOUT1 */
 229         {"Headphone Jack", NULL, "LHPOUT"},
 230         {"Headphone Jack", NULL, "RHPOUT"},
 231 
 232         /* speaker connected to LOUT, ROUT */
 233         {"Ext Spk", NULL, "ROUT"},
 234         {"Ext Spk", NULL, "LOUT"},
 235 
 236         /* mic is connected to MICIN (via right channel of headphone jack) */
 237         {"MICIN", NULL, "Mic Jack"},
 238 
 239         /* Same as the above but no mic bias for line signals */
 240         {"MICIN", NULL, "Line Jack"},
 241 };
 242 
 243 static const char * const jack_function[] = {"Headphone", "Mic", "Line",
 244         "Headset", "Off"};
 245 static const char * const spk_function[] = {"On", "Off"};
 246 static const struct soc_enum corgi_enum[] = {
 247         SOC_ENUM_SINGLE_EXT(5, jack_function),
 248         SOC_ENUM_SINGLE_EXT(2, spk_function),
 249 };
 250 
 251 static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
 252         SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack,
 253                 corgi_set_jack),
 254         SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk,
 255                 corgi_set_spk),
 256 };
 257 
 258 /* corgi digital audio interface glue - connects codec <--> CPU */
 259 SND_SOC_DAILINK_DEFS(wm8731,
 260         DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
 261         DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.0-001b", "wm8731-hifi")),
 262         DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
 263 
 264 static struct snd_soc_dai_link corgi_dai = {
 265         .name = "WM8731",
 266         .stream_name = "WM8731",
 267         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 268                    SND_SOC_DAIFMT_CBS_CFS,
 269         .ops = &corgi_ops,
 270         SND_SOC_DAILINK_REG(wm8731),
 271 };
 272 
 273 /* corgi audio machine driver */
 274 static struct snd_soc_card corgi = {
 275         .name = "Corgi",
 276         .owner = THIS_MODULE,
 277         .dai_link = &corgi_dai,
 278         .num_links = 1,
 279 
 280         .controls = wm8731_corgi_controls,
 281         .num_controls = ARRAY_SIZE(wm8731_corgi_controls),
 282         .dapm_widgets = wm8731_dapm_widgets,
 283         .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
 284         .dapm_routes = corgi_audio_map,
 285         .num_dapm_routes = ARRAY_SIZE(corgi_audio_map),
 286         .fully_routed = true,
 287 };
 288 
 289 static int corgi_probe(struct platform_device *pdev)
 290 {
 291         struct snd_soc_card *card = &corgi;
 292         int ret;
 293 
 294         card->dev = &pdev->dev;
 295 
 296         ret = devm_snd_soc_register_card(&pdev->dev, card);
 297         if (ret)
 298                 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 299                         ret);
 300         return ret;
 301 }
 302 
 303 static struct platform_driver corgi_driver = {
 304         .driver         = {
 305                 .name   = "corgi-audio",
 306                 .pm     = &snd_soc_pm_ops,
 307         },
 308         .probe          = corgi_probe,
 309 };
 310 
 311 module_platform_driver(corgi_driver);
 312 
 313 /* Module information */
 314 MODULE_AUTHOR("Richard Purdie");
 315 MODULE_DESCRIPTION("ALSA SoC Corgi");
 316 MODULE_LICENSE("GPL");
 317 MODULE_ALIAS("platform:corgi-audio");

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