summaryrefslogtreecommitdiff
path: root/sound/soc/sh
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sh')
-rw-r--r--sound/soc/sh/fsi.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 5a2fdf3b84b9..1029a03c618e 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -153,6 +153,13 @@ struct fsi_priv {
int clk_master:1;
long rate;
+
+ /* for suspend/resume */
+ u32 saved_do_fmt;
+ u32 saved_di_fmt;
+ u32 saved_ckg1;
+ u32 saved_ckg2;
+ u32 saved_out_sel;
};
struct fsi_core {
@@ -173,6 +180,13 @@ struct fsi_master {
struct fsi_core *core;
struct sh_fsi_platform_info *info;
spinlock_t lock;
+
+ /* for suspend/resume */
+ u32 saved_a_mclk;
+ u32 saved_b_mclk;
+ u32 saved_iemsk;
+ u32 saved_imsk;
+ u32 saved_clk_rst;
};
/*
@@ -1277,6 +1291,76 @@ static int fsi_remove(struct platform_device *pdev)
return 0;
}
+static void __fsi_suspend(struct fsi_priv *fsi,
+ struct device *dev,
+ set_rate_func set_rate)
+{
+ fsi->saved_do_fmt = fsi_reg_read(fsi, DO_FMT);
+ fsi->saved_di_fmt = fsi_reg_read(fsi, DI_FMT);
+ fsi->saved_ckg1 = fsi_reg_read(fsi, CKG1);
+ fsi->saved_ckg2 = fsi_reg_read(fsi, CKG2);
+ fsi->saved_out_sel = fsi_reg_read(fsi, OUT_SEL);
+
+ if (fsi_is_clk_master(fsi))
+ set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0);
+}
+
+static void __fsi_resume(struct fsi_priv *fsi,
+ struct device *dev,
+ set_rate_func set_rate)
+{
+ fsi_reg_write(fsi, DO_FMT, fsi->saved_do_fmt);
+ fsi_reg_write(fsi, DI_FMT, fsi->saved_di_fmt);
+ fsi_reg_write(fsi, CKG1, fsi->saved_ckg1);
+ fsi_reg_write(fsi, CKG2, fsi->saved_ckg2);
+ fsi_reg_write(fsi, OUT_SEL, fsi->saved_out_sel);
+
+ if (fsi_is_clk_master(fsi))
+ set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1);
+}
+
+static int fsi_suspend(struct device *dev)
+{
+ struct fsi_master *master = dev_get_drvdata(dev);
+ set_rate_func set_rate = fsi_get_info_set_rate(master);
+
+ pm_runtime_get_sync(dev);
+
+ __fsi_suspend(&master->fsia, dev, set_rate);
+ __fsi_suspend(&master->fsib, dev, set_rate);
+
+ master->saved_a_mclk = fsi_core_read(master, a_mclk);
+ master->saved_b_mclk = fsi_core_read(master, b_mclk);
+ master->saved_iemsk = fsi_core_read(master, iemsk);
+ master->saved_imsk = fsi_core_read(master, imsk);
+ master->saved_clk_rst = fsi_master_read(master, CLK_RST);
+
+ pm_runtime_put_sync(dev);
+
+ return 0;
+}
+
+static int fsi_resume(struct device *dev)
+{
+ struct fsi_master *master = dev_get_drvdata(dev);
+ set_rate_func set_rate = fsi_get_info_set_rate(master);
+
+ pm_runtime_get_sync(dev);
+
+ __fsi_resume(&master->fsia, dev, set_rate);
+ __fsi_resume(&master->fsib, dev, set_rate);
+
+ fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk);
+ fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk);
+ fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk);
+ fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk);
+ fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst);
+
+ pm_runtime_put_sync(dev);
+
+ return 0;
+}
+
static int fsi_runtime_nop(struct device *dev)
{
/* Runtime PM callback shared between ->runtime_suspend()
@@ -1290,6 +1374,8 @@ static int fsi_runtime_nop(struct device *dev)
}
static struct dev_pm_ops fsi_pm_ops = {
+ .suspend = fsi_suspend,
+ .resume = fsi_resume,
.runtime_suspend = fsi_runtime_nop,
.runtime_resume = fsi_runtime_nop,
};