summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm_adsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r--sound/soc/codecs/wm_adsp.c191
1 files changed, 140 insertions, 51 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index f5fbadc5e7e2..d3d32b501aca 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -599,6 +599,9 @@ struct wm_coeff_ctl_ops {
struct wm_coeff_ctl {
const char *name;
const char *fw_name;
+ /* Subname is needed to match with firmware */
+ const char *subname;
+ unsigned int subname_len;
struct wm_adsp_alg_region alg_region;
struct wm_coeff_ctl_ops ops;
struct wm_adsp *dsp;
@@ -1027,8 +1030,8 @@ static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
return -ETIMEDOUT;
}
-static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
- const void *buf, size_t len)
+static int wm_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl,
+ const void *buf, size_t len)
{
struct wm_adsp *dsp = ctl->dsp;
void *scratch;
@@ -1058,6 +1061,23 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
return 0;
}
+static int wm_coeff_write_ctrl(struct wm_coeff_ctl *ctl,
+ const void *buf, size_t len)
+{
+ int ret = 0;
+
+ if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+ ret = -EPERM;
+ else if (buf != ctl->cache)
+ memcpy(ctl->cache, buf, len);
+
+ ctl->set = 1;
+ if (ctl->enabled && ctl->dsp->running)
+ ret = wm_coeff_write_ctrl_raw(ctl, buf, len);
+
+ return ret;
+}
+
static int wm_coeff_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1068,16 +1088,7 @@ static int wm_coeff_put(struct snd_kcontrol *kctl,
int ret = 0;
mutex_lock(&ctl->dsp->pwr_lock);
-
- if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
- ret = -EPERM;
- else
- memcpy(ctl->cache, p, ctl->len);
-
- ctl->set = 1;
- if (ctl->enabled && ctl->dsp->running)
- ret = wm_coeff_write_control(ctl, p, ctl->len);
-
+ ret = wm_coeff_write_ctrl(ctl, p, ctl->len);
mutex_unlock(&ctl->dsp->pwr_lock);
return ret;
@@ -1093,15 +1104,10 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
mutex_lock(&ctl->dsp->pwr_lock);
- if (copy_from_user(ctl->cache, bytes, size)) {
+ if (copy_from_user(ctl->cache, bytes, size))
ret = -EFAULT;
- } else {
- ctl->set = 1;
- if (ctl->enabled && ctl->dsp->running)
- ret = wm_coeff_write_control(ctl, ctl->cache, size);
- else if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
- ret = -EPERM;
- }
+ else
+ ret = wm_coeff_write_ctrl(ctl, ctl->cache, size);
mutex_unlock(&ctl->dsp->pwr_lock);
@@ -1132,8 +1138,8 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
return ret;
}
-static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
- void *buf, size_t len)
+static int wm_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl,
+ void *buf, size_t len)
{
struct wm_adsp *dsp = ctl->dsp;
void *scratch;
@@ -1163,29 +1169,37 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
return 0;
}
-static int wm_coeff_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *ucontrol)
+static int wm_coeff_read_ctrl(struct wm_coeff_ctl *ctl, void *buf, size_t len)
{
- 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;
int ret = 0;
- mutex_lock(&ctl->dsp->pwr_lock);
-
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
if (ctl->enabled && ctl->dsp->running)
- ret = wm_coeff_read_control(ctl, p, ctl->len);
+ return wm_coeff_read_ctrl_raw(ctl, buf, len);
else
- ret = -EPERM;
+ return -EPERM;
} else {
if (!ctl->flags && ctl->enabled && ctl->dsp->running)
- ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
+ ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
- memcpy(p, ctl->cache, ctl->len);
+ if (buf != ctl->cache)
+ memcpy(buf, ctl->cache, len);
}
+ return ret;
+}
+
+static int wm_coeff_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ 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;
+ int ret;
+
+ mutex_lock(&ctl->dsp->pwr_lock);
+ ret = wm_coeff_read_ctrl(ctl, p, ctl->len);
mutex_unlock(&ctl->dsp->pwr_lock);
return ret;
@@ -1201,15 +1215,7 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
mutex_lock(&ctl->dsp->pwr_lock);
- if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
- if (ctl->enabled && ctl->dsp->running)
- ret = wm_coeff_read_control(ctl, ctl->cache, size);
- else
- ret = -EPERM;
- } else {
- if (!ctl->flags && ctl->enabled && ctl->dsp->running)
- ret = wm_coeff_read_control(ctl, ctl->cache, size);
- }
+ ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, size);
if (!ret && copy_to_user(bytes, ctl->cache, size))
ret = -EFAULT;
@@ -1259,8 +1265,7 @@ static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
}
if (in) {
- if (in & WMFW_CTL_FLAG_READABLE)
- out |= rd;
+ out |= rd;
if (in & WMFW_CTL_FLAG_WRITEABLE)
out |= wr;
if (in & WMFW_CTL_FLAG_VOLATILE)
@@ -1338,7 +1343,7 @@ static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
* created so we don't need to do anything.
*/
if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
- ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
+ ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len);
if (ret < 0)
return ret;
}
@@ -1356,7 +1361,8 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp)
if (!ctl->enabled)
continue;
if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
- ret = wm_coeff_write_control(ctl, ctl->cache, ctl->len);
+ ret = wm_coeff_write_ctrl_raw(ctl, ctl->cache,
+ ctl->len);
if (ret < 0)
return ret;
}
@@ -1400,6 +1406,7 @@ static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl)
{
kfree(ctl->cache);
kfree(ctl->name);
+ kfree(ctl->subname);
kfree(ctl);
}
@@ -1473,6 +1480,15 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
ret = -ENOMEM;
goto err_ctl;
}
+ if (subname) {
+ ctl->subname_len = subname_len;
+ ctl->subname = kmemdup(subname,
+ strlen(subname) + 1, GFP_KERNEL);
+ if (!ctl->subname) {
+ ret = -ENOMEM;
+ goto err_ctl_name;
+ }
+ }
ctl->enabled = 1;
ctl->set = 0;
ctl->ops.xget = wm_coeff_get;
@@ -1486,7 +1502,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
if (!ctl->cache) {
ret = -ENOMEM;
- goto err_ctl_name;
+ goto err_ctl_subname;
}
list_add(&ctl->list, &dsp->ctl_list);
@@ -1509,6 +1525,8 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
err_ctl_cache:
kfree(ctl->cache);
+err_ctl_subname:
+ kfree(ctl->subname);
err_ctl_name:
kfree(ctl->name);
err_ctl:
@@ -1996,6 +2014,70 @@ out:
return ret;
}
+/*
+ * Find wm_coeff_ctl with input name as its subname
+ * If not found, return NULL
+ */
+static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp,
+ const char *name, int type,
+ unsigned int alg)
+{
+ struct wm_coeff_ctl *pos, *rslt = NULL;
+
+ list_for_each_entry(pos, &dsp->ctl_list, list) {
+ if (!pos->subname)
+ continue;
+ if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
+ pos->alg_region.alg == alg &&
+ pos->alg_region.type == type) {
+ rslt = pos;
+ break;
+ }
+ }
+
+ return rslt;
+}
+
+int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
+ unsigned int alg, void *buf, size_t len)
+{
+ struct wm_coeff_ctl *ctl;
+ struct snd_kcontrol *kcontrol;
+ int ret;
+
+ ctl = wm_adsp_get_ctl(dsp, name, type, alg);
+ if (!ctl)
+ return -EINVAL;
+
+ if (len > ctl->len)
+ return -EINVAL;
+
+ ret = wm_coeff_write_ctrl(ctl, buf, len);
+
+ kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl->name);
+ snd_ctl_notify(dsp->component->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
+
+int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
+ unsigned int alg, void *buf, size_t len)
+{
+ struct wm_coeff_ctl *ctl;
+
+ ctl = wm_adsp_get_ctl(dsp, name, type, alg);
+ if (!ctl)
+ return -EINVAL;
+
+ if (len > ctl->len)
+ return -EINVAL;
+
+ return wm_coeff_read_ctrl(ctl, buf, len);
+}
+EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
+
static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
const struct wm_adsp_alg_region *alg_region)
{
@@ -3697,11 +3779,16 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
u32 xmalg, addr, magic;
int i, ret;
+ alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
+ if (!alg_region) {
+ adsp_err(dsp, "No algorithm region found\n");
+ return -EINVAL;
+ }
+
buf = wm_adsp_buffer_alloc(dsp);
if (!buf)
return -ENOMEM;
- alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
xmalg = dsp->ops->sys_config_size / sizeof(__be32);
addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
@@ -4242,8 +4329,9 @@ static void wm_adsp_fatal_error(struct wm_adsp *dsp)
}
}
-irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)
+irqreturn_t wm_adsp2_bus_error(int irq, void *data)
{
+ struct wm_adsp *dsp = (struct wm_adsp *)data;
unsigned int val;
struct regmap *regmap = dsp->regmap;
int ret = 0;
@@ -4307,8 +4395,9 @@ error:
}
EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
-irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp)
+irqreturn_t wm_halo_bus_error(int irq, void *data)
{
+ struct wm_adsp *dsp = (struct wm_adsp *)data;
struct regmap *regmap = dsp->regmap;
unsigned int fault[6];
struct reg_sequence clear[] = {
OpenPOWER on IntegriCloud