0001
0002
0003
0004
0005
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
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
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
0072
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
0104
0105
0106
0107
0108
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
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
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
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
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");