aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZidan Wang <zidan.wang@freescale.com>2015-09-17 23:09:12 -0400
committerMark Brown <broonie@kernel.org>2015-10-05 12:26:18 -0400
commit05cf237972fe65eb537ea4f10e5627ceeb8f89b6 (patch)
tree50d08578783b8b296e39850ffce952632bc714cd
parentf9f4fa61aab9417e40898cf6706fffa94005dc44 (diff)
ASoC: fsl_ssi: Add driver suspend and resume to support MEGA Fast
For i.MX6 SoloX, there is a mode of the SoC to shutdown all power source of modules during system suspend and resume procedure. Thus, SSI needs to save all the values of registers before the system suspend and restore them after the system resume. The register SFCSR is volatile, but some bits in it need to be recovered after suspend/resume. Signed-off-by: Zidan Wang <zidan.wang@freescale.com> Acked-by: Nicolin Chen <nicoleotsuka@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/fsl/fsl_ssi.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 8ec6fb208ea0..7c495d3d188a 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -111,12 +111,75 @@ struct fsl_ssi_rxtx_reg_val {
111 struct fsl_ssi_reg_val rx; 111 struct fsl_ssi_reg_val rx;
112 struct fsl_ssi_reg_val tx; 112 struct fsl_ssi_reg_val tx;
113}; 113};
114
115static const struct reg_default fsl_ssi_reg_defaults[] = {
116 {0x10, 0x00000000},
117 {0x18, 0x00003003},
118 {0x1c, 0x00000200},
119 {0x20, 0x00000200},
120 {0x24, 0x00040000},
121 {0x28, 0x00040000},
122 {0x38, 0x00000000},
123 {0x48, 0x00000000},
124 {0x4c, 0x00000000},
125 {0x54, 0x00000000},
126 {0x58, 0x00000000},
127};
128
129static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
130{
131 switch (reg) {
132 case CCSR_SSI_SACCEN:
133 case CCSR_SSI_SACCDIS:
134 return false;
135 default:
136 return true;
137 }
138}
139
140static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
141{
142 switch (reg) {
143 case CCSR_SSI_STX0:
144 case CCSR_SSI_STX1:
145 case CCSR_SSI_SRX0:
146 case CCSR_SSI_SRX1:
147 case CCSR_SSI_SISR:
148 case CCSR_SSI_SFCSR:
149 case CCSR_SSI_SACADD:
150 case CCSR_SSI_SACDAT:
151 case CCSR_SSI_SATAG:
152 case CCSR_SSI_SACCST:
153 return true;
154 default:
155 return false;
156 }
157}
158
159static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg)
160{
161 switch (reg) {
162 case CCSR_SSI_SRX0:
163 case CCSR_SSI_SRX1:
164 case CCSR_SSI_SACCST:
165 return false;
166 default:
167 return true;
168 }
169}
170
114static const struct regmap_config fsl_ssi_regconfig = { 171static const struct regmap_config fsl_ssi_regconfig = {
115 .max_register = CCSR_SSI_SACCDIS, 172 .max_register = CCSR_SSI_SACCDIS,
116 .reg_bits = 32, 173 .reg_bits = 32,
117 .val_bits = 32, 174 .val_bits = 32,
118 .reg_stride = 4, 175 .reg_stride = 4,
119 .val_format_endian = REGMAP_ENDIAN_NATIVE, 176 .val_format_endian = REGMAP_ENDIAN_NATIVE,
177 .reg_defaults = fsl_ssi_reg_defaults,
178 .num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults),
179 .readable_reg = fsl_ssi_readable_reg,
180 .volatile_reg = fsl_ssi_volatile_reg,
181 .writeable_reg = fsl_ssi_writeable_reg,
182 .cache_type = REGCACHE_RBTREE,
120}; 183};
121 184
122struct fsl_ssi_soc_data { 185struct fsl_ssi_soc_data {
@@ -176,6 +239,9 @@ struct fsl_ssi_private {
176 unsigned int baudclk_streams; 239 unsigned int baudclk_streams;
177 unsigned int bitclk_freq; 240 unsigned int bitclk_freq;
178 241
242 /*regcache for SFCSR*/
243 u32 regcache_sfcsr;
244
179 /* DMA params */ 245 /* DMA params */
180 struct snd_dmaengine_dai_dma_data dma_params_tx; 246 struct snd_dmaengine_dai_dma_data dma_params_tx;
181 struct snd_dmaengine_dai_dma_data dma_params_rx; 247 struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -1513,10 +1579,46 @@ static int fsl_ssi_remove(struct platform_device *pdev)
1513 return 0; 1579 return 0;
1514} 1580}
1515 1581
1582#ifdef CONFIG_PM_SLEEP
1583static int fsl_ssi_suspend(struct device *dev)
1584{
1585 struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
1586 struct regmap *regs = ssi_private->regs;
1587
1588 regmap_read(regs, CCSR_SSI_SFCSR,
1589 &ssi_private->regcache_sfcsr);
1590
1591 regcache_cache_only(regs, true);
1592 regcache_mark_dirty(regs);
1593
1594 return 0;
1595}
1596
1597static int fsl_ssi_resume(struct device *dev)
1598{
1599 struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
1600 struct regmap *regs = ssi_private->regs;
1601
1602 regcache_cache_only(regs, false);
1603
1604 regmap_update_bits(regs, CCSR_SSI_SFCSR,
1605 CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK |
1606 CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK,
1607 ssi_private->regcache_sfcsr);
1608
1609 return regcache_sync(regs);
1610}
1611#endif /* CONFIG_PM_SLEEP */
1612
1613static const struct dev_pm_ops fsl_ssi_pm = {
1614 SET_SYSTEM_SLEEP_PM_OPS(fsl_ssi_suspend, fsl_ssi_resume)
1615};
1616
1516static struct platform_driver fsl_ssi_driver = { 1617static struct platform_driver fsl_ssi_driver = {
1517 .driver = { 1618 .driver = {
1518 .name = "fsl-ssi-dai", 1619 .name = "fsl-ssi-dai",
1519 .of_match_table = fsl_ssi_ids, 1620 .of_match_table = fsl_ssi_ids,
1621 .pm = &fsl_ssi_pm,
1520 }, 1622 },
1521 .probe = fsl_ssi_probe, 1623 .probe = fsl_ssi_probe,
1522 .remove = fsl_ssi_remove, 1624 .remove = fsl_ssi_remove,