From 071ededc197a4a867abecb0bba308585b33fb5b9 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 10 Jan 2019 19:19:31 +0900 Subject: [PATCH 01/16] gpu/drm: Fix lock held when returning to user space. We need to call drm_modeset_acquire_fini() when drm_atomic_state_alloc() failed or call drm_modeset_acquire_init() after drm_atomic_state_alloc() succeeded. Signed-off-by: Tetsuo Handa Reported-by: syzbot Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1547115571-21219-1-git-send-email-penguin-kernel@I-love.SAKURA.ne.jp [hoegeun.kwon: this patch from the mainline 4089e272ac61 and it has been modified to be able to backport linux-v4.14.] Change-Id: Iaa0d6e104054abc11181c43bdb6283a8bd30eb19 Signed-off-by: Hoegeun Kwon --- drivers/gpu/drm/drm_atomic.c | 3 +-- drivers/gpu/drm/drm_mode_object.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index bb5cc15..8bb5088 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -2247,12 +2247,11 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) return -EINVAL; - drm_modeset_acquire_init(&ctx, 0); - state = drm_atomic_state_alloc(dev); if (!state) return -ENOMEM; + drm_modeset_acquire_init(&ctx, 0); state->acquire_ctx = &ctx; state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index 1055533..4177ee2 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -432,11 +432,11 @@ static int set_property_atomic(struct drm_mode_object *obj, struct drm_modeset_acquire_ctx ctx; int ret; - drm_modeset_acquire_init(&ctx, 0); - state = drm_atomic_state_alloc(dev); if (!state) return -ENOMEM; + + drm_modeset_acquire_init(&ctx, 0); state->acquire_ctx = &ctx; retry: if (prop == state->dev->mode_config.dpms_property) { -- 2.7.4 From 0a7ed2f37ca4a59d008d113cfc8f6b87afdbd66a Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 27 Feb 2019 10:54:37 +0100 Subject: [PATCH 02/16] ASoC: Revert "LOCAL / temporary workaround for i2s/prepare_lock deadlock" This reverts commit a146d53312cc7151d7aa5d517b808d2d1fdfd6c1. Revert temporarily in order to apply patches from the mainline cleanly. Change-Id: I2cce77968974c36d8ccbe4b2df75b77113e6d5bf Signed-off-by: Sylwester Nawrocki --- sound/soc/samsung/i2s.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index cbfb9b7..f914ed4 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -592,11 +592,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, writel(mod, i2s->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); done: - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); return 0; err: - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); return ret; } @@ -680,7 +680,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, if (any_active(i2s) && ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { spin_unlock_irqrestore(i2s->lock, flags); - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; @@ -690,7 +690,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, mod |= tmp; writel(mod, i2s->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); return 0; } @@ -832,7 +832,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, spin_unlock_irqrestore(&lock, flags); - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); } static int config_setup(struct i2s_dai *i2s) @@ -941,7 +941,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream, } spin_unlock_irqrestore(i2s->lock, flags); - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); break; } @@ -959,13 +959,13 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai, pm_runtime_get_sync(dai->dev); if ((any_active(i2s) && div && (get_bfs(i2s) != div)) || (other && other->bfs && (other->bfs != div))) { - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; } i2s->bfs = div; - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); break; default: dev_err(&i2s->pdev->dev, @@ -1051,7 +1051,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) if (!is_opened(other)) i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK, 0, SND_SOC_CLOCK_IN); - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); return 0; } @@ -1071,7 +1071,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) } } - pm_runtime_put_sync(dai->dev); + pm_runtime_put(dai->dev); return 0; } -- 2.7.4 From 2812817b6716fb50d093d9c45cc838cea9555dd9 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 15:20:41 +0100 Subject: [PATCH 03/16] ASoC: samsung: Prevent clk_get_rate() calls in atomic context MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This patch moves clk_get_rate() call from trigger() to hw_params() callback to avoid calling sleeping clk API from atomic context and prevent deadlock as indicated below. Before this change clk_get_rate() was being called with same spinlock held as the one passed to the clk API when registering clocks exposed by the I2S driver. [ 82.109780] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:908 [ 82.117009] in_atomic(): 1, irqs_disabled(): 128, pid: 1554, name: speaker-test [ 82.124235] 3 locks held by speaker-test/1554: [ 82.128653] #0: cc8c5328 (snd_pcm_link_rwlock){...-}, at: snd_pcm_stream_lock_irq+0x20/0x38 [ 82.137058] #1: ec9eda17 (&(&substream->self_group.lock)->rlock){..-.}, at: snd_pcm_ioctl+0x900/0x1268 [ 82.146417] #2: 6ac279bf (&(&pri_dai->spinlock)->rlock){..-.}, at: i2s_trigger+0x64/0x6d4 [ 82.154650] irq event stamp: 8144 [ 82.157949] hardirqs last enabled at (8143): [] _raw_read_unlock_irq+0x24/0x5c [ 82.166089] hardirqs last disabled at (8144): [] _raw_read_lock_irq+0x18/0x58 [ 82.174063] softirqs last enabled at (8004): [] __do_softirq+0x3a4/0x66c [ 82.181688] softirqs last disabled at (7997): [] irq_exit+0x140/0x168 [ 82.188964] Preemption disabled at: [ 82.188967] [<00000000>] (null) [ 82.195728] CPU: 6 PID: 1554 Comm: speaker-test Not tainted 5.0.0-rc5-00192-ga6e6caca8f03 #191 [ 82.204302] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 82.210376] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 82.218084] [] (show_stack) from [] (dump_stack+0x90/0xc8) [ 82.225278] [] (dump_stack) from [] (___might_sleep+0x22c/0x2c8) [ 82.232990] [] (___might_sleep) from [] (__mutex_lock+0x28/0xa3c) [ 82.240788] [] (__mutex_lock) from [] (mutex_lock_nested+0x1c/0x24) [ 82.248763] [] (mutex_lock_nested) from [] (clk_prepare_lock+0x78/0xec) [ 82.257079] [] (clk_prepare_lock) from [] (clk_core_get_rate+0xc/0x5c) [ 82.265309] [] (clk_core_get_rate) from [] (i2s_trigger+0x490/0x6d4) [ 82.273369] [] (i2s_trigger) from [] (soc_pcm_trigger+0x100/0x140) [ 82.281254] [] (soc_pcm_trigger) from [] (snd_pcm_do_start+0x2c/0x30) [ 82.289400] [] (snd_pcm_do_start) from [] (snd_pcm_action_single+0x38/0x78) [ 82.298065] [] (snd_pcm_action_single) from [] (snd_pcm_ioctl+0x910/0x1268) [ 82.306734] [] (snd_pcm_ioctl) from [] (do_vfs_ioctl+0x90/0x9ec) [ 82.314443] [] (do_vfs_ioctl) from [] (ksys_ioctl+0x34/0x60) [ 82.321808] [] (ksys_ioctl) from [] (ret_fast_syscall+0x0/0x28) [ 82.329431] Exception stack(0xeb875fa8 to 0xeb875ff0) [ 82.334459] 5fa0: 00033c18 b6e31000 00000004 00004142 00033d80 00033d80 [ 82.342605] 5fc0: 00033c18 b6e31000 00008000 00000036 00008000 00000000 beea38a8 00008000 [ 82.350748] 5fe0: b6e3142c beea384c b6da9a30 b6c9212c [ 82.355789] [ 82.357245] ====================================================== [ 82.363397] WARNING: possible circular locking dependency detected [ 82.369551] 5.0.0-rc5-00192-ga6e6caca8f03 #191 Tainted: G W [ 82.376395] ------------------------------------------------------ [ 82.382548] speaker-test/1554 is trying to acquire lock: [ 82.387834] 6d2007f4 (prepare_lock){+.+.}, at: clk_prepare_lock+0x78/0xec [ 82.394593] [ 82.394593] but task is already holding lock: [ 82.400398] 6ac279bf (&(&pri_dai->spinlock)->rlock){..-.}, at: i2s_trigger+0x64/0x6d4 [ 82.408197] [ 82.408197] which lock already depends on the new lock. [ 82.416343] [ 82.416343] the existing dependency chain (in reverse order) is: [ 82.423795] [ 82.423795] -> #1 (&(&pri_dai->spinlock)->rlock){..-.}: [ 82.430472] clk_mux_set_parent+0x34/0xb8 [ 82.434975] clk_core_set_parent_nolock+0x1c4/0x52c [ 82.440347] clk_set_parent+0x38/0x6c [ 82.444509] of_clk_set_defaults+0xc8/0x308 [ 82.449186] of_clk_add_provider+0x84/0xd0 [ 82.453779] samsung_i2s_probe+0x408/0x5f8 [ 82.458376] platform_drv_probe+0x48/0x98 [ 82.462879] really_probe+0x224/0x3f4 [ 82.467037] driver_probe_device+0x70/0x1c4 [ 82.471716] bus_for_each_drv+0x44/0x8c [ 82.476049] __device_attach+0xa0/0x138 [ 82.480382] bus_probe_device+0x88/0x90 [ 82.484715] deferred_probe_work_func+0x6c/0xbc [ 82.489741] process_one_work+0x200/0x740 [ 82.494246] worker_thread+0x2c/0x4c8 [ 82.498408] kthread+0x128/0x164 [ 82.502131] ret_from_fork+0x14/0x20 [ 82.506204] (null) [ 82.508976] [ 82.508976] -> #0 (prepare_lock){+.+.}: [ 82.514264] __mutex_lock+0x60/0xa3c [ 82.518336] mutex_lock_nested+0x1c/0x24 [ 82.522756] clk_prepare_lock+0x78/0xec [ 82.527088] clk_core_get_rate+0xc/0x5c [ 82.531421] i2s_trigger+0x490/0x6d4 [ 82.535494] soc_pcm_trigger+0x100/0x140 [ 82.539913] snd_pcm_do_start+0x2c/0x30 [ 82.544246] snd_pcm_action_single+0x38/0x78 [ 82.549012] snd_pcm_ioctl+0x910/0x1268 [ 82.553345] do_vfs_ioctl+0x90/0x9ec [ 82.557417] ksys_ioctl+0x34/0x60 [ 82.561229] ret_fast_syscall+0x0/0x28 [ 82.565477] 0xbeea384c [ 82.568421] [ 82.568421] other info that might help us debug this: [ 82.568421] [ 82.576394] Possible unsafe locking scenario: [ 82.576394] [ 82.582285] CPU0 CPU1 [ 82.586792] ---- ---- [ 82.591297] lock(&(&pri_dai->spinlock)->rlock); [ 82.595977] lock(prepare_lock); [ 82.601782] lock(&(&pri_dai->spinlock)->rlock); [ 82.608975] lock(prepare_lock); [ 82.612268] [ 82.612268] *** DEADLOCK *** Fixes: 647d04f8e07a ("ASoC: samsung: i2s: Ensure the RCLK rate is properly determined") Change-Id: I1b8100d4e65a1d9964aa92d2ac56965a01359791 Reported-by: Krzysztof Kozłowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f914ed4..582b980 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -700,6 +700,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, { struct i2s_dai *i2s = to_info(dai); u32 mod, mask = 0, val = 0; + struct clk *rclksrc; unsigned long flags; WARN_ON(!pm_runtime_active(dai->dev)); @@ -781,6 +782,10 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, i2s->frmclk = params_rate(params); + rclksrc = i2s->clk_table[CLK_I2S_RCLK_SRC]; + if (rclksrc && !IS_ERR(rclksrc)) + i2s->rclk_srcrate = clk_get_rate(rclksrc); + return 0; } @@ -885,11 +890,6 @@ static int config_setup(struct i2s_dai *i2s) return 0; if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { - struct clk *rclksrc = i2s->clk_table[CLK_I2S_RCLK_SRC]; - - if (rclksrc && !IS_ERR(rclksrc)) - i2s->rclk_srcrate = clk_get_rate(rclksrc); - psr = i2s->rclk_srcrate / i2s->frmclk / rfs; writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR); dev_dbg(&i2s->pdev->dev, -- 2.7.4 From b2f6576efa9ef15f659b494d34de813310f3cfaa Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:12 +0100 Subject: [PATCH 04/16] ASoC: samsung: i2s: Fix prescaler setting for the secondary DAI Make sure i2s->rclk_srcrate is properly initialized also during playback through the secondary DAI. Change-Id: Ic27fe0b834379a95485668137eee1e7d22d93952 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 582b980..b712c02 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -604,6 +604,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct i2s_dai *i2s = to_info(dai); + struct i2s_dai *other = get_other_dai(i2s); int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; u32 mod, tmp = 0; unsigned long flags; @@ -661,7 +662,8 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any * clock configuration assigned in DT is not overwritten. */ - if (i2s->rclk_srcrate == 0 && i2s->clk_data.clks == NULL) + if (i2s->rclk_srcrate == 0 && i2s->clk_data.clks == NULL && + other->clk_data.clks == NULL) i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0, 0, SND_SOC_CLOCK_IN); break; @@ -699,6 +701,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); + struct i2s_dai *other = get_other_dai(i2s); u32 mod, mask = 0, val = 0; struct clk *rclksrc; unsigned long flags; @@ -783,6 +786,9 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, i2s->frmclk = params_rate(params); rclksrc = i2s->clk_table[CLK_I2S_RCLK_SRC]; + if (!rclksrc || IS_ERR(rclksrc)) + rclksrc = other->clk_table[CLK_I2S_RCLK_SRC]; + if (rclksrc && !IS_ERR(rclksrc)) i2s->rclk_srcrate = clk_get_rate(rclksrc); -- 2.7.4 From b45cafeedc94cac52812333c6cc72b37333d27ba Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:09 +0100 Subject: [PATCH 05/16] ASoC: dmaengine: Improve of_node test in dmaengine_pcm_request_chan_of() Currently when of_node of the "PCM" device is null dmaengine_pcm_request_chan_of() function will bail out, including cases when custom DMA device is intended to be used. To have the channels properly requested when custom DMA device is provided extend the of_node test to also consider dma_dev->of_node. Change-Id: Icac9da759fdefa367492f5d0ad0ff031a7b0bb62 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/soc-generic-dmaengine-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index d537864..613ed8c 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -360,7 +360,8 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - !dev->of_node) + (!dev->of_node && !(config && config->dma_dev && + config->dma_dev->of_node))) return 0; if (config && config->dma_dev) { -- 2.7.4 From 8088d62a54972f6d3ff891965141c64425f383ac Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:10 +0100 Subject: [PATCH 06/16] ASoC: dmaengine: Extend use of chan_names provided in custom DMA config There are currently two ways to specify custom DMA channel names: - through the SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag and snd_dmaengine_dai_dma_data data structure, - through chan_names field of struct snd_dmaengine_pcm_config. In order to replace the DAI DMA data method with the custom DMA config one on non-DT platforms the dmaengine_pcm_new() function is extended to also consider channel names specified in the custom DMA config. If both config->chan_names and dma_data->chan_name are provided the former will be used. Change-Id: I6a325754971c7d4daf3141f3cfeede9280d9941c Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/soc-generic-dmaengine-pcm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 613ed8c..06d4dfc 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -286,9 +286,16 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (!pcm->chan[i] && - (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) + ((pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME) || + (config && config->chan_names[i]))) { + const char *chan_name = dma_data->chan_name; + + if (config && config->chan_names[i]) + chan_name = config->chan_names[i]; + pcm->chan[i] = dma_request_slave_channel(dev, - dma_data->chan_name); + chan_name); + } if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, -- 2.7.4 From 257b11b7975a874cd083cb9ff60292ae87787c48 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:11 +0100 Subject: [PATCH 07/16] ASoC: samsung: dmaengine: Allow to specify custom DMA device The additional function argument will allow to select proper DMA device for requesting DMA channel for the secondary CPU DAI. Change-Id: I3848594e393bcf55770020857ee5f2d0271b779b Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/dma.h | 3 ++- sound/soc/samsung/dmaengine.c | 4 +++- sound/soc/samsung/i2s.c | 4 ++-- sound/soc/samsung/pcm.c | 2 +- sound/soc/samsung/s3c2412-i2s.c | 2 +- sound/soc/samsung/s3c24xx-i2s.c | 2 +- sound/soc/samsung/spdif.c | 2 +- 7 files changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 7ae580d..0ae15d0 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -17,5 +17,6 @@ * otherwise actual DMA channel names must be passed to this function. */ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, - const char *tx, const char *rx); + const char *tx, const char *rx, + struct device *dma_dev); #endif /* _SAMSUNG_DMA_H */ diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 9104c98..84601fa 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -25,7 +25,8 @@ #include "dma.h" int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, - const char *tx, const char *rx) + const char *tx, const char *rx, + struct device *dma_dev) { unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT; struct snd_dmaengine_pcm_config *pcm_conf; @@ -36,6 +37,7 @@ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, pcm_conf->prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; pcm_conf->compat_filter_fn = filter; + pcm_conf->dma_dev = dma_dev; if (dev->of_node) { pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index b712c02..0763203 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1350,7 +1350,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->i2s_dai_drv.playback.channels_max = 6; ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, - NULL, NULL); + NULL, NULL, NULL); if (ret < 0) goto err_disable_clk; @@ -1387,7 +1387,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->sec_dai = sec_dai; ret = samsung_asoc_dma_platform_register(&pdev->dev, - sec_dai->filter, "tx-sec", NULL); + sec_dai->filter, "tx-sec", NULL, NULL); if (ret < 0) goto err_disable_clk; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 37f95ee..3c7baa5 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -553,7 +553,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id]; ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, - NULL, NULL); + NULL, NULL, NULL); if (ret) { dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); goto err_dis_pclk; diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index cc0840f..67dfa27 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -177,7 +177,7 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) ret = samsung_asoc_dma_platform_register(&pdev->dev, pdata->dma_filter, - NULL, NULL); + NULL, NULL, NULL); if (ret) { pr_err("failed to register the DMA: %d\n", ret); return ret; diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 8d58d02..ba0f2b9 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -446,7 +446,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL, - NULL, NULL); + NULL, NULL, NULL); if (ret) { dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret); return ret; diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index cb59911..5e4afb3 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -430,7 +430,7 @@ static int spdif_probe(struct platform_device *pdev) spdif->dma_playback = &spdif_stereo_out; ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, - NULL, NULL); + NULL, NULL, NULL); if (ret) { dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); goto err4; -- 2.7.4 From 2523652bcca60a61c5ee1eec39da01430ab7e396 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:13 +0100 Subject: [PATCH 08/16] ASoC: samsung: i2s: Convert to single component with multiple DAIs This patch includes minimal changes as a prerequisite for adding support for the Exynos secondary I2S interface as second DAI of the I2S component. Doing it that way allows to avoid problems as indicated in commmit 6b01e0365b1689 ("ASoC: samsung: i2s: disable secondary DAI until it gets fixed") The samsung_i2s_get_pri_dai() helper added in this patch is temporary and will be removed in one of subsequent patches. Change-Id: I5cb8ff7cb13a144bc6944752081b93a847080f94 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 192 +++++++++++++++++++++++++++++------------------- 1 file changed, 115 insertions(+), 77 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 0763203..692389c 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -34,6 +34,9 @@ #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) +#define SAMSUNG_I2S_ID_PRIMARY 1 +#define SAMSUNG_I2S_ID_SECONDARY 2 + struct samsung_i2s_variant_regs { unsigned int bfs_off; unsigned int rfs_off; @@ -79,8 +82,10 @@ struct i2s_dai { #define DAI_OPENED (1 << 0) /* Dai is opened */ #define DAI_MANAGER (1 << 1) /* Dai is the manager */ unsigned mode; + /* Driver for this DAI */ - struct snd_soc_dai_driver i2s_dai_drv; + struct snd_soc_dai_driver *drv; + /* DMA parameters */ struct snd_dmaengine_dai_dma_data dma_playback; struct snd_dmaengine_dai_dma_data dma_capture; @@ -92,8 +97,6 @@ struct i2s_dai { u32 suspend_i2spsr; const struct samsung_i2s_variant_regs *variant_regs; - /* Spinlock protecting access to the device's registers */ - spinlock_t spinlock; spinlock_t *lock; /* Below fields are only valid if this is the primary FIFO */ @@ -104,10 +107,29 @@ struct i2s_dai { /* Lock for cross i/f checks */ static DEFINE_SPINLOCK(lock); -/* If this is the 'overlay' stereo DAI */ +struct samsung_i2s_priv { + struct platform_device *pdev; + + /* Spinlock protecting access to the device's registers */ + spinlock_t spinlock; + + /* CPU DAIs and their corresponding drivers */ + struct i2s_dai *dai; + struct snd_soc_dai_driver *dai_drv; + int num_dais; +}; + +struct i2s_dai *samsung_i2s_get_pri_dai(struct device *dev) +{ + struct samsung_i2s_priv *priv = dev_get_drvdata(dev); + + return &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; +} + +/* Returns true if this is the 'overlay' stereo DAI */ static inline bool is_secondary(struct i2s_dai *i2s) { - return i2s->pri_dai ? true : false; + return i2s->drv->id == SAMSUNG_I2S_ID_SECONDARY; } /* If operating in SoC-Slave mode */ @@ -202,7 +224,9 @@ static inline bool any_active(struct i2s_dai *i2s) static inline struct i2s_dai *to_info(struct snd_soc_dai *dai) { - return snd_soc_dai_get_drvdata(dai); + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); + + return &priv->dai[dai->id - 1]; } static inline bool is_opened(struct i2s_dai *i2s) @@ -1064,7 +1088,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) { - struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); + struct i2s_dai *i2s = to_info(dai); unsigned long flags; pm_runtime_get_sync(dai->dev); @@ -1101,47 +1125,63 @@ static const struct snd_soc_component_driver samsung_i2s_component = { SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE) -static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, - const struct samsung_i2s_dai_data *i2s_dai_data, - bool sec) +static int i2s_alloc_dais(struct samsung_i2s_priv *priv, + const struct samsung_i2s_dai_data *i2s_dai_data, + int num_dais) { - struct i2s_dai *i2s; - - i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL); - if (i2s == NULL) - return NULL; - - i2s->pdev = pdev; - i2s->pri_dai = NULL; - i2s->sec_dai = NULL; - i2s->i2s_dai_drv.id = 1; - i2s->i2s_dai_drv.symmetric_rates = 1; - i2s->i2s_dai_drv.probe = samsung_i2s_dai_probe; - i2s->i2s_dai_drv.remove = samsung_i2s_dai_remove; - i2s->i2s_dai_drv.ops = &samsung_i2s_dai_ops; - i2s->i2s_dai_drv.suspend = i2s_suspend; - i2s->i2s_dai_drv.resume = i2s_resume; - i2s->i2s_dai_drv.playback.channels_min = 1; - i2s->i2s_dai_drv.playback.channels_max = 2; - i2s->i2s_dai_drv.playback.rates = i2s_dai_data->pcm_rates; - i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS; - - if (!sec) { - i2s->i2s_dai_drv.name = SAMSUNG_I2S_DAI; - i2s->i2s_dai_drv.capture.channels_min = 1; - i2s->i2s_dai_drv.capture.channels_max = 2; - i2s->i2s_dai_drv.capture.rates = i2s_dai_data->pcm_rates; - i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; - } else { - i2s->i2s_dai_drv.name = SAMSUNG_I2S_DAI_SEC; + static const char *dai_names[] = { "samsung-i2s", "samsung-i2s-sec" }; + struct snd_soc_dai_driver *dai_drv; + struct i2s_dai *dai; + int i; + + priv->dai = devm_kcalloc(&priv->pdev->dev, num_dais, + sizeof(*dai), GFP_KERNEL); + if (!priv->dai) + return -ENOMEM; + + priv->dai_drv = devm_kcalloc(&priv->pdev->dev, num_dais, + sizeof(*dai_drv), GFP_KERNEL); + if (!priv->dai_drv) + return -ENOMEM; + + for (i = 0; i < num_dais; i++) { + dai_drv = &priv->dai_drv[i]; + + dai_drv->probe = samsung_i2s_dai_probe; + dai_drv->remove = samsung_i2s_dai_remove; + dai_drv->suspend = i2s_suspend; + dai_drv->resume = i2s_resume; + + dai_drv->symmetric_rates = 1; + dai_drv->ops = &samsung_i2s_dai_ops; + + dai_drv->playback.channels_min = 1; + dai_drv->playback.channels_max = 2; + dai_drv->playback.rates = i2s_dai_data->pcm_rates; + dai_drv->playback.formats = SAMSUNG_I2S_FMTS; + + dai_drv->id = i + 1; + dai_drv->name = dai_names[i]; + + priv->dai[i].drv = &priv->dai_drv[i]; + priv->dai[i].pdev = priv->pdev; } - return i2s; + + /* Initialize capture only for the primary DAI */ + dai_drv = &priv->dai_drv[SAMSUNG_I2S_ID_PRIMARY - 1]; + + dai_drv->capture.channels_min = 1; + dai_drv->capture.channels_max = 2; + dai_drv->capture.rates = i2s_dai_data->pcm_rates; + dai_drv->capture.formats = SAMSUNG_I2S_FMTS; + + return 0; } #ifdef CONFIG_PM static int i2s_runtime_suspend(struct device *dev) { - struct i2s_dai *i2s = dev_get_drvdata(dev); + struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); i2s->suspend_i2scon = readl(i2s->addr + I2SCON); @@ -1156,7 +1196,7 @@ static int i2s_runtime_suspend(struct device *dev) static int i2s_runtime_resume(struct device *dev) { - struct i2s_dai *i2s = dev_get_drvdata(dev); + struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); int ret; ret = clk_prepare_enable(i2s->clk); @@ -1191,7 +1231,7 @@ static void i2s_unregister_clocks(struct i2s_dai *i2s) static void i2s_unregister_clock_provider(struct platform_device *pdev) { - struct i2s_dai *i2s = dev_get_drvdata(&pdev->dev); + struct i2s_dai *i2s = samsung_i2s_get_pri_dai(&pdev->dev); of_clk_del_provider(pdev->dev.of_node); i2s_unregister_clocks(i2s); @@ -1199,11 +1239,12 @@ static void i2s_unregister_clock_provider(struct platform_device *pdev) static int i2s_register_clock_provider(struct platform_device *pdev) { + const char * const i2s_clk_desc[] = { "cdclk", "rclk_src", "prescaler" }; const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" }; const char *p_names[2] = { NULL }; struct device *dev = &pdev->dev; - struct i2s_dai *i2s = dev_get_drvdata(dev); + struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs; const char *i2s_clk_name[ARRAY_SIZE(i2s_clk_desc)]; struct clk *rclksrc; @@ -1278,7 +1319,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) u32 regs_base, quirks = 0, idma_addr = 0; struct device_node *np = pdev->dev.of_node; const struct samsung_i2s_dai_data *i2s_dai_data; - int ret; + int num_dais, ret; + struct samsung_i2s_priv *priv; if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) i2s_dai_data = of_device_get_match_data(&pdev->dev); @@ -1286,14 +1328,24 @@ static int samsung_i2s_probe(struct platform_device *pdev) i2s_dai_data = (struct samsung_i2s_dai_data *) platform_get_device_id(pdev)->driver_data; - pri_dai = i2s_alloc_dai(pdev, i2s_dai_data, false); - if (!pri_dai) { - dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - } - spin_lock_init(&pri_dai->spinlock); - pri_dai->lock = &pri_dai->spinlock; + quirks = np ? i2s_dai_data->quirks : i2s_pdata->type.quirks; + quirks &= ~(QUIRK_SEC_DAI | QUIRK_SUPPORTS_IDMA); + + num_dais = (quirks & QUIRK_SEC_DAI) ? 2 : 1; + priv->pdev = pdev; + + ret = i2s_alloc_dais(priv, i2s_dai_data, num_dais); + if (ret < 0) + return ret; + + pri_dai = &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; + + spin_lock_init(&priv->spinlock); + pri_dai->lock = &priv->spinlock; if (!np) { if (i2s_pdata == NULL) { @@ -1305,10 +1357,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_capture.filter_data = i2s_pdata->dma_capture; pri_dai->filter = i2s_pdata->dma_filter; - quirks = i2s_pdata->type.quirks; idma_addr = i2s_pdata->type.idma_addr; } else { - quirks = i2s_dai_data->quirks; if (of_property_read_u32(np, "samsung,idma-addr", &idma_addr)) { if (quirks & QUIRK_SUPPORTS_IDMA) { @@ -1317,7 +1367,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) } } } - quirks &= ~(QUIRK_SEC_DAI | QUIRK_SUPPORTS_IDMA); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pri_dai->addr = devm_ioremap_resource(&pdev->dev, res); @@ -1347,28 +1396,17 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; if (quirks & QUIRK_PRI_6CHAN) - pri_dai->i2s_dai_drv.playback.channels_max = 6; + pri_dai->drv->playback.channels_max = 6; ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, NULL, NULL, NULL); if (ret < 0) goto err_disable_clk; - ret = devm_snd_soc_register_component(&pdev->dev, - &samsung_i2s_component, - &pri_dai->i2s_dai_drv, 1); - if (ret < 0) - goto err_disable_clk; - if (quirks & QUIRK_SEC_DAI) { - sec_dai = i2s_alloc_dai(pdev, i2s_dai_data, true); - if (!sec_dai) { - dev_err(&pdev->dev, "Unable to alloc I2S_sec\n"); - ret = -ENOMEM; - goto err_disable_clk; - } + sec_dai = &priv->dai[SAMSUNG_I2S_ID_SECONDARY - 1]; - sec_dai->lock = &pri_dai->spinlock; + sec_dai->lock = &priv->spinlock; sec_dai->variant_regs = pri_dai->variant_regs; sec_dai->dma_playback.addr = regs_base + I2STXDS; sec_dai->dma_playback.chan_name = "tx-sec"; @@ -1391,11 +1429,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (ret < 0) goto err_disable_clk; - ret = devm_snd_soc_register_component(&pdev->dev, - &samsung_i2s_component, - &sec_dai->i2s_dai_drv, 1); - if (ret < 0) - goto err_disable_clk; } if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { @@ -1404,7 +1437,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) goto err_disable_clk; } - dev_set_drvdata(&pdev->dev, pri_dai); + dev_set_drvdata(&pdev->dev, priv); + + ret = devm_snd_soc_register_component(&pdev->dev, + &samsung_i2s_component, + priv->dai_drv, num_dais); + if (ret < 0) + goto err_disable_clk; pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -1426,9 +1465,8 @@ err_disable_clk: static int samsung_i2s_remove(struct platform_device *pdev) { - struct i2s_dai *pri_dai; - - pri_dai = dev_get_drvdata(&pdev->dev); + struct samsung_i2s_priv *priv = dev_get_drvdata(&pdev->dev); + struct i2s_dai *pri_dai = samsung_i2s_get_pri_dai(&pdev->dev); pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); -- 2.7.4 From 13f8c0d674dd2d6fe115706a6e60212b487fff10 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:22 +0100 Subject: [PATCH 09/16] ASoC: samsung: i2s: Restore support for the secondary PCM This patch introduces again registration of additional platform device as we still need it for registering the secondary dmaengine PCM component. This patch in most part is a revert of changes done in commit be2c92eb64023e ("ASoC: samsung: i2s: Remove virtual device for secondary DAI") Change-Id: Ib7a47c83511403b32e04c41edf8148d77481abb3 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 52 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 692389c..ba37d5d 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -109,6 +109,7 @@ static DEFINE_SPINLOCK(lock); struct samsung_i2s_priv { struct platform_device *pdev; + struct platform_device *pdev_sec; /* Spinlock protecting access to the device's registers */ spinlock_t spinlock; @@ -1311,6 +1312,34 @@ static int i2s_register_clock_provider(struct platform_device *pdev) return ret; } +/* Create platform device for the secondary PCM */ +static int i2s_create_secondary_device(struct samsung_i2s_priv *priv) +{ + struct platform_device *pdev; + int ret; + + pdev = platform_device_register_simple("samsung-i2s-sec", -1, NULL, 0); + if (!pdev) + return -ENOMEM; + + ret = device_attach(&pdev->dev); + if (ret < 0) { + dev_info(&pdev->dev, "device_attach() failed\n"); + return ret; + } + + priv->pdev_sec = pdev; + + return 0; +} + +static void i2s_delete_secondary_device(struct samsung_i2s_priv *priv) +{ + if (priv->pdev_sec) { + platform_device_del(priv->pdev_sec); + priv->pdev_sec = NULL; + } +} static int samsung_i2s_probe(struct platform_device *pdev) { struct i2s_dai *pri_dai, *sec_dai = NULL; @@ -1328,13 +1357,15 @@ static int samsung_i2s_probe(struct platform_device *pdev) i2s_dai_data = (struct samsung_i2s_dai_data *) platform_get_device_id(pdev)->driver_data; + /* Nothing to do if it is the secondary device probe */ + if (!i2s_dai_data) + return 0; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; quirks = np ? i2s_dai_data->quirks : i2s_pdata->type.quirks; - quirks &= ~(QUIRK_SEC_DAI | QUIRK_SUPPORTS_IDMA); - num_dais = (quirks & QUIRK_SEC_DAI) ? 2 : 1; priv->pdev = pdev; @@ -1424,8 +1455,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->pri_dai = pri_dai; pri_dai->sec_dai = sec_dai; - ret = samsung_asoc_dma_platform_register(&pdev->dev, - sec_dai->filter, "tx-sec", NULL, NULL); + ret = i2s_create_secondary_device(priv); + if (ret < 0) + goto err_disable_clk; + + ret = samsung_asoc_dma_platform_register(&priv->pdev_sec->dev, + sec_dai->filter, "tx-sec", NULL, + &pdev->dev); if (ret < 0) goto err_disable_clk; @@ -1460,6 +1496,7 @@ err_disable_pm: pm_runtime_disable(&pdev->dev); err_disable_clk: clk_disable_unprepare(pri_dai->clk); + i2s_delete_secondary_device(priv); return ret; } @@ -1468,12 +1505,17 @@ static int samsung_i2s_remove(struct platform_device *pdev) struct samsung_i2s_priv *priv = dev_get_drvdata(&pdev->dev); struct i2s_dai *pri_dai = samsung_i2s_get_pri_dai(&pdev->dev); + /* The secondary device has no driver data assigned */ + if (!priv) + return 0; + pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); i2s_unregister_clock_provider(pdev); clk_disable_unprepare(pri_dai->clk); pm_runtime_put_noidle(&pdev->dev); + i2s_delete_secondary_device(priv); return 0; } @@ -1571,6 +1613,8 @@ static const struct platform_device_id samsung_i2s_driver_ids[] = { { .name = "samsung-i2s", .driver_data = (kernel_ulong_t)&i2sv3_dai_type, + }, { + .name = "samsung-i2s-sec", }, {}, }; -- 2.7.4 From 4f907b21186e3d9cb0779815440058c73d81157d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:23 +0100 Subject: [PATCH 10/16] ASoC: samsung: i2s: Move clk supplier data to common driver data structure Having the clocks provider data in struct samsung_i2s_priv, i.e. per the I2S controller instance, rather than per CPU DAI better models the hardware and simplifies the code a little. The clock provider is common for both DAIs. Change-Id: I76db45001d8303263405b2cc40526e4101f35d16 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 68 ++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index ba37d5d..c39349a 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -99,9 +99,7 @@ struct i2s_dai { spinlock_t *lock; - /* Below fields are only valid if this is the primary FIFO */ - struct clk *clk_table[3]; - struct clk_onecell_data clk_data; + struct samsung_i2s_priv *priv; }; /* Lock for cross i/f checks */ @@ -118,6 +116,10 @@ struct samsung_i2s_priv { struct i2s_dai *dai; struct snd_soc_dai_driver *dai_drv; int num_dais; + + /* The clock provider's data */ + struct clk *clk_table[3]; + struct clk_onecell_data clk_data; }; struct i2s_dai *samsung_i2s_get_pri_dai(struct device *dev) @@ -625,11 +627,10 @@ err: return ret; } -static int i2s_set_fmt(struct snd_soc_dai *dai, - unsigned int fmt) +static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); - struct i2s_dai *other = get_other_dai(i2s); int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; u32 mod, tmp = 0; unsigned long flags; @@ -687,8 +688,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any * clock configuration assigned in DT is not overwritten. */ - if (i2s->rclk_srcrate == 0 && i2s->clk_data.clks == NULL && - other->clk_data.clks == NULL) + if (i2s->rclk_srcrate == 0 && priv->clk_data.clks == NULL) i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0, 0, SND_SOC_CLOCK_IN); break; @@ -725,8 +725,8 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, static int i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); - struct i2s_dai *other = get_other_dai(i2s); u32 mod, mask = 0, val = 0; struct clk *rclksrc; unsigned long flags; @@ -810,10 +810,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, i2s->frmclk = params_rate(params); - rclksrc = i2s->clk_table[CLK_I2S_RCLK_SRC]; - if (!rclksrc || IS_ERR(rclksrc)) - rclksrc = other->clk_table[CLK_I2S_RCLK_SRC]; - + rclksrc = priv->clk_table[CLK_I2S_RCLK_SRC]; if (rclksrc && !IS_ERR(rclksrc)) i2s->rclk_srcrate = clk_get_rate(rclksrc); @@ -1220,31 +1217,30 @@ static int i2s_runtime_resume(struct device *dev) } #endif /* CONFIG_PM */ -static void i2s_unregister_clocks(struct i2s_dai *i2s) +static void i2s_unregister_clocks(struct samsung_i2s_priv *priv) { int i; - for (i = 0; i < i2s->clk_data.clk_num; i++) { - if (!IS_ERR(i2s->clk_table[i])) - clk_unregister(i2s->clk_table[i]); + for (i = 0; i < priv->clk_data.clk_num; i++) { + if (!IS_ERR(priv->clk_table[i])) + clk_unregister(priv->clk_table[i]); } } -static void i2s_unregister_clock_provider(struct platform_device *pdev) +static void i2s_unregister_clock_provider(struct samsung_i2s_priv *priv) { - struct i2s_dai *i2s = samsung_i2s_get_pri_dai(&pdev->dev); - - of_clk_del_provider(pdev->dev.of_node); - i2s_unregister_clocks(i2s); + of_clk_del_provider(priv->pdev->dev.of_node); + i2s_unregister_clocks(priv); } -static int i2s_register_clock_provider(struct platform_device *pdev) + +static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) { const char * const i2s_clk_desc[] = { "cdclk", "rclk_src", "prescaler" }; const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" }; const char *p_names[2] = { NULL }; - struct device *dev = &pdev->dev; + struct device *dev = &priv->pdev->dev; struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs; const char *i2s_clk_name[ARRAY_SIZE(i2s_clk_desc)]; @@ -1276,37 +1272,37 @@ static int i2s_register_clock_provider(struct platform_device *pdev) u32 val = readl(i2s->addr + I2SPSR); writel(val | PSR_PSREN, i2s->addr + I2SPSR); - i2s->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev, + priv->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev, i2s_clk_name[CLK_I2S_RCLK_SRC], p_names, ARRAY_SIZE(p_names), CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, i2s->addr + I2SMOD, reg_info->rclksrc_off, 1, 0, i2s->lock); - i2s->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, + priv->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, i2s_clk_name[CLK_I2S_RCLK_PSR], i2s_clk_name[CLK_I2S_RCLK_SRC], CLK_SET_RATE_PARENT, i2s->addr + I2SPSR, 8, 6, 0, i2s->lock); p_names[0] = i2s_clk_name[CLK_I2S_RCLK_PSR]; - i2s->clk_data.clk_num = 2; + priv->clk_data.clk_num = 2; } - i2s->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, + priv->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, i2s_clk_name[CLK_I2S_CDCLK], p_names[0], CLK_SET_RATE_PARENT, i2s->addr + I2SMOD, reg_info->cdclkcon_off, CLK_GATE_SET_TO_DISABLE, i2s->lock); - i2s->clk_data.clk_num += 1; - i2s->clk_data.clks = i2s->clk_table; + priv->clk_data.clk_num += 1; + priv->clk_data.clks = priv->clk_table; ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, - &i2s->clk_data); + &priv->clk_data); if (ret < 0) { dev_err(dev, "failed to add clock provider: %d\n", ret); - i2s_unregister_clocks(i2s); + i2s_unregister_clocks(priv); } return ret; @@ -1425,6 +1421,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_capture.addr_width = 4; pri_dai->quirks = quirks; pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; + pri_dai->priv = priv; if (quirks & QUIRK_PRI_6CHAN) pri_dai->drv->playback.channels_max = 6; @@ -1453,6 +1450,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->quirks = quirks; sec_dai->idma_playback.addr = idma_addr; sec_dai->pri_dai = pri_dai; + sec_dai->priv = priv; pri_dai->sec_dai = sec_dai; ret = i2s_create_secondary_device(priv); @@ -1484,11 +1482,11 @@ static int samsung_i2s_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - ret = i2s_register_clock_provider(pdev); + ret = i2s_register_clock_provider(priv); if (ret < 0) goto err_disable_pm; - pri_dai->op_clk = clk_get_parent(pri_dai->clk_table[CLK_I2S_RCLK_SRC]); + pri_dai->op_clk = clk_get_parent(priv->clk_table[CLK_I2S_RCLK_SRC]); return 0; @@ -1512,7 +1510,7 @@ static int samsung_i2s_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - i2s_unregister_clock_provider(pdev); + i2s_unregister_clock_provider(priv); clk_disable_unprepare(pri_dai->clk); pm_runtime_put_noidle(&pdev->dev); i2s_delete_secondary_device(priv); -- 2.7.4 From 182f052dd8ce2c7f48bd97064e8ad0ecb747460f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:24 +0100 Subject: [PATCH 11/16] ASoC: samsung: i2s: Add widgets and routes for DPCM support This patch adds DAPM widgets required to model the internal mixer of the I2S controller merging audio streams from the primary and from the secondary PCM interface. Change-Id: I3cb7b1b17f0c6891f6edb638db97ca6a482cec4b Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index c39349a..fc65621 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1115,8 +1115,31 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { .delay = i2s_delay, }; +static const struct snd_soc_dapm_widget samsung_i2s_widgets[] = { + /* Backend DAI */ + SND_SOC_DAPM_AIF_OUT("Mixer DAI TX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("Mixer DAI RX", NULL, 0, SND_SOC_NOPM, 0, 0), + + /* Playback Mixer */ + SND_SOC_DAPM_MIXER("Playback Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route samsung_i2s_dapm_routes[] = { + { "Playback Mixer", NULL, "Primary" }, + { "Playback Mixer", NULL, "Secondary" }, + + { "Mixer DAI TX", NULL, "Playback Mixer" }, + { "Playback Mixer", NULL, "Mixer DAI RX" }, +}; + static const struct snd_soc_component_driver samsung_i2s_component = { - .name = "samsung-i2s", + .name = "samsung-i2s", + + .dapm_widgets = samsung_i2s_widgets, + .num_dapm_widgets = ARRAY_SIZE(samsung_i2s_widgets), + + .dapm_routes = samsung_i2s_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(samsung_i2s_dapm_routes), }; #define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ @@ -1128,6 +1151,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, int num_dais) { static const char *dai_names[] = { "samsung-i2s", "samsung-i2s-sec" }; + static const char *stream_names[] = { "Primary", "Secondary" }; struct snd_soc_dai_driver *dai_drv; struct i2s_dai *dai; int i; @@ -1157,6 +1181,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, dai_drv->playback.channels_max = 2; dai_drv->playback.rates = i2s_dai_data->pcm_rates; dai_drv->playback.formats = SAMSUNG_I2S_FMTS; + dai_drv->playback.stream_name = stream_names[i]; dai_drv->id = i + 1; dai_drv->name = dai_names[i]; -- 2.7.4 From 4d26091f99aaf70230f057df560e3968e22bfa48 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:25 +0100 Subject: [PATCH 12/16] ASoC: samsung: i2s: Move core clk to the driver common data structure The core clock is also common for both CPU DAIs so move it to the driver's private data structure. Change-Id: Ib6f2975bd34a8cfba20faaa9e51be88b6a41bc30 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index fc65621..5dce970b 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -71,8 +71,6 @@ struct i2s_dai { * 0 indicates CPU driver is free to choose any value. */ unsigned rfs, bfs; - /* I2S Controller's core clock */ - struct clk *clk; /* Clock for generating I2S signals */ struct clk *op_clk; /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */ @@ -117,6 +115,9 @@ struct samsung_i2s_priv { struct snd_soc_dai_driver *dai_drv; int num_dais; + /* The I2S controller's core clock */ + struct clk *clk; + /* The clock provider's data */ struct clk *clk_table[3]; struct clk_onecell_data clk_data; @@ -1204,6 +1205,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, #ifdef CONFIG_PM static int i2s_runtime_suspend(struct device *dev) { + struct samsung_i2s_priv *priv = dev_get_drvdata(dev); struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); @@ -1212,24 +1214,25 @@ static int i2s_runtime_suspend(struct device *dev) if (i2s->op_clk) clk_disable_unprepare(i2s->op_clk); - clk_disable_unprepare(i2s->clk); + clk_disable_unprepare(priv->clk); return 0; } static int i2s_runtime_resume(struct device *dev) { + struct samsung_i2s_priv *priv = dev_get_drvdata(dev); struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); int ret; - ret = clk_prepare_enable(i2s->clk); + ret = clk_prepare_enable(priv->clk); if (ret) return ret; if (i2s->op_clk) { ret = clk_prepare_enable(i2s->op_clk); if (ret) { - clk_disable_unprepare(i2s->clk); + clk_disable_unprepare(priv->clk); return ret; } } @@ -1427,13 +1430,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) regs_base = res->start; - pri_dai->clk = devm_clk_get(&pdev->dev, "iis"); - if (IS_ERR(pri_dai->clk)) { + priv->clk = devm_clk_get(&pdev->dev, "iis"); + if (IS_ERR(priv->clk)) { dev_err(&pdev->dev, "Failed to get iis clock\n"); - return PTR_ERR(pri_dai->clk); + return PTR_ERR(priv->clk); } - ret = clk_prepare_enable(pri_dai->clk); + ret = clk_prepare_enable(priv->clk); if (ret != 0) { dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); return ret; @@ -1471,7 +1474,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->dma_playback.addr_width = 4; sec_dai->addr = pri_dai->addr; - sec_dai->clk = pri_dai->clk; sec_dai->quirks = quirks; sec_dai->idma_playback.addr = idma_addr; sec_dai->pri_dai = pri_dai; @@ -1518,7 +1520,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) err_disable_pm: pm_runtime_disable(&pdev->dev); err_disable_clk: - clk_disable_unprepare(pri_dai->clk); + clk_disable_unprepare(priv->clk); i2s_delete_secondary_device(priv); return ret; } @@ -1526,7 +1528,6 @@ err_disable_clk: static int samsung_i2s_remove(struct platform_device *pdev) { struct samsung_i2s_priv *priv = dev_get_drvdata(&pdev->dev); - struct i2s_dai *pri_dai = samsung_i2s_get_pri_dai(&pdev->dev); /* The secondary device has no driver data assigned */ if (!priv) @@ -1536,7 +1537,7 @@ static int samsung_i2s_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); i2s_unregister_clock_provider(priv); - clk_disable_unprepare(pri_dai->clk); + clk_disable_unprepare(priv->clk); pm_runtime_put_noidle(&pdev->dev); i2s_delete_secondary_device(priv); -- 2.7.4 From 7bfe5378492de7d3105a6d7a391207c7c26fbbc7 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:26 +0100 Subject: [PATCH 13/16] ASoC: samsung: i2s: Move opclk data to common driver data structure The clock for generating I2S signals is also common for both CPU DAIs so move it to the driver's common data structure. Change-Id: Ia8320f1e9ab0c02d113bb73002cd4ae98caec7e8 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 70 +++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 5dce970b..6af1e97 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -62,8 +62,6 @@ struct i2s_dai { struct platform_device *pdev; /* Memory mapped SFR region */ void __iomem *addr; - /* Rate of RCLK source clock */ - unsigned long rclk_srcrate; /* Frame Clock */ unsigned frmclk; /* @@ -71,8 +69,6 @@ struct i2s_dai { * 0 indicates CPU driver is free to choose any value. */ unsigned rfs, bfs; - /* Clock for generating I2S signals */ - struct clk *op_clk; /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */ struct i2s_dai *pri_dai; /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */ @@ -118,6 +114,12 @@ struct samsung_i2s_priv { /* The I2S controller's core clock */ struct clk *clk; + /* Clock for generating I2S signals */ + struct clk *op_clk; + + /* Rate of RCLK source clock */ + unsigned long rclk_srcrate; + /* The clock provider's data */ struct clk *clk_table[3]; struct clk_onecell_data clk_data; @@ -496,9 +498,10 @@ static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush) writel(readl(fic) & ~flush, fic); } -static int i2s_set_sysclk(struct snd_soc_dai *dai, - int clk_id, unsigned int rfs, int dir) +static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, + int dir) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; @@ -554,44 +557,39 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, clk_id = 1; if (!any_active(i2s)) { - if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { + if (priv->op_clk && !IS_ERR(priv->op_clk)) { if ((clk_id && !(mod & rsrc_mask)) || (!clk_id && (mod & rsrc_mask))) { - clk_disable_unprepare(i2s->op_clk); - clk_put(i2s->op_clk); + clk_disable_unprepare(priv->op_clk); + clk_put(priv->op_clk); } else { - i2s->rclk_srcrate = - clk_get_rate(i2s->op_clk); + priv->rclk_srcrate = + clk_get_rate(priv->op_clk); goto done; } } if (clk_id) - i2s->op_clk = clk_get(&i2s->pdev->dev, + priv->op_clk = clk_get(&i2s->pdev->dev, "i2s_opclk1"); else - i2s->op_clk = clk_get(&i2s->pdev->dev, + priv->op_clk = clk_get(&i2s->pdev->dev, "i2s_opclk0"); - if (WARN_ON(IS_ERR(i2s->op_clk))) { - ret = PTR_ERR(i2s->op_clk); - i2s->op_clk = NULL; + if (WARN_ON(IS_ERR(priv->op_clk))) { + ret = PTR_ERR(priv->op_clk); + priv->op_clk = NULL; goto err; } - ret = clk_prepare_enable(i2s->op_clk); + ret = clk_prepare_enable(priv->op_clk); if (ret) { - clk_put(i2s->op_clk); - i2s->op_clk = NULL; + clk_put(priv->op_clk); + priv->op_clk = NULL; goto err; } - i2s->rclk_srcrate = clk_get_rate(i2s->op_clk); + priv->rclk_srcrate = clk_get_rate(priv->op_clk); - /* Over-ride the other's */ - if (other) { - other->op_clk = i2s->op_clk; - other->rclk_srcrate = i2s->rclk_srcrate; - } } else if ((!clk_id && (mod & rsrc_mask)) || (clk_id && !(mod & rsrc_mask))) { dev_err(&i2s->pdev->dev, @@ -600,8 +598,6 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, goto err; } else { /* Call can't be on the active DAI */ - i2s->op_clk = other->op_clk; - i2s->rclk_srcrate = other->rclk_srcrate; goto done; } @@ -689,7 +685,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any * clock configuration assigned in DT is not overwritten. */ - if (i2s->rclk_srcrate == 0 && priv->clk_data.clks == NULL) + if (priv->rclk_srcrate == 0 && priv->clk_data.clks == NULL) i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0, 0, SND_SOC_CLOCK_IN); break; @@ -813,7 +809,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, rclksrc = priv->clk_table[CLK_I2S_RCLK_SRC]; if (rclksrc && !IS_ERR(rclksrc)) - i2s->rclk_srcrate = clk_get_rate(rclksrc); + priv->rclk_srcrate = clk_get_rate(rclksrc); return 0; } @@ -871,6 +867,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, static int config_setup(struct i2s_dai *i2s) { + struct samsung_i2s_priv *priv = i2s->priv; struct i2s_dai *other = get_other_dai(i2s); unsigned rfs, bfs, blc; u32 psr; @@ -919,11 +916,11 @@ static int config_setup(struct i2s_dai *i2s) return 0; if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { - psr = i2s->rclk_srcrate / i2s->frmclk / rfs; + psr = priv->rclk_srcrate / i2s->frmclk / rfs; writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR); dev_dbg(&i2s->pdev->dev, "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n", - i2s->rclk_srcrate, psr, rfs, bfs); + priv->rclk_srcrate, psr, rfs, bfs); } return 0; @@ -1066,7 +1063,6 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) /* Reset any constraint on RFS and BFS */ i2s->rfs = 0; i2s->bfs = 0; - i2s->rclk_srcrate = 0; spin_lock_irqsave(i2s->lock, flags); i2s_txctrl(i2s, 0); @@ -1212,8 +1208,8 @@ static int i2s_runtime_suspend(struct device *dev) i2s->suspend_i2scon = readl(i2s->addr + I2SCON); i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); - if (i2s->op_clk) - clk_disable_unprepare(i2s->op_clk); + if (priv->op_clk) + clk_disable_unprepare(priv->op_clk); clk_disable_unprepare(priv->clk); return 0; @@ -1229,8 +1225,8 @@ static int i2s_runtime_resume(struct device *dev) if (ret) return ret; - if (i2s->op_clk) { - ret = clk_prepare_enable(i2s->op_clk); + if (priv->op_clk) { + ret = clk_prepare_enable(priv->op_clk); if (ret) { clk_disable_unprepare(priv->clk); return ret; @@ -1513,7 +1509,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (ret < 0) goto err_disable_pm; - pri_dai->op_clk = clk_get_parent(priv->clk_table[CLK_I2S_RCLK_SRC]); + priv->op_clk = clk_get_parent(priv->clk_table[CLK_I2S_RCLK_SRC]); return 0; -- 2.7.4 From fd317818ce72043e86ccd4a0fa6d7da0fb18b36e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:27 +0100 Subject: [PATCH 14/16] ASoC: samsung: i2s: Move registers cache to common driver data structure There is no need to keep the PM suspend/resume register cache separate for each DAI as those registers are common, move related i2s_dai data structure to the driver's common data structure. This will allow us to simplify the code a little eventually and to make it easier to follow. Change-Id: I91919c337611dc69983d2ee346e988f2e93d0695 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 6af1e97..01e9512 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -86,9 +86,6 @@ struct i2s_dai { struct snd_dmaengine_dai_dma_data idma_playback; dma_filter_fn filter; u32 quirks; - u32 suspend_i2smod; - u32 suspend_i2scon; - u32 suspend_i2spsr; const struct samsung_i2s_variant_regs *variant_regs; spinlock_t *lock; @@ -120,6 +117,11 @@ struct samsung_i2s_priv { /* Rate of RCLK source clock */ unsigned long rclk_srcrate; + /* Cache of selected I2S registers for system suspend */ + u32 suspend_i2smod; + u32 suspend_i2scon; + u32 suspend_i2spsr; + /* The clock provider's data */ struct clk *clk_table[3]; struct clk_onecell_data clk_data; @@ -1204,9 +1206,9 @@ static int i2s_runtime_suspend(struct device *dev) struct samsung_i2s_priv *priv = dev_get_drvdata(dev); struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); - i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); - i2s->suspend_i2scon = readl(i2s->addr + I2SCON); - i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); + priv->suspend_i2smod = readl(i2s->addr + I2SMOD); + priv->suspend_i2scon = readl(i2s->addr + I2SCON); + priv->suspend_i2spsr = readl(i2s->addr + I2SPSR); if (priv->op_clk) clk_disable_unprepare(priv->op_clk); @@ -1233,9 +1235,9 @@ static int i2s_runtime_resume(struct device *dev) } } - writel(i2s->suspend_i2scon, i2s->addr + I2SCON); - writel(i2s->suspend_i2smod, i2s->addr + I2SMOD); - writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR); + writel(priv->suspend_i2scon, i2s->addr + I2SCON); + writel(priv->suspend_i2smod, i2s->addr + I2SMOD); + writel(priv->suspend_i2spsr, i2s->addr + I2SPSR); return 0; } -- 2.7.4 From 3871cab89d7127abd4233f69298f5f0cd7dfc993 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:35 +0100 Subject: [PATCH 15/16] ASoC: samsung: i2s: Move SFR pointer to common driver data structure The SFR region is common for both DAIs so move related data structure field from struct i2s_dai to the common driver data structure. Change-Id: I2080a75f0a49f431ee37fa4488ed13ae8fd26b12 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 106 +++++++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 01e9512..7cfcef6 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -60,8 +60,7 @@ struct samsung_i2s_dai_data { struct i2s_dai { /* Platform device for this DAI */ struct platform_device *pdev; - /* Memory mapped SFR region */ - void __iomem *addr; + /* Frame Clock */ unsigned frmclk; /* @@ -100,6 +99,9 @@ struct samsung_i2s_priv { struct platform_device *pdev; struct platform_device *pdev_sec; + /* Memory mapped SFR region */ + void __iomem *addr; + /* Spinlock protecting access to the device's registers */ spinlock_t spinlock; @@ -143,7 +145,9 @@ static inline bool is_secondary(struct i2s_dai *i2s) /* If operating in SoC-Slave mode */ static inline bool is_slave(struct i2s_dai *i2s) { - u32 mod = readl(i2s->addr + I2SMOD); + struct samsung_i2s_priv *priv = i2s->priv; + + u32 mod = readl(priv->addr + I2SMOD); return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false; } @@ -155,7 +159,7 @@ static inline bool tx_active(struct i2s_dai *i2s) if (!i2s) return false; - active = readl(i2s->addr + I2SCON); + active = readl(i2s->priv->addr + I2SCON); if (is_secondary(i2s)) active &= CON_TXSDMA_ACTIVE; @@ -193,7 +197,7 @@ static inline bool rx_active(struct i2s_dai *i2s) if (!i2s) return false; - active = readl(i2s->addr + I2SCON) & CON_RXDMA_ACTIVE; + active = readl(i2s->priv->addr + I2SCON) & CON_RXDMA_ACTIVE; return active ? true : false; } @@ -256,8 +260,10 @@ static inline bool is_manager(struct i2s_dai *i2s) /* Read RCLK of I2S (in multiples of LRCLK) */ static inline unsigned get_rfs(struct i2s_dai *i2s) { + struct samsung_i2s_priv *priv = i2s->priv; u32 rfs; - rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off; + + rfs = readl(priv->addr + I2SMOD) >> i2s->variant_regs->rfs_off; rfs &= i2s->variant_regs->rfs_mask; switch (rfs) { @@ -275,7 +281,8 @@ static inline unsigned get_rfs(struct i2s_dai *i2s) /* Write RCLK of I2S (in multiples of LRCLK) */ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) { - u32 mod = readl(i2s->addr + I2SMOD); + struct samsung_i2s_priv *priv = i2s->priv; + u32 mod = readl(priv->addr + I2SMOD); int rfs_shift = i2s->variant_regs->rfs_off; mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift); @@ -307,14 +314,16 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) break; } - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); } /* Read Bit-Clock of I2S (in multiples of LRCLK) */ static inline unsigned get_bfs(struct i2s_dai *i2s) { + struct samsung_i2s_priv *priv = i2s->priv; u32 bfs; - bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off; + + bfs = readl(priv->addr + I2SMOD) >> i2s->variant_regs->bfs_off; bfs &= i2s->variant_regs->bfs_mask; switch (bfs) { @@ -333,7 +342,8 @@ static inline unsigned get_bfs(struct i2s_dai *i2s) /* Write Bit-Clock of I2S (in multiples of LRCLK) */ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) { - u32 mod = readl(i2s->addr + I2SMOD); + struct samsung_i2s_priv *priv = i2s->priv; + u32 mod = readl(priv->addr + I2SMOD); int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; int bfs_shift = i2s->variant_regs->bfs_off; @@ -378,13 +388,13 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) return; } - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); } /* Sample-Size */ static inline int get_blc(struct i2s_dai *i2s) { - int blc = readl(i2s->addr + I2SMOD); + int blc = readl(i2s->priv->addr + I2SMOD); blc = (blc >> 13) & 0x3; @@ -398,7 +408,8 @@ static inline int get_blc(struct i2s_dai *i2s) /* TX Channel Control */ static void i2s_txctrl(struct i2s_dai *i2s, int on) { - void __iomem *addr = i2s->addr; + struct samsung_i2s_priv *priv = i2s->priv; + void __iomem *addr = priv->addr; int txr_off = i2s->variant_regs->txr_off; u32 con = readl(addr + I2SCON); u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); @@ -448,7 +459,8 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) /* RX Channel Control */ static void i2s_rxctrl(struct i2s_dai *i2s, int on) { - void __iomem *addr = i2s->addr; + struct samsung_i2s_priv *priv = i2s->priv; + void __iomem *addr = priv->addr; int txr_off = i2s->variant_regs->txr_off; u32 con = readl(addr + I2SCON); u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); @@ -485,9 +497,9 @@ static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush) return; if (is_secondary(i2s)) - fic = i2s->addr + I2SFICS; + fic = i2s->priv->addr + I2SFICS; else - fic = i2s->addr + I2SFIC; + fic = i2s->priv->addr + I2SFIC; /* Flush the FIFO */ writel(readl(fic) | flush, fic); @@ -516,7 +528,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, pm_runtime_get_sync(dai->dev); spin_lock_irqsave(i2s->lock, flags); - mod = readl(i2s->addr + I2SMOD); + mod = readl(priv->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); switch (clk_id) { @@ -613,9 +625,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, } spin_lock_irqsave(i2s->lock, flags); - mod = readl(i2s->addr + I2SMOD); + mod = readl(priv->addr + I2SMOD); mod = (mod & ~mask) | val; - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); done: pm_runtime_put(dai->dev); @@ -698,7 +710,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) pm_runtime_get_sync(dai->dev); spin_lock_irqsave(i2s->lock, flags); - mod = readl(i2s->addr + I2SMOD); + mod = readl(priv->addr + I2SMOD); /* * Don't change the I2S mode if any controller is active on this * channel. @@ -714,7 +726,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) mod &= ~(sdf_mask | lrp_rlow | mod_slave); mod |= tmp; - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); pm_runtime_put(dai->dev); @@ -800,9 +812,9 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, } spin_lock_irqsave(i2s->lock, flags); - mod = readl(i2s->addr + I2SMOD); + mod = readl(priv->addr + I2SMOD); mod = (mod & ~mask) | val; - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); @@ -836,7 +848,7 @@ static int i2s_startup(struct snd_pcm_substream *substream, i2s->mode |= DAI_MANAGER; if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR)) - writel(CON_RSTCLR, i2s->addr + I2SCON); + writel(CON_RSTCLR, i2s->priv->addr + I2SCON); spin_unlock_irqrestore(&lock, flags); @@ -919,7 +931,7 @@ static int config_setup(struct i2s_dai *i2s) if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { psr = priv->rclk_srcrate / i2s->frmclk / rfs; - writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR); + writel(((psr - 1) << 8) | PSR_PSREN, priv->addr + I2SPSR); dev_dbg(&i2s->pdev->dev, "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n", priv->rclk_srcrate, psr, rfs, bfs); @@ -1007,8 +1019,9 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai, static snd_pcm_sframes_t i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); - u32 reg = readl(i2s->addr + I2SFIC); + u32 reg = readl(priv->addr + I2SFIC); snd_pcm_sframes_t delay; const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; @@ -1017,7 +1030,7 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) delay = FIC_RXCOUNT(reg); else if (is_secondary(i2s)) - delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS)); + delay = FICS_TXCOUNT(readl(priv->addr + I2SFICS)); else delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f; @@ -1041,6 +1054,7 @@ static int i2s_resume(struct snd_soc_dai *dai) static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); unsigned long flags; @@ -1055,10 +1069,10 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) &i2s->dma_capture); if (i2s->quirks & QUIRK_NEED_RSTCLR) - writel(CON_RSTCLR, i2s->addr + I2SCON); + writel(CON_RSTCLR, priv->addr + I2SCON); if (i2s->quirks & QUIRK_SUPPORTS_IDMA) - idma_reg_addr_init(i2s->addr, + idma_reg_addr_init(priv->addr, i2s->sec_dai->idma_playback.addr); } @@ -1085,6 +1099,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); unsigned long flags; @@ -1093,7 +1108,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) if (!is_secondary(i2s)) { if (i2s->quirks & QUIRK_NEED_RSTCLR) { spin_lock_irqsave(i2s->lock, flags); - writel(0, i2s->addr + I2SCON); + writel(0, priv->addr + I2SCON); spin_unlock_irqrestore(i2s->lock, flags); } } @@ -1204,11 +1219,10 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, static int i2s_runtime_suspend(struct device *dev) { struct samsung_i2s_priv *priv = dev_get_drvdata(dev); - struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); - priv->suspend_i2smod = readl(i2s->addr + I2SMOD); - priv->suspend_i2scon = readl(i2s->addr + I2SCON); - priv->suspend_i2spsr = readl(i2s->addr + I2SPSR); + priv->suspend_i2smod = readl(priv->addr + I2SMOD); + priv->suspend_i2scon = readl(priv->addr + I2SCON); + priv->suspend_i2spsr = readl(priv->addr + I2SPSR); if (priv->op_clk) clk_disable_unprepare(priv->op_clk); @@ -1220,7 +1234,6 @@ static int i2s_runtime_suspend(struct device *dev) static int i2s_runtime_resume(struct device *dev) { struct samsung_i2s_priv *priv = dev_get_drvdata(dev); - struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); int ret; ret = clk_prepare_enable(priv->clk); @@ -1235,9 +1248,9 @@ static int i2s_runtime_resume(struct device *dev) } } - writel(priv->suspend_i2scon, i2s->addr + I2SCON); - writel(priv->suspend_i2smod, i2s->addr + I2SMOD); - writel(priv->suspend_i2spsr, i2s->addr + I2SPSR); + writel(priv->suspend_i2scon, priv->addr + I2SCON); + writel(priv->suspend_i2smod, priv->addr + I2SMOD); + writel(priv->suspend_i2spsr, priv->addr + I2SPSR); return 0; } @@ -1295,21 +1308,21 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { /* Activate the prescaler */ - u32 val = readl(i2s->addr + I2SPSR); - writel(val | PSR_PSREN, i2s->addr + I2SPSR); + u32 val = readl(priv->addr + I2SPSR); + writel(val | PSR_PSREN, priv->addr + I2SPSR); priv->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev, i2s_clk_name[CLK_I2S_RCLK_SRC], p_names, ARRAY_SIZE(p_names), CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, - i2s->addr + I2SMOD, reg_info->rclksrc_off, + priv->addr + I2SMOD, reg_info->rclksrc_off, 1, 0, i2s->lock); priv->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, i2s_clk_name[CLK_I2S_RCLK_PSR], i2s_clk_name[CLK_I2S_RCLK_SRC], CLK_SET_RATE_PARENT, - i2s->addr + I2SPSR, 8, 6, 0, i2s->lock); + priv->addr + I2SPSR, 8, 6, 0, i2s->lock); p_names[0] = i2s_clk_name[CLK_I2S_RCLK_PSR]; priv->clk_data.clk_num = 2; @@ -1318,7 +1331,7 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) priv->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, i2s_clk_name[CLK_I2S_CDCLK], p_names[0], CLK_SET_RATE_PARENT, - i2s->addr + I2SMOD, reg_info->cdclkcon_off, + priv->addr + I2SMOD, reg_info->cdclkcon_off, CLK_GATE_SET_TO_DISABLE, i2s->lock); priv->clk_data.clk_num += 1; @@ -1422,9 +1435,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pri_dai->addr = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pri_dai->addr)) - return PTR_ERR(pri_dai->addr); + priv->addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->addr)) + return PTR_ERR(priv->addr); regs_base = res->start; @@ -1471,7 +1484,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) } sec_dai->dma_playback.addr_width = 4; - sec_dai->addr = pri_dai->addr; sec_dai->quirks = quirks; sec_dai->idma_playback.addr = idma_addr; sec_dai->pri_dai = pri_dai; -- 2.7.4 From 0287faee08f15bdb184269714ef40e6073e14f4f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:36 +0100 Subject: [PATCH 16/16] ASoC: samsung: i2s: Drop spinlock pointer from i2s_dai data structure As we now have the 'priv' pointer in most of the places we can use priv->lock directly, dropping extra indirection in the SFR region spinlock access. Change-Id: Ic137ee120aa1871a9d2142eaee9f9292e2c0f25f Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 51 +++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 7cfcef6..a1265f9 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -87,8 +87,6 @@ struct i2s_dai { u32 quirks; const struct samsung_i2s_variant_regs *variant_regs; - spinlock_t *lock; - struct samsung_i2s_priv *priv; }; @@ -103,7 +101,7 @@ struct samsung_i2s_priv { void __iomem *addr; /* Spinlock protecting access to the device's registers */ - spinlock_t spinlock; + spinlock_t lock; /* CPU DAIs and their corresponding drivers */ struct i2s_dai *dai; @@ -527,9 +525,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, pm_runtime_get_sync(dai->dev); - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); mod = readl(priv->addr + I2SMOD); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); switch (clk_id) { case SAMSUNG_I2S_OPCLK: @@ -624,11 +622,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, goto err; } - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); mod = readl(priv->addr + I2SMOD); mod = (mod & ~mask) | val; writel(mod, priv->addr + I2SMOD); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); done: pm_runtime_put(dai->dev); @@ -709,7 +707,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } pm_runtime_get_sync(dai->dev); - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); mod = readl(priv->addr + I2SMOD); /* * Don't change the I2S mode if any controller is active on this @@ -717,7 +715,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) */ if (any_active(i2s) && ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); pm_runtime_put(dai->dev); dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); @@ -727,7 +725,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) mod &= ~(sdf_mask | lrp_rlow | mod_slave); mod |= tmp; writel(mod, priv->addr + I2SMOD); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); pm_runtime_put(dai->dev); return 0; @@ -811,11 +809,11 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); mod = readl(priv->addr + I2SMOD); mod = (mod & ~mask) | val; writel(mod, priv->addr + I2SMOD); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); @@ -943,6 +941,7 @@ static int config_setup(struct i2s_dai *i2s) static int i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); struct snd_soc_pcm_runtime *rtd = substream->private_data; struct i2s_dai *i2s = to_info(rtd->cpu_dai); @@ -953,10 +952,10 @@ static int i2s_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: pm_runtime_get_sync(dai->dev); - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); if (config_setup(i2s)) { - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); return -EINVAL; } @@ -965,12 +964,12 @@ static int i2s_trigger(struct snd_pcm_substream *substream, else i2s_txctrl(i2s, 1); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); if (capture) { i2s_rxctrl(i2s, 0); @@ -980,7 +979,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream, i2s_fifo(i2s, FIC_TXFLUSH); } - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); pm_runtime_put(dai->dev); break; } @@ -1080,13 +1079,13 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) i2s->rfs = 0; i2s->bfs = 0; - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); i2s_txctrl(i2s, 0); i2s_rxctrl(i2s, 0); i2s_fifo(i2s, FIC_TXFLUSH); i2s_fifo(other, FIC_TXFLUSH); i2s_fifo(i2s, FIC_RXFLUSH); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); /* Gate CDCLK by default */ if (!is_opened(other)) @@ -1107,9 +1106,9 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) if (!is_secondary(i2s)) { if (i2s->quirks & QUIRK_NEED_RSTCLR) { - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); writel(0, priv->addr + I2SCON); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); } } @@ -1316,13 +1315,13 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) ARRAY_SIZE(p_names), CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, priv->addr + I2SMOD, reg_info->rclksrc_off, - 1, 0, i2s->lock); + 1, 0, &priv->lock); priv->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, i2s_clk_name[CLK_I2S_RCLK_PSR], i2s_clk_name[CLK_I2S_RCLK_SRC], CLK_SET_RATE_PARENT, - priv->addr + I2SPSR, 8, 6, 0, i2s->lock); + priv->addr + I2SPSR, 8, 6, 0, &priv->lock); p_names[0] = i2s_clk_name[CLK_I2S_RCLK_PSR]; priv->clk_data.clk_num = 2; @@ -1332,7 +1331,7 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) i2s_clk_name[CLK_I2S_CDCLK], p_names[0], CLK_SET_RATE_PARENT, priv->addr + I2SMOD, reg_info->cdclkcon_off, - CLK_GATE_SET_TO_DISABLE, i2s->lock); + CLK_GATE_SET_TO_DISABLE, &priv->lock); priv->clk_data.clk_num += 1; priv->clk_data.clks = priv->clk_table; @@ -1410,8 +1409,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai = &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; - spin_lock_init(&priv->spinlock); - pri_dai->lock = &priv->spinlock; + spin_lock_init(&priv->lock); if (!np) { if (i2s_pdata == NULL) { @@ -1473,7 +1471,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (quirks & QUIRK_SEC_DAI) { sec_dai = &priv->dai[SAMSUNG_I2S_ID_SECONDARY - 1]; - sec_dai->lock = &priv->spinlock; sec_dai->variant_regs = pri_dai->variant_regs; sec_dai->dma_playback.addr = regs_base + I2STXDS; sec_dai->dma_playback.chan_name = "tx-sec"; -- 2.7.4