From 154bab12e1db824ad12ffd6df2d213dfb3d09878 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Thu, 24 Oct 2013 14:13:48 +0200 Subject: [PATCH 01/29] ASoC: eukrea-tlv320: Use dev_err instead of pr_err. It also contains a minor style cleanup. Signed-off-by: Denis Carikli Signed-off-by: Mark Brown --- sound/soc/fsl/eukrea-tlv320.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 9a4a0ca2c1de..5983740be123 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -42,7 +42,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret) { - pr_err("%s: failed set cpu dai format\n", __func__); + dev_err(cpu_dai->dev, + "Failed to set the cpu dai format.\n"); return ret; } @@ -50,14 +51,16 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret) { - pr_err("%s: failed set codec dai format\n", __func__); + dev_err(cpu_dai->dev, + "Failed to set the codec format.\n"); return ret; } ret = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_OUT); if (ret) { - pr_err("%s: failed setting codec sysclk\n", __func__); + dev_err(cpu_dai->dev, + "Failed to set the codec sysclk.\n"); return ret; } snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); @@ -65,7 +68,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN); if (ret) { - pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n"); + dev_err(cpu_dai->dev, + "Can't set the IMX_SSP_SYS_CLK CPU system clock.\n"); return ret; } @@ -155,7 +159,8 @@ static struct platform_driver eukrea_tlv320_driver = { .owner = THIS_MODULE, }, .probe = eukrea_tlv320_probe, - .remove = eukrea_tlv320_remove,}; + .remove = eukrea_tlv320_remove, +}; module_platform_driver(eukrea_tlv320_driver); From 99d8d3ba512810feb13e158042975dcda75cef31 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Thu, 24 Oct 2013 17:55:18 +0200 Subject: [PATCH 02/29] ASoC: kirkwood: Fix compile error due to patch 'add S/PDIF support' This patch fixes the compilation error of kirkwood-i2s.c introduced by the commit 75b9b65ee5a80e99e 'ASoC: kirkwood: add S/PDIF support'. Signed-off-by: Jean-Francois Moine Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 9ec38d15df9e..d34d91743e3f 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -568,7 +568,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) } else { dev_info(&pdev->dev, "found external clock\n"); clk_prepare_enable(priv->extclk); - soc_dai = &kirkwood_i2s_dai_extclk; + soc_dai = kirkwood_i2s_dai_extclk; } } From 29ca9c73e54131c9ad90c5381f368d9b09b5aca4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 25 Oct 2013 17:06:24 +0800 Subject: [PATCH 03/29] ASoC: samsung: fix return value check in i2s_alloc_dai() In case of error, the function platform_device_alloc() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 32956df8f50c..2e031fa729f0 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1073,7 +1073,7 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) dev_set_drvdata(&i2s->pdev->dev, i2s); } else { /* Create a new platform_device for Secondary */ i2s->pdev = platform_device_alloc("samsung-i2s-sec", -1); - if (IS_ERR(i2s->pdev)) + if (!i2s->pdev) return NULL; i2s->pdev->dev.parent = &pdev->dev; From 6dd17757927ba9d23c604fee6fe72b4755c7ea7f Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Fri, 25 Oct 2013 10:01:14 -0500 Subject: [PATCH 04/29] ASoC: cs42l52: Add platform data for reset gpio This patch adds platform data support for a reset GPIO. Also uses reset_gpio to toggle reset of the CODEC Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- include/sound/cs42l52.h | 2 ++ sound/soc/codecs/cs42l52.c | 21 +++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/include/sound/cs42l52.h b/include/sound/cs42l52.h index 4c68955f7330..7c2be4a51894 100644 --- a/include/sound/cs42l52.h +++ b/include/sound/cs42l52.h @@ -31,6 +31,8 @@ struct cs42l52_platform_data { /* Charge Pump Freq. Check datasheet Pg73 */ unsigned int chgfreq; + /* Reset GPIO */ + unsigned int reset_gpio; }; #endif /* __CS42L52_H */ diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index be2ba1b6fe4a..8367f3c571eb 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1205,6 +1206,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs42l52_private *cs42l52; + struct cs42l52_platform_data *pdata = dev_get_platdata(&i2c_client->dev); int ret; unsigned int devid = 0; unsigned int reg; @@ -1222,11 +1224,22 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, return ret; } - i2c_set_clientdata(i2c_client, cs42l52); + if (pdata) + cs42l52->pdata = *pdata; - if (dev_get_platdata(&i2c_client->dev)) - memcpy(&cs42l52->pdata, dev_get_platdata(&i2c_client->dev), - sizeof(cs42l52->pdata)); + if (cs42l52->pdata.reset_gpio) { + ret = gpio_request_one(cs42l52->pdata.reset_gpio, + GPIOF_OUT_INIT_HIGH, "CS42L52 /RST"); + if (ret < 0) { + dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n", + cs42l52->pdata.reset_gpio, ret); + return ret; + } + gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 0); + gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 1); + } + + i2c_set_clientdata(i2c_client, cs42l52); ret = regmap_register_patch(cs42l52->regmap, cs42l52_threshold_patch, ARRAY_SIZE(cs42l52_threshold_patch)); From 153723f6f1d13e7b9541b425ebdbaead4cc85346 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Fri, 25 Oct 2013 10:01:16 -0500 Subject: [PATCH 05/29] ASoC: cs42l52: convert pdata config to regmap_update_bits Moving platform data to bus probe and convert to regmap_update_bits. This will work nicer when converted to device tree instead of having it split into multiple probes Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 69 +++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 8367f3c571eb..56c5611fa752 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1117,40 +1117,6 @@ static int cs42l52_probe(struct snd_soc_codec *codec) cs42l52->sysclk = CS42L52_DEFAULT_CLK; cs42l52->config.format = CS42L52_DEFAULT_FORMAT; - /* Set Platform MICx CFG */ - snd_soc_update_bits(codec, CS42L52_MICA_CTL, - CS42L52_MIC_CTL_TYPE_MASK, - cs42l52->pdata.mica_cfg << - CS42L52_MIC_CTL_TYPE_SHIFT); - - snd_soc_update_bits(codec, CS42L52_MICB_CTL, - CS42L52_MIC_CTL_TYPE_MASK, - cs42l52->pdata.micb_cfg << - CS42L52_MIC_CTL_TYPE_SHIFT); - - /* if Single Ended, Get Mic_Select */ - if (cs42l52->pdata.mica_cfg) - snd_soc_update_bits(codec, CS42L52_MICA_CTL, - CS42L52_MIC_CTL_MIC_SEL_MASK, - cs42l52->pdata.mica_sel << - CS42L52_MIC_CTL_MIC_SEL_SHIFT); - if (cs42l52->pdata.micb_cfg) - snd_soc_update_bits(codec, CS42L52_MICB_CTL, - CS42L52_MIC_CTL_MIC_SEL_MASK, - cs42l52->pdata.micb_sel << - CS42L52_MIC_CTL_MIC_SEL_SHIFT); - - /* Set Platform Charge Pump Freq */ - snd_soc_update_bits(codec, CS42L52_CHARGE_PUMP, - CS42L52_CHARGE_PUMP_MASK, - cs42l52->pdata.chgfreq << - CS42L52_CHARGE_PUMP_SHIFT); - - /* Set Platform Bias Level */ - snd_soc_update_bits(codec, CS42L52_IFACE_CTL2, - CS42L52_IFACE_CTL2_BIAS_LVL, - cs42l52->pdata.micbias_lvl); - return ret; } @@ -1257,7 +1223,40 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, return ret; } - regcache_cache_only(cs42l52->regmap, true); + /* Set Platform Data */ + if (cs42l52->pdata.mica_cfg) + regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL, + CS42L52_MIC_CTL_TYPE_MASK, + cs42l52->pdata.mica_cfg << + CS42L52_MIC_CTL_TYPE_SHIFT); + + if (cs42l52->pdata.micb_cfg) + regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL, + CS42L52_MIC_CTL_TYPE_MASK, + cs42l52->pdata.micb_cfg << + CS42L52_MIC_CTL_TYPE_SHIFT); + + if (cs42l52->pdata.mica_sel) + regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL, + CS42L52_MIC_CTL_MIC_SEL_MASK, + cs42l52->pdata.mica_sel << + CS42L52_MIC_CTL_MIC_SEL_SHIFT); + if (cs42l52->pdata.micb_sel) + regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL, + CS42L52_MIC_CTL_MIC_SEL_MASK, + cs42l52->pdata.micb_sel << + CS42L52_MIC_CTL_MIC_SEL_SHIFT); + + if (cs42l52->pdata.chgfreq) + regmap_update_bits(cs42l52->regmap, CS42L52_CHARGE_PUMP, + CS42L52_CHARGE_PUMP_MASK, + cs42l52->pdata.chgfreq << + CS42L52_CHARGE_PUMP_SHIFT); + + if (cs42l52->pdata.micbias_lvl) + regmap_update_bits(cs42l52->regmap, CS42L52_IFACE_CTL2, + CS42L52_IFACE_CTL2_BIAS_LVL, + cs42l52->pdata.micbias_lvl); ret = snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_cs42l52, &cs42l52_dai, 1); From e5f03af644c46b8713ddf5df545a32c1af8557ed Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Fri, 25 Oct 2013 10:01:17 -0500 Subject: [PATCH 06/29] ASoC: cs42l52: Add chip rev id message This patch adds a print message at bootup for the CODEC Rev ID Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 56c5611fa752..8b427c977083 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1223,6 +1223,9 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, return ret; } + dev_info(&i2c_client->dev, "Cirrus Logic CS42L52, Revision: %02X\n", + reg & 0xFF); + /* Set Platform Data */ if (cs42l52->pdata.mica_cfg) regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL, From aab554ede931eddaca2e9b38c12489ae3f83fbe3 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Fri, 25 Oct 2013 10:01:15 -0500 Subject: [PATCH 07/29] ASoC: cs42l52: increase MAX_REGISTER for regmap_register_patch regmap_register_patch fails without the MAX_REGISTER set to highest register written to. Increase to register 0x47 Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l52.h b/sound/soc/codecs/cs42l52.h index 4277012c4719..1a9412d86d17 100644 --- a/sound/soc/codecs/cs42l52.h +++ b/sound/soc/codecs/cs42l52.h @@ -269,6 +269,6 @@ #define CS42L52_FIX_BITS1 0x3E #define CS42L52_FIX_BITS2 0x47 -#define CS42L52_MAX_REGISTER 0x34 +#define CS42L52_MAX_REGISTER 0x47 #endif From a9c9cafdde46d06a28f92e3a68b5534fa268e92d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Sat, 26 Oct 2013 15:31:26 +0100 Subject: [PATCH 08/29] ASoC: wm5110: Add missing routes for AEC Loopback Reported-by: Nariman Poushin Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index bbd64384ca1c..8c91be5d67e3 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -983,24 +983,36 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"), ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"), + { "AEC Loopback", "HPOUT1L", "OUT1L" }, + { "AEC Loopback", "HPOUT1R", "OUT1R" }, { "HPOUT1L", NULL, "OUT1L" }, { "HPOUT1R", NULL, "OUT1R" }, + { "AEC Loopback", "HPOUT2L", "OUT2L" }, + { "AEC Loopback", "HPOUT2R", "OUT2R" }, { "HPOUT2L", NULL, "OUT2L" }, { "HPOUT2R", NULL, "OUT2R" }, + { "AEC Loopback", "HPOUT3L", "OUT3L" }, + { "AEC Loopback", "HPOUT3R", "OUT3R" }, { "HPOUT3L", NULL, "OUT3L" }, { "HPOUT3R", NULL, "OUT3L" }, + { "AEC Loopback", "SPKOUTL", "OUT4L" }, { "SPKOUTLN", NULL, "OUT4L" }, { "SPKOUTLP", NULL, "OUT4L" }, + { "AEC Loopback", "SPKOUTR", "OUT4R" }, { "SPKOUTRN", NULL, "OUT4R" }, { "SPKOUTRP", NULL, "OUT4R" }, + { "AEC Loopback", "SPKDAT1L", "OUT5L" }, + { "AEC Loopback", "SPKDAT1R", "OUT5R" }, { "SPKDAT1L", NULL, "OUT5L" }, { "SPKDAT1R", NULL, "OUT5R" }, + { "AEC Loopback", "SPKDAT2L", "OUT6L" }, + { "AEC Loopback", "SPKDAT2R", "OUT6R" }, { "SPKDAT2L", NULL, "OUT6L" }, { "SPKDAT2R", NULL, "OUT6R" }, From 3d8f7318f929f3b84571ffac2ef7bf8bddfb6d41 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 25 Oct 2013 17:29:25 +0800 Subject: [PATCH 09/29] ASoC: fsl_spdif: fix return value check in fsl_spdif_probe() In case of error, the function platform_get_resource() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index c0fea02114e1..e1bf5ef31bdd 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1107,9 +1107,9 @@ static int fsl_spdif_probe(struct platform_device *pdev) /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (IS_ERR(res)) { + if (!res) { dev_err(&pdev->dev, "could not determine device resources\n"); - return PTR_ERR(res); + return -ENXIO; } regs = devm_ioremap_resource(&pdev->dev, res); From b5ef3f2a8074af7aef9a32f4535c57f986364a60 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 29 Oct 2013 17:06:27 +0800 Subject: [PATCH 10/29] ASoC: wm8962: Fix null pointer pdata access in I2C probe() When using DT binding to pass private data, there would be Kernel panic occuring due to NULL pointer access in wm8962_i2c_probe(). Thus fix it. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 2bf9ee7c5407..7dd79c4efc13 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3616,28 +3616,28 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, 0); /* Apply static configuration for GPIOs */ - for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) - if (pdata->gpio_init[i]) { + for (i = 0; i < ARRAY_SIZE(wm8962->pdata.gpio_init); i++) + if (wm8962->pdata.gpio_init[i]) { wm8962_set_gpio_mode(wm8962, i + 1); regmap_write(wm8962->regmap, 0x200 + i, - pdata->gpio_init[i] & 0xffff); + wm8962->pdata.gpio_init[i] & 0xffff); } /* Put the speakers into mono mode? */ - if (pdata->spk_mono) + if (wm8962->pdata.spk_mono) regmap_update_bits(wm8962->regmap, WM8962_CLASS_D_CONTROL_2, WM8962_SPK_MONO_MASK, WM8962_SPK_MONO); /* Micbias setup, detection enable and detection * threasholds. */ - if (pdata->mic_cfg) + if (wm8962->pdata.mic_cfg) regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4, WM8962_MICDET_ENA | WM8962_MICDET_THR_MASK | WM8962_MICSHORT_THR_MASK | WM8962_MICBIAS_LVL, - pdata->mic_cfg); + wm8962->pdata.mic_cfg); /* Latch volume update bits */ regmap_update_bits(wm8962->regmap, WM8962_LEFT_INPUT_VOLUME, @@ -3682,7 +3682,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, } if (wm8962->irq) { - if (pdata->irq_active_low) { + if (wm8962->pdata.irq_active_low) { trigger = IRQF_TRIGGER_LOW; irq_pol = WM8962_IRQ_POL; } else { From 00ecdd93a80fda1336bf5413b1d705c742a5b598 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Oct 2013 08:34:59 +0100 Subject: [PATCH 11/29] ASoC: ab8500: Add missing of NULL check of devm_kzalloc() Spotted by coverity CID 712316. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 7f6ca111659b..10be4cbfe969 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2570,6 +2570,8 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) /* Create driver private-data struct */ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_codec_drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; drvdata->sid_status = SID_UNCONFIGURED; drvdata->anc_status = ANC_UNCONFIGURED; dev_set_drvdata(&pdev->dev, drvdata); From 166a34d27fcad1eeb0322cff23939a1910f8a77c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Oct 2013 08:35:01 +0100 Subject: [PATCH 12/29] ASoC: ab8500: Fix invalid cast to long pointer Don't cast to long pointers blindly just for using find_first_bit() and co. This is certainly not portable at all. Reimplement the code with ffs() and fls() instead. This is a slight optimization, too. Spotted by coverity CID 1056484 and 1056485. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 10be4cbfe969..3ef481551740 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2295,17 +2295,17 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, case 0: break; case 1: - slot = find_first_bit((unsigned long *)&tx_mask, 32); + slot = ffs(tx_mask); snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot); snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot); snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot); snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot); break; case 2: - slot = find_first_bit((unsigned long *)&tx_mask, 32); + slot = ffs(tx_mask); snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot); snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot); - slot = find_next_bit((unsigned long *)&tx_mask, 32, slot + 1); + slot = fls(tx_mask); snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot); snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot); break; @@ -2336,18 +2336,18 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, case 0: break; case 1: - slot = find_first_bit((unsigned long *)&rx_mask, 32); + slot = ffs(rx_mask); snd_soc_update_bits(codec, AB8500_ADSLOTSEL(slot), AB8500_MASK_SLOT(slot), AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot)); break; case 2: - slot = find_first_bit((unsigned long *)&rx_mask, 32); + slot = ffs(rx_mask); snd_soc_update_bits(codec, AB8500_ADSLOTSEL(slot), AB8500_MASK_SLOT(slot), AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot)); - slot = find_next_bit((unsigned long *)&rx_mask, 32, slot + 1); + slot = fls(rx_mask); snd_soc_update_bits(codec, AB8500_ADSLOTSEL(slot), AB8500_MASK_SLOT(slot), From c36c89096cb9f95fbdb0a6f3d80d4b9a50537ed3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Oct 2013 08:35:03 +0100 Subject: [PATCH 13/29] ASoC: wm0010: Fix possible out-of-bounds array read Spotted by coverity CID 744701. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/wm0010.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index d5ebcb00019b..bf7804a12863 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -793,11 +793,11 @@ static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source, wm0010->max_spi_freq = 0; } else { for (i = 0; i < ARRAY_SIZE(pll_clock_map); i++) - if (freq >= pll_clock_map[i].max_sysclk) + if (freq >= pll_clock_map[i].max_sysclk) { + wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed; + wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1; break; - - wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed; - wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1; + } } return 0; From fe329a1a92cfe2d0c7e04fe3bc63761dc0f35950 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Oct 2013 08:35:07 +0100 Subject: [PATCH 14/29] ASoC: wm8996: Fix negative array index read Spotted by coverity CID 146355. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/wm8996.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 46fe83d2b224..b70379ebd142 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -438,6 +438,8 @@ static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); int block = wm8996_get_retune_mobile_block(kcontrol->id.name); + if (block < 0) + return block; ucontrol->value.enumerated.item[0] = wm8996->retune_mobile_cfg[block]; return 0; From 5a7615cf1fcaaf1598b5689e54915d88c2344788 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Oct 2013 08:35:06 +0100 Subject: [PATCH 15/29] ASoC: rt5640: Fix ignored error checks The negative error value returned from get_sdp_info() is ignored because it's assigned to unsigned variables. Spotted by coverity CIDs 1042657, 1042658. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 4d041d376f31..a3fb41179636 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1604,8 +1604,8 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); - unsigned int val_len = 0, val_clk, mask_clk, dai_sel; - int pre_div, bclk_ms, frame_size; + unsigned int val_len = 0, val_clk, mask_clk; + int dai_sel, pre_div, bclk_ms, frame_size; rt5640->lrck[dai->id] = params_rate(params); pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]); @@ -1675,7 +1675,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_codec *codec = dai->codec; struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); - unsigned int reg_val = 0, dai_sel; + unsigned int reg_val = 0; + int dai_sel; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: From 8b4b30365ce6cefe4193f439ac7263bb2cdd66fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Oct 2013 18:40:04 +0100 Subject: [PATCH 16/29] ASoC: ml26124: Fix negative array index read get_coeff() may return an error. Spotted by coverity CID 703394. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/ml26124.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 26118828782b..185fa3bc3052 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -342,6 +342,8 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream, struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec); int i = get_coeff(priv->mclk, params_rate(hw_params)); + if (i < 0) + return i; priv->substream = substream; priv->rate = params_rate(hw_params); From 9ade09d6c62e48fba6c74ce3958ca1035dfd8427 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 29 Oct 2013 00:52:19 -0700 Subject: [PATCH 17/29] ASoC: rcar: remove original filter from rsnd_dma_init() Remove original filter from rsnd_dma_init(), and use SH-DMA suitable filter. This new style can be used from Device Tree. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index b234ed663073..78c35b44fc04 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -94,6 +94,7 @@ * */ #include +#include #include "rsnd.h" #define RSND_RATES SNDRV_PCM_RATE_8000_96000 @@ -209,13 +210,6 @@ int rsnd_dma_available(struct rsnd_dma *dma) return !!dma->chan; } -static bool rsnd_dma_filter(struct dma_chan *chan, void *param) -{ - chan->private = param; - - return true; -} - int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int is_play, int id, int (*inquiry)(struct rsnd_dma *dma, @@ -223,7 +217,9 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int (*complete)(struct rsnd_dma *dma)) { struct device *dev = rsnd_priv_to_dev(priv); + struct dma_slave_config cfg; dma_cap_mask_t mask; + int ret; if (dma->chan) { dev_err(dev, "it already has dma channel\n"); @@ -233,15 +229,23 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - dma->slave.shdma_slave.slave_id = id; - - dma->chan = dma_request_channel(mask, rsnd_dma_filter, - &dma->slave.shdma_slave); + dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, + (void *)id, dev, + is_play ? "tx" : "rx"); if (!dma->chan) { dev_err(dev, "can't get dma channel\n"); return -EIO; } + cfg.slave_id = id; + cfg.dst_addr = 0; /* use default addr when playback */ + cfg.src_addr = 0; /* use default addr when capture */ + cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + + ret = dmaengine_slave_config(dma->chan, &cfg); + if (ret < 0) + goto rsnd_dma_init_err; + dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; dma->priv = priv; dma->inquiry = inquiry; @@ -249,6 +253,11 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, INIT_WORK(&dma->work, rsnd_dma_do_work); return 0; + +rsnd_dma_init_err: + rsnd_dma_quit(priv, dma); + + return ret; } void rsnd_dma_quit(struct rsnd_priv *priv, From a19685cb72bb6a80ac453e76b3ab3bb7770e1742 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Oct 2013 14:21:46 +0100 Subject: [PATCH 18/29] ASoC: Use strlcpy() for copying in snd_soc_info_enum_double() The provided texts aren't guaranteed to be in the fixed size. Spotted by coverity CID 139318. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0860a7f11299..b38e0ee622df 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2552,8 +2552,9 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item > e->max - 1) uinfo->value.enumerated.item = e->max - 1; - strcpy(uinfo->value.enumerated.name, - e->texts[uinfo->value.enumerated.item]); + strlcpy(uinfo->value.enumerated.name, + e->texts[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)); return 0; } EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); From c5914b0aaea6494aaa9e415cbd32f8b7eb604af0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 Oct 2013 17:47:39 -0700 Subject: [PATCH 19/29] ASoC: pcm: Check for ops before deferencing them Ensure that we always check that an ops structure is present before we try to use it, improving the robustness of the system. Reported-by: Russell King Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d4498723b375..d81b79251760 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -190,7 +190,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); /* startup the audio subsystem */ - if (cpu_dai->driver->ops->startup) { + if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) { ret = cpu_dai->driver->ops->startup(substream, cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "ASoC: can't open interface" @@ -208,7 +208,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } - if (codec_dai->driver->ops->startup) { + if (codec_dai->driver->ops && codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai); if (ret < 0) { dev_err(codec_dai->dev, "ASoC: can't open codec" @@ -463,7 +463,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - if (codec_dai->driver->ops->prepare) { + if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); if (ret < 0) { dev_err(codec_dai->dev, "ASoC: DAI prepare error: %d\n", @@ -472,7 +472,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - if (cpu_dai->driver->ops->prepare) { + if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) { ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "ASoC: DAI prepare error: %d\n", @@ -523,7 +523,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - if (codec_dai->driver->ops->hw_params) { + if (codec_dai->driver->ops && codec_dai->driver->ops->hw_params) { ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); if (ret < 0) { dev_err(codec_dai->dev, "ASoC: can't set %s hw params:" @@ -532,7 +532,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - if (cpu_dai->driver->ops->hw_params) { + if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_params) { ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "ASoC: %s hw params failed: %d\n", @@ -559,11 +559,11 @@ out: return ret; platform_err: - if (cpu_dai->driver->ops->hw_free) + if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) cpu_dai->driver->ops->hw_free(substream, cpu_dai); interface_err: - if (codec_dai->driver->ops->hw_free) + if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); codec_err: @@ -600,10 +600,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) platform->driver->ops->hw_free(substream); /* now free hw params for the DAIs */ - if (codec_dai->driver->ops->hw_free) + if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); - if (cpu_dai->driver->ops->hw_free) + if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) cpu_dai->driver->ops->hw_free(substream, cpu_dai); mutex_unlock(&rtd->pcm_mutex); @@ -618,7 +618,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret; - if (codec_dai->driver->ops->trigger) { + if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) { ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); if (ret < 0) return ret; @@ -630,7 +630,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } - if (cpu_dai->driver->ops->trigger) { + if (cpu_dai->driver->ops && cpu_dai->driver->ops->trigger) { ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); if (ret < 0) return ret; @@ -647,19 +647,20 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret; - if (codec_dai->driver->ops->bespoke_trigger) { + if (codec_dai->driver->ops && + codec_dai->driver->ops->bespoke_trigger) { ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); if (ret < 0) return ret; } - if (platform->driver->bespoke_trigger) { + if (platform->driver->ops && platform->driver->bespoke_trigger) { ret = platform->driver->bespoke_trigger(substream, cmd); if (ret < 0) return ret; } - if (cpu_dai->driver->ops->bespoke_trigger) { + if (cpu_dai->driver->ops && cpu_dai->driver->ops->bespoke_trigger) { ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); if (ret < 0) return ret; @@ -684,10 +685,10 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) if (platform->driver->ops && platform->driver->ops->pointer) offset = platform->driver->ops->pointer(substream); - if (cpu_dai->driver->ops->delay) + if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay) delay += cpu_dai->driver->ops->delay(substream, cpu_dai); - if (codec_dai->driver->ops->delay) + if (codec_dai->driver->ops && codec_dai->driver->ops->delay) delay += codec_dai->driver->ops->delay(substream, codec_dai); if (platform->driver->delay) @@ -1673,7 +1674,7 @@ static int soc_pcm_ioctl(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; - if (platform->driver->ops->ioctl) + if (platform->driver->ops && platform->driver->ops->ioctl) return platform->driver->ops->ioctl(substream, cmd, arg); return snd_pcm_lib_ioctl(substream, cmd, arg); } @@ -1934,8 +1935,8 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) dev_dbg(be->dev, "ASoC: BE digital mute %s\n", be->dai_link->name); - if (drv->ops->digital_mute && dai->playback_active) - drv->ops->digital_mute(dai, mute); + if (drv->ops && drv->ops->digital_mute && dai->playback_active) + drv->ops->digital_mute(dai, mute); } return 0; @@ -2224,7 +2225,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); int snd_soc_platform_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_platform *platform) { - if (platform->driver->ops->trigger) + if (platform->driver->ops && platform->driver->ops->trigger) return platform->driver->ops->trigger(substream, cmd); return 0; } From 2062b4c5d2d8fa47dc89105464e67a7ba310c9e7 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Thu, 31 Oct 2013 15:09:20 +0000 Subject: [PATCH 20/29] ASoC: dpcm: improve robustness Avoid oopsing if there is no backend stream associated with a front end stream. Signed-off-by: Russell King Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d81b79251760..591f0f3074c5 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1038,6 +1038,12 @@ static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); + if (!be_substream) { + dev_err(be->dev, "ASoC: no backend %s stream\n", + stream ? "capture" : "playback"); + continue; + } + /* is this op for this BE ? */ if (!snd_soc_dpcm_be_can_update(fe, be, stream)) continue; @@ -1055,7 +1061,8 @@ static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) continue; - dev_dbg(be->dev, "ASoC: open BE %s\n", be->dai_link->name); + dev_dbg(be->dev, "ASoC: open %s BE %s\n", + stream ? "capture" : "playback", be->dai_link->name); be_substream->runtime = be->dpcm[stream].runtime; err = soc_pcm_open(be_substream); From 7b5bfb82882b9b1c8423ce0ed6852ca3762d967a Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Thu, 31 Oct 2013 23:06:17 -0700 Subject: [PATCH 21/29] ASoC: ak4642: prevent un-necessary changes to SG_SL1 If you record the sound during playback, the playback sound becomes silent. Modify so that the codec driver does not clear SG_SL1::DACL bit which is controlled under widget Signed-off-by: Phil Edworthy Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/ak4642.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 2d0378709702..687565d08d9c 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -257,7 +257,7 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, * This operation came from example code of * "ASAHI KASEI AK4642" (japanese) manual p94. */ - snd_soc_write(codec, SG_SL1, PMMP | MGAIN0); + snd_soc_update_bits(codec, SG_SL1, PMMP | MGAIN0, PMMP | MGAIN0); snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3)); snd_soc_write(codec, ALC_CTL1, ALC | LMTH0); snd_soc_update_bits(codec, PW_MGMT1, PMADL, PMADL); From 43bc3bf64b30cdfdffdc41e33bf21222e9396c42 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Fri, 1 Nov 2013 15:56:52 +0000 Subject: [PATCH 22/29] ASoC: wm_adsp: Print error when regmap reads/writes fail Signed-off-by: Dimitris Papastamos Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b38f3506418f..076da025ba84 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -396,8 +396,8 @@ static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, ret = regmap_raw_write(adsp->regmap, reg, scratch, ctl->len); if (ret) { - adsp_err(adsp, "Failed to write %zu bytes to %x\n", - ctl->len, reg); + adsp_err(adsp, "Failed to write %zu bytes to %x: %d\n", + ctl->len, reg, ret); kfree(scratch); return ret; } @@ -450,8 +450,8 @@ static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len); if (ret) { - adsp_err(adsp, "Failed to read %zu bytes from %x\n", - ctl->len, reg); + adsp_err(adsp, "Failed to read %zu bytes from %x: %d\n", + ctl->len, reg, ret); kfree(scratch); return ret; } @@ -1313,8 +1313,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) le32_to_cpu(blk->len)); if (ret != 0) { adsp_err(dsp, - "%s.%d: Failed to write to %x in %s\n", - file, blocks, reg, region_name); + "%s.%d: Failed to write to %x in %s: %d\n", + file, blocks, reg, region_name, ret); } } From 7328823d0052bbdb15af162f9f510ced811bdfe8 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Fri, 1 Nov 2013 15:56:53 +0000 Subject: [PATCH 23/29] ASoC: wm_adsp: Release firmware on memory allocation failure Signed-off-by: Dimitris Papastamos Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 076da025ba84..4008ceb77c5b 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -689,7 +689,8 @@ static int wm_adsp_load(struct wm_adsp *dsp) &buf_list); if (!buf) { adsp_err(dsp, "Out of memory\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out_fw; } ret = regmap_raw_write_async(regmap, reg, buf->buf, From 562c5e6f52bc9ed48b8dc9cef97923b64bd843ec Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Fri, 1 Nov 2013 15:56:55 +0000 Subject: [PATCH 24/29] ASoC: wm_adsp: Add debug info on get()/put() transfers Signed-off-by: Dimitris Papastamos Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 4008ceb77c5b..1f1fc0dd716e 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -401,6 +401,7 @@ static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, kfree(scratch); return ret; } + adsp_dbg(adsp, "Wrote %zu bytes to %x\n", ctl->len, reg); kfree(scratch); @@ -455,6 +456,7 @@ static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, kfree(scratch); return ret; } + adsp_dbg(adsp, "Read %zu bytes from %x\n", ctl->len, reg); memcpy(buf, scratch, ctl->len); kfree(scratch); From b0101b4f14d591719f53f7f38ede3651113e6a53 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Fri, 1 Nov 2013 15:56:56 +0000 Subject: [PATCH 25/29] ASoC: wm_adsp: Remove and free algorithm regions for ADSP1 Do it in a similar fashion as we do for ADSP2. Signed-off-by: Dimitris Papastamos Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 1f1fc0dd716e..cc3575b5783f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1361,6 +1361,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = w->codec; struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; + struct wm_adsp_alg_region *alg_region; struct wm_coeff_ctl *ctl; int ret; int val; @@ -1438,6 +1439,14 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, list_for_each_entry(ctl, &dsp->ctl_list, list) ctl->enabled = 0; + + while (!list_empty(&dsp->alg_regions)) { + alg_region = list_first_entry(&dsp->alg_regions, + struct wm_adsp_alg_region, + list); + list_del(&alg_region->list); + kfree(alg_region); + } break; default: From 3626992a21610fa19534d392bb0e79cc55a99c9a Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Fri, 1 Nov 2013 15:56:57 +0000 Subject: [PATCH 26/29] ASoC: wm_adsp: Print out the firmware version Signed-off-by: Dimitris Papastamos Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index cc3575b5783f..53b6033658a6 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -570,6 +570,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) file, header->ver); goto out_fw; } + adsp_info(dsp, "Firmware version: %d\n", header->ver); if (header->core != dsp->type) { adsp_err(dsp, "%s: invalid core %d != %d\n", From dea0c74ff9e0d85d07b694e261aa7bda2c314ce8 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 1 Nov 2013 10:02:10 +0000 Subject: [PATCH 27/29] ASoC: wm8962: Add ALC coefficient support Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 7dd79c4efc13..028686fd3eb9 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1775,6 +1775,11 @@ WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT), SND_SOC_BYTES("HPF Coefficients", WM8962_LHPF2, 1), WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT), SND_SOC_BYTES("HD Bass Coefficients", WM8962_HDBASS_AI_1, 30), + +SOC_DOUBLE("ALC Switch", WM8962_ALC1, WM8962_ALCL_ENA_SHIFT, + WM8962_ALCR_ENA_SHIFT, 1, 0), +SND_SOC_BYTES_MASK("ALC Coefficients", WM8962_ALC1, 4, + WM8962_ALCL_ENA_MASK | WM8962_ALCR_ENA_MASK), }; static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = { From ae2ff9f6c529ba28adea906037a93fd14e46e052 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 1 Nov 2013 10:02:58 +0000 Subject: [PATCH 28/29] ASoC: wm8962: Add EQ coefficient support Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 028686fd3eb9..3a2f96c5442c 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1758,6 +1758,9 @@ SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23, WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv), SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23, WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv), +SND_SOC_BYTES("EQL Coefficients", WM8962_EQ4, 18), +SND_SOC_BYTES("EQR Coefficients", WM8962_EQ24, 18), + SOC_SINGLE("3D Switch", WM8962_THREED1, 0, 1, 0), SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA), From fc7dc61d9a87011aaf8a6eb3144ebf9552adf5d2 Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Tue, 12 Nov 2013 15:46:38 +0000 Subject: [PATCH 29/29] ASoC: fsl: imx-pcm-fiq: omit fiq counter to avoid harm in unbalanced situations Unbalanced calls to snd_imx_pcm_trigger() may result in endless FIQ activity and thus provoke eternal sound. While on the first glance, the switch statement looks pretty symmetric, the SUSPEND/RESUME pair is not: the suspend case comes along snd_pcm_suspend_all(), which for fsl/imx-pcm-fiq is called only at snd_soc_suspend(), but the resume case originates straight from the SNDRV_PCM_IOCTL_RESUME. This way userland may provoke an unbalanced resume, which might cause the fiq_enable counter to increase and never return to zero again, so eventually imx_pcm_fiq is never disabled. Simply removing the fiq_enable will solve the problem, as long as one never goes play and capture game simultaneously, but beware trying both at once, the early TRIGGER_STOP will cut off the other activity prematurely. So now playing and capturing is scrutinized separately, instead of by counting. Signed-off-by: Oskar Schirmer Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/fsl/imx-pcm-fiq.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 34043c55f2a6..2fc872b2deff 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -44,7 +44,8 @@ struct imx_pcm_runtime_data { struct hrtimer hrt; int poll_time_ns; struct snd_pcm_substream *substream; - atomic_t running; + atomic_t playing; + atomic_t capturing; }; static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) @@ -56,7 +57,7 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) struct pt_regs regs; unsigned long delta; - if (!atomic_read(&iprtd->running)) + if (!atomic_read(&iprtd->playing) && !atomic_read(&iprtd->capturing)) return HRTIMER_NORESTART; get_fiq_regs(®s); @@ -124,7 +125,6 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static int fiq_enable; static int imx_pcm_fiq; static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) @@ -136,23 +136,27 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - atomic_set(&iprtd->running, 1); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + atomic_set(&iprtd->playing, 1); + else + atomic_set(&iprtd->capturing, 1); hrtimer_start(&iprtd->hrt, ns_to_ktime(iprtd->poll_time_ns), HRTIMER_MODE_REL); - if (++fiq_enable == 1) - enable_fiq(imx_pcm_fiq); - + enable_fiq(imx_pcm_fiq); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - atomic_set(&iprtd->running, 0); - - if (--fiq_enable == 0) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + atomic_set(&iprtd->playing, 0); + else + atomic_set(&iprtd->capturing, 0); + if (!atomic_read(&iprtd->playing) && + !atomic_read(&iprtd->capturing)) disable_fiq(imx_pcm_fiq); - break; + default: return -EINVAL; } @@ -200,7 +204,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream) iprtd->substream = substream; - atomic_set(&iprtd->running, 0); + atomic_set(&iprtd->playing, 0); + atomic_set(&iprtd->capturing, 0); hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); iprtd->hrt.function = snd_hrtimer_callback;