Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d48b088e authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Mark Brown
Browse files

ASoC: sigmadsp: Restructure in preparation for fw v2 support



The v2 file format of the SigmaDSP takes a more declarative style compared
to the imperative style of the v1 format. In addition some features that are
supported with v2 require the driver to keep state around for the firmware.
This requires a bit of restructuring of both the firmware loader itself and
the drivers making use of the firmware loader.

Instead of loading and executing the firmware in place when the DSP is
configured the firmware is now loaded at driver probe time. This is required
since the new firmware format will in addition to the firmware data itself
contain meta information describing the firmware and its requirements and
capabilities. Those will for example be used to restrict the supported
samplerates advertised by the driver to userspace to the list of samplerates
supported for the firmware.

This only does the restructuring required by the v2 format, but does not
yet add support for the new format itself.

Signed-off-by: default avatarLars-Peter Clausen <lars@metafoo.de>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 6b25730f
Loading
Loading
Loading
Loading
+28 −5
Original line number Diff line number Diff line
@@ -103,6 +103,8 @@ struct adau1701 {
	unsigned int sysclk;
	struct regmap *regmap;
	u8 pin_config[12];

	struct sigmadsp *sigmadsp;
};

static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -238,12 +240,14 @@ static int adau1701_reg_read(void *context, unsigned int reg,
	return 0;
}

static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv,
	unsigned int rate)
{
	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
	struct i2c_client *client = to_i2c_client(codec->dev);
	int ret;

	sigmadsp_reset(adau1701->sigmadsp);

	if (clkdiv != ADAU1707_CLKDIV_UNSET &&
	    gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
	    gpio_is_valid(adau1701->gpio_pll_mode[1])) {
@@ -284,7 +288,7 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
	 * know the correct PLL setup
	 */
	if (clkdiv != ADAU1707_CLKDIV_UNSET) {
		ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
		ret = sigmadsp_setup(adau1701->sigmadsp, rate);
		if (ret) {
			dev_warn(codec->dev, "Failed to load firmware\n");
			return ret;
@@ -385,7 +389,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
	 * firmware upload.
	 */
	if (clkdiv != adau1701->pll_clkdiv) {
		ret = adau1701_reset(codec, clkdiv);
		ret = adau1701_reset(codec, clkdiv, params_rate(params));
		if (ret < 0)
			return ret;
	}
@@ -554,6 +558,14 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
	return 0;
}

static int adau1701_startup(struct snd_pcm_substream *substream,
	struct snd_soc_dai *dai)
{
	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(dai->codec);

	return sigmadsp_restrict_params(adau1701->sigmadsp, substream);
}

#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
	SNDRV_PCM_RATE_192000)

@@ -564,6 +576,7 @@ static const struct snd_soc_dai_ops adau1701_dai_ops = {
	.set_fmt	= adau1701_set_dai_fmt,
	.hw_params	= adau1701_hw_params,
	.digital_mute	= adau1701_digital_mute,
	.startup	= adau1701_startup,
};

static struct snd_soc_dai_driver adau1701_dai = {
@@ -600,6 +613,10 @@ static int adau1701_probe(struct snd_soc_codec *codec)
	unsigned int val;
	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);

	ret = sigmadsp_attach(adau1701->sigmadsp, &codec->component);
	if (ret)
		return ret;

	/*
	 * Let the pll_clkdiv variable default to something that won't happen
	 * at runtime. That way, we can postpone the firmware download from
@@ -609,7 +626,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
	adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;

	/* initalize with pre-configured pll mode settings */
	ret = adau1701_reset(codec, adau1701->pll_clkdiv);
	ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
	if (ret < 0)
		return ret;

@@ -722,6 +739,12 @@ static int adau1701_i2c_probe(struct i2c_client *client,
	adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];

	i2c_set_clientdata(client, adau1701);

	adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, NULL,
		ADAU1701_FIRMWARE);
	if (IS_ERR(adau1701->sigmadsp))
		return PTR_ERR(adau1701->sigmadsp);

	ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
			&adau1701_dai, 1);
	return ret;
+10 −11
Original line number Diff line number Diff line
@@ -698,11 +698,6 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
			ARRAY_SIZE(adau1761_dapm_routes));
		if (ret)
			return ret;

		ret = adau17x1_load_firmware(adau, codec->dev,
			ADAU1761_FIRMWARE);
		if (ret)
			dev_warn(codec->dev, "Failed to firmware\n");
	}

	ret = adau17x1_add_routes(codec);
@@ -771,16 +766,20 @@ int adau1761_probe(struct device *dev, struct regmap *regmap,
	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
{
	struct snd_soc_dai_driver *dai_drv;
	const char *firmware_name;
	int ret;

	ret = adau17x1_probe(dev, regmap, type, switch_mode);
	if (ret)
		return ret;

	if (type == ADAU1361)
	if (type == ADAU1361) {
		dai_drv = &adau1361_dai_driver;
	else
		firmware_name = NULL;
	} else {
		dai_drv = &adau1761_dai_driver;
		firmware_name = ADAU1761_FIRMWARE;
	}

	ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
	if (ret)
		return ret;

	return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
}
+13 −17
Original line number Diff line number Diff line
@@ -385,7 +385,6 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
{
	struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
	struct adau *adau = snd_soc_codec_get_drvdata(codec);
	const char *firmware;
	int ret;

	ret = adau17x1_add_widgets(codec);
@@ -422,25 +421,10 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
			return ret;
	}

	switch (adau->type) {
	case ADAU1381:
		firmware = ADAU1381_FIRMWARE;
		break;
	case ADAU1781:
		firmware = ADAU1781_FIRMWARE;
		break;
	default:
		return -EINVAL;
	}

	ret = adau17x1_add_routes(codec);
	if (ret < 0)
		return ret;

	ret = adau17x1_load_firmware(adau, codec->dev, firmware);
	if (ret)
		dev_warn(codec->dev, "Failed to load firmware\n");

	return 0;
}

@@ -495,9 +479,21 @@ EXPORT_SYMBOL_GPL(adau1781_regmap_config);
int adau1781_probe(struct device *dev, struct regmap *regmap,
	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
{
	const char *firmware_name;
	int ret;

	ret = adau17x1_probe(dev, regmap, type, switch_mode);
	switch (type) {
	case ADAU1381:
		firmware_name = ADAU1381_FIRMWARE;
		break;
	case ADAU1781:
		firmware_name = ADAU1781_FIRMWARE;
		break;
	default:
		return -EINVAL;
	}

	ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
	if (ret)
		return ret;

+48 −6
Original line number Diff line number Diff line
@@ -307,6 +307,7 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
	struct adau *adau = snd_soc_codec_get_drvdata(codec);
	unsigned int val, div, dsp_div;
	unsigned int freq;
	int ret;

	if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
		freq = adau->pll_freq;
@@ -356,6 +357,12 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
		regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
	}

	if (adau->sigmadsp) {
		ret = adau17x1_setup_firmware(adau, params_rate(params));
		if (ret < 0)
			return ret;
	}

	if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
		return 0;

@@ -661,12 +668,24 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
	return 0;
}

static int adau17x1_startup(struct snd_pcm_substream *substream,
	struct snd_soc_dai *dai)
{
	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);

	if (adau->sigmadsp)
		return sigmadsp_restrict_params(adau->sigmadsp, substream);

	return 0;
}

const struct snd_soc_dai_ops adau17x1_dai_ops = {
	.hw_params	= adau17x1_hw_params,
	.set_sysclk	= adau17x1_set_dai_sysclk,
	.set_fmt	= adau17x1_set_dai_fmt,
	.set_pll	= adau17x1_set_dai_pll,
	.set_tdm_slot	= adau17x1_set_dai_tdm_slot,
	.startup	= adau17x1_startup,
};
EXPORT_SYMBOL_GPL(adau17x1_dai_ops);

@@ -745,8 +764,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
}
EXPORT_SYMBOL_GPL(adau17x1_volatile_register);

int adau17x1_load_firmware(struct adau *adau, struct device *dev,
	const char *firmware)
int adau17x1_setup_firmware(struct adau *adau, unsigned int rate)
{
	int ret;
	int dspsr;
@@ -758,7 +776,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,
	regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
	regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);

	ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware);
	ret = sigmadsp_setup(adau->sigmadsp, rate);
	if (ret) {
		regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
		return ret;
@@ -767,7 +785,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,

	return 0;
}
EXPORT_SYMBOL_GPL(adau17x1_load_firmware);
EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);

int adau17x1_add_widgets(struct snd_soc_codec *codec)
{
@@ -787,8 +805,21 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
		ret = snd_soc_dapm_new_controls(&codec->dapm,
			adau17x1_dsp_dapm_widgets,
			ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
	}
		if (ret)
			return ret;

		if (!adau->sigmadsp)
			return 0;

		ret = sigmadsp_attach(adau->sigmadsp, &codec->component);
		if (ret) {
			dev_err(codec->dev, "Failed to attach firmware: %d\n",
				ret);
			return ret;
		}
	}

	return 0;
}
EXPORT_SYMBOL_GPL(adau17x1_add_widgets);

@@ -829,7 +860,8 @@ int adau17x1_resume(struct snd_soc_codec *codec)
EXPORT_SYMBOL_GPL(adau17x1_resume);

int adau17x1_probe(struct device *dev, struct regmap *regmap,
	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
	enum adau17x1_type type, void (*switch_mode)(struct device *dev),
	const char *firmware_name)
{
	struct adau *adau;

@@ -846,6 +878,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,

	dev_set_drvdata(dev, adau);

	if (firmware_name) {
		adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
			firmware_name);
		if (IS_ERR(adau->sigmadsp)) {
			dev_warn(dev, "Could not find firmware file: %ld\n",
				PTR_ERR(adau->sigmadsp));
			adau->sigmadsp = NULL;
		}
	}

	if (switch_mode)
		switch_mode(dev);

+6 −3
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@
#include <linux/regmap.h>
#include <linux/platform_data/adau17x1.h>

#include "sigmadsp.h"

enum adau17x1_type {
	ADAU1361,
	ADAU1761,
@@ -42,12 +44,14 @@ struct adau {
	bool dsp_bypass[2];

	struct regmap *regmap;
	struct sigmadsp *sigmadsp;
};

int adau17x1_add_widgets(struct snd_soc_codec *codec);
int adau17x1_add_routes(struct snd_soc_codec *codec);
int adau17x1_probe(struct device *dev, struct regmap *regmap,
	enum adau17x1_type type, void (*switch_mode)(struct device *dev));
	enum adau17x1_type type, void (*switch_mode)(struct device *dev),
	const char *firmware_name);
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
	enum adau17x1_micbias_voltage micbias);
bool adau17x1_readable_register(struct device *dev, unsigned int reg);
@@ -56,8 +60,7 @@ int adau17x1_resume(struct snd_soc_codec *codec);

extern const struct snd_soc_dai_ops adau17x1_dai_ops;

int adau17x1_load_firmware(struct adau *adau, struct device *dev,
	const char *firmware);
int adau17x1_setup_firmware(struct adau *adau, unsigned int rate);
bool adau17x1_has_dsp(struct adau *adau);

#define ADAU17X1_CLOCK_CONTROL			0x4000
Loading