Unverified Commit b0f2d651 authored by Danny Smith's avatar Danny Smith Committed by Mark Brown
Browse files

ASoC: adau17x1: Implemented safeload support



Safeload support has been implemented which is used
when updating for instance filter parameters using
alsa controls. Without safeload support audio can
become distorted during update.

Signed-off-by: default avatarDanny Smith <dannys@axis.com>
Signed-off-by: default avatarRobert Rosengren <robertr@axis.com>
Acked-by: default avatarLars-Peter Clausen <lars@metafoo.de>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 6bae5ea9
Loading
Loading
Loading
Loading
+75 −2
Original line number Diff line number Diff line
@@ -21,11 +21,18 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <asm/unaligned.h>

#include "sigmadsp.h"
#include "adau17x1.h"
#include "adau-utils.h"

#define ADAU17X1_SAFELOAD_TARGET_ADDRESS 0x0006
#define ADAU17X1_SAFELOAD_TRIGGER 0x0007
#define ADAU17X1_SAFELOAD_DATA 0x0001
#define ADAU17X1_SAFELOAD_DATA_SIZE 20
#define ADAU17X1_WORD_SIZE 4

static const char * const adau17x1_capture_mixer_boost_text[] = {
	"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
};
@@ -326,6 +333,17 @@ bool adau17x1_has_dsp(struct adau *adau)
}
EXPORT_SYMBOL_GPL(adau17x1_has_dsp);

static bool adau17x1_has_safeload(struct adau *adau)
{
	switch (adau->type) {
	case ADAU1761:
	case ADAU1781:
		return true;
	default:
		return false;
	}
}

static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
	int source, unsigned int freq_in, unsigned int freq_out)
{
@@ -957,6 +975,56 @@ int adau17x1_resume(struct snd_soc_component *component)
}
EXPORT_SYMBOL_GPL(adau17x1_resume);

static int adau17x1_safeload(struct sigmadsp *sigmadsp, unsigned int addr,
	const uint8_t bytes[], size_t len)
{
	uint8_t buf[ADAU17X1_WORD_SIZE];
	uint8_t data[ADAU17X1_SAFELOAD_DATA_SIZE];
	unsigned int addr_offset;
	unsigned int nbr_words;
	int ret;

	/* write data to safeload addresses. Check if len is not a multiple of
	 * 4 bytes, if so we need to zero pad.
	 */
	nbr_words = len / ADAU17X1_WORD_SIZE;
	if ((len - nbr_words * ADAU17X1_WORD_SIZE) == 0) {
		ret = regmap_raw_write(sigmadsp->control_data,
			ADAU17X1_SAFELOAD_DATA, bytes, len);
	} else {
		nbr_words++;
		memset(data, 0, ADAU17X1_SAFELOAD_DATA_SIZE);
		memcpy(data, bytes, len);
		ret = regmap_raw_write(sigmadsp->control_data,
			ADAU17X1_SAFELOAD_DATA, data,
			nbr_words * ADAU17X1_WORD_SIZE);
	}

	if (ret < 0)
		return ret;

	/* Write target address, target address is offset by 1 */
	addr_offset = addr - 1;
	put_unaligned_be32(addr_offset, buf);
	ret = regmap_raw_write(sigmadsp->control_data,
		ADAU17X1_SAFELOAD_TARGET_ADDRESS, buf, ADAU17X1_WORD_SIZE);
	if (ret < 0)
		return ret;

	/* write nbr of words to trigger address */
	put_unaligned_be32(nbr_words, buf);
	ret = regmap_raw_write(sigmadsp->control_data,
		ADAU17X1_SAFELOAD_TRIGGER, buf, ADAU17X1_WORD_SIZE);
	if (ret < 0)
		return ret;

	return 0;
}

static const struct sigmadsp_ops adau17x1_sigmadsp_ops = {
	.safeload = adau17x1_safeload,
};

int adau17x1_probe(struct device *dev, struct regmap *regmap,
	enum adau17x1_type type, void (*switch_mode)(struct device *dev),
	const char *firmware_name)
@@ -1002,8 +1070,13 @@ 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 (adau17x1_has_safeload(adau)) {
			adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap,
				&adau17x1_sigmadsp_ops, firmware_name);
		} else {
			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));