summaryrefslogtreecommitdiff
path: root/sound/soc/img/img-i2s-out.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-11-13 15:45:57 +0100
committerTakashi Iwai <tiwai@suse.de>2017-11-13 15:45:57 +0100
commit76727c2c3bf4a5e58dff8cca23d0147ba08fb2c8 (patch)
treec84c07b9deac4425190777a962f6788d355a0dd1 /sound/soc/img/img-i2s-out.c
parentc429bda21ffafb28f02fb2eb4055b4ab6879ed58 (diff)
parentdf6a3e245541ac61cc99f2887437e0a43dd08f2e (diff)
Merge tag 'asoc-v4.15' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v4.15 The biggest thing this release has been the conversion of the AC98 bus to the driver model, that's been a long time coming so thanks to Robert Jarzmik for his dedication there. Due to there being some AC97 MFD there's a few fairly large changes in input and the MFD layer, mainly to the wm97xx driver. There's also some drivers/drm changes to support the new AMD Stoney platform, these are shared with the DRM subsystem and should be being merged via both. Within the subsystem the overwhelming bulk of the changes is in the Intel drivers which continue to need lots of cleanups and fixes, this release they've also gained support for their open source firmware. There's also some large changs in the core as Morimoto-san continues to mirror operations into the component level in preparation for conversion of drivers to that. - The AC97 bus has finally caught up with the driver model thanks to some dedicated and persistent work from Robert Jarzmik. - Continued work from Morimoto-san on moving us towards being able to use components for everything. - Lots of cleanups for the Intel platform code, including support for their open source audio firmware. - Support for scaling MCLK with sample rate in simple-card. - Support for AMD Stoney platform.
Diffstat (limited to 'sound/soc/img/img-i2s-out.c')
-rw-r--r--sound/soc/img/img-i2s-out.c120
1 files changed, 91 insertions, 29 deletions
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index 78b7f6cd675b..30a95bcef2db 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -63,29 +63,36 @@ struct img_i2s_out {
unsigned int active_channels;
struct reset_control *rst;
struct snd_soc_dai_driver dai_driver;
+ u32 suspend_ctl;
+ u32 *suspend_ch_ctl;
};
-static int img_i2s_out_suspend(struct device *dev)
+static int img_i2s_out_runtime_suspend(struct device *dev)
{
struct img_i2s_out *i2s = dev_get_drvdata(dev);
- if (!i2s->force_clk_active)
- clk_disable_unprepare(i2s->clk_ref);
+ clk_disable_unprepare(i2s->clk_ref);
+ clk_disable_unprepare(i2s->clk_sys);
return 0;
}
-static int img_i2s_out_resume(struct device *dev)
+static int img_i2s_out_runtime_resume(struct device *dev)
{
struct img_i2s_out *i2s = dev_get_drvdata(dev);
int ret;
- if (!i2s->force_clk_active) {
- ret = clk_prepare_enable(i2s->clk_ref);
- if (ret) {
- dev_err(dev, "clk_enable failed: %d\n", ret);
- return ret;
- }
+ ret = clk_prepare_enable(i2s->clk_sys);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(i2s->clk_ref);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ clk_disable_unprepare(i2s->clk_sys);
+ return ret;
}
return 0;
@@ -287,7 +294,7 @@ static int img_i2s_out_hw_params(struct snd_pcm_substream *substream,
static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
- int i;
+ int i, ret;
bool force_clk_active;
u32 chan_control_mask, control_mask, chan_control_set = 0;
u32 reg, control_set = 0;
@@ -342,6 +349,10 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
+ ret = pm_runtime_get_sync(i2s->dev);
+ if (ret < 0)
+ return ret;
+
img_i2s_out_disable(i2s);
reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
@@ -361,6 +372,7 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
img_i2s_out_ch_enable(i2s, i);
img_i2s_out_enable(i2s);
+ pm_runtime_put(i2s->dev);
i2s->force_clk_active = force_clk_active;
@@ -467,9 +479,20 @@ static int img_i2s_out_probe(struct platform_device *pdev)
return PTR_ERR(i2s->clk_ref);
}
- ret = clk_prepare_enable(i2s->clk_sys);
- if (ret)
- return ret;
+ i2s->suspend_ch_ctl = devm_kzalloc(dev,
+ sizeof(*i2s->suspend_ch_ctl) * i2s->max_i2s_chan, GFP_KERNEL);
+ if (!i2s->suspend_ch_ctl)
+ return -ENOMEM;
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = img_i2s_out_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ goto err_suspend;
reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK;
img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
@@ -483,13 +506,7 @@ static int img_i2s_out_probe(struct platform_device *pdev)
img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
img_i2s_out_reset(i2s);
-
- pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev)) {
- ret = img_i2s_out_resume(&pdev->dev);
- if (ret)
- goto err_pm_disable;
- }
+ pm_runtime_put(&pdev->dev);
i2s->active_channels = 1;
i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO;
@@ -517,26 +534,70 @@ static int img_i2s_out_probe(struct platform_device *pdev)
err_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
- img_i2s_out_suspend(&pdev->dev);
+ img_i2s_out_runtime_suspend(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(i2s->clk_sys);
return ret;
}
static int img_i2s_out_dev_remove(struct platform_device *pdev)
{
- struct img_i2s_out *i2s = platform_get_drvdata(pdev);
-
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
- img_i2s_out_suspend(&pdev->dev);
+ img_i2s_out_runtime_suspend(&pdev->dev);
- clk_disable_unprepare(i2s->clk_sys);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int img_i2s_out_suspend(struct device *dev)
+{
+ struct img_i2s_out *i2s = dev_get_drvdata(dev);
+ int i, ret;
+ u32 reg;
+
+ if (pm_runtime_status_suspended(dev)) {
+ ret = img_i2s_out_runtime_resume(dev);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < i2s->max_i2s_chan; i++) {
+ reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL);
+ i2s->suspend_ch_ctl[i] = reg;
+ }
+
+ i2s->suspend_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+
+ img_i2s_out_runtime_suspend(dev);
+
+ return 0;
+}
+
+static int img_i2s_out_resume(struct device *dev)
+{
+ struct img_i2s_out *i2s = dev_get_drvdata(dev);
+ int i, ret;
+ u32 reg;
+
+ ret = img_i2s_out_runtime_resume(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < i2s->max_i2s_chan; i++) {
+ reg = i2s->suspend_ch_ctl[i];
+ img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
+ }
+
+ img_i2s_out_writel(i2s, i2s->suspend_ctl, IMG_I2S_OUT_CTL);
+
+ if (pm_runtime_status_suspended(dev))
+ img_i2s_out_runtime_suspend(dev);
return 0;
}
+#endif
static const struct of_device_id img_i2s_out_of_match[] = {
{ .compatible = "img,i2s-out" },
@@ -545,8 +606,9 @@ static const struct of_device_id img_i2s_out_of_match[] = {
MODULE_DEVICE_TABLE(of, img_i2s_out_of_match);
static const struct dev_pm_ops img_i2s_out_pm_ops = {
- SET_RUNTIME_PM_OPS(img_i2s_out_suspend,
- img_i2s_out_resume, NULL)
+ SET_RUNTIME_PM_OPS(img_i2s_out_runtime_suspend,
+ img_i2s_out_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(img_i2s_out_suspend, img_i2s_out_resume)
};
static struct platform_driver img_i2s_out_driver = {