Commit 202f5ecb authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/adau1977', 'asoc/topic/adav80x',...

Merge remote-tracking branches 'asoc/topic/adau1977', 'asoc/topic/adav80x', 'asoc/topic/arizona' and 'asoc/topic/atmel' into asoc-next
...@@ -78,11 +78,6 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev, ...@@ -78,11 +78,6 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
if (ret != 0) if (ret != 0)
return ret; return ret;
ret = regmap_update_bits(regmap, ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
ARIZONA_SUBSYS_MAX_FREQ, val);
if (ret != 0)
return ret;
if (val) if (val)
return 0; return 0;
......
...@@ -6,27 +6,22 @@ config SND_ATMEL_SOC ...@@ -6,27 +6,22 @@ config SND_ATMEL_SOC
the ATMEL SSC interface. You will also need the ATMEL SSC interface. You will also need
to select the audio interfaces to support below. to select the audio interfaces to support below.
if SND_ATMEL_SOC
config SND_ATMEL_SOC_PDC config SND_ATMEL_SOC_PDC
tristate bool
depends on SND_ATMEL_SOC
config SND_ATMEL_SOC_DMA config SND_ATMEL_SOC_DMA
tristate bool
depends on SND_ATMEL_SOC
select SND_SOC_GENERIC_DMAENGINE_PCM select SND_SOC_GENERIC_DMAENGINE_PCM
config SND_ATMEL_SOC_SSC config SND_ATMEL_SOC_SSC
tristate tristate
depends on SND_ATMEL_SOC
help
Say Y or M if you want to add support for codecs the
ATMEL SSC interface. You will also needs to select the individual
machine drivers to support below.
config SND_AT91_SOC_SAM9G20_WM8731 config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
depends on ARCH_AT91 || COMPILE_TEST depends on ARCH_AT91 || COMPILE_TEST
depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI
select SND_ATMEL_SOC_PDC select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC select SND_ATMEL_SOC_SSC
select SND_SOC_WM8731 select SND_SOC_WM8731
...@@ -37,7 +32,7 @@ config SND_AT91_SOC_SAM9G20_WM8731 ...@@ -37,7 +32,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
config SND_ATMEL_SOC_WM8904 config SND_ATMEL_SOC_WM8904
tristate "Atmel ASoC driver for boards using WM8904 codec" tristate "Atmel ASoC driver for boards using WM8904 codec"
depends on ARCH_AT91 || COMPILE_TEST depends on ARCH_AT91 || COMPILE_TEST
depends on ATMEL_SSC && SND_ATMEL_SOC && I2C depends on ATMEL_SSC && I2C
select SND_ATMEL_SOC_SSC select SND_ATMEL_SOC_SSC
select SND_ATMEL_SOC_DMA select SND_ATMEL_SOC_DMA
select SND_SOC_WM8904 select SND_SOC_WM8904
...@@ -48,10 +43,11 @@ config SND_ATMEL_SOC_WM8904 ...@@ -48,10 +43,11 @@ config SND_ATMEL_SOC_WM8904
config SND_AT91_SOC_SAM9X5_WM8731 config SND_AT91_SOC_SAM9X5_WM8731
tristate "SoC Audio support for WM8731-based at91sam9x5 board" tristate "SoC Audio support for WM8731-based at91sam9x5 board"
depends on ARCH_AT91 || COMPILE_TEST depends on ARCH_AT91 || COMPILE_TEST
depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI
select SND_ATMEL_SOC_SSC select SND_ATMEL_SOC_SSC
select SND_ATMEL_SOC_DMA select SND_ATMEL_SOC_DMA
select SND_SOC_WM8731 select SND_SOC_WM8731
help help
Say Y if you want to add support for audio SoC on an Say Y if you want to add support for audio SoC on an
at91sam9x5 based board that is using WM8731 codec. at91sam9x5 based board that is using WM8731 codec.
endif
# AT91 Platform Support # AT91 Platform Support
snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o snd-soc-atmel-pcm-$(CONFIG_SND_ATMEL_SOC_PDC) := atmel-pcm-pdc.o
snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o snd-soc-atmel-pcm-$(CONFIG_SND_ATMEL_SOC_DMA) += atmel-pcm-dma.o
snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o $(snd-soc-atmel-pcm-y)
obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
# AT91 Machine Support # AT91 Machine Support
......
...@@ -95,8 +95,9 @@ static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { ...@@ -95,8 +95,9 @@ static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
static const struct snd_soc_dapm_route intercon[] = { static const struct snd_soc_dapm_route intercon[] = {
/* speaker connected to LHPOUT */ /* speaker connected to LHPOUT/RHPOUT */
{"Ext Spk", NULL, "LHPOUT"}, {"Ext Spk", NULL, "LHPOUT"},
{"Ext Spk", NULL, "RHPOUT"},
/* mic is connected to Mic Jack, with WM8731 Mic Bias */ /* mic is connected to Mic Jack, with WM8731 Mic Bias */
{"MICIN", NULL, "Mic Bias"}, {"MICIN", NULL, "Mic Bias"},
...@@ -108,9 +109,7 @@ static const struct snd_soc_dapm_route intercon[] = { ...@@ -108,9 +109,7 @@ static const struct snd_soc_dapm_route intercon[] = {
*/ */
static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret; int ret;
printk(KERN_DEBUG printk(KERN_DEBUG
...@@ -124,10 +123,6 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) ...@@ -124,10 +123,6 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
return ret; return ret;
} }
/* not connected */
snd_soc_dapm_nc_pin(dapm, "RLINEIN");
snd_soc_dapm_nc_pin(dapm, "LLINEIN");
#ifndef ENABLE_MIC_INPUT #ifndef ENABLE_MIC_INPUT
snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic"); snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic");
#endif #endif
...@@ -158,6 +153,7 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = { ...@@ -158,6 +153,7 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
.num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets), .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets),
.dapm_routes = intercon, .dapm_routes = intercon,
.num_dapm_routes = ARRAY_SIZE(intercon), .num_dapm_routes = ARRAY_SIZE(intercon),
.fully_routed = true,
}; };
static int at91sam9g20ek_audio_probe(struct platform_device *pdev) static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
......
...@@ -202,7 +202,7 @@ static const struct snd_soc_dapm_route adau1977_dapm_routes[] = { ...@@ -202,7 +202,7 @@ static const struct snd_soc_dapm_route adau1977_dapm_routes[] = {
ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0) ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
#define ADAU1977_DC_SUB_SWITCH(x) \ #define ADAU1977_DC_SUB_SWITCH(x) \
SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \ SOC_SINGLE("ADC" #x " DC Subtraction Capture Switch", \
ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0) ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
static const struct snd_kcontrol_new adau1977_snd_controls[] = { static const struct snd_kcontrol_new adau1977_snd_controls[] = {
......
...@@ -539,7 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, ...@@ -539,7 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
unsigned int freq, int dir) unsigned int freq, int dir)
{ {
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
if (dir == SND_SOC_CLOCK_IN) { if (dir == SND_SOC_CLOCK_IN) {
switch (clk_id) { switch (clk_id) {
...@@ -622,6 +622,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, ...@@ -622,6 +622,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out) int source, unsigned int freq_in, unsigned int freq_out)
{ {
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
unsigned int pll_ctrl1 = 0; unsigned int pll_ctrl1 = 0;
unsigned int pll_ctrl2 = 0; unsigned int pll_ctrl2 = 0;
...@@ -687,7 +688,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, ...@@ -687,7 +688,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
adav80x->pll_src = source; adav80x->pll_src = source;
snd_soc_dapm_sync(&codec->dapm); snd_soc_dapm_sync(dapm);
} }
return 0; return 0;
...@@ -800,11 +801,12 @@ static struct snd_soc_dai_driver adav80x_dais[] = { ...@@ -800,11 +801,12 @@ static struct snd_soc_dai_driver adav80x_dais[] = {
static int adav80x_probe(struct snd_soc_codec *codec) static int adav80x_probe(struct snd_soc_codec *codec)
{ {
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
/* Force PLLs on for SYSCLK output */ /* Force PLLs on for SYSCLK output */
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); snd_soc_dapm_force_enable_pin(dapm, "PLL1");
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); snd_soc_dapm_force_enable_pin(dapm, "PLL2");
/* Power down S/PDIF receiver, since it is currently not supported */ /* Power down S/PDIF receiver, since it is currently not supported */
regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20); regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);
......
...@@ -851,6 +851,134 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w, ...@@ -851,6 +851,134 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
} }
EXPORT_SYMBOL_GPL(arizona_hp_ev); EXPORT_SYMBOL_GPL(arizona_hp_ev);
static int arizona_dvfs_enable(struct snd_soc_codec *codec)
{
const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int ret;
ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
if (ret) {
dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
return ret;
}
ret = regmap_update_bits(arizona->regmap,
ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
ARIZONA_SUBSYS_MAX_FREQ,
ARIZONA_SUBSYS_MAX_FREQ);
if (ret) {
dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
return ret;
}
return 0;
}
static int arizona_dvfs_disable(struct snd_soc_codec *codec)
{
const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int ret;
ret = regmap_update_bits(arizona->regmap,
ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
ARIZONA_SUBSYS_MAX_FREQ, 0);
if (ret) {
dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
return ret;
}
ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
if (ret) {
dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
return ret;
}
return 0;
}
int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret = 0;
mutex_lock(&priv->dvfs_lock);
if (!priv->dvfs_cached && !priv->dvfs_reqs) {
ret = arizona_dvfs_enable(codec);
if (ret)
goto err;
}
priv->dvfs_reqs |= flags;
err:
mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_up);
int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
unsigned int old_reqs;
int ret = 0;
mutex_lock(&priv->dvfs_lock);
old_reqs = priv->dvfs_reqs;
priv->dvfs_reqs &= ~flags;
if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
ret = arizona_dvfs_disable(codec);
mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_down);
int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret = 0;
mutex_lock(&priv->dvfs_lock);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (priv->dvfs_reqs)
ret = arizona_dvfs_enable(codec);
priv->dvfs_cached = false;
break;
case SND_SOC_DAPM_PRE_PMD:
/* We must ensure DVFS is disabled before the codec goes into
* suspend so that we are never in an illegal state of DVFS
* enabled without enough DCVDD
*/
priv->dvfs_cached = true;
if (priv->dvfs_reqs)
ret = arizona_dvfs_disable(codec);
break;
default:
break;
}
mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
void arizona_init_dvfs(struct arizona_priv *priv)
{
mutex_init(&priv->dvfs_lock);
}
EXPORT_SYMBOL_GPL(arizona_init_dvfs);
static unsigned int arizona_sysclk_48k_rates[] = { static unsigned int arizona_sysclk_48k_rates[] = {
6144000, 6144000,
12288000, 12288000,
...@@ -1266,7 +1394,7 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream, ...@@ -1266,7 +1394,7 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
int base = dai->driver->base; int base = dai->driver->base;
int i, sr_val; int i, sr_val, ret;
/* /*
* We will need to be more flexible than this in future, * We will need to be more flexible than this in future,
...@@ -1282,6 +1410,23 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream, ...@@ -1282,6 +1410,23 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
} }
sr_val = i; sr_val = i;
switch (priv->arizona->type) {
case WM5102:
case WM8997:
if (arizona_sr_vals[sr_val] >= 88200)
ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
else
ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
if (ret) {
arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
return ret;
}
break;
default:
break;
}
switch (dai_priv->clk) { switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK: case ARIZONA_CLK_SYSCLK:
switch (priv->arizona->type) { switch (priv->arizona->type) {
......
...@@ -60,6 +60,9 @@ ...@@ -60,6 +60,9 @@
#define ARIZONA_MAX_DAI 6 #define ARIZONA_MAX_DAI 6
#define ARIZONA_MAX_ADSP 4 #define ARIZONA_MAX_ADSP 4
#define ARIZONA_DVFS_SR1_RQ 0x001
#define ARIZONA_DVFS_ADSP1_RQ 0x100
struct arizona; struct arizona;
struct wm_adsp; struct wm_adsp;
...@@ -84,6 +87,10 @@ struct arizona_priv { ...@@ -84,6 +87,10 @@ struct arizona_priv {
unsigned int spk_ena:2; unsigned int spk_ena:2;
unsigned int spk_ena_pending:1; unsigned int spk_ena_pending:1;
unsigned int dvfs_reqs;
struct mutex dvfs_lock;
bool dvfs_cached;
}; };
#define ARIZONA_NUM_MIXER_INPUTS 103 #define ARIZONA_NUM_MIXER_INPUTS 103
...@@ -107,8 +114,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ...@@ -107,8 +114,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
arizona_mixer_tlv) arizona_mixer_tlv)
#define ARIZONA_MUX_ENUM_DECL(name, reg) \ #define ARIZONA_MUX_ENUM_DECL(name, reg) \
SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \ SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL( \
arizona_mixer_texts, arizona_mixer_values) name, reg, 0, 0xff, arizona_mixer_texts, arizona_mixer_values)
#define ARIZONA_MUX_CTL_DECL(name) \ #define ARIZONA_MUX_CTL_DECL(name) \
const struct snd_kcontrol_new name##_mux = \ const struct snd_kcontrol_new name##_mux = \
...@@ -245,6 +252,12 @@ struct arizona_fll { ...@@ -245,6 +252,12 @@ struct arizona_fll {
char clock_ok_name[ARIZONA_FLL_NAME_LEN]; char clock_ok_name[ARIZONA_FLL_NAME_LEN];
}; };
extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
extern void arizona_init_dvfs(struct arizona_priv *priv);
extern int arizona_init_fll(struct arizona *arizona, int id, int base, extern int arizona_init_fll(struct arizona *arizona, int id, int base,
int lock_irq, int ok_irq, struct arizona_fll *fll); int lock_irq, int ok_irq, struct arizona_fll *fll);
extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
......
...@@ -605,12 +605,56 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, ...@@ -605,12 +605,56 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
regmap_write_async(regmap, patch[i].reg, regmap_write_async(regmap, patch[i].reg,
patch[i].def); patch[i].def);
break; break;
case SND_SOC_DAPM_PRE_PMD:
break;
default:
return 0;
}
return arizona_dvfs_sysclk_ev(w, kcontrol, event);
}
static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
unsigned int v;
int ret;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
if (ret != 0) {
dev_err(codec->dev,
"Failed to read SYSCLK state: %d\n", ret);
return -EIO;
}
v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
if (v >= 3) {
ret = arizona_dvfs_up(codec, ARIZONA_DVFS_ADSP1_RQ);
if (ret) {
dev_err(codec->dev,
"Failed to raise DVFS: %d\n", ret);
return ret;
}
}
break;
case SND_SOC_DAPM_POST_PMD:
ret = arizona_dvfs_down(codec, ARIZONA_DVFS_ADSP1_RQ);
if (ret)
dev_warn(codec->dev,
"Failed to lower DVFS: %d\n", ret);
break;
default: default:
break; break;
} }
return 0; return wm_adsp2_early_event(w, kcontrol, event);
} }
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
...@@ -1036,7 +1080,8 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux = ...@@ -1036,7 +1080,8 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = { static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
0, wm5102_sysclk_ev, SND_SOC_DAPM_POST_PMU), 0, wm5102_sysclk_ev,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
...@@ -1367,7 +1412,7 @@ ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), ...@@ -1367,7 +1412,7 @@ ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
WM_ADSP2("DSP1", 0), WM_ADSP2_E("DSP1", 0, wm5102_adsp_power_ev),
SND_SOC_DAPM_OUTPUT("HPOUT1L"), SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"), SND_SOC_DAPM_OUTPUT("HPOUT1R"),
...@@ -1910,6 +1955,8 @@ static int wm5102_probe(struct platform_device *pdev) ...@@ -1910,6 +1955,8 @@ static int wm5102_probe(struct platform_device *pdev)
wm5102->core.arizona = arizona; wm5102->core.arizona = arizona;
wm5102->core.num_inputs = 6; wm5102->core.num_inputs = 6;
arizona_init_dvfs(&wm5102->core);
wm5102->core.adsp[0].part = "wm5102"; wm5102->core.adsp[0].part = "wm5102";
wm5102->core.adsp[0].num = 1; wm5102->core.adsp[0].num = 1;
wm5102->core.adsp[0].type = WMFW_ADSP2; wm5102->core.adsp[0].type = WMFW_ADSP2;
...@@ -1919,7 +1966,7 @@ static int wm5102_probe(struct platform_device *pdev) ...@@ -1919,7 +1966,7 @@ static int wm5102_probe(struct platform_device *pdev)
wm5102->core.adsp[0].mem = wm5102_dsp1_regions; wm5102->core.adsp[0].mem = wm5102_dsp1_regions;
wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions); wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions);
ret = wm_adsp2_init(&wm5102->core.adsp[0], true); ret = wm_adsp2_init(&wm5102->core.adsp[0]);
if (ret != 0) if (ret != 0)
return ret; return ret;
......
...@@ -1696,7 +1696,7 @@ static int wm5110_probe(struct platform_device *pdev) ...@@ -1696,7 +1696,7 @@ static int wm5110_probe(struct platform_device *pdev)
wm5110->core.adsp[i].num_mems wm5110->core.adsp[i].num_mems
= ARRAY_SIZE(wm5110_dsp1_regions); = ARRAY_SIZE(wm5110_dsp1_regions);
ret = wm_adsp2_init(&wm5110->core.adsp[i], false); ret = wm_adsp2_init(&wm5110->core.adsp[i]);
if (ret != 0) if (ret != 0)
return ret; return ret;
} }
......
...@@ -106,11 +106,13 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w, ...@@ -106,11 +106,13 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
regmap_write_async(regmap, patch[i].reg, regmap_write_async(regmap, patch[i].reg,
patch[i].def); patch[i].def);
break; break;
default: case SND_SOC_DAPM_PRE_PMD:
break; break;
default:
return 0;
} }
return 0; return arizona_dvfs_sysclk_ev(w, kcontrol, event);
} }
static const char *wm8997_osr_text[] = { static const char *wm8997_osr_text[] = {
...@@ -409,7 +411,8 @@ static const struct snd_kcontrol_new wm8997_aec_loopback_mux = ...@@ -409,7 +411,8 @@ static const struct snd_kcontrol_new wm8997_aec_loopback_mux =
static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = { static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
0, wm8997_sysclk_ev, SND_SOC_DAPM_POST_PMU), 0, wm8997_sysclk_ev,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
...@@ -1127,6 +1130,8 @@ static int wm8997_probe(struct platform_device *pdev) ...@@ -1127,6 +1130,8 @@ static int wm8997_probe(struct platform_device *pdev)
wm8997->core.arizona = arizona; wm8997->core.arizona = arizona;
wm8997->core.num_inputs = 4; wm8997->core.num_inputs = 4;
arizona_init_dvfs(&wm8997->core);
for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++) for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++)
wm8997->fll[i].vco_mult = 1; wm8997->fll[i].vco_mult = 1;
......
...@@ -121,6 +121,11 @@ ...@@ -121,6 +121,11 @@
#define ADSP2_WDMA_CONFIG_2 0x31 #define ADSP2_WDMA_CONFIG_2 0x31
#define ADSP2_RDMA_CONFIG_1 0x34 #define ADSP2_RDMA_CONFIG_1 0x34
#define ADSP2_SCRATCH0 0x40
#define ADSP2_SCRATCH1 0x41
#define ADSP2_SCRATCH2 0x42
#define ADSP2_SCRATCH3 0x43
/* /*
* ADSP2 Control * ADSP2 Control
*/ */
...@@ -229,16 +234,18 @@ struct wm_coeff_ctl_ops { ...@@ -229,16 +234,18 @@ struct wm_coeff_ctl_ops {
struct wm_coeff_ctl { struct wm_coeff_ctl {
const char *name; const char *name;
struct wm_adsp_alg_region region; const char *fw_name;
struct wm_adsp_alg_region alg_region;
struct wm_coeff_ctl_ops ops; struct wm_coeff_ctl_ops ops;
struct wm_adsp *adsp; struct wm_adsp *dsp;
void *private;
unsigned int enabled:1; unsigned int enabled:1;
struct list_head list; struct list_head list;
void *cache; void *cache;
unsigned int offset;
size_t len; size_t len;
unsigned int set:1; unsigned int set:1;
struct snd_kcontrol *kcontrol; struct snd_kcontrol *kcontrol;
unsigned int flags;
}; };
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
...@@ -246,9 +253,9 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, ...@@ -246,9 +253,9 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = adsp[e->shift_l].fw; ucontrol->value.integer.value[0] = dsp[e->shift_l].fw;
return 0; return 0;
} }
...@@ -258,18 +265,18 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, ...@@ -258,18 +265,18 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw) if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
return 0; return 0;
if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
return -EINVAL; return -EINVAL;
if (adsp[e->shift_l].running) if (dsp[e->shift_l].running)
return -EBUSY; return -EBUSY;
adsp[e->shift_l].fw = ucontrol->value.integer.value[0]; dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
return 0; return 0;
} }
...@@ -340,28 +347,47 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, ...@@ -340,28 +347,47 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
return NULL; return NULL;
} }
static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region, static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
unsigned int offset) unsigned int offset)
{ {
if (WARN_ON(!region)) if (WARN_ON(!mem))
return offset; return offset;
switch (region->type) { switch (mem->type) {
case WMFW_ADSP1_PM: case WMFW_ADSP1_PM:
return region->base + (offset * 3); return mem->base + (offset * 3);
case WMFW_ADSP1_DM: case WMFW_ADSP1_DM:
return region->base + (offset * 2); return mem->base + (offset * 2);
case WMFW_ADSP2_XM: case WMFW_ADSP2_XM:
return region->base + (offset * 2); return mem->base + (offset * 2);
case WMFW_ADSP2_YM: case WMFW_ADSP2_YM:
return region->base + (offset * 2); return mem->base + (offset * 2);
case WMFW_ADSP1_ZM: case WMFW_ADSP1_ZM:
return region->base + (offset * 2); return mem->base + (offset * 2);
default: default:
WARN(1, "Unknown memory region type"); WARN(1, "Unknown memory region type");
return offset; return offset;
} }
} }
static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
{
u16 scratch[4];
int ret;
ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0,
scratch, sizeof(scratch));
if (ret) {
adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
return;
}
adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
be16_to_cpu(scratch[0]),
be16_to_cpu(scratch[1]),
be16_to_cpu(scratch[2]),
be16_to_cpu(scratch[3]));
}
static int wm_coeff_info(struct snd_kcontrol *kcontrol, static int wm_coeff_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo) struct snd_ctl_elem_info *uinfo)
{ {
...@@ -372,40 +398,39 @@ static int wm_coeff_info(struct snd_kcontrol *kcontrol, ...@@ -372,40 +398,39 @@ static int wm_coeff_info(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
const void *buf, size_t len) const void *buf, size_t len)
{ {
struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
struct wm_adsp_alg_region *region = &ctl->region;
const struct wm_adsp_region *mem; const struct wm_adsp_region *mem;
struct wm_adsp *adsp = ctl->adsp; struct wm_adsp *dsp = ctl->dsp;
void *scratch; void *scratch;
int ret; int ret;
unsigned int reg; unsigned int reg;
mem = wm_adsp_find_region(adsp, region->type); mem = wm_adsp_find_region(dsp, alg_region->type);
if (!mem) { if (!mem) {
adsp_err(adsp, "No base for region %x\n", adsp_err(dsp, "No base for region %x\n",
region->type); alg_region->type);
return -EINVAL; return -EINVAL;
} }
reg = ctl->region.base; reg = ctl->alg_region.base + ctl->offset;
reg = wm_adsp_region_to_reg(mem, reg); reg = wm_adsp_region_to_reg(mem, reg);
scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA); scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
if (!scratch) if (!scratch)
return -ENOMEM; return -ENOMEM;
ret = regmap_raw_write(adsp->regmap, reg, scratch, ret = regmap_raw_write(dsp->regmap, reg, scratch,
ctl->len); ctl->len);
if (ret) { if (ret) {
adsp_err(adsp, "Failed to write %zu bytes to %x: %d\n", adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
ctl->len, reg, ret); ctl->len, reg, ret);
kfree(scratch); kfree(scratch);
return ret; return ret;
} }
adsp_dbg(adsp, "Wrote %zu bytes to %x\n", ctl->len, reg); adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
kfree(scratch); kfree(scratch);
...@@ -424,42 +449,41 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol, ...@@ -424,42 +449,41 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol,
if (!ctl->enabled) if (!ctl->enabled)
return 0; return 0;
return wm_coeff_write_control(kcontrol, p, ctl->len); return wm_coeff_write_control(ctl, p, ctl->len);
} }
static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
void *buf, size_t len) void *buf, size_t len)
{ {
struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
struct wm_adsp_alg_region *region = &ctl->region;
const struct wm_adsp_region *mem; const struct wm_adsp_region *mem;
struct wm_adsp *adsp = ctl->adsp; struct wm_adsp *dsp = ctl->dsp;
void *scratch; void *scratch;
int ret; int ret;
unsigned int reg; unsigned int reg;
mem = wm_adsp_find_region(adsp, region->type); mem = wm_adsp_find_region(dsp, alg_region->type);
if (!mem) { if (!mem) {
adsp_err(adsp, "No base for region %x\n", adsp_err(dsp, "No base for region %x\n",
region->type); alg_region->type);
return -EINVAL; return -EINVAL;
} }
reg = ctl->region.base; reg = ctl->alg_region.base + ctl->offset;
reg = wm_adsp_region_to_reg(mem, reg); reg = wm_adsp_region_to_reg(mem, reg);
scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA); scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
if (!scratch) if (!scratch)
return -ENOMEM; return -ENOMEM;
ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len); ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len);
if (ret) { if (ret) {
adsp_err(adsp, "Failed to read %zu bytes from %x: %d\n", adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
ctl->len, reg, ret); ctl->len, reg, ret);
kfree(scratch); kfree(scratch);
return ret; return ret;
} }
adsp_dbg(adsp, "Read %zu bytes from %x\n", ctl->len, reg); adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg);
memcpy(buf, scratch, ctl->len); memcpy(buf, scratch, ctl->len);
kfree(scratch); kfree(scratch);
...@@ -473,17 +497,25 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol, ...@@ -473,17 +497,25 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol,
struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
char *p = ucontrol->value.bytes.data; char *p = ucontrol->value.bytes.data;
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
if (ctl->enabled)
return wm_coeff_read_control(ctl, p, ctl->len);
else
return -EPERM;
}
memcpy(p, ctl->cache, ctl->len); memcpy(p, ctl->cache, ctl->len);
return 0; return 0;
} }
struct wmfw_ctl_work { struct wmfw_ctl_work {
struct wm_adsp *adsp; struct wm_adsp *dsp;
struct wm_coeff_ctl *ctl; struct wm_coeff_ctl *ctl;
struct work_struct work; struct work_struct work;
}; };
static int wmfw_add_ctl(struct wm_adsp *adsp, 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;
int ret; int ret;
...@@ -502,17 +534,25 @@ static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl) ...@@ -502,17 +534,25 @@ static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
kcontrol->put = wm_coeff_put; kcontrol->put = wm_coeff_put;
kcontrol->private_value = (unsigned long)ctl; kcontrol->private_value = (unsigned long)ctl;
ret = snd_soc_add_card_controls(adsp->card, if (ctl->flags) {
if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE)
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
if (ctl->flags & WMFW_CTL_FLAG_READABLE)
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
}
ret = snd_soc_add_card_controls(dsp->card,
kcontrol, 1); kcontrol, 1);
if (ret < 0) if (ret < 0)
goto err_kcontrol; goto err_kcontrol;
kfree(kcontrol); kfree(kcontrol);
ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card, ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card,
ctl->name); ctl->name);
list_add(&ctl->list, &adsp->ctl_list);
return 0; return 0;
err_kcontrol: err_kcontrol:
...@@ -520,6 +560,358 @@ static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl) ...@@ -520,6 +560,358 @@ static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
return ret; return ret;
} }
static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
{
struct wm_coeff_ctl *ctl;
int ret;
list_for_each_entry(ctl, &dsp->ctl_list, list) {
if (!ctl->enabled || ctl->set)
continue;
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
continue;
ret = wm_coeff_read_control(ctl,
ctl->cache,
ctl->len);
if (ret < 0)
return ret;
}
return 0;
}
static int wm_coeff_sync_controls(struct wm_adsp *dsp)
{
struct wm_coeff_ctl *ctl;
int ret;
list_for_each_entry(ctl, &dsp->ctl_list, list) {
if (!ctl->enabled)
continue;
if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
ret = wm_coeff_write_control(ctl,
ctl->cache,
ctl->len);
if (ret < 0)
return ret;
}
}
return 0;
}
static void wm_adsp_ctl_work(struct work_struct *work)
{
struct wmfw_ctl_work *ctl_work = container_of(work,
struct wmfw_ctl_work,
work);
wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
kfree(ctl_work);
}
static int wm_adsp_create_control(struct wm_adsp *dsp,
const struct wm_adsp_alg_region *alg_region,
unsigned int offset, unsigned int len,
const char *subname, unsigned int subname_len,
unsigned int flags)
{
struct wm_coeff_ctl *ctl;
struct wmfw_ctl_work *ctl_work;
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
char *region_name;
int ret;
if (flags & WMFW_CTL_FLAG_SYS)
return 0;
switch (alg_region->type) {
case WMFW_ADSP1_PM:
region_name = "PM";
break;
case WMFW_ADSP1_DM:
region_name = "DM";
break;
case WMFW_ADSP2_XM:
region_name = "XM";
break;
case WMFW_ADSP2_YM:
region_name = "YM";
break;
case WMFW_ADSP1_ZM:
region_name = "ZM";
break;
default:
adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
return -EINVAL;
}
switch (dsp->fw_ver) {
case 0:
case 1:
snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
dsp->num, region_name, alg_region->alg);
break;
default:
ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
"DSP%d%c %.12s %x", dsp->num, *region_name,
wm_adsp_fw_text[dsp->fw], alg_region->alg);
/* Truncate the subname from the start if it is too long */
if (subname) {
int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
int skip = 0;
if (subname_len > avail)
skip = subname_len - avail;
snprintf(name + ret,
SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s",
subname_len - skip, subname + skip);
}
break;
}
list_for_each_entry(ctl, &dsp->ctl_list,
list) {
if (!strcmp(ctl->name, name)) {
if (!ctl->enabled)
ctl->enabled = 1;
return 0;
}
}
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
if (!ctl)
return -ENOMEM;
ctl->fw_name = wm_adsp_fw_text[dsp->fw];
ctl->alg_region = *alg_region;
ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
if (!ctl->name) {
ret = -ENOMEM;
goto err_ctl;
}
ctl->enabled = 1;
ctl->set = 0;
ctl->ops.xget = wm_coeff_get;
ctl->ops.xput = wm_coeff_put;
ctl->dsp = dsp;
ctl->flags = flags;
ctl->offset = offset;
if (len > 512) {
adsp_warn(dsp, "Truncating control %s from %d\n",
ctl->name, len);
len = 512;
}
ctl->len = len;
ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
if (!ctl->cache) {
ret = -ENOMEM;
goto err_ctl_name;
}
list_add(&ctl->list, &dsp->ctl_list);
ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
if (!ctl_work) {
ret = -ENOMEM;
goto err_ctl_cache;
}
ctl_work->dsp = dsp;
ctl_work->ctl = ctl;
INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
schedule_work(&ctl_work->work);
return 0;
err_ctl_cache:
kfree(ctl->cache);
err_ctl_name:
kfree(ctl->name);
err_ctl:
kfree(ctl);
return ret;
}
struct wm_coeff_parsed_alg {
int id;
const u8 *name;
int name_len;
int ncoeff;
};
struct wm_coeff_parsed_coeff {
int offset;
int mem_type;
const u8 *name;
int name_len;
int ctl_type;
int flags;
int len;
};
static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
{
int length;
switch (bytes) {
case 1:
length = **pos;
break;
case 2:
length = le16_to_cpu(*((__le16 *)*pos));
break;
default:
return 0;
}
if (str)
*str = *pos + bytes;
*pos += ((length + bytes) + 3) & ~0x03;
return length;
}
static int wm_coeff_parse_int(int bytes, const u8 **pos)
{
int val = 0;
switch (bytes) {
case 2:
val = le16_to_cpu(*((__le16 *)*pos));
break;
case 4:
val = le32_to_cpu(*((__le32 *)*pos));
break;
default:
break;
}
*pos += bytes;
return val;
}
static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
struct wm_coeff_parsed_alg *blk)
{
const struct wmfw_adsp_alg_data *raw;
switch (dsp->fw_ver) {
case 0:
case 1:
raw = (const struct wmfw_adsp_alg_data *)*data;
*data = raw->data;
blk->id = le32_to_cpu(raw->id);
blk->name = raw->name;
blk->name_len = strlen(raw->name);
blk->ncoeff = le32_to_cpu(raw->ncoeff);
break;
default:
blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
&blk->name);
wm_coeff_parse_string(sizeof(u16), data, NULL);
blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
break;
}
adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
}
static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
struct wm_coeff_parsed_coeff *blk)
{
const struct wmfw_adsp_coeff_data *raw;
const u8 *tmp;
int length;
switch (dsp->fw_ver) {
case 0:
case 1:
raw = (const struct wmfw_adsp_coeff_data *)*data;
*data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
blk->offset = le16_to_cpu(raw->hdr.offset);
blk->mem_type = le16_to_cpu(raw->hdr.type);
blk->name = raw->name;
blk->name_len = strlen(raw->name);
blk->ctl_type = le16_to_cpu(raw->ctl_type);
blk->flags = le16_to_cpu(raw->flags);
blk->len = le32_to_cpu(raw->len);
break;
default:
tmp = *data;
blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
&blk->name);
wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
*data = *data + sizeof(raw->hdr) + length;
break;
}
adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
}
static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
const struct wmfw_region *region)
{
struct wm_adsp_alg_region alg_region = {};
struct wm_coeff_parsed_alg alg_blk;
struct wm_coeff_parsed_coeff coeff_blk;
const u8 *data = region->data;
int i, ret;
wm_coeff_parse_alg(dsp, &data, &alg_blk);
for (i = 0; i < alg_blk.ncoeff; i++) {
wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
switch (coeff_blk.ctl_type) {
case SNDRV_CTL_ELEM_TYPE_BYTES:
break;
default:
adsp_err(dsp, "Unknown control type: %d\n",
coeff_blk.ctl_type);
return -EINVAL;
}
alg_region.type = coeff_blk.mem_type;
alg_region.alg = alg_blk.id;
ret = wm_adsp_create_control(dsp, &alg_region,
coeff_blk.offset,
coeff_blk.len,
coeff_blk.name,
coeff_blk.name_len,
coeff_blk.flags);
if (ret < 0)
adsp_err(dsp, "Failed to create control: %.*s, %d\n",
coeff_blk.name_len, coeff_blk.name, ret);
}
return 0;
}
static int wm_adsp_load(struct wm_adsp *dsp) static int wm_adsp_load(struct wm_adsp *dsp)
{ {
LIST_HEAD(buf_list); LIST_HEAD(buf_list);
...@@ -568,12 +960,22 @@ static int wm_adsp_load(struct wm_adsp *dsp) ...@@ -568,12 +960,22 @@ static int wm_adsp_load(struct wm_adsp *dsp)
goto out_fw; goto out_fw;
} }
if (header->ver != 0) { switch (header->ver) {
case 0:
adsp_warn(dsp, "%s: Depreciated file format %d\n",
file, header->ver);
break;
case 1:
case 2:
break;
default:
adsp_err(dsp, "%s: unknown file format %d\n", adsp_err(dsp, "%s: unknown file format %d\n",
file, header->ver); file, header->ver);
goto out_fw; goto out_fw;
} }
adsp_info(dsp, "Firmware version: %d\n", header->ver); adsp_info(dsp, "Firmware version: %d\n", header->ver);
dsp->fw_ver = header->ver;
if (header->core != dsp->type) { if (header->core != dsp->type) {
adsp_err(dsp, "%s: invalid core %d != %d\n", adsp_err(dsp, "%s: invalid core %d != %d\n",
...@@ -638,6 +1040,12 @@ static int wm_adsp_load(struct wm_adsp *dsp) ...@@ -638,6 +1040,12 @@ static int wm_adsp_load(struct wm_adsp *dsp)
text = kzalloc(le32_to_cpu(region->len) + 1, text = kzalloc(le32_to_cpu(region->len) + 1,
GFP_KERNEL); GFP_KERNEL);
break; break;
case WMFW_ALGORITHM_DATA:
region_name = "Algorithm";
ret = wm_adsp_parse_coeff(dsp, region);
if (ret != 0)
goto out_fw;
break;
case WMFW_INFO_TEXT: case WMFW_INFO_TEXT:
region_name = "Information"; region_name = "Information";
text = kzalloc(le32_to_cpu(region->len) + 1, text = kzalloc(le32_to_cpu(region->len) + 1,
...@@ -730,444 +1138,316 @@ static int wm_adsp_load(struct wm_adsp *dsp) ...@@ -730,444 +1138,316 @@ static int wm_adsp_load(struct wm_adsp *dsp)
return ret; return ret;
} }
static int wm_coeff_init_control_caches(struct wm_adsp *adsp) static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
const struct wm_adsp_alg_region *alg_region)
{ {
struct wm_coeff_ctl *ctl; struct wm_coeff_ctl *ctl;
int ret;
list_for_each_entry(ctl, &adsp->ctl_list, list) { list_for_each_entry(ctl, &dsp->ctl_list, list) {
if (!ctl->enabled || ctl->set) if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
continue; alg_region->alg == ctl->alg_region.alg &&
ret = wm_coeff_read_control(ctl->kcontrol, alg_region->type == ctl->alg_region.type) {
ctl->cache, ctl->alg_region.base = alg_region->base;
ctl->len); }
if (ret < 0)
return ret;
} }
return 0;
} }
static int wm_coeff_sync_controls(struct wm_adsp *adsp) static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
unsigned int pos, unsigned int len)
{ {
struct wm_coeff_ctl *ctl; void *alg;
int ret; int ret;
__be32 val;
list_for_each_entry(ctl, &adsp->ctl_list, list) { if (n_algs == 0) {
if (!ctl->enabled) adsp_err(dsp, "No algorithms\n");
continue; return ERR_PTR(-EINVAL);
if (ctl->set) {
ret = wm_coeff_write_control(ctl->kcontrol,
ctl->cache,
ctl->len);
if (ret < 0)
return ret;
}
} }
return 0; if (n_algs > 1024) {
} adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
return ERR_PTR(-EINVAL);
static void wm_adsp_ctl_work(struct work_struct *work) }
{
struct wmfw_ctl_work *ctl_work = container_of(work,
struct wmfw_ctl_work,
work);
wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl);
kfree(ctl_work);
}
static int wm_adsp_create_control(struct wm_adsp *dsp,
const struct wm_adsp_alg_region *region)
{
struct wm_coeff_ctl *ctl;
struct wmfw_ctl_work *ctl_work;
char *name;
char *region_name;
int ret;
name = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!name)
return -ENOMEM;
switch (region->type) { /* Read the terminator first to validate the length */
case WMFW_ADSP1_PM: ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
region_name = "PM"; if (ret != 0) {
break; adsp_err(dsp, "Failed to read algorithm list end: %d\n",
case WMFW_ADSP1_DM: ret);
region_name = "DM"; return ERR_PTR(ret);
break;
case WMFW_ADSP2_XM:
region_name = "XM";
break;
case WMFW_ADSP2_YM:
region_name = "YM";
break;
case WMFW_ADSP1_ZM:
region_name = "ZM";
break;
default:
ret = -EINVAL;
goto err_name;
} }
snprintf(name, PAGE_SIZE, "DSP%d %s %x", if (be32_to_cpu(val) != 0xbedead)
dsp->num, region_name, region->alg); adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
pos + len, be32_to_cpu(val));
list_for_each_entry(ctl, &dsp->ctl_list, alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
list) { if (!alg)
if (!strcmp(ctl->name, name)) { return ERR_PTR(-ENOMEM);
if (!ctl->enabled)
ctl->enabled = 1;
goto found;
}
}
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
if (!ctl) { if (ret != 0) {
ret = -ENOMEM; adsp_err(dsp, "Failed to read algorithm list: %d\n",
goto err_name; ret);
} kfree(alg);
ctl->region = *region; return ERR_PTR(ret);
ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
if (!ctl->name) {
ret = -ENOMEM;
goto err_ctl;
} }
ctl->enabled = 1;
ctl->set = 0;
ctl->ops.xget = wm_coeff_get;
ctl->ops.xput = wm_coeff_put;
ctl->adsp = dsp;
ctl->len = region->len; return alg;
ctl->cache = kzalloc(ctl->len, GFP_KERNEL); }
if (!ctl->cache) {
ret = -ENOMEM;
goto err_ctl_name;
}
ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
if (!ctl_work) { int type, __be32 id,
ret = -ENOMEM; __be32 base)
goto err_ctl_cache; {
} struct wm_adsp_alg_region *alg_region;
ctl_work->adsp = dsp; alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
ctl_work->ctl = ctl; if (!alg_region)
INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); return ERR_PTR(-ENOMEM);
schedule_work(&ctl_work->work);
found: alg_region->type = type;
kfree(name); alg_region->alg = be32_to_cpu(id);
alg_region->base = be32_to_cpu(base);
return 0; list_add_tail(&alg_region->list, &dsp->alg_regions);
err_ctl_cache: if (dsp->fw_ver > 0)
kfree(ctl->cache); wm_adsp_ctl_fixup_base(dsp, alg_region);
err_ctl_name:
kfree(ctl->name); return alg_region;
err_ctl:
kfree(ctl);
err_name:
kfree(name);
return ret;
} }
static int wm_adsp_setup_algs(struct wm_adsp *dsp) static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
{ {
struct regmap *regmap = dsp->regmap;
struct wmfw_adsp1_id_hdr adsp1_id; struct wmfw_adsp1_id_hdr adsp1_id;
struct wmfw_adsp2_id_hdr adsp2_id;
struct wmfw_adsp1_alg_hdr *adsp1_alg; struct wmfw_adsp1_alg_hdr *adsp1_alg;
struct wmfw_adsp2_alg_hdr *adsp2_alg; struct wm_adsp_alg_region *alg_region;
void *alg, *buf;
struct wm_adsp_alg_region *region;
const struct wm_adsp_region *mem; const struct wm_adsp_region *mem;
unsigned int pos, term; unsigned int pos, len;
size_t algs, buf_size; size_t n_algs;
__be32 val;
int i, ret; int i, ret;
switch (dsp->type) { mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
case WMFW_ADSP1:
mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
break;
case WMFW_ADSP2:
mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
break;
default:
mem = NULL;
break;
}
if (WARN_ON(!mem)) if (WARN_ON(!mem))
return -EINVAL; return -EINVAL;
switch (dsp->type) { ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
case WMFW_ADSP1: sizeof(adsp1_id));
ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
sizeof(adsp1_id));
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm info: %d\n",
ret);
return ret;
}
buf = &adsp1_id;
buf_size = sizeof(adsp1_id);
algs = be32_to_cpu(adsp1_id.algs);
dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
dsp->fw_id,
(be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
be32_to_cpu(adsp1_id.fw.ver) & 0xff,
algs);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP1_ZM;
region->alg = be32_to_cpu(adsp1_id.fw.id);
region->base = be32_to_cpu(adsp1_id.zm);
list_add_tail(&region->list, &dsp->alg_regions);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP1_DM;
region->alg = be32_to_cpu(adsp1_id.fw.id);
region->base = be32_to_cpu(adsp1_id.dm);
list_add_tail(&region->list, &dsp->alg_regions);
pos = sizeof(adsp1_id) / 2;
term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
break;
case WMFW_ADSP2:
ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
sizeof(adsp2_id));
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm info: %d\n",
ret);
return ret;
}
buf = &adsp2_id;
buf_size = sizeof(adsp2_id);
algs = be32_to_cpu(adsp2_id.algs);
dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
dsp->fw_id,
(be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
be32_to_cpu(adsp2_id.fw.ver) & 0xff,
algs);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_XM;
region->alg = be32_to_cpu(adsp2_id.fw.id);
region->base = be32_to_cpu(adsp2_id.xm);
list_add_tail(&region->list, &dsp->alg_regions);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_YM;
region->alg = be32_to_cpu(adsp2_id.fw.id);
region->base = be32_to_cpu(adsp2_id.ym);
list_add_tail(&region->list, &dsp->alg_regions);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_ZM;
region->alg = be32_to_cpu(adsp2_id.fw.id);
region->base = be32_to_cpu(adsp2_id.zm);
list_add_tail(&region->list, &dsp->alg_regions);
pos = sizeof(adsp2_id) / 2;
term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
break;
default:
WARN(1, "Unknown DSP type");
return -EINVAL;
}
if (algs == 0) {
adsp_err(dsp, "No algorithms\n");
return -EINVAL;
}
if (algs > 1024) {
adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
buf, buf_size);
return -EINVAL;
}
/* Read the terminator first to validate the length */
ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
if (ret != 0) { if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm list end: %d\n", adsp_err(dsp, "Failed to read algorithm info: %d\n",
ret); ret);
return ret; return ret;
} }
if (be32_to_cpu(val) != 0xbedead) n_algs = be32_to_cpu(adsp1_id.n_algs);
adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
term, be32_to_cpu(val)); adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
dsp->fw_id,
alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA); (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
if (!alg) (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
return -ENOMEM; be32_to_cpu(adsp1_id.fw.ver) & 0xff,
n_algs);
ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
if (ret != 0) { alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
adsp_err(dsp, "Failed to read algorithm list: %d\n", adsp1_id.fw.id, adsp1_id.zm);
ret); if (IS_ERR(alg_region))
goto out; return PTR_ERR(alg_region);
}
alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
adsp1_alg = alg; adsp1_id.fw.id, adsp1_id.dm);
adsp2_alg = alg; if (IS_ERR(alg_region))
return PTR_ERR(alg_region);
for (i = 0; i < algs; i++) {
switch (dsp->type) { pos = sizeof(adsp1_id) / 2;
case WMFW_ADSP1: len = (sizeof(*adsp1_alg) * n_algs) / 2;
adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
i, be32_to_cpu(adsp1_alg[i].alg.id), adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, if (IS_ERR(adsp1_alg))
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, return PTR_ERR(adsp1_alg);
be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
be32_to_cpu(adsp1_alg[i].dm), for (i = 0; i < n_algs; i++) {
be32_to_cpu(adsp1_alg[i].zm)); adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
i, be32_to_cpu(adsp1_alg[i].alg.id),
region = kzalloc(sizeof(*region), GFP_KERNEL); (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
if (!region) { (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
ret = -ENOMEM; be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
goto out; be32_to_cpu(adsp1_alg[i].dm),
} be32_to_cpu(adsp1_alg[i].zm));
region->type = WMFW_ADSP1_DM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id); alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
region->base = be32_to_cpu(adsp1_alg[i].dm); adsp1_alg[i].alg.id,
region->len = 0; adsp1_alg[i].dm);
list_add_tail(&region->list, &dsp->alg_regions); if (IS_ERR(alg_region)) {
if (i + 1 < algs) { ret = PTR_ERR(alg_region);
region->len = be32_to_cpu(adsp1_alg[i + 1].dm); goto out;
region->len -= be32_to_cpu(adsp1_alg[i].dm); }
region->len *= 4; if (dsp->fw_ver == 0) {
wm_adsp_create_control(dsp, region); if (i + 1 < n_algs) {
len = be32_to_cpu(adsp1_alg[i + 1].dm);
len -= be32_to_cpu(adsp1_alg[i].dm);
len *= 4;
wm_adsp_create_control(dsp, alg_region, 0,
len, NULL, 0, 0);
} else { } else {
adsp_warn(dsp, "Missing length info for region DM with ID %x\n", adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
be32_to_cpu(adsp1_alg[i].alg.id)); be32_to_cpu(adsp1_alg[i].alg.id));
} }
}
region = kzalloc(sizeof(*region), GFP_KERNEL); alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
if (!region) { adsp1_alg[i].alg.id,
ret = -ENOMEM; adsp1_alg[i].zm);
goto out; if (IS_ERR(alg_region)) {
} ret = PTR_ERR(alg_region);
region->type = WMFW_ADSP1_ZM; goto out;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id); }
region->base = be32_to_cpu(adsp1_alg[i].zm); if (dsp->fw_ver == 0) {
region->len = 0; if (i + 1 < n_algs) {
list_add_tail(&region->list, &dsp->alg_regions); len = be32_to_cpu(adsp1_alg[i + 1].zm);
if (i + 1 < algs) { len -= be32_to_cpu(adsp1_alg[i].zm);
region->len = be32_to_cpu(adsp1_alg[i + 1].zm); len *= 4;
region->len -= be32_to_cpu(adsp1_alg[i].zm); wm_adsp_create_control(dsp, alg_region, 0,
region->len *= 4; len, NULL, 0, 0);
wm_adsp_create_control(dsp, region);
} else { } else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
be32_to_cpu(adsp1_alg[i].alg.id)); be32_to_cpu(adsp1_alg[i].alg.id));
} }
break; }
}
case WMFW_ADSP2: out:
adsp_info(dsp, kfree(adsp1_alg);
"%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", return ret;
i, be32_to_cpu(adsp2_alg[i].alg.id), }
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, {
be32_to_cpu(adsp2_alg[i].xm), struct wmfw_adsp2_id_hdr adsp2_id;
be32_to_cpu(adsp2_alg[i].ym), struct wmfw_adsp2_alg_hdr *adsp2_alg;
be32_to_cpu(adsp2_alg[i].zm)); struct wm_adsp_alg_region *alg_region;
const struct wm_adsp_region *mem;
region = kzalloc(sizeof(*region), GFP_KERNEL); unsigned int pos, len;
if (!region) { size_t n_algs;
ret = -ENOMEM; int i, ret;
goto out;
} mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
region->type = WMFW_ADSP2_XM; if (WARN_ON(!mem))
region->alg = be32_to_cpu(adsp2_alg[i].alg.id); return -EINVAL;
region->base = be32_to_cpu(adsp2_alg[i].xm);
region->len = 0; ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
list_add_tail(&region->list, &dsp->alg_regions); sizeof(adsp2_id));
if (i + 1 < algs) { if (ret != 0) {
region->len = be32_to_cpu(adsp2_alg[i + 1].xm); adsp_err(dsp, "Failed to read algorithm info: %d\n",
region->len -= be32_to_cpu(adsp2_alg[i].xm); ret);
region->len *= 4; return ret;
wm_adsp_create_control(dsp, region); }
n_algs = be32_to_cpu(adsp2_id.n_algs);
dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
dsp->fw_id,
(be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
be32_to_cpu(adsp2_id.fw.ver) & 0xff,
n_algs);
alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
adsp2_id.fw.id, adsp2_id.xm);
if (IS_ERR(alg_region))
return PTR_ERR(alg_region);
alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
adsp2_id.fw.id, adsp2_id.ym);
if (IS_ERR(alg_region))
return PTR_ERR(alg_region);
alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
adsp2_id.fw.id, adsp2_id.zm);
if (IS_ERR(alg_region))
return PTR_ERR(alg_region);
pos = sizeof(adsp2_id) / 2;
len = (sizeof(*adsp2_alg) * n_algs) / 2;
adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
if (IS_ERR(adsp2_alg))
return PTR_ERR(adsp2_alg);
for (i = 0; i < n_algs; i++) {
adsp_info(dsp,
"%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
i, be32_to_cpu(adsp2_alg[i].alg.id),
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
be32_to_cpu(adsp2_alg[i].xm),
be32_to_cpu(adsp2_alg[i].ym),
be32_to_cpu(adsp2_alg[i].zm));
alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
adsp2_alg[i].alg.id,
adsp2_alg[i].xm);
if (IS_ERR(alg_region)) {
ret = PTR_ERR(alg_region);
goto out;
}
if (dsp->fw_ver == 0) {
if (i + 1 < n_algs) {
len = be32_to_cpu(adsp2_alg[i + 1].xm);
len -= be32_to_cpu(adsp2_alg[i].xm);
len *= 4;
wm_adsp_create_control(dsp, alg_region, 0,
len, NULL, 0, 0);
} else { } else {
adsp_warn(dsp, "Missing length info for region XM with ID %x\n", adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id)); be32_to_cpu(adsp2_alg[i].alg.id));
} }
}
region = kzalloc(sizeof(*region), GFP_KERNEL); alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
if (!region) { adsp2_alg[i].alg.id,
ret = -ENOMEM; adsp2_alg[i].ym);
goto out; if (IS_ERR(alg_region)) {
} ret = PTR_ERR(alg_region);
region->type = WMFW_ADSP2_YM; goto out;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id); }
region->base = be32_to_cpu(adsp2_alg[i].ym); if (dsp->fw_ver == 0) {
region->len = 0; if (i + 1 < n_algs) {
list_add_tail(&region->list, &dsp->alg_regions); len = be32_to_cpu(adsp2_alg[i + 1].ym);
if (i + 1 < algs) { len -= be32_to_cpu(adsp2_alg[i].ym);
region->len = be32_to_cpu(adsp2_alg[i + 1].ym); len *= 4;
region->len -= be32_to_cpu(adsp2_alg[i].ym); wm_adsp_create_control(dsp, alg_region, 0,
region->len *= 4; len, NULL, 0, 0);
wm_adsp_create_control(dsp, region);
} else { } else {
adsp_warn(dsp, "Missing length info for region YM with ID %x\n", adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id)); be32_to_cpu(adsp2_alg[i].alg.id));
} }
}
region = kzalloc(sizeof(*region), GFP_KERNEL); alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
if (!region) { adsp2_alg[i].alg.id,
ret = -ENOMEM; adsp2_alg[i].zm);
goto out; if (IS_ERR(alg_region)) {
} ret = PTR_ERR(alg_region);
region->type = WMFW_ADSP2_ZM; goto out;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id); }
region->base = be32_to_cpu(adsp2_alg[i].zm); if (dsp->fw_ver == 0) {
region->len = 0; if (i + 1 < n_algs) {
list_add_tail(&region->list, &dsp->alg_regions); len = be32_to_cpu(adsp2_alg[i + 1].zm);
if (i + 1 < algs) { len -= be32_to_cpu(adsp2_alg[i].zm);
region->len = be32_to_cpu(adsp2_alg[i + 1].zm); len *= 4;
region->len -= be32_to_cpu(adsp2_alg[i].zm); wm_adsp_create_control(dsp, alg_region, 0,
region->len *= 4; len, NULL, 0, 0);
wm_adsp_create_control(dsp, region);
} else { } else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id)); be32_to_cpu(adsp2_alg[i].alg.id));
} }
break;
} }
} }
out: out:
kfree(alg); kfree(adsp2_alg);
return ret; return ret;
} }
...@@ -1354,9 +1634,9 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) ...@@ -1354,9 +1634,9 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
return ret; return ret;
} }
int wm_adsp1_init(struct wm_adsp *adsp) int wm_adsp1_init(struct wm_adsp *dsp)
{ {
INIT_LIST_HEAD(&adsp->alg_regions); INIT_LIST_HEAD(&dsp->alg_regions);
return 0; return 0;
} }
...@@ -1410,7 +1690,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, ...@@ -1410,7 +1690,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
if (ret != 0) if (ret != 0)
goto err; goto err;
ret = wm_adsp_setup_algs(dsp); ret = wm_adsp1_setup_algs(dsp);
if (ret != 0) if (ret != 0)
goto err; goto err;
...@@ -1531,35 +1811,6 @@ static void wm_adsp2_boot_work(struct work_struct *work) ...@@ -1531,35 +1811,6 @@ static void wm_adsp2_boot_work(struct work_struct *work)
return; return;
} }
if (dsp->dvfs) {
ret = regmap_read(dsp->regmap,
dsp->base + ADSP2_CLOCKING, &val);
if (ret != 0) {
adsp_err(dsp, "Failed to read clocking: %d\n", ret);
return;
}
if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
ret = regulator_enable(dsp->dvfs);
if (ret != 0) {
adsp_err(dsp,
"Failed to enable supply: %d\n",
ret);
return;
}
ret = regulator_set_voltage(dsp->dvfs,
1800000,
1800000);
if (ret != 0) {
adsp_err(dsp,
"Failed to raise supply: %d\n",
ret);
return;
}
}
}
ret = wm_adsp2_ena(dsp); ret = wm_adsp2_ena(dsp);
if (ret != 0) if (ret != 0)
return; return;
...@@ -1568,7 +1819,7 @@ static void wm_adsp2_boot_work(struct work_struct *work) ...@@ -1568,7 +1819,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
if (ret != 0) if (ret != 0)
goto err; goto err;
ret = wm_adsp_setup_algs(dsp); ret = wm_adsp2_setup_algs(dsp);
if (ret != 0) if (ret != 0)
goto err; goto err;
...@@ -1642,6 +1893,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ...@@ -1642,6 +1893,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
break; break;
case SND_SOC_DAPM_PRE_PMD: case SND_SOC_DAPM_PRE_PMD:
/* Log firmware state, it can be useful for analysis */
wm_adsp2_show_fw_status(dsp);
dsp->running = false; dsp->running = false;
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
...@@ -1653,21 +1907,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ...@@ -1653,21 +1907,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
if (dsp->dvfs) {
ret = regulator_set_voltage(dsp->dvfs, 1200000,
1800000);
if (ret != 0)
adsp_warn(dsp,
"Failed to lower supply: %d\n",
ret);
ret = regulator_disable(dsp->dvfs);
if (ret != 0)
adsp_err(dsp,
"Failed to enable supply: %d\n",
ret);
}
list_for_each_entry(ctl, &dsp->ctl_list, list) list_for_each_entry(ctl, &dsp->ctl_list, list)
ctl->enabled = 0; ctl->enabled = 0;
...@@ -1694,7 +1933,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ...@@ -1694,7 +1933,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
} }
EXPORT_SYMBOL_GPL(wm_adsp2_event); EXPORT_SYMBOL_GPL(wm_adsp2_event);
int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) int wm_adsp2_init(struct wm_adsp *dsp)
{ {
int ret; int ret;
...@@ -1702,43 +1941,16 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) ...@@ -1702,43 +1941,16 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
* Disable the DSP memory by default when in reset for a small * Disable the DSP memory by default when in reset for a small
* power saving. * power saving.
*/ */
ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL, ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
ADSP2_MEM_ENA, 0); ADSP2_MEM_ENA, 0);
if (ret != 0) { if (ret != 0) {
adsp_err(adsp, "Failed to clear memory retention: %d\n", ret); adsp_err(dsp, "Failed to clear memory retention: %d\n", ret);
return ret; return ret;
} }
INIT_LIST_HEAD(&adsp->alg_regions); INIT_LIST_HEAD(&dsp->alg_regions);
INIT_LIST_HEAD(&adsp->ctl_list); INIT_LIST_HEAD(&dsp->ctl_list);
INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work); INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
if (dvfs) {
adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
if (IS_ERR(adsp->dvfs)) {
ret = PTR_ERR(adsp->dvfs);
adsp_err(adsp, "Failed to get DCVDD: %d\n", ret);
return ret;
}
ret = regulator_enable(adsp->dvfs);
if (ret != 0) {
adsp_err(adsp, "Failed to enable DCVDD: %d\n", ret);
return ret;
}
ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
if (ret != 0) {
adsp_err(adsp, "Failed to initialise DVFS: %d\n", ret);
return ret;
}
ret = regulator_disable(adsp->dvfs);
if (ret != 0) {
adsp_err(adsp, "Failed to disable DCVDD: %d\n", ret);
return ret;
}
}
return 0; return 0;
} }
......
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
#include "wmfw.h" #include "wmfw.h"
struct regulator;
struct wm_adsp_region { struct wm_adsp_region {
int type; int type;
unsigned int base; unsigned int base;
...@@ -30,7 +28,6 @@ struct wm_adsp_alg_region { ...@@ -30,7 +28,6 @@ struct wm_adsp_alg_region {
unsigned int alg; unsigned int alg;
int type; int type;
unsigned int base; unsigned int base;
size_t len;
}; };
struct wm_adsp { struct wm_adsp {
...@@ -54,10 +51,9 @@ struct wm_adsp { ...@@ -54,10 +51,9 @@ struct wm_adsp {
int num_mems; int num_mems;
int fw; int fw;
int fw_ver;
bool running; bool running;
struct regulator *dvfs;
struct list_head ctl_list; struct list_head ctl_list;
struct work_struct boot_work; struct work_struct boot_work;
...@@ -67,19 +63,22 @@ struct wm_adsp { ...@@ -67,19 +63,22 @@ struct wm_adsp {
SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
#define WM_ADSP2(wname, num) \ #define WM_ADSP2_E(wname, num, event_fn) \
{ .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \ { .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_early_event, \ .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
.event_flags = SND_SOC_DAPM_PRE_PMU }, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \
{ .id = snd_soc_dapm_out_drv, .name = wname, \ { .id = snd_soc_dapm_out_drv, .name = wname, \
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \ .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
#define WM_ADSP2(wname, num) \
WM_ADSP2_E(wname, num, wm_adsp2_early_event)
extern const struct snd_kcontrol_new wm_adsp1_fw_controls[]; extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
extern const struct snd_kcontrol_new wm_adsp2_fw_controls[]; extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
int wm_adsp1_init(struct wm_adsp *adsp); int wm_adsp1_init(struct wm_adsp *dsp);
int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs); int wm_adsp2_init(struct wm_adsp *dsp);
int wm_adsp1_event(struct snd_soc_dapm_widget *w, int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event); struct snd_kcontrol *kcontrol, int event);
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
......
...@@ -15,6 +15,17 @@ ...@@ -15,6 +15,17 @@
#include <linux/types.h> #include <linux/types.h>
#define WMFW_MAX_ALG_NAME 256
#define WMFW_MAX_ALG_DESCR_NAME 256
#define WMFW_MAX_COEFF_NAME 256
#define WMFW_MAX_COEFF_DESCR_NAME 256
#define WMFW_CTL_FLAG_SYS 0x8000
#define WMFW_CTL_FLAG_VOLATILE 0x0004
#define WMFW_CTL_FLAG_WRITEABLE 0x0002
#define WMFW_CTL_FLAG_READABLE 0x0001
struct wmfw_header { struct wmfw_header {
char magic[4]; char magic[4];
__le32 len; __le32 len;
...@@ -61,7 +72,7 @@ struct wmfw_adsp1_id_hdr { ...@@ -61,7 +72,7 @@ struct wmfw_adsp1_id_hdr {
struct wmfw_id_hdr fw; struct wmfw_id_hdr fw;
__be32 zm; __be32 zm;
__be32 dm; __be32 dm;
__be32 algs; __be32 n_algs;
} __packed; } __packed;
struct wmfw_adsp2_id_hdr { struct wmfw_adsp2_id_hdr {
...@@ -69,7 +80,7 @@ struct wmfw_adsp2_id_hdr { ...@@ -69,7 +80,7 @@ struct wmfw_adsp2_id_hdr {
__be32 zm; __be32 zm;
__be32 xm; __be32 xm;
__be32 ym; __be32 ym;
__be32 algs; __be32 n_algs;
} __packed; } __packed;
struct wmfw_alg_hdr { struct wmfw_alg_hdr {
...@@ -90,6 +101,28 @@ struct wmfw_adsp2_alg_hdr { ...@@ -90,6 +101,28 @@ struct wmfw_adsp2_alg_hdr {
__be32 ym; __be32 ym;
} __packed; } __packed;
struct wmfw_adsp_alg_data {
__le32 id;
u8 name[WMFW_MAX_ALG_NAME];
u8 descr[WMFW_MAX_ALG_DESCR_NAME];
__le32 ncoeff;
u8 data[];
} __packed;
struct wmfw_adsp_coeff_data {
struct {
__le16 offset;
__le16 type;
__le32 size;
} hdr;
u8 name[WMFW_MAX_COEFF_NAME];
u8 descr[WMFW_MAX_COEFF_DESCR_NAME];
__le16 ctl_type;
__le16 flags;
__le32 len;
u8 data[];
} __packed;
struct wmfw_coeff_hdr { struct wmfw_coeff_hdr {
u8 magic[4]; u8 magic[4];
__le32 len; __le32 len;
...@@ -117,9 +150,10 @@ struct wmfw_coeff_item { ...@@ -117,9 +150,10 @@ struct wmfw_coeff_item {
#define WMFW_ADSP1 1 #define WMFW_ADSP1 1
#define WMFW_ADSP2 2 #define WMFW_ADSP2 2
#define WMFW_ABSOLUTE 0xf0 #define WMFW_ABSOLUTE 0xf0
#define WMFW_NAME_TEXT 0xfe #define WMFW_ALGORITHM_DATA 0xf2
#define WMFW_INFO_TEXT 0xff #define WMFW_NAME_TEXT 0xfe
#define WMFW_INFO_TEXT 0xff
#define WMFW_ADSP1_PM 2 #define WMFW_ADSP1_PM 2
#define WMFW_ADSP1_DM 3 #define WMFW_ADSP1_DM 3
......
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