aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl
diff options
context:
space:
mode:
authorNicolin Chen <Guangyu.Chen@freescale.com>2014-05-15 06:51:56 -0400
committerNicolin Chen <Guangyu.Chen@freescale.com>2014-06-19 05:07:58 -0400
commit34c50abd9df28580b367070bc20b8bca6cd7655c (patch)
tree1b750d6cdb21d164974be53132dce0ae1346438a /sound/soc/fsl
parentfd7d2c1a137c1b9d7adb58aaf06b90938172b964 (diff)
ENGR00318773-9 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. Acked-by: Wang Shengjiu <b02247@freescale.com> Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/fsl_ssi.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index a66dd375047b..331c1465a818 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -53,9 +53,9 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
53} 53}
54#endif 54#endif
55 55
56#ifdef DEBUG
57#define NUM_OF_SSI_REG (sizeof(struct ccsr_ssi) / sizeof(__be32)) 56#define NUM_OF_SSI_REG (sizeof(struct ccsr_ssi) / sizeof(__be32))
58 57
58#ifdef DEBUG
59void dump_reg(struct ccsr_ssi __iomem *ssi) 59void dump_reg(struct ccsr_ssi __iomem *ssi)
60{ 60{
61 u32 val, i; 61 u32 val, i;
@@ -169,9 +169,25 @@ struct fsl_ssi_private {
169 unsigned int tfe0; 169 unsigned int tfe0;
170 } stats; 170 } stats;
171 171
172 u32 regcache[NUM_OF_SSI_REG];
172 char name[1]; 173 char name[1];
173}; 174};
174 175
176static bool fsl_ssi_volatile_reg(unsigned int reg)
177{
178 switch (reg) {
179 case 0x0: /* stx0 */
180 case 0x4: /* stx1 */
181 case 0x8: /* srx0 */
182 case 0xc: /* srx1 */
183 case 0x14: /* sisr */
184 case 0x50: /* saccst */
185 return true;
186 default:
187 return false;
188 }
189}
190
175/** 191/**
176 * fsl_ssi_isr: SSI interrupt handler 192 * fsl_ssi_isr: SSI interrupt handler
177 * 193 *
@@ -1163,10 +1179,51 @@ static int fsl_ssi_runtime_suspend(struct device *dev)
1163} 1179}
1164#endif 1180#endif
1165 1181
1182#ifdef CONFIG_PM_SLEEP
1183static int fsl_ssi_suspend(struct device *dev)
1184{
1185 struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
1186 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
1187 int i;
1188
1189 clk_prepare_enable(ssi_private->coreclk);
1190
1191 for (i = 0; i < NUM_OF_SSI_REG; i++) {
1192 if (&ssi->stx0 + i == NULL || fsl_ssi_volatile_reg(i * 0x4))
1193 continue;
1194 ssi_private->regcache[i] = read_ssi(&ssi->stx0 + i);
1195 }
1196
1197 clk_disable_unprepare(ssi_private->coreclk);
1198
1199 return 0;
1200}
1201
1202static int fsl_ssi_resume(struct device *dev)
1203{
1204 struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
1205 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
1206 int i;
1207
1208 clk_prepare_enable(ssi_private->coreclk);
1209
1210 for (i = 0; i < NUM_OF_SSI_REG; i++) {
1211 if (&ssi->stx0 + i == NULL || fsl_ssi_volatile_reg(i * 0x4))
1212 continue;
1213 write_ssi(ssi_private->regcache[i], &ssi->stx0 + i);
1214 }
1215
1216 clk_disable_unprepare(ssi_private->coreclk);
1217
1218 return 0;
1219}
1220#endif /* CONFIG_PM_SLEEP */
1221
1166static const struct dev_pm_ops fsl_ssi_pm = { 1222static const struct dev_pm_ops fsl_ssi_pm = {
1167 SET_RUNTIME_PM_OPS(fsl_ssi_runtime_suspend, 1223 SET_RUNTIME_PM_OPS(fsl_ssi_runtime_suspend,
1168 fsl_ssi_runtime_resume, 1224 fsl_ssi_runtime_resume,
1169 NULL) 1225 NULL)
1226 SET_SYSTEM_SLEEP_PM_OPS(fsl_ssi_suspend, fsl_ssi_resume)
1170}; 1227};
1171 1228
1172static const struct of_device_id fsl_ssi_ids[] = { 1229static const struct of_device_id fsl_ssi_ids[] = {