root/sound/soc/ti/n810.c

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

DEFINITIONS

This source file includes following definitions.
  1. n810_ext_control
  2. n810_startup
  3. n810_shutdown
  4. n810_hw_params
  5. n810_get_spk
  6. n810_set_spk
  7. n810_get_jack
  8. n810_set_jack
  9. n810_get_input
  10. n810_set_input
  11. n810_spk_event
  12. n810_jack_event
  13. n810_soc_init
  14. n810_soc_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * n810.c  --  SoC audio for Nokia N810
   4  *
   5  * Copyright (C) 2008 Nokia Corporation
   6  *
   7  * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
   8  */
   9 
  10 #include <linux/clk.h>
  11 #include <linux/i2c.h>
  12 #include <linux/platform_device.h>
  13 #include <sound/core.h>
  14 #include <sound/pcm.h>
  15 #include <sound/soc.h>
  16 
  17 #include <asm/mach-types.h>
  18 #include <linux/gpio.h>
  19 #include <linux/module.h>
  20 #include <linux/platform_data/asoc-ti-mcbsp.h>
  21 
  22 #include "omap-mcbsp.h"
  23 
  24 #define N810_HEADSET_AMP_GPIO   10
  25 #define N810_SPEAKER_AMP_GPIO   101
  26 
  27 enum {
  28         N810_JACK_DISABLED,
  29         N810_JACK_HP,
  30         N810_JACK_HS,
  31         N810_JACK_MIC,
  32 };
  33 
  34 static struct clk *sys_clkout2;
  35 static struct clk *sys_clkout2_src;
  36 static struct clk *func96m_clk;
  37 
  38 static int n810_spk_func;
  39 static int n810_jack_func;
  40 static int n810_dmic_func;
  41 
  42 static void n810_ext_control(struct snd_soc_dapm_context *dapm)
  43 {
  44         int hp = 0, line1l = 0;
  45 
  46         switch (n810_jack_func) {
  47         case N810_JACK_HS:
  48                 line1l = 1;
  49                 /* fall through */
  50         case N810_JACK_HP:
  51                 hp = 1;
  52                 break;
  53         case N810_JACK_MIC:
  54                 line1l = 1;
  55                 break;
  56         }
  57 
  58         snd_soc_dapm_mutex_lock(dapm);
  59 
  60         if (n810_spk_func)
  61                 snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
  62         else
  63                 snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
  64 
  65         if (hp)
  66                 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
  67         else
  68                 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
  69         if (line1l)
  70                 snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
  71         else
  72                 snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
  73 
  74         if (n810_dmic_func)
  75                 snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
  76         else
  77                 snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
  78 
  79         snd_soc_dapm_sync_unlocked(dapm);
  80 
  81         snd_soc_dapm_mutex_unlock(dapm);
  82 }
  83 
  84 static int n810_startup(struct snd_pcm_substream *substream)
  85 {
  86         struct snd_pcm_runtime *runtime = substream->runtime;
  87         struct snd_soc_pcm_runtime *rtd = substream->private_data;
  88 
  89         snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
  90 
  91         n810_ext_control(&rtd->card->dapm);
  92         return clk_prepare_enable(sys_clkout2);
  93 }
  94 
  95 static void n810_shutdown(struct snd_pcm_substream *substream)
  96 {
  97         clk_disable_unprepare(sys_clkout2);
  98 }
  99 
 100 static int n810_hw_params(struct snd_pcm_substream *substream,
 101         struct snd_pcm_hw_params *params)
 102 {
 103         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 104         struct snd_soc_dai *codec_dai = rtd->codec_dai;
 105         int err;
 106 
 107         /* Set the codec system clock for DAC and ADC */
 108         err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000,
 109                                             SND_SOC_CLOCK_IN);
 110 
 111         return err;
 112 }
 113 
 114 static const struct snd_soc_ops n810_ops = {
 115         .startup = n810_startup,
 116         .hw_params = n810_hw_params,
 117         .shutdown = n810_shutdown,
 118 };
 119 
 120 static int n810_get_spk(struct snd_kcontrol *kcontrol,
 121                         struct snd_ctl_elem_value *ucontrol)
 122 {
 123         ucontrol->value.enumerated.item[0] = n810_spk_func;
 124 
 125         return 0;
 126 }
 127 
 128 static int n810_set_spk(struct snd_kcontrol *kcontrol,
 129                         struct snd_ctl_elem_value *ucontrol)
 130 {
 131         struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 132 
 133         if (n810_spk_func == ucontrol->value.enumerated.item[0])
 134                 return 0;
 135 
 136         n810_spk_func = ucontrol->value.enumerated.item[0];
 137         n810_ext_control(&card->dapm);
 138 
 139         return 1;
 140 }
 141 
 142 static int n810_get_jack(struct snd_kcontrol *kcontrol,
 143                          struct snd_ctl_elem_value *ucontrol)
 144 {
 145         ucontrol->value.enumerated.item[0] = n810_jack_func;
 146 
 147         return 0;
 148 }
 149 
 150 static int n810_set_jack(struct snd_kcontrol *kcontrol,
 151                          struct snd_ctl_elem_value *ucontrol)
 152 {
 153         struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 154 
 155         if (n810_jack_func == ucontrol->value.enumerated.item[0])
 156                 return 0;
 157 
 158         n810_jack_func = ucontrol->value.enumerated.item[0];
 159         n810_ext_control(&card->dapm);
 160 
 161         return 1;
 162 }
 163 
 164 static int n810_get_input(struct snd_kcontrol *kcontrol,
 165                           struct snd_ctl_elem_value *ucontrol)
 166 {
 167         ucontrol->value.enumerated.item[0] = n810_dmic_func;
 168 
 169         return 0;
 170 }
 171 
 172 static int n810_set_input(struct snd_kcontrol *kcontrol,
 173                           struct snd_ctl_elem_value *ucontrol)
 174 {
 175         struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
 176 
 177         if (n810_dmic_func == ucontrol->value.enumerated.item[0])
 178                 return 0;
 179 
 180         n810_dmic_func = ucontrol->value.enumerated.item[0];
 181         n810_ext_control(&card->dapm);
 182 
 183         return 1;
 184 }
 185 
 186 static int n810_spk_event(struct snd_soc_dapm_widget *w,
 187                           struct snd_kcontrol *k, int event)
 188 {
 189         if (SND_SOC_DAPM_EVENT_ON(event))
 190                 gpio_set_value(N810_SPEAKER_AMP_GPIO, 1);
 191         else
 192                 gpio_set_value(N810_SPEAKER_AMP_GPIO, 0);
 193 
 194         return 0;
 195 }
 196 
 197 static int n810_jack_event(struct snd_soc_dapm_widget *w,
 198                            struct snd_kcontrol *k, int event)
 199 {
 200         if (SND_SOC_DAPM_EVENT_ON(event))
 201                 gpio_set_value(N810_HEADSET_AMP_GPIO, 1);
 202         else
 203                 gpio_set_value(N810_HEADSET_AMP_GPIO, 0);
 204 
 205         return 0;
 206 }
 207 
 208 static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
 209         SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
 210         SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
 211         SND_SOC_DAPM_MIC("DMic", NULL),
 212         SND_SOC_DAPM_MIC("HS Mic", NULL),
 213 };
 214 
 215 static const struct snd_soc_dapm_route audio_map[] = {
 216         {"Headphone Jack", NULL, "HPLOUT"},
 217         {"Headphone Jack", NULL, "HPROUT"},
 218 
 219         {"Ext Spk", NULL, "LLOUT"},
 220         {"Ext Spk", NULL, "RLOUT"},
 221 
 222         {"DMic Rate 64", NULL, "DMic"},
 223         {"DMic", NULL, "Mic Bias"},
 224 
 225         /*
 226          * Note that the mic bias is coming from Retu/Vilma and we don't have
 227          * control over it atm. The analog HS mic is not working. <- TODO
 228          */
 229         {"LINE1L", NULL, "HS Mic"},
 230 };
 231 
 232 static const char *spk_function[] = {"Off", "On"};
 233 static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"};
 234 static const char *input_function[] = {"ADC", "Digital Mic"};
 235 static const struct soc_enum n810_enum[] = {
 236         SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
 237         SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
 238         SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
 239 };
 240 
 241 static const struct snd_kcontrol_new aic33_n810_controls[] = {
 242         SOC_ENUM_EXT("Speaker Function", n810_enum[0],
 243                      n810_get_spk, n810_set_spk),
 244         SOC_ENUM_EXT("Jack Function", n810_enum[1],
 245                      n810_get_jack, n810_set_jack),
 246         SOC_ENUM_EXT("Input Select",  n810_enum[2],
 247                      n810_get_input, n810_set_input),
 248 };
 249 
 250 /* Digital audio interface glue - connects codec <--> CPU */
 251 SND_SOC_DAILINK_DEFS(aic33,
 252         DAILINK_COMP_ARRAY(COMP_CPU("48076000.mcbsp")),
 253         DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018",
 254                                       "tlv320aic3x-hifi")),
 255         DAILINK_COMP_ARRAY(COMP_PLATFORM("48076000.mcbsp")));
 256 
 257 static struct snd_soc_dai_link n810_dai = {
 258         .name = "TLV320AIC33",
 259         .stream_name = "AIC33",
 260         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 261                    SND_SOC_DAIFMT_CBM_CFM,
 262         .ops = &n810_ops,
 263         SND_SOC_DAILINK_REG(aic33),
 264 };
 265 
 266 /* Audio machine driver */
 267 static struct snd_soc_card snd_soc_n810 = {
 268         .name = "N810",
 269         .owner = THIS_MODULE,
 270         .dai_link = &n810_dai,
 271         .num_links = 1,
 272 
 273         .controls = aic33_n810_controls,
 274         .num_controls = ARRAY_SIZE(aic33_n810_controls),
 275         .dapm_widgets = aic33_dapm_widgets,
 276         .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets),
 277         .dapm_routes = audio_map,
 278         .num_dapm_routes = ARRAY_SIZE(audio_map),
 279         .fully_routed = true,
 280 };
 281 
 282 static struct platform_device *n810_snd_device;
 283 
 284 static int __init n810_soc_init(void)
 285 {
 286         int err;
 287         struct device *dev;
 288 
 289         if (!of_have_populated_dt() ||
 290             (!of_machine_is_compatible("nokia,n810") &&
 291              !of_machine_is_compatible("nokia,n810-wimax")))
 292                 return -ENODEV;
 293 
 294         n810_snd_device = platform_device_alloc("soc-audio", -1);
 295         if (!n810_snd_device)
 296                 return -ENOMEM;
 297 
 298         platform_set_drvdata(n810_snd_device, &snd_soc_n810);
 299         err = platform_device_add(n810_snd_device);
 300         if (err)
 301                 goto err1;
 302 
 303         dev = &n810_snd_device->dev;
 304 
 305         sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
 306         if (IS_ERR(sys_clkout2_src)) {
 307                 dev_err(dev, "Could not get sys_clkout2_src clock\n");
 308                 err = PTR_ERR(sys_clkout2_src);
 309                 goto err2;
 310         }
 311         sys_clkout2 = clk_get(dev, "sys_clkout2");
 312         if (IS_ERR(sys_clkout2)) {
 313                 dev_err(dev, "Could not get sys_clkout2\n");
 314                 err = PTR_ERR(sys_clkout2);
 315                 goto err3;
 316         }
 317         /*
 318          * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
 319          * 96 MHz as its parent in order to get 12 MHz
 320          */
 321         func96m_clk = clk_get(dev, "func_96m_ck");
 322         if (IS_ERR(func96m_clk)) {
 323                 dev_err(dev, "Could not get func 96M clock\n");
 324                 err = PTR_ERR(func96m_clk);
 325                 goto err4;
 326         }
 327         clk_set_parent(sys_clkout2_src, func96m_clk);
 328         clk_set_rate(sys_clkout2, 12000000);
 329 
 330         if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
 331                     (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) {
 332                 err = -EINVAL;
 333                 goto err4;
 334         }
 335 
 336         gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
 337         gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
 338 
 339         return 0;
 340 err4:
 341         clk_put(sys_clkout2);
 342 err3:
 343         clk_put(sys_clkout2_src);
 344 err2:
 345         platform_device_del(n810_snd_device);
 346 err1:
 347         platform_device_put(n810_snd_device);
 348 
 349         return err;
 350 }
 351 
 352 static void __exit n810_soc_exit(void)
 353 {
 354         gpio_free(N810_SPEAKER_AMP_GPIO);
 355         gpio_free(N810_HEADSET_AMP_GPIO);
 356         clk_put(sys_clkout2_src);
 357         clk_put(sys_clkout2);
 358         clk_put(func96m_clk);
 359 
 360         platform_device_unregister(n810_snd_device);
 361 }
 362 
 363 module_init(n810_soc_init);
 364 module_exit(n810_soc_exit);
 365 
 366 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 367 MODULE_DESCRIPTION("ALSA SoC Nokia N810");
 368 MODULE_LICENSE("GPL");

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