]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
ASoC: adau17x1: Implemented safeload support
authorDanny Smith <dannys@axis.com>
Tue, 21 Aug 2018 11:07:49 +0000 (13:07 +0200)
committerMark Brown <broonie@kernel.org>
Tue, 28 Aug 2018 19:34:37 +0000 (20:34 +0100)
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: Danny Smith <dannys@axis.com>
Signed-off-by: Robert Rosengren <robertr@axis.com>
Acked-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/adau17x1.c

index 57169b8ff14e3f4d02871ccbc074eb14fec5d5e5..c0bc429249fa42e6606b79e68145beb2d6d7310b 100644 (file)
 #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));