ASoC: tegra-alt: Add power management for T124
Arun Shamanna Lakshmi [Wed, 29 Oct 2014 00:29:29 +0000 (17:29 -0700)]
1. Set idle_bias_off=1 for I2S, AMX, ADX, SPDIF, DAM, AFC
   for power management reasons. runtime_resume/suspend APIs
   are called when playback/record starts/stops accordingly.

2. Add suspend/resume APIs for I2S, AMX, ADX, SPDIF, DAM,
   AFC and XBAR for LP0 power cycle.

Bug 200046472

Change-Id: If241844859835d7cb17d34fded6ea5c96e69fca1
Signed-off-by: Arun Shamanna Lakshmi <aruns@nvidia.com>
Reviewed-on: http://git-master/r/591003
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Simon Je <sje@nvidia.com>
Tested-by: Simon Je <sje@nvidia.com>

sound/soc/tegra-alt/tegra114_adx_alt.c
sound/soc/tegra-alt/tegra114_amx_alt.c
sound/soc/tegra-alt/tegra124_afc_alt.c
sound/soc/tegra-alt/tegra30_dam_alt.c
sound/soc/tegra-alt/tegra30_i2s_alt.c
sound/soc/tegra-alt/tegra30_i2s_alt.h
sound/soc/tegra-alt/tegra30_spdif_alt.c
sound/soc/tegra-alt/tegra30_xbar_alt.c

index ce6bb96..111e26a 100644 (file)
@@ -192,6 +192,30 @@ static int tegra114_adx_runtime_resume(struct device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra114_adx_suspend(struct device *dev)
+{
+       struct tegra114_adx *adx = dev_get_drvdata(dev);
+
+       regcache_mark_dirty(adx->regmap);
+
+       return 0;
+}
+static int tegra114_adx_resume(struct device *dev)
+{
+       struct tegra114_adx *adx = dev_get_drvdata(dev);
+
+       regcache_sync(adx->regmap);
+
+       /* update map ram if needed */
+       pm_runtime_get_sync(dev);
+       tegra114_adx_update_map_ram(adx);
+       pm_runtime_put(dev);
+
+       return 0;
+}
+#endif
+
 static int tegra114_adx_set_audio_cif(struct tegra114_adx *adx,
                                struct snd_pcm_hw_params *params,
                                unsigned int reg)
@@ -310,7 +334,9 @@ int tegra114_adx_set_channel_map(struct snd_soc_dai *dai,
        }
 
        /* soft reset ADX */
+       pm_runtime_get_sync(dai->dev);
        ret = tegra114_adx_soft_reset(adx);
+       pm_runtime_put(dai->dev);
        if (ret) {
                dev_err(dev, "Failed at ADX sw reset\n");
                return ret;
@@ -340,9 +366,11 @@ int tegra114_adx_set_channel_map(struct snd_soc_dai *dai,
                }
        }
 
+       /* update the map ram */
+       pm_runtime_get_sync(dai->dev);
        tegra114_adx_update_map_ram(adx);
-
        tegra114_adx_set_in_byte_mask(adx, byte_mask1, byte_mask2);
+       pm_runtime_put(dai->dev);
 
        return 0;
 }
@@ -438,6 +466,7 @@ static struct snd_soc_codec_driver tegra114_adx_codec = {
        .num_dapm_widgets = ARRAY_SIZE(tegra114_adx_widgets),
        .dapm_routes = tegra114_adx_routes,
        .num_dapm_routes = ARRAY_SIZE(tegra114_adx_routes),
+       .idle_bias_off = 1,
 };
 
 static bool tegra114_adx_wr_rd_reg(struct device *dev,
@@ -461,6 +490,19 @@ static bool tegra114_adx_wr_rd_reg(struct device *dev,
        };
 }
 
+static bool tegra114_adx_volatile_reg(struct device *dev,
+                               unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA_ADX_CTRL:
+       case TEGRA_ADX_AUDIORAMCTL_ADX_CTRL:
+       case TEGRA_ADX_AUDIORAMCTL_ADX_DATA:
+               return true;
+       default:
+               return false;
+       };
+}
+
 static const struct regmap_config tegra114_adx_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
@@ -468,7 +510,7 @@ static const struct regmap_config tegra114_adx_regmap_config = {
        .max_register = TEGRA_ADX_AUDIOCIF_CH3_CTRL,
        .writeable_reg = tegra114_adx_wr_rd_reg,
        .readable_reg = tegra114_adx_wr_rd_reg,
-       .volatile_reg = tegra114_adx_wr_rd_reg,
+       .volatile_reg = tegra114_adx_volatile_reg,
        .cache_type = REGCACHE_FLAT,
 };
 
@@ -597,6 +639,8 @@ static int tegra114_adx_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra114_adx_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra114_adx_runtime_suspend,
                           tegra114_adx_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra114_adx_suspend,
+                          tegra114_adx_resume)
 };
 
 static struct platform_driver tegra114_adx_driver = {
index b29be2c..680b5e6 100644 (file)
@@ -214,6 +214,32 @@ static int tegra114_amx_runtime_resume(struct device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra114_amx_suspend(struct device *dev)
+{
+       struct tegra114_amx *amx = dev_get_drvdata(dev);
+
+       regcache_mark_dirty(amx->regmap);
+
+       return 0;
+}
+static int tegra114_amx_resume(struct device *dev)
+{
+       struct tegra114_amx *amx = dev_get_drvdata(dev);
+
+       regcache_sync(amx->regmap);
+
+       /* update map ram if needed */
+       pm_runtime_get_sync(dev);
+       tegra114_amx_set_master_stream(amx, 0,
+                               TEGRA_AMX_WAIT_ON_ANY);
+       tegra114_amx_update_map_ram(amx);
+       pm_runtime_put(dev);
+
+       return 0;
+}
+#endif
+
 static int tegra114_amx_set_audio_cif(struct tegra114_amx *amx,
                                struct snd_pcm_hw_params *params,
                                unsigned int reg)
@@ -333,7 +359,9 @@ int tegra114_amx_set_channel_map(struct snd_soc_dai *dai,
        }
 
        /* soft reset AMX */
+       pm_runtime_get_sync(dai->dev);
        ret = tegra114_amx_soft_reset(amx);
+       pm_runtime_put(dai->dev);
        if (ret) {
                dev_err(dev, "Failed at AMX sw reset\n");
                return ret;
@@ -342,9 +370,6 @@ int tegra114_amx_set_channel_map(struct snd_soc_dai *dai,
        /* flush the mapping values if any */
        memset(amx->map, 0, sizeof(amx->map));
 
-       tegra114_amx_set_master_stream(amx, 0,
-                               TEGRA_AMX_WAIT_ON_ANY);
-
        for (i = 0; i < tx_num; i++) {
                if (tx_slot[i] != 0) {
                        /* getting mapping information */
@@ -366,9 +391,12 @@ int tegra114_amx_set_channel_map(struct snd_soc_dai *dai,
                }
        }
 
+       pm_runtime_get_sync(dai->dev);
+       tegra114_amx_set_master_stream(amx, 0,
+                               TEGRA_AMX_WAIT_ON_ANY);
        tegra114_amx_update_map_ram(amx);
-
        tegra114_amx_set_out_byte_mask(amx, byte_mask1, byte_mask2);
+       pm_runtime_put(dai->dev);
 
        return 0;
 }
@@ -472,6 +500,7 @@ static struct snd_soc_codec_driver tegra114_amx_codec = {
        .num_dapm_widgets = ARRAY_SIZE(tegra114_amx_widgets),
        .dapm_routes = tegra114_amx_routes,
        .num_dapm_routes = ARRAY_SIZE(tegra114_amx_routes),
+       .idle_bias_off = 1,
 };
 
 static bool tegra114_amx_wr_rd_reg(struct device *dev,
@@ -495,6 +524,19 @@ static bool tegra114_amx_wr_rd_reg(struct device *dev,
        };
 }
 
+static bool tegra114_amx_volatile_reg(struct device *dev,
+                               unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA_AMX_CTRL:
+       case TEGRA_AMX_AUDIORAMCTL_AMX_CTRL:
+       case TEGRA_AMX_AUDIORAMCTL_AMX_DATA:
+               return true;
+       default:
+               return false;
+       };
+}
+
 static const struct regmap_config tegra114_amx_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
@@ -502,7 +544,7 @@ static const struct regmap_config tegra114_amx_regmap_config = {
        .max_register = TEGRA_AMX_AUDIOCIF_CH3_CTRL,
        .writeable_reg = tegra114_amx_wr_rd_reg,
        .readable_reg = tegra114_amx_wr_rd_reg,
-       .volatile_reg = tegra114_amx_wr_rd_reg,
+       .volatile_reg = tegra114_amx_volatile_reg,
        .cache_type = REGCACHE_FLAT,
 };
 
@@ -641,6 +683,8 @@ static int tegra114_amx_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra114_amx_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra114_amx_runtime_suspend,
                           tegra114_amx_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra114_amx_suspend,
+                          tegra114_amx_resume)
 };
 
 static struct platform_driver tegra114_amx_driver = {
index 2a89751..666a5e6 100644 (file)
@@ -62,6 +62,25 @@ static int tegra124_afc_runtime_resume(struct device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra124_afc_suspend(struct device *dev)
+{
+       struct tegra124_afc *afc = dev_get_drvdata(dev);
+
+       regcache_mark_dirty(afc->regmap);
+
+       return 0;
+}
+static int tegra124_afc_resume(struct device *dev)
+{
+       struct tegra124_afc *afc = dev_get_drvdata(dev);
+
+       regcache_sync(afc->regmap);
+
+       return 0;
+}
+#endif
+
 /* returns the destination I2S id connected along the AFC path */
 static unsigned int tegra124_afc_get_i2s_id(unsigned int afc_id)
 {
@@ -272,6 +291,7 @@ static struct snd_soc_codec_driver tegra124_afc_codec = {
        .num_dapm_widgets = ARRAY_SIZE(tegra124_afc_widgets),
        .dapm_routes = tegra124_afc_routes,
        .num_dapm_routes = ARRAY_SIZE(tegra124_afc_routes),
+       .idle_bias_off = 1,
 };
 
 static bool tegra124_afc_wr_reg(struct device *dev, unsigned int reg)
@@ -483,6 +503,8 @@ static int tegra124_afc_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra124_afc_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra124_afc_runtime_suspend,
                           tegra124_afc_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra124_afc_suspend,
+                          tegra124_afc_resume)
 };
 
 static struct platform_driver tegra124_afc_driver = {
index b8e6088..70c37fa 100644 (file)
@@ -342,6 +342,25 @@ static int tegra30_dam_runtime_resume(struct device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra30_dam_suspend(struct device *dev)
+{
+       struct tegra30_dam *dam = dev_get_drvdata(dev);
+
+       regcache_mark_dirty(dam->regmap);
+
+       return 0;
+}
+static int tegra30_dam_resume(struct device *dev)
+{
+       struct tegra30_dam *dam = dev_get_drvdata(dev);
+
+       regcache_sync(dam->regmap);
+
+       return 0;
+}
+#endif
+
 static int tegra30_dam_set_dai_sysclk(struct snd_soc_dai *dai,
                int clk_id, unsigned int freq, int dir)
 {
@@ -806,6 +825,7 @@ static struct snd_soc_codec_driver tegra30_dam_codec = {
        .num_dapm_routes = ARRAY_SIZE(tegra30_dam_routes),
        .controls = tegra30_dam_controls,
        .num_controls = ARRAY_SIZE(tegra30_dam_controls),
+       .idle_bias_off = 1,
 };
 
 static bool tegra30_dam_wr_rd_reg(struct device *dev,
@@ -997,6 +1017,8 @@ static int tegra30_dam_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra30_dam_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_dam_runtime_suspend,
                           tegra30_dam_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra30_dam_suspend,
+                          tegra30_dam_resume)
 };
 
 static struct platform_driver tegra30_dam_driver = {
index 3450e8d..47e2999 100644 (file)
@@ -122,63 +122,13 @@ static int tegra30_i2s_set_clock_rate(struct device *dev, int clock_rate)
        return ret;
 }
 
-static int tegra30_i2s_runtime_suspend(struct device *dev)
+static int tegra30_i2s_set_format(struct device *dev)
 {
        struct tegra30_i2s *i2s = dev_get_drvdata(dev);
-
-       regcache_cache_only(i2s->regmap, true);
-
-       clk_disable_unprepare(i2s->clk_i2s);
-
-       return 0;
-}
-
-static int tegra30_i2s_runtime_resume(struct device *dev)
-{
-       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
-       int ret;
-
-       ret = clk_prepare_enable(i2s->clk_i2s);
-       if (ret) {
-               dev_err(dev, "clk_enable failed: %d\n", ret);
-               return ret;
-       }
-
-       regcache_cache_only(i2s->regmap, false);
-
-       return 0;
-}
-
-static int tegra30_i2s_set_tdm_slot(struct snd_soc_dai *dai,
-               unsigned int tx_mask, unsigned int rx_mask,
-               int slots, int slot_width)
-{
-       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-       /* copy the required tx and rx mask */
-       i2s->tx_mask = (tx_mask > 0xFFFF) ? 0xFFFF : tx_mask;
-       i2s->rx_mask = (rx_mask > 0xFFFF) ? 0xFFFF : rx_mask;
-
-       return 0;
-}
-static int tegra30_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
-               unsigned int ratio)
-{
-       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-       i2s->bclk_ratio = ratio;
-
-       return 0;
-}
-
-static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
-                               unsigned int fmt)
-{
-       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        unsigned int mask, val, i2s_ctrl, edge_ctrl, data_offset;
 
        mask = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK;
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       switch (i2s->dai_fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_NB_NF:
                edge_ctrl = TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE;
                i2s_ctrl = TEGRA30_I2S_CTRL_LRCK_L_LOW;
@@ -199,13 +149,13 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       pm_runtime_get_sync(dai->dev);
+       pm_runtime_get_sync(dev);
        regmap_update_bits(i2s->regmap, TEGRA30_I2S_CH_CTRL,
                mask, edge_ctrl);
-       pm_runtime_put(dai->dev);
+       pm_runtime_put(dev);
 
        mask = TEGRA30_I2S_CTRL_MASTER_MASK;
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       switch (i2s->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
                i2s_ctrl |= TEGRA30_I2S_CTRL_SLAVE_ENABLE;
                break;
@@ -218,7 +168,7 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
 
        mask |= TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
                TEGRA30_I2S_CTRL_LRCK_MASK;
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       switch (i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_A:
                i2s_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
                data_offset = 1;
@@ -248,14 +198,96 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
        val = (data_offset << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
              (data_offset << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
 
-       pm_runtime_get_sync(dai->dev);
+       pm_runtime_get_sync(dev);
        regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
                mask, i2s_ctrl);
        regmap_write(i2s->regmap, TEGRA30_I2S_OFFSET, val);
        regmap_update_bits(i2s->regmap, TEGRA30_I2S_CH_CTRL,
                TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK,
                i2s->fsync_width << TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT);
-       pm_runtime_put(dai->dev);
+       pm_runtime_put(dev);
+
+       return 0;
+}
+
+static int tegra30_i2s_runtime_suspend(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+
+       regcache_cache_only(i2s->regmap, true);
+
+       clk_disable_unprepare(i2s->clk_i2s);
+
+       return 0;
+}
+
+static int tegra30_i2s_runtime_resume(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(i2s->clk_i2s);
+       if (ret) {
+               dev_err(dev, "clk_enable failed: %d\n", ret);
+               return ret;
+       }
+       regcache_cache_only(i2s->regmap, false);
+       regcache_sync(i2s->regmap);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra30_i2s_suspend(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+
+       regcache_mark_dirty(i2s->regmap);
+
+       return 0;
+}
+static int tegra30_i2s_resume(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+
+       regcache_sync(i2s->regmap);
+
+       /* restore the format */
+       tegra30_i2s_set_format(dev);
+
+       return 0;
+}
+#endif
+
+static int tegra30_i2s_set_tdm_slot(struct snd_soc_dai *dai,
+               unsigned int tx_mask, unsigned int rx_mask,
+               int slots, int slot_width)
+{
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       /* copy the required tx and rx mask */
+       i2s->tx_mask = (tx_mask > 0xFFFF) ? 0xFFFF : tx_mask;
+       i2s->rx_mask = (rx_mask > 0xFFFF) ? 0xFFFF : rx_mask;
+
+       return 0;
+}
+static int tegra30_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+               unsigned int ratio)
+{
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       i2s->bclk_ratio = ratio;
+
+       return 0;
+}
+
+static int tegra30_i2s_set_dai_fmt(struct snd_soc_dai *dai,
+                               unsigned int fmt)
+{
+       struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       i2s->dai_fmt = fmt;
+       tegra30_i2s_set_format(dai->dev);
 
        return 0;
 }
@@ -476,7 +508,7 @@ static int tegra30_i2s_codec_probe(struct snd_soc_codec *codec)
 }
 
 static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
-       .set_fmt        = tegra30_i2s_set_fmt,
+       .set_fmt        = tegra30_i2s_set_dai_fmt,
        .hw_params      = tegra30_i2s_hw_params,
        .set_bclk_ratio = tegra30_i2s_set_dai_bclk_ratio,
        .set_tdm_slot   = tegra30_i2s_set_tdm_slot,
@@ -568,6 +600,7 @@ static struct snd_soc_codec_driver tegra30_i2s_codec = {
        .num_dapm_routes = ARRAY_SIZE(tegra30_i2s_routes),
        .controls = tegra30_i2s_controls,
        .num_controls = ARRAY_SIZE(tegra30_i2s_controls),
+       .idle_bias_off = 1,
 };
 
 static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
@@ -840,7 +873,9 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
 
 static const struct dev_pm_ops tegra30_i2s_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
-                          tegra30_i2s_runtime_resume, NULL)
+                       tegra30_i2s_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra30_i2s_suspend,
+                       tegra30_i2s_resume)
 };
 
 static struct platform_driver tegra30_i2s_driver = {
index bf7566a..e558d6e 100644 (file)
@@ -263,6 +263,7 @@ struct tegra30_i2s {
        unsigned int fsync_width;
        unsigned int tx_mask;
        unsigned int rx_mask;
+       unsigned int dai_fmt;
        const struct tegra30_i2s_soc_data *soc_data;
        unsigned int irq;
        spinlock_t int_lock;
index 591e0ef..6e1825e 100644 (file)
@@ -70,6 +70,25 @@ static int tegra30_spdif_runtime_resume(struct device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra30_spdif_suspend(struct device *dev)
+{
+       struct tegra30_spdif *spdif = dev_get_drvdata(dev);
+
+       regcache_mark_dirty(spdif->regmap);
+
+       return 0;
+}
+static int tegra30_spdif_resume(struct device *dev)
+{
+       struct tegra30_spdif *spdif = dev_get_drvdata(dev);
+
+       regcache_sync(spdif->regmap);
+
+       return 0;
+}
+#endif
+
 static int tegra30_spdif_set_dai_sysclk(struct snd_soc_dai *dai,
                int clk_id, unsigned int freq, int dir)
 {
@@ -112,14 +131,18 @@ static int tegra30_spdif_set_dai_sysclk(struct snd_soc_dai *dai,
        }
 
        if (dir == SND_SOC_CLOCK_OUT) {
+               pm_runtime_get_sync(dai->dev);
                ret = clk_set_rate(spdif->clk_spdif_out, spdif_out_clock_rate);
+               pm_runtime_put(dai->dev);
                if (ret) {
                        dev_err(dev, "Can't set SPDIF Out clock rate: %d\n",
                                ret);
                        return ret;
                }
        } else {
+               pm_runtime_get_sync(dai->dev);
                ret = clk_set_rate(spdif->clk_spdif_in, spdif_in_clock_rate);
+               pm_runtime_put(dai->dev);
                if (ret) {
                        dev_err(dev, "Can't set SPDIF In clock rate: %d\n",
                                ret);
@@ -130,7 +153,6 @@ static int tegra30_spdif_set_dai_sysclk(struct snd_soc_dai *dai,
        return 0;
 }
 
-
 static int tegra30_spdif_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
@@ -273,6 +295,7 @@ static struct snd_soc_codec_driver tegra30_spdif_codec = {
        .num_dapm_widgets = ARRAY_SIZE(tegra30_spdif_widgets),
        .dapm_routes = tegra30_spdif_routes,
        .num_dapm_routes = ARRAY_SIZE(tegra30_spdif_routes),
+       .idle_bias_off = 1,
 };
 
 static bool tegra30_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
@@ -463,6 +486,8 @@ static int tegra30_spdif_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra30_spdif_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_spdif_runtime_suspend,
                           tegra30_spdif_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra30_spdif_suspend,
+                          tegra30_spdif_resume)
 };
 
 static struct platform_driver tegra30_spdif_driver = {
index 4127dda..b493361 100644 (file)
 
 struct tegra30_xbar *xbar;
 
+static bool tegra30_xbar_volatile_reg(struct device *dev,
+                               unsigned int reg)
+{
+       return false;
+}
+
 static const struct regmap_config tegra30_xbar_regmap_config = {
        .reg_bits = 32,
        .val_bits = 32,
@@ -48,6 +54,7 @@ static const struct regmap_config tegra124_xbar_regmap_config = {
        .reg_stride = 4,
        .max_register = TEGRA_AHUB_AUDIO_RX1 + (TEGRA_AHUB_AUDIO_RX_STRIDE *
                        (TEGRA_AHUB_AUDIO_RX_COUNT - 1)),
+       .volatile_reg = tegra30_xbar_volatile_reg,
        .cache_type = REGCACHE_FLAT,
 };
 
@@ -75,6 +82,20 @@ static int tegra30_xbar_runtime_resume(struct device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra30_xbar_suspend(struct device *dev)
+{
+       regcache_mark_dirty(xbar->regmap);
+       return 0;
+}
+
+static int tegra30_xbar_resume(struct device *dev)
+{
+       regcache_sync(xbar->regmap);
+       return 0;
+}
+#endif
+
 static int tegra30_xbar_codec_probe(struct snd_soc_codec *codec)
 {
        int ret;
@@ -833,6 +854,8 @@ static int tegra30_xbar_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra30_xbar_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_xbar_runtime_suspend,
                           tegra30_xbar_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra30_xbar_suspend,
+                          tegra30_xbar_resume)
 };
 
 static struct platform_driver tegra30_xbar_driver = {