Commit 3b15d43b authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/adsp', 'asoc/topic/ak4624',...

Merge remote-tracking branches 'asoc/topic/adsp', 'asoc/topic/ak4624', 'asoc/topic/atmel' and 'asoc/topic/au1x' into asoc-next
...@@ -652,7 +652,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ...@@ -652,7 +652,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
| SSC_BF(RCMR_STTDLY, 1) | SSC_BF(RCMR_STTDLY, 1)
| SSC_BF(RCMR_START, SSC_START_RISING_RF) | SSC_BF(RCMR_START, SSC_START_RISING_RF)
| SSC_BF(RCMR_CKI, SSC_CKI_FALLING) | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
| SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
| SSC_BF(RCMR_CKS, SSC_CKS_DIV); | SSC_BF(RCMR_CKS, SSC_CKS_DIV);
...@@ -692,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ...@@ -692,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
rcmr = SSC_BF(RCMR_PERIOD, 0) rcmr = SSC_BF(RCMR_PERIOD, 0)
| SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_STTDLY, START_DELAY)
| SSC_BF(RCMR_START, SSC_START_RISING_RF) | SSC_BF(RCMR_START, SSC_START_RISING_RF)
| SSC_BF(RCMR_CKI, SSC_CKI_FALLING) | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
| SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
| SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
SSC_CKS_PIN : SSC_CKS_CLOCK); SSC_CKS_PIN : SSC_CKS_CLOCK);
......
...@@ -206,8 +206,8 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -206,8 +206,8 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
stype = substream->stream; stype = substream->stream;
pcd = to_dmadata(substream); pcd = to_dmadata(substream);
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %zu "
"runtime->min_align %d\n", "runtime->min_align %lu\n",
(unsigned long)runtime->dma_area, (unsigned long)runtime->dma_area,
(unsigned long)runtime->dma_addr, runtime->dma_bytes, (unsigned long)runtime->dma_addr, runtime->dma_bytes,
runtime->min_align); runtime->min_align);
......
...@@ -608,9 +608,7 @@ static struct clk *ak4642_of_parse_mcko(struct device *dev) ...@@ -608,9 +608,7 @@ static struct clk *ak4642_of_parse_mcko(struct device *dev)
of_property_read_string(np, "clock-output-names", &clk_name); of_property_read_string(np, "clock-output-names", &clk_name);
clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name, clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name, 0, rate);
(parent_clk_name) ? 0 : CLK_IS_ROOT,
rate);
if (!IS_ERR(clk)) if (!IS_ERR(clk))
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
......
...@@ -221,6 +221,8 @@ int arizona_init_spk(struct snd_soc_codec *codec) ...@@ -221,6 +221,8 @@ int arizona_init_spk(struct snd_soc_codec *codec)
switch (arizona->type) { switch (arizona->type) {
case WM8997: case WM8997:
case CS47L24:
case WM1831:
break; break;
default: default:
ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1); 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,7 +1136,6 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w,
int event) int event)
{ {
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
unsigned int mask = 0x3 << w->shift;
unsigned int val; unsigned int val;
switch (event) { switch (event) {
...@@ -1148,7 +1149,7 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w, ...@@ -1148,7 +1149,7 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w,
return 0; return 0;
} }
snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val); snd_soc_write(codec, ARIZONA_CLOCK_CONTROL, val);
return 0; return 0;
} }
...@@ -2047,7 +2048,21 @@ static int arizona_calc_fratio(struct arizona_fll *fll, ...@@ -2047,7 +2048,21 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
init_ratio, Fref, refdiv); init_ratio, Fref, refdiv);
while (div <= ARIZONA_FLL_MAX_REFDIV) { while (div <= ARIZONA_FLL_MAX_REFDIV) {
for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; /* start from init_ratio because this may already give a
* fractional N.K
*/
for (ratio = init_ratio; ratio > 0; ratio--) {
if (target % (ratio * Fref)) {
cfg->refdiv = refdiv;
cfg->fratio = ratio - 1;
arizona_fll_dbg(fll,
"pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
Fref, refdiv, div, ratio);
return ratio;
}
}
for (ratio = init_ratio + 1; ratio <= ARIZONA_FLL_MAX_FRATIO;
ratio++) { ratio++) {
if ((ARIZONA_FLL_VCO_CORNER / 2) / if ((ARIZONA_FLL_VCO_CORNER / 2) /
(fll->vco_mult * ratio) < Fref) { (fll->vco_mult * ratio) < Fref) {
...@@ -2073,17 +2088,6 @@ static int arizona_calc_fratio(struct arizona_fll *fll, ...@@ -2073,17 +2088,6 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
} }
} }
for (ratio = init_ratio - 1; ratio > 0; ratio--) {
if (target % (ratio * Fref)) {
cfg->refdiv = refdiv;
cfg->fratio = ratio - 1;
arizona_fll_dbg(fll,
"pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
Fref, refdiv, div, ratio);
return ratio;
}
}
div *= 2; div *= 2;
Fref /= 2; Fref /= 2;
refdiv++; refdiv++;
......
...@@ -807,6 +807,9 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { ...@@ -807,6 +807,9 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
{ "IN2L PGA", NULL, "IN2L" }, { "IN2L PGA", NULL, "IN2L" },
{ "IN2R PGA", NULL, "IN2R" }, { "IN2R PGA", NULL, "IN2R" },
{ "Audio Trace DSP", NULL, "DSP2" },
{ "Audio Trace DSP", NULL, "SYSCLK" },
ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
...@@ -1016,6 +1019,27 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { ...@@ -1016,6 +1019,27 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
.formats = CS47L24_FORMATS, .formats = CS47L24_FORMATS,
}, },
}, },
{
.name = "cs47l24-cpu-trace",
.capture = {
.stream_name = "Audio Trace CPU",
.channels_min = 1,
.channels_max = 6,
.rates = CS47L24_RATES,
.formats = CS47L24_FORMATS,
},
.compress_new = snd_soc_new_compress,
},
{
.name = "cs47l24-dsp-trace",
.capture = {
.stream_name = "Audio Trace DSP",
.channels_min = 1,
.channels_max = 6,
.rates = CS47L24_RATES,
.formats = CS47L24_FORMATS,
},
},
}; };
static int cs47l24_open(struct snd_compr_stream *stream) static int cs47l24_open(struct snd_compr_stream *stream)
...@@ -1027,6 +1051,8 @@ static int cs47l24_open(struct snd_compr_stream *stream) ...@@ -1027,6 +1051,8 @@ static int cs47l24_open(struct snd_compr_stream *stream)
if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) { if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) {
n_adsp = 2; n_adsp = 2;
} else if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-trace") == 0) {
n_adsp = 1;
} else { } else {
dev_err(arizona->dev, dev_err(arizona->dev,
"No suitable compressed stream for DAI '%s'\n", "No suitable compressed stream for DAI '%s'\n",
...@@ -1041,10 +1067,16 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) ...@@ -1041,10 +1067,16 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
{ {
struct cs47l24_priv *priv = data; struct cs47l24_priv *priv = data;
struct arizona *arizona = priv->core.arizona; struct arizona *arizona = priv->core.arizona;
int ret; int serviced = 0;
int i, ret;
ret = wm_adsp_compr_handle_irq(&priv->core.adsp[2]); for (i = 1; i <= 2; ++i) {
if (ret == -ENODEV) { ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
if (ret != -ENODEV)
serviced++;
}
if (!serviced) {
dev_err(arizona->dev, "Spurious compressed data IRQ\n"); dev_err(arizona->dev, "Spurious compressed data IRQ\n");
return IRQ_NONE; return IRQ_NONE;
} }
...@@ -1160,6 +1192,7 @@ static struct snd_compr_ops cs47l24_compr_ops = { ...@@ -1160,6 +1192,7 @@ static struct snd_compr_ops cs47l24_compr_ops = {
static struct snd_soc_platform_driver cs47l24_compr_platform = { static struct snd_soc_platform_driver cs47l24_compr_platform = {
.compr_ops = &cs47l24_compr_ops, .compr_ops = &cs47l24_compr_ops,
}; };
static int cs47l24_probe(struct platform_device *pdev) static int cs47l24_probe(struct platform_device *pdev)
{ {
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
...@@ -1228,9 +1261,9 @@ static int cs47l24_probe(struct platform_device *pdev) ...@@ -1228,9 +1261,9 @@ static int cs47l24_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
return ret; return ret;
} }
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_platform(&pdev->dev);
...@@ -1241,10 +1274,15 @@ static int cs47l24_probe(struct platform_device *pdev) ...@@ -1241,10 +1274,15 @@ static int cs47l24_probe(struct platform_device *pdev)
static int cs47l24_remove(struct platform_device *pdev) static int cs47l24_remove(struct platform_device *pdev)
{ {
struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev);
snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_platform(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev); snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
wm_adsp2_remove(&cs47l24->core.adsp[1]);
wm_adsp2_remove(&cs47l24->core.adsp[2]);
return 0; return 0;
} }
......
...@@ -2098,10 +2098,14 @@ static int wm5102_probe(struct platform_device *pdev) ...@@ -2098,10 +2098,14 @@ static int wm5102_probe(struct platform_device *pdev)
static int wm5102_remove(struct platform_device *pdev) static int wm5102_remove(struct platform_device *pdev)
{ {
struct wm5102_priv *wm5102 = platform_get_drvdata(pdev);
snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_platform(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev); snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
wm_adsp2_remove(&wm5102->core.adsp[0]);
return 0; return 0;
} }
......
...@@ -2437,10 +2437,16 @@ static int wm5110_probe(struct platform_device *pdev) ...@@ -2437,10 +2437,16 @@ static int wm5110_probe(struct platform_device *pdev)
static int wm5110_remove(struct platform_device *pdev) static int wm5110_remove(struct platform_device *pdev)
{ {
struct wm5110_priv *wm5110 = platform_get_drvdata(pdev);
int i;
snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_platform(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev); snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
for (i = 0; i < WM5110_NUM_ADSP; i++)
wm_adsp2_remove(&wm5110->core.adsp[i]);
return 0; return 0;
} }
......
...@@ -160,6 +160,8 @@ ...@@ -160,6 +160,8 @@
#define ADSP2_RAM_RDY_SHIFT 0 #define ADSP2_RAM_RDY_SHIFT 0
#define ADSP2_RAM_RDY_WIDTH 1 #define ADSP2_RAM_RDY_WIDTH 1
#define ADSP_MAX_STD_CTRL_SIZE 512
struct wm_adsp_buf { struct wm_adsp_buf {
struct list_head list; struct list_head list;
void *buf; void *buf;
...@@ -271,8 +273,11 @@ struct wm_adsp_buffer { ...@@ -271,8 +273,11 @@ struct wm_adsp_buffer {
__be32 words_written[2]; /* total words written (64 bit) */ __be32 words_written[2]; /* total words written (64 bit) */
}; };
struct wm_adsp_compr;
struct wm_adsp_compr_buf { struct wm_adsp_compr_buf {
struct wm_adsp *dsp; struct wm_adsp *dsp;
struct wm_adsp_compr *compr;
struct wm_adsp_buffer_region *regions; struct wm_adsp_buffer_region *regions;
u32 host_buf_ptr; u32 host_buf_ptr;
...@@ -435,6 +440,7 @@ struct wm_coeff_ctl { ...@@ -435,6 +440,7 @@ struct wm_coeff_ctl {
size_t len; size_t len;
unsigned int set:1; unsigned int set:1;
struct snd_kcontrol *kcontrol; struct snd_kcontrol *kcontrol;
struct soc_bytes_ext bytes_ext;
unsigned int flags; unsigned int flags;
}; };
...@@ -711,10 +717,17 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) ...@@ -711,10 +717,17 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
be16_to_cpu(scratch[3])); be16_to_cpu(scratch[3]));
} }
static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
{
return container_of(ext, struct wm_coeff_ctl, bytes_ext);
}
static int wm_coeff_info(struct snd_kcontrol *kctl, static int wm_coeff_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *uinfo) struct snd_ctl_elem_info *uinfo)
{ {
struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
uinfo->count = ctl->len; uinfo->count = ctl->len;
...@@ -763,7 +776,9 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, ...@@ -763,7 +776,9 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
static int wm_coeff_put(struct snd_kcontrol *kctl, static int wm_coeff_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
char *p = ucontrol->value.bytes.data; char *p = ucontrol->value.bytes.data;
int ret = 0; int ret = 0;
...@@ -780,6 +795,29 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, ...@@ -780,6 +795,29 @@ static int wm_coeff_put(struct snd_kcontrol *kctl,
return ret; return ret;
} }
static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
const unsigned int __user *bytes, unsigned int size)
{
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
int ret = 0;
mutex_lock(&ctl->dsp->pwr_lock);
if (copy_from_user(ctl->cache, bytes, size)) {
ret = -EFAULT;
} else {
ctl->set = 1;
if (ctl->enabled)
ret = wm_coeff_write_control(ctl, ctl->cache, size);
}
mutex_unlock(&ctl->dsp->pwr_lock);
return ret;
}
static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
void *buf, size_t len) void *buf, size_t len)
{ {
...@@ -822,7 +860,9 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, ...@@ -822,7 +860,9 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
static int wm_coeff_get(struct snd_kcontrol *kctl, static int wm_coeff_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
char *p = ucontrol->value.bytes.data; char *p = ucontrol->value.bytes.data;
int ret = 0; int ret = 0;
...@@ -845,12 +885,72 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, ...@@ -845,12 +885,72 @@ static int wm_coeff_get(struct snd_kcontrol *kctl,
return ret; return ret;
} }
static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
unsigned int __user *bytes, unsigned int size)
{
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
int ret = 0;
mutex_lock(&ctl->dsp->pwr_lock);
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
if (ctl->enabled)
ret = wm_coeff_read_control(ctl, ctl->cache, size);
else
ret = -EPERM;
} else {
if (!ctl->flags && ctl->enabled)
ret = wm_coeff_read_control(ctl, ctl->cache, size);
}
if (!ret && copy_to_user(bytes, ctl->cache, size))
ret = -EFAULT;
mutex_unlock(&ctl->dsp->pwr_lock);
return ret;
}
struct wmfw_ctl_work { struct wmfw_ctl_work {
struct wm_adsp *dsp; struct wm_adsp *dsp;
struct wm_coeff_ctl *ctl; struct wm_coeff_ctl *ctl;
struct work_struct work; struct work_struct work;
}; };
static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
{
unsigned int out, rd, wr, vol;
if (len > ADSP_MAX_STD_CTRL_SIZE) {
rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ;
wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
} else {
rd = SNDRV_CTL_ELEM_ACCESS_READ;
wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
out = 0;
}
if (in) {
if (in & WMFW_CTL_FLAG_READABLE)
out |= rd;
if (in & WMFW_CTL_FLAG_WRITEABLE)
out |= wr;
if (in & WMFW_CTL_FLAG_VOLATILE)
out |= vol;
} else {
out |= rd | wr | vol;
}
return out;
}
static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
{ {
struct snd_kcontrol_new *kcontrol; struct snd_kcontrol_new *kcontrol;
...@@ -868,19 +968,15 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) ...@@ -868,19 +968,15 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
kcontrol->info = wm_coeff_info; kcontrol->info = wm_coeff_info;
kcontrol->get = wm_coeff_get; kcontrol->get = wm_coeff_get;
kcontrol->put = wm_coeff_put; kcontrol->put = wm_coeff_put;
kcontrol->private_value = (unsigned long)ctl; kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
if (ctl->flags) { ctl->bytes_ext.max = ctl->len;
if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE) ctl->bytes_ext.get = wm_coeff_tlv_get;
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE; ctl->bytes_ext.put = wm_coeff_tlv_put;
if (ctl->flags & WMFW_CTL_FLAG_READABLE)
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ; kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len);
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
} else {
kcontrol->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
}
ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1);
if (ret < 0) if (ret < 0)
...@@ -944,6 +1040,13 @@ static void wm_adsp_ctl_work(struct work_struct *work) ...@@ -944,6 +1040,13 @@ static void wm_adsp_ctl_work(struct work_struct *work)
kfree(ctl_work); kfree(ctl_work);
} }
static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl)
{
kfree(ctl->cache);
kfree(ctl->name);
kfree(ctl);
}
static int wm_adsp_create_control(struct wm_adsp *dsp, static int wm_adsp_create_control(struct wm_adsp *dsp,
const struct wm_adsp_alg_region *alg_region, const struct wm_adsp_alg_region *alg_region,
unsigned int offset, unsigned int len, unsigned int offset, unsigned int len,
...@@ -1032,11 +1135,6 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, ...@@ -1032,11 +1135,6 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
ctl->flags = flags; ctl->flags = flags;
ctl->offset = offset; ctl->offset = offset;
if (len > 512) {
adsp_warn(dsp, "Truncating control %s from %d\n",
ctl->name, len);
len = 512;
}
ctl->len = len; ctl->len = len;
ctl->cache = kzalloc(ctl->len, GFP_KERNEL); ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
if (!ctl->cache) { if (!ctl->cache) {
...@@ -1564,6 +1662,19 @@ static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, ...@@ -1564,6 +1662,19 @@ static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
return alg_region; return alg_region;
} }
static void wm_adsp_free_alg_regions(struct wm_adsp *dsp)
{
struct wm_adsp_alg_region *alg_region;
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);
}
}
static int wm_adsp1_setup_algs(struct wm_adsp *dsp) static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
{ {
struct wmfw_adsp1_id_hdr adsp1_id; struct wmfw_adsp1_id_hdr adsp1_id;
...@@ -1994,7 +2105,6 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, ...@@ -1994,7 +2105,6 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = &dsps[w->shift]; struct wm_adsp *dsp = &dsps[w->shift];
struct wm_adsp_alg_region *alg_region;
struct wm_coeff_ctl *ctl; struct wm_coeff_ctl *ctl;
int ret; int ret;
unsigned int val; unsigned int val;
...@@ -2074,13 +2184,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, ...@@ -2074,13 +2184,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
list_for_each_entry(ctl, &dsp->ctl_list, list) list_for_each_entry(ctl, &dsp->ctl_list, list)
ctl->enabled = 0; ctl->enabled = 0;
while (!list_empty(&dsp->alg_regions)) {
alg_region = list_first_entry(&dsp->alg_regions, wm_adsp_free_alg_regions(dsp);
struct wm_adsp_alg_region,
list);
list_del(&alg_region->list);
kfree(alg_region);
}
break; break;
default: default:
...@@ -2222,7 +2327,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ...@@ -2222,7 +2327,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = &dsps[w->shift]; struct wm_adsp *dsp = &dsps[w->shift];
struct wm_adsp_alg_region *alg_region;
struct wm_coeff_ctl *ctl; struct wm_coeff_ctl *ctl;
int ret; int ret;
...@@ -2240,9 +2344,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ...@@ -2240,9 +2344,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
if (ret != 0) if (ret != 0)
goto err; goto err;
mutex_lock(&dsp->pwr_lock);
if (wm_adsp_fw[dsp->fw].num_caps != 0) if (wm_adsp_fw[dsp->fw].num_caps != 0)
ret = wm_adsp_buffer_init(dsp); ret = wm_adsp_buffer_init(dsp);
mutex_unlock(&dsp->pwr_lock);
break; break;
case SND_SOC_DAPM_PRE_PMD: case SND_SOC_DAPM_PRE_PMD:
...@@ -2269,13 +2377,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ...@@ -2269,13 +2377,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
list_for_each_entry(ctl, &dsp->ctl_list, list) list_for_each_entry(ctl, &dsp->ctl_list, list)
ctl->enabled = 0; ctl->enabled = 0;
while (!list_empty(&dsp->alg_regions)) { wm_adsp_free_alg_regions(dsp);
alg_region = list_first_entry(&dsp->alg_regions,
struct wm_adsp_alg_region,
list);
list_del(&alg_region->list);
kfree(alg_region);
}
if (wm_adsp_fw[dsp->fw].num_caps != 0) if (wm_adsp_fw[dsp->fw].num_caps != 0)
wm_adsp_buffer_free(dsp); wm_adsp_buffer_free(dsp);
...@@ -2340,6 +2442,54 @@ int wm_adsp2_init(struct wm_adsp *dsp) ...@@ -2340,6 +2442,54 @@ int wm_adsp2_init(struct wm_adsp *dsp)
} }
EXPORT_SYMBOL_GPL(wm_adsp2_init); EXPORT_SYMBOL_GPL(wm_adsp2_init);
void wm_adsp2_remove(struct wm_adsp *dsp)
{
struct wm_coeff_ctl *ctl;
while (!list_empty(&dsp->ctl_list)) {
ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl,
list);
list_del(&ctl->list);
wm_adsp_free_ctl_blk(ctl);
}
}
EXPORT_SYMBOL_GPL(wm_adsp2_remove);
static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
{
return compr->buf != NULL;
}
static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
{
/*
* Note this will be more complex once each DSP can support multiple
* streams
*/
if (!compr->dsp->buffer)
return -EINVAL;
compr->buf = compr->dsp->buffer;
compr->buf->compr = compr;
return 0;
}
static void wm_adsp_compr_detach(struct wm_adsp_compr *compr)
{
if (!compr)
return;
/* Wake the poll so it can see buffer is no longer attached */
if (compr->stream)
snd_compr_fragment_elapsed(compr->stream);
if (wm_adsp_compr_attached(compr)) {
compr->buf->compr = NULL;
compr->buf = NULL;
}
}
int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
{ {
struct wm_adsp_compr *compr; struct wm_adsp_compr *compr;
...@@ -2393,6 +2543,7 @@ int wm_adsp_compr_free(struct snd_compr_stream *stream) ...@@ -2393,6 +2543,7 @@ int wm_adsp_compr_free(struct snd_compr_stream *stream)
mutex_lock(&dsp->pwr_lock); mutex_lock(&dsp->pwr_lock);
wm_adsp_compr_detach(compr);
dsp->compr = NULL; dsp->compr = NULL;
kfree(compr->raw_buf); kfree(compr->raw_buf);
...@@ -2689,6 +2840,8 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp) ...@@ -2689,6 +2840,8 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp)
static int wm_adsp_buffer_free(struct wm_adsp *dsp) static int wm_adsp_buffer_free(struct wm_adsp *dsp)
{ {
if (dsp->buffer) { if (dsp->buffer) {
wm_adsp_compr_detach(dsp->buffer->compr);
kfree(dsp->buffer->regions); kfree(dsp->buffer->regions);
kfree(dsp->buffer); kfree(dsp->buffer);
...@@ -2698,25 +2851,6 @@ static int wm_adsp_buffer_free(struct wm_adsp *dsp) ...@@ -2698,25 +2851,6 @@ static int wm_adsp_buffer_free(struct wm_adsp *dsp)
return 0; return 0;
} }
static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
{
return compr->buf != NULL;
}
static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
{
/*
* Note this will be more complex once each DSP can support multiple
* streams
*/
if (!compr->dsp->buffer)
return -EINVAL;
compr->buf = compr->dsp->buffer;
return 0;
}
int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
{ {
struct wm_adsp_compr *compr = stream->runtime->private_data; 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,21 +2939,41 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
avail += wm_adsp_buffer_size(buf); avail += wm_adsp_buffer_size(buf);
adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
buf->read_index, write_index, avail); buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE);
buf->avail = avail; buf->avail = avail;
return 0; return 0;
} }
static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
{
int ret;
ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
if (ret < 0) {
adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret);
return ret;
}
if (buf->error != 0) {
adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error);
return -EIO;
}
return 0;
}
int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
{ {
struct wm_adsp_compr_buf *buf = dsp->buffer; struct wm_adsp_compr_buf *buf;
struct wm_adsp_compr *compr = dsp->compr; struct wm_adsp_compr *compr;
int ret = 0; int ret = 0;
mutex_lock(&dsp->pwr_lock); mutex_lock(&dsp->pwr_lock);
buf = dsp->buffer;
compr = dsp->compr;
if (!buf) { if (!buf) {
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
...@@ -2827,16 +2981,9 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) ...@@ -2827,16 +2981,9 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
adsp_dbg(dsp, "Handling buffer IRQ\n"); adsp_dbg(dsp, "Handling buffer IRQ\n");
ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); ret = wm_adsp_buffer_get_error(buf);
if (ret < 0) { if (ret < 0)
adsp_err(dsp, "Failed to check buffer error: %d\n", ret); goto out_notify; /* Wake poll to report error */
goto out;
}
if (buf->error != 0) {
adsp_err(dsp, "Buffer error occurred: %d\n", buf->error);
ret = -EIO;
goto out;
}
ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
&buf->irq_count); &buf->irq_count);
...@@ -2851,6 +2998,7 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) ...@@ -2851,6 +2998,7 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
goto out; goto out;
} }
out_notify:
if (compr && compr->stream) if (compr && compr->stream)
snd_compr_fragment_elapsed(compr->stream); snd_compr_fragment_elapsed(compr->stream);
...@@ -2879,14 +3027,16 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, ...@@ -2879,14 +3027,16 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
struct snd_compr_tstamp *tstamp) struct snd_compr_tstamp *tstamp)
{ {
struct wm_adsp_compr *compr = stream->runtime->private_data; struct wm_adsp_compr *compr = stream->runtime->private_data;
struct wm_adsp_compr_buf *buf = compr->buf;
struct wm_adsp *dsp = compr->dsp; struct wm_adsp *dsp = compr->dsp;
struct wm_adsp_compr_buf *buf;
int ret = 0; int ret = 0;
adsp_dbg(dsp, "Pointer request\n"); adsp_dbg(dsp, "Pointer request\n");
mutex_lock(&dsp->pwr_lock); mutex_lock(&dsp->pwr_lock);
buf = compr->buf;
if (!compr->buf) { if (!compr->buf) {
ret = -ENXIO; ret = -ENXIO;
goto out; goto out;
...@@ -2909,6 +3059,10 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, ...@@ -2909,6 +3059,10 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
* DSP to inform us once a whole fragment is available. * DSP to inform us once a whole fragment is available.
*/ */
if (buf->avail < wm_adsp_compr_frag_words(compr)) { if (buf->avail < wm_adsp_compr_frag_words(compr)) {
ret = wm_adsp_buffer_get_error(buf);
if (ret < 0)
goto out;
ret = wm_adsp_buffer_reenable_irq(buf); ret = wm_adsp_buffer_reenable_irq(buf);
if (ret < 0) { if (ret < 0) {
adsp_err(dsp, adsp_err(dsp,
......
...@@ -92,6 +92,7 @@ extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; ...@@ -92,6 +92,7 @@ extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
int wm_adsp1_init(struct wm_adsp *dsp); int wm_adsp1_init(struct wm_adsp *dsp);
int wm_adsp2_init(struct wm_adsp *dsp); int wm_adsp2_init(struct wm_adsp *dsp);
void wm_adsp2_remove(struct wm_adsp *dsp);
int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec); int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec);
int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec);
int wm_adsp1_event(struct snd_soc_dapm_widget *w, int wm_adsp1_event(struct snd_soc_dapm_widget *w,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment