diff options
-rw-r--r-- | sound/soc/tegra/tegra20_das.c | 36 | ||||
-rw-r--r-- | sound/soc/tegra/tegra20_das.h | 11 | ||||
-rw-r--r-- | sound/soc/tegra/tegra20_i2s.c | 51 | ||||
-rw-r--r-- | sound/soc/tegra/tegra20_i2s.h | 9 | ||||
-rw-r--r-- | sound/soc/tegra/tegra20_spdif.c | 52 | ||||
-rw-r--r-- | sound/soc/tegra/tegra20_spdif.h | 8 |
6 files changed, 167 insertions, 0 deletions
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index b647798bfadb..29ce3166052c 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -37,6 +37,9 @@ static struct tegra20_das *das; static inline void tegra20_das_write(u32 reg, u32 val) { +#ifdef CONFIG_PM + das->reg_cache[reg >> 2] = val; +#endif __raw_writel(val, das->regs + reg); } @@ -45,6 +48,24 @@ static inline u32 tegra20_das_read(u32 reg) return __raw_readl(das->regs + reg); } +#ifdef CONFIG_PM +int tegra20_das_resume() +{ + int i, reg; + + for (i = 0; i <= TEGRA20_DAS_DAP_ID_5; i++) + tegra20_das_write(i << 2, das->reg_cache[i]); + + for (i = 0; i <= TEGRA20_DAS_DAC_ID_3; i++) { + reg = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL + + (i * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); + tegra20_das_write(reg, das->reg_cache[reg >> 2]); + } + + return 0; +} +#endif + int tegra20_das_connect_dap_to_dac(int dap, int dac) { u32 addr; @@ -168,6 +189,9 @@ static int __devinit tegra20_das_probe(struct platform_device *pdev) { struct resource *res, *region; int ret = 0; +#ifdef CONFIG_PM + int i, reg; +#endif if (das) return -ENODEV; @@ -202,6 +226,18 @@ static int __devinit tegra20_das_probe(struct platform_device *pdev) goto err_release; } +#ifdef CONFIG_PM + /* populate the das reg cache with POR values*/ + for (i = 0; i <= TEGRA20_DAS_DAP_ID_5; i++) + das->reg_cache[i] = tegra20_das_read(i << 2); + + for (i = 0; i <= TEGRA20_DAS_DAC_ID_3; i++) { + reg = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL + + (i * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); + das->reg_cache[reg >> 2] = tegra20_das_read(reg); + } +#endif + tegra20_das_debug_add(das); platform_set_drvdata(pdev, das); diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h index 2fd731b70849..1d7c57fd0092 100644 --- a/sound/soc/tegra/tegra20_das.h +++ b/sound/soc/tegra/tegra20_das.h @@ -83,12 +83,23 @@ #define TEGRA20_DAS_DAC_ID_2 1 #define TEGRA20_DAS_DAC_ID_3 2 +#ifdef CONFIG_PM +#define TEGRA20_DAS_CACHE_SIZE ((((TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL) + (TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE*TEGRA20_DAS_DAC_ID_3))>>2) + 1) +#endif + struct tegra20_das { struct device *dev; void __iomem *regs; struct dentry *debug; +#ifdef CONFIG_PM + u32 reg_cache[TEGRA20_DAS_CACHE_SIZE]; +#endif }; +#ifdef CONFIG_PM +/* Restores the das registers from cache */ +extern int tegra20_das_resume(); +#endif /* * Terminology: * DAS: Digital audio switch (HW module controlled by this driver) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 3f83887a7185..c8682302b4aa 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -49,6 +49,9 @@ static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val) { +#ifdef CONFIG_PM + i2s->reg_cache[reg >> 2] = val; +#endif __raw_writel(val, i2s->regs + reg); } @@ -336,13 +339,59 @@ static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd, static int tegra20_i2s_probe(struct snd_soc_dai *dai) { struct tegra20_i2s * i2s = snd_soc_dai_get_drvdata(dai); +#ifdef CONFIG_PM + int i; +#endif dai->capture_dma_data = &i2s->capture_dma_data; dai->playback_dma_data = &i2s->playback_dma_data; +#ifdef CONFIG_PM + /* populate the i2s reg cache with POR values*/ + clk_enable(i2s->clk_i2s); + + for (i = 0; i < ((TEGRA20_I2S_TDM_TX_RX_CTRL >> 2) + 1); i++) { + if ((i == TEGRA20_I2S_CACHE_RSVD_6) || + (i == TEGRA20_I2S_CACHE_RSVD_7)) + continue; + + i2s->reg_cache[i] = tegra20_i2s_read(i2s, i << 2); + } + + clk_disable(i2s->clk_i2s); +#endif + return 0; } +#ifdef CONFIG_PM +int tegra20_i2s_resume(struct snd_soc_dai *cpu_dai) +{ + struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); + int i; + + clk_enable(i2s->clk_i2s); + + /*restore the i2s regs*/ + for (i = 0; i < ((TEGRA20_I2S_TDM_TX_RX_CTRL >> 2) + 1); i++) { + if ((i == TEGRA20_I2S_CACHE_RSVD_6) || + (i == TEGRA20_I2S_CACHE_RSVD_7)) + continue; + + tegra20_i2s_write(i2s, i << 2, i2s->reg_cache[i]); + } + + /*restore the das regs*/ + tegra20_das_resume(); + + clk_disable(i2s->clk_i2s); + + return 0; +} +#else +#define tegra20_i2s_resume NULL +#endif + static struct snd_soc_dai_ops tegra20_i2s_dai_ops = { .set_fmt = tegra20_i2s_set_fmt, .hw_params = tegra20_i2s_hw_params, @@ -353,6 +402,7 @@ struct snd_soc_dai_driver tegra20_i2s_dai[] = { { .name = DRV_NAME ".0", .probe = tegra20_i2s_probe, + .resume = tegra20_i2s_resume, .playback = { .channels_min = 1, .channels_max = 2, @@ -371,6 +421,7 @@ struct snd_soc_dai_driver tegra20_i2s_dai[] = { { .name = DRV_NAME ".1", .probe = tegra20_i2s_probe, + .resume = tegra20_i2s_resume, .playback = { .channels_min = 1, .channels_max = 2, diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h index b2d3ef710599..ded0c8dee023 100644 --- a/sound/soc/tegra/tegra20_i2s.h +++ b/sound/soc/tegra/tegra20_i2s.h @@ -177,6 +177,12 @@ #define TEGRA20_I2S_PCM_CTRL_RCV_MODE_EN (1 << 0) +#ifdef CONFIG_PM +/* unused cache locations for i2s reg cache */ +#define TEGRA20_I2S_CACHE_RSVD_6 ((TEGRA20_I2S_NW_CTRL>>2) + 1) +#define TEGRA20_I2S_CACHE_RSVD_7 (TEGRA20_I2S_CACHE_RSVD_6 + 1) +#endif + struct tegra20_i2s { struct clk *clk_i2s; struct tegra_pcm_dma_params capture_dma_data; @@ -184,6 +190,9 @@ struct tegra20_i2s { void __iomem *regs; struct dentry *debug; u32 reg_ctrl; +#ifdef CONFIG_PM + u32 reg_cache[(TEGRA20_I2S_TDM_TX_RX_CTRL >> 2) + 1]; +#endif }; #endif diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index e5ef59841566..3e747b5e1931 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -42,6 +42,13 @@ static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg, u32 val) { +#ifdef CONFIG_PM + if (reg < TEGRA20_SPDIF_CH_STA_TX_A) + spdif->reg_ctrl_cache[reg >> 2] = val; + else + spdif->reg_tx_cache[((reg - TEGRA20_SPDIF_CH_STA_TX_A) >> 2)] + = val; +#endif __raw_writel(val, spdif->regs + reg); } @@ -250,13 +257,57 @@ static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd, static int tegra20_spdif_probe(struct snd_soc_dai *dai) { struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); +#ifdef CONFIG_PM + int i, reg; +#endif dai->capture_dma_data = NULL; dai->playback_dma_data = &spdif->playback_dma_data; +#ifdef CONFIG_PM + clk_enable(spdif->clk_spdif_out); + + /* populate the spdif reg cache with POR values*/ + for (i = 0; i < TEGRA20_SPDIF_CTRL_CACHE_SIZE; i++) + spdif->reg_ctrl_cache[i] = tegra20_spdif_read(spdif, i << 2); + + for (i = 0; i < TEGRA20_SPDIF_TX_CACHE_SIZE; i++) { + reg = (TEGRA20_SPDIF_CH_STA_TX_A) + (i << 2); + spdif->reg_tx_cache[i] = tegra20_spdif_read(spdif, reg); + } + + clk_disable(spdif->clk_spdif_out); + +#endif + return 0; } +#ifdef CONFIG_PM +int tegra20_spdif_resume(struct snd_soc_dai *cpu_dai) +{ + struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(cpu_dai); + int i, reg; + + clk_enable(spdif->clk_spdif_out); + + /*restore the spdif regs*/ + for (i = 0; i < TEGRA20_SPDIF_CTRL_CACHE_SIZE; i++) + tegra20_spdif_write(spdif, i << 2, spdif->reg_ctrl_cache[i]); + + for (i = 0; i < TEGRA20_SPDIF_TX_CACHE_SIZE; i++) { + reg = (TEGRA20_SPDIF_CH_STA_TX_A) + (i << 2); + tegra20_spdif_write(spdif, reg, spdif->reg_tx_cache[i]); + } + + clk_disable(spdif->clk_spdif_out); + + return 0; +} +#else +#define tegra20_spdif_resume NULL +#endif + static struct snd_soc_dai_ops tegra20_spdif_dai_ops = { .hw_params = tegra20_spdif_hw_params, .trigger = tegra20_spdif_trigger, @@ -265,6 +316,7 @@ static struct snd_soc_dai_ops tegra20_spdif_dai_ops = { struct snd_soc_dai_driver tegra20_spdif_dai = { .name = DRV_NAME, .probe = tegra20_spdif_probe, + .resume = tegra20_spdif_resume, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h index 1938aa67917f..c1fb6ed2a79f 100644 --- a/sound/soc/tegra/tegra20_spdif.h +++ b/sound/soc/tegra/tegra20_spdif.h @@ -535,6 +535,10 @@ * This 4-word deep FIFO transmits user FIFO field information. The order of * transmission is from LSB to MSB bit. */ +#ifdef CONFIG_PM +#define TEGRA20_SPDIF_CTRL_CACHE_SIZE ((TEGRA20_SPDIF_DATA_FIFO_CSR >> 2) + 1) +#define TEGRA20_SPDIF_TX_CACHE_SIZE (((TEGRA20_SPDIF_CH_STA_TX_F - TEGRA20_SPDIF_CH_STA_TX_A) >> 2) + 1) +#endif struct tegra20_spdif { struct clk *clk_spdif_out; @@ -543,6 +547,10 @@ struct tegra20_spdif { void __iomem *regs; struct dentry *debug; u32 reg_ctrl; +#ifdef CONFIG_PM + u32 reg_ctrl_cache[TEGRA20_SPDIF_CTRL_CACHE_SIZE]; + u32 reg_tx_cache[TEGRA20_SPDIF_TX_CACHE_SIZE]; +#endif }; #endif |