diff options
| -rw-r--r-- | sound/soc/atmel/atmel_ssc_dai.c | 4 | ||||
| -rw-r--r-- | sound/soc/au1x/dbdma2.c | 4 | ||||
| -rw-r--r-- | sound/soc/codecs/ak4642.c | 4 | ||||
| -rw-r--r-- | sound/soc/codecs/arizona.c | 32 | ||||
| -rw-r--r-- | sound/soc/codecs/cs47l24.c | 46 | ||||
| -rw-r--r-- | sound/soc/codecs/wm5102.c | 4 | ||||
| -rw-r--r-- | sound/soc/codecs/wm5110.c | 6 | ||||
| -rw-r--r-- | sound/soc/codecs/wm_adsp.c | 292 | ||||
| -rw-r--r-- | sound/soc/codecs/wm_adsp.h | 1 |
9 files changed, 299 insertions, 94 deletions
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 276897033639..1267e1af0fae 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
| @@ -652,7 +652,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
| 652 | rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | 652 | rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) |
| 653 | | SSC_BF(RCMR_STTDLY, 1) | 653 | | SSC_BF(RCMR_STTDLY, 1) |
| 654 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) | 654 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) |
| 655 | | SSC_BF(RCMR_CKI, SSC_CKI_FALLING) | 655 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
| 656 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | 656 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
| 657 | | SSC_BF(RCMR_CKS, SSC_CKS_DIV); | 657 | | SSC_BF(RCMR_CKS, SSC_CKS_DIV); |
| 658 | 658 | ||
| @@ -692,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
| 692 | rcmr = SSC_BF(RCMR_PERIOD, 0) | 692 | rcmr = SSC_BF(RCMR_PERIOD, 0) |
| 693 | | SSC_BF(RCMR_STTDLY, START_DELAY) | 693 | | SSC_BF(RCMR_STTDLY, START_DELAY) |
| 694 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) | 694 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) |
| 695 | | SSC_BF(RCMR_CKI, SSC_CKI_FALLING) | 695 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
| 696 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | 696 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
| 697 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? | 697 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? |
| 698 | SSC_CKS_PIN : SSC_CKS_CLOCK); | 698 | SSC_CKS_PIN : SSC_CKS_CLOCK); |
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 5741c0aa6c03..b5d1caa04d8e 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c | |||
| @@ -206,8 +206,8 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 206 | stype = substream->stream; | 206 | stype = substream->stream; |
| 207 | pcd = to_dmadata(substream); | 207 | pcd = to_dmadata(substream); |
| 208 | 208 | ||
| 209 | DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " | 209 | DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %zu " |
| 210 | "runtime->min_align %d\n", | 210 | "runtime->min_align %lu\n", |
| 211 | (unsigned long)runtime->dma_area, | 211 | (unsigned long)runtime->dma_area, |
| 212 | (unsigned long)runtime->dma_addr, runtime->dma_bytes, | 212 | (unsigned long)runtime->dma_addr, runtime->dma_bytes, |
| 213 | runtime->min_align); | 213 | runtime->min_align); |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index cda27c22812a..1ee8506c06c7 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
| @@ -608,9 +608,7 @@ static struct clk *ak4642_of_parse_mcko(struct device *dev) | |||
| 608 | 608 | ||
| 609 | of_property_read_string(np, "clock-output-names", &clk_name); | 609 | of_property_read_string(np, "clock-output-names", &clk_name); |
| 610 | 610 | ||
| 611 | clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name, | 611 | clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name, 0, rate); |
| 612 | (parent_clk_name) ? 0 : CLK_IS_ROOT, | ||
| 613 | rate); | ||
| 614 | if (!IS_ERR(clk)) | 612 | if (!IS_ERR(clk)) |
| 615 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | 613 | of_clk_add_provider(np, of_clk_src_simple_get, clk); |
| 616 | 614 | ||
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 83959312f7a0..664a8c044ffb 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
| @@ -221,6 +221,8 @@ int arizona_init_spk(struct snd_soc_codec *codec) | |||
| 221 | 221 | ||
| 222 | switch (arizona->type) { | 222 | switch (arizona->type) { |
| 223 | case WM8997: | 223 | case WM8997: |
| 224 | case CS47L24: | ||
| 225 | case WM1831: | ||
| 224 | break; | 226 | break; |
| 225 | default: | 227 | default: |
| 226 | ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1); | 228 | ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1); |
| @@ -1134,7 +1136,6 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w, | |||
| 1134 | int event) | 1136 | int event) |
| 1135 | { | 1137 | { |
| 1136 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | 1138 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
| 1137 | unsigned int mask = 0x3 << w->shift; | ||
| 1138 | unsigned int val; | 1139 | unsigned int val; |
| 1139 | 1140 | ||
| 1140 | switch (event) { | 1141 | switch (event) { |
| @@ -1148,7 +1149,7 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w, | |||
| 1148 | return 0; | 1149 | return 0; |
| 1149 | } | 1150 | } |
| 1150 | 1151 | ||
| 1151 | snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val); | 1152 | snd_soc_write(codec, ARIZONA_CLOCK_CONTROL, val); |
| 1152 | 1153 | ||
| 1153 | return 0; | 1154 | return 0; |
| 1154 | } | 1155 | } |
| @@ -2047,7 +2048,21 @@ static int arizona_calc_fratio(struct arizona_fll *fll, | |||
| 2047 | init_ratio, Fref, refdiv); | 2048 | init_ratio, Fref, refdiv); |
| 2048 | 2049 | ||
| 2049 | while (div <= ARIZONA_FLL_MAX_REFDIV) { | 2050 | while (div <= ARIZONA_FLL_MAX_REFDIV) { |
| 2050 | for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; | 2051 | /* start from init_ratio because this may already give a |
| 2052 | * fractional N.K | ||
| 2053 | */ | ||
| 2054 | for (ratio = init_ratio; ratio > 0; ratio--) { | ||
| 2055 | if (target % (ratio * Fref)) { | ||
| 2056 | cfg->refdiv = refdiv; | ||
| 2057 | cfg->fratio = ratio - 1; | ||
| 2058 | arizona_fll_dbg(fll, | ||
| 2059 | "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n", | ||
| 2060 | Fref, refdiv, div, ratio); | ||
| 2061 | return ratio; | ||
| 2062 | } | ||
| 2063 | } | ||
| 2064 | |||
| 2065 | for (ratio = init_ratio + 1; ratio <= ARIZONA_FLL_MAX_FRATIO; | ||
| 2051 | ratio++) { | 2066 | ratio++) { |
| 2052 | if ((ARIZONA_FLL_VCO_CORNER / 2) / | 2067 | if ((ARIZONA_FLL_VCO_CORNER / 2) / |
| 2053 | (fll->vco_mult * ratio) < Fref) { | 2068 | (fll->vco_mult * ratio) < Fref) { |
| @@ -2073,17 +2088,6 @@ static int arizona_calc_fratio(struct arizona_fll *fll, | |||
| 2073 | } | 2088 | } |
| 2074 | } | 2089 | } |
| 2075 | 2090 | ||
| 2076 | for (ratio = init_ratio - 1; ratio > 0; ratio--) { | ||
| 2077 | if (target % (ratio * Fref)) { | ||
| 2078 | cfg->refdiv = refdiv; | ||
| 2079 | cfg->fratio = ratio - 1; | ||
| 2080 | arizona_fll_dbg(fll, | ||
| 2081 | "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n", | ||
| 2082 | Fref, refdiv, div, ratio); | ||
| 2083 | return ratio; | ||
| 2084 | } | ||
| 2085 | } | ||
| 2086 | |||
| 2087 | div *= 2; | 2091 | div *= 2; |
| 2088 | Fref /= 2; | 2092 | Fref /= 2; |
| 2089 | refdiv++; | 2093 | refdiv++; |
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 00e9b6fc1b5c..5ec5a682d186 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c | |||
| @@ -807,6 +807,9 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { | |||
| 807 | { "IN2L PGA", NULL, "IN2L" }, | 807 | { "IN2L PGA", NULL, "IN2L" }, |
| 808 | { "IN2R PGA", NULL, "IN2R" }, | 808 | { "IN2R PGA", NULL, "IN2R" }, |
| 809 | 809 | ||
| 810 | { "Audio Trace DSP", NULL, "DSP2" }, | ||
| 811 | { "Audio Trace DSP", NULL, "SYSCLK" }, | ||
| 812 | |||
| 810 | ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), | 813 | ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), |
| 811 | ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), | 814 | ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), |
| 812 | 815 | ||
| @@ -1016,6 +1019,27 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { | |||
| 1016 | .formats = CS47L24_FORMATS, | 1019 | .formats = CS47L24_FORMATS, |
| 1017 | }, | 1020 | }, |
| 1018 | }, | 1021 | }, |
| 1022 | { | ||
| 1023 | .name = "cs47l24-cpu-trace", | ||
| 1024 | .capture = { | ||
| 1025 | .stream_name = "Audio Trace CPU", | ||
| 1026 | .channels_min = 1, | ||
| 1027 | .channels_max = 6, | ||
| 1028 | .rates = CS47L24_RATES, | ||
| 1029 | .formats = CS47L24_FORMATS, | ||
| 1030 | }, | ||
| 1031 | .compress_new = snd_soc_new_compress, | ||
| 1032 | }, | ||
| 1033 | { | ||
| 1034 | .name = "cs47l24-dsp-trace", | ||
| 1035 | .capture = { | ||
| 1036 | .stream_name = "Audio Trace DSP", | ||
| 1037 | .channels_min = 1, | ||
| 1038 | .channels_max = 6, | ||
| 1039 | .rates = CS47L24_RATES, | ||
| 1040 | .formats = CS47L24_FORMATS, | ||
| 1041 | }, | ||
| 1042 | }, | ||
| 1019 | }; | 1043 | }; |
| 1020 | 1044 | ||
| 1021 | static int cs47l24_open(struct snd_compr_stream *stream) | 1045 | static int cs47l24_open(struct snd_compr_stream *stream) |
| @@ -1027,6 +1051,8 @@ static int cs47l24_open(struct snd_compr_stream *stream) | |||
| 1027 | 1051 | ||
| 1028 | if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) { | 1052 | if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) { |
| 1029 | n_adsp = 2; | 1053 | n_adsp = 2; |
| 1054 | } else if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-trace") == 0) { | ||
| 1055 | n_adsp = 1; | ||
| 1030 | } else { | 1056 | } else { |
| 1031 | dev_err(arizona->dev, | 1057 | dev_err(arizona->dev, |
| 1032 | "No suitable compressed stream for DAI '%s'\n", | 1058 | "No suitable compressed stream for DAI '%s'\n", |
| @@ -1041,10 +1067,16 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) | |||
| 1041 | { | 1067 | { |
| 1042 | struct cs47l24_priv *priv = data; | 1068 | struct cs47l24_priv *priv = data; |
| 1043 | struct arizona *arizona = priv->core.arizona; | 1069 | struct arizona *arizona = priv->core.arizona; |
| 1044 | int ret; | 1070 | int serviced = 0; |
| 1071 | int i, ret; | ||
| 1045 | 1072 | ||
| 1046 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[2]); | 1073 | for (i = 1; i <= 2; ++i) { |
| 1047 | if (ret == -ENODEV) { | 1074 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); |
| 1075 | if (ret != -ENODEV) | ||
| 1076 | serviced++; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | if (!serviced) { | ||
| 1048 | dev_err(arizona->dev, "Spurious compressed data IRQ\n"); | 1080 | dev_err(arizona->dev, "Spurious compressed data IRQ\n"); |
| 1049 | return IRQ_NONE; | 1081 | return IRQ_NONE; |
| 1050 | } | 1082 | } |
| @@ -1160,6 +1192,7 @@ static struct snd_compr_ops cs47l24_compr_ops = { | |||
| 1160 | static struct snd_soc_platform_driver cs47l24_compr_platform = { | 1192 | static struct snd_soc_platform_driver cs47l24_compr_platform = { |
| 1161 | .compr_ops = &cs47l24_compr_ops, | 1193 | .compr_ops = &cs47l24_compr_ops, |
| 1162 | }; | 1194 | }; |
| 1195 | |||
| 1163 | static int cs47l24_probe(struct platform_device *pdev) | 1196 | static int cs47l24_probe(struct platform_device *pdev) |
| 1164 | { | 1197 | { |
| 1165 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | 1198 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); |
| @@ -1228,9 +1261,9 @@ static int cs47l24_probe(struct platform_device *pdev) | |||
| 1228 | dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); | 1261 | dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); |
| 1229 | return ret; | 1262 | return ret; |
| 1230 | } | 1263 | } |
| 1264 | |||
| 1231 | ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, | 1265 | ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, |
| 1232 | cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); | 1266 | cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); |
| 1233 | |||
| 1234 | if (ret < 0) { | 1267 | if (ret < 0) { |
| 1235 | dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); | 1268 | dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); |
| 1236 | snd_soc_unregister_platform(&pdev->dev); | 1269 | snd_soc_unregister_platform(&pdev->dev); |
| @@ -1241,10 +1274,15 @@ static int cs47l24_probe(struct platform_device *pdev) | |||
| 1241 | 1274 | ||
| 1242 | static int cs47l24_remove(struct platform_device *pdev) | 1275 | static int cs47l24_remove(struct platform_device *pdev) |
| 1243 | { | 1276 | { |
| 1277 | struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev); | ||
| 1278 | |||
| 1244 | snd_soc_unregister_platform(&pdev->dev); | 1279 | snd_soc_unregister_platform(&pdev->dev); |
| 1245 | snd_soc_unregister_codec(&pdev->dev); | 1280 | snd_soc_unregister_codec(&pdev->dev); |
| 1246 | pm_runtime_disable(&pdev->dev); | 1281 | pm_runtime_disable(&pdev->dev); |
| 1247 | 1282 | ||
| 1283 | wm_adsp2_remove(&cs47l24->core.adsp[1]); | ||
| 1284 | wm_adsp2_remove(&cs47l24->core.adsp[2]); | ||
| 1285 | |||
| 1248 | return 0; | 1286 | return 0; |
| 1249 | } | 1287 | } |
| 1250 | 1288 | ||
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 1bae17ee8817..da60e3fe5ee7 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
| @@ -2098,10 +2098,14 @@ static int wm5102_probe(struct platform_device *pdev) | |||
| 2098 | 2098 | ||
| 2099 | static int wm5102_remove(struct platform_device *pdev) | 2099 | static int wm5102_remove(struct platform_device *pdev) |
| 2100 | { | 2100 | { |
| 2101 | struct wm5102_priv *wm5102 = platform_get_drvdata(pdev); | ||
| 2102 | |||
| 2101 | snd_soc_unregister_platform(&pdev->dev); | 2103 | snd_soc_unregister_platform(&pdev->dev); |
| 2102 | snd_soc_unregister_codec(&pdev->dev); | 2104 | snd_soc_unregister_codec(&pdev->dev); |
| 2103 | pm_runtime_disable(&pdev->dev); | 2105 | pm_runtime_disable(&pdev->dev); |
| 2104 | 2106 | ||
| 2107 | wm_adsp2_remove(&wm5102->core.adsp[0]); | ||
| 2108 | |||
| 2105 | return 0; | 2109 | return 0; |
| 2106 | } | 2110 | } |
| 2107 | 2111 | ||
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 2728ac545ffe..b5820e4d5471 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c | |||
| @@ -2437,10 +2437,16 @@ static int wm5110_probe(struct platform_device *pdev) | |||
| 2437 | 2437 | ||
| 2438 | static int wm5110_remove(struct platform_device *pdev) | 2438 | static int wm5110_remove(struct platform_device *pdev) |
| 2439 | { | 2439 | { |
| 2440 | struct wm5110_priv *wm5110 = platform_get_drvdata(pdev); | ||
| 2441 | int i; | ||
| 2442 | |||
| 2440 | snd_soc_unregister_platform(&pdev->dev); | 2443 | snd_soc_unregister_platform(&pdev->dev); |
| 2441 | snd_soc_unregister_codec(&pdev->dev); | 2444 | snd_soc_unregister_codec(&pdev->dev); |
| 2442 | pm_runtime_disable(&pdev->dev); | 2445 | pm_runtime_disable(&pdev->dev); |
| 2443 | 2446 | ||
| 2447 | for (i = 0; i < WM5110_NUM_ADSP; i++) | ||
| 2448 | wm_adsp2_remove(&wm5110->core.adsp[i]); | ||
| 2449 | |||
| 2444 | return 0; | 2450 | return 0; |
| 2445 | } | 2451 | } |
| 2446 | 2452 | ||
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index d3b1cb15e7f0..a07bd7c2c587 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
| @@ -160,6 +160,8 @@ | |||
| 160 | #define ADSP2_RAM_RDY_SHIFT 0 | 160 | #define ADSP2_RAM_RDY_SHIFT 0 |
| 161 | #define ADSP2_RAM_RDY_WIDTH 1 | 161 | #define ADSP2_RAM_RDY_WIDTH 1 |
| 162 | 162 | ||
| 163 | #define ADSP_MAX_STD_CTRL_SIZE 512 | ||
| 164 | |||
| 163 | struct wm_adsp_buf { | 165 | struct wm_adsp_buf { |
| 164 | struct list_head list; | 166 | struct list_head list; |
| 165 | void *buf; | 167 | void *buf; |
| @@ -271,8 +273,11 @@ struct wm_adsp_buffer { | |||
| 271 | __be32 words_written[2]; /* total words written (64 bit) */ | 273 | __be32 words_written[2]; /* total words written (64 bit) */ |
| 272 | }; | 274 | }; |
| 273 | 275 | ||
| 276 | struct wm_adsp_compr; | ||
| 277 | |||
| 274 | struct wm_adsp_compr_buf { | 278 | struct wm_adsp_compr_buf { |
| 275 | struct wm_adsp *dsp; | 279 | struct wm_adsp *dsp; |
| 280 | struct wm_adsp_compr *compr; | ||
| 276 | 281 | ||
| 277 | struct wm_adsp_buffer_region *regions; | 282 | struct wm_adsp_buffer_region *regions; |
| 278 | u32 host_buf_ptr; | 283 | u32 host_buf_ptr; |
| @@ -435,6 +440,7 @@ struct wm_coeff_ctl { | |||
| 435 | size_t len; | 440 | size_t len; |
| 436 | unsigned int set:1; | 441 | unsigned int set:1; |
| 437 | struct snd_kcontrol *kcontrol; | 442 | struct snd_kcontrol *kcontrol; |
| 443 | struct soc_bytes_ext bytes_ext; | ||
| 438 | unsigned int flags; | 444 | unsigned int flags; |
| 439 | }; | 445 | }; |
| 440 | 446 | ||
| @@ -711,10 +717,17 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) | |||
| 711 | be16_to_cpu(scratch[3])); | 717 | be16_to_cpu(scratch[3])); |
| 712 | } | 718 | } |
| 713 | 719 | ||
| 720 | static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) | ||
| 721 | { | ||
| 722 | return container_of(ext, struct wm_coeff_ctl, bytes_ext); | ||
| 723 | } | ||
| 724 | |||
| 714 | static int wm_coeff_info(struct snd_kcontrol *kctl, | 725 | static int wm_coeff_info(struct snd_kcontrol *kctl, |
| 715 | struct snd_ctl_elem_info *uinfo) | 726 | struct snd_ctl_elem_info *uinfo) |
| 716 | { | 727 | { |
| 717 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; | 728 | struct soc_bytes_ext *bytes_ext = |
| 729 | (struct soc_bytes_ext *)kctl->private_value; | ||
| 730 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
| 718 | 731 | ||
| 719 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | 732 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; |
| 720 | uinfo->count = ctl->len; | 733 | uinfo->count = ctl->len; |
| @@ -763,7 +776,9 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, | |||
| 763 | static int wm_coeff_put(struct snd_kcontrol *kctl, | 776 | static int wm_coeff_put(struct snd_kcontrol *kctl, |
| 764 | struct snd_ctl_elem_value *ucontrol) | 777 | struct snd_ctl_elem_value *ucontrol) |
| 765 | { | 778 | { |
| 766 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; | 779 | struct soc_bytes_ext *bytes_ext = |
| 780 | (struct soc_bytes_ext *)kctl->private_value; | ||
| 781 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
| 767 | char *p = ucontrol->value.bytes.data; | 782 | char *p = ucontrol->value.bytes.data; |
| 768 | int ret = 0; | 783 | int ret = 0; |
| 769 | 784 | ||
| @@ -780,6 +795,29 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, | |||
| 780 | return ret; | 795 | return ret; |
| 781 | } | 796 | } |
| 782 | 797 | ||
| 798 | static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, | ||
| 799 | const unsigned int __user *bytes, unsigned int size) | ||
| 800 | { | ||
| 801 | struct soc_bytes_ext *bytes_ext = | ||
| 802 | (struct soc_bytes_ext *)kctl->private_value; | ||
| 803 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
| 804 | int ret = 0; | ||
| 805 | |||
| 806 | mutex_lock(&ctl->dsp->pwr_lock); | ||
| 807 | |||
| 808 | if (copy_from_user(ctl->cache, bytes, size)) { | ||
| 809 | ret = -EFAULT; | ||
| 810 | } else { | ||
| 811 | ctl->set = 1; | ||
| 812 | if (ctl->enabled) | ||
| 813 | ret = wm_coeff_write_control(ctl, ctl->cache, size); | ||
| 814 | } | ||
| 815 | |||
| 816 | mutex_unlock(&ctl->dsp->pwr_lock); | ||
| 817 | |||
| 818 | return ret; | ||
| 819 | } | ||
| 820 | |||
| 783 | static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, | 821 | static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, |
| 784 | void *buf, size_t len) | 822 | void *buf, size_t len) |
| 785 | { | 823 | { |
| @@ -822,7 +860,9 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, | |||
| 822 | static int wm_coeff_get(struct snd_kcontrol *kctl, | 860 | static int wm_coeff_get(struct snd_kcontrol *kctl, |
| 823 | struct snd_ctl_elem_value *ucontrol) | 861 | struct snd_ctl_elem_value *ucontrol) |
| 824 | { | 862 | { |
| 825 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; | 863 | struct soc_bytes_ext *bytes_ext = |
| 864 | (struct soc_bytes_ext *)kctl->private_value; | ||
| 865 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
| 826 | char *p = ucontrol->value.bytes.data; | 866 | char *p = ucontrol->value.bytes.data; |
| 827 | int ret = 0; | 867 | int ret = 0; |
| 828 | 868 | ||
| @@ -845,12 +885,72 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, | |||
| 845 | return ret; | 885 | return ret; |
| 846 | } | 886 | } |
| 847 | 887 | ||
| 888 | static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, | ||
| 889 | unsigned int __user *bytes, unsigned int size) | ||
| 890 | { | ||
| 891 | struct soc_bytes_ext *bytes_ext = | ||
| 892 | (struct soc_bytes_ext *)kctl->private_value; | ||
| 893 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
| 894 | int ret = 0; | ||
| 895 | |||
| 896 | mutex_lock(&ctl->dsp->pwr_lock); | ||
| 897 | |||
| 898 | if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { | ||
| 899 | if (ctl->enabled) | ||
| 900 | ret = wm_coeff_read_control(ctl, ctl->cache, size); | ||
| 901 | else | ||
| 902 | ret = -EPERM; | ||
| 903 | } else { | ||
| 904 | if (!ctl->flags && ctl->enabled) | ||
| 905 | ret = wm_coeff_read_control(ctl, ctl->cache, size); | ||
| 906 | } | ||
| 907 | |||
| 908 | if (!ret && copy_to_user(bytes, ctl->cache, size)) | ||
| 909 | ret = -EFAULT; | ||
| 910 | |||
| 911 | mutex_unlock(&ctl->dsp->pwr_lock); | ||
| 912 | |||
| 913 | return ret; | ||
| 914 | } | ||
| 915 | |||
| 848 | struct wmfw_ctl_work { | 916 | struct wmfw_ctl_work { |
| 849 | struct wm_adsp *dsp; | 917 | struct wm_adsp *dsp; |
| 850 | struct wm_coeff_ctl *ctl; | 918 | struct wm_coeff_ctl *ctl; |
| 851 | struct work_struct work; | 919 | struct work_struct work; |
| 852 | }; | 920 | }; |
| 853 | 921 | ||
| 922 | static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len) | ||
| 923 | { | ||
| 924 | unsigned int out, rd, wr, vol; | ||
| 925 | |||
| 926 | if (len > ADSP_MAX_STD_CTRL_SIZE) { | ||
| 927 | rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
| 928 | wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE; | ||
| 929 | vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
| 930 | |||
| 931 | out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | ||
| 932 | } else { | ||
| 933 | rd = SNDRV_CTL_ELEM_ACCESS_READ; | ||
| 934 | wr = SNDRV_CTL_ELEM_ACCESS_WRITE; | ||
| 935 | vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
| 936 | |||
| 937 | out = 0; | ||
| 938 | } | ||
| 939 | |||
| 940 | if (in) { | ||
| 941 | if (in & WMFW_CTL_FLAG_READABLE) | ||
| 942 | out |= rd; | ||
| 943 | if (in & WMFW_CTL_FLAG_WRITEABLE) | ||
| 944 | out |= wr; | ||
| 945 | if (in & WMFW_CTL_FLAG_VOLATILE) | ||
| 946 | out |= vol; | ||
| 947 | } else { | ||
| 948 | out |= rd | wr | vol; | ||
| 949 | } | ||
| 950 | |||
| 951 | return out; | ||
| 952 | } | ||
| 953 | |||
| 854 | static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) | 954 | static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) |
| 855 | { | 955 | { |
| 856 | struct snd_kcontrol_new *kcontrol; | 956 | struct snd_kcontrol_new *kcontrol; |
| @@ -868,19 +968,15 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) | |||
| 868 | kcontrol->info = wm_coeff_info; | 968 | kcontrol->info = wm_coeff_info; |
| 869 | kcontrol->get = wm_coeff_get; | 969 | kcontrol->get = wm_coeff_get; |
| 870 | kcontrol->put = wm_coeff_put; | 970 | kcontrol->put = wm_coeff_put; |
| 871 | kcontrol->private_value = (unsigned long)ctl; | 971 | kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
| 972 | kcontrol->tlv.c = snd_soc_bytes_tlv_callback; | ||
| 973 | kcontrol->private_value = (unsigned long)&ctl->bytes_ext; | ||
| 872 | 974 | ||
| 873 | if (ctl->flags) { | 975 | ctl->bytes_ext.max = ctl->len; |
| 874 | if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE) | 976 | ctl->bytes_ext.get = wm_coeff_tlv_get; |
| 875 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE; | 977 | ctl->bytes_ext.put = wm_coeff_tlv_put; |
| 876 | if (ctl->flags & WMFW_CTL_FLAG_READABLE) | 978 | |
| 877 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ; | 979 | kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); |
| 878 | if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) | ||
| 879 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
| 880 | } else { | ||
| 881 | kcontrol->access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
| 882 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
| 883 | } | ||
| 884 | 980 | ||
| 885 | ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); | 981 | ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); |
| 886 | if (ret < 0) | 982 | if (ret < 0) |
| @@ -944,6 +1040,13 @@ static void wm_adsp_ctl_work(struct work_struct *work) | |||
| 944 | kfree(ctl_work); | 1040 | kfree(ctl_work); |
| 945 | } | 1041 | } |
| 946 | 1042 | ||
| 1043 | static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl) | ||
| 1044 | { | ||
| 1045 | kfree(ctl->cache); | ||
| 1046 | kfree(ctl->name); | ||
| 1047 | kfree(ctl); | ||
| 1048 | } | ||
| 1049 | |||
| 947 | static int wm_adsp_create_control(struct wm_adsp *dsp, | 1050 | static int wm_adsp_create_control(struct wm_adsp *dsp, |
| 948 | const struct wm_adsp_alg_region *alg_region, | 1051 | const struct wm_adsp_alg_region *alg_region, |
| 949 | unsigned int offset, unsigned int len, | 1052 | unsigned int offset, unsigned int len, |
| @@ -1032,11 +1135,6 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, | |||
| 1032 | 1135 | ||
| 1033 | ctl->flags = flags; | 1136 | ctl->flags = flags; |
| 1034 | ctl->offset = offset; | 1137 | ctl->offset = offset; |
| 1035 | if (len > 512) { | ||
| 1036 | adsp_warn(dsp, "Truncating control %s from %d\n", | ||
| 1037 | ctl->name, len); | ||
| 1038 | len = 512; | ||
| 1039 | } | ||
| 1040 | ctl->len = len; | 1138 | ctl->len = len; |
| 1041 | ctl->cache = kzalloc(ctl->len, GFP_KERNEL); | 1139 | ctl->cache = kzalloc(ctl->len, GFP_KERNEL); |
| 1042 | if (!ctl->cache) { | 1140 | if (!ctl->cache) { |
| @@ -1564,6 +1662,19 @@ static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, | |||
| 1564 | return alg_region; | 1662 | return alg_region; |
| 1565 | } | 1663 | } |
| 1566 | 1664 | ||
| 1665 | static void wm_adsp_free_alg_regions(struct wm_adsp *dsp) | ||
| 1666 | { | ||
| 1667 | struct wm_adsp_alg_region *alg_region; | ||
| 1668 | |||
| 1669 | while (!list_empty(&dsp->alg_regions)) { | ||
| 1670 | alg_region = list_first_entry(&dsp->alg_regions, | ||
| 1671 | struct wm_adsp_alg_region, | ||
| 1672 | list); | ||
| 1673 | list_del(&alg_region->list); | ||
| 1674 | kfree(alg_region); | ||
| 1675 | } | ||
| 1676 | } | ||
| 1677 | |||
| 1567 | static int wm_adsp1_setup_algs(struct wm_adsp *dsp) | 1678 | static int wm_adsp1_setup_algs(struct wm_adsp *dsp) |
| 1568 | { | 1679 | { |
| 1569 | struct wmfw_adsp1_id_hdr adsp1_id; | 1680 | struct wmfw_adsp1_id_hdr adsp1_id; |
| @@ -1994,7 +2105,6 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
| 1994 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | 2105 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
| 1995 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 2106 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); |
| 1996 | struct wm_adsp *dsp = &dsps[w->shift]; | 2107 | struct wm_adsp *dsp = &dsps[w->shift]; |
| 1997 | struct wm_adsp_alg_region *alg_region; | ||
| 1998 | struct wm_coeff_ctl *ctl; | 2108 | struct wm_coeff_ctl *ctl; |
| 1999 | int ret; | 2109 | int ret; |
| 2000 | unsigned int val; | 2110 | unsigned int val; |
| @@ -2074,13 +2184,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
| 2074 | list_for_each_entry(ctl, &dsp->ctl_list, list) | 2184 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
| 2075 | ctl->enabled = 0; | 2185 | ctl->enabled = 0; |
| 2076 | 2186 | ||
| 2077 | while (!list_empty(&dsp->alg_regions)) { | 2187 | |
| 2078 | alg_region = list_first_entry(&dsp->alg_regions, | 2188 | wm_adsp_free_alg_regions(dsp); |
| 2079 | struct wm_adsp_alg_region, | ||
| 2080 | list); | ||
| 2081 | list_del(&alg_region->list); | ||
| 2082 | kfree(alg_region); | ||
| 2083 | } | ||
| 2084 | break; | 2189 | break; |
| 2085 | 2190 | ||
| 2086 | default: | 2191 | default: |
| @@ -2222,7 +2327,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
| 2222 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | 2327 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
| 2223 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 2328 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); |
| 2224 | struct wm_adsp *dsp = &dsps[w->shift]; | 2329 | struct wm_adsp *dsp = &dsps[w->shift]; |
| 2225 | struct wm_adsp_alg_region *alg_region; | ||
| 2226 | struct wm_coeff_ctl *ctl; | 2330 | struct wm_coeff_ctl *ctl; |
| 2227 | int ret; | 2331 | int ret; |
| 2228 | 2332 | ||
| @@ -2240,9 +2344,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
| 2240 | if (ret != 0) | 2344 | if (ret != 0) |
| 2241 | goto err; | 2345 | goto err; |
| 2242 | 2346 | ||
| 2347 | mutex_lock(&dsp->pwr_lock); | ||
| 2348 | |||
| 2243 | if (wm_adsp_fw[dsp->fw].num_caps != 0) | 2349 | if (wm_adsp_fw[dsp->fw].num_caps != 0) |
| 2244 | ret = wm_adsp_buffer_init(dsp); | 2350 | ret = wm_adsp_buffer_init(dsp); |
| 2245 | 2351 | ||
| 2352 | mutex_unlock(&dsp->pwr_lock); | ||
| 2353 | |||
| 2246 | break; | 2354 | break; |
| 2247 | 2355 | ||
| 2248 | case SND_SOC_DAPM_PRE_PMD: | 2356 | case SND_SOC_DAPM_PRE_PMD: |
| @@ -2269,13 +2377,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
| 2269 | list_for_each_entry(ctl, &dsp->ctl_list, list) | 2377 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
| 2270 | ctl->enabled = 0; | 2378 | ctl->enabled = 0; |
| 2271 | 2379 | ||
| 2272 | while (!list_empty(&dsp->alg_regions)) { | 2380 | wm_adsp_free_alg_regions(dsp); |
| 2273 | alg_region = list_first_entry(&dsp->alg_regions, | ||
| 2274 | struct wm_adsp_alg_region, | ||
| 2275 | list); | ||
| 2276 | list_del(&alg_region->list); | ||
| 2277 | kfree(alg_region); | ||
| 2278 | } | ||
| 2279 | 2381 | ||
| 2280 | if (wm_adsp_fw[dsp->fw].num_caps != 0) | 2382 | if (wm_adsp_fw[dsp->fw].num_caps != 0) |
| 2281 | wm_adsp_buffer_free(dsp); | 2383 | wm_adsp_buffer_free(dsp); |
| @@ -2340,6 +2442,54 @@ int wm_adsp2_init(struct wm_adsp *dsp) | |||
| 2340 | } | 2442 | } |
| 2341 | EXPORT_SYMBOL_GPL(wm_adsp2_init); | 2443 | EXPORT_SYMBOL_GPL(wm_adsp2_init); |
| 2342 | 2444 | ||
| 2445 | void wm_adsp2_remove(struct wm_adsp *dsp) | ||
| 2446 | { | ||
| 2447 | struct wm_coeff_ctl *ctl; | ||
| 2448 | |||
| 2449 | while (!list_empty(&dsp->ctl_list)) { | ||
| 2450 | ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl, | ||
| 2451 | list); | ||
| 2452 | list_del(&ctl->list); | ||
| 2453 | wm_adsp_free_ctl_blk(ctl); | ||
| 2454 | } | ||
| 2455 | } | ||
| 2456 | EXPORT_SYMBOL_GPL(wm_adsp2_remove); | ||
| 2457 | |||
| 2458 | static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) | ||
| 2459 | { | ||
| 2460 | return compr->buf != NULL; | ||
| 2461 | } | ||
| 2462 | |||
| 2463 | static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) | ||
| 2464 | { | ||
| 2465 | /* | ||
| 2466 | * Note this will be more complex once each DSP can support multiple | ||
| 2467 | * streams | ||
| 2468 | */ | ||
| 2469 | if (!compr->dsp->buffer) | ||
| 2470 | return -EINVAL; | ||
| 2471 | |||
| 2472 | compr->buf = compr->dsp->buffer; | ||
| 2473 | compr->buf->compr = compr; | ||
| 2474 | |||
| 2475 | return 0; | ||
| 2476 | } | ||
| 2477 | |||
| 2478 | static void wm_adsp_compr_detach(struct wm_adsp_compr *compr) | ||
| 2479 | { | ||
| 2480 | if (!compr) | ||
| 2481 | return; | ||
| 2482 | |||
| 2483 | /* Wake the poll so it can see buffer is no longer attached */ | ||
| 2484 | if (compr->stream) | ||
| 2485 | snd_compr_fragment_elapsed(compr->stream); | ||
| 2486 | |||
| 2487 | if (wm_adsp_compr_attached(compr)) { | ||
| 2488 | compr->buf->compr = NULL; | ||
| 2489 | compr->buf = NULL; | ||
| 2490 | } | ||
| 2491 | } | ||
| 2492 | |||
| 2343 | int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) | 2493 | int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) |
| 2344 | { | 2494 | { |
| 2345 | struct wm_adsp_compr *compr; | 2495 | struct wm_adsp_compr *compr; |
| @@ -2393,6 +2543,7 @@ int wm_adsp_compr_free(struct snd_compr_stream *stream) | |||
| 2393 | 2543 | ||
| 2394 | mutex_lock(&dsp->pwr_lock); | 2544 | mutex_lock(&dsp->pwr_lock); |
| 2395 | 2545 | ||
| 2546 | wm_adsp_compr_detach(compr); | ||
| 2396 | dsp->compr = NULL; | 2547 | dsp->compr = NULL; |
| 2397 | 2548 | ||
| 2398 | kfree(compr->raw_buf); | 2549 | kfree(compr->raw_buf); |
| @@ -2689,6 +2840,8 @@ err_buffer: | |||
| 2689 | static int wm_adsp_buffer_free(struct wm_adsp *dsp) | 2840 | static int wm_adsp_buffer_free(struct wm_adsp *dsp) |
| 2690 | { | 2841 | { |
| 2691 | if (dsp->buffer) { | 2842 | if (dsp->buffer) { |
| 2843 | wm_adsp_compr_detach(dsp->buffer->compr); | ||
| 2844 | |||
| 2692 | kfree(dsp->buffer->regions); | 2845 | kfree(dsp->buffer->regions); |
| 2693 | kfree(dsp->buffer); | 2846 | kfree(dsp->buffer); |
| 2694 | 2847 | ||
| @@ -2698,25 +2851,6 @@ static int wm_adsp_buffer_free(struct wm_adsp *dsp) | |||
| 2698 | return 0; | 2851 | return 0; |
| 2699 | } | 2852 | } |
| 2700 | 2853 | ||
| 2701 | static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) | ||
| 2702 | { | ||
| 2703 | return compr->buf != NULL; | ||
| 2704 | } | ||
| 2705 | |||
| 2706 | static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) | ||
| 2707 | { | ||
| 2708 | /* | ||
| 2709 | * Note this will be more complex once each DSP can support multiple | ||
| 2710 | * streams | ||
| 2711 | */ | ||
| 2712 | if (!compr->dsp->buffer) | ||
| 2713 | return -EINVAL; | ||
| 2714 | |||
| 2715 | compr->buf = compr->dsp->buffer; | ||
| 2716 | |||
| 2717 | return 0; | ||
| 2718 | } | ||
| 2719 | |||
| 2720 | int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) | 2854 | int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) |
| 2721 | { | 2855 | { |
| 2722 | struct wm_adsp_compr *compr = stream->runtime->private_data; | 2856 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
| @@ -2805,21 +2939,41 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) | |||
| 2805 | avail += wm_adsp_buffer_size(buf); | 2939 | avail += wm_adsp_buffer_size(buf); |
| 2806 | 2940 | ||
| 2807 | adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", | 2941 | adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", |
| 2808 | buf->read_index, write_index, avail); | 2942 | buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE); |
| 2809 | 2943 | ||
| 2810 | buf->avail = avail; | 2944 | buf->avail = avail; |
| 2811 | 2945 | ||
| 2812 | return 0; | 2946 | return 0; |
| 2813 | } | 2947 | } |
| 2814 | 2948 | ||
| 2949 | static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) | ||
| 2950 | { | ||
| 2951 | int ret; | ||
| 2952 | |||
| 2953 | ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); | ||
| 2954 | if (ret < 0) { | ||
| 2955 | adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret); | ||
| 2956 | return ret; | ||
| 2957 | } | ||
| 2958 | if (buf->error != 0) { | ||
| 2959 | adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error); | ||
| 2960 | return -EIO; | ||
| 2961 | } | ||
| 2962 | |||
| 2963 | return 0; | ||
| 2964 | } | ||
| 2965 | |||
| 2815 | int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) | 2966 | int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) |
| 2816 | { | 2967 | { |
| 2817 | struct wm_adsp_compr_buf *buf = dsp->buffer; | 2968 | struct wm_adsp_compr_buf *buf; |
| 2818 | struct wm_adsp_compr *compr = dsp->compr; | 2969 | struct wm_adsp_compr *compr; |
| 2819 | int ret = 0; | 2970 | int ret = 0; |
| 2820 | 2971 | ||
| 2821 | mutex_lock(&dsp->pwr_lock); | 2972 | mutex_lock(&dsp->pwr_lock); |
| 2822 | 2973 | ||
| 2974 | buf = dsp->buffer; | ||
| 2975 | compr = dsp->compr; | ||
| 2976 | |||
| 2823 | if (!buf) { | 2977 | if (!buf) { |
| 2824 | ret = -ENODEV; | 2978 | ret = -ENODEV; |
| 2825 | goto out; | 2979 | goto out; |
| @@ -2827,16 +2981,9 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) | |||
| 2827 | 2981 | ||
| 2828 | adsp_dbg(dsp, "Handling buffer IRQ\n"); | 2982 | adsp_dbg(dsp, "Handling buffer IRQ\n"); |
| 2829 | 2983 | ||
| 2830 | ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); | 2984 | ret = wm_adsp_buffer_get_error(buf); |
| 2831 | if (ret < 0) { | 2985 | if (ret < 0) |
| 2832 | adsp_err(dsp, "Failed to check buffer error: %d\n", ret); | 2986 | goto out_notify; /* Wake poll to report error */ |
| 2833 | goto out; | ||
| 2834 | } | ||
| 2835 | if (buf->error != 0) { | ||
| 2836 | adsp_err(dsp, "Buffer error occurred: %d\n", buf->error); | ||
| 2837 | ret = -EIO; | ||
| 2838 | goto out; | ||
| 2839 | } | ||
| 2840 | 2987 | ||
| 2841 | ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), | 2988 | ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), |
| 2842 | &buf->irq_count); | 2989 | &buf->irq_count); |
| @@ -2851,6 +2998,7 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) | |||
| 2851 | goto out; | 2998 | goto out; |
| 2852 | } | 2999 | } |
| 2853 | 3000 | ||
| 3001 | out_notify: | ||
| 2854 | if (compr && compr->stream) | 3002 | if (compr && compr->stream) |
| 2855 | snd_compr_fragment_elapsed(compr->stream); | 3003 | snd_compr_fragment_elapsed(compr->stream); |
| 2856 | 3004 | ||
| @@ -2879,14 +3027,16 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, | |||
| 2879 | struct snd_compr_tstamp *tstamp) | 3027 | struct snd_compr_tstamp *tstamp) |
| 2880 | { | 3028 | { |
| 2881 | struct wm_adsp_compr *compr = stream->runtime->private_data; | 3029 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
| 2882 | struct wm_adsp_compr_buf *buf = compr->buf; | ||
| 2883 | struct wm_adsp *dsp = compr->dsp; | 3030 | struct wm_adsp *dsp = compr->dsp; |
| 3031 | struct wm_adsp_compr_buf *buf; | ||
| 2884 | int ret = 0; | 3032 | int ret = 0; |
| 2885 | 3033 | ||
| 2886 | adsp_dbg(dsp, "Pointer request\n"); | 3034 | adsp_dbg(dsp, "Pointer request\n"); |
| 2887 | 3035 | ||
| 2888 | mutex_lock(&dsp->pwr_lock); | 3036 | mutex_lock(&dsp->pwr_lock); |
| 2889 | 3037 | ||
| 3038 | buf = compr->buf; | ||
| 3039 | |||
| 2890 | if (!compr->buf) { | 3040 | if (!compr->buf) { |
| 2891 | ret = -ENXIO; | 3041 | ret = -ENXIO; |
| 2892 | goto out; | 3042 | goto out; |
| @@ -2909,6 +3059,10 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, | |||
| 2909 | * DSP to inform us once a whole fragment is available. | 3059 | * DSP to inform us once a whole fragment is available. |
| 2910 | */ | 3060 | */ |
| 2911 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { | 3061 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { |
| 3062 | ret = wm_adsp_buffer_get_error(buf); | ||
| 3063 | if (ret < 0) | ||
| 3064 | goto out; | ||
| 3065 | |||
| 2912 | ret = wm_adsp_buffer_reenable_irq(buf); | 3066 | ret = wm_adsp_buffer_reenable_irq(buf); |
| 2913 | if (ret < 0) { | 3067 | if (ret < 0) { |
| 2914 | adsp_err(dsp, | 3068 | adsp_err(dsp, |
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index b61cb57e600f..feb61e2c4bb4 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h | |||
| @@ -92,6 +92,7 @@ extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; | |||
| 92 | 92 | ||
| 93 | int wm_adsp1_init(struct wm_adsp *dsp); | 93 | int wm_adsp1_init(struct wm_adsp *dsp); |
| 94 | int wm_adsp2_init(struct wm_adsp *dsp); | 94 | int wm_adsp2_init(struct wm_adsp *dsp); |
| 95 | void wm_adsp2_remove(struct wm_adsp *dsp); | ||
| 95 | int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec); | 96 | int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec); |
| 96 | int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); | 97 | int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); |
| 97 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, | 98 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, |
