From 0db54e74a9e44afb92bc547277827258dbf5dc8f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 13:56:12 +0100 Subject: ASoC: sh: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/sh/dma-sh7760.c | 6 ------ sound/soc/sh/fsi.c | 6 ------ sound/soc/sh/siu_pcm.c | 1 - 3 files changed, 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index a5b2c4ea90d9..fd11404a3bc7 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -305,11 +305,6 @@ static struct snd_pcm_ops camelot_pcm_ops = { .pointer = camelot_pos, }; -static void camelot_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; @@ -328,7 +323,6 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_platform_driver sh7760_soc_platform = { .ops = &camelot_pcm_ops, .pcm_new = camelot_pcm_new, - .pcm_free = camelot_pcm_free, }; static int sh7760_soc_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 8869971d7884..422faa93972b 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1765,11 +1765,6 @@ static struct snd_pcm_ops fsi_pcm_ops = { #define PREALLOC_BUFFER (32 * 1024) #define PREALLOC_BUFFER_MAX (32 * 1024) -static void fsi_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) { return snd_pcm_lib_preallocate_pages_for_all( @@ -1821,7 +1816,6 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { static struct snd_soc_platform_driver fsi_soc_platform = { .ops = &fsi_pcm_ops, .pcm_new = fsi_pcm_new, - .pcm_free = fsi_pcm_free, }; static const struct snd_soc_component_driver fsi_soc_component = { diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index 32eb6da2d2bd..82902f56e82f 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -589,7 +589,6 @@ static void siu_pcm_free(struct snd_pcm *pcm) tasklet_kill(&port_info->playback.tasklet); siu_free_port(port_info); - snd_pcm_lib_preallocate_free_for_all(pcm); dev_dbg(pcm->card->dev, "%s\n", __func__); } -- cgit v1.2.3 From fce091ee0a7f25108c7ab3eb06b9e436b7aeac11 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 19 Dec 2014 14:55:21 +0100 Subject: ASoC: samsung: i2s: Remove unused gpios field from struct i2s The 'gpios' field in 'struct i2s' is now unused, this change seems to be missing in commit 0429ffeff460c4302bd1520e6 ("ASoC: samsung: Remove obsolete GPIO based DT pinmuxing"). Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index b5a80c528d86..86491c9f121f 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -95,7 +95,6 @@ struct i2s_dai { u32 suspend_i2smod; u32 suspend_i2scon; u32 suspend_i2spsr; - unsigned long gpios[7]; /* i2s gpio line numbers */ const struct samsung_i2s_variant_regs *variant_regs; }; -- cgit v1.2.3 From 9cf247473167df29a3d99464385b4afe1fc16f2f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:28 +0100 Subject: ASoC: samsung: i2s: samsung_i2s_get_driver_data() cleanup Tidy up the samsung_i2s_get_driver_data() function by using IS_ENABLE() instead of #ifdef and add missing braces for the 'else' part. Also ensure we are not dereferencing NULL 'match' pointer. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 86491c9f121f..e5473ee799d7 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1123,15 +1123,14 @@ static const struct of_device_id exynos_i2s_match[]; static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data( struct platform_device *pdev) { -#ifdef CONFIG_OF - if (pdev->dev.of_node) { + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { const struct of_device_id *match; match = of_match_node(exynos_i2s_match, pdev->dev.of_node); - return match->data; - } else -#endif + return match ? match->data : NULL; + } else { return (struct samsung_i2s_dai_data *) platform_get_device_id(pdev)->driver_data; + } } #ifdef CONFIG_PM -- cgit v1.2.3 From 53f7faa17e9489f8b7be67dd9e87167f1779ef28 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:29 +0100 Subject: ASoC: samsung: i2s: Add return value checks in probe() These functions may fail so let's properly report any errors. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index e5473ee799d7..aa52b41f1749 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1173,11 +1173,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to get drvdata\n"); return -EFAULT; } - devm_snd_soc_register_component(&sec_dai->pdev->dev, + ret = devm_snd_soc_register_component(&sec_dai->pdev->dev, &samsung_i2s_component, &sec_dai->i2s_dai_drv, 1); - samsung_asoc_dma_platform_register(&pdev->dev); - return 0; + if (ret != 0) + return ret; + + return samsung_asoc_dma_platform_register(&pdev->dev); } pri_dai = i2s_alloc_dai(pdev, false); @@ -1290,7 +1292,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev); + if (ret != 0) + return ret; return 0; err: -- cgit v1.2.3 From af1cf5cf9c1881192f72af204e873ac345a3e265 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:30 +0100 Subject: ASoC: samsung: i2s: Request memory region in driver probe() The memory mapped registers region is common for both DAIs so request it in the I2S platform device driver's probe for the platform device corresponding to the primary DAI, rather than in the ASoC DAI's probe callback. While at it switch to devm_ioremap_resource(). This also drops the hard coded (0x100) register region size in the driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 45 +++++++-------------------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index aa52b41f1749..366b720731e1 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -59,10 +59,8 @@ struct samsung_i2s_dai_data { struct i2s_dai { /* Platform device for this DAI */ struct platform_device *pdev; - /* IOREMAP'd SFRs */ + /* Memory mapped SFR region */ void __iomem *addr; - /* Physical base address of SFRs */ - u32 base; /* Rate of RCLK source clock */ unsigned long rclk_srcrate; /* Frame Clock */ @@ -979,16 +977,9 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) goto probe_exit; } - i2s->addr = ioremap(i2s->base, 0x100); - if (i2s->addr == NULL) { - dev_err(&i2s->pdev->dev, "cannot ioremap registers\n"); - return -ENXIO; - } - i2s->clk = clk_get(&i2s->pdev->dev, "iis"); if (IS_ERR(i2s->clk)) { dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n"); - iounmap(i2s->addr); return PTR_ERR(i2s->clk); } @@ -1001,7 +992,6 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); if (other) { - other->addr = i2s->addr; other->clk = i2s->clk; } @@ -1043,8 +1033,6 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) clk_disable_unprepare(i2s->clk); clk_put(i2s->clk); - - iounmap(i2s->addr); } i2s->clk = NULL; @@ -1162,7 +1150,6 @@ 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 = 0; /* Call during Seconday interface registration */ i2s_dai_data = samsung_i2s_get_driver_data(pdev); @@ -1229,16 +1216,10 @@ static int samsung_i2s_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Unable to get I2S SFR address\n"); - return -ENXIO; - } + pri_dai->addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pri_dai->addr)) + return PTR_ERR(pri_dai->addr); - if (!request_mem_region(res->start, resource_size(res), - "samsung-i2s")) { - dev_err(&pdev->dev, "Unable to request SFR region\n"); - return -EBUSY; - } regs_base = res->start; pri_dai->dma_playback.dma_addr = regs_base + I2STXD; @@ -1247,7 +1228,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_capture.ch_name = "rx"; pri_dai->dma_playback.dma_size = 4; pri_dai->dma_capture.dma_size = 4; - pri_dai->base = regs_base; pri_dai->quirks = quirks; pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; @@ -1258,8 +1238,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai = i2s_alloc_dai(pdev, true); if (!sec_dai) { dev_err(&pdev->dev, "Unable to alloc I2S_sec\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } sec_dai->variant_regs = pri_dai->variant_regs; @@ -1273,7 +1252,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) } sec_dai->dma_playback.dma_size = 4; - sec_dai->base = regs_base; + sec_dai->addr = pri_dai->addr; sec_dai->quirks = quirks; sec_dai->idma_playback.dma_addr = idma_addr; sec_dai->pri_dai = pri_dai; @@ -1282,8 +1261,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { dev_err(&pdev->dev, "Unable to configure gpio\n"); - ret = -EINVAL; - goto err; + return -EINVAL; } devm_snd_soc_register_component(&pri_dai->pdev->dev, @@ -1297,17 +1275,11 @@ static int samsung_i2s_probe(struct platform_device *pdev) return ret; return 0; -err: - if (res) - release_mem_region(regs_base, resource_size(res)); - - return ret; } static int samsung_i2s_remove(struct platform_device *pdev) { struct i2s_dai *i2s, *other; - struct resource *res; i2s = dev_get_drvdata(&pdev->dev); other = i2s->pri_dai ? : i2s->sec_dai; @@ -1317,9 +1289,6 @@ static int samsung_i2s_remove(struct platform_device *pdev) other->sec_dai = NULL; } else { pm_runtime_disable(&pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); } i2s->pri_dai = NULL; -- cgit v1.2.3 From 0ec2ba807c1563134a865b6f0b326b8a2e776937 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:31 +0100 Subject: ASoC: samsung: i2s: Move clk_get() to platform driver probe() Acquire the I2S interface clock in driver probe() callback as it's a per-device not a per-DAI clock. While at it switch to the resource managed clk_get(). Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 366b720731e1..a854ffca2416 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -971,18 +971,12 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; int ret; - if (other && other->clk) { /* If this is probe on secondary */ + if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, NULL); goto probe_exit; } - i2s->clk = clk_get(&i2s->pdev->dev, "iis"); - if (IS_ERR(i2s->clk)) { - dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n"); - return PTR_ERR(i2s->clk); - } - ret = clk_prepare_enable(i2s->clk); if (ret != 0) { dev_err(&i2s->pdev->dev, "failed to enable clock: %d\n", ret); @@ -991,10 +985,6 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); - if (other) { - other->clk = i2s->clk; - } - if (i2s->quirks & QUIRK_NEED_RSTCLR) writel(CON_RSTCLR, i2s->addr + I2SCON); @@ -1032,7 +1022,6 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) writel(0, i2s->addr + I2SCON); clk_disable_unprepare(i2s->clk); - clk_put(i2s->clk); } i2s->clk = NULL; @@ -1222,6 +1211,11 @@ 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)) { + dev_err(&pdev->dev, "Failed to get iis clock\n"); + return PTR_ERR(pri_dai->clk); + } pri_dai->dma_playback.dma_addr = regs_base + I2STXD; pri_dai->dma_capture.dma_addr = regs_base + I2SRXD; pri_dai->dma_playback.ch_name = "tx"; @@ -1253,6 +1247,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->dma_playback.dma_size = 4; sec_dai->addr = pri_dai->addr; + sec_dai->clk = pri_dai->clk; sec_dai->quirks = quirks; sec_dai->idma_playback.dma_addr = idma_addr; sec_dai->pri_dai = pri_dai; -- cgit v1.2.3 From c92f1d0e7c8431f8b3bf1d42e951ead07b22078e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:32 +0100 Subject: ASoC: samsung: i2s: Move clk enable to the platform driver probe() The clk_prepare_enable() call on the "iis" clock is moved to happen earlier in the DAI platform device driver's probe() callback, so the I2S registers can be safely accessed through the clk API, after the clk supplier is registered in the platform device probe(). After this patch the "iis" clock is kept enabled since the (primary) I2S platform device probe() and until the platform device driver remove() call. This is similar to gating the clock in the snd_soc_dai probe() and remove() callbacks. Normally, in addition to that we should mark the device as PM runtime active, so if runtime PM is enabled it can idle the device by turning off the clock. Correcting this issue is left for a separate patch series, as we need to ensure the BUSCLK clock is always enabled when required. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index a854ffca2416..f75c19e5b5c3 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -969,7 +969,6 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; - int ret; if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, @@ -977,12 +976,6 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) goto probe_exit; } - ret = clk_prepare_enable(i2s->clk); - if (ret != 0) { - dev_err(&i2s->pdev->dev, "failed to enable clock: %d\n", ret); - return ret; - } - samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); if (i2s->quirks & QUIRK_NEED_RSTCLR) @@ -1014,18 +1007,12 @@ probe_exit: static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) { struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); - struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; - - if (!other || !other->clk) { + if (!is_secondary(i2s)) { if (i2s->quirks & QUIRK_NEED_RSTCLR) writel(0, i2s->addr + I2SCON); - - clk_disable_unprepare(i2s->clk); } - i2s->clk = NULL; - return 0; } @@ -1139,6 +1126,7 @@ 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; /* Call during Seconday interface registration */ i2s_dai_data = samsung_i2s_get_driver_data(pdev); @@ -1216,6 +1204,12 @@ static int samsung_i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to get iis clock\n"); return PTR_ERR(pri_dai->clk); } + + ret = clk_prepare_enable(pri_dai->clk); + if (ret != 0) { + dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); + return ret; + } pri_dai->dma_playback.dma_addr = regs_base + I2STXD; pri_dai->dma_capture.dma_addr = regs_base + I2SRXD; pri_dai->dma_playback.ch_name = "tx"; @@ -1286,6 +1280,9 @@ static int samsung_i2s_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } + if (!is_secondary(i2s)) + clk_disable_unprepare(i2s->clk); + i2s->pri_dai = NULL; i2s->sec_dai = NULL; -- cgit v1.2.3 From dcd60fc3445329d738a23ab7997717491c2f4cec Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:33 +0100 Subject: ASoC: samsung: i2s: Add get_other_dai helper function The code to get pointer to the other DAI is repeated multiple times. Add a helper function and use it instead. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f75c19e5b5c3..cab2a2abc89b 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -130,10 +130,16 @@ static inline bool tx_active(struct i2s_dai *i2s) return active ? true : false; } +/* Return pointer to the other DAI */ +static inline struct i2s_dai *get_other_dai(struct i2s_dai *i2s) +{ + return i2s->pri_dai ? : i2s->sec_dai; +} + /* If the other interface of the controller is transmitting data */ static inline bool other_tx_active(struct i2s_dai *i2s) { - struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; + struct i2s_dai *other = get_other_dai(i2s); return tx_active(other); } @@ -160,7 +166,7 @@ static inline bool rx_active(struct i2s_dai *i2s) /* If the other interface of the controller is receiving data */ static inline bool other_rx_active(struct i2s_dai *i2s) { - struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; + struct i2s_dai *other = get_other_dai(i2s); return rx_active(other); } @@ -461,7 +467,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, int dir) { struct i2s_dai *i2s = to_info(dai); - struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; + struct i2s_dai *other = get_other_dai(i2s); u32 mod = readl(i2s->addr + I2SMOD); const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; @@ -733,7 +739,7 @@ static int i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); - struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; + struct i2s_dai *other = get_other_dai(i2s); unsigned long flags; spin_lock_irqsave(&lock, flags); @@ -760,7 +766,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); - struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; + struct i2s_dai *other = get_other_dai(i2s); unsigned long flags; const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; @@ -791,7 +797,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, static int config_setup(struct i2s_dai *i2s) { - struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; + struct i2s_dai *other = get_other_dai(i2s); unsigned rfs, bfs, blc; u32 psr; @@ -899,7 +905,7 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { struct i2s_dai *i2s = to_info(dai); - struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; + struct i2s_dai *other = get_other_dai(i2s); switch (div_id) { case SAMSUNG_I2S_DIV_BCLK: @@ -968,7 +974,7 @@ static int i2s_resume(struct snd_soc_dai *dai) static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); - struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; + struct i2s_dai *other = get_other_dai(i2s); if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, @@ -1271,7 +1277,7 @@ static int samsung_i2s_remove(struct platform_device *pdev) struct i2s_dai *i2s, *other; i2s = dev_get_drvdata(&pdev->dev); - other = i2s->pri_dai ? : i2s->sec_dai; + other = get_other_dai(i2s); if (other) { other->pri_dai = NULL; -- cgit v1.2.3 From 872c26bd801dcda21402caa2dcd0a39315b08b65 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:34 +0100 Subject: ASoC: samsung: i2s: Remove an unneeded goto usage The usage of this goto seems unjustified, use if/else statement instead. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index cab2a2abc89b..2bac71945b3e 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -979,19 +979,18 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, NULL); - goto probe_exit; - } - - samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); + } else { + samsung_asoc_init_dma_data(dai, &i2s->dma_playback, + &i2s->dma_capture); - if (i2s->quirks & QUIRK_NEED_RSTCLR) - writel(CON_RSTCLR, i2s->addr + I2SCON); + if (i2s->quirks & QUIRK_NEED_RSTCLR) + writel(CON_RSTCLR, i2s->addr + I2SCON); - if (i2s->quirks & QUIRK_SUPPORTS_IDMA) - idma_reg_addr_init(i2s->addr, + if (i2s->quirks & QUIRK_SUPPORTS_IDMA) + idma_reg_addr_init(i2s->addr, i2s->sec_dai->idma_playback.dma_addr); + } -probe_exit: /* Reset any constraint on RFS and BFS */ i2s->rfs = 0; i2s->bfs = 0; -- cgit v1.2.3 From f36705366a2324fedd6cca7683fadf947ac0b154 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:35 +0100 Subject: ASoC: samsung: i2s: Add spinlock in place of local_irq_* calls It seems this driver hasn't been updated for SMP, as local_irq_save/ local_irq_restore don't provide proper protection of read/modify/write of the device's registers on such systems. Introduce a spinlock serializing access to the register region, it will be helpful later when I2SMOD, I2SPSR registers are made also accessible through the clk API. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 2bac71945b3e..20cc51fc76ae 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -94,6 +94,10 @@ struct i2s_dai { u32 suspend_i2scon; 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; }; /* Lock for cross i/f checks */ @@ -867,10 +871,10 @@ static int i2s_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - local_irq_save(flags); + spin_lock_irqsave(i2s->lock, flags); if (config_setup(i2s)) { - local_irq_restore(flags); + spin_unlock_irqrestore(i2s->lock, flags); return -EINVAL; } @@ -879,12 +883,12 @@ static int i2s_trigger(struct snd_pcm_substream *substream, else i2s_txctrl(i2s, 1); - local_irq_restore(flags); + spin_unlock_irqrestore(i2s->lock, flags); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - local_irq_save(flags); + spin_lock_irqsave(i2s->lock, flags); if (capture) { i2s_rxctrl(i2s, 0); @@ -894,7 +898,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream, i2s_fifo(i2s, FIC_TXFLUSH); } - local_irq_restore(flags); + spin_unlock_irqrestore(i2s->lock, flags); break; } @@ -1157,6 +1161,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) return -ENOMEM; } + spin_lock_init(&pri_dai->spinlock); + pri_dai->lock = &pri_dai->spinlock; + if (!np) { res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!res) { @@ -1234,6 +1241,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) return -ENOMEM; } + sec_dai->lock = &pri_dai->spinlock; sec_dai->variant_regs = pri_dai->variant_regs; sec_dai->dma_playback.dma_addr = regs_base + I2STXDS; sec_dai->dma_playback.ch_name = "tx-sec"; -- cgit v1.2.3 From ce8bcdbb61d96de481de14b3ad985797a417246c Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:36 +0100 Subject: ASoC: samsung: i2s: Protect more registers with a spinlock Ensure the I2SMOD, I2SPSR registers, which are also exposed through clk API are only accessed with the i2s->spinlock spinlock held. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 81 +++++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 20cc51fc76ae..05fc2f0e91ca 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -472,17 +472,22 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, { struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); - u32 mod = readl(i2s->addr + I2SMOD); const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; + u32 mod, mask, val = 0; + + spin_lock(i2s->lock); + mod = readl(i2s->addr + I2SMOD); + spin_unlock(i2s->lock); switch (clk_id) { case SAMSUNG_I2S_OPCLK: - mod &= ~MOD_OPCLK_MASK; - mod |= dir; + mask = MOD_OPCLK_MASK; + val = dir; break; case SAMSUNG_I2S_CDCLK: + mask = 1 << i2s_regs->cdclkcon_off; /* Shouldn't matter in GATING(CLOCK_IN) mode */ if (dir == SND_SOC_CLOCK_IN) rfs = 0; @@ -499,15 +504,15 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, } if (dir == SND_SOC_CLOCK_IN) - mod |= 1 << i2s_regs->cdclkcon_off; - else - mod &= ~(1 << i2s_regs->cdclkcon_off); + val = 1 << i2s_regs->cdclkcon_off; i2s->rfs = rfs; break; case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */ case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */ + mask = 1 << i2s_regs->rclksrc_off; + if ((i2s->quirks & QUIRK_NO_MUXPSR) || (clk_id == SAMSUNG_I2S_RCLKSRC_0)) clk_id = 0; @@ -557,18 +562,19 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, return 0; } - if (clk_id == 0) - mod &= ~(1 << i2s_regs->rclksrc_off); - else - mod |= 1 << i2s_regs->rclksrc_off; - + if (clk_id == 1) + val = 1 << i2s_regs->rclksrc_off; break; default: dev_err(&i2s->pdev->dev, "We don't serve that!\n"); return -EINVAL; } + spin_lock(i2s->lock); + mod = readl(i2s->addr + I2SMOD); + mod = (mod & ~mask) | val; writel(mod, i2s->addr + I2SMOD); + spin_unlock(i2s->lock); return 0; } @@ -577,9 +583,8 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct i2s_dai *i2s = to_info(dai); - u32 mod = readl(i2s->addr + I2SMOD); int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; - u32 tmp = 0; + u32 mod, tmp = 0; lrp_shift = i2s->variant_regs->lrp_off; sdf_shift = i2s->variant_regs->sdf_off; @@ -639,12 +644,15 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, return -EINVAL; } + spin_lock(i2s->lock); + mod = readl(i2s->addr + I2SMOD); /* * Don't change the I2S mode if any controller is active on this * channel. */ if (any_active(i2s) && ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { + spin_unlock(i2s->lock); dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; @@ -653,6 +661,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, mod &= ~(sdf_mask | lrp_rlow | mod_slave); mod |= tmp; writel(mod, i2s->addr + I2SMOD); + spin_unlock(i2s->lock); return 0; } @@ -661,16 +670,16 @@ 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); - u32 mod = readl(i2s->addr + I2SMOD); + u32 mod, mask = 0, val = 0; if (!is_secondary(i2s)) - mod &= ~(MOD_DC2_EN | MOD_DC1_EN); + mask |= (MOD_DC2_EN | MOD_DC1_EN); switch (params_channels(params)) { case 6: - mod |= MOD_DC2_EN; + val |= MOD_DC2_EN; case 4: - mod |= MOD_DC1_EN; + val |= MOD_DC1_EN; break; case 2: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -692,44 +701,49 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, } if (is_secondary(i2s)) - mod &= ~MOD_BLCS_MASK; + mask |= MOD_BLCS_MASK; else - mod &= ~MOD_BLCP_MASK; + mask |= MOD_BLCP_MASK; if (is_manager(i2s)) - mod &= ~MOD_BLC_MASK; + mask |= MOD_BLC_MASK; switch (params_width(params)) { case 8: if (is_secondary(i2s)) - mod |= MOD_BLCS_8BIT; + val |= MOD_BLCS_8BIT; else - mod |= MOD_BLCP_8BIT; + val |= MOD_BLCP_8BIT; if (is_manager(i2s)) - mod |= MOD_BLC_8BIT; + val |= MOD_BLC_8BIT; break; case 16: if (is_secondary(i2s)) - mod |= MOD_BLCS_16BIT; + val |= MOD_BLCS_16BIT; else - mod |= MOD_BLCP_16BIT; + val |= MOD_BLCP_16BIT; if (is_manager(i2s)) - mod |= MOD_BLC_16BIT; + val |= MOD_BLC_16BIT; break; case 24: if (is_secondary(i2s)) - mod |= MOD_BLCS_24BIT; + val |= MOD_BLCS_24BIT; else - mod |= MOD_BLCP_24BIT; + val |= MOD_BLCP_24BIT; if (is_manager(i2s)) - mod |= MOD_BLC_24BIT; + val |= MOD_BLC_24BIT; break; default: dev_err(&i2s->pdev->dev, "Format(%d) not supported\n", params_format(params)); return -EINVAL; } + + spin_lock(i2s->lock); + mod = readl(i2s->addr + I2SMOD); + mod = (mod & ~mask) | val; writel(mod, i2s->addr + I2SMOD); + spin_unlock(i2s->lock); samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); @@ -979,6 +993,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); + unsigned long flags; if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, @@ -999,11 +1014,14 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) i2s->rfs = 0; i2s->bfs = 0; i2s->rclk_srcrate = 0; + + spin_lock_irqsave(i2s->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); /* Gate CDCLK by default */ if (!is_opened(other)) @@ -1018,8 +1036,11 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); if (!is_secondary(i2s)) { - if (i2s->quirks & QUIRK_NEED_RSTCLR) + if (i2s->quirks & QUIRK_NEED_RSTCLR) { + spin_lock(i2s->lock); writel(0, i2s->addr + I2SCON); + spin_unlock(i2s->lock); + } } return 0; -- cgit v1.2.3 From ecb400cabb37cfef3221e45e4f6370a855aa7a44 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:37 +0100 Subject: ASoC: samsung: odroidx2: Handle I2S CDCLK clock conditionally In order to support old DTs we check the codec device node if it contains "clocks" property and only if it doesn't (which indicates an old DT) we proceed with enabling the CDCLK clock by means of the set_sysclk() callback. For new DTs which use the common clock bindings for CDCLK that clock is supposed to be handled outside the sound machine driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/odroidx2_max98090.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c index fa4f1d2f69bf..596f1180a369 100644 --- a/sound/soc/samsung/odroidx2_max98090.c +++ b/sound/soc/samsung/odroidx2_max98090.c @@ -21,6 +21,8 @@ struct odroidx2_drv_data { /* The I2S CDCLK output clock frequency for the MAX98090 codec */ #define MAX98090_MCLK 19200000 +static struct snd_soc_dai_link odroidx2_dai[]; + static int odroidx2_late_probe(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; @@ -29,7 +31,9 @@ static int odroidx2_late_probe(struct snd_soc_card *card) ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK, SND_SOC_CLOCK_IN); - if (ret < 0) + + if (ret < 0 || of_find_property(odroidx2_dai[0].codec_of_node, + "clocks", NULL)) return ret; /* Set the cpu DAI configuration in order to use CDCLK */ -- cgit v1.2.3 From 074b89bb5fb7e80e0f98f1b45f276b0386269e3d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 14 Jan 2015 19:42:39 +0100 Subject: ASoC: samsung: i2s: Add clock provider for the I2S internal clocks This patch adds clock provider (currently only for DT platforms) for the CODECLKO (CDCLK) gate, RCLKSRC mux and RCLK pre-scaler divider divider clock. Those all tree clock are only available in the IIS Multi Audio Interface (I2S0), the regular IIS Bus Interface has only CDCLK gate clock. The motivation behind this patch is to expose the I2S internal clocks which are currently controlled through set_sysclk() through the clk API, so dedicated sound machine driver per each board can be avoided. The intention is also to fix the CDCLK gating issue reported by Daniel Drake: http://mailman.alsa-project.org/pipermail/alsa-devel/2014-September/081753.html This patch also reverts commit b97c60abf9a561f86ae71bd741add02673cc1 ("ASoC: samsung-i2s: Maintain CDCLK settings across i2s_{shutdown/ startup}") The problem that commit attempted to solve only affects the Odroid X2/U3, which doesn't configure the CDCLK clock in struct snd_soc_dai_ops hw_params callback and the issue should be now resolved by using clk API, i.e. having the codec enabling/ disabling the CDCLK clock as required. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 113 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 05fc2f0e91ca..b92ab40d2be6 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -10,9 +10,11 @@ * published by the Free Software Foundation. */ +#include #include #include #include +#include #include #include #include @@ -81,8 +83,6 @@ struct i2s_dai { #define DAI_OPENED (1 << 0) /* Dai is opened */ #define DAI_MANAGER (1 << 1) /* Dai is the manager */ unsigned mode; - /* CDCLK pin direction: 0 - input, 1 - output */ - unsigned int cdclk_out:1; /* Driver for this DAI */ struct snd_soc_dai_driver i2s_dai_drv; /* DMA parameters */ @@ -98,6 +98,10 @@ struct i2s_dai { /* 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 */ + struct clk *clk_table[3]; + struct clk_onecell_data clk_data; }; /* Lock for cross i/f checks */ @@ -774,9 +778,6 @@ static int i2s_startup(struct snd_pcm_substream *substream, spin_unlock_irqrestore(&lock, flags); - if (!is_opened(other) && i2s->cdclk_out) - i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK, - 0, SND_SOC_CLOCK_OUT); return 0; } @@ -786,31 +787,20 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); unsigned long flags; - const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; spin_lock_irqsave(&lock, flags); i2s->mode &= ~DAI_OPENED; i2s->mode &= ~DAI_MANAGER; - if (is_opened(other)) { + if (is_opened(other)) other->mode |= DAI_MANAGER; - } else { - u32 mod = readl(i2s->addr + I2SMOD); - i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off)); - if (other) - other->cdclk_out = i2s->cdclk_out; - } + /* Reset any constraint on RFS and BFS */ i2s->rfs = 0; i2s->bfs = 0; spin_unlock_irqrestore(&lock, flags); - - /* Gate CDCLK by default */ - if (!is_opened(other)) - i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK, - 0, SND_SOC_CLOCK_IN); } static int config_setup(struct i2s_dai *i2s) @@ -1147,6 +1137,87 @@ static int i2s_runtime_resume(struct device *dev) } #endif /* CONFIG_PM */ +static void i2s_unregister_clocks(struct i2s_dai *i2s) +{ + 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]); + } +} + +static void i2s_unregister_clock_provider(struct platform_device *pdev) +{ + struct i2s_dai *i2s = dev_get_drvdata(&pdev->dev); + + of_clk_del_provider(pdev->dev.of_node); + i2s_unregister_clocks(i2s); +} + +static int i2s_register_clock_provider(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct i2s_dai *i2s = dev_get_drvdata(dev); + const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" }; + const char *p_names[2] = { NULL }; + const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs; + struct clk *rclksrc; + int ret, i; + + /* Register the clock provider only if it's expected in the DTB */ + if (!of_find_property(dev->of_node, "#clock-cells", NULL)) + return 0; + + /* Get the RCLKSRC mux clock parent clock names */ + for (i = 0; i < ARRAY_SIZE(p_names); i++) { + rclksrc = clk_get(dev, clk_name[i]); + if (IS_ERR(rclksrc)) + continue; + p_names[i] = __clk_get_name(rclksrc); + clk_put(rclksrc); + } + + if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { + /* Activate the prescaler */ + u32 val = readl(i2s->addr + I2SPSR); + writel(val | PSR_PSREN, i2s->addr + I2SPSR); + + i2s->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(NULL, + "i2s_rclksrc", 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(NULL, + "i2s_presc", "i2s_rclksrc", + CLK_SET_RATE_PARENT, + i2s->addr + I2SPSR, 8, 6, 0, i2s->lock); + + p_names[0] = "i2s_presc"; + i2s->clk_data.clk_num = 2; + } + of_property_read_string_index(dev->of_node, + "clock-output-names", 0, &clk_name[0]); + + i2s->clk_table[CLK_I2S_CDCLK] = clk_register_gate(NULL, clk_name[0], + 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; + + ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, + &i2s->clk_data); + if (ret < 0) { + dev_err(dev, "failed to add clock provider: %d\n", ret); + i2s_unregister_clocks(i2s); + } + + return ret; +} + static int samsung_i2s_probe(struct platform_device *pdev) { struct i2s_dai *pri_dai, *sec_dai = NULL; @@ -1297,7 +1368,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (ret != 0) return ret; - return 0; + return i2s_register_clock_provider(pdev); } static int samsung_i2s_remove(struct platform_device *pdev) @@ -1314,8 +1385,10 @@ static int samsung_i2s_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } - if (!is_secondary(i2s)) + if (!is_secondary(i2s)) { + i2s_unregister_clock_provider(pdev); clk_disable_unprepare(i2s->clk); + } i2s->pri_dai = NULL; i2s->sec_dai = NULL; -- cgit v1.2.3 From 3a41e0f7233a644b45e536a31c0116500ac106a4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 16 Jan 2015 14:34:52 +0100 Subject: ASoC: jive: Automatically disconnect non-connected pins All DAPM input and output pins of the wm8750 are either used in the card's DAPM routing table or are marked as not connected. Set the fully_routed flag of the card instead of manually marking the unused inputs and outputs as not connected. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/jive_wm8750.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c index 6c3b359bb4c1..7fcb51faa2a0 100644 --- a/sound/soc/samsung/jive_wm8750.c +++ b/sound/soc/samsung/jive_wm8750.c @@ -83,22 +83,6 @@ static struct snd_soc_ops jive_ops = { .hw_params = jive_hw_params, }; -static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - /* These endpoints are not being used. */ - snd_soc_dapm_nc_pin(dapm, "LINPUT2"); - snd_soc_dapm_nc_pin(dapm, "RINPUT2"); - snd_soc_dapm_nc_pin(dapm, "LINPUT3"); - snd_soc_dapm_nc_pin(dapm, "RINPUT3"); - snd_soc_dapm_nc_pin(dapm, "OUT3"); - snd_soc_dapm_nc_pin(dapm, "MONO"); - - return 0; -} - static struct snd_soc_dai_link jive_dai = { .name = "wm8750", .stream_name = "WM8750", @@ -106,7 +90,6 @@ static struct snd_soc_dai_link jive_dai = { .codec_dai_name = "wm8750-hifi", .platform_name = "s3c2412-i2s", .codec_name = "wm8750.0-001a", - .init = jive_wm8750_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .ops = &jive_ops, @@ -123,6 +106,7 @@ static struct snd_soc_card snd_soc_machine_jive = { .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), .dapm_routes = audio_map, .num_dapm_routes = ARRAY_SIZE(audio_map), + .fully_routed = true, }; static struct platform_device *jive_snd_device; -- cgit v1.2.3 From e236d4d796f87d062f59af8004c8f485baf10b62 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 16 Jan 2015 14:34:53 +0100 Subject: ASoC: smdk_wm8580: Pass card DAPM context to snd_soc_dapm_disable_pin() The "MicIn" widget is a card level DAPM element so pass the card's DAPM context instead of the CODEC's DAPM context to snd_soc_dapm_disable_pin(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/smdk_wm8580.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index 17a2f717ec02..548bfd993788 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -136,13 +136,10 @@ static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = { static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - /* Enabling the microphone requires the fitting of a 0R * resistor to connect the line from the microphone jack. */ - snd_soc_dapm_disable_pin(dapm, "MicIn"); + snd_soc_dapm_disable_pin(&rtd->card->dapm, "MicIn"); return 0; } -- cgit v1.2.3 From a59aa180ea56004a8dd6ece93699adf5eacdf4d9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 16 Jan 2015 20:04:16 +0100 Subject: ASoC: samsung: Replace depends on REGMAP_I2C with depends on I2C regmap is a library function that gets selected by drivers that need it. No driver modules should depend on it, since this can create dependency loops. E.g. if machine driver depends on REGMAP_I2C and selects the CODEC driver and the CODEC driver selects REGMAP_I2C, then the machine driver selects by extension one of its dependencies. The proper way to handle this is for machine drivers to depend on the same dependencies as the CODEC driver they select. In this case it is I2C. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index fc67f97f19f6..e817a2f43ea8 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -54,7 +54,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) - depends on REGMAP_I2C + depends on I2C select SND_SOC_WM8580 select SND_SAMSUNG_I2S help @@ -167,7 +167,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF config SND_SOC_SMDK_WM8580_PCM tristate "SoC PCM Audio support for WM8580 on SMDK" depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110) - depends on REGMAP_I2C + depends on I2C select SND_SOC_WM8580 select SND_SAMSUNG_PCM help -- cgit v1.2.3 From 4c121129c9dcb43b33d1cd568c8f2636e72597b0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 28 Jan 2015 22:31:30 +0100 Subject: ASoC: rt5677: fix SPI dependency The rt5677 codec has gained code that requires SPI to work correctly, but there is no provision in Kconfig to prevent the driver from being used when SPI is disabled or a loadable module, resulting in this build error: sound/built-in.o: In function `rt5677_spi_write': :(.text+0xa7ba0): undefined reference to `spi_sync' sound/built-in.o: In function `rt5677_spi_driver_init': :(.init.text+0x253c): undefined reference to `spi_register_driver' ERROR: "spi_sync" [sound/soc/codecs/snd-soc-rt5677-spi.ko] undefined! ERROR: "spi_register_driver" [sound/soc/codecs/snd-soc-rt5677-spi.ko] undefined! This makes the SPI portion of the driver depend on the SPI subsystem, and disables the function that uses SPI for firmware download if SPI is disabled. The latter may not be the correct solution, but I could not come up with a better one. Signed-off-by: Arnd Bergmann Fixes: af48f1d08a54741 ("ASoC: rt5677: Support DSP function for VAD application") Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/rt5677.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8349f982a586..ef2c70e77d91 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -525,7 +525,7 @@ config SND_SOC_RT5677 config SND_SOC_RT5677_SPI tristate - default SND_SOC_RT5677 + default SND_SOC_RT5677 && SPI #Freescale sgtl5000 codec config SND_SOC_SGTL5000 diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 88de759fb7fc..75d2d73be545 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -702,6 +702,9 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) static bool activity; int ret; + if (!IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI)) + return -ENXIO; + if (on && !activity) { activity = true; -- cgit v1.2.3 From 2ca087bc9edafd7cd1e89d0ac61a31067985bd15 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 30 Jan 2015 09:32:43 +0200 Subject: ASoC: rx51: Correct DAPM route for capture "Mic Bias" is DAPM_SUPPLY so it has to be connected in the route accordingly. Fixes audio capture on the board. Reported-by: Pavel Machek Signed-off-by: Peter Ujfalusi Tested-by: Pavel Machek Signed-off-by: Mark Brown --- sound/soc/omap/rx51.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 04896d6252a2..7f299357c2d2 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -250,14 +250,14 @@ static const struct snd_soc_dapm_route audio_map[] = { {"FM Transmitter", NULL, "LLOUT"}, {"FM Transmitter", NULL, "RLOUT"}, - {"DMic Rate 64", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "DMic"}, + {"DMic Rate 64", NULL, "DMic"}, + {"DMic", NULL, "Mic Bias"}, {"b LINE2R", NULL, "MONO_LOUT"}, {"Earphone", NULL, "b HPLOUT"}, - {"LINE1L", NULL, "b Mic Bias"}, - {"b Mic Bias", NULL, "HS Mic"} + {"LINE1L", NULL, "HS Mic"}, + {"HS Mic", NULL, "b Mic Bias"}, }; static const char * const spk_function[] = {"Off", "On"}; -- cgit v1.2.3 From 6cf2cf31507522c199cf7974245bec9ac94cd9ea Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Mon, 19 Jan 2015 11:41:41 +0100 Subject: ASoC: samsung: Remove goni or aquila with the WM8994 Commit 28c8331d386a ("ARM: S5PV210: Remove support for board files") removed the Kconfig symbols MACH_GONI and MACH_AQUILA. As a result the dependencies of SND_SOC_GONI_AQUILA_WM8994 can never be met. So remove the unbuildable "SoC I2S Audio support for AQUILA/GONI - WM8994". Signed-off-by: Paul Bolle Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 11 -- sound/soc/samsung/Makefile | 2 - sound/soc/samsung/goni_wm8994.c | 289 ---------------------------------------- 3 files changed, 302 deletions(-) delete mode 100644 sound/soc/samsung/goni_wm8994.c (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index e817a2f43ea8..3cebf6ca03df 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -146,17 +146,6 @@ config SND_SOC_SMARTQ select SND_SAMSUNG_I2S select SND_SOC_WM8750 -config SND_SOC_GONI_AQUILA_WM8994 - tristate "SoC I2S Audio support for AQUILA/GONI - WM8994" - depends on SND_SOC_SAMSUNG && (MACH_GONI || MACH_AQUILA) - depends on I2C=y - select SND_SAMSUNG_I2S - select MFD_WM8994 - select SND_SOC_WM8994 - help - Say Y if you want to add support for SoC audio on goni or aquila - with the WM8994. - config SND_SOC_SAMSUNG_SMDK_SPDIF tristate "SoC S/PDIF Audio support for SMDK" depends on SND_SOC_SAMSUNG diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 31e3dba7e3b5..052fe71be518 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -35,7 +35,6 @@ snd-soc-smdk-wm8994-objs := smdk_wm8994.o snd-soc-snow-objs := snow.o snd-soc-smdk-wm9713-objs := smdk_wm9713.o snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o -snd-soc-goni-wm8994-objs := goni_wm8994.o snd-soc-smdk-spdif-objs := smdk_spdif.o snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o @@ -63,7 +62,6 @@ obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o -obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c deleted file mode 100644 index fad56b9e7369..000000000000 --- a/sound/soc/samsung/goni_wm8994.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * goni_wm8994.c - * - * Copyright (C) 2010 Samsung Electronics Co.Ltd - * Author: Chanwoo Choi - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include -#include -#include - -#include -#include - -#include "../codecs/wm8994.h" - -#define MACHINE_NAME 0 -#define CPU_VOICE_DAI 1 - -static const char *aquila_str[] = { - [MACHINE_NAME] = "aquila", - [CPU_VOICE_DAI] = "aquila-voice-dai", -}; - -static struct snd_soc_card goni; -static struct platform_device *goni_snd_device; - -/* 3.5 pie jack */ -static struct snd_soc_jack jack; - -/* 3.5 pie jack detection DAPM pins */ -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, { - .pin = "Headset Stereophone", - .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL | - SND_JACK_AVOUT, - }, -}; - -/* 3.5 pie jack detection gpios */ -static struct snd_soc_jack_gpio jack_gpios[] = { - { - .gpio = S5PV210_GPH0(6), - .name = "DET_3.5", - .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_AVOUT, - .debounce_time = 200, - }, -}; - -static const struct snd_soc_dapm_widget goni_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Ext Left Spk", NULL), - SND_SOC_DAPM_SPK("Ext Right Spk", NULL), - SND_SOC_DAPM_SPK("Ext Rcv", NULL), - SND_SOC_DAPM_HP("Headset Stereophone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Main Mic", NULL), - SND_SOC_DAPM_MIC("2nd Mic", NULL), - SND_SOC_DAPM_LINE("Radio In", NULL), -}; - -static const struct snd_soc_dapm_route goni_dapm_routes[] = { - {"Ext Left Spk", NULL, "SPKOUTLP"}, - {"Ext Left Spk", NULL, "SPKOUTLN"}, - - {"Ext Right Spk", NULL, "SPKOUTRP"}, - {"Ext Right Spk", NULL, "SPKOUTRN"}, - - {"Ext Rcv", NULL, "HPOUT2N"}, - {"Ext Rcv", NULL, "HPOUT2P"}, - - {"Headset Stereophone", NULL, "HPOUT1L"}, - {"Headset Stereophone", NULL, "HPOUT1R"}, - - {"IN1RN", NULL, "Headset Mic"}, - {"IN1RP", NULL, "Headset Mic"}, - - {"IN1RN", NULL, "2nd Mic"}, - {"IN1RP", NULL, "2nd Mic"}, - - {"IN1LN", NULL, "Main Mic"}, - {"IN1LP", NULL, "Main Mic"}, - - {"IN2LN", NULL, "Radio In"}, - {"IN2RN", NULL, "Radio In"}, -}; - -static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; - - /* set endpoints to not connected */ - snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN"); - snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); - snd_soc_dapm_nc_pin(dapm, "LINEOUT1N"); - snd_soc_dapm_nc_pin(dapm, "LINEOUT1P"); - snd_soc_dapm_nc_pin(dapm, "LINEOUT2N"); - snd_soc_dapm_nc_pin(dapm, "LINEOUT2P"); - - if (machine_is_aquila()) { - snd_soc_dapm_nc_pin(dapm, "SPKOUTRN"); - snd_soc_dapm_nc_pin(dapm, "SPKOUTRP"); - } - - /* Headset jack detection */ - ret = snd_soc_jack_new(codec, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT, - &jack); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins); - if (ret) - return ret; - - ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios); - if (ret) - return ret; - - return 0; -} - -static int goni_hifi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - unsigned int pll_out = 24000000; - int ret = 0; - - /* set the codec FLL */ - ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out, - params_rate(params) * 256); - if (ret < 0) - return ret; - - /* set the codec system clock */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, - params_rate(params) * 256, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops goni_hifi_ops = { - .hw_params = goni_hifi_hw_params, -}; - -static int goni_voice_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - unsigned int pll_out = 24000000; - int ret = 0; - - if (params_rate(params) != 8000) - return -EINVAL; - - /* set the codec FLL */ - ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out, - params_rate(params) * 256); - if (ret < 0) - return ret; - - /* set the codec system clock */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2, - params_rate(params) * 256, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_dai_driver voice_dai = { - .name = "goni-voice-dai", - .id = 0, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, -}; - -static const struct snd_soc_component_driver voice_component = { - .name = "goni-voice", -}; - -static struct snd_soc_ops goni_voice_ops = { - .hw_params = goni_voice_hw_params, -}; - -static struct snd_soc_dai_link goni_dai[] = { -{ - .name = "WM8994", - .stream_name = "WM8994 HiFi", - .cpu_dai_name = "samsung-i2s.0", - .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-i2s.0", - .codec_name = "wm8994-codec.0-001a", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, - .init = goni_wm8994_init, - .ops = &goni_hifi_ops, -}, { - .name = "WM8994 Voice", - .stream_name = "Voice", - .cpu_dai_name = "goni-voice-dai", - .codec_dai_name = "wm8994-aif2", - .codec_name = "wm8994-codec.0-001a", - .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_IB_IF | - SND_SOC_DAIFMT_CBM_CFM, - .ops = &goni_voice_ops, -}, -}; - -static struct snd_soc_card goni = { - .name = "goni", - .owner = THIS_MODULE, - .dai_link = goni_dai, - .num_links = ARRAY_SIZE(goni_dai), - - .dapm_widgets = goni_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(goni_dapm_widgets), - .dapm_routes = goni_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(goni_dapm_routes), -}; - -static int __init goni_init(void) -{ - int ret; - - if (machine_is_aquila()) { - voice_dai.name = aquila_str[CPU_VOICE_DAI]; - goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI]; - goni.name = aquila_str[MACHINE_NAME]; - } else if (!machine_is_goni()) - return -ENODEV; - - goni_snd_device = platform_device_alloc("soc-audio", -1); - if (!goni_snd_device) - return -ENOMEM; - - /* register voice DAI here */ - ret = devm_snd_soc_register_component(&goni_snd_device->dev, - &voice_component, &voice_dai, 1); - if (ret) { - platform_device_put(goni_snd_device); - return ret; - } - - platform_set_drvdata(goni_snd_device, &goni); - ret = platform_device_add(goni_snd_device); - - if (ret) - platform_device_put(goni_snd_device); - - return ret; -} - -static void __exit goni_exit(void) -{ - platform_device_unregister(goni_snd_device); -} - -module_init(goni_init); -module_exit(goni_exit); - -/* Module information */ -MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)"); -MODULE_AUTHOR("Chanwoo Choi "); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 92b133f251b5f914f3ed28bc83e5b7a40d4e22ed Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 9 Feb 2015 14:41:50 +0800 Subject: ASoC: rt5670: Set use_single_rw flag for regmap RT5670 doesn't support auto incrementing writes so driver should set the use_single_rw flag for regmap. Signed-off-by: Bard Liao Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/rt5670.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0632b7458a53..6aa4ab24288e 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2614,6 +2614,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = { static const struct regmap_config rt5670_regmap = { .reg_bits = 8, .val_bits = 16, + .use_single_rw = true, .max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) * RT5670_PR_SPACING), .volatile_reg = rt5670_volatile_register, -- cgit v1.2.3