| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Common code for ADAU1X61 and ADAU1X81 codecs |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2011-2014 Analog Devices Inc. |
|---|
| 5 | 6 | * Author: Lars-Peter Clausen <lars@metafoo.de> |
|---|
| 6 | | - * |
|---|
| 7 | | - * Licensed under the GPL-2 or later. |
|---|
| 8 | 7 | */ |
|---|
| 9 | 8 | |
|---|
| 10 | 9 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 21 | 20 | #include <linux/i2c.h> |
|---|
| 22 | 21 | #include <linux/spi/spi.h> |
|---|
| 23 | 22 | #include <linux/regmap.h> |
|---|
| 23 | +#include <asm/unaligned.h> |
|---|
| 24 | 24 | |
|---|
| 25 | 25 | #include "sigmadsp.h" |
|---|
| 26 | 26 | #include "adau17x1.h" |
|---|
| 27 | 27 | #include "adau-utils.h" |
|---|
| 28 | + |
|---|
| 29 | +#define ADAU17X1_SAFELOAD_TARGET_ADDRESS 0x0006 |
|---|
| 30 | +#define ADAU17X1_SAFELOAD_TRIGGER 0x0007 |
|---|
| 31 | +#define ADAU17X1_SAFELOAD_DATA 0x0001 |
|---|
| 32 | +#define ADAU17X1_SAFELOAD_DATA_SIZE 20 |
|---|
| 33 | +#define ADAU17X1_WORD_SIZE 4 |
|---|
| 28 | 34 | |
|---|
| 29 | 35 | static const char * const adau17x1_capture_mixer_boost_text[] = { |
|---|
| 30 | 36 | "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3", |
|---|
| .. | .. |
|---|
| 59 | 65 | |
|---|
| 60 | 66 | SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum), |
|---|
| 61 | 67 | }; |
|---|
| 68 | + |
|---|
| 69 | +static int adau17x1_setup_firmware(struct snd_soc_component *component, |
|---|
| 70 | + unsigned int rate); |
|---|
| 62 | 71 | |
|---|
| 63 | 72 | static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, |
|---|
| 64 | 73 | struct snd_kcontrol *kcontrol, int event) |
|---|
| .. | .. |
|---|
| 313 | 322 | { "Capture", NULL, "Right Decimator" }, |
|---|
| 314 | 323 | }; |
|---|
| 315 | 324 | |
|---|
| 316 | | -bool adau17x1_has_dsp(struct adau *adau) |
|---|
| 325 | +static bool adau17x1_has_dsp(struct adau *adau) |
|---|
| 317 | 326 | { |
|---|
| 318 | 327 | switch (adau->type) { |
|---|
| 319 | 328 | case ADAU1761: |
|---|
| .. | .. |
|---|
| 324 | 333 | return false; |
|---|
| 325 | 334 | } |
|---|
| 326 | 335 | } |
|---|
| 327 | | -EXPORT_SYMBOL_GPL(adau17x1_has_dsp); |
|---|
| 336 | + |
|---|
| 337 | +static bool adau17x1_has_safeload(struct adau *adau) |
|---|
| 338 | +{ |
|---|
| 339 | + switch (adau->type) { |
|---|
| 340 | + case ADAU1761: |
|---|
| 341 | + case ADAU1781: |
|---|
| 342 | + return true; |
|---|
| 343 | + default: |
|---|
| 344 | + return false; |
|---|
| 345 | + } |
|---|
| 346 | +} |
|---|
| 328 | 347 | |
|---|
| 329 | 348 | static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id, |
|---|
| 330 | 349 | int source, unsigned int freq_in, unsigned int freq_out) |
|---|
| .. | .. |
|---|
| 366 | 385 | case ADAU17X1_CLK_SRC_PLL_AUTO: |
|---|
| 367 | 386 | if (!adau->mclk) |
|---|
| 368 | 387 | return -EINVAL; |
|---|
| 369 | | - /* Fall-through */ |
|---|
| 388 | + fallthrough; |
|---|
| 370 | 389 | case ADAU17X1_CLK_SRC_PLL: |
|---|
| 371 | 390 | is_pll = true; |
|---|
| 372 | 391 | break; |
|---|
| .. | .. |
|---|
| 450 | 469 | ret = adau17x1_auto_pll(dai, params); |
|---|
| 451 | 470 | if (ret) |
|---|
| 452 | 471 | return ret; |
|---|
| 453 | | - /* Fall-through */ |
|---|
| 472 | + fallthrough; |
|---|
| 454 | 473 | case ADAU17X1_CLK_SRC_PLL: |
|---|
| 455 | 474 | freq = adau->pll_freq; |
|---|
| 456 | 475 | break; |
|---|
| .. | .. |
|---|
| 836 | 855 | } |
|---|
| 837 | 856 | EXPORT_SYMBOL_GPL(adau17x1_volatile_register); |
|---|
| 838 | 857 | |
|---|
| 839 | | -int adau17x1_setup_firmware(struct snd_soc_component *component, |
|---|
| 858 | +static int adau17x1_setup_firmware(struct snd_soc_component *component, |
|---|
| 840 | 859 | unsigned int rate) |
|---|
| 841 | 860 | { |
|---|
| 842 | 861 | int ret; |
|---|
| .. | .. |
|---|
| 880 | 899 | |
|---|
| 881 | 900 | return ret; |
|---|
| 882 | 901 | } |
|---|
| 883 | | -EXPORT_SYMBOL_GPL(adau17x1_setup_firmware); |
|---|
| 884 | 902 | |
|---|
| 885 | 903 | int adau17x1_add_widgets(struct snd_soc_component *component) |
|---|
| 886 | 904 | { |
|---|
| .. | .. |
|---|
| 957 | 975 | } |
|---|
| 958 | 976 | EXPORT_SYMBOL_GPL(adau17x1_resume); |
|---|
| 959 | 977 | |
|---|
| 978 | +static int adau17x1_safeload(struct sigmadsp *sigmadsp, unsigned int addr, |
|---|
| 979 | + const uint8_t bytes[], size_t len) |
|---|
| 980 | +{ |
|---|
| 981 | + uint8_t buf[ADAU17X1_WORD_SIZE]; |
|---|
| 982 | + uint8_t data[ADAU17X1_SAFELOAD_DATA_SIZE]; |
|---|
| 983 | + unsigned int addr_offset; |
|---|
| 984 | + unsigned int nbr_words; |
|---|
| 985 | + int ret; |
|---|
| 986 | + |
|---|
| 987 | + /* write data to safeload addresses. Check if len is not a multiple of |
|---|
| 988 | + * 4 bytes, if so we need to zero pad. |
|---|
| 989 | + */ |
|---|
| 990 | + nbr_words = len / ADAU17X1_WORD_SIZE; |
|---|
| 991 | + if ((len - nbr_words * ADAU17X1_WORD_SIZE) == 0) { |
|---|
| 992 | + ret = regmap_raw_write(sigmadsp->control_data, |
|---|
| 993 | + ADAU17X1_SAFELOAD_DATA, bytes, len); |
|---|
| 994 | + } else { |
|---|
| 995 | + nbr_words++; |
|---|
| 996 | + memset(data, 0, ADAU17X1_SAFELOAD_DATA_SIZE); |
|---|
| 997 | + memcpy(data, bytes, len); |
|---|
| 998 | + ret = regmap_raw_write(sigmadsp->control_data, |
|---|
| 999 | + ADAU17X1_SAFELOAD_DATA, data, |
|---|
| 1000 | + nbr_words * ADAU17X1_WORD_SIZE); |
|---|
| 1001 | + } |
|---|
| 1002 | + |
|---|
| 1003 | + if (ret < 0) |
|---|
| 1004 | + return ret; |
|---|
| 1005 | + |
|---|
| 1006 | + /* Write target address, target address is offset by 1 */ |
|---|
| 1007 | + addr_offset = addr - 1; |
|---|
| 1008 | + put_unaligned_be32(addr_offset, buf); |
|---|
| 1009 | + ret = regmap_raw_write(sigmadsp->control_data, |
|---|
| 1010 | + ADAU17X1_SAFELOAD_TARGET_ADDRESS, buf, ADAU17X1_WORD_SIZE); |
|---|
| 1011 | + if (ret < 0) |
|---|
| 1012 | + return ret; |
|---|
| 1013 | + |
|---|
| 1014 | + /* write nbr of words to trigger address */ |
|---|
| 1015 | + put_unaligned_be32(nbr_words, buf); |
|---|
| 1016 | + ret = regmap_raw_write(sigmadsp->control_data, |
|---|
| 1017 | + ADAU17X1_SAFELOAD_TRIGGER, buf, ADAU17X1_WORD_SIZE); |
|---|
| 1018 | + if (ret < 0) |
|---|
| 1019 | + return ret; |
|---|
| 1020 | + |
|---|
| 1021 | + return 0; |
|---|
| 1022 | +} |
|---|
| 1023 | + |
|---|
| 1024 | +static const struct sigmadsp_ops adau17x1_sigmadsp_ops = { |
|---|
| 1025 | + .safeload = adau17x1_safeload, |
|---|
| 1026 | +}; |
|---|
| 1027 | + |
|---|
| 960 | 1028 | int adau17x1_probe(struct device *dev, struct regmap *regmap, |
|---|
| 961 | 1029 | enum adau17x1_type type, void (*switch_mode)(struct device *dev), |
|---|
| 962 | 1030 | const char *firmware_name) |
|---|
| .. | .. |
|---|
| 1002 | 1070 | dev_set_drvdata(dev, adau); |
|---|
| 1003 | 1071 | |
|---|
| 1004 | 1072 | if (firmware_name) { |
|---|
| 1005 | | - adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL, |
|---|
| 1006 | | - firmware_name); |
|---|
| 1073 | + if (adau17x1_has_safeload(adau)) { |
|---|
| 1074 | + adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, |
|---|
| 1075 | + &adau17x1_sigmadsp_ops, firmware_name); |
|---|
| 1076 | + } else { |
|---|
| 1077 | + adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, |
|---|
| 1078 | + NULL, firmware_name); |
|---|
| 1079 | + } |
|---|
| 1007 | 1080 | if (IS_ERR(adau->sigmadsp)) { |
|---|
| 1008 | 1081 | dev_warn(dev, "Could not find firmware file: %ld\n", |
|---|
| 1009 | 1082 | PTR_ERR(adau->sigmadsp)); |
|---|