Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * omap3pandora.c  --  SoC audio for Pandora Handheld Console
0004  *
0005  * Author: GraÅžvydas Ignotas <notasas@gmail.com>
0006  */
0007 
0008 #include <linux/clk.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/gpio.h>
0011 #include <linux/delay.h>
0012 #include <linux/regulator/consumer.h>
0013 #include <linux/module.h>
0014 
0015 #include <sound/core.h>
0016 #include <sound/pcm.h>
0017 #include <sound/soc.h>
0018 
0019 #include <asm/mach-types.h>
0020 #include <linux/platform_data/asoc-ti-mcbsp.h>
0021 
0022 #include "omap-mcbsp.h"
0023 
0024 #define OMAP3_PANDORA_DAC_POWER_GPIO    118
0025 #define OMAP3_PANDORA_AMP_POWER_GPIO    14
0026 
0027 #define PREFIX "ASoC omap3pandora: "
0028 
0029 static struct regulator *omap3pandora_dac_reg;
0030 
0031 static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
0032     struct snd_pcm_hw_params *params)
0033 {
0034     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0035     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0036     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0037     int ret;
0038 
0039     /* Set the codec system clock for DAC and ADC */
0040     ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
0041                         SND_SOC_CLOCK_IN);
0042     if (ret < 0) {
0043         pr_err(PREFIX "can't set codec system clock\n");
0044         return ret;
0045     }
0046 
0047     /* Set McBSP clock to external */
0048     ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
0049                      256 * params_rate(params),
0050                      SND_SOC_CLOCK_IN);
0051     if (ret < 0) {
0052         pr_err(PREFIX "can't set cpu system clock\n");
0053         return ret;
0054     }
0055 
0056     ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8);
0057     if (ret < 0) {
0058         pr_err(PREFIX "can't set SRG clock divider\n");
0059         return ret;
0060     }
0061 
0062     return 0;
0063 }
0064 
0065 static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
0066     struct snd_kcontrol *k, int event)
0067 {
0068     int ret;
0069 
0070     /*
0071      * The PCM1773 DAC datasheet requires 1ms delay between switching
0072      * VCC power on/off and /PD pin high/low
0073      */
0074     if (SND_SOC_DAPM_EVENT_ON(event)) {
0075         ret = regulator_enable(omap3pandora_dac_reg);
0076         if (ret) {
0077             dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
0078             return ret;
0079         }
0080         mdelay(1);
0081         gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
0082     } else {
0083         gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
0084         mdelay(1);
0085         regulator_disable(omap3pandora_dac_reg);
0086     }
0087 
0088     return 0;
0089 }
0090 
0091 static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
0092     struct snd_kcontrol *k, int event)
0093 {
0094     if (SND_SOC_DAPM_EVENT_ON(event))
0095         gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
0096     else
0097         gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
0098 
0099     return 0;
0100 }
0101 
0102 /*
0103  * Audio paths on Pandora board:
0104  *
0105  *  |O| ---> PCM DAC +-> AMP -> Headphone Jack
0106  *  |M|         A    +--------> Line Out
0107  *  |A| <~~clk~~+
0108  *  |P| <--- TWL4030 <--------- Line In and MICs
0109  */
0110 static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = {
0111     SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
0112                0, 0, omap3pandora_dac_event,
0113                SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
0114     SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
0115                0, 0, NULL, 0, omap3pandora_hp_event,
0116                SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
0117     SND_SOC_DAPM_HP("Headphone Jack", NULL),
0118     SND_SOC_DAPM_LINE("Line Out", NULL),
0119 
0120     SND_SOC_DAPM_MIC("Mic (internal)", NULL),
0121     SND_SOC_DAPM_MIC("Mic (external)", NULL),
0122     SND_SOC_DAPM_LINE("Line In", NULL),
0123 };
0124 
0125 static const struct snd_soc_dapm_route omap3pandora_map[] = {
0126     {"PCM DAC", NULL, "APLL Enable"},
0127     {"Headphone Amplifier", NULL, "PCM DAC"},
0128     {"Line Out", NULL, "PCM DAC"},
0129     {"Headphone Jack", NULL, "Headphone Amplifier"},
0130 
0131     {"AUXL", NULL, "Line In"},
0132     {"AUXR", NULL, "Line In"},
0133 
0134     {"MAINMIC", NULL, "Mic (internal)"},
0135     {"Mic (internal)", NULL, "Mic Bias 1"},
0136 
0137     {"SUBMIC", NULL, "Mic (external)"},
0138     {"Mic (external)", NULL, "Mic Bias 2"},
0139 };
0140 
0141 static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
0142 {
0143     struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
0144 
0145     /* All TWL4030 output pins are floating */
0146     snd_soc_dapm_nc_pin(dapm, "EARPIECE");
0147     snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
0148     snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
0149     snd_soc_dapm_nc_pin(dapm, "HSOL");
0150     snd_soc_dapm_nc_pin(dapm, "HSOR");
0151     snd_soc_dapm_nc_pin(dapm, "CARKITL");
0152     snd_soc_dapm_nc_pin(dapm, "CARKITR");
0153     snd_soc_dapm_nc_pin(dapm, "HFL");
0154     snd_soc_dapm_nc_pin(dapm, "HFR");
0155     snd_soc_dapm_nc_pin(dapm, "VIBRA");
0156 
0157     return 0;
0158 }
0159 
0160 static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
0161 {
0162     struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
0163 
0164     /* Not comnnected */
0165     snd_soc_dapm_nc_pin(dapm, "HSMIC");
0166     snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
0167     snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
0168     snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
0169 
0170     return 0;
0171 }
0172 
0173 static const struct snd_soc_ops omap3pandora_ops = {
0174     .hw_params = omap3pandora_hw_params,
0175 };
0176 
0177 /* Digital audio interface glue - connects codec <--> CPU */
0178 SND_SOC_DAILINK_DEFS(out,
0179     DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.2")),
0180     DAILINK_COMP_ARRAY(COMP_CODEC("twl4030-codec", "twl4030-hifi")),
0181     DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.2")));
0182 
0183 SND_SOC_DAILINK_DEFS(in,
0184     DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.4")),
0185     DAILINK_COMP_ARRAY(COMP_CODEC("twl4030-codec", "twl4030-hifi")),
0186     DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.4")));
0187 
0188 static struct snd_soc_dai_link omap3pandora_dai[] = {
0189     {
0190         .name = "PCM1773",
0191         .stream_name = "HiFi Out",
0192         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0193                SND_SOC_DAIFMT_CBS_CFS,
0194         .ops = &omap3pandora_ops,
0195         .init = omap3pandora_out_init,
0196         SND_SOC_DAILINK_REG(out),
0197     }, {
0198         .name = "TWL4030",
0199         .stream_name = "Line/Mic In",
0200         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0201                SND_SOC_DAIFMT_CBS_CFS,
0202         .ops = &omap3pandora_ops,
0203         .init = omap3pandora_in_init,
0204         SND_SOC_DAILINK_REG(in),
0205     }
0206 };
0207 
0208 /* SoC card */
0209 static struct snd_soc_card snd_soc_card_omap3pandora = {
0210     .name = "omap3pandora",
0211     .owner = THIS_MODULE,
0212     .dai_link = omap3pandora_dai,
0213     .num_links = ARRAY_SIZE(omap3pandora_dai),
0214 
0215     .dapm_widgets = omap3pandora_dapm_widgets,
0216     .num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets),
0217     .dapm_routes = omap3pandora_map,
0218     .num_dapm_routes = ARRAY_SIZE(omap3pandora_map),
0219 };
0220 
0221 static struct platform_device *omap3pandora_snd_device;
0222 
0223 static int __init omap3pandora_soc_init(void)
0224 {
0225     int ret;
0226 
0227     if (!machine_is_omap3_pandora())
0228         return -ENODEV;
0229 
0230     pr_info("OMAP3 Pandora SoC init\n");
0231 
0232     ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power");
0233     if (ret) {
0234         pr_err(PREFIX "Failed to get DAC power GPIO\n");
0235         return ret;
0236     }
0237 
0238     ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
0239     if (ret) {
0240         pr_err(PREFIX "Failed to set DAC power GPIO direction\n");
0241         goto fail0;
0242     }
0243 
0244     ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power");
0245     if (ret) {
0246         pr_err(PREFIX "Failed to get amp power GPIO\n");
0247         goto fail0;
0248     }
0249 
0250     ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
0251     if (ret) {
0252         pr_err(PREFIX "Failed to set amp power GPIO direction\n");
0253         goto fail1;
0254     }
0255 
0256     omap3pandora_snd_device = platform_device_alloc("soc-audio", -1);
0257     if (omap3pandora_snd_device == NULL) {
0258         pr_err(PREFIX "Platform device allocation failed\n");
0259         ret = -ENOMEM;
0260         goto fail1;
0261     }
0262 
0263     platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
0264 
0265     ret = platform_device_add(omap3pandora_snd_device);
0266     if (ret) {
0267         pr_err(PREFIX "Unable to add platform device\n");
0268         goto fail2;
0269     }
0270 
0271     omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc");
0272     if (IS_ERR(omap3pandora_dac_reg)) {
0273         pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
0274             dev_name(&omap3pandora_snd_device->dev),
0275             PTR_ERR(omap3pandora_dac_reg));
0276         ret = PTR_ERR(omap3pandora_dac_reg);
0277         goto fail3;
0278     }
0279 
0280     return 0;
0281 
0282 fail3:
0283     platform_device_del(omap3pandora_snd_device);
0284 fail2:
0285     platform_device_put(omap3pandora_snd_device);
0286 fail1:
0287     gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
0288 fail0:
0289     gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
0290     return ret;
0291 }
0292 module_init(omap3pandora_soc_init);
0293 
0294 static void __exit omap3pandora_soc_exit(void)
0295 {
0296     regulator_put(omap3pandora_dac_reg);
0297     platform_device_unregister(omap3pandora_snd_device);
0298     gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
0299     gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
0300 }
0301 module_exit(omap3pandora_soc_exit);
0302 
0303 MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>");
0304 MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora");
0305 MODULE_LICENSE("GPL");