diff options
Diffstat (limited to 'sound/soc/omap/omap-abe-dsp.c')
-rw-r--r-- | sound/soc/omap/omap-abe-dsp.c | 176 |
1 files changed, 134 insertions, 42 deletions
diff --git a/sound/soc/omap/omap-abe-dsp.c b/sound/soc/omap/omap-abe-dsp.c index 2043cc3..0992b3f 100644 --- a/sound/soc/omap/omap-abe-dsp.c +++ b/sound/soc/omap/omap-abe-dsp.c @@ -117,12 +117,15 @@ struct abe_data { /* coefficients */ struct fw_header hdr; + u32 *firmware; s32 *equ[ABE_MAX_EQU]; int equ_profile[ABE_MAX_EQU]; struct soc_enum equalizer_enum[ABE_MAX_EQU]; struct snd_kcontrol_new equalizer_control[ABE_MAX_EQU]; struct coeff_config *equ_texts; + int mono_mix[ABE_NUM_MONO_MIXERS]; + /* DAPM mixer config - TODO: some of this can be replaced with HAL update */ u32 widget_opp[ABE_NUM_DAPM_REG + 1]; @@ -450,6 +453,55 @@ static int abe_get_mixer(struct snd_kcontrol *kcontrol, return 0; } +static int abe_dsp_set_mono_mixer(int id, int enable) +{ + int mixer; + + switch (id) { + case MIX_DL1_MONO: + mixer = MIXDL1; + break; + case MIX_DL2_MONO: + mixer = MIXDL2; + break; + case MIX_AUDUL_MONO: + mixer = MIXAUDUL; + break; + default: + return -EINVAL; + } + + pm_runtime_get_sync(the_abe->dev); + abe_mono_mixer(mixer, enable); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + +static int abe_put_mono_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int id = mc->shift - MIX_DL1_MONO; + + the_abe->mono_mix[id] = ucontrol->value.integer.value[0]; + abe_dsp_set_mono_mixer(mc->shift, the_abe->mono_mix[id]); + + return 1; +} + +static int abe_get_mono_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int id = mc->shift - MIX_DL1_MONO; + + ucontrol->value.integer.value[0] = the_abe->mono_mix[id]; + return 0; +} + /* router IDs that match our mixer strings */ static const abe_router_t router[] = { ZERO_labelID, /* strangely this is not 0 */ @@ -732,38 +784,50 @@ static int volume_get_gain(struct snd_kcontrol *kcontrol, return 0; } +static int abe_dsp_set_equalizer(unsigned int id, unsigned int profile) +{ + abe_equ_t equ_params; + int len; + + if (id >= the_abe->hdr.num_equ) + return -EINVAL; + + if (profile >= the_abe->equ_texts[id].count) + return -EINVAL; + + len = the_abe->equ_texts[id].coeff; + equ_params.equ_length = len; + memcpy(equ_params.coef.type1, the_abe->equ[id] + profile * len, + len * sizeof(u32)); + the_abe->equ_profile[id] = profile; + + pm_runtime_get_sync(the_abe->dev); + abe_write_equalizer(id + 1, &equ_params); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + static int abe_get_equalizer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { -#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) struct soc_enum *eqc = (struct soc_enum *)kcontrol->private_value; ucontrol->value.integer.value[0] = the_abe->equ_profile[eqc->reg]; -#endif return 0; } static int abe_put_equalizer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { -#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) struct soc_enum *eqc = (struct soc_enum *)kcontrol->private_value; u16 val = ucontrol->value.enumerated.item[0]; - abe_equ_t equ_params; - int size; - - if (val >= the_abe->hdr.num_equ) - return -EINVAL; + int ret; - equ_params.equ_length = the_abe->equ_texts[eqc->reg].coeff; - size = the_abe->equ_texts[eqc->reg].coeff * sizeof(s32); - memcpy(equ_params.coef.type1, the_abe->equ[eqc->reg] + val * size, size); - the_abe->equ_profile[eqc->reg] = val; + ret = abe_dsp_set_equalizer(eqc->reg, val); + if (ret < 0) + return ret; - pm_runtime_get_sync(the_abe->dev); - abe_write_equalizer(eqc->reg, &equ_params); - pm_runtime_put_sync(the_abe->dev); -#endif return 1; } @@ -1008,6 +1072,13 @@ static const struct snd_kcontrol_new abe_controls[] = { SOC_DOUBLE_EXT_TLV("BT UL Volume", GAINS_BTUL, GAIN_LEFT_OFFSET, GAIN_RIGHT_OFFSET, 149, 0, volume_get_gain, volume_put_gain, btul_tlv), + + SOC_SINGLE_EXT("DL1 Mono Mixer", MIXDL1, MIX_DL1_MONO, 1, 0, + abe_get_mono_mixer, abe_put_mono_mixer), + SOC_SINGLE_EXT("DL2 Mono Mixer", MIXDL2, MIX_DL2_MONO, 1, 0, + abe_get_mono_mixer, abe_put_mono_mixer), + SOC_SINGLE_EXT("AUDUL Mono Mixer", MIXAUDUL, MIX_AUDUL_MONO, 1, 0, + abe_get_mono_mixer, abe_put_mono_mixer), }; static const struct snd_soc_dapm_widget abe_dapm_widgets[] = { @@ -1876,7 +1947,7 @@ static int aess_save_context(struct abe_data *abe) static int aess_restore_context(struct abe_data *abe) { struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata; - int loss_count = 0, ret; + int i, loss_count = 0, ret; if (pdata && pdata->device_scale) { ret = pdata->device_scale(the_abe->dev, the_abe->dev, @@ -1891,7 +1962,7 @@ static int aess_restore_context(struct abe_data *abe) loss_count = pdata->get_context_loss_count(abe->dev); if (loss_count != the_abe->loss_count) - abe_reload_fw(); + abe_reload_fw(abe->firmware); /* TODO: Find a better way to save/retore gains after dor OFF mode */ abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER); @@ -1925,6 +1996,12 @@ static int aess_restore_context(struct abe_data *abe) abe_set_router_configuration(UPROUTE, 0, (u32 *)abe->router); + for (i = 0; i < abe->hdr.num_equ; i++) + abe_dsp_set_equalizer(i, abe->equ_profile[i]); + + for (i = 0; i < ABE_NUM_MONO_MIXERS; i++) + abe_dsp_set_mono_mixer(MIX_DL1_MONO + i, abe->mono_mix[i]); + return 0; } @@ -2124,7 +2201,6 @@ static int abe_add_widgets(struct snd_soc_platform *platform) struct fw_header *hdr = &abe->hdr; int i, j; -#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) /* create equalizer controls */ for (i = 0; i < hdr->num_equ; i++) { struct soc_enum *equalizer_enum = &abe->equalizer_enum[i]; @@ -2152,7 +2228,6 @@ static int abe_add_widgets(struct snd_soc_platform *platform) snd_soc_add_platform_controls(platform, abe->equalizer_control, hdr->num_equ); -#endif snd_soc_add_platform_controls(platform, abe_controls, ARRAY_SIZE(abe_controls)); @@ -2225,7 +2300,7 @@ static int abe_resume(struct snd_soc_dai *dai) { struct abe_data *abe = the_abe; struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata; - int loss_count = 0, ret = 0; + int i, loss_count = 0, ret = 0; dev_dbg(dai->dev, "%s: %s active %d\n", __func__, dai->name, dai->active); @@ -2248,7 +2323,7 @@ static int abe_resume(struct snd_soc_dai *dai) } if (loss_count != abe->loss_count) - abe_reload_fw(); + abe_reload_fw(abe->firmware); switch (dai->id) { case OMAP_ABE_DAI_PDM_UL: @@ -2283,6 +2358,9 @@ static int abe_resume(struct snd_soc_dai *dai) abe_set_router_configuration(UPROUTE, 0, (u32 *)abe->router); + for (i = 0; i < abe->hdr.num_equ; i++) + abe_dsp_set_equalizer(i, abe->equ_profile[i]); + out: pm_runtime_put_sync(abe->dev); return ret; @@ -2295,11 +2373,13 @@ out: static int abe_probe(struct snd_soc_platform *platform) { struct abe_data *abe = snd_soc_platform_get_drvdata(platform); - const struct firmware *fw; - struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata; struct opp *opp; + const u8 *fw_data; unsigned long freq = ULONG_MAX; int ret = 0, i, opp_count, offset = 0; +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) + const struct firmware *fw; +#endif abe->platform = platform; @@ -2313,14 +2393,18 @@ static int abe_probe(struct snd_soc_platform *platform) dev_err(abe->dev, "Failed to load firmware: %d\n", ret); return ret; } + fw_data = fw->data; +#else + fw_data = (u8 *)abe_get_default_fw(); +#endif /* get firmware and coefficients header info */ - memcpy(&abe->hdr, fw->data, sizeof(struct fw_header)); + memcpy(&abe->hdr, fw_data, sizeof(struct fw_header)); if (abe->hdr.firmware_size > ABE_MAX_FW_SIZE) { - dev_err(abe->dev, "Firmware too large at %d bytes: %d\n", + dev_err(abe->dev, "Firmware too large at %d bytes: %d\n", abe->hdr.firmware_size, ret); - ret = -EINVAL; - goto err_fw; + ret = -EINVAL; + goto err_fw; } dev_dbg(abe->dev, "ABE firmware size %d bytes\n", abe->hdr.firmware_size); @@ -2345,7 +2429,7 @@ static int abe_probe(struct snd_soc_platform *platform) goto err_fw; } offset = sizeof(struct fw_header); - memcpy(abe->equ_texts, fw->data + offset, + memcpy(abe->equ_texts, fw_data + offset, abe->hdr.num_equ * sizeof(struct coeff_config)); /* get coefficients from firmware */ @@ -2355,7 +2439,7 @@ static int abe_probe(struct snd_soc_platform *platform) goto err_equ; } offset += abe->hdr.num_equ * sizeof(struct coeff_config); - memcpy(abe->equ[0], fw->data + offset, abe->hdr.coeff_size); + memcpy(abe->equ[0], fw_data + offset, abe->hdr.coeff_size); /* allocate coefficient mixer texts */ dev_dbg(abe->dev, "loaded %d equalizers\n", abe->hdr.num_equ); @@ -2379,14 +2463,25 @@ static int abe_probe(struct snd_soc_platform *platform) /* initialise coefficient equalizers */ for (i = 1; i < abe->hdr.num_equ; i++) { abe->equ[i] = abe->equ[i - 1] + - abe->equ_texts[i - 1].count * abe->equ_texts[i - 1].coeff * sizeof(s32); + abe->equ_texts[i - 1].count * abe->equ_texts[i - 1].coeff; } -#endif + + /* store ABE firmware for later context restore */ + abe->firmware = kzalloc(abe->hdr.firmware_size, GFP_KERNEL); + if (abe->firmware == NULL) { + ret = -ENOMEM; + goto err_texts; + } + + memcpy(abe->firmware, + fw_data + sizeof(struct fw_header) + abe->hdr.coeff_size, + abe->hdr.firmware_size); + ret = request_irq(abe->irq, abe_irq_handler, 0, "ABE", (void *)abe); if (ret) { dev_err(platform->dev, "request for ABE IRQ %d failed %d\n", abe->irq, ret); - goto err_texts; + goto err_irq; } /* query supported opps */ @@ -2426,12 +2521,7 @@ static int abe_probe(struct snd_soc_platform *platform) abe_reset_hal(); -#if 0 -#warning fixup load fw args - //abe_load_fw(fw->data + sizeof(struct fw_header) + abe->hdr.coeff_size); -#else - abe_load_fw(); -#endif + abe_load_fw(abe->firmware); /* "tick" of the audio engine */ abe_write_event_generator(EVENT_TIMER); @@ -2450,14 +2540,16 @@ static int abe_probe(struct snd_soc_platform *platform) err_opp: rcu_read_unlock(); free_irq(abe->irq, (void *)abe); +err_irq: + kfree(abe->firmware); err_texts: -#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) for (i = 0; i < abe->hdr.num_equ; i++) kfree(abe->equalizer_enum[i].texts); kfree(abe->equ[0]); err_equ: kfree(abe->equ_texts); err_fw: +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) release_firmware(fw); #endif return ret; @@ -2470,13 +2562,13 @@ static int abe_remove(struct snd_soc_platform *platform) free_irq(abe->irq, (void *)abe); -#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) for (i = 0; i < abe->hdr.num_equ; i++) kfree(abe->equalizer_enum[i].texts); kfree(abe->equ[0]); kfree(abe->equ_texts); -#endif + kfree(abe->firmware); + pm_runtime_disable(abe->dev); return 0; |