ASoC: pandora: try to power down the DAC properly
authorGrazvydas Ignotas <notasas@gmail.com>
Mon, 4 Jul 2016 23:57:40 +0000 (02:57 +0300)
committerGrazvydas Ignotas <notasas@gmail.com>
Mon, 4 Jul 2016 23:57:40 +0000 (02:57 +0300)
some nasty stuff, but without this, there is like 5-10mW loss

sound/soc/omap/omap3pandora.c

index 4099227..0d308f9 100644 (file)
@@ -101,20 +101,83 @@ static int omap3pandora_hw_free(struct snd_pcm_substream *substream)
        return 0;
 }
 
+#include <plat/mcbsp.h>
+
+static struct omap_mcbsp_reg_cfg cfg = {
+       .spcr2 = XINTM(3) | FREE,
+       .spcr1 = RINTM(3),
+       .rcr2  = RPHASE | RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
+       .rcr1  = RWDLEN1(OMAP_MCBSP_WORD_16),
+       .xcr2  = XPHASE | XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1),
+       .xcr1  = XWDLEN1(OMAP_MCBSP_WORD_16),
+       .srgr2 = FSGM | FPER(32 - 1),
+       .srgr1 = FWID(32 / 2 - 1) | CLKGDV(8 - 1),
+       .pcr0  = FSXM | FSRM | CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
+       .xccr  = DXENDLY(1) | XDISABLE,
+       .rccr  = RFULL_CYCLE | RDISABLE,
+};
+
+/* to power down the DAC properly, it's not enough to just set the GPIO,
+ * the clocks must be running. What's worse, SCKI (256fs) is not enough,
+ * the other clocks must be running too, and for that McBSP must be started,
+ * so here are some horrible functions */
+static int mcbsp2_clocking_start(void)
+{
+       int ret;
+
+       ret = omap_mcbsp_request(1);
+       if (ret != 0) {
+               pr_err("%s: request mcbsp2: %d\n", __func__, ret);
+               return ret;
+       }
+       omap2_mcbsp_set_clks_src(1, MCBSP_CLKS_PAD_SRC);
+
+       cfg.xccr &= ~XDMAEN,
+       cfg.rccr &= ~RDMAEN,
+       omap_mcbsp_config(1, &cfg);
+
+       omap_mcbsp_start(1, 1, 0);
+
+       /* according to TRM "21.4.4.5 Underflow in the Transmitter",
+        * now it should output zeros on mcbspi_dx, so it's enough to sleep */
+       return 0;
+}
+
+static void mcbsp2_clocking_stop(void)
+{
+       omap_mcbsp_stop(1, 1, 0);
+
+       cfg.xccr |= XDMAEN,
+       cfg.rccr |= RDMAEN,
+       omap_mcbsp_config(1, &cfg);
+
+       omap2_mcbsp_set_clks_src(1, MCBSP_CLKS_PRCM_SRC);
+       omap_mcbsp_free(1);
+}
+
 static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *k, int event)
 {
-       /*
-        * The PCM1773 DAC datasheet requires 1ms delay between switching
-        * VCC power on/off and /PD pin high/low
-        */
        if (SND_SOC_DAPM_EVENT_ON(event)) {
                regulator_enable(omap3pandora_dac_reg);
-               mdelay(1);
+               /* can only set /PD from low to high 1ms after
+                * power and clock stabilize */
+               msleep(1);
                gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
        } else {
+               int ret = mcbsp2_clocking_start();
+
+               /* let it sync to the clocks (just in case) */
+               msleep(1);
+
                gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
-               regulator_disable_deferred(omap3pandora_dac_reg, 1);
+
+               /* 9334 (!) samples before power and clocks can be cut */
+               msleep(9334 * 1000 / 8000 + 1);
+
+               if (ret == 0)
+                       mcbsp2_clocking_stop();
+               regulator_disable(omap3pandora_dac_reg);
        }
 
        return 0;