.. | .. |
---|
| 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)); |
---|