root/sound/soc/ti/omap3pandora.c

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

DEFINITIONS

This source file includes following definitions.
  1. omap3pandora_hw_params
  2. omap3pandora_dac_event
  3. omap3pandora_hp_event
  4. omap3pandora_out_init
  5. omap3pandora_in_init
  6. omap3pandora_soc_init
  7. omap3pandora_soc_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * omap3pandora.c  --  SoC audio for Pandora Handheld Console
   4  *
   5  * Author: GraÅžvydas Ignotas <notasas@gmail.com>
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/platform_device.h>
  10 #include <linux/gpio.h>
  11 #include <linux/delay.h>
  12 #include <linux/regulator/consumer.h>
  13 #include <linux/module.h>
  14 
  15 #include <sound/core.h>
  16 #include <sound/pcm.h>
  17 #include <sound/soc.h>
  18 
  19 #include <asm/mach-types.h>
  20 #include <linux/platform_data/asoc-ti-mcbsp.h>
  21 
  22 #include "omap-mcbsp.h"
  23 
  24 #define OMAP3_PANDORA_DAC_POWER_GPIO    118
  25 #define OMAP3_PANDORA_AMP_POWER_GPIO    14
  26 
  27 #define PREFIX "ASoC omap3pandora: "
  28 
  29 static struct regulator *omap3pandora_dac_reg;
  30 
  31 static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
  32         struct snd_pcm_hw_params *params)
  33 {
  34         struct snd_soc_pcm_runtime *rtd = substream->private_data;
  35         struct snd_soc_dai *codec_dai = rtd->codec_dai;
  36         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  37         int ret;
  38 
  39         /* Set the codec system clock for DAC and ADC */
  40         ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
  41                                             SND_SOC_CLOCK_IN);
  42         if (ret < 0) {
  43                 pr_err(PREFIX "can't set codec system clock\n");
  44                 return ret;
  45         }
  46 
  47         /* Set McBSP clock to external */
  48         ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
  49                                      256 * params_rate(params),
  50                                      SND_SOC_CLOCK_IN);
  51         if (ret < 0) {
  52                 pr_err(PREFIX "can't set cpu system clock\n");
  53                 return ret;
  54         }
  55 
  56         ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8);
  57         if (ret < 0) {
  58                 pr_err(PREFIX "can't set SRG clock divider\n");
  59                 return ret;
  60         }
  61 
  62         return 0;
  63 }
  64 
  65 static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
  66         struct snd_kcontrol *k, int event)
  67 {
  68         int ret;
  69 
  70         /*
  71          * The PCM1773 DAC datasheet requires 1ms delay between switching
  72          * VCC power on/off and /PD pin high/low
  73          */
  74         if (SND_SOC_DAPM_EVENT_ON(event)) {
  75                 ret = regulator_enable(omap3pandora_dac_reg);
  76                 if (ret) {
  77                         dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
  78                         return ret;
  79                 }
  80                 mdelay(1);
  81                 gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
  82         } else {
  83                 gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
  84                 mdelay(1);
  85                 regulator_disable(omap3pandora_dac_reg);
  86         }
  87 
  88         return 0;
  89 }
  90 
  91 static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
  92         struct snd_kcontrol *k, int event)
  93 {
  94         if (SND_SOC_DAPM_EVENT_ON(event))
  95                 gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
  96         else
  97                 gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
  98 
  99         return 0;
 100 }
 101 
 102 /*
 103  * Audio paths on Pandora board:
 104  *
 105  *  |O| ---> PCM DAC +-> AMP -> Headphone Jack
 106  *  |M|         A    +--------> Line Out
 107  *  |A| <~~clk~~+
 108  *  |P| <--- TWL4030 <--------- Line In and MICs
 109  */
 110 static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = {
 111         SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
 112                            0, 0, omap3pandora_dac_event,
 113                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 114         SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
 115                            0, 0, NULL, 0, omap3pandora_hp_event,
 116                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 117         SND_SOC_DAPM_HP("Headphone Jack", NULL),
 118         SND_SOC_DAPM_LINE("Line Out", NULL),
 119 
 120         SND_SOC_DAPM_MIC("Mic (internal)", NULL),
 121         SND_SOC_DAPM_MIC("Mic (external)", NULL),
 122         SND_SOC_DAPM_LINE("Line In", NULL),
 123 };
 124 
 125 static const struct snd_soc_dapm_route omap3pandora_map[] = {
 126         {"PCM DAC", NULL, "APLL Enable"},
 127         {"Headphone Amplifier", NULL, "PCM DAC"},
 128         {"Line Out", NULL, "PCM DAC"},
 129         {"Headphone Jack", NULL, "Headphone Amplifier"},
 130 
 131         {"AUXL", NULL, "Line In"},
 132         {"AUXR", NULL, "Line In"},
 133 
 134         {"MAINMIC", NULL, "Mic (internal)"},
 135         {"Mic (internal)", NULL, "Mic Bias 1"},
 136 
 137         {"SUBMIC", NULL, "Mic (external)"},
 138         {"Mic (external)", NULL, "Mic Bias 2"},
 139 };
 140 
 141 static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
 142 {
 143         struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
 144 
 145         /* All TWL4030 output pins are floating */
 146         snd_soc_dapm_nc_pin(dapm, "EARPIECE");
 147         snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
 148         snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
 149         snd_soc_dapm_nc_pin(dapm, "HSOL");
 150         snd_soc_dapm_nc_pin(dapm, "HSOR");
 151         snd_soc_dapm_nc_pin(dapm, "CARKITL");
 152         snd_soc_dapm_nc_pin(dapm, "CARKITR");
 153         snd_soc_dapm_nc_pin(dapm, "HFL");
 154         snd_soc_dapm_nc_pin(dapm, "HFR");
 155         snd_soc_dapm_nc_pin(dapm, "VIBRA");
 156 
 157         return 0;
 158 }
 159 
 160 static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
 161 {
 162         struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
 163 
 164         /* Not comnnected */
 165         snd_soc_dapm_nc_pin(dapm, "HSMIC");
 166         snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
 167         snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
 168         snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
 169 
 170         return 0;
 171 }
 172 
 173 static const struct snd_soc_ops omap3pandora_ops = {
 174         .hw_params = omap3pandora_hw_params,
 175 };
 176 
 177 /* Digital audio interface glue - connects codec <--> CPU */
 178 SND_SOC_DAILINK_DEFS(out,
 179         DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.2")),
 180         DAILINK_COMP_ARRAY(COMP_CODEC("twl4030-codec", "twl4030-hifi")),
 181         DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.2")));
 182 
 183 SND_SOC_DAILINK_DEFS(in,
 184         DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.4")),
 185         DAILINK_COMP_ARRAY(COMP_CODEC("twl4030-codec", "twl4030-hifi")),
 186         DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.4")));
 187 
 188 static struct snd_soc_dai_link omap3pandora_dai[] = {
 189         {
 190                 .name = "PCM1773",
 191                 .stream_name = "HiFi Out",
 192                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 193                            SND_SOC_DAIFMT_CBS_CFS,
 194                 .ops = &omap3pandora_ops,
 195                 .init = omap3pandora_out_init,
 196                 SND_SOC_DAILINK_REG(out),
 197         }, {
 198                 .name = "TWL4030",
 199                 .stream_name = "Line/Mic In",
 200                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 201                            SND_SOC_DAIFMT_CBS_CFS,
 202                 .ops = &omap3pandora_ops,
 203                 .init = omap3pandora_in_init,
 204                 SND_SOC_DAILINK_REG(in),
 205         }
 206 };
 207 
 208 /* SoC card */
 209 static struct snd_soc_card snd_soc_card_omap3pandora = {
 210         .name = "omap3pandora",
 211         .owner = THIS_MODULE,
 212         .dai_link = omap3pandora_dai,
 213         .num_links = ARRAY_SIZE(omap3pandora_dai),
 214 
 215         .dapm_widgets = omap3pandora_dapm_widgets,
 216         .num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets),
 217         .dapm_routes = omap3pandora_map,
 218         .num_dapm_routes = ARRAY_SIZE(omap3pandora_map),
 219 };
 220 
 221 static struct platform_device *omap3pandora_snd_device;
 222 
 223 static int __init omap3pandora_soc_init(void)
 224 {
 225         int ret;
 226 
 227         if (!machine_is_omap3_pandora())
 228                 return -ENODEV;
 229 
 230         pr_info("OMAP3 Pandora SoC init\n");
 231 
 232         ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power");
 233         if (ret) {
 234                 pr_err(PREFIX "Failed to get DAC power GPIO\n");
 235                 return ret;
 236         }
 237 
 238         ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
 239         if (ret) {
 240                 pr_err(PREFIX "Failed to set DAC power GPIO direction\n");
 241                 goto fail0;
 242         }
 243 
 244         ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power");
 245         if (ret) {
 246                 pr_err(PREFIX "Failed to get amp power GPIO\n");
 247                 goto fail0;
 248         }
 249 
 250         ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
 251         if (ret) {
 252                 pr_err(PREFIX "Failed to set amp power GPIO direction\n");
 253                 goto fail1;
 254         }
 255 
 256         omap3pandora_snd_device = platform_device_alloc("soc-audio", -1);
 257         if (omap3pandora_snd_device == NULL) {
 258                 pr_err(PREFIX "Platform device allocation failed\n");
 259                 ret = -ENOMEM;
 260                 goto fail1;
 261         }
 262 
 263         platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
 264 
 265         ret = platform_device_add(omap3pandora_snd_device);
 266         if (ret) {
 267                 pr_err(PREFIX "Unable to add platform device\n");
 268                 goto fail2;
 269         }
 270 
 271         omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc");
 272         if (IS_ERR(omap3pandora_dac_reg)) {
 273                 pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
 274                         dev_name(&omap3pandora_snd_device->dev),
 275                         PTR_ERR(omap3pandora_dac_reg));
 276                 ret = PTR_ERR(omap3pandora_dac_reg);
 277                 goto fail3;
 278         }
 279 
 280         return 0;
 281 
 282 fail3:
 283         platform_device_del(omap3pandora_snd_device);
 284 fail2:
 285         platform_device_put(omap3pandora_snd_device);
 286 fail1:
 287         gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
 288 fail0:
 289         gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
 290         return ret;
 291 }
 292 module_init(omap3pandora_soc_init);
 293 
 294 static void __exit omap3pandora_soc_exit(void)
 295 {
 296         regulator_put(omap3pandora_dac_reg);
 297         platform_device_unregister(omap3pandora_snd_device);
 298         gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
 299         gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
 300 }
 301 module_exit(omap3pandora_soc_exit);
 302 
 303 MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>");
 304 MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora");
 305 MODULE_LICENSE("GPL");

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