diff options
Diffstat (limited to 'sound/soc/omap')
-rw-r--r-- | sound/soc/omap/Kconfig | 3 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcpdm.c | 74 | ||||
-rw-r--r-- | sound/soc/omap/rx51.c | 46 |
3 files changed, 89 insertions, 34 deletions
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 5185a3844da9..f5451c78ede5 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -100,13 +100,14 @@ config SND_OMAP_SOC_OMAP_TWL4030 config SND_OMAP_SOC_OMAP_ABE_TWL6040 tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" - depends on TWL6040_CORE && SND_OMAP_SOC + depends on TWL6040_CORE && SND_OMAP_SOC && COMMON_CLK depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST select SND_OMAP_SOC_DMIC select SND_OMAP_SOC_MCPDM select SND_SOC_TWL6040 select SND_SOC_DMIC select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS) + select CLK_TWL6040 help Say Y if you want to add support for SoC audio on OMAP boards using ABE and twl6040 codec. This driver currently supports: diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index b837265ac3e9..e7cdc51fd806 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -31,6 +31,7 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/irq.h> +#include <linux/clk.h> #include <linux/slab.h> #include <linux/pm_runtime.h> #include <linux/of_device.h> @@ -54,6 +55,7 @@ struct omap_mcpdm { unsigned long phys_base; void __iomem *io_base; int irq; + struct clk *pdmclk; struct mutex mutex; @@ -66,6 +68,9 @@ struct omap_mcpdm { /* McPDM needs to be restarted due to runtime reconfiguration */ bool restart; + /* pm state for suspend/resume handling */ + int pm_active_count; + struct snd_dmaengine_dai_dma_data dma_data[2]; }; @@ -173,6 +178,10 @@ static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm) */ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm) { + u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); + + omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); + omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET, MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL | MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); @@ -258,12 +267,9 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, mutex_lock(&mcpdm->mutex); - if (!dai->active) { - u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); - - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); + if (!dai->active) omap_mcpdm_open_streams(mcpdm); - } + mutex_unlock(&mcpdm->mutex); return 0; @@ -384,6 +390,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai) struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); int ret; + clk_prepare_enable(mcpdm->pdmclk); pm_runtime_enable(mcpdm->dev); /* Disable lines while request is ongoing */ @@ -418,8 +425,54 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) pm_runtime_disable(mcpdm->dev); + clk_disable_unprepare(mcpdm->pdmclk); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int omap_mcpdm_suspend(struct snd_soc_dai *dai) +{ + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + + if (dai->active) { + omap_mcpdm_stop(mcpdm); + omap_mcpdm_close_streams(mcpdm); + } + + mcpdm->pm_active_count = 0; + while (pm_runtime_active(mcpdm->dev)) { + pm_runtime_put_sync(mcpdm->dev); + mcpdm->pm_active_count++; + } + + clk_disable_unprepare(mcpdm->pdmclk); + + return 0; +} + +static int omap_mcpdm_resume(struct snd_soc_dai *dai) +{ + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + + clk_prepare_enable(mcpdm->pdmclk); + + if (mcpdm->pm_active_count) { + while (mcpdm->pm_active_count--) + pm_runtime_get_sync(mcpdm->dev); + + if (dai->active) { + omap_mcpdm_open_streams(mcpdm); + omap_mcpdm_start(mcpdm); + } + } + + return 0; } +#else +#define omap_mcpdm_suspend NULL +#define omap_mcpdm_resume NULL +#endif #define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) #define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE @@ -427,6 +480,8 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) static struct snd_soc_dai_driver omap_mcpdm_dai = { .probe = omap_mcpdm_probe, .remove = omap_mcpdm_remove, + .suspend = omap_mcpdm_suspend, + .resume = omap_mcpdm_resume, .probe_order = SND_SOC_COMP_ORDER_LATE, .remove_order = SND_SOC_COMP_ORDER_EARLY, .playback = { @@ -494,6 +549,15 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) mcpdm->dev = &pdev->dev; + mcpdm->pdmclk = devm_clk_get(&pdev->dev, "pdmclk"); + if (IS_ERR(mcpdm->pdmclk)) { + if (PTR_ERR(mcpdm->pdmclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_warn(&pdev->dev, "Error getting pdmclk (%ld)!\n", + PTR_ERR(mcpdm->pdmclk)); + mcpdm->pdmclk = NULL; + } + ret = devm_snd_soc_register_component(&pdev->dev, &omap_mcpdm_component, &omap_mcpdm_dai, 1); diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 54949242bc70..a76845748a10 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -33,7 +33,6 @@ #include <sound/pcm.h> #include <sound/soc.h> #include <linux/platform_data/asoc-ti-mcbsp.h> -#include "../codecs/tpa6130a2.h" #include <asm/mach-types.h> @@ -164,19 +163,6 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w, return 0; } -static int rx51_hp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - - if (SND_SOC_DAPM_EVENT_ON(event)) - tpa6130a2_stereo_enable(codec, 1); - else - tpa6130a2_stereo_enable(codec, 0); - - return 0; -} - static int rx51_get_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -235,7 +221,7 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = { static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), SND_SOC_DAPM_MIC("DMic", NULL), - SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event), + SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("HS Mic", NULL), SND_SOC_DAPM_LINE("FM Transmitter", NULL), SND_SOC_DAPM_SPK("Earphone", NULL), @@ -246,11 +232,14 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Ext Spk", NULL, "HPROUT"}, {"Ext Spk", NULL, "HPLCOM"}, {"Ext Spk", NULL, "HPRCOM"}, - {"Headphone Jack", NULL, "LLOUT"}, - {"Headphone Jack", NULL, "RLOUT"}, {"FM Transmitter", NULL, "LLOUT"}, {"FM Transmitter", NULL, "RLOUT"}, + {"Headphone Jack", NULL, "TPA6130A2 HPLEFT"}, + {"Headphone Jack", NULL, "TPA6130A2 HPRIGHT"}, + {"TPA6130A2 LEFTIN", NULL, "LLOUT"}, + {"TPA6130A2 RIGHTIN", NULL, "RLOUT"}, + {"DMic Rate 64", NULL, "DMic"}, {"DMic", NULL, "Mic Bias"}, @@ -286,16 +275,10 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = { static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = rtd->card; struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card); int err; - err = tpa6130a2_add_controls(codec); - if (err < 0) { - dev_err(card->dev, "Failed to add TPA6130A2 controls\n"); - return err; - } snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42); err = omap_mcbsp_st_add_controls(rtd, 2); @@ -357,6 +340,10 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = { .name = "TLV320AIC34b", .codec_name = "tlv320aic3x-codec.2-0019", }, + { + .name = "TPA61320A2", + .codec_name = "tpa6130a2.2-0060", + }, }; static struct snd_soc_codec_conf rx51_codec_conf[] = { @@ -364,6 +351,10 @@ static struct snd_soc_codec_conf rx51_codec_conf[] = { .dev_name = "tlv320aic3x-codec.2-0019", .name_prefix = "b", }, + { + .dev_name = "tpa6130a2.2-0060", + .name_prefix = "TPA6130A2", + }, }; /* Audio card */ @@ -435,11 +426,10 @@ static int rx51_soc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Headphone amplifier node is not provided\n"); return -EINVAL; } - - /* TODO: tpa6130a2a driver supports only a single instance, so - * this driver ignores the headphone-amplifier node for now. - * It's already mandatory in the DT binding to be future proof. - */ + rx51_aux_dev[1].codec_name = NULL; + rx51_aux_dev[1].codec_of_node = dai_node; + rx51_codec_conf[1].dev_name = NULL; + rx51_codec_conf[1].of_node = dai_node; } pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |