diff options
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 59 |
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 | ||
59 | void dump_reg(struct ccsr_ssi __iomem *ssi) | 59 | void 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 | ||
176 | static 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 | ||
1183 | static 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 | |||
1202 | static 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 | |||
1166 | static const struct dev_pm_ops fsl_ssi_pm = { | 1222 | static 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 | ||
1172 | static const struct of_device_id fsl_ssi_ids[] = { | 1229 | static const struct of_device_id fsl_ssi_ids[] = { |