aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c4
-rw-r--r--sound/soc/au1x/dbdma2.c4
-rw-r--r--sound/soc/codecs/ak4642.c4
-rw-r--r--sound/soc/codecs/arizona.c32
-rw-r--r--sound/soc/codecs/cs47l24.c46
-rw-r--r--sound/soc/codecs/wm5102.c4
-rw-r--r--sound/soc/codecs/wm5110.c6
-rw-r--r--sound/soc/codecs/wm_adsp.c292
-rw-r--r--sound/soc/codecs/wm_adsp.h1
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
1021static int cs47l24_open(struct snd_compr_stream *stream) 1045static 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 = {
1160static struct snd_soc_platform_driver cs47l24_compr_platform = { 1192static struct snd_soc_platform_driver cs47l24_compr_platform = {
1161 .compr_ops = &cs47l24_compr_ops, 1193 .compr_ops = &cs47l24_compr_ops,
1162}; 1194};
1195
1163static int cs47l24_probe(struct platform_device *pdev) 1196static 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
1242static int cs47l24_remove(struct platform_device *pdev) 1275static 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
2099static int wm5102_remove(struct platform_device *pdev) 2099static 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
2438static int wm5110_remove(struct platform_device *pdev) 2438static 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
163struct wm_adsp_buf { 165struct 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
276struct wm_adsp_compr;
277
274struct wm_adsp_compr_buf { 278struct 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
720static 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
714static int wm_coeff_info(struct snd_kcontrol *kctl, 725static 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,
763static int wm_coeff_put(struct snd_kcontrol *kctl, 776static 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
798static 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
783static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, 821static 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,
822static int wm_coeff_get(struct snd_kcontrol *kctl, 860static 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
888static 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
848struct wmfw_ctl_work { 916struct 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
922static 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
854static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) 954static 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
1043static 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
947static int wm_adsp_create_control(struct wm_adsp *dsp, 1050static 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
1665static 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
1567static int wm_adsp1_setup_algs(struct wm_adsp *dsp) 1678static 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}
2341EXPORT_SYMBOL_GPL(wm_adsp2_init); 2443EXPORT_SYMBOL_GPL(wm_adsp2_init);
2342 2444
2445void 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}
2456EXPORT_SYMBOL_GPL(wm_adsp2_remove);
2457
2458static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
2459{
2460 return compr->buf != NULL;
2461}
2462
2463static 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
2478static 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
2343int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) 2493int 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:
2689static int wm_adsp_buffer_free(struct wm_adsp *dsp) 2840static 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
2701static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
2702{
2703 return compr->buf != NULL;
2704}
2705
2706static 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
2720int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) 2854int 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
2949static 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
2815int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) 2966int 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
3001out_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
93int wm_adsp1_init(struct wm_adsp *dsp); 93int wm_adsp1_init(struct wm_adsp *dsp);
94int wm_adsp2_init(struct wm_adsp *dsp); 94int wm_adsp2_init(struct wm_adsp *dsp);
95void wm_adsp2_remove(struct wm_adsp *dsp);
95int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec); 96int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec);
96int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); 97int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec);
97int wm_adsp1_event(struct snd_soc_dapm_widget *w, 98int wm_adsp1_event(struct snd_soc_dapm_widget *w,