root/sound/soc/pxa/spitz.c

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

DEFINITIONS

This source file includes following definitions.
  1. spitz_ext_control
  2. spitz_startup
  3. spitz_hw_params
  4. spitz_get_jack
  5. spitz_set_jack
  6. spitz_get_spk
  7. spitz_set_spk
  8. spitz_mic_bias
  9. spitz_probe
  10. spitz_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * spitz.c  --  SoC audio for Sharp SL-Cxx00 models Spitz, Borzoi and Akita
   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/interrupt.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/gpio.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 <mach/spitz.h>
  24 #include "../codecs/wm8750.h"
  25 #include "pxa2xx-i2s.h"
  26 
  27 #define SPITZ_HP        0
  28 #define SPITZ_MIC       1
  29 #define SPITZ_LINE      2
  30 #define SPITZ_HEADSET   3
  31 #define SPITZ_HP_OFF    4
  32 #define SPITZ_SPK_ON    0
  33 #define SPITZ_SPK_OFF   1
  34 
  35  /* audio clock in Hz - rounded from 12.235MHz */
  36 #define SPITZ_AUDIO_CLOCK 12288000
  37 
  38 static int spitz_jack_func;
  39 static int spitz_spk_func;
  40 static int spitz_mic_gpio;
  41 
  42 static void spitz_ext_control(struct snd_soc_dapm_context *dapm)
  43 {
  44         snd_soc_dapm_mutex_lock(dapm);
  45 
  46         if (spitz_spk_func == SPITZ_SPK_ON)
  47                 snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
  48         else
  49                 snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
  50 
  51         /* set up jack connection */
  52         switch (spitz_jack_func) {
  53         case SPITZ_HP:
  54                 /* enable and unmute hp jack, disable mic bias */
  55                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
  56                 snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
  57                 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
  58                 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
  59                 gpio_set_value(SPITZ_GPIO_MUTE_L, 1);
  60                 gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
  61                 break;
  62         case SPITZ_MIC:
  63                 /* enable mic jack and bias, mute hp */
  64                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
  65                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
  66                 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
  67                 snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
  68                 gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
  69                 gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
  70                 break;
  71         case SPITZ_LINE:
  72                 /* enable line jack, disable mic bias and mute hp */
  73                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
  74                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
  75                 snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
  76                 snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
  77                 gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
  78                 gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
  79                 break;
  80         case SPITZ_HEADSET:
  81                 /* enable and unmute headset jack enable mic bias, mute L hp */
  82                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
  83                 snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
  84                 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
  85                 snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
  86                 gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
  87                 gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
  88                 break;
  89         case SPITZ_HP_OFF:
  90 
  91                 /* jack removed, everything off */
  92                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
  93                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
  94                 snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
  95                 snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
  96                 gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
  97                 gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
  98                 break;
  99         }
 100 
 101         snd_soc_dapm_sync_unlocked(dapm);
 102 
 103         snd_soc_dapm_mutex_unlock(dapm);
 104 }
 105 
 106 static int spitz_startup(struct snd_pcm_substream *substream)
 107 {
 108         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 109 
 110         /* check the jack status at stream startup */
 111         spitz_ext_control(&rtd->card->dapm);
 112 
 113         return 0;
 114 }
 115 
 116 static int spitz_hw_params(struct snd_pcm_substream *substream,
 117         struct snd_pcm_hw_params *params)
 118 {
 119         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 120         struct snd_soc_dai *codec_dai = rtd->codec_dai;
 121         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 122         unsigned int clk = 0;
 123         int ret = 0;
 124 
 125         switch (params_rate(params)) {
 126         case 8000:
 127         case 16000:
 128         case 48000:
 129         case 96000:
 130                 clk = 12288000;
 131                 break;
 132         case 11025:
 133         case 22050:
 134         case 44100:
 135                 clk = 11289600;
 136                 break;
 137         }
 138 
 139         /* set the codec system clock for DAC and ADC */
 140         ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
 141                 SND_SOC_CLOCK_IN);
 142         if (ret < 0)
 143                 return ret;
 144 
 145         /* set the I2S system clock as input (unused) */
 146         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
 147                 SND_SOC_CLOCK_IN);
 148         if (ret < 0)
 149                 return ret;
 150 
 151         return 0;
 152 }
 153 
 154 static const struct snd_soc_ops spitz_ops = {
 155         .startup = spitz_startup,
 156         .hw_params = spitz_hw_params,
 157 };
 158 
 159 static int spitz_get_jack(struct snd_kcontrol *kcontrol,
 160         struct snd_ctl_elem_value *ucontrol)
 161 {
 162         ucontrol->value.enumerated.item[0] = spitz_jack_func;
 163         return 0;
 164 }
 165 
 166 static int spitz_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 (spitz_jack_func == ucontrol->value.enumerated.item[0])
 172                 return 0;
 173 
 174         spitz_jack_func = ucontrol->value.enumerated.item[0];
 175         spitz_ext_control(&card->dapm);
 176         return 1;
 177 }
 178 
 179 static int spitz_get_spk(struct snd_kcontrol *kcontrol,
 180         struct snd_ctl_elem_value *ucontrol)
 181 {
 182         ucontrol->value.enumerated.item[0] = spitz_spk_func;
 183         return 0;
 184 }
 185 
 186 static int spitz_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 (spitz_spk_func == ucontrol->value.enumerated.item[0])
 192                 return 0;
 193 
 194         spitz_spk_func = ucontrol->value.enumerated.item[0];
 195         spitz_ext_control(&card->dapm);
 196         return 1;
 197 }
 198 
 199 static int spitz_mic_bias(struct snd_soc_dapm_widget *w,
 200         struct snd_kcontrol *k, int event)
 201 {
 202         gpio_set_value_cansleep(spitz_mic_gpio, SND_SOC_DAPM_EVENT_ON(event));
 203         return 0;
 204 }
 205 
 206 /* spitz machine dapm widgets */
 207 static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
 208         SND_SOC_DAPM_HP("Headphone Jack", NULL),
 209         SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
 210         SND_SOC_DAPM_SPK("Ext Spk", NULL),
 211         SND_SOC_DAPM_LINE("Line Jack", NULL),
 212 
 213         /* headset is a mic and mono headphone */
 214         SND_SOC_DAPM_HP("Headset Jack", NULL),
 215 };
 216 
 217 /* Spitz machine audio_map */
 218 static const struct snd_soc_dapm_route spitz_audio_map[] = {
 219 
 220         /* headphone connected to LOUT1, ROUT1 */
 221         {"Headphone Jack", NULL, "LOUT1"},
 222         {"Headphone Jack", NULL, "ROUT1"},
 223 
 224         /* headset connected to ROUT1 and LINPUT1 with bias (def below) */
 225         {"Headset Jack", NULL, "ROUT1"},
 226 
 227         /* ext speaker connected to LOUT2, ROUT2  */
 228         {"Ext Spk", NULL, "ROUT2"},
 229         {"Ext Spk", NULL, "LOUT2"},
 230 
 231         /* mic is connected to input 1 - with bias */
 232         {"LINPUT1", NULL, "Mic Bias"},
 233         {"Mic Bias", NULL, "Mic Jack"},
 234 
 235         /* line is connected to input 1 - no bias */
 236         {"LINPUT1", NULL, "Line Jack"},
 237 };
 238 
 239 static const char * const jack_function[] = {"Headphone", "Mic", "Line",
 240         "Headset", "Off"};
 241 static const char * const spk_function[] = {"On", "Off"};
 242 static const struct soc_enum spitz_enum[] = {
 243         SOC_ENUM_SINGLE_EXT(5, jack_function),
 244         SOC_ENUM_SINGLE_EXT(2, spk_function),
 245 };
 246 
 247 static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
 248         SOC_ENUM_EXT("Jack Function", spitz_enum[0], spitz_get_jack,
 249                 spitz_set_jack),
 250         SOC_ENUM_EXT("Speaker Function", spitz_enum[1], spitz_get_spk,
 251                 spitz_set_spk),
 252 };
 253 
 254 /* spitz digital audio interface glue - connects codec <--> CPU */
 255 SND_SOC_DAILINK_DEFS(wm8750,
 256         DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
 257         DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001b", "wm8750-hifi")),
 258         DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
 259 
 260 static struct snd_soc_dai_link spitz_dai = {
 261         .name = "wm8750",
 262         .stream_name = "WM8750",
 263         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 264                    SND_SOC_DAIFMT_CBS_CFS,
 265         .ops = &spitz_ops,
 266         SND_SOC_DAILINK_REG(wm8750),
 267 };
 268 
 269 /* spitz audio machine driver */
 270 static struct snd_soc_card snd_soc_spitz = {
 271         .name = "Spitz",
 272         .owner = THIS_MODULE,
 273         .dai_link = &spitz_dai,
 274         .num_links = 1,
 275 
 276         .controls = wm8750_spitz_controls,
 277         .num_controls = ARRAY_SIZE(wm8750_spitz_controls),
 278         .dapm_widgets = wm8750_dapm_widgets,
 279         .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
 280         .dapm_routes = spitz_audio_map,
 281         .num_dapm_routes = ARRAY_SIZE(spitz_audio_map),
 282         .fully_routed = true,
 283 };
 284 
 285 static int spitz_probe(struct platform_device *pdev)
 286 {
 287         struct snd_soc_card *card = &snd_soc_spitz;
 288         int ret;
 289 
 290         if (machine_is_akita())
 291                 spitz_mic_gpio = AKITA_GPIO_MIC_BIAS;
 292         else
 293                 spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS;
 294 
 295         ret = gpio_request(spitz_mic_gpio, "MIC GPIO");
 296         if (ret)
 297                 goto err1;
 298 
 299         ret = gpio_direction_output(spitz_mic_gpio, 0);
 300         if (ret)
 301                 goto err2;
 302 
 303         card->dev = &pdev->dev;
 304 
 305         ret = devm_snd_soc_register_card(&pdev->dev, card);
 306         if (ret) {
 307                 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
 308                         ret);
 309                 goto err2;
 310         }
 311 
 312         return 0;
 313 
 314 err2:
 315         gpio_free(spitz_mic_gpio);
 316 err1:
 317         return ret;
 318 }
 319 
 320 static int spitz_remove(struct platform_device *pdev)
 321 {
 322         gpio_free(spitz_mic_gpio);
 323         return 0;
 324 }
 325 
 326 static struct platform_driver spitz_driver = {
 327         .driver         = {
 328                 .name   = "spitz-audio",
 329                 .pm     = &snd_soc_pm_ops,
 330         },
 331         .probe          = spitz_probe,
 332         .remove         = spitz_remove,
 333 };
 334 
 335 module_platform_driver(spitz_driver);
 336 
 337 MODULE_AUTHOR("Richard Purdie");
 338 MODULE_DESCRIPTION("ALSA SoC Spitz");
 339 MODULE_LICENSE("GPL");
 340 MODULE_ALIAS("platform:spitz-audio");

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