From 965cc040bf0698e81b0c0aef359ae650b42b428e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 20 May 2024 16:19:56 +0200 Subject: ASoC: Constify channel mapping array arguments in set_channel_map() There is no need for implementations of DAI set_channel_map() to modify contents of passed arrays with actual channel mapping. Additionally, the caller keeps full ownership of the array. Constify these pointer arguments so the code will be safer and easier to read (documenting the caller's ownership). Acked-by: Charles Keepax Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240520-asoc-x1e80100-4-channel-mapping-v4-1-f657159b4aad@linaro.org Signed-off-by: Mark Brown --- include/sound/cs35l41.h | 4 ++-- include/sound/soc-dai.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index bb70782d15d0..43c6a9ef8d9f 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -896,8 +896,8 @@ int cs35l41_test_key_lock(struct device *dev, struct regmap *regmap); int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap); int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid); int cs35l41_set_channels(struct device *dev, struct regmap *reg, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot); + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot); int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg); void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_dsp *dsp); int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap, diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index adcd8719d343..15ef268c9845 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -188,8 +188,8 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot); + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot); int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); @@ -305,8 +305,8 @@ struct snd_soc_dai_ops { unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); int (*set_channel_map)(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot); + unsigned int tx_num, const unsigned int *tx_slot, + unsigned int rx_num, const unsigned int *rx_slot); int (*get_channel_map)(struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); -- cgit v1.2.3 From 734447685ecc7c6328e40cb1bd4aaeeac03c1413 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 May 2024 19:37:20 +0200 Subject: ASoC: topology: Constify an argument of snd_soc_tplg_component_load() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit snd_soc_tplg_component_load() does not modify its "*ops" argument. It only read some values and stores it in "soc_tplg.ops". This argument and the ops field in "struct soc_tplg" can be made const. Signed-off-by: Christophe JAILLET Reviewed-by: Amadeusz Sławiński Link: https://msgid.link/r/f2f983e791d7f941a95556bb147f426a345d84d4.1715526069.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 2 +- sound/soc/soc-topology.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index f055c6917f6c..1eedd203ac29 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -178,7 +178,7 @@ static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr) /* Dynamic Object loading and removal for component drivers */ int snd_soc_tplg_component_load(struct snd_soc_component *comp, - struct snd_soc_tplg_ops *ops, const struct firmware *fw); + const struct snd_soc_tplg_ops *ops, const struct firmware *fw); int snd_soc_tplg_component_remove(struct snd_soc_component *comp); /* Binds event handlers to dynamic widgets */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 90ca37e008b3..b00ec01361c2 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -73,7 +73,7 @@ struct soc_tplg { int bytes_ext_ops_count; /* optional fw loading callbacks to component drivers */ - struct snd_soc_tplg_ops *ops; + const struct snd_soc_tplg_ops *ops; }; /* check we dont overflow the data for this control chunk */ @@ -2334,7 +2334,7 @@ static int soc_tplg_load(struct soc_tplg *tplg) /* load audio component topology from "firmware" file */ int snd_soc_tplg_component_load(struct snd_soc_component *comp, - struct snd_soc_tplg_ops *ops, const struct firmware *fw) + const struct snd_soc_tplg_ops *ops, const struct firmware *fw) { struct soc_tplg tplg; int ret; -- cgit v1.2.3 From 8cb3aeebcb86088e30232277c9bee9054837442b Mon Sep 17 00:00:00 2001 From: Mohan Kumar Date: Mon, 27 May 2024 12:56:06 +0000 Subject: ASoC: simple-card-utils: Split simple_fixup_sample_fmt func Split the simple_fixup_sample_fmt() into two functions by adding one more function named simple_util_get_sample_fmt() to return the sample format value. This is useful for drivers that wish to simply get the sample format without setting the mask. Signed-off-by: Mohan Kumar Signed-off-by: Sameer Pujar Link: https://msgid.link/r/20240527125608.2461300-2-spujar@nvidia.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 ++ sound/soc/generic/simple-card-utils.c | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ad67957b7b48..2c2279d082ec 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -174,6 +174,8 @@ void simple_util_parse_convert(struct device_node *np, char *prefix, struct simple_util_data *data); bool simple_util_is_convert_required(const struct simple_util_data *data); +int simple_util_get_sample_fmt(struct simple_util_data *data); + int simple_util_parse_routing(struct snd_soc_card *card, char *prefix); int simple_util_parse_widgets(struct snd_soc_card *card, diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index b4876b4f259d..852989611362 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -13,12 +13,11 @@ #include #include -static void simple_fixup_sample_fmt(struct simple_util_data *data, - struct snd_pcm_hw_params *params) +int simple_util_get_sample_fmt(struct simple_util_data *data) { int i; - struct snd_mask *mask = hw_param_mask(params, - SNDRV_PCM_HW_PARAM_FORMAT); + int val = -EINVAL; + struct { char *fmt; u32 val; @@ -33,11 +32,26 @@ static void simple_fixup_sample_fmt(struct simple_util_data *data, for (i = 0; i < ARRAY_SIZE(of_sample_fmt_table); i++) { if (!strcmp(data->convert_sample_format, of_sample_fmt_table[i].fmt)) { - snd_mask_none(mask); - snd_mask_set(mask, of_sample_fmt_table[i].val); + val = of_sample_fmt_table[i].val; break; } } + return val; +} +EXPORT_SYMBOL_GPL(simple_util_get_sample_fmt); + +static void simple_fixup_sample_fmt(struct simple_util_data *data, + struct snd_pcm_hw_params *params) +{ + int val; + struct snd_mask *mask = hw_param_mask(params, + SNDRV_PCM_HW_PARAM_FORMAT); + + val = simple_util_get_sample_fmt(data); + if (val >= 0) { + snd_mask_none(mask); + snd_mask_set(mask, val); + } } void simple_util_parse_convert(struct device_node *np, -- cgit v1.2.3 From 1deba6e24c221c61c6eab8656a53f8c17035932b Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Mon, 27 May 2024 14:35:47 -0500 Subject: ASoC: SOF: sof-audio: add sof_dai_get_tdm_slots function An new interface, sof_dai_get_tdm_slots(), is added for machine driver to get tdm slot number from topology. The dai_get_param() callback needs to support new parameter type SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS by returning the tdm slot number of specific SSP port. Reviewed-by: Bard Liao Signed-off-by: Brent Lu Signed-off-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240527193552.165567-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 1 + sound/soc/sof/sof-audio.c | 10 ++++++++++ sound/soc/sof/sof-audio.h | 5 +++-- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound/sof.h b/include/sound/sof.h index ec6c30d54592..64fd5504cb2b 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -173,5 +173,6 @@ struct sof_dev_desc { int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd); int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd); +int sof_dai_get_tdm_slots(struct snd_soc_pcm_runtime *rtd); #endif diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 2421a115747e..881eec38c2e2 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -1016,3 +1016,13 @@ int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_BCLK); } EXPORT_SYMBOL(sof_dai_get_bclk); + +/* + * Helper to get SSP TDM slot number from a pcm_runtime. + * Return 0 if not exist. + */ +int sof_dai_get_tdm_slots(struct snd_soc_pcm_runtime *rtd) +{ + return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS); +} +EXPORT_SYMBOL(sof_dai_get_tdm_slots); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index abb2a00c520d..49be02234fc3 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -44,8 +44,9 @@ #define WIDGET_IS_AIF_OR_DAI(id) (WIDGET_IS_DAI(id) || WIDGET_IS_AIF(id)) #define WIDGET_IS_COPIER(id) (WIDGET_IS_AIF_OR_DAI(id) || (id) == snd_soc_dapm_buffer) -#define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 -#define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 +#define SOF_DAI_PARAM_INTEL_SSP_MCLK 0 +#define SOF_DAI_PARAM_INTEL_SSP_BCLK 1 +#define SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS 2 enum sof_widget_op { SOF_WIDGET_PREPARE, -- cgit v1.2.3 From 45919c28134519080a85a5fb66d0f65955ef7572 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 May 2024 05:05:14 +0000 Subject: ASoC: simple-card-utils: remove both playback/capture_only check soc-pcm.c :: soc_get_playback_capture() will indicate error if both playback_only / capture_only were true. Thus, graph_util_parse_link_direction() which setup playback_only / capture_only don't need to check it. And, its return value is not used on existing driver. Let's remove it. Signed-off-by: Kuninori Morimoto Link: https://msgid.link/r/87a5kah6gm.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/simple-card-utils.c | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 2c2279d082ec..0a6435ac5c5f 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -197,7 +197,7 @@ int graph_util_is_ports0(struct device_node *port); int graph_util_parse_dai(struct device *dev, struct device_node *ep, struct snd_soc_dai_link_component *dlc, int *is_single_link); -int graph_util_parse_link_direction(struct device_node *np, +void graph_util_parse_link_direction(struct device_node *np, bool *is_playback_only, bool *is_capture_only); #ifdef DEBUG diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 852989611362..bc4d518c35cb 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -1140,7 +1140,7 @@ parse_dai_end: } EXPORT_SYMBOL_GPL(graph_util_parse_dai); -int graph_util_parse_link_direction(struct device_node *np, +void graph_util_parse_link_direction(struct device_node *np, bool *playback_only, bool *capture_only) { bool is_playback_only = false; @@ -1149,13 +1149,8 @@ int graph_util_parse_link_direction(struct device_node *np, is_playback_only = of_property_read_bool(np, "playback-only"); is_capture_only = of_property_read_bool(np, "capture-only"); - if (is_playback_only && is_capture_only) - return -EINVAL; - *playback_only = is_playback_only; *capture_only = is_capture_only; - - return 0; } EXPORT_SYMBOL_GPL(graph_util_parse_link_direction); -- cgit v1.2.3 From 0b7e448119428e1dcb854abb5855f66966fb82dc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 28 May 2024 14:29:33 -0500 Subject: ACPI: utils: introduce acpi_get_local_u64_address() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ACPI _ADR is a 64-bit value. We changed the definitions in commit ca6f998cf9a2 ("ACPI: bus: change _ADR representation to 64 bits") but some helpers still assume the value is a 32-bit value. This patch adds a new helper to extract the full 64-bits. The existing 32-bit helper is kept for backwards-compatibility and cases where the _ADR is known to fit in a 32-bit value. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Acked-by: Rafael J. Wysocki Reviewed-by: Takashi Iwai Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240528192936.16180-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- drivers/acpi/utils.c | 16 +++++++++++++--- include/linux/acpi.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 202234ba54bd..ae9384282273 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -277,15 +277,25 @@ acpi_evaluate_integer(acpi_handle handle, EXPORT_SYMBOL(acpi_evaluate_integer); -int acpi_get_local_address(acpi_handle handle, u32 *addr) +int acpi_get_local_u64_address(acpi_handle handle, u64 *addr) { - unsigned long long adr; acpi_status status; - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, addr); if (ACPI_FAILURE(status)) return -ENODATA; + return 0; +} +EXPORT_SYMBOL(acpi_get_local_u64_address); + +int acpi_get_local_address(acpi_handle handle, u32 *addr) +{ + u64 adr; + int ret; + ret = acpi_get_local_u64_address(handle, &adr); + if (ret < 0) + return ret; *addr = (u32)adr; return 0; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 28c3fb2bef0d..65e7177bcb02 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -761,6 +761,7 @@ static inline u64 acpi_arch_get_root_pointer(void) } #endif +int acpi_get_local_u64_address(acpi_handle handle, u64 *addr); int acpi_get_local_address(acpi_handle handle, u32 *addr); const char *acpi_get_subsystem_id(acpi_handle handle); -- cgit v1.2.3 From 163f10b2935362f0e8ef8d7fadd0b5aa33e9130f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Jun 2024 08:47:07 +0200 Subject: PCI: Add INTEL_HDA_PTL to pci_ids.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More PCI ids for Intel audio. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Acked-by: Bjorn Helgaas Link: https://lore.kernel.org/r/20240612064709.51141-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 942a587bb97e..0168c6a60148 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -3112,6 +3112,7 @@ #define PCI_DEVICE_ID_INTEL_HDA_LNL_P 0xa828 #define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 #define PCI_DEVICE_ID_INTEL_HDA_BMG 0xe2f7 +#define PCI_DEVICE_ID_INTEL_HDA_PTL 0xe428 #define PCI_DEVICE_ID_INTEL_HDA_CML_R 0xf0c8 #define PCI_DEVICE_ID_INTEL_HDA_RKL_S 0xf1c8 -- cgit v1.2.3 From 1c75adb22d49ca9389333ca5e6939052a7203111 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 13 Jun 2024 22:59:09 +0200 Subject: ASoC: SOF: mediatek: Constify struct mtk_adsp_ipc_ops 'struct mtk_adsp_ipc_ops' is not modified in these drivers. Constifying this structure moves some data to a read-only section, so increase overall security. In order to do it, "struct mtk_adsp_ipc" also needs to be adjusted to this new const qualifier. On a x86_64, with allmodconfig: Before: ====== text data bss dec hex filename 15533 2383 0 17916 45fc sound/soc/sof/mediatek/mt8195/mt8195.o After: ===== text data bss dec hex filename 15557 2367 0 17924 4604 sound/soc/sof/mediatek/mt8195/mt8195.o Signed-off-by: Christophe JAILLET Link: https://msgid.link/r/a45d6b2b5ec040ea0fc78fca662c2dca3f13a49f.1718312321.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- include/linux/firmware/mediatek/mtk-adsp-ipc.h | 2 +- sound/soc/sof/mediatek/mt8186/mt8186.c | 2 +- sound/soc/sof/mediatek/mt8195/mt8195.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/firmware/mediatek/mtk-adsp-ipc.h b/include/linux/firmware/mediatek/mtk-adsp-ipc.h index 5b1d16fa3f56..6e86799a7dc4 100644 --- a/include/linux/firmware/mediatek/mtk-adsp-ipc.h +++ b/include/linux/firmware/mediatek/mtk-adsp-ipc.h @@ -40,7 +40,7 @@ struct mtk_adsp_chan { struct mtk_adsp_ipc { struct mtk_adsp_chan chans[MTK_ADSP_MBOX_NUM]; struct device *dev; - struct mtk_adsp_ipc_ops *ops; + const struct mtk_adsp_ipc_ops *ops; void *private_data; }; diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index bea1b9d9ca28..74522400207e 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -82,7 +82,7 @@ static void mt8186_dsp_handle_request(struct mtk_adsp_ipc *ipc) } } -static struct mtk_adsp_ipc_ops dsp_ops = { +static const struct mtk_adsp_ipc_ops dsp_ops = { .handle_reply = mt8186_dsp_handle_reply, .handle_request = mt8186_dsp_handle_request, }; diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 31dc98d1b1d8..24ae1d4959be 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -82,7 +82,7 @@ static void mt8195_dsp_handle_request(struct mtk_adsp_ipc *ipc) } } -static struct mtk_adsp_ipc_ops dsp_ops = { +static const struct mtk_adsp_ipc_ops dsp_ops = { .handle_reply = mt8195_dsp_handle_reply, .handle_request = mt8195_dsp_handle_request, }; -- cgit v1.2.3 From d4a7d067e061c95c6387cf537258082074a4d299 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 14:57:34 +0200 Subject: ASoC: soc-dai.h: Constify DAI ops auto_selectable_formats The core ASoC code does not modify contents of the 'auto_selectable_formats' array passed in 'struct snd_soc_dai_ops', so make it const for code safety. Reviewed-by: Herve Codina Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617125735.582963-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 15ef268c9845..279223c4ef5e 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -361,7 +361,7 @@ struct snd_soc_dai_ops { * see * snd_soc_dai_get_fmt() */ - u64 *auto_selectable_formats; + const u64 *auto_selectable_formats; int num_auto_selectable_formats; /* probe ordering - for components with runtime dependencies */ -- cgit v1.2.3 From 2fbafecb0f05818e25f6c926c6f9ad9ef597429c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:19 +0200 Subject: ASoC: Constify of_phandle_args in snd_soc_dai_driver ASoC core code does not modify contents of 'of_phandle_args' in 'struct snd_soc_dai_driver', so the pointer can be made as a pointer to const. This makes code safer, serves as clear annotation of core's intentions and allows putting pointed structures in rodata (if ever applicable). Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-1-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 15ef268c9845..e6c61c79c483 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -413,7 +413,7 @@ struct snd_soc_dai_driver { unsigned int id; unsigned int base; struct snd_soc_dobj dobj; - struct of_phandle_args *dai_args; + const struct of_phandle_args *dai_args; /* ops */ const struct snd_soc_dai_ops *ops; -- cgit v1.2.3 From 020b37d06f97de289940805bc821190d5858eda0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:20 +0200 Subject: ASoC: Constify of_phandle_args in snd_soc_dai_link_component ASoC core code does not modify contents of 'of_phandle_args' in 'struct snd_soc_dai_link_component', so the pointer can be made as a pointer to const. This makes code safer, serves as clear annotation of core's intentions and allows putting pointed structures in rodata (if ever applicable). Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-2-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 33671437ee89..f02a51694ab4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -675,7 +675,7 @@ struct snd_soc_dai_link_component { const char *name; struct device_node *of_node; const char *dai_name; - struct of_phandle_args *dai_args; + const struct of_phandle_args *dai_args; }; /* -- cgit v1.2.3 From f3ac3da7e4d0957b3402fb31a4ca480e739e086f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:21 +0200 Subject: ASoC: Constify passed data to core function Several ASoC functions receive pointers to data which is not modified, e.g. pointers to 'snd_soc_dai', 'snd_soc_pcm_runtime', 'snd_pcm_hw_params' and 'snd_soc_dai_link'. All these pointers can be made as a pointer to const. This makes code safer, serves as clear annotation of function's intentions (no ownership passed to the function, no modifications) and allows putting pointed structures in rodata (if ever applicable). Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-3-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 18 ++++++++++-------- include/sound/soc.h | 17 +++++++++-------- sound/soc/soc-core.c | 4 ++-- sound/soc/soc-dai.c | 8 ++++---- sound/soc/soc-utils.c | 8 ++++---- 5 files changed, 29 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index e6c61c79c483..3c45b418270e 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -180,8 +180,8 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio); /* Digital Audio interface formatting */ -int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd); -u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority); +int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd); +u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority); int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, @@ -202,7 +202,7 @@ int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); -int snd_soc_dai_is_dummy(struct snd_soc_dai *dai); +int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai); int snd_soc_dai_hw_params(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, @@ -218,7 +218,7 @@ void snd_soc_dai_suspend(struct snd_soc_dai *dai); void snd_soc_dai_resume(struct snd_soc_dai *dai); int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd, int num); -bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream); +bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int stream); void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link); void snd_soc_dai_action(struct snd_soc_dai *dai, int stream, int action); @@ -232,7 +232,7 @@ static inline void snd_soc_dai_deactivate(struct snd_soc_dai *dai, { snd_soc_dai_action(dai, stream, -1); } -int snd_soc_dai_active(struct snd_soc_dai *dai); +int snd_soc_dai_active(const struct snd_soc_dai *dai); int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order); int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order); @@ -271,7 +271,7 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai, struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata); -const char *snd_soc_dai_name_get(struct snd_soc_dai *dai); +const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai); struct snd_soc_dai_ops { /* DAI driver callbacks */ @@ -518,7 +518,8 @@ static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai, void *play snd_soc_dai_dma_data_set_capture(dai, capture); } -static inline unsigned int snd_soc_dai_tdm_mask_get(struct snd_soc_dai *dai, int stream) +static inline unsigned int snd_soc_dai_tdm_mask_get(const struct snd_soc_dai *dai, + int stream) { return dai->stream[stream].tdm_mask; } @@ -529,7 +530,8 @@ static inline void snd_soc_dai_tdm_mask_set(struct snd_soc_dai *dai, int stream, dai->stream[stream].tdm_mask = tdm_mask; } -static inline unsigned int snd_soc_dai_stream_active(struct snd_soc_dai *dai, int stream) +static inline unsigned int snd_soc_dai_stream_active(const struct snd_soc_dai *dai, + int stream) { /* see snd_soc_dai_action() for setup */ return dai->stream[stream].active; diff --git a/include/sound/soc.h b/include/sound/soc.h index f02a51694ab4..a8e66bbf932b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -534,10 +534,10 @@ static inline int snd_soc_set_dmi_name(struct snd_soc_card *card, /* Utility functions to get clock rates from various things */ int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); -int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); +int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params *params); int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots); -int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms); -int snd_soc_tdm_params_to_bclk(struct snd_pcm_hw_params *params, +int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *parms); +int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params, int tdm_width, int tdm_slots, int slot_multiple); /* set runtime hw params */ @@ -837,7 +837,8 @@ struct snd_soc_dai_link { #endif }; -static inline int snd_soc_link_num_ch_map(struct snd_soc_dai_link *link) { +static inline int snd_soc_link_num_ch_map(const struct snd_soc_dai_link *link) +{ return max(link->num_cpus, link->num_codecs); } @@ -1299,7 +1300,7 @@ struct soc_enum { #endif }; -static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) +static inline bool snd_soc_volsw_is_stereo(const struct soc_mixer_control *mc) { if (mc->reg == mc->rreg && mc->shift == mc->rshift) return false; @@ -1311,7 +1312,7 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) return true; } -static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e, +static inline unsigned int snd_soc_enum_val_to_item(const struct soc_enum *e, unsigned int val) { unsigned int i; @@ -1326,7 +1327,7 @@ static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e, return 0; } -static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e, +static inline unsigned int snd_soc_enum_item_to_val(const struct soc_enum *e, unsigned int item) { if (!e->values) @@ -1401,7 +1402,7 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, snd_soc_daifmt_clock_provider_from_bitmap( \ snd_soc_daifmt_parse_clock_provider_as_bitmap(np, prefix)) -int snd_soc_get_stream_cpu(struct snd_soc_dai_link *dai_link, int stream); +int snd_soc_get_stream_cpu(const struct snd_soc_dai_link *dai_link, int stream); int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_component *dlc); int snd_soc_of_get_dlc(struct device_node *of_node, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3ab6626ad680..724fe1f033b5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -297,7 +297,7 @@ static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc, return 0; } -const char *snd_soc_dai_name_get(struct snd_soc_dai *dai) +const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai) { /* see snd_soc_is_matching_dai() */ if (dai->driver->name) @@ -3430,7 +3430,7 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_daifmt_parse_clock_provider_raw); -int snd_soc_get_stream_cpu(struct snd_soc_dai_link *dai_link, int stream) +int snd_soc_get_stream_cpu(const struct snd_soc_dai_link *dai_link, int stream) { /* * [Normal] diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 03afd5efb24c..55d1a5a099df 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -134,7 +134,7 @@ int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) } EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); -int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd) +int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai; int i, max = 0; @@ -166,7 +166,7 @@ int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd) * modes. This will mean that sometimes fewer formats * are reported here than are supported by set_fmt(). */ -u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority) +u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority) { const struct snd_soc_dai_ops *ops = dai->driver->ops; u64 fmt = 0; @@ -471,7 +471,7 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, * * Returns true if the DAI supports the indicated stream type. */ -bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir) +bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir) { struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir); @@ -528,7 +528,7 @@ void snd_soc_dai_action(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(snd_soc_dai_action); -int snd_soc_dai_active(struct snd_soc_dai *dai) +int snd_soc_dai_active(const struct snd_soc_dai *dai) { int stream, active; diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index d05e712c9518..5dea5609baf4 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -21,7 +21,7 @@ int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots) } EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size); -int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params) +int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params *params) { int sample_size; @@ -40,7 +40,7 @@ int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots) } EXPORT_SYMBOL_GPL(snd_soc_calc_bclk); -int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) +int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *params) { int ret; @@ -79,7 +79,7 @@ EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); * Return: bclk frequency in Hz, else a negative error code if params format * is invalid. */ -int snd_soc_tdm_params_to_bclk(struct snd_pcm_hw_params *params, +int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params, int tdm_width, int tdm_slots, int slot_multiple) { if (!tdm_slots) @@ -211,7 +211,7 @@ static struct snd_soc_dai_driver dummy_dai = { .ops = &dummy_dai_ops, }; -int snd_soc_dai_is_dummy(struct snd_soc_dai *dai) +int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai) { if (dai->driver == &dummy_dai) return 1; -- cgit v1.2.3 From 785d64c4941221044940ab199e6625af17296470 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:22 +0200 Subject: ASoC: Constify DAI passed to get_channel_map get_channel_map() is supposed to obtain map of channels without modifying the state of the given DAI, so make the pointer to 'struct snd_soc_dai' as pointing to const. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-4-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 4 ++-- sound/soc/codecs/lpass-rx-macro.c | 2 +- sound/soc/codecs/lpass-tx-macro.c | 2 +- sound/soc/codecs/lpass-va-macro.c | 2 +- sound/soc/codecs/lpass-wsa-macro.c | 2 +- sound/soc/codecs/wcd9335.c | 2 +- sound/soc/codecs/wcd934x.c | 2 +- sound/soc/soc-dai.c | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 3c45b418270e..f22969298de1 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -198,7 +198,7 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, int direction); -int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, +int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); @@ -307,7 +307,7 @@ struct snd_soc_dai_ops { int (*set_channel_map)(struct snd_soc_dai *dai, unsigned int tx_num, const unsigned int *tx_slot, unsigned int rx_num, const unsigned int *rx_slot); - int (*get_channel_map)(struct snd_soc_dai *dai, + int (*get_channel_map)(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); int (*set_tristate)(struct snd_soc_dai *dai, int tristate); diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 00ecc470ba8b..83791507ed13 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -1833,7 +1833,7 @@ static int rx_macro_hw_params(struct snd_pcm_substream *substream, return 0; } -static int rx_macro_get_channel_map(struct snd_soc_dai *dai, +static int rx_macro_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index c98b0b747a92..209c12ec16dd 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1167,7 +1167,7 @@ static int tx_macro_hw_params(struct snd_pcm_substream *substream, return 0; } -static int tx_macro_get_channel_map(struct snd_soc_dai *dai, +static int tx_macro_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index a555e1e078eb..b0006f4ce8a2 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -892,7 +892,7 @@ static int va_macro_hw_params(struct snd_pcm_substream *substream, return 0; } -static int va_macro_get_channel_map(struct snd_soc_dai *dai, +static int va_macro_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 6ce309980cd1..1e19c2b28a4f 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -992,7 +992,7 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream, return 0; } -static int wsa_macro_get_channel_map(struct snd_soc_dai *dai, +static int wsa_macro_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 42a99978fe5a..fc0ab00a253f 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -2014,7 +2014,7 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai, return 0; } -static int wcd9335_get_channel_map(struct snd_soc_dai *dai, +static int wcd9335_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index fcad2c9fba55..b5a929659dc8 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1960,7 +1960,7 @@ static int wcd934x_set_channel_map(struct snd_soc_dai *dai, return 0; } -static int wcd934x_get_channel_map(struct snd_soc_dai *dai, +static int wcd934x_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 55d1a5a099df..0c3a834e504d 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -11,7 +11,7 @@ #include #define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret) -static inline int _soc_dai_ret(struct snd_soc_dai *dai, +static inline int _soc_dai_ret(const struct snd_soc_dai *dai, const char *func, int ret) { /* Positive, Zero values are not errors */ @@ -327,7 +327,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); * @rx_slot: pointer to an array which imply the RX slot number channel * 0~num-1 uses */ -int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, +int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot) { -- cgit v1.2.3 From de267e7a6ea8e6fa29af2287adfc9fc9d87e6dc9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 17 Jun 2024 15:03:23 +0200 Subject: ASoC: Constify return of snd_soc_dai_get_pcm_stream() Returned 'struct snd_soc_pcm_stream' by snd_soc_dai_get_pcm_stream() is not modified by the users, so it can be changed as pointer to const. This is a necessary step towards making the 'dai->driver' a pointer to const. Signed-off-by: Krzysztof Kozlowski Link: https://msgid.link/r/20240617-n-asoc-const-auto-selectable-formats-v1-5-8004f346ee38@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 +- sound/soc/intel/avs/pcm.c | 4 ++-- sound/soc/soc-dai.c | 2 +- sound/soc/soc-pcm.c | 26 +++++++++++++------------- 4 files changed, 17 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index f22969298de1..bd249710d716 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -473,7 +473,7 @@ struct snd_soc_dai { unsigned int probed:1; }; -static inline struct snd_soc_pcm_stream * +static inline const struct snd_soc_pcm_stream * snd_soc_dai_get_pcm_stream(const struct snd_soc_dai *dai, int stream) { return (stream == SNDRV_PCM_STREAM_PLAYBACK) ? diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 88e711875004..c76b86254a8b 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -341,7 +341,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_stream *stream_info; + const struct snd_soc_pcm_stream *stream_info; struct hdac_ext_stream *link_stream; struct hdac_ext_link *link; struct avs_dma_data *data; @@ -637,7 +637,7 @@ static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_so static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_stream *stream_info; + const struct snd_soc_pcm_stream *stream_info; struct avs_dma_data *data; struct hdac_ext_stream *host_stream; unsigned int format_val; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 0c3a834e504d..9e47053419c1 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -473,7 +473,7 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, */ bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir) { - struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir); + const struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir); /* If the codec specifies any channels at all, it supports the stream */ return stream->channels_min; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 711b2f49ed88..bad823718ae4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -504,7 +504,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) unsigned int bits = 0, cpu_bits = 0; for_each_rtd_codec_dais(rtd, i, codec_dai) { - struct snd_soc_pcm_stream *pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream); + const struct snd_soc_pcm_stream *pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream); if (pcm_codec->sig_bits == 0) { bits = 0; @@ -514,7 +514,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) } for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - struct snd_soc_pcm_stream *pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream); + const struct snd_soc_pcm_stream *pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream); if (pcm_cpu->sig_bits == 0) { cpu_bits = 0; @@ -538,7 +538,7 @@ static void soc_pcm_hw_init(struct snd_pcm_hardware *hw) } static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw, - struct snd_soc_pcm_stream *p) + const struct snd_soc_pcm_stream *p) { hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates); @@ -551,20 +551,20 @@ static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw, } static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw, - struct snd_soc_pcm_stream *p) + const struct snd_soc_pcm_stream *p) { hw->channels_min = max(hw->channels_min, p->channels_min); hw->channels_max = min(hw->channels_max, p->channels_max); } static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw, - struct snd_soc_pcm_stream *p) + const struct snd_soc_pcm_stream *p) { hw->formats &= p->formats; } static void soc_pcm_hw_update_subformat(struct snd_pcm_hardware *hw, - struct snd_soc_pcm_stream *p) + const struct snd_soc_pcm_stream *p) { hw->subformats &= p->subformats; } @@ -583,8 +583,8 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai; - struct snd_soc_pcm_stream *codec_stream; - struct snd_soc_pcm_stream *cpu_stream; + const struct snd_soc_pcm_stream *codec_stream; + const struct snd_soc_pcm_stream *cpu_stream; unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX; int i; @@ -1712,7 +1712,7 @@ static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream) hw->formats &= formats; for_each_rtd_cpu_dais(fe, i, dai) { - struct snd_soc_pcm_stream *cpu_stream; + const struct snd_soc_pcm_stream *cpu_stream; /* * Skip CPUs which don't support the current stream @@ -1750,7 +1750,7 @@ static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream) for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_soc_pcm_stream *codec_stream; + const struct snd_soc_pcm_stream *codec_stream; int i; for_each_rtd_codec_dais(be, i, dai) { @@ -1787,7 +1787,7 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream) for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_soc_pcm_stream *cpu_stream; + const struct snd_soc_pcm_stream *cpu_stream; struct snd_soc_dai *dai; int i; @@ -1809,7 +1809,7 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream) * DAIs connected to a single CPU DAI, use CPU DAI's directly */ if (be->dai_link->num_codecs == 1) { - struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream( + const struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream( snd_soc_rtd_to_codec(be, 0), stream); soc_pcm_hw_update_chan(hw, codec_stream); @@ -1835,7 +1835,7 @@ static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream) for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_soc_pcm_stream *pcm; + const struct snd_soc_pcm_stream *pcm; struct snd_soc_dai *dai; int i; -- cgit v1.2.3 From 9f774c757e3fb2ac32dc4377e8f21f3364a8df81 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 14 Jun 2024 21:36:45 +0800 Subject: ASoc: tas2781: Enable RCA-based playback without DSP firmware download In only loading RCA (Reconfigurable Architecture) binary case, no DSP program will be working inside tas2563/tas2781, that is dsp-bypass mode, do not support speaker protection, or audio acoustic algorithms in this mode. Fixes: ef3bcde75d06 ("ASoC: tas2781: Add tas2781 driver") Signed-off-by: Shenghao Ding Reviewed-by: Pierre-Louis Bossart Link: https://msgid.link/r/20240614133646.910-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781-dsp.h | 11 +++++++++-- sound/soc/codecs/tas2781-fmwlib.c | 18 +++++++++++++----- sound/soc/codecs/tas2781-i2c.c | 39 ++++++++++++++++++++++++++------------- 3 files changed, 48 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h index 7fba7ea26a4b..3cda9da14f6d 100644 --- a/include/sound/tas2781-dsp.h +++ b/include/sound/tas2781-dsp.h @@ -117,10 +117,17 @@ struct tasdevice_fw { struct device *dev; }; -enum tasdevice_dsp_fw_state { - TASDEVICE_DSP_FW_NONE = 0, +enum tasdevice_fw_state { + /* Driver in startup mode, not load any firmware. */ TASDEVICE_DSP_FW_PENDING, + /* DSP firmware in the system, but parsing error. */ TASDEVICE_DSP_FW_FAIL, + /* + * Only RCA (Reconfigurable Architecture) firmware load + * successfully. + */ + TASDEVICE_RCA_FW_OK, + /* Both RCA and DSP firmware load successfully. */ TASDEVICE_DSP_FW_ALL_OK, }; diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index 265a8ca25cbb..838d29fead96 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -2324,14 +2324,21 @@ void tasdevice_tuning_switch(void *context, int state) struct tasdevice_fw *tas_fmw = tas_priv->fmw; int profile_cfg_id = tas_priv->rcabin.profile_cfg_id; - if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) { - dev_err(tas_priv->dev, "DSP bin file not loaded\n"); + /* + * Only RCA-based Playback can still work with no dsp program running + * inside the chip. + */ + switch (tas_priv->fw_state) { + case TASDEVICE_RCA_FW_OK: + case TASDEVICE_DSP_FW_ALL_OK: + break; + default: return; } if (state == 0) { - if (tas_priv->cur_prog < tas_fmw->nr_programs) { - /*dsp mode or tuning mode*/ + if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) { + /* dsp mode or tuning mode */ profile_cfg_id = tas_priv->rcabin.profile_cfg_id; tasdevice_select_tuningprm_cfg(tas_priv, tas_priv->cur_prog, tas_priv->cur_conf, @@ -2340,9 +2347,10 @@ void tasdevice_tuning_switch(void *context, int state) tasdevice_select_cfg_blk(tas_priv, profile_cfg_id, TASDEVICE_BIN_BLK_PRE_POWER_UP); - } else + } else { tasdevice_select_cfg_blk(tas_priv, profile_cfg_id, TASDEVICE_BIN_BLK_PRE_SHUTDOWN); + } } EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch, SND_SOC_TAS2781_FMWLIB); diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 9350972dfefe..c64d458e524e 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -380,23 +380,37 @@ static void tasdevice_fw_ready(const struct firmware *fmw, mutex_lock(&tas_priv->codec_lock); ret = tasdevice_rca_parser(tas_priv, fmw); - if (ret) + if (ret) { + tasdevice_config_info_remove(tas_priv); goto out; + } tasdevice_create_control(tas_priv); tasdevice_dsp_remove(tas_priv); tasdevice_calbin_remove(tas_priv); - tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; + /* + * The baseline is the RCA-only case, and then the code attempts to + * load DSP firmware but in case of failures just keep going, i.e. + * failing to load DSP firmware is NOT an error. + */ + tas_priv->fw_state = TASDEVICE_RCA_FW_OK; scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin", tas_priv->dev_name); ret = tasdevice_dsp_parser(tas_priv); if (ret) { dev_err(tas_priv->dev, "dspfw load %s error\n", tas_priv->coef_binaryname); - tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; goto out; } - tasdevice_dsp_create_ctrls(tas_priv); + + /* + * If no dsp-related kcontrol created, the dsp resource will be freed. + */ + ret = tasdevice_dsp_create_ctrls(tas_priv); + if (ret) { + dev_err(tas_priv->dev, "dsp controls error\n"); + goto out; + } tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; @@ -417,9 +431,8 @@ static void tasdevice_fw_ready(const struct firmware *fmw, tasdevice_prmg_load(tas_priv, 0); tas_priv->cur_prog = 0; out: - if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) { - /*If DSP FW fail, kcontrol won't be created */ - tasdevice_config_info_remove(tas_priv); + if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) { + /* If DSP FW fail, DSP kcontrol won't be created. */ tasdevice_dsp_remove(tas_priv); } mutex_unlock(&tas_priv->codec_lock); @@ -466,14 +479,14 @@ static int tasdevice_startup(struct snd_pcm_substream *substream, { struct snd_soc_component *codec = dai->component; struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); - int ret = 0; - if (tas_priv->fw_state != TASDEVICE_DSP_FW_ALL_OK) { - dev_err(tas_priv->dev, "DSP bin file not loaded\n"); - ret = -EINVAL; + switch (tas_priv->fw_state) { + case TASDEVICE_RCA_FW_OK: + case TASDEVICE_DSP_FW_ALL_OK: + return 0; + default: + return -EINVAL; } - - return ret; } static int tasdevice_hw_params(struct snd_pcm_substream *substream, -- cgit v1.2.3 From fe1ff61487ace69cd4e680e36169c90667eb9624 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 19 Jun 2024 05:53:42 +0000 Subject: ASoC: rt1318: Add RT1318 audio amplifier driver This is the initial i2s-based amplifier driver for rt1318. Signed-off-by: Jack Yu Link: https://msgid.link/r/b3055442ce6d4994aa01aa1fad6ba1fe@realtek.com Signed-off-by: Mark Brown --- include/sound/rt1318.h | 16 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt1318.c | 1354 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt1318.h | 342 ++++++++++++ 5 files changed, 1719 insertions(+) create mode 100644 include/sound/rt1318.h create mode 100644 sound/soc/codecs/rt1318.c create mode 100644 sound/soc/codecs/rt1318.h (limited to 'include') diff --git a/include/sound/rt1318.h b/include/sound/rt1318.h new file mode 100644 index 000000000000..fe6bff06036c --- /dev/null +++ b/include/sound/rt1318.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * linux/sound/rt1318.h -- Platform data for RT1318 + * + * Copyright 2024 Realtek Semiconductor Corp. + */ + +#ifndef __LINUX_SND_RT1318_H +#define __LINUX_SND_RT1318_H + +struct rt1318_platform_data { + unsigned int init_r0_l; + unsigned int init_r0_r; +}; + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7b99556f24d3..a99cb26eb280 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -221,6 +221,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT722_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW + imply SND_SOC_RT1318 imply SND_SOC_RT1318_SDW imply SND_SOC_RT1320_SDW imply SND_SOC_RT9120 @@ -1576,6 +1577,10 @@ config SND_SOC_RT1316_SDW depends on SOUNDWIRE select REGMAP_SOUNDWIRE +config SND_SOC_RT1318 + tristate + depends on I2C + config SND_SOC_RT1318_SDW tristate "Realtek RT1318 Codec - SDW" depends on SOUNDWIRE diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index ca69f35cc0f7..ad0f77224c74 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -222,6 +222,7 @@ snd-soc-rt1305-y := rt1305.o snd-soc-rt1308-y := rt1308.o snd-soc-rt1308-sdw-y := rt1308-sdw.o snd-soc-rt1316-sdw-y := rt1316-sdw.o +snd-soc-rt1318-y := rt1318.o snd-soc-rt1318-sdw-y := rt1318-sdw.o snd-soc-rt1320-sdw-y := rt1320-sdw.o snd-soc-rt274-y := rt274.o @@ -618,6 +619,7 @@ obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o +obj-$(CONFIG_SND_SOC_RT1318) += snd-soc-rt1318.o obj-$(CONFIG_SND_SOC_RT1318_SDW) += snd-soc-rt1318-sdw.o obj-$(CONFIG_SND_SOC_RT1320_SDW) += snd-soc-rt1320-sdw.o obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c new file mode 100644 index 000000000000..4e47db4fc7fb --- /dev/null +++ b/sound/soc/codecs/rt1318.c @@ -0,0 +1,1354 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt1318.c -- RT1318 ALSA SoC audio amplifier driver +// Author: Jack Yu +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt1318.h" + +static struct reg_sequence init_list[] = { + { 0x0000C000, 0x01}, + { 0x0000F20D, 0x00}, + { 0x0000F212, 0x3E}, + { 0x0000C001, 0x02}, + { 0x0000C003, 0x22}, + { 0x0000C004, 0x44}, + { 0x0000C005, 0x44}, + { 0x0000C007, 0x64}, + { 0x0000C00E, 0xE7}, + { 0x0000F223, 0x7F}, + { 0x0000F224, 0xDB}, + { 0x0000F225, 0xEE}, + { 0x0000F226, 0x3F}, + { 0x0000F227, 0x0F}, + { 0x0000F21A, 0x78}, + { 0x0000F242, 0x3C}, + { 0x0000C120, 0x40}, + { 0x0000C125, 0x03}, + { 0x0000C321, 0x0A}, + { 0x0000C200, 0xD8}, + { 0x0000C201, 0x27}, + { 0x0000C202, 0x0F}, + { 0x0000C400, 0x0E}, + { 0x0000C401, 0x43}, + { 0x0000C402, 0xE0}, + { 0x0000C403, 0x00}, + { 0x0000C404, 0x4C}, + { 0x0000C406, 0x40}, + { 0x0000C407, 0x02}, + { 0x0000C408, 0x3F}, + { 0x0000C300, 0x01}, + { 0x0000C125, 0x03}, + { 0x0000DF00, 0x10}, + { 0x0000F20B, 0x2A}, + { 0x0000DF5F, 0x01}, + { 0x0000DF60, 0xA7}, + { 0x0000C203, 0x84}, + { 0x0000C206, 0x78}, + { 0x0000F10A, 0x09}, + { 0x0000F10B, 0x4C}, + { 0x0000F104, 0xF4}, + { 0x0000F105, 0x03}, + { 0x0000F109, 0xE0}, + { 0x0000F10B, 0x5C}, + { 0x0000F104, 0xF4}, + { 0x0000F105, 0x04}, + { 0x0000F109, 0x65}, + { 0x0000F10B, 0x5C}, + { 0x0000F104, 0xF4}, + { 0x0000F105, 0x02}, + { 0x0000F109, 0x30}, + { 0x0000F10B, 0x5C}, + { 0x0000E706, 0x0F}, + { 0x0000E707, 0x30}, + { 0x0000E806, 0x0F}, + { 0x0000E807, 0x30}, + { 0x0000CE04, 0x03}, + { 0x0000CE05, 0x5F}, + { 0x0000CE06, 0xA2}, + { 0x0000CE07, 0x6B}, + { 0x0000CF04, 0x03}, + { 0x0000CF05, 0x5F}, + { 0x0000CF06, 0xA2}, + { 0x0000CF07, 0x6B}, + { 0x0000CE60, 0xE3}, + { 0x0000C130, 0x51}, + { 0x0000E000, 0xA8}, + { 0x0000F102, 0x00}, + { 0x0000F103, 0x00}, + { 0x0000F104, 0xF5}, + { 0x0000F105, 0x23}, + { 0x0000F109, 0x04}, + { 0x0000F10A, 0x0B}, + { 0x0000F10B, 0x4C}, + { 0x0000F10B, 0x5C}, + { 0x41001888, 0x00}, + { 0x0000C121, 0x0B}, + { 0x0000F102, 0x00}, + { 0x0000F103, 0x00}, + { 0x0000F104, 0xF5}, + { 0x0000F105, 0x23}, + { 0x0000F109, 0x00}, + { 0x0000F10A, 0x0B}, + { 0x0000F10B, 0x4C}, + { 0x0000F10B, 0x5C}, + { 0x0000F800, 0x20}, + { 0x0000CA00, 0x80}, + { 0x0000CA10, 0x00}, + { 0x0000CA02, 0x78}, + { 0x0000CA12, 0x78}, + { 0x0000ED00, 0x90}, + { 0x0000E604, 0x00}, + { 0x0000DB00, 0x0C}, + { 0x0000DD00, 0x0C}, + { 0x0000DC19, 0x00}, + { 0x0000DC1A, 0x6A}, + { 0x0000DC1B, 0xAA}, + { 0x0000DC1C, 0xAB}, + { 0x0000DC1D, 0x00}, + { 0x0000DC1E, 0x16}, + { 0x0000DC1F, 0xDB}, + { 0x0000DC20, 0x6D}, + { 0x0000DE19, 0x00}, + { 0x0000DE1A, 0x6A}, + { 0x0000DE1B, 0xAA}, + { 0x0000DE1C, 0xAB}, + { 0x0000DE1D, 0x00}, + { 0x0000DE1E, 0x16}, + { 0x0000DE1F, 0xDB}, + { 0x0000DE20, 0x6D}, + { 0x0000DB32, 0x00}, + { 0x0000DD32, 0x00}, + { 0x0000DB33, 0x0A}, + { 0x0000DD33, 0x0A}, + { 0x0000DB34, 0x1A}, + { 0x0000DD34, 0x1A}, + { 0x0000DB15, 0xEF}, + { 0x0000DD15, 0xEF}, + { 0x0000DB17, 0xEF}, + { 0x0000DD17, 0xEF}, + { 0x0000DB94, 0x70}, + { 0x0000DD94, 0x70}, + { 0x0000DB19, 0x40}, + { 0x0000DD19, 0x40}, + { 0x0000DB12, 0xC0}, + { 0x0000DD12, 0xC0}, + { 0x0000DB00, 0x4C}, + { 0x0000DB04, 0x05}, + { 0x0000DB05, 0x03}, + { 0x0000DD04, 0x05}, + { 0x0000DD05, 0x03}, + { 0x0000DBBB, 0x09}, + { 0x0000DBBC, 0x30}, + { 0x0000DBBD, 0xF0}, + { 0x0000DBBE, 0xF1}, + { 0x0000DDBB, 0x09}, + { 0x0000DDBC, 0x30}, + { 0x0000DDBD, 0xF0}, + { 0x0000DDBE, 0xF1}, + { 0x0000DB01, 0x79}, + { 0x0000DD01, 0x79}, + { 0x0000DB08, 0x40}, + { 0x0000DD08, 0x40}, + { 0x0000DC52, 0xEF}, + { 0x0000DE52, 0xEF}, + { 0x0000DB00, 0xCC}, + { 0x0000CC2C, 0x00}, + { 0x0000CC2D, 0x2A}, + { 0x0000CC2E, 0x83}, + { 0x0000CC2F, 0xA8}, + { 0x0000CD2C, 0x00}, + { 0x0000CD2D, 0x2A}, + { 0x0000CD2E, 0x83}, + { 0x0000CD2F, 0xA8}, + { 0x0000CC24, 0x00}, + { 0x0000CC25, 0x51}, + { 0x0000CC26, 0xEB}, + { 0x0000CC27, 0x85}, + { 0x0000CD24, 0x00}, + { 0x0000CD25, 0x51}, + { 0x0000CD26, 0xEB}, + { 0x0000CD27, 0x85}, + { 0x0000CC20, 0x00}, + { 0x0000CC21, 0x00}, + { 0x0000CC22, 0x43}, + { 0x0000CD20, 0x00}, + { 0x0000CD21, 0x00}, + { 0x0000CD22, 0x43}, + { 0x0000CC16, 0x0F}, + { 0x0000CC17, 0x00}, + { 0x0000CD16, 0x0F}, + { 0x0000CD17, 0x00}, + { 0x0000CC29, 0x5D}, + { 0x0000CC2A, 0xC0}, + { 0x0000CD29, 0x5D}, + { 0x0000CD2A, 0xC0}, + { 0x0000CC31, 0x20}, + { 0x0000CC32, 0x00}, + { 0x0000CC33, 0x00}, + { 0x0000CC34, 0x00}, + { 0x0000CD31, 0x20}, + { 0x0000CD32, 0x00}, + { 0x0000CD33, 0x00}, + { 0x0000CD34, 0x00}, + { 0x0000CC36, 0x79}, + { 0x0000CC37, 0x99}, + { 0x0000CC38, 0x99}, + { 0x0000CC39, 0x99}, + { 0x0000CD36, 0x79}, + { 0x0000CD37, 0x99}, + { 0x0000CD38, 0x99}, + { 0x0000CD39, 0x99}, + { 0x0000CC09, 0x00}, + { 0x0000CC0A, 0x07}, + { 0x0000CC0B, 0x5F}, + { 0x0000CC0C, 0x6F}, + { 0x0000CD09, 0x00}, + { 0x0000CD0A, 0x07}, + { 0x0000CD0B, 0x5F}, + { 0x0000CD0C, 0x6F}, + { 0x0000CC0E, 0x00}, + { 0x0000CC0F, 0x03}, + { 0x0000CC10, 0xAF}, + { 0x0000CC11, 0xB7}, + { 0x0000CD0E, 0x00}, + { 0x0000CD0F, 0x03}, + { 0x0000CD10, 0xAF}, + { 0x0000CD11, 0xB7}, + { 0x0000CCD6, 0x00}, + { 0x0000CCD7, 0x03}, + { 0x0000CDD6, 0x00}, + { 0x0000CDD7, 0x03}, + { 0x0000CCD8, 0x00}, + { 0x0000CCD9, 0x03}, + { 0x0000CDD8, 0x00}, + { 0x0000CDD9, 0x03}, + { 0x0000CCDA, 0x00}, + { 0x0000CCDB, 0x03}, + { 0x0000CDDA, 0x00}, + { 0x0000CDDB, 0x03}, + { 0x0000C320, 0x20}, + { 0x0000C203, 0x9C}, +}; +#define rt1318_INIT_REG_LEN ARRAY_SIZE(init_list) + +static const struct reg_default rt1318_reg[] = { + { 0xc000, 0x00 }, + { 0xc001, 0x43 }, + { 0xc003, 0x22 }, + { 0xc004, 0x44 }, + { 0xc005, 0x44 }, + { 0xc006, 0x33 }, + { 0xc007, 0x64 }, + { 0xc008, 0x05 }, + { 0xc00a, 0xfc }, + { 0xc00b, 0x0f }, + { 0xc00c, 0x0e }, + { 0xc00d, 0xef }, + { 0xc00e, 0xe5 }, + { 0xc00f, 0xff }, + { 0xc120, 0xc0 }, + { 0xc121, 0x00 }, + { 0xc122, 0x00 }, + { 0xc123, 0x14 }, + { 0xc125, 0x00 }, + { 0xc130, 0x59 }, + { 0xc200, 0x00 }, + { 0xc201, 0x00 }, + { 0xc202, 0x00 }, + { 0xc203, 0x04 }, + { 0xc204, 0x00 }, + { 0xc205, 0x00 }, + { 0xc206, 0x68 }, + { 0xc207, 0x70 }, + { 0xc208, 0x00 }, + { 0xc20a, 0x00 }, + { 0xc20b, 0x01 }, + { 0xc20c, 0x7f }, + { 0xc20d, 0x01 }, + { 0xc20e, 0x7f }, + { 0xc300, 0x00 }, + { 0xc301, 0x00 }, + { 0xc303, 0x80 }, + { 0xc320, 0x00 }, + { 0xc321, 0x09 }, + { 0xc322, 0x02 }, + { 0xc400, 0x00 }, + { 0xc401, 0x00 }, + { 0xc402, 0x00 }, + { 0xc403, 0x00 }, + { 0xc404, 0x00 }, + { 0xc405, 0x00 }, + { 0xc406, 0x00 }, + { 0xc407, 0x00 }, + { 0xc408, 0x00 }, + { 0xc410, 0x04 }, + { 0xc430, 0x00 }, + { 0xc431, 0x00 }, + { 0xca00, 0x10 }, + { 0xca01, 0x00 }, + { 0xca02, 0x0b }, + { 0xca10, 0x10 }, + { 0xca11, 0x00 }, + { 0xca12, 0x0b }, + { 0xce04, 0x08 }, + { 0xce05, 0x00 }, + { 0xce06, 0x00 }, + { 0xce07, 0x00 }, + { 0xce60, 0x63 }, + { 0xcf04, 0x08 }, + { 0xcf05, 0x00 }, + { 0xcf06, 0x00 }, + { 0xcf07, 0x00 }, + { 0xdb00, 0x00 }, + { 0xdb08, 0x40 }, + { 0xdb12, 0x00 }, + { 0xdb35, 0x00 }, + { 0xdbb5, 0x00 }, + { 0xdbb6, 0x40 }, + { 0xdbb7, 0x00 }, + { 0xdbb8, 0x00 }, + { 0xdbc5, 0x00 }, + { 0xdbc6, 0x00 }, + { 0xdbc7, 0x00 }, + { 0xdbc8, 0x00 }, + { 0xdd08, 0x40 }, + { 0xdd12, 0x00 }, + { 0xdd35, 0x00 }, + { 0xddb5, 0x00 }, + { 0xddb6, 0x40 }, + { 0xddb7, 0x00 }, + { 0xddb8, 0x00 }, + { 0xddc5, 0x00 }, + { 0xddc6, 0x00 }, + { 0xddc7, 0x00 }, + { 0xddc8, 0x00 }, + { 0xdd93, 0x00 }, + { 0xdd94, 0x64 }, + { 0xdf00, 0x00 }, + { 0xdf5f, 0x00 }, + { 0xdf60, 0x00 }, + { 0xe000, 0x08 }, + { 0xe300, 0xa0 }, + { 0xe400, 0x22 }, + { 0xe706, 0x2f }, + { 0xe707, 0x2f }, + { 0xe806, 0x2f }, + { 0xe807, 0x2f }, + { 0xea00, 0x43 }, + { 0xed00, 0x80 }, + { 0xed01, 0x0f }, + { 0xed02, 0xff }, + { 0xed03, 0x00 }, + { 0xed04, 0x00 }, + { 0xed05, 0x0f }, + { 0xed06, 0xff }, + { 0xf010, 0x10 }, + { 0xf011, 0xec }, + { 0xf012, 0x68 }, + { 0xf013, 0x21 }, + { 0xf102, 0x00 }, + { 0xf103, 0x00 }, + { 0xf104, 0x00 }, + { 0xf105, 0x00 }, + { 0xf106, 0x00 }, + { 0xf107, 0x00 }, + { 0xf108, 0x00 }, + { 0xf109, 0x00 }, + { 0xf10a, 0x03 }, + { 0xf10b, 0x40 }, + { 0xf20b, 0x28 }, + { 0xf20d, 0x00 }, + { 0xf212, 0x00 }, + { 0xf21a, 0x00 }, + { 0xf223, 0x40 }, + { 0xf224, 0x00 }, + { 0xf225, 0x00 }, + { 0xf226, 0x00 }, + { 0xf227, 0x00 }, + { 0xf242, 0x0c }, + { 0xf800, 0x00 }, + { 0xf801, 0x12 }, + { 0xf802, 0xe0 }, + { 0xf803, 0x2f }, + { 0xf804, 0x00 }, + { 0xf805, 0x00 }, + { 0xf806, 0x07 }, + { 0xf807, 0xff }, +}; + +static bool rt1318_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0xc000: + case 0xc301: + case 0xc410: + case 0xc430 ... 0xc431: + case 0xdb06: + case 0xdb12: + case 0xdb1d ... 0xdb1f: + case 0xdb35: + case 0xdb37: + case 0xdb8a ... 0xdb92: + case 0xdbc5 ... 0xdbc8: + case 0xdc2b ... 0xdc49: + case 0xdd0b: + case 0xdd12: + case 0xdd1d ... 0xdd1f: + case 0xdd35: + case 0xdd8a ... 0xdd92: + case 0xddc5 ... 0xddc8: + case 0xde2b ... 0xde44: + case 0xdf4a ... 0xdf55: + case 0xe224 ... 0xe23b: + case 0xea01: + case 0xebc5: + case 0xebc8: + case 0xebcb ... 0xebcc: + case 0xed03 ... 0xed06: + case 0xf010 ... 0xf014: + return true; + + default: + return false; + } +} + +static bool rt1318_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0xc000 ... 0xc00f: + case 0xc120 ... 0xc130: + case 0xc200 ... 0xc20e: + case 0xc300 ... 0xc303: + case 0xc320 ... 0xc322: + case 0xc400 ... 0xc408: + case 0xc430 ... 0xc431: + case 0xca00 ... 0xca02: + case 0xca10 ... 0xca12: + case 0xcb00 ... 0xcb0b: + case 0xcc00 ... 0xcce5: + case 0xcd00 ... 0xcde5: + case 0xce00 ... 0xce6a: + case 0xcf00 ... 0xcf53: + case 0xd000 ... 0xd0cc: + case 0xd100 ... 0xd1b9: + case 0xdb00 ... 0xdc53: + case 0xdd00 ... 0xde53: + case 0xdf00 ... 0xdf6b: + case 0xe000: + case 0xe300: + case 0xe400: + case 0xe706 ... 0xe707: + case 0xe806 ... 0xe807: + case 0xea00: + case 0xeb00 ... 0xebcc: + case 0xec00 ... 0xecb9: + case 0xed00 ... 0xed06: + case 0xf010 ... 0xf014: + case 0xf102 ... 0xf10b: + case 0xf20b: + case 0xf20d ... 0xf242: + case 0xf800 ... 0xf807: + return true; + default: + return false; + } +} + +static int rt1318_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1, + RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_HIGH); + break; + + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1, + RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_LOW); + break; + + default: + break; + } + return 0; +} + +static int rt1318_dvol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + rt1318->rt1318_dvol = ucontrol->value.integer.value[0]; + + if (rt1318->rt1318_dvol <= RT1318_DVOL_STEP && rt1318->rt1318_dvol >= 0) { + regmap_write(rt1318->regmap, RT1318_DA_VOL_L_8, + rt1318->rt1318_dvol >> 8); + regmap_write(rt1318->regmap, RT1318_DA_VOL_L_1_7, + rt1318->rt1318_dvol & 0xff); + regmap_write(rt1318->regmap, RT1318_DA_VOL_R_8, + rt1318->rt1318_dvol >> 8); + regmap_write(rt1318->regmap, RT1318_DA_VOL_R_1_7, + rt1318->rt1318_dvol & 0xff); + return 1; + } + + return 0; +} + +static int rt1318_dvol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1318->rt1318_dvol; + + return 0; +} + +static const struct snd_kcontrol_new rt1318_snd_controls[] = { + SOC_SINGLE_EXT("Amp Playback Volume", SND_SOC_NOPM, 0, 383, 0, + rt1318_dvol_get, rt1318_dvol_put), +}; + +static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + /* DACs */ + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, + rt1318_dac_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("Amp"), +}; + +static const struct snd_soc_dapm_route rt1318_dapm_routes[] = { + {"DAC", NULL, "AIF1RX"}, + {"Amp", NULL, "DAC"}, +}; + +static int rt1318_get_clk_info(int sclk, int rate) +{ + int i, pd[] = {1, 2, 4, 8, 16, 24}; + + if (sclk <= 0 || rate <= 0) + return -EINVAL; + + rate = rate << 8; + for (i = 0; i < ARRAY_SIZE(pd); i++) + if (sclk == rate * pd[i]) + return i; + + return -EINVAL; +} + +static int rt1318_clk_ip_info(struct snd_soc_component *component, int lrclk) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + switch (lrclk) { + case RT1318_LRCLK_48000: + case RT1318_LRCLK_44100: + case RT1318_LRCLK_16000: + regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON, + RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK, + RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON4); + break; + case RT1318_LRCLK_96000: + regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON, + RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK, + RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON2); + break; + case RT1318_LRCLK_192000: + regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON, + RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK, + RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON1); + break; + default: + dev_err(component->dev, "Unsupported clock rate.\n"); + return -EINVAL; + } + + return 0; +} + +static int rt1318_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + int data_len = 0, ch_len = 0; + int pre_div, ret; + + rt1318->lrck = params_rate(params); + pre_div = rt1318_get_clk_info(rt1318->sysclk, rt1318->lrck); + if (pre_div < 0) { + dev_err(component->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + ret = rt1318_clk_ip_info(component, rt1318->lrck); + if (ret < 0) { + dev_err(component->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + + switch (params_width(params)) { + case 16: + break; + case 20: + data_len = RT1318_I2S_DL_20; + ch_len = RT1318_I2S_DL_20; + break; + case 24: + data_len = RT1318_I2S_DL_24; + ch_len = RT1318_I2S_DL_24; + break; + case 32: + data_len = RT1318_I2S_DL_32; + ch_len = RT1318_I2S_DL_32; + break; + case 8: + data_len = RT1318_I2S_DL_8; + ch_len = RT1318_I2S_DL_8; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rt1318->regmap, RT1318_CLK2, + RT1318_DIV_AP_MASK | RT1318_DIV_DAMOD_MASK, + pre_div << RT1318_DIV_AP_SFT | + pre_div << RT1318_DIV_DAMOD_SFT); + regmap_update_bits(rt1318->regmap, RT1318_CLK3, + RT1318_AD_STO1_MASK | RT1318_AD_STO2_MASK, + pre_div << RT1318_AD_STO1_SFT | + pre_div << RT1318_AD_STO2_SFT); + regmap_update_bits(rt1318->regmap, RT1318_CLK4, + RT1318_AD_ANA_STO1_MASK | RT1318_AD_ANA_STO2_MASK, + pre_div << RT1318_AD_ANA_STO1_SFT | + pre_div << RT1318_AD_ANA_STO2_SFT); + regmap_update_bits(rt1318->regmap, RT1318_CLK5, + RT1318_DIV_FIFO_IN_MASK | RT1318_DIV_FIFO_OUT_MASK, + pre_div << RT1318_DIV_FIFO_IN_SFT | + pre_div << RT1318_DIV_FIFO_OUT_SFT); + regmap_update_bits(rt1318->regmap, RT1318_CLK6, + RT1318_DIV_NLMS_MASK | RT1318_DIV_AD_MONO_MASK | + RT1318_DIV_POST_G_MASK, pre_div << RT1318_DIV_NLMS_SFT | + pre_div << RT1318_DIV_AD_MONO_SFT | + pre_div << RT1318_DIV_POST_G_SFT); + + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2, + RT1318_I2S_DL_MASK, data_len << RT1318_I2S_DL_SFT); + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3, + RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK, + ch_len << RT1318_I2S_TX_CHL_SFT | + ch_len << RT1318_I2S_RX_CHL_SFT); + + return 0; +} + +static int rt1318_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + unsigned int reg_val = 0, reg_val2 = 0; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val2 |= RT1318_TDM_BCLK_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT1318_FMT_LEFT_J; + break; + + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT1318_FMT_PCM_A_R; + break; + + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT1318_FMT_PCM_B_R; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1, + RT1318_I2S_FMT_MASK, reg_val); + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1, + RT1318_TDM_BCLK_MASK, reg_val2); + + return 0; +} + +static int rt1318_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + int reg_val = 0; + + if (freq == rt1318->sysclk && clk_id == rt1318->sysclk_src) + return 0; + + switch (clk_id) { + case RT1318_SCLK_S_BCLK: + reg_val |= RT1318_SYSCLK_BCLK; + break; + case RT1318_SCLK_S_SDW: + reg_val |= RT1318_SYSCLK_SDW; + break; + case RT1318_SCLK_S_PLL2F: + reg_val |= RT1318_SYSCLK_PLL2F; + break; + case RT1318_SCLK_S_PLL2B: + reg_val |= RT1318_SYSCLK_PLL2B; + break; + case RT1318_SCLK_S_MCLK: + reg_val |= RT1318_SYSCLK_MCLK; + break; + case RT1318_SCLK_S_RC0: + reg_val |= RT1318_SYSCLK_RC1; + break; + case RT1318_SCLK_S_RC1: + reg_val |= RT1318_SYSCLK_RC2; + break; + case RT1318_SCLK_S_RC2: + reg_val |= RT1318_SYSCLK_RC3; + break; + default: + dev_err(component->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + + rt1318->sysclk = freq; + rt1318->sysclk_src = clk_id; + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_SYSCLK_SEL_MASK, reg_val); + + return 0; +} + +static const struct pll_calc_map pll_preset_table[] = { + {512000, 4096000, 22, 190, 0, true, false}, + {1024000, 4096000, 22, 94, 0, true, false}, + {1024000, 16384000, 4, 190, 0, true, false}, + {1411200, 11289600, 6, 62, 0, true, false}, + {1536000, 12288000, 6, 62, 0, true, false}, + {2822400, 11289600, 6, 62, 0, true, false}, + {2822400, 45158400, 0, 62, 0, true, false}, + {2822400, 49152000, 0, 62, 0, true, false}, + {3072000, 12288000, 6, 62, 0, true, false}, + {3072000, 24576000, 2, 62, 0, true, false}, + {3072000, 49152000, 0, 62, 0, true, false}, + {6144000, 24576000, 2, 94, 4, false, false}, + {6144000, 49152000, 0, 30, 0, true, false}, + {6144000, 98304000, 0, 94, 4, false, true}, + {12288000, 49152000, 0, 62, 6, false, false}, +}; + +static int rt1318_pll_calc(const unsigned int freq_in, + const unsigned int freq_out, struct rt1318_pll_code *pll_code) +{ + int max_n = RT1318_PLL_N_MAX, max_m = RT1318_PLL_M_MAX; + int i, k, red, n_t, pll_out, in_t, out_t; + int n = 0, m = 0, m_t = 0; + int red_t = abs(freq_out - freq_in); + bool m_bypass = false, k_bypass = false; + + if (RT1318_PLL_INP_MAX < freq_in || RT1318_PLL_INP_MIN > freq_in) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) { + if (freq_in == pll_preset_table[i].pll_in && + freq_out == pll_preset_table[i].pll_out) { + k = pll_preset_table[i].k; + m = pll_preset_table[i].m; + n = pll_preset_table[i].n; + m_bypass = pll_preset_table[i].m_bp; + k_bypass = pll_preset_table[i].k_bp; + goto code_find; + } + } + + k = 100000000 / freq_out - 2; + if (k > RT1318_PLL_K_MAX) + k = RT1318_PLL_K_MAX; + if (k < 0) { + k = 0; + k_bypass = true; + } + for (n_t = 0; n_t <= max_n; n_t++) { + in_t = freq_in / (k_bypass ? 1 : (k + 2)); + pll_out = freq_out / (n_t + 2); + if (in_t < 0) + continue; + if (in_t == pll_out) { + m_bypass = true; + n = n_t; + goto code_find; + } + red = abs(in_t - pll_out); + if (red < red_t) { + m_bypass = true; + n = n_t; + m = m_t; + if (red == 0) + goto code_find; + red_t = red; + } + for (m_t = 0; m_t <= max_m; m_t++) { + out_t = in_t / (m_t + 2); + red = abs(out_t - pll_out); + if (red < red_t) { + m_bypass = false; + n = n_t; + m = m_t; + if (red == 0) + goto code_find; + red_t = red; + } + } + } + pr_debug("Only get approximation about PLL\n"); + +code_find: + + pll_code->m_bp = m_bypass; + pll_code->k_bp = k_bypass; + pll_code->m_code = m; + pll_code->n_code = n; + pll_code->k_code = k; + return 0; +} + +static int rt1318_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_component *component = dai->component; + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + struct rt1318_pll_code pll_code; + int ret; + + if (!freq_in || !freq_out) { + dev_dbg(component->dev, "PLL disabled\n"); + rt1318->pll_in = 0; + rt1318->pll_out = 0; + return 0; + } + + if (source == rt1318->pll_src && freq_in == rt1318->pll_in && + freq_out == rt1318->pll_out) + return 0; + + switch (source) { + case RT1318_PLL_S_BCLK0: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK0); + break; + case RT1318_PLL_S_BCLK1: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK1); + break; + case RT1318_PLL_S_RC: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_RC); + break; + case RT1318_PLL_S_MCLK: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_MCLK); + break; + case RT1318_PLL_S_SDW_IN_PLL: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_SDW1); + break; + case RT1318_PLL_S_SDW_0: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_SDW2); + break; + case RT1318_PLL_S_SDW_1: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_SDW3); + break; + case RT1318_PLL_S_SDW_2: + regmap_update_bits(rt1318->regmap, RT1318_CLK1, + RT1318_PLLIN_MASK, RT1318_PLLIN_SDW4); + break; + default: + dev_err(component->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rt1318_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + regmap_update_bits(rt1318->regmap, RT1318_PLL1_K, + RT1318_K_PLL1_MASK, pll_code.k_code); + regmap_update_bits(rt1318->regmap, RT1318_PLL1_M, + RT1318_M_PLL1_MASK, (pll_code.m_bp ? 0 : pll_code.m_code)); + regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_8, + RT1318_N_8_PLL1_MASK, pll_code.n_code >> 8); + regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_7_0, + RT1318_N_7_0_PLL1_MASK, pll_code.n_code); + + rt1318->pll_in = freq_in; + rt1318->pll_out = freq_out; + rt1318->pll_src = source; + + return 0; +} + +static int rt1318_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + unsigned int cn = 0, cl = 0, rx_slotnum; + int ret = 0, first_bit; + + switch (slots) { + case 4: + cn |= RT1318_I2S_CH_TX_4CH; + cn |= RT1318_I2S_CH_RX_4CH; + break; + case 6: + cn |= RT1318_I2S_CH_TX_6CH; + cn |= RT1318_I2S_CH_RX_6CH; + break; + case 8: + cn |= RT1318_I2S_CH_TX_8CH; + cn |= RT1318_I2S_CH_RX_8CH; + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + cl |= RT1318_I2S_TX_CHL_20; + cl |= RT1318_I2S_RX_CHL_20; + break; + case 24: + cl |= RT1318_I2S_TX_CHL_24; + cl |= RT1318_I2S_RX_CHL_24; + break; + case 32: + cl |= RT1318_I2S_TX_CHL_32; + cl |= RT1318_I2S_RX_CHL_32; + break; + case 8: + cl |= RT1318_I2S_TX_CHL_8; + cl |= RT1318_I2S_RX_CHL_8; + break; + case 16: + break; + default: + return -EINVAL; + } + + /* Rx slot configuration */ + rx_slotnum = hweight_long(rx_mask); + if (rx_slotnum != 1) { + ret = -EINVAL; + dev_err(component->dev, "too many rx slots or zero slot\n"); + goto _set_tdm_err_; + } + + first_bit = __ffs(rx_mask); + switch (first_bit) { + case 0: + case 2: + case 4: + case 6: + regmap_update_bits(rt1318->regmap, + RT1318_TDM_CTRL9, + RT1318_TDM_I2S_TX_L_DAC1_1_MASK | + RT1318_TDM_I2S_TX_R_DAC1_1_MASK, + (first_bit << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) | + ((first_bit + 1) << RT1318_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + case 1: + case 3: + case 5: + case 7: + regmap_update_bits(rt1318->regmap, + RT1318_TDM_CTRL9, + RT1318_TDM_I2S_TX_L_DAC1_1_MASK | + RT1318_TDM_I2S_TX_R_DAC1_1_MASK, + ((first_bit - 1) << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) | + (first_bit << RT1318_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2, + RT1318_I2S_CH_TX_MASK | RT1318_I2S_CH_RX_MASK, cn); + regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3, + RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK, cl); + +_set_tdm_err_: + return ret; +} + +static int rt1318_probe(struct snd_soc_component *component) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + rt1318->component = component; + + schedule_work(&rt1318->cali_work); + rt1318->rt1318_dvol = RT1318_DVOL_STEP; + + return 0; +} + +static void rt1318_remove(struct snd_soc_component *component) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + cancel_work_sync(&rt1318->cali_work); +} + +#ifdef CONFIG_PM +static int rt1318_suspend(struct snd_soc_component *component) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt1318->regmap, true); + regcache_mark_dirty(rt1318->regmap); + return 0; +} + +static int rt1318_resume(struct snd_soc_component *component) +{ + struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt1318->regmap, false); + regcache_sync(rt1318->regmap); + return 0; +} +#else +#define rt1318_suspend NULL +#define rt1318_resume NULL +#endif + +#define RT1318_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt1318_aif_dai_ops = { + .hw_params = rt1318_hw_params, + .set_fmt = rt1318_set_dai_fmt, + .set_sysclk = rt1318_set_dai_sysclk, + .set_pll = rt1318_set_dai_pll, + .set_tdm_slot = rt1318_set_tdm_slot, +}; + +static struct snd_soc_dai_driver rt1318_dai[] = { + { + .name = "rt1318-aif", + .id = 0, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT1318_STEREO_RATES, + .formats = RT1318_FORMATS, + }, + .ops = &rt1318_aif_dai_ops, + } +}; + +static const struct snd_soc_component_driver soc_component_dev_rt1318 = { + .probe = rt1318_probe, + .remove = rt1318_remove, + .suspend = rt1318_suspend, + .resume = rt1318_resume, + .controls = rt1318_snd_controls, + .num_controls = ARRAY_SIZE(rt1318_snd_controls), + .dapm_widgets = rt1318_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets), + .dapm_routes = rt1318_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct regmap_config rt1318_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt1318_readable_register, + .volatile_reg = rt1318_volatile_register, + .max_register = 0x41001888, + .reg_defaults = rt1318_reg, + .num_reg_defaults = ARRAY_SIZE(rt1318_reg), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct i2c_device_id rt1318_i2c_id[] = { + { "rt1318", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt1318_i2c_id); + +static const struct of_device_id rt1318_of_match[] = { + { .compatible = "realtek,rt1318", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt1318_of_match); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id rt1318_acpi_match[] = { + { "10EC1318", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt1318_acpi_match); +#endif + +static int rt1318_parse_dt(struct rt1318_priv *rt1318, struct device *dev) +{ + device_property_read_u32(dev, "realtek,r0_l", + &rt1318->pdata.init_r0_l); + device_property_read_u32(dev, "realtek,r0_r", + &rt1318->pdata.init_r0_r); + + return 0; +} + +static void rt1318_calibration_sequence(struct rt1318_priv *rt1318) +{ + regmap_write(rt1318->regmap, RT1318_CLK1, 0x22); + regmap_write(rt1318->regmap, RT1318_PLL1_N_7_0, 0x06); + regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xCC); + regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x40); + regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x40); + regmap_write(rt1318->regmap, RT1318_SINE_GEN0, 0x20); + regmap_write(rt1318->regmap, RT1318_SPK_VOL_TH, 0x00); + regmap_write(rt1318->regmap, RT1318_FEEDBACK_PATH, 0x0B); + regmap_write(rt1318->regmap, RT1318_TCON, 0x1C); + regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x58); + regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x78); + regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xC2); +} + +static void rt1318_r0_calculate(struct rt1318_priv *rt1318) +{ + unsigned int r0_l, r0_l_byte0, r0_l_byte1, r0_l_byte2, r0_l_byte3; + unsigned int r0_r, r0_r_byte0, r0_r_byte1, r0_r_byte2, r0_r_byte3; + unsigned int r0_l_integer, r0_l_factor, r0_r_integer, r0_r_factor; + unsigned int format = 16777216; /* 2^24 */ + + regmap_read(rt1318->regmap, RT1318_R0_L_24, &r0_l_byte0); + regmap_read(rt1318->regmap, RT1318_R0_L_23_16, &r0_l_byte1); + regmap_read(rt1318->regmap, RT1318_R0_L_15_8, &r0_l_byte2); + regmap_read(rt1318->regmap, RT1318_R0_L_7_0, &r0_l_byte3); + r0_l = r0_l_byte0 << 24 | r0_l_byte1 << 16 | r0_l_byte2 << 8 | r0_l_byte3; + r0_l_integer = format / r0_l; + r0_l_factor = (format * 10) / r0_l - r0_l_integer * 10; + + regmap_read(rt1318->regmap, RT1318_R0_R_24, &r0_r_byte0); + regmap_read(rt1318->regmap, RT1318_R0_R_23_16, &r0_r_byte1); + regmap_read(rt1318->regmap, RT1318_R0_R_15_8, &r0_r_byte2); + regmap_read(rt1318->regmap, RT1318_R0_R_7_0, &r0_r_byte3); + r0_r = r0_r_byte0 << 24 | r0_r_byte1 << 16 | r0_r_byte2 << 8 | r0_r_byte3; + r0_r_integer = format / r0_r; + r0_r_factor = (format * 10) / r0_r - r0_r_integer * 10; + + dev_dbg(rt1318->component->dev, "r0_l_ch:%d.%d ohm\n", r0_l_integer, r0_l_factor); + dev_dbg(rt1318->component->dev, "r0_r_ch:%d.%d ohm\n", r0_r_integer, r0_r_factor); +} + +static void rt1318_r0_restore(struct rt1318_priv *rt1318) +{ + regmap_write(rt1318->regmap, RT1318_PRE_R0_L_24, + (rt1318->pdata.init_r0_l >> 24) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_L_23_16, + (rt1318->pdata.init_r0_l >> 16) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_L_15_8, + (rt1318->pdata.init_r0_l >> 8) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_L_7_0, + (rt1318->pdata.init_r0_l >> 0) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_R_24, + (rt1318->pdata.init_r0_r >> 24) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_R_23_16, + (rt1318->pdata.init_r0_r >> 16) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_R_15_8, + (rt1318->pdata.init_r0_r >> 8) & 0xff); + regmap_write(rt1318->regmap, RT1318_PRE_R0_R_7_0, + (rt1318->pdata.init_r0_r >> 0) & 0xff); + regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x80); + regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x80); + regmap_write(rt1318->regmap, RT1318_R0_CMP_L_FLAG, 0xc0); + regmap_write(rt1318->regmap, RT1318_R0_CMP_R_FLAG, 0xc0); + regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xc0); + regmap_write(rt1318->regmap, RT1318_STP_R0_EN_R, 0xc0); + regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xcc); + regmap_write(rt1318->regmap, RT1318_TCON, 0x9c); +} + +static int rt1318_calibrate(struct rt1318_priv *rt1318) +{ + int chk_cnt = 30, count = 0; + int val, val2; + + regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x1); + usleep_range(0, 10000); + rt1318_calibration_sequence(rt1318); + + while (count < chk_cnt) { + msleep(100); + regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val); + regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2); + val = (val >> 1) & 0x1; + val2 = (val2 >> 1) & 0x1; + if (val & val2) { + dev_dbg(rt1318->component->dev, "Calibration done.\n"); + break; + } + count++; + if (count == chk_cnt) { + regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0); + return RT1318_R0_CALIB_NOT_DONE; + } + } + regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0); + regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val); + regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2); + if ((val & 0x1) & (val2 & 0x1)) + return RT1318_R0_IN_RANGE; + else + return RT1318_R0_OUT_OF_RANGE; +} + +static void rt1318_calibration_work(struct work_struct *work) +{ + struct rt1318_priv *rt1318 = + container_of(work, struct rt1318_priv, cali_work); + int ret; + + if (rt1318->pdata.init_r0_l && rt1318->pdata.init_r0_r) + rt1318_r0_restore(rt1318); + else { + ret = rt1318_calibrate(rt1318); + if (ret == RT1318_R0_IN_RANGE) + rt1318_r0_calculate(rt1318); + dev_dbg(rt1318->component->dev, "Calibrate R0 result:%d\n", ret); + } +} + +static int rt1318_i2c_probe(struct i2c_client *i2c) +{ + struct rt1318_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt1318_priv *rt1318; + int ret, val, val2, dev_id; + + rt1318 = devm_kzalloc(&i2c->dev, sizeof(struct rt1318_priv), + GFP_KERNEL); + if (!rt1318) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt1318); + + if (pdata) + rt1318->pdata = *pdata; + else + rt1318_parse_dt(rt1318, &i2c->dev); + + rt1318->regmap = devm_regmap_init_i2c(i2c, &rt1318_regmap); + if (IS_ERR(rt1318->regmap)) { + ret = PTR_ERR(rt1318->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt1318->regmap, RT1318_DEV_ID1, &val); + regmap_read(rt1318->regmap, RT1318_DEV_ID2, &val2); + dev_id = (val << 8) | val2; + if (dev_id != 0x6821) { + dev_err(&i2c->dev, + "Device with ID register %#x is not rt1318\n", + dev_id); + return -ENODEV; + } + + ret = regmap_register_patch(rt1318->regmap, init_list, + ARRAY_SIZE(init_list)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + INIT_WORK(&rt1318->cali_work, rt1318_calibration_work); + + return devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_rt1318, rt1318_dai, ARRAY_SIZE(rt1318_dai)); +} + +static struct i2c_driver rt1318_i2c_driver = { + .driver = { + .name = "rt1318", + .of_match_table = of_match_ptr(rt1318_of_match), + .acpi_match_table = ACPI_PTR(rt1318_acpi_match), + }, + .probe = rt1318_i2c_probe, + .id_table = rt1318_i2c_id, +}; +module_i2c_driver(rt1318_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT1318 driver"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt1318.h b/sound/soc/codecs/rt1318.h new file mode 100644 index 000000000000..cec40b484216 --- /dev/null +++ b/sound/soc/codecs/rt1318.h @@ -0,0 +1,342 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt1318.h -- Platform data for RT1318 + * + * Copyright 2024 Realtek Semiconductor Corp. + */ +#include + +#ifndef __RT1318_H__ +#define __RT1318_H__ + +struct rt1318_priv { + struct snd_soc_component *component; + struct rt1318_platform_data pdata; + struct work_struct cali_work; + struct regmap *regmap; + + unsigned int r0_l_integer; + unsigned int r0_l_factor; + unsigned int r0_r_integer; + unsigned int r0_r_factor; + int rt1318_init; + int rt1318_dvol; + int sysclk_src; + int sysclk; + int lrck; + int bclk; + int master; + int pll_src; + int pll_in; + int pll_out; +}; + +#define RT1318_PLL_INP_MAX 40000000 +#define RT1318_PLL_INP_MIN 256000 +#define RT1318_PLL_N_MAX 0x1ff +#define RT1318_PLL_K_MAX 0x1f +#define RT1318_PLL_M_MAX 0x1f + +#define RT1318_LRCLK_192000 192000 +#define RT1318_LRCLK_96000 96000 +#define RT1318_LRCLK_48000 48000 +#define RT1318_LRCLK_44100 44100 +#define RT1318_LRCLK_16000 16000 +#define RT1318_DVOL_STEP 383 + +#define RT1318_CLK1 0xc001 +#define RT1318_CLK2 0xc003 +#define RT1318_CLK3 0xc004 +#define RT1318_CLK4 0xc005 +#define RT1318_CLK5 0xc006 +#define RT1318_CLK6 0xc007 +#define RT1318_CLK7 0xc008 +#define RT1318_PWR_STA1 0xc121 +#define RT1318_SPK_VOL_TH 0xc130 +#define RT1318_TCON 0xc203 +#define RT1318_SRC_TCON 0xc204 +#define RT1318_TCON_RELATE 0xc206 +#define RT1318_DA_VOL_L_8 0xc20b +#define RT1318_DA_VOL_L_1_7 0xc20c +#define RT1318_DA_VOL_R_8 0xc20d +#define RT1318_DA_VOL_R_1_7 0xc20e +#define RT1318_FEEDBACK_PATH 0xc321 +#define RT1318_STP_TEMP_L 0xdb00 +#define RT1318_STP_SEL_L 0xdb08 +#define RT1318_STP_R0_EN_L 0xdb12 +#define RT1318_R0_CMP_L_FLAG 0xdb35 +#define RT1318_PRE_R0_L_24 0xdbb5 +#define RT1318_PRE_R0_L_23_16 0xdbb6 +#define RT1318_PRE_R0_L_15_8 0xdbb7 +#define RT1318_PRE_R0_L_7_0 0xdbb8 +#define RT1318_R0_L_24 0xdbc5 +#define RT1318_R0_L_23_16 0xdbc6 +#define RT1318_R0_L_15_8 0xdbc7 +#define RT1318_R0_L_7_0 0xdbc8 +#define RT1318_STP_SEL_R 0xdd08 +#define RT1318_STP_R0_EN_R 0xdd12 +#define RT1318_R0_CMP_R_FLAG 0xdd35 +#define RT1318_PRE_R0_R_24 0xddb5 +#define RT1318_PRE_R0_R_23_16 0xddb6 +#define RT1318_PRE_R0_R_15_8 0xddb7 +#define RT1318_PRE_R0_R_7_0 0xddb8 +#define RT1318_R0_R_24 0xddc5 +#define RT1318_R0_R_23_16 0xddc6 +#define RT1318_R0_R_15_8 0xddc7 +#define RT1318_R0_R_7_0 0xddc8 +#define RT1318_DEV_ID1 0xf012 +#define RT1318_DEV_ID2 0xf013 +#define RT1318_PLL1_K 0xf20d +#define RT1318_PLL1_M 0xf20f +#define RT1318_PLL1_N_8 0xf211 +#define RT1318_PLL1_N_7_0 0xf212 +#define RT1318_SINE_GEN0 0xf800 +#define RT1318_TDM_CTRL1 0xf900 +#define RT1318_TDM_CTRL2 0xf901 +#define RT1318_TDM_CTRL3 0xf902 +#define RT1318_TDM_CTRL9 0xf908 + + +/* Clock-1 (0xC001) */ +#define RT1318_PLLIN_MASK (0x7 << 4) +#define RT1318_PLLIN_BCLK0 (0x0 << 4) +#define RT1318_PLLIN_BCLK1 (0x1 << 4) +#define RT1318_PLLIN_RC (0x2 << 4) +#define RT1318_PLLIN_MCLK (0x3 << 4) +#define RT1318_PLLIN_SDW1 (0x4 << 4) +#define RT1318_PLLIN_SDW2 (0x5 << 4) +#define RT1318_PLLIN_SDW3 (0x6 << 4) +#define RT1318_PLLIN_SDW4 (0x7 << 4) +#define RT1318_SYSCLK_SEL_MASK (0x7 << 0) +#define RT1318_SYSCLK_BCLK (0x0 << 0) +#define RT1318_SYSCLK_SDW (0x1 << 0) +#define RT1318_SYSCLK_PLL2F (0x2 << 0) +#define RT1318_SYSCLK_PLL2B (0x3 << 0) +#define RT1318_SYSCLK_MCLK (0x4 << 0) +#define RT1318_SYSCLK_RC1 (0x5 << 0) +#define RT1318_SYSCLK_RC2 (0x6 << 0) +#define RT1318_SYSCLK_RC3 (0x7 << 0) +/* Clock-2 (0xC003) */ +#define RT1318_DIV_AP_MASK (0x3 << 4) +#define RT1318_DIV_AP_SFT 4 +#define RT1318_DIV_AP_DIV1 (0x0 << 4) +#define RT1318_DIV_AP_DIV2 (0x1 << 4) +#define RT1318_DIV_AP_DIV4 (0x2 << 4) +#define RT1318_DIV_AP_DIV8 (0x3 << 4) +#define RT1318_DIV_DAMOD_MASK (0x3 << 0) +#define RT1318_DIV_DAMOD_SFT 0 +#define RT1318_DIV_DAMOD_DIV1 (0x0 << 0) +#define RT1318_DIV_DAMOD_DIV2 (0x1 << 0) +#define RT1318_DIV_DAMOD_DIV4 (0x2 << 0) +#define RT1318_DIV_DAMOD_DIV8 (0x3 << 0) +/* Clock-3 (0xC004) */ +#define RT1318_AD_STO1_MASK (0x7 << 4) +#define RT1318_AD_STO1_SFT 4 +#define RT1318_AD_STO1_DIV1 (0x0 << 4) +#define RT1318_AD_STO1_DIV2 (0x1 << 4) +#define RT1318_AD_STO1_DIV4 (0x2 << 4) +#define RT1318_AD_STO1_DIV8 (0x3 << 4) +#define RT1318_AD_STO1_DIV16 (0x4 << 4) +#define RT1318_AD_STO2_MASK (0x7 << 0) +#define RT1318_AD_STO2_SFT 0 +#define RT1318_AD_STO2_DIV1 (0x0 << 0) +#define RT1318_AD_STO2_DIV2 (0x1 << 0) +#define RT1318_AD_STO2_DIV4 (0x2 << 0) +#define RT1318_AD_STO2_DIV8 (0x3 << 0) +#define RT1318_AD_STO2_DIV16 (0x4 << 0) +#define RT1318_AD_STO2_SFT 0 +/* Clock-4 (0xC005) */ +#define RT1318_AD_ANA_STO1_MASK (0x7 << 4) +#define RT1318_AD_ANA_STO1_SFT 4 +#define RT1318_AD_ANA_STO1_DIV1 (0x0 << 4) +#define RT1318_AD_ANA_STO1_DIV2 (0x1 << 4) +#define RT1318_AD_ANA_STO1_DIV4 (0x2 << 4) +#define RT1318_AD_ANA_STO1_DIV8 (0x3 << 4) +#define RT1318_AD_ANA_STO1_DIV16 (0x4 << 4) +#define RT1318_AD_ANA_STO2_MASK (0x7 << 0) +#define RT1318_AD_ANA_STO2_DIV1 (0x0 << 0) +#define RT1318_AD_ANA_STO2_DIV2 (0x1 << 0) +#define RT1318_AD_ANA_STO2_DIV4 (0x2 << 0) +#define RT1318_AD_ANA_STO2_DIV8 (0x3 << 0) +#define RT1318_AD_ANA_STO2_DIV16 (0x4 << 0) +#define RT1318_AD_ANA_STO2_SFT 0 +/* Clock-5 (0xC006) */ +#define RT1318_DIV_FIFO_IN_MASK (0x3 << 4) +#define RT1318_DIV_FIFO_IN_SFT 4 +#define RT1318_DIV_FIFO_IN_DIV1 (0x0 << 4) +#define RT1318_DIV_FIFO_IN_DIV2 (0x1 << 4) +#define RT1318_DIV_FIFO_IN_DIV4 (0x2 << 4) +#define RT1318_DIV_FIFO_IN_DIV8 (0x3 << 4) +#define RT1318_DIV_FIFO_OUT_MASK (0x3 << 0) +#define RT1318_DIV_FIFO_OUT_DIV1 (0x0 << 0) +#define RT1318_DIV_FIFO_OUT_DIV2 (0x1 << 0) +#define RT1318_DIV_FIFO_OUT_DIV4 (0x2 << 0) +#define RT1318_DIV_FIFO_OUT_DIV8 (0x3 << 0) +#define RT1318_DIV_FIFO_OUT_SFT 0 +/* Clock-6 (0xC007) */ +#define RT1318_DIV_NLMS_MASK (0x3 << 6) +#define RT1318_DIV_NLMS_SFT 6 +#define RT1318_DIV_NLMS_DIV1 (0x0 << 6) +#define RT1318_DIV_NLMS_DIV2 (0x1 << 6) +#define RT1318_DIV_NLMS_DIV4 (0x2 << 6) +#define RT1318_DIV_NLMS_DIV8 (0x3 << 6) +#define RT1318_DIV_AD_MONO_MASK (0x7 << 3) +#define RT1318_DIV_AD_MONO_SFT 3 +#define RT1318_DIV_AD_MONO_DIV1 (0x0 << 3) +#define RT1318_DIV_AD_MONO_DIV2 (0x1 << 3) +#define RT1318_DIV_AD_MONO_DIV4 (0x2 << 3) +#define RT1318_DIV_AD_MONO_DIV8 (0x3 << 3) +#define RT1318_DIV_AD_MONO_DIV16 (0x4 << 3) +#define RT1318_DIV_POST_G_MASK (0x7 << 0) +#define RT1318_DIV_POST_G_SFT 0 +#define RT1318_DIV_POST_G_DIV1 (0x0 << 0) +#define RT1318_DIV_POST_G_DIV2 (0x1 << 0) +#define RT1318_DIV_POST_G_DIV4 (0x2 << 0) +#define RT1318_DIV_POST_G_DIV8 (0x3 << 0) +#define RT1318_DIV_POST_G_DIV16 (0x4 << 0) +/* Power Status 1 (0xC121) */ +#define RT1318_PDB_CTRL_MASK (0x1) +#define RT1318_PDB_CTRL_LOW (0x0) +#define RT1318_PDB_CTRL_HIGH (0x1) +#define RT1318_PDB_CTRL_SFT 0 +/* SRC Tcon(0xc204) */ +#define RT1318_SRCIN_IN_SEL_MASK (0x3 << 6) +#define RT1318_SRCIN_IN_48K (0x0 << 6) +#define RT1318_SRCIN_IN_44P1 (0x1 << 6) +#define RT1318_SRCIN_IN_32K (0x2 << 6) +#define RT1318_SRCIN_IN_16K (0x3 << 6) +#define RT1318_SRCIN_F12288_MASK (0x3 << 4) +#define RT1318_SRCIN_TCON1 (0x0 << 4) +#define RT1318_SRCIN_TCON2 (0x1 << 4) +#define RT1318_SRCIN_TCON4 (0x2 << 4) +#define RT1318_SRCIN_TCON8 (0x3 << 4) +#define RT1318_SRCIN_DACLK_MASK (0x3 << 2) +#define RT1318_DACLK_TCON1 (0x0 << 2) +#define RT1318_DACLK_TCON2 (0x1 << 2) +#define RT1318_DACLK_TCON4 (0x2 << 2) +#define RT1318_DACLK_TCON8 (0x3 << 2) +/* R0 Compare Flag (0xDB35) */ +#define RT1318_R0_RANGE_MASK (0x1) +#define RT1318_R0_OUTOFRANGE (0x0) +#define RT1318_R0_INRANGE (0x1) +/* PLL internal setting (0xF20D), K value */ +#define RT1318_K_PLL1_MASK (0x1f << 0) +/* PLL internal setting (0xF20F), M value */ +#define RT1318_M_PLL1_MASK (0x1f << 0) +/* PLL internal setting (0xF211), N_8 value */ +#define RT1318_N_8_PLL1_MASK (0x1 << 0) +/* PLL internal setting (0xF212), N_7_0 value */ +#define RT1318_N_7_0_PLL1_MASK (0xff << 0) +/* TDM CTRL 1 (0xf900) */ +#define RT1318_TDM_BCLK_MASK (0x1 << 7) +#define RT1318_TDM_BCLK_NORM (0x0 << 7) +#define RT1318_TDM_BCLK_INV (0x1 << 7) +#define RT1318_I2S_FMT_MASK (0x7 << 0) +#define RT1318_FMT_I2S (0x0 << 0) +#define RT1318_FMT_LEFT_J (0x1 << 0) +#define RT1318_FMT_PCM_A_R (0x2 << 0) +#define RT1318_FMT_PCM_B_R (0x3 << 0) +#define RT1318_FMT_PCM_A_F (0x6 << 0) +#define RT1318_FMT_PCM_B_F (0x7 << 0) +#define RT1318_I2S_FMT_SFT 0 +/* TDM CTRL 2 (0xf901) */ +#define RT1318_I2S_CH_TX_MASK (0x3 << 6) +#define RT1318_I2S_CH_TX_2CH (0x0 << 6) +#define RT1318_I2S_CH_TX_4CH (0x1 << 6) +#define RT1318_I2S_CH_TX_6CH (0x2 << 6) +#define RT1318_I2S_CH_TX_8CH (0x3 << 6) +#define RT1318_I2S_CH_RX_MASK (0x3 << 4) +#define RT1318_I2S_CH_RX_2CH (0x0 << 4) +#define RT1318_I2S_CH_RX_4CH (0x1 << 4) +#define RT1318_I2S_CH_RX_6CH (0x2 << 4) +#define RT1318_I2S_CH_RX_8CH (0x3 << 4) +#define RT1318_I2S_DL_MASK 0x7 +#define RT1318_I2S_DL_SFT 0 +#define RT1318_I2S_DL_16 0x0 +#define RT1318_I2S_DL_20 0x1 +#define RT1318_I2S_DL_24 0x2 +#define RT1318_I2S_DL_32 0x3 +#define RT1318_I2S_DL_8 0x4 +/* TDM CTRL 3 (0xf902) */ +#define RT1318_I2S_TX_CHL_MASK (0x7 << 4) +#define RT1318_I2S_TX_CHL_SFT 4 +#define RT1318_I2S_TX_CHL_16 (0x0 << 4) +#define RT1318_I2S_TX_CHL_20 (0x1 << 4) +#define RT1318_I2S_TX_CHL_24 (0x2 << 4) +#define RT1318_I2S_TX_CHL_32 (0x3 << 4) +#define RT1318_I2S_TX_CHL_8 (0x4 << 4) +#define RT1318_I2S_RX_CHL_MASK (0x7 << 0) +#define RT1318_I2S_RX_CHL_SFT 0 +#define RT1318_I2S_RX_CHL_16 (0x0 << 0) +#define RT1318_I2S_RX_CHL_20 (0x1 << 0) +#define RT1318_I2S_RX_CHL_24 (0x2 << 0) +#define RT1318_I2S_RX_CHL_32 (0x3 << 0) +#define RT1318_I2S_RX_CHL_8 (0x4 << 0) +/* TDM CTRL 9 (0xf908) */ +#define RT1318_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 4) +#define RT1318_TDM_I2S_TX_R_DAC1_1_MASK 0x7 +#define RT1318_TDM_I2S_TX_L_DAC1_1_SFT 4 +#define RT1318_TDM_I2S_TX_R_DAC1_1_SFT 0 + +#define RT1318_REG_DISP_LEN 23 + +/* System Clock Source */ +enum { + RT1318_SCLK_S_BCLK, + RT1318_SCLK_S_SDW, + RT1318_SCLK_S_PLL2F, + RT1318_SCLK_S_PLL2B, + RT1318_SCLK_S_MCLK, + RT1318_SCLK_S_RC0, + RT1318_SCLK_S_RC1, + RT1318_SCLK_S_RC2, +}; + +/* PLL Source */ +enum { + RT1318_PLL_S_BCLK0, + RT1318_PLL_S_BCLK1, + RT1318_PLL_S_RC, + RT1318_PLL_S_MCLK, + RT1318_PLL_S_SDW_IN_PLL, + RT1318_PLL_S_SDW_0, + RT1318_PLL_S_SDW_1, + RT1318_PLL_S_SDW_2, +}; + +/* TDM channel */ +enum { + RT1318_2CH, + RT1318_4CH, + RT1318_6CH, + RT1318_8CH, +}; + +/* R0 calibration result */ +enum { + RT1318_R0_OUT_OF_RANGE, + RT1318_R0_IN_RANGE, + RT1318_R0_CALIB_NOT_DONE, +}; + +/* PLL pre-defined M/N/K */ + +struct pll_calc_map { + unsigned int pll_in; + unsigned int pll_out; + int k; + int n; + int m; + bool m_bp; + bool k_bp; +}; + +struct rt1318_pll_code { + bool m_bp; /* Indicates bypass m code or not. */ + bool k_bp; /* Indicates bypass k code or not. */ + int m_code; + int n_code; + int k_code; +}; + +#endif /* __RT1318_H__ */ -- cgit v1.2.3 From 00dd4d86ed908e70d912a96ad91d1248ff055b62 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 21 Jun 2024 21:23:07 +0800 Subject: ASoc: tas2781: Add name_prefix as the prefix name of firmwares and kcontrol to support corresponding TAS2563/TAS2781s Add name_prefix as the prefix name of firmwares and kcontrol to support corresponding TAS2563/TAS2781s. name_prefix is not mandatory. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240621132309.564-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781.h | 1 + sound/soc/codecs/tas2781-comlib.c | 13 +++++++++---- sound/soc/codecs/tas2781-i2c.c | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index 99ca3e401fd1..cd8ce522b78e 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -108,6 +108,7 @@ struct tasdevice_priv { unsigned char coef_binaryname[64]; unsigned char rca_binaryname[64]; unsigned char dev_name[32]; + const char *name_prefix; unsigned char ndev; unsigned int magic_num; unsigned int chip_id; diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index 3aa81514dad7..6db1a260da82 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 // -// tas2781-lib.c -- TAS2781 Common functions for HDA and ASoC Audio drivers +// TAS2781 Common functions for HDA and ASoC Audio drivers // -// Copyright 2023 Texas Instruments, Inc. +// Copyright 2023 - 2024 Texas Instruments, Inc. // // Author: Shenghao Ding @@ -277,8 +277,13 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, */ mutex_lock(&tas_priv->codec_lock); - scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin", - tas_priv->dev_name, tas_priv->ndev); + if (tas_priv->name_prefix) + scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin", + tas_priv->name_prefix, tas_priv->dev_name, + tas_priv->ndev); + else + scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin", + tas_priv->dev_name, tas_priv->ndev); crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL); tas_priv->codec = codec; ret = request_firmware_nowait(module, FW_ACTION_UEVENT, diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index c64d458e524e..4d1a0d836e77 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -579,6 +579,7 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec) { struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + tas_priv->name_prefix = codec->name_prefix; return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready); } -- cgit v1.2.3 From fafc20ded3f4659873c83c2af6d389983d480994 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 Jun 2024 06:02:26 +0000 Subject: ASoC: audio-graph-port: add link-trigger-order Sound Card need to consider/adjust HW control ordering based on the combination of CPU/Codec. The controlling feature is already supported on ASoC, but Simple Audio Card / Audio Graph Card still not support it. Let's support it. Cc: Maxim Kochetkov Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87sexizojx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-port.yaml | 9 ++++++++ include/dt-bindings/sound/audio-graph.h | 26 ++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 include/dt-bindings/sound/audio-graph.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index 28b27e7e45de..d1cbfc5edd3a 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -25,6 +25,15 @@ definitions: capture-only: description: port connection used only for capture $ref: /schemas/types.yaml#/definitions/flag + link-trigger-order: + description: trigger order for both start/stop + $ref: /schemas/types.yaml#/definitions/uint32-array + link-trigger-order-start: + description: trigger order for start + $ref: /schemas/types.yaml#/definitions/uint32-array + link-trigger-order-stop: + description: trigger order for stop + $ref: /schemas/types.yaml#/definitions/uint32-array endpoint-base: allOf: diff --git a/include/dt-bindings/sound/audio-graph.h b/include/dt-bindings/sound/audio-graph.h new file mode 100644 index 000000000000..bdb70c6b7332 --- /dev/null +++ b/include/dt-bindings/sound/audio-graph.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * audio-graph.h + * + * Copyright (c) 2024 Kuninori Morimoto + */ +#ifndef __AUDIO_GRAPH_H +#define __AUDIO_GRAPH_H + +/* + * used in + * link-trigger-order + * link-trigger-order-start + * link-trigger-order-stop + * + * default is + * link-trigger-order = ; + */ +#define SND_SOC_TRIGGER_LINK 0 +#define SND_SOC_TRIGGER_COMPONENT 1 +#define SND_SOC_TRIGGER_DAI 2 +#define SND_SOC_TRIGGER_SIZE 3 /* shoud be last */ + +#endif /* __AUDIO_GRAPH_H */ -- cgit v1.2.3 From 5d9cacdccf17bd33dac3ea378324650159c2a863 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 Jun 2024 06:02:33 +0000 Subject: ASoC: simple-card-utils: add link-trigger-order support Some Sound Card might need special trigger ordering which is based on CPU/Codec connection. It is already supported on ASoC, but Simple Audio Card / Audio Graph Card still not support it. Let's support it. Cc: Maxim Kochetkov Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87r0d2zojq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 4 ++ sound/soc/generic/simple-card-utils.c | 71 +++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) (limited to 'include') diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 0a6435ac5c5f..3360d9eab068 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -199,6 +199,10 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep, void graph_util_parse_link_direction(struct device_node *np, bool *is_playback_only, bool *is_capture_only); +void graph_util_parse_trigger_order(struct simple_util_priv *priv, + struct device_node *np, + enum snd_soc_trigger_order *trigger_start, + enum snd_soc_trigger_order *trigger_stop); #ifdef DEBUG static inline void simple_util_debug_dai(struct simple_util_priv *priv, diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index dcd0569157ce..a18de86b3c88 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -4,6 +4,7 @@ // // Copyright (c) 2016 Kuninori Morimoto +#include #include #include #include @@ -1156,6 +1157,76 @@ void graph_util_parse_link_direction(struct device_node *np, } EXPORT_SYMBOL_GPL(graph_util_parse_link_direction); +static enum snd_soc_trigger_order +__graph_util_parse_trigger_order(struct simple_util_priv *priv, + struct device_node *np, + const char *prop) +{ + u32 val[SND_SOC_TRIGGER_SIZE]; + int ret; + + ret = of_property_read_u32_array(np, prop, val, SND_SOC_TRIGGER_SIZE); + if (ret == 0) { + struct device *dev = simple_priv_to_dev(priv); + u32 order = (val[0] << 8) + + (val[1] << 4) + + (val[2]); + + switch (order) { + case (SND_SOC_TRIGGER_LINK << 8) + + (SND_SOC_TRIGGER_COMPONENT << 4) + + (SND_SOC_TRIGGER_DAI): + return SND_SOC_TRIGGER_ORDER_DEFAULT; + + case (SND_SOC_TRIGGER_LINK << 8) + + (SND_SOC_TRIGGER_DAI << 4) + + (SND_SOC_TRIGGER_COMPONENT): + return SND_SOC_TRIGGER_ORDER_LDC; + + default: + dev_err(dev, "unsupported trigger order [0x%x]\n", order); + } + } + + /* SND_SOC_TRIGGER_ORDER_MAX means error */ + return SND_SOC_TRIGGER_ORDER_MAX; +} + +void graph_util_parse_trigger_order(struct simple_util_priv *priv, + struct device_node *np, + enum snd_soc_trigger_order *trigger_start, + enum snd_soc_trigger_order *trigger_stop) +{ + static enum snd_soc_trigger_order order; + + /* + * We can use it like below + * + * #include + * + * link-trigger-order = ; + */ + + order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order"); + if (order < SND_SOC_TRIGGER_ORDER_MAX) { + *trigger_start = order; + *trigger_stop = order; + } + + order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-start"); + if (order < SND_SOC_TRIGGER_ORDER_MAX) + *trigger_start = order; + + order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-stop"); + if (order < SND_SOC_TRIGGER_ORDER_MAX) + *trigger_stop = order; + + return; +} +EXPORT_SYMBOL_GPL(graph_util_parse_trigger_order); + /* Module information */ MODULE_AUTHOR("Kuninori Morimoto "); MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); -- cgit v1.2.3 From 5d7e328e20b3d2bd3e1e8bea7a868ab8892aeed1 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 1 Jul 2024 11:44:42 +0100 Subject: ASoC: cs35l56: Revert support for dual-ownership of ASP registers This patch reverts a series of commits that allowed for the ASP registers to be owned by either the driver or the firmware. Nothing currently depends on the functionality that is being reverted, so it is safe to remove. The commits being reverted are (last 3 are bugfixes to the first 2): commit 72a77d7631c6 ("ASoC: cs35l56: Fix to ensure ASP1 registers match cache") commit 07f7d6e7a124 ("ASoC: cs35l56: Fix for initializing ASP1 mixer registers") commit 4703b014f28b ("ASoC: cs35l56: fix reversed if statement in cs35l56_dspwait_asp1tx_put()") commit c14f09f010cc ("ASoC: cs35l56: Fix deadlock in ASP1 mixer register initialization") commit dfd2ffb37399 ("ASoC: cs35l56: Prevent overwriting firmware ASP config") These reverts have been squashed into a single commit because there would be no reason to revert only some of them (which would just reintroduce bugs). The changes introduced by the commits were well-intentioned but somewhat misguided. ACPI does not provide any information about how audio hardware is linked together, so that information has to be hardcoded into drivers. On Windows the firmware is customized to statically setup appropriate configuration of the audio links, and the intent of the commits was to re-use this information if the Linux host drivers aren't taking control of the ASP. This would avoid having to hardcode the ASP config into the machine driver on some systems. However, this added complexity and race conditions into the driver. It also complicates implementation of new code. The only case where the ASP is used but the host is not taking ownership is when CS35L56 is used in SoundWire mode with the ASP as a reference audio interconnect. But even in that case it's not necessarily required even if the firmware initialized it. Typically it is used to avoid the host SDCA drivers having to be capable of aggregating capture paths from multiple SoundWire peripherals. But the SOF SoundWire support is capable of doing that aggregation. Reverting all these commits significantly simplifies the driver. Let's just use the normal Linux mechanisms of the machine driver and ALSA controls to set things up instead of trying to use the firmware to do use-case setup. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20240701104444.172556-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 9 +- sound/soc/codecs/cs35l56-shared.c | 101 +++++-------------- sound/soc/codecs/cs35l56.c | 205 +++----------------------------------- sound/soc/codecs/cs35l56.h | 1 - 4 files changed, 43 insertions(+), 273 deletions(-) (limited to 'include') diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 1a3c6f66f620..2e19722989f7 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -267,13 +267,18 @@ struct cs35l56_base { bool fw_patched; bool secured; bool can_hibernate; - bool fw_owns_asp1; bool cal_data_valid; s8 cal_index; struct cirrus_amp_cal_data cal_data; struct gpio_desc *reset_gpio; }; +/* Temporary to avoid a build break with the HDA driver */ +static inline int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base) +{ + return 0; +} + extern struct regmap_config cs35l56_regmap_i2c; extern struct regmap_config cs35l56_regmap_spi; extern struct regmap_config cs35l56_regmap_sdw; @@ -284,8 +289,6 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC]; extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; int cs35l56_set_patch(struct cs35l56_base *cs35l56_base); -int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base); -int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base); int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command); int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base); int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 880228f89baf..035d7c3c4683 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -20,6 +20,18 @@ static const struct reg_sequence cs35l56_patch[] = { * Firmware can change these to non-defaults to satisfy SDCA. * Ensure that they are at known defaults. */ + { CS35L56_ASP1_ENABLES1, 0x00000000 }, + { CS35L56_ASP1_CONTROL1, 0x00000028 }, + { CS35L56_ASP1_CONTROL2, 0x18180200 }, + { CS35L56_ASP1_CONTROL3, 0x00000002 }, + { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 }, + { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 }, + { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, + { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, + { CS35L56_ASP1TX1_INPUT, 0x00000000 }, + { CS35L56_ASP1TX2_INPUT, 0x00000000 }, + { CS35L56_ASP1TX3_INPUT, 0x00000000 }, + { CS35L56_ASP1TX4_INPUT, 0x00000000 }, { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 }, { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 }, { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 }, @@ -41,12 +53,18 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED); static const struct reg_default cs35l56_reg_defaults[] = { /* no defaults for OTP_MEM - first read populates cache */ - /* - * No defaults for ASP1 control or ASP1TX mixer. See - * cs35l56_populate_asp1_register_defaults() and - * cs35l56_sync_asp1_mixer_widgets_with_firmware(). - */ - + { CS35L56_ASP1_ENABLES1, 0x00000000 }, + { CS35L56_ASP1_CONTROL1, 0x00000028 }, + { CS35L56_ASP1_CONTROL2, 0x18180200 }, + { CS35L56_ASP1_CONTROL3, 0x00000002 }, + { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 }, + { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 }, + { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, + { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, + { CS35L56_ASP1TX1_INPUT, 0x00000000 }, + { CS35L56_ASP1TX2_INPUT, 0x00000000 }, + { CS35L56_ASP1TX3_INPUT, 0x00000000 }, + { CS35L56_ASP1TX4_INPUT, 0x00000000 }, { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 }, { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 }, { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 }, @@ -206,77 +224,6 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) } } -static const struct reg_sequence cs35l56_asp1_defaults[] = { - REG_SEQ0(CS35L56_ASP1_ENABLES1, 0x00000000), - REG_SEQ0(CS35L56_ASP1_CONTROL1, 0x00000028), - REG_SEQ0(CS35L56_ASP1_CONTROL2, 0x18180200), - REG_SEQ0(CS35L56_ASP1_CONTROL3, 0x00000002), - REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL1, 0x03020100), - REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL5, 0x00020100), - REG_SEQ0(CS35L56_ASP1_DATA_CONTROL1, 0x00000018), - REG_SEQ0(CS35L56_ASP1_DATA_CONTROL5, 0x00000018), - REG_SEQ0(CS35L56_ASP1TX1_INPUT, 0x00000000), - REG_SEQ0(CS35L56_ASP1TX2_INPUT, 0x00000000), - REG_SEQ0(CS35L56_ASP1TX3_INPUT, 0x00000000), - REG_SEQ0(CS35L56_ASP1TX4_INPUT, 0x00000000), -}; - -/* - * The firmware can have control of the ASP so we don't provide regmap - * with defaults for these registers, to prevent a regcache_sync() from - * overwriting the firmware settings. But if the machine driver hooks up - * the ASP it means the driver is taking control of the ASP, so then the - * registers are populated with the defaults. - */ -int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base) -{ - if (!cs35l56_base->fw_owns_asp1) - return 0; - - cs35l56_base->fw_owns_asp1 = false; - - return regmap_multi_reg_write(cs35l56_base->regmap, cs35l56_asp1_defaults, - ARRAY_SIZE(cs35l56_asp1_defaults)); -} -EXPORT_SYMBOL_NS_GPL(cs35l56_init_asp1_regs_for_driver_control, SND_SOC_CS35L56_SHARED); - -/* - * The firmware boot sequence can overwrite the ASP1 config registers so that - * they don't match regmap's view of their values. Rewrite the values from the - * regmap cache into the hardware registers. - */ -int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base) -{ - struct reg_sequence asp1_regs[ARRAY_SIZE(cs35l56_asp1_defaults)]; - int i, ret; - - if (cs35l56_base->fw_owns_asp1) - return 0; - - memcpy(asp1_regs, cs35l56_asp1_defaults, sizeof(asp1_regs)); - - /* Read current values from regmap cache into the write sequence */ - for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) { - ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def); - if (ret) - goto err; - } - - /* Write the values cache-bypassed so that they will be written to silicon */ - ret = regmap_multi_reg_write_bypassed(cs35l56_base->regmap, asp1_regs, - ARRAY_SIZE(asp1_regs)); - if (ret) - goto err; - - return 0; - -err: - dev_err(cs35l56_base->dev, "Failed to sync ASP1 registers: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(cs35l56_force_sync_asp1_registers_from_cache, SND_SOC_CS35L56_SHARED); - int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) { unsigned int val; diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 758dfdf9d3ea..7cac9812f5b5 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -63,131 +63,6 @@ static int cs35l56_dspwait_put_volsw(struct snd_kcontrol *kcontrol, return snd_soc_put_volsw(kcontrol, ucontrol); } -static const unsigned short cs35l56_asp1_mixer_regs[] = { - CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX2_INPUT, - CS35L56_ASP1TX3_INPUT, CS35L56_ASP1TX4_INPUT, -}; - -static const char * const cs35l56_asp1_mux_control_names[] = { - "ASP1 TX1 Source", "ASP1 TX2 Source", "ASP1 TX3 Source", "ASP1 TX4 Source" -}; - -static int cs35l56_sync_asp1_mixer_widgets_with_firmware(struct cs35l56_private *cs35l56) -{ - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component); - const char *prefix = cs35l56->component->name_prefix; - char full_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - const char *name; - struct snd_kcontrol *kcontrol; - struct soc_enum *e; - unsigned int val[4]; - int i, item, ret; - - if (cs35l56->asp1_mixer_widgets_initialized) - return 0; - - /* - * Resume so we can read the registers from silicon if the regmap - * cache has not yet been populated. - */ - ret = pm_runtime_resume_and_get(cs35l56->base.dev); - if (ret < 0) - return ret; - - /* Wait for firmware download and reboot */ - cs35l56_wait_dsp_ready(cs35l56); - - ret = regmap_bulk_read(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, - val, ARRAY_SIZE(val)); - - pm_runtime_mark_last_busy(cs35l56->base.dev); - pm_runtime_put_autosuspend(cs35l56->base.dev); - - if (ret) { - dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(cs35l56_asp1_mux_control_names); ++i) { - name = cs35l56_asp1_mux_control_names[i]; - - if (prefix) { - snprintf(full_name, sizeof(full_name), "%s %s", prefix, name); - name = full_name; - } - - kcontrol = snd_soc_card_get_kcontrol_locked(dapm->card, name); - if (!kcontrol) { - dev_warn(cs35l56->base.dev, "Could not find control %s\n", name); - continue; - } - - e = (struct soc_enum *)kcontrol->private_value; - item = snd_soc_enum_val_to_item(e, val[i] & CS35L56_ASP_TXn_SRC_MASK); - snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL); - } - - cs35l56->asp1_mixer_widgets_initialized = true; - - return 0; -} - -static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); - struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int index = e->shift_l; - unsigned int addr, val; - int ret; - - ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56); - if (ret) - return ret; - - addr = cs35l56_asp1_mixer_regs[index]; - ret = regmap_read(cs35l56->base.regmap, addr, &val); - if (ret) - return ret; - - val &= CS35L56_ASP_TXn_SRC_MASK; - ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); - - return 0; -} - -static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); - struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); - struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int item = ucontrol->value.enumerated.item[0]; - int index = e->shift_l; - unsigned int addr, val; - bool changed; - int ret; - - ret = cs35l56_sync_asp1_mixer_widgets_with_firmware(cs35l56); - if (ret) - return ret; - - addr = cs35l56_asp1_mixer_regs[index]; - val = snd_soc_enum_item_to_val(e, item); - - ret = regmap_update_bits_check(cs35l56->base.regmap, addr, - CS35L56_ASP_TXn_SRC_MASK, val, &changed); - if (ret) - return ret; - - if (changed) - snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL); - - return changed; -} - static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0); static const struct snd_kcontrol_new cs35l56_controls[] = { @@ -206,44 +81,40 @@ static const struct snd_kcontrol_new cs35l56_controls[] = { }; static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum, - SND_SOC_NOPM, - 0, 0, + CS35L56_ASP1TX1_INPUT, + 0, CS35L56_ASP_TXn_SRC_MASK, cs35l56_tx_input_texts, cs35l56_tx_input_values); static const struct snd_kcontrol_new asp1_tx1_mux = - SOC_DAPM_ENUM_EXT("ASP1TX1 SRC", cs35l56_asp1tx1_enum, - cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put); + SOC_DAPM_ENUM("ASP1TX1 SRC", cs35l56_asp1tx1_enum); static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx2_enum, - SND_SOC_NOPM, - 1, 0, + CS35L56_ASP1TX2_INPUT, + 0, CS35L56_ASP_TXn_SRC_MASK, cs35l56_tx_input_texts, cs35l56_tx_input_values); static const struct snd_kcontrol_new asp1_tx2_mux = - SOC_DAPM_ENUM_EXT("ASP1TX2 SRC", cs35l56_asp1tx2_enum, - cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put); + SOC_DAPM_ENUM("ASP1TX2 SRC", cs35l56_asp1tx2_enum); static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx3_enum, - SND_SOC_NOPM, - 2, 0, + CS35L56_ASP1TX3_INPUT, + 0, CS35L56_ASP_TXn_SRC_MASK, cs35l56_tx_input_texts, cs35l56_tx_input_values); static const struct snd_kcontrol_new asp1_tx3_mux = - SOC_DAPM_ENUM_EXT("ASP1TX3 SRC", cs35l56_asp1tx3_enum, - cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put); + SOC_DAPM_ENUM("ASP1TX3 SRC", cs35l56_asp1tx3_enum); static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx4_enum, - SND_SOC_NOPM, - 3, 0, + CS35L56_ASP1TX4_INPUT, + 0, CS35L56_ASP_TXn_SRC_MASK, cs35l56_tx_input_texts, cs35l56_tx_input_values); static const struct snd_kcontrol_new asp1_tx4_mux = - SOC_DAPM_ENUM_EXT("ASP1TX4 SRC", cs35l56_asp1tx4_enum, - cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put); + SOC_DAPM_ENUM("ASP1TX4 SRC", cs35l56_asp1tx4_enum); static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx1_enum, CS35L56_SWIRE_DP3_CH1_INPUT, @@ -281,21 +152,6 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx4_enum, static const struct snd_kcontrol_new sdw1_tx4_mux = SOC_DAPM_ENUM("SDW1TX4 SRC", cs35l56_sdw1tx4_enum); -static int cs35l56_asp1_cfg_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Override register values set by firmware boot */ - return cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); - default: - return 0; - } -} - static int cs35l56_play_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -332,9 +188,6 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = { SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_B", 0, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_AMP", 0, 0), - SND_SOC_DAPM_SUPPLY("ASP1 CFG", SND_SOC_NOPM, 0, 0, cs35l56_asp1_cfg_event, - SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_SUPPLY("PLAY", SND_SOC_NOPM, 0, 0, cs35l56_play_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), @@ -402,9 +255,6 @@ static const struct snd_soc_dapm_route cs35l56_audio_map[] = { { "AMP", NULL, "VDD_B" }, { "AMP", NULL, "VDD_AMP" }, - { "ASP1 Playback", NULL, "ASP1 CFG" }, - { "ASP1 Capture", NULL, "ASP1 CFG" }, - { "ASP1 Playback", NULL, "PLAY" }, { "SDW1 Playback", NULL, "PLAY" }, @@ -455,14 +305,9 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component); unsigned int val; - int ret; dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt); - ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); - if (ret) - return ret; - switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { case SND_SOC_DAIFMT_CBC_CFC: break; @@ -536,11 +381,6 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx unsigned int rx_mask, int slots, int slot_width) { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); - int ret; - - ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); - if (ret) - return ret; if ((slots == 0) || (slot_width == 0)) { dev_dbg(cs35l56->base.dev, "tdm config cleared\n"); @@ -589,11 +429,6 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream, struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); unsigned int rate = params_rate(params); u8 asp_width, asp_wl; - int ret; - - ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); - if (ret) - return ret; asp_wl = params_width(params); if (cs35l56->asp_slot_width) @@ -650,11 +485,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); - int freq_id, ret; - - ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); - if (ret) - return ret; + int freq_id; if (freq == 0) { cs35l56->sysclk_set = false; @@ -1035,13 +866,6 @@ static int cs35l56_component_probe(struct snd_soc_component *component) debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate); debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched); - /* - * The widgets for the ASP1TX mixer can't be initialized - * until the firmware has been downloaded and rebooted. - */ - regcache_drop_region(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX4_INPUT); - cs35l56->asp1_mixer_widgets_initialized = false; - queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work); return 0; @@ -1432,9 +1256,6 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) cs35l56->base.cal_index = -1; cs35l56->speaker_id = -ENOENT; - /* Assume that the firmware owns ASP1 until we know different */ - cs35l56->base.fw_owns_asp1 = true; - dev_set_drvdata(cs35l56->base.dev, cs35l56); cs35l56_fill_supply_names(cs35l56->supplies); diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index b000e7365e40..200f695efca3 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -51,7 +51,6 @@ struct cs35l56_private { u8 asp_slot_count; bool tdm_mode; bool sysclk_set; - bool asp1_mixer_widgets_initialized; u8 old_sdw_clock_scale; }; -- cgit v1.2.3 From e2996141d6db0d8b353e1c221a37c8e1be109d4a Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 1 Jul 2024 11:44:43 +0100 Subject: ASoC: cs35l56: Remove support for A1 silicon No product was ever released with A1 silicon so there is no need for the driver to include support for it. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20240701104444.172556-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 2 -- sound/soc/codecs/cs35l56-sdw.c | 74 --------------------------------------- sound/soc/codecs/cs35l56-shared.c | 21 ++--------- sound/soc/codecs/cs35l56.h | 1 - 4 files changed, 2 insertions(+), 96 deletions(-) (limited to 'include') diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 2e19722989f7..642ef690ebc2 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -80,9 +80,7 @@ #define CS35L56_DSP1_AHBM_WINDOW_DEBUG_1 0x25E2044 #define CS35L56_DSP1_XMEM_UNPACKED24_0 0x2800000 #define CS35L56_DSP1_FW_VER 0x2800010 -#define CS35L56_DSP1_HALO_STATE_A1 0x2801E58 #define CS35L56_DSP1_HALO_STATE 0x28021E0 -#define CS35L56_DSP1_PM_CUR_STATE_A1 0x2804000 #define CS35L56_DSP1_PM_CUR_STATE 0x2804308 #define CS35L56_DSP1_XMEM_UNPACKED24_8191 0x2807FFC #define CS35L56_DSP1_CORE_BASE 0x2B80000 diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 70ff55c1517f..8862107105ae 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -317,79 +317,6 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral, return 0; } -static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, - struct sdw_slave *peripheral) -{ - unsigned int curr_scale_reg, next_scale_reg; - int curr_scale, next_scale, ret; - - if (!cs35l56->base.init_done) - return 0; - - if (peripheral->bus->params.curr_bank) { - curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1; - next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0; - } else { - curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0; - next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1; - } - - /* - * Current clock scale value must be different to new value. - * Modify current to guarantee this. If next still has the dummy - * value we wrote when it was current, the core code has not set - * a new scale so restore its original good value - */ - curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg); - if (curr_scale < 0) { - dev_err(cs35l56->base.dev, "Failed to read current clock scale: %d\n", curr_scale); - return curr_scale; - } - - next_scale = sdw_read_no_pm(peripheral, next_scale_reg); - if (next_scale < 0) { - dev_err(cs35l56->base.dev, "Failed to read next clock scale: %d\n", next_scale); - return next_scale; - } - - if (next_scale == CS35L56_SDW_INVALID_BUS_SCALE) { - next_scale = cs35l56->old_sdw_clock_scale; - ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale); - if (ret < 0) { - dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", - ret); - return ret; - } - } - - cs35l56->old_sdw_clock_scale = curr_scale; - ret = sdw_write_no_pm(peripheral, curr_scale_reg, CS35L56_SDW_INVALID_BUS_SCALE); - if (ret < 0) { - dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", ret); - return ret; - } - - dev_dbg(cs35l56->base.dev, "Next bus scale: %#x\n", next_scale); - - return 0; -} - -static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral, - struct sdw_bus_params *params) -{ - struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); - int sclk; - - sclk = params->curr_dr_freq / 2; - dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n", - __func__, sclk, params->col, params->row); - - if ((cs35l56->base.type == 0x56) && (cs35l56->base.rev < 0xb0)) - return cs35l56_a1_kick_divider(cs35l56, peripheral); - - return 0; -} - static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral, enum sdw_clk_stop_mode mode, enum sdw_clk_stop_type type) @@ -405,7 +332,6 @@ static const struct sdw_slave_ops cs35l56_sdw_ops = { .read_prop = cs35l56_sdw_read_prop, .interrupt_callback = cs35l56_sdw_interrupt, .update_status = cs35l56_sdw_update_status, - .bus_config = cs35l56_sdw_bus_config, #ifdef DEBUG .clk_stop = cs35l56_sdw_clk_stop, #endif diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 035d7c3c4683..e7e8d617da94 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -245,19 +245,13 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED); int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base) { int ret; - unsigned int reg; unsigned int val; ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_SHUTDOWN); if (ret) return ret; - if (cs35l56_base->rev < CS35L56_REVID_B0) - reg = CS35L56_DSP1_PM_CUR_STATE_A1; - else - reg = CS35L56_DSP1_PM_CUR_STATE; - - ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg, + ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP1_PM_CUR_STATE, val, (val == CS35L56_HALO_STATE_SHUTDOWN), CS35L56_HALO_STATE_POLL_US, CS35L56_HALO_STATE_TIMEOUT_US); @@ -270,15 +264,9 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED); int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) { - unsigned int reg; unsigned int val = 0; int read_ret, poll_ret; - if (cs35l56_base->rev < CS35L56_REVID_B0) - reg = CS35L56_DSP1_HALO_STATE_A1; - else - reg = CS35L56_DSP1_HALO_STATE; - /* * The regmap must remain in cache-only until the chip has * booted, so use a bypassed read of the status register. @@ -288,7 +276,7 @@ int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) CS35L56_HALO_STATE_POLL_US, CS35L56_HALO_STATE_TIMEOUT_US, false, - cs35l56_base->regmap, reg, &val); + cs35l56_base->regmap, CS35L56_DSP1_HALO_STATE, &val); if (poll_ret) { dev_err(cs35l56_base->dev, "Firmware boot timed out(%d): HALO_STATE=%#x\n", @@ -726,11 +714,6 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) else cs35l56_wait_control_port_ready(); - /* - * The HALO_STATE register is in different locations on Ax and B0 - * devices so the REVID needs to be determined before waiting for the - * firmware to boot. - */ ret = regmap_read_bypassed(cs35l56_base->regmap, CS35L56_REVID, &revid); if (ret < 0) { dev_err(cs35l56_base->dev, "Get Revision ID failed\n"); diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index 200f695efca3..8a987ec01507 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -51,7 +51,6 @@ struct cs35l56_private { u8 asp_slot_count; bool tdm_mode; bool sysclk_set; - u8 old_sdw_clock_scale; }; extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi; -- cgit v1.2.3 From f05c1ffc274516ef101d2e0f860bcb9b08c6c622 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 25 Jun 2024 19:25:46 +0200 Subject: ALSA: pcm: reinvent the stream synchronization ID API Until the commit e11f0f90a626 ("ALSA: pcm: remove SNDRV_PCM_IOCTL1_INFO internal command"), there was a possibility to pass information about the synchronized streams to the user space. The mentioned commit removed blindly the appropriate code with an irrelevant comment. The revert may be appropriate, but since this API was lost for several years without any complains, it's time to improve it. The hardware parameters may change the used stream clock source (e.g. USB hardware) so move this synchronization ID to hw_params as read-only field. It seems that pipewire can benefit from this API (disable adaptive resampling for perfectly synchronized PCM streams) now. Note that the contents of ID is not supposed to be used for direct comparison with a specific byte sequence. The "empty" case is when all bytes are zero (driver does not offer this information) and all other cases must be only used for equal comparison among PCM streams (including different sound cards) if they are using identical hardware clock. Cc: Takashi Sakamoto Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20240625172836.589380-2-perex@perex.cz --- include/sound/pcm.h | 3 ++- include/uapi/sound/asound.h | 9 +++++---- sound/core/pcm_lib.c | 27 +++++++++++++++++++++++---- sound/core/pcm_native.c | 6 ++++++ sound/pci/emu10k1/p16v.c | 7 +++---- 5 files changed, 39 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 3edd7a7346da..dbce137d8806 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -93,6 +93,7 @@ struct snd_pcm_ops { #define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 /* 3 is absent slot. */ #define SNDRV_PCM_IOCTL1_FIFO_SIZE 4 +#define SNDRV_PCM_IOCTL1_SYNC_ID 5 #define SNDRV_PCM_TRIGGER_STOP 0 #define SNDRV_PCM_TRIGGER_START 1 @@ -401,7 +402,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ snd_pcm_uframes_t silence_filled; /* already filled part of silence area */ - union snd_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char sync[16]; /* hardware synchronization ID */ /* -- mmap -- */ struct snd_pcm_mmap_status *status; diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 628d46a0da92..8bf7e8a0eb6f 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 17) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 18) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; @@ -334,7 +334,7 @@ union snd_pcm_sync_id { unsigned char id[16]; unsigned short id16[8]; unsigned int id32[4]; -}; +} __attribute__((deprecated)); struct snd_pcm_info { unsigned int device; /* RO/WR (control): device number */ @@ -348,7 +348,7 @@ struct snd_pcm_info { int dev_subclass; /* SNDRV_PCM_SUBCLASS_* */ unsigned int subdevices_count; unsigned int subdevices_avail; - union snd_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char pad1[16]; /* was: hardware synchronization ID */ unsigned char reserved[64]; /* reserved for future... */ }; @@ -420,7 +420,8 @@ struct snd_pcm_hw_params { unsigned int rate_num; /* R: rate numerator */ unsigned int rate_den; /* R: rate denominator */ snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ - unsigned char reserved[64]; /* reserved for future */ + unsigned char sync[16]; /* R: synchronization ID (perfect sync - one clock source) */ + unsigned char reserved[48]; /* reserved for future */ }; enum { diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 071c67cbc479..f64a03f79b01 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -525,10 +525,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - runtime->sync.id32[0] = substream->pcm->card->number; - runtime->sync.id32[1] = -1; - runtime->sync.id32[2] = -1; - runtime->sync.id32[3] = -1; + *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); + memset(runtime->sync + 4, 0xff, sizeof(runtime->sync) - 4); } EXPORT_SYMBOL(snd_pcm_set_sync); @@ -1810,6 +1808,25 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, return 0; } +/** + * is sync id (clock id) empty? + */ +static inline bool pcm_sync_empty(const unsigned char *sync) +{ + return sync[0] == 0 && sync[1] == 0 && sync[2] == 0 && sync[3] == 0 && + sync[4] == 0 && sync[5] == 0 && sync[6] == 0 && sync[7] == 0; +} + +static int snd_pcm_lib_ioctl_sync_id(struct snd_pcm_substream *substream, + void *arg) +{ + struct snd_pcm_hw_params *params = arg; + + if (pcm_sync_empty(params->sync)) + memcpy(params->sync, substream->runtime->sync, sizeof(params->sync)); + return 0; +} + /** * snd_pcm_lib_ioctl - a generic PCM ioctl callback * @substream: the pcm substream instance @@ -1831,6 +1848,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl_channel_info(substream, arg); case SNDRV_PCM_IOCTL1_FIFO_SIZE: return snd_pcm_lib_ioctl_fifo_size(substream, arg); + case SNDRV_PCM_IOCTL1_SYNC_ID: + return snd_pcm_lib_ioctl_sync_id(substream, arg); } return -ENXIO; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index c152ccf32214..4057f9f10aee 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -533,6 +533,12 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, SNDRV_PCM_INFO_MMAP_VALID); } + err = snd_pcm_ops_ioctl(substream, + SNDRV_PCM_IOCTL1_SYNC_ID, + params); + if (err < 0) + return err; + return 0; } diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index e7f097cae574..773725dbdfbd 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -174,10 +174,9 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea if (err < 0) return err; - runtime->sync.id32[0] = substream->pcm->card->number; - runtime->sync.id32[1] = 'P'; - runtime->sync.id32[2] = 16; - runtime->sync.id32[3] = 'V'; + *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); + memset(runtime->sync + 4, 0, sizeof(runtime->sync) - 4); + strncpy(runtime->sync + 4, "P16V", 4); return 0; } -- cgit v1.2.3 From d712c58c55d9a4b4cc88ec2e1f8cd2e3b82359b5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 25 Jun 2024 19:25:47 +0200 Subject: ALSA: pcm: optimize and clarify stream synchronization ID API Optimize the memory usage in struct snd_pcm_runtime - use boolean value for the standard sync ID scheme. Introduce snd_pcm_set_sync_per_card function to build synchronization IDs. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20240625172836.589380-3-perex@perex.cz --- include/sound/pcm.h | 15 ++++++++++++-- sound/core/pcm_lib.c | 51 +++++++++++++++++++++++++++++------------------- sound/pci/emu10k1/p16v.c | 16 +++++++++++---- 3 files changed, 56 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index dbce137d8806..ac8f3aef9205 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -402,7 +402,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ snd_pcm_uframes_t silence_filled; /* already filled part of silence area */ - unsigned char sync[16]; /* hardware synchronization ID */ + bool std_sync_id; /* hardware synchronization - standard per card ID */ /* -- mmap -- */ struct snd_pcm_mmap_status *status; @@ -1156,7 +1156,18 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, const struct snd_pcm_ops *ops); -void snd_pcm_set_sync(struct snd_pcm_substream *substream); +void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, + const unsigned char *id, unsigned int len); +/** + * snd_pcm_set_sync - set the PCM sync id + * @substream: the pcm substream + * + * Use the default PCM sync identifier for the specific card. + */ +static inline void snd_pcm_set_sync(struct snd_pcm_substream *substream) +{ + substream->runtime->std_sync_id = true; +} int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index f64a03f79b01..e48a84f8e977 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -516,19 +516,37 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, EXPORT_SYMBOL(snd_pcm_set_ops); /** - * snd_pcm_set_sync - set the PCM sync id + * snd_pcm_set_sync_per_card - set the PCM sync id with card number * @substream: the pcm substream + * @params: modified hardware parameters + * @id: identifier (max 12 bytes) + * @len: identifier length (max 12 bytes) * - * Sets the PCM sync identifier for the card. + * Sets the PCM sync identifier for the card with zero padding. + * + * User space or any user should use this 16-byte identifier for a comparison only + * to check if two IDs are similar or different. Special case is the identifier + * containing only zeros. Interpretation for this combination is - empty (not set). + * The contents of the identifier should not be interpreted in any other way. + * + * The synchronization ID must be unique per clock source (usually one sound card, + * but multiple soundcard may use one PCM word clock source which means that they + * are fully synchronized). + * + * This routine composes this ID using card number in first four bytes and + * 12-byte additional ID. When other ID composition is used (e.g. for multiple + * sound cards), make sure that the composition does not clash with this + * composition scheme. */ -void snd_pcm_set_sync(struct snd_pcm_substream *substream) +void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + const unsigned char *id, unsigned int len) { - struct snd_pcm_runtime *runtime = substream->runtime; - - *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); - memset(runtime->sync + 4, 0xff, sizeof(runtime->sync) - 4); + *(__u32 *)params->sync = cpu_to_le32(substream->pcm->card->number); + len = max(12, len); + strncpy(params->sync + 4, id, len); + memset(params->sync + 4 + len, 0, 12 - len); } -EXPORT_SYMBOL(snd_pcm_set_sync); /* * Standard ioctl routine @@ -1808,22 +1826,15 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, return 0; } -/** - * is sync id (clock id) empty? - */ -static inline bool pcm_sync_empty(const unsigned char *sync) -{ - return sync[0] == 0 && sync[1] == 0 && sync[2] == 0 && sync[3] == 0 && - sync[4] == 0 && sync[5] == 0 && sync[6] == 0 && sync[7] == 0; -} - static int snd_pcm_lib_ioctl_sync_id(struct snd_pcm_substream *substream, void *arg) { - struct snd_pcm_hw_params *params = arg; + static const unsigned char id[12] = { 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff }; - if (pcm_sync_empty(params->sync)) - memcpy(params->sync, substream->runtime->sync, sizeof(params->sync)); + if (substream->runtime->std_sync_id) + snd_pcm_set_sync_per_card(substream, arg, id, sizeof(id)); return 0; } diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 773725dbdfbd..a9a75891f1da 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -174,10 +174,6 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea if (err < 0) return err; - *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); - memset(runtime->sync + 4, 0, sizeof(runtime->sync) - 4); - strncpy(runtime->sync + 4, "P16V", 4); - return 0; } @@ -225,6 +221,17 @@ static int snd_p16v_pcm_open_capture(struct snd_pcm_substream *substream) return snd_p16v_pcm_open_capture_channel(substream, 0); } +static int snd_p16v_pcm_ioctl_playback(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + if (cmd == SNDRV_PCM_IOCTL1_SYNC_ID) { + static const unsigned char id[4] = { 'P', '1', '6', 'V' }; + snd_pcm_set_sync_per_card(substream, arg, id, 4); + return 0; + } + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + /* prepare playback callback */ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) { @@ -530,6 +537,7 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream) static const struct snd_pcm_ops snd_p16v_playback_front_ops = { .open = snd_p16v_pcm_open_playback_front, .close = snd_p16v_pcm_close_playback, + .ioctl = snd_p16v_pcm_ioctl_playback, .prepare = snd_p16v_pcm_prepare_playback, .trigger = snd_p16v_pcm_trigger_playback, .pointer = snd_p16v_pcm_pointer_playback, -- cgit v1.2.3 From 244389bd42870640c4b5ef672a360da329b579ed Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 3 Jul 2024 10:55:17 +0100 Subject: ASoC: cs35l56: Limit Speaker Volume to +12dB maximum Change CS35L56_MAIN_RENDER_USER_VOLUME_MAX to 48, to limit the maximum value of the Speaker Volume control to +12dB. The minimum value is unchanged so that the default 0dB has the same integer control value. The original maximum of 400 (+100dB) was the largest value that can be mathematically handled by the DSP. The actual maximum amplification is +12dB. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20240703095517.208077-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l56.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 642ef690ebc2..a6aa112e5741 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -207,7 +207,7 @@ /* CS35L56_MAIN_RENDER_USER_VOLUME */ #define CS35L56_MAIN_RENDER_USER_VOLUME_MIN -400 -#define CS35L56_MAIN_RENDER_USER_VOLUME_MAX 400 +#define CS35L56_MAIN_RENDER_USER_VOLUME_MAX 48 #define CS35L56_MAIN_RENDER_USER_VOLUME_MASK 0x0000FFC0 #define CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT 6 #define CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT 9 -- cgit v1.2.3 From bf95919fe1917efa8f5da83057ff9fc11130aa55 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 1 Jul 2024 09:39:36 +0200 Subject: ASoC: dapm: Use unsigned for number of widgets in snd_soc_dapm_new_controls() Number of widgets in array passed to snd_soc_dapm_new_controls() cannot be negative, so make it explicit by using 'unsigned int', just like snd_soc_add_component_controls() is doing. Reviewed-by: Dmitry Baryshkov Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240701-b4-qcom-audio-lpass-codec-cleanups-v3-4-6d98d4dd1ef5@linaro.org Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 +- sound/soc/soc-dapm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 667ecd4daa68..12cd7b5a2202 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -457,7 +457,7 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uncontrol); int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget, int num); + const struct snd_soc_dapm_widget *widget, unsigned int num); struct snd_soc_dapm_widget *snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget); struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 16dad4a45443..32cc90d09bc2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3857,7 +3857,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); */ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, - int num) + unsigned int num) { int i; int ret = 0; -- cgit v1.2.3 From 37797c605da33445adc112561695f70bfaa11133 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:34 +0200 Subject: soc: fsl: cpm1: qmc: Introduce functions to get a channel from a phandle list qmc_chan_get_byphandle() and the resource managed version retrieve a channel from a simple phandle. Extend the API and introduce qmc_chan_get_byphandles_index() and the resource managed version in order to retrieve a channel from a phandle list using the provided index to identify the phandle in the list. Also update qmc_chan_get_byphandle() and the resource managed version to use qmc_chan_get_byphandles_index() and so avoid code duplication. Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-8-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/soc/fsl/qe/qmc.c | 19 +++++++++++-------- include/soc/fsl/qe/qmc.h | 25 ++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index f498db9abe35..e23d60018400 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1777,13 +1777,15 @@ static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsign return qmc_chan; } -struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name) +struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, + const char *phandles_name, + int index) { struct of_phandle_args out_args; struct qmc_chan *qmc_chan; int ret; - ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, + ret = of_parse_phandle_with_fixed_args(np, phandles_name, 1, index, &out_args); if (ret < 0) return ERR_PTR(ret); @@ -1797,7 +1799,7 @@ struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phan of_node_put(out_args.np); return qmc_chan; } -EXPORT_SYMBOL(qmc_chan_get_byphandle); +EXPORT_SYMBOL(qmc_chan_get_byphandles_index); struct qmc_chan *qmc_chan_get_bychild(struct device_node *np) { @@ -1827,9 +1829,10 @@ static void devm_qmc_chan_release(struct device *dev, void *res) qmc_chan_put(*qmc_chan); } -struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, - struct device_node *np, - const char *phandle_name) +struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev, + struct device_node *np, + const char *phandles_name, + int index) { struct qmc_chan *qmc_chan; struct qmc_chan **dr; @@ -1838,7 +1841,7 @@ struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, if (!dr) return ERR_PTR(-ENOMEM); - qmc_chan = qmc_chan_get_byphandle(np, phandle_name); + qmc_chan = qmc_chan_get_byphandles_index(np, phandles_name, index); if (!IS_ERR(qmc_chan)) { *dr = qmc_chan; devres_add(dev, dr); @@ -1848,7 +1851,7 @@ struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, return qmc_chan; } -EXPORT_SYMBOL(devm_qmc_chan_get_byphandle); +EXPORT_SYMBOL(devm_qmc_chan_get_byphandles_index); struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, struct device_node *np) diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h index 2a333fc1ea81..0fa7205145ce 100644 --- a/include/soc/fsl/qe/qmc.h +++ b/include/soc/fsl/qe/qmc.h @@ -16,11 +16,30 @@ struct device_node; struct device; struct qmc_chan; -struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name); +struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, + const char *phandles_name, + int index); +struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev, + struct device_node *np, + const char *phandles_name, + int index); + +static inline struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, + const char *phandle_name) +{ + return qmc_chan_get_byphandles_index(np, phandle_name, 0); +} + +static inline struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, + struct device_node *np, + const char *phandle_name) +{ + return devm_qmc_chan_get_byphandles_index(dev, np, phandle_name, 0); +} + struct qmc_chan *qmc_chan_get_bychild(struct device_node *np); void qmc_chan_put(struct qmc_chan *chan); -struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, struct device_node *np, - const char *phandle_name); + struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, struct device_node *np); enum qmc_mode { -- cgit v1.2.3 From af8432b2e41abc0a20bdc01a3b144ea7b2f1ee09 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Mon, 1 Jul 2024 13:30:35 +0200 Subject: soc: fsl: cpm1: qmc: Introduce qmc_chan_count_phandles() No function in the QMC API is available to get the number of phandles present in a phandle list. Fill this lack introducing qmc_chan_count_phandles(). Signed-off-by: Herve Codina Link: https://patch.msgid.link/20240701113038.55144-9-herve.codina@bootlin.com Signed-off-by: Mark Brown --- drivers/soc/fsl/qe/qmc.c | 13 +++++++++++++ include/soc/fsl/qe/qmc.h | 2 ++ 2 files changed, 15 insertions(+) (limited to 'include') diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index e23d60018400..76bb496305a0 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1777,6 +1777,19 @@ static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsign return qmc_chan; } +int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name) +{ + int count; + + /* phandles are fixed args phandles with one arg */ + count = of_count_phandle_with_args(np, phandles_name, NULL); + if (count < 0) + return count; + + return count / 2; +} +EXPORT_SYMBOL(qmc_chan_count_phandles); + struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, const char *phandles_name, int index) diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h index 0fa7205145ce..294e42ea8d4c 100644 --- a/include/soc/fsl/qe/qmc.h +++ b/include/soc/fsl/qe/qmc.h @@ -16,6 +16,8 @@ struct device_node; struct device; struct qmc_chan; +int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name); + struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, const char *phandles_name, int index); -- cgit v1.2.3 From fefbbdfb59d3a20fd98734363e6dd9fa7cc65c70 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Jul 2024 18:03:42 +0200 Subject: ALSA: seq: Add tempo base unit for MIDI2 Set Tempo messages MIDI2 Set Tempo message defines the tempo in 10ns unit for finer accuracy, while MIDI1 was defined in 1us unit. For adapting this different unit, introduce "tempo_base" field to snd_seq_queue_tempo struct so that user-space can pass the proper tempo base unit. The accepted value is limited, it must be either 0, 10 or 1000. The protocol version is bumped to 1.0.4 along with this. The access with the older protocol version ignores the tempo-base value in ioctls and always treats as 1000. Reviewed-by: Jaroslav Kysela Link: https://patch.msgid.link/20240705160344.6481-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 7 ++++--- sound/core/seq/seq_clientmgr.c | 4 ++++ sound/core/seq/seq_queue.c | 6 ++++-- sound/core/seq/seq_timer.c | 21 +++++++++++++++------ sound/core/seq/seq_timer.h | 4 +++- 5 files changed, 30 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index c85fdd8895d8..39b37edcf813 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -10,7 +10,7 @@ #include /** version of the sequencer */ -#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 3) +#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 4) /** * definition of sequencer event types @@ -523,11 +523,12 @@ struct snd_seq_queue_status { /* queue tempo */ struct snd_seq_queue_tempo { int queue; /* sequencer queue */ - unsigned int tempo; /* current tempo, us/tick */ + unsigned int tempo; /* current tempo, us/tick (or different time-base below) */ int ppq; /* time resolution, ticks/quarter */ unsigned int skew_value; /* queue skew */ unsigned int skew_base; /* queue skew base */ - char reserved[24]; /* for the future */ + unsigned short tempo_base; /* tempo base in nsec unit; either 10 or 1000 */ + char reserved[22]; /* for the future */ }; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 42a705141050..8c4ee5066afe 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1718,6 +1718,8 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client, tempo->ppq = tmr->ppq; tempo->skew_value = tmr->skew; tempo->skew_base = tmr->skew_base; + if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 4)) + tempo->tempo_base = tmr->tempo_base; queuefree(queue); return 0; @@ -1739,6 +1741,8 @@ static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client, struct snd_seq_queue_tempo *tempo = arg; int result; + if (client->user_pversion < SNDRV_PROTOCOL_VERSION(1, 0, 4)) + tempo->tempo_base = 0; result = snd_seq_set_queue_tempo(client->number, tempo); return result < 0 ? result : 0; } diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 500ee6b19c71..5df26788dda4 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -460,7 +460,8 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client, return -EPERM; } - result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq); + result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq, + info->tempo_base); if (result >= 0 && info->skew_base > 0) result = snd_seq_timer_set_skew(q->timer, info->skew_value, info->skew_base); @@ -724,7 +725,7 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, tmr = q->timer; if (tmr->tempo) - bpm = 60000000 / tmr->tempo; + bpm = (60000 * tmr->tempo_base) / tmr->tempo; else bpm = 0; @@ -741,6 +742,7 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped"); snd_iprintf(buffer, "timer PPQ : %d\n", tmr->ppq); snd_iprintf(buffer, "current tempo : %d\n", tmr->tempo); + snd_iprintf(buffer, "tempo base : %d ns\n", tmr->tempo_base); snd_iprintf(buffer, "current BPM : %d\n", bpm); snd_iprintf(buffer, "current time : %d.%09d s\n", tmr->cur_time.tv_sec, tmr->cur_time.tv_nsec); snd_iprintf(buffer, "current tick : %d\n", tmr->tick.cur_tick); diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index ad2b97e2762d..c9f0392ac7f1 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -20,14 +20,17 @@ static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr) { - if (tmr->tempo < 1000000) - tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq; + unsigned int threshold = + tmr->tempo_base == 1000 ? 1000000 : 10000; + + if (tmr->tempo < threshold) + tmr->tick.resolution = (tmr->tempo * tmr->tempo_base) / tmr->ppq; else { /* might overflow.. */ unsigned int s; s = tmr->tempo % tmr->ppq; - s = (s * 1000) / tmr->ppq; - tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000; + s = (s * tmr->tempo_base) / tmr->ppq; + tmr->tick.resolution = (tmr->tempo / tmr->ppq) * tmr->tempo_base; tmr->tick.resolution += s; } if (tmr->tick.resolution <= 0) @@ -79,6 +82,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) /* setup defaults */ tmr->ppq = 96; /* 96 PPQ */ tmr->tempo = 500000; /* 120 BPM */ + tmr->tempo_base = 1000; /* 1us */ snd_seq_timer_set_tick_resolution(tmr); tmr->running = 0; @@ -164,8 +168,9 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) return 0; } -/* set current tempo and ppq in a shot */ -int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) +/* set current tempo, ppq and base in a shot */ +int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq, + unsigned int tempo_base) { int changed; @@ -173,6 +178,9 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) return -EINVAL; if (tempo <= 0 || ppq <= 0) return -EINVAL; + /* allow only 10ns or 1us tempo base for now */ + if (tempo_base && tempo_base != 10 && tempo_base != 1000) + return -EINVAL; guard(spinlock_irqsave)(&tmr->lock); if (tmr->running && (ppq != tmr->ppq)) { /* refuse to change ppq on running timers */ @@ -183,6 +191,7 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) changed = (tempo != tmr->tempo) || (ppq != tmr->ppq); tmr->tempo = tempo; tmr->ppq = ppq; + tmr->tempo_base = tempo_base ? tempo_base : 1000; if (changed) snd_seq_timer_set_tick_resolution(tmr); return 0; diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 4bec57df8158..3b906064bde1 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h @@ -36,6 +36,7 @@ struct snd_seq_timer { unsigned int skew; unsigned int skew_base; + unsigned int tempo_base; struct timespec64 last_update; /* time of last clock update, used for interpolation */ @@ -116,7 +117,8 @@ int snd_seq_timer_stop(struct snd_seq_timer *tmr); int snd_seq_timer_start(struct snd_seq_timer *tmr); int snd_seq_timer_continue(struct snd_seq_timer *tmr); int snd_seq_timer_set_tempo(struct snd_seq_timer *tmr, int tempo); -int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq); +int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq, + unsigned int tempo_base); int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position); int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position); int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base); -- cgit v1.2.3 From be5db7581f59621ed9cb9cbf6bebccda38263eb5 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Tue, 9 Jul 2024 12:33:40 +0800 Subject: ASoc: TAS2781: rename the tas2781_reset as tasdevice_reset Rename the tas2781_reset as tasdevice_reset in case of misunderstanding. RESET register for both tas2563 and tas2781 is same and the use of reset pin is also same. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240709043342.946-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781.h | 8 ++++---- sound/pci/hda/tas2781_hda_i2c.c | 4 ++-- sound/soc/codecs/tas2781-comlib.c | 8 ++++---- sound/soc/codecs/tas2781-i2c.c | 2 ++ 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index cd8ce522b78e..a43ad6dcb7c7 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -2,7 +2,7 @@ // // ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier // -// Copyright (C) 2022 - 2023 Texas Instruments Incorporated +// Copyright (C) 2022 - 2024 Texas Instruments Incorporated // https://www.ti.com // // The TAS2563/TAS2781 driver implements a flexible and configurable @@ -43,8 +43,8 @@ (page * 128)) + reg) /*Software Reset */ -#define TAS2781_REG_SWRESET TASDEVICE_REG(0x0, 0X0, 0x01) -#define TAS2781_REG_SWRESET_RESET BIT(0) +#define TASDEVICE_REG_SWRESET TASDEVICE_REG(0x0, 0X0, 0x01) +#define TASDEVICE_REG_SWRESET_RESET BIT(0) /*I2C Checksum */ #define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E) @@ -140,7 +140,7 @@ struct tasdevice_priv { void (*apply_calibration)(struct tasdevice_priv *tas_priv); }; -void tas2781_reset(struct tasdevice_priv *tas_dev); +void tasdevice_reset(struct tasdevice_priv *tas_dev); int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, struct module *module, void (*cont)(const struct firmware *fw, void *context)); diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 75f7674c66ee..10420360b214 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -834,7 +834,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) pm_runtime_set_active(tas_hda->dev); pm_runtime_enable(tas_hda->dev); - tas2781_reset(tas_hda->priv); + tasdevice_reset(tas_hda->priv); ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops); if (ret) { @@ -929,7 +929,7 @@ static int tas2781_system_resume(struct device *dev) tas_hda->priv->tasdevice[i].cur_prog = -1; tas_hda->priv->tasdevice[i].cur_conf = -1; } - tas2781_reset(tas_hda->priv); + tasdevice_reset(tas_hda->priv); tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); /* If calibrated data occurs error, dsp will still work with default diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index 6db1a260da82..1fbf4560f5cc 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -243,7 +243,7 @@ struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c) } EXPORT_SYMBOL_GPL(tasdevice_kzalloc); -void tas2781_reset(struct tasdevice_priv *tas_dev) +void tasdevice_reset(struct tasdevice_priv *tas_dev) { int ret, i; @@ -254,8 +254,8 @@ void tas2781_reset(struct tasdevice_priv *tas_dev) } else { for (i = 0; i < tas_dev->ndev; i++) { ret = tasdevice_dev_write(tas_dev, i, - TAS2781_REG_SWRESET, - TAS2781_REG_SWRESET_RESET); + TASDEVICE_REG_SWRESET, + TASDEVICE_REG_SWRESET_RESET); if (ret < 0) dev_err(tas_dev->dev, "dev %d swreset fail, %d\n", @@ -264,7 +264,7 @@ void tas2781_reset(struct tasdevice_priv *tas_dev) } usleep_range(1000, 1050); } -EXPORT_SYMBOL_GPL(tas2781_reset); +EXPORT_SYMBOL_GPL(tasdevice_reset); int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, struct module *module, diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index b412f8f2e5d5..d5d95ae57c73 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -742,6 +742,8 @@ static int tasdevice_i2c_probe(struct i2c_client *i2c) if (ret) goto err; + tasdevice_reset(tas_priv); + ret = devm_snd_soc_register_component(tas_priv->dev, &soc_codec_driver_tasdevice, tasdevice_dai_driver, ARRAY_SIZE(tasdevice_dai_driver)); -- cgit v1.2.3 From 584e86e14c59d36688633002613792923620d8c0 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 10 Jul 2024 11:36:38 +0100 Subject: firmware: cs_dsp: Make wmfw and bin filename arguments const char * The wmfw_filename and bin_filename strings passed into cs_dsp_power_up() and cs_dsp_adsp1_power_up() should be const char *. Signed-off-by: Richard Fitzgerald Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20240710103640.78197-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 8 ++++---- include/linux/firmware/cirrus/cs_dsp.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 9bd3f78396ea..fda6faa8c835 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -2410,8 +2410,8 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, FW_CS_DSP); * Return: Zero for success, a negative number on error. */ int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, - const struct firmware *wmfw_firmware, char *wmfw_filename, - const struct firmware *coeff_firmware, char *coeff_filename, + const struct firmware *wmfw_firmware, const char *wmfw_filename, + const struct firmware *coeff_firmware, const char *coeff_filename, const char *fw_name) { unsigned int val; @@ -2704,8 +2704,8 @@ static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp) * Return: Zero for success, a negative number on error. */ int cs_dsp_power_up(struct cs_dsp *dsp, - const struct firmware *wmfw_firmware, char *wmfw_filename, - const struct firmware *coeff_firmware, char *coeff_filename, + const struct firmware *wmfw_firmware, const char *wmfw_filename, + const struct firmware *coeff_firmware, const char *coeff_filename, const char *fw_name) { int ret; diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 82687e07a7c2..8078dc377948 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -213,13 +213,13 @@ int cs_dsp_adsp2_init(struct cs_dsp *dsp); int cs_dsp_halo_init(struct cs_dsp *dsp); int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, - const struct firmware *wmfw_firmware, char *wmfw_filename, - const struct firmware *coeff_firmware, char *coeff_filename, + const struct firmware *wmfw_firmware, const char *wmfw_filename, + const struct firmware *coeff_firmware, const char *coeff_filename, const char *fw_name); void cs_dsp_adsp1_power_down(struct cs_dsp *dsp); int cs_dsp_power_up(struct cs_dsp *dsp, - const struct firmware *wmfw_firmware, char *wmfw_filename, - const struct firmware *coeff_firmware, char *coeff_filename, + const struct firmware *wmfw_firmware, const char *wmfw_filename, + const struct firmware *coeff_firmware, const char *coeff_filename, const char *fw_name); void cs_dsp_power_down(struct cs_dsp *dsp); int cs_dsp_run(struct cs_dsp *dsp); -- cgit v1.2.3 From dc0e5ca8856dc6a97e3b117879dfb2b52bda06b6 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 10 Jul 2024 11:36:40 +0100 Subject: firmware: cs_dsp: Rename fw_ver to wmfw_ver Rename the confusingly named struct member fw_ver to wmfw_ver. It contains the wmfw format version of the loaded wmfw file. This commit also contains an update to wm_adsp for the new name. Signed-off-by: Richard Fitzgerald Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20240710103640.78197-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 20 ++++++++++---------- include/linux/firmware/cirrus/cs_dsp.h | 2 +- sound/soc/codecs/wm_adsp.c | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 865db8defc56..66c2f09b0be7 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -1048,7 +1048,7 @@ static int cs_dsp_create_control(struct cs_dsp *dsp, ctl->fw_name = dsp->fw_name; ctl->alg_region = *alg_region; - if (subname && dsp->fw_ver >= 2) { + if (subname && dsp->wmfw_ver >= 2) { ctl->subname_len = subname_len; ctl->subname = kasprintf(GFP_KERNEL, "%.*s", subname_len, subname); if (!ctl->subname) { @@ -1175,7 +1175,7 @@ static int cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, raw = (const struct wmfw_adsp_alg_data *)region->data; - switch (dsp->fw_ver) { + switch (dsp->wmfw_ver) { case 0: case 1: if (sizeof(*raw) > data_len) @@ -1252,7 +1252,7 @@ static int cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, blk->offset = le16_to_cpu(raw->hdr.offset); blk->mem_type = le16_to_cpu(raw->hdr.type); - switch (dsp->fw_ver) { + switch (dsp->wmfw_ver) { case 0: case 1: if (sizeof(*raw) > (data_len - pos)) @@ -1499,7 +1499,7 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, goto out_fw; } - dsp->fw_ver = header->ver; + dsp->wmfw_ver = header->ver; if (header->core != dsp->type) { cs_dsp_err(dsp, "%s: invalid core %d != %d\n", @@ -1779,7 +1779,7 @@ static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, list_add_tail(&alg_region->list, &dsp->alg_regions); - if (dsp->fw_ver > 0) + if (dsp->wmfw_ver > 0) cs_dsp_ctl_fixup_base(dsp, alg_region); return alg_region; @@ -1902,7 +1902,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp1_alg[i + 1].dm); len -= be32_to_cpu(adsp1_alg[i].dm); @@ -1924,7 +1924,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp1_alg[i + 1].zm); len -= be32_to_cpu(adsp1_alg[i].zm); @@ -2015,7 +2015,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp2_alg[i + 1].xm); len -= be32_to_cpu(adsp2_alg[i].xm); @@ -2037,7 +2037,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp2_alg[i + 1].ym); len -= be32_to_cpu(adsp2_alg[i].ym); @@ -2059,7 +2059,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) ret = PTR_ERR(alg_region); goto out; } - if (dsp->fw_ver == 0) { + if (dsp->wmfw_ver == 0) { if (i + 1 < n_algs) { len = be32_to_cpu(adsp2_alg[i + 1].zm); len -= be32_to_cpu(adsp2_alg[i].zm); diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 8078dc377948..2e649810169f 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -167,7 +167,7 @@ struct cs_dsp { const struct cs_dsp_region *mem; int num_mems; - int fw_ver; + int wmfw_ver; bool booted; bool running; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 68d2d6444533..9f8549b34e30 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -601,7 +601,7 @@ static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl) return -EINVAL; } - switch (cs_dsp->fw_ver) { + switch (cs_dsp->wmfw_ver) { case 0: case 1: ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, -- cgit v1.2.3 From 75ed63a5ab5d1d2872c735bc7edf8fef0e2fa2ea Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Wed, 10 Jul 2024 14:42:37 +0800 Subject: ASoC: tas2781: Add new Kontrol to set tas2563 digital Volume Requriment from customer to add new kcontrol to set tas2563 digital Volume Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20240710064238.1480-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- include/sound/tas2781-tlv.h | 262 ++++++++++++++++++++++++++++++++++++++++- include/sound/tas2781.h | 1 + sound/soc/codecs/tas2781-i2c.c | 129 ++++++++++++++++++-- 3 files changed, 382 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/sound/tas2781-tlv.h b/include/sound/tas2781-tlv.h index 1dc59005d241..99c41bfc7827 100644 --- a/include/sound/tas2781-tlv.h +++ b/include/sound/tas2781-tlv.h @@ -2,7 +2,7 @@ // // ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier // -// Copyright (C) 2022 - 2023 Texas Instruments Incorporated +// Copyright (C) 2022 - 2024 Texas Instruments Incorporated // https://www.ti.com // // The TAS2781 driver implements a flexible and configurable @@ -17,5 +17,265 @@ static const __maybe_unused DECLARE_TLV_DB_SCALE(dvc_tlv, -10000, 100, 0); static const DECLARE_TLV_DB_SCALE(amp_vol_tlv, 1100, 50, 0); +static const DECLARE_TLV_DB_SCALE(tas2563_dvc_tlv, -12150, 50, 1); +/* pow(10, db/20) * pow(2,30) */ +static const unsigned char tas2563_dvc_table[][4] = { + { 0X00, 0X00, 0X00, 0X00 }, /* -121.5db */ + { 0X00, 0X00, 0X03, 0XBC }, /* -121.0db */ + { 0X00, 0X00, 0X03, 0XF5 }, /* -120.5db */ + { 0X00, 0X00, 0X04, 0X31 }, /* -120.0db */ + { 0X00, 0X00, 0X04, 0X71 }, /* -119.5db */ + { 0X00, 0X00, 0X04, 0XB4 }, /* -119.0db */ + { 0X00, 0X00, 0X04, 0XFC }, /* -118.5db */ + { 0X00, 0X00, 0X05, 0X47 }, /* -118.0db */ + { 0X00, 0X00, 0X05, 0X97 }, /* -117.5db */ + { 0X00, 0X00, 0X05, 0XEC }, /* -117.0db */ + { 0X00, 0X00, 0X06, 0X46 }, /* -116.5db */ + { 0X00, 0X00, 0X06, 0XA5 }, /* -116.0db */ + { 0X00, 0X00, 0X07, 0X0A }, /* -115.5db */ + { 0X00, 0X00, 0X07, 0X75 }, /* -115.0db */ + { 0X00, 0X00, 0X07, 0XE6 }, /* -114.5db */ + { 0X00, 0X00, 0X08, 0X5E }, /* -114.0db */ + { 0X00, 0X00, 0X08, 0XDD }, /* -113.5db */ + { 0X00, 0X00, 0X09, 0X63 }, /* -113.0db */ + { 0X00, 0X00, 0X09, 0XF2 }, /* -112.5db */ + { 0X00, 0X00, 0X0A, 0X89 }, /* -112.0db */ + { 0X00, 0X00, 0X0B, 0X28 }, /* -111.5db */ + { 0X00, 0X00, 0X0B, 0XD2 }, /* -111.0db */ + { 0X00, 0X00, 0X0C, 0X85 }, /* -110.5db */ + { 0X00, 0X00, 0X0D, 0X43 }, /* -110.0db */ + { 0X00, 0X00, 0X0E, 0X0C }, /* -109.5db */ + { 0X00, 0X00, 0X0E, 0XE1 }, /* -109.0db */ + { 0X00, 0X00, 0X0F, 0XC3 }, /* -108.5db */ + { 0X00, 0X00, 0X10, 0XB2 }, /* -108.0db */ + { 0X00, 0X00, 0X11, 0XAF }, /* -107.5db */ + { 0X00, 0X00, 0X12, 0XBC }, /* -107.0db */ + { 0X00, 0X00, 0X13, 0XD8 }, /* -106.5db */ + { 0X00, 0X00, 0X15, 0X05 }, /* -106.0db */ + { 0X00, 0X00, 0X16, 0X44 }, /* -105.5db */ + { 0X00, 0X00, 0X17, 0X96 }, /* -105.0db */ + { 0X00, 0X00, 0X18, 0XFB }, /* -104.5db */ + { 0X00, 0X00, 0X1A, 0X76 }, /* -104.0db */ + { 0X00, 0X00, 0X1C, 0X08 }, /* -103.5db */ + { 0X00, 0X00, 0X1D, 0XB1 }, /* -103.0db */ + { 0X00, 0X00, 0X1F, 0X73 }, /* -102.5db */ + { 0X00, 0X00, 0X21, 0X51 }, /* -102.0db */ + { 0X00, 0X00, 0X23, 0X4A }, /* -101.5db */ + { 0X00, 0X00, 0X25, 0X61 }, /* -101.0db */ + { 0X00, 0X00, 0X27, 0X98 }, /* -100.5db */ + { 0X00, 0X00, 0X29, 0XF1 }, /* -100.0db */ + { 0X00, 0X00, 0X2C, 0X6D }, /* -99.5db */ + { 0X00, 0X00, 0X2F, 0X0F }, /* -99.0db */ + { 0X00, 0X00, 0X31, 0XD9 }, /* -98.5db */ + { 0X00, 0X00, 0X34, 0XCD }, /* -98.0db */ + { 0X00, 0X00, 0X37, 0XEE }, /* -97.5db */ + { 0X00, 0X00, 0X3B, 0X3F }, /* -97.0db */ + { 0X00, 0X00, 0X3E, 0XC1 }, /* -96.5db */ + { 0X00, 0X00, 0X42, 0X79 }, /* -96.0db */ + { 0X00, 0X00, 0X46, 0X6A }, /* -95.5db */ + { 0X00, 0X00, 0X4A, 0X96 }, /* -95.0db */ + { 0X00, 0X00, 0X4F, 0X01 }, /* -94.5db */ + { 0X00, 0X00, 0X53, 0XAF }, /* -94.0db */ + { 0X00, 0X00, 0X58, 0XA5 }, /* -93.5db */ + { 0X00, 0X00, 0X5D, 0XE6 }, /* -93.0db */ + { 0X00, 0X00, 0X63, 0X76 }, /* -92.5db */ + { 0X00, 0X00, 0X69, 0X5B }, /* -92.0db */ + { 0X00, 0X00, 0X6F, 0X99 }, /* -91.5db */ + { 0X00, 0X00, 0X76, 0X36 }, /* -91.0db */ + { 0X00, 0X00, 0X7D, 0X37 }, /* -90.5db */ + { 0X00, 0X00, 0X84, 0XA2 }, /* -90.0db */ + { 0X00, 0X00, 0X8C, 0X7E }, /* -89.5db */ + { 0X00, 0X00, 0X94, 0XD1 }, /* -89.0db */ + { 0X00, 0X00, 0X9D, 0XA3 }, /* -88.5db */ + { 0X00, 0X00, 0XA6, 0XFA }, /* -88.0db */ + { 0X00, 0X00, 0XB0, 0XDF }, /* -87.5db */ + { 0X00, 0X00, 0XBB, 0X5A }, /* -87.0db */ + { 0X00, 0X00, 0XC6, 0X74 }, /* -86.5db */ + { 0X00, 0X00, 0XD2, 0X36 }, /* -86.0db */ + { 0X00, 0X00, 0XDE, 0XAB }, /* -85.5db */ + { 0X00, 0X00, 0XEB, 0XDC }, /* -85.0db */ + { 0X00, 0X00, 0XF9, 0XD6 }, /* -84.5db */ + { 0X00, 0X01, 0X08, 0XA4 }, /* -84.0db */ + { 0X00, 0X01, 0X18, 0X52 }, /* -83.5db */ + { 0X00, 0X01, 0X28, 0XEF }, /* -83.0db */ + { 0X00, 0X01, 0X3A, 0X87 }, /* -82.5db */ + { 0X00, 0X01, 0X4D, 0X2A }, /* -82.0db */ + { 0X00, 0X01, 0X60, 0XE8 }, /* -81.5db */ + { 0X00, 0X01, 0X75, 0XD1 }, /* -81.0db */ + { 0X00, 0X01, 0X8B, 0XF7 }, /* -80.5db */ + { 0X00, 0X01, 0XA3, 0X6E }, /* -80.0db */ + { 0X00, 0X01, 0XBC, 0X48 }, /* -79.5db */ + { 0X00, 0X01, 0XD6, 0X9B }, /* -79.0db */ + { 0X00, 0X01, 0XF2, 0X7E }, /* -78.5db */ + { 0X00, 0X02, 0X10, 0X08 }, /* -78.0db */ + { 0X00, 0X02, 0X2F, 0X51 }, /* -77.5db */ + { 0X00, 0X02, 0X50, 0X76 }, /* -77.0db */ + { 0X00, 0X02, 0X73, 0X91 }, /* -76.5db */ + { 0X00, 0X02, 0X98, 0XC0 }, /* -76.0db */ + { 0X00, 0X02, 0XC0, 0X24 }, /* -75.5db */ + { 0X00, 0X02, 0XE9, 0XDD }, /* -75.0db */ + { 0X00, 0X03, 0X16, 0X0F }, /* -74.5db */ + { 0X00, 0X03, 0X44, 0XDF }, /* -74.0db */ + { 0X00, 0X03, 0X76, 0X76 }, /* -73.5db */ + { 0X00, 0X03, 0XAA, 0XFC }, /* -73.0db */ + { 0X00, 0X03, 0XE2, 0XA0 }, /* -72.5db */ + { 0X00, 0X04, 0X1D, 0X8F }, /* -72.0db */ + { 0X00, 0X04, 0X5B, 0XFD }, /* -71.5db */ + { 0X00, 0X04, 0X9E, 0X1D }, /* -71.0db */ + { 0X00, 0X04, 0XE4, 0X29 }, /* -70.5db */ + { 0X00, 0X05, 0X2E, 0X5A }, /* -70.0db */ + { 0X00, 0X05, 0X7C, 0XF2 }, /* -69.5db */ + { 0X00, 0X05, 0XD0, 0X31 }, /* -69.0db */ + { 0X00, 0X06, 0X28, 0X60 }, /* -68.5db */ + { 0X00, 0X06, 0X85, 0XC8 }, /* -68.0db */ + { 0X00, 0X06, 0XE8, 0XB9 }, /* -67.5db */ + { 0X00, 0X07, 0X51, 0X86 }, /* -67.0db */ + { 0X00, 0X07, 0XC0, 0X8A }, /* -66.5db */ + { 0X00, 0X08, 0X36, 0X21 }, /* -66.0db */ + { 0X00, 0X08, 0XB2, 0XB0 }, /* -65.5db */ + { 0X00, 0X09, 0X36, 0XA1 }, /* -65.0db */ + { 0X00, 0X09, 0XC2, 0X63 }, /* -64.5db */ + { 0X00, 0X0A, 0X56, 0X6D }, /* -64.0db */ + { 0X00, 0X0A, 0XF3, 0X3C }, /* -63.5db */ + { 0X00, 0X0B, 0X99, 0X56 }, /* -63.0db */ + { 0X00, 0X0C, 0X49, 0X48 }, /* -62.5db */ + { 0X00, 0X0D, 0X03, 0XA7 }, /* -62.0db */ + { 0X00, 0X0D, 0XC9, 0X11 }, /* -61.5db */ + { 0X00, 0X0E, 0X9A, 0X2D }, /* -61.0db */ + { 0X00, 0X0F, 0X77, 0XAD }, /* -60.5db */ + { 0X00, 0X10, 0X62, 0X4D }, /* -60.0db */ + { 0X00, 0X11, 0X5A, 0XD5 }, /* -59.5db */ + { 0X00, 0X12, 0X62, 0X16 }, /* -59.0db */ + { 0X00, 0X13, 0X78, 0XF0 }, /* -58.5db */ + { 0X00, 0X14, 0XA0, 0X50 }, /* -58.0db */ + { 0X00, 0X15, 0XD9, 0X31 }, /* -57.5db */ + { 0X00, 0X17, 0X24, 0X9C }, /* -57.0db */ + { 0X00, 0X18, 0X83, 0XAA }, /* -56.5db */ + { 0X00, 0X19, 0XF7, 0X86 }, /* -56.0db */ + { 0X00, 0X1B, 0X81, 0X6A }, /* -55.5db */ + { 0X00, 0X1D, 0X22, 0XA4 }, /* -55.0db */ + { 0X00, 0X1E, 0XDC, 0X98 }, /* -54.5db */ + { 0X00, 0X20, 0XB0, 0XBC }, /* -54.0db */ + { 0X00, 0X22, 0XA0, 0X9D }, /* -53.5db */ + { 0X00, 0X24, 0XAD, 0XE0 }, /* -53.0db */ + { 0X00, 0X26, 0XDA, 0X43 }, /* -52.5db */ + { 0X00, 0X29, 0X27, 0X9D }, /* -52.0db */ + { 0X00, 0X2B, 0X97, 0XE3 }, /* -51.5db */ + { 0X00, 0X2E, 0X2D, 0X27 }, /* -51.0db */ + { 0X00, 0X30, 0XE9, 0X9A }, /* -50.5db */ + { 0X00, 0X33, 0XCF, 0X8D }, /* -50.0db */ + { 0X00, 0X36, 0XE1, 0X78 }, /* -49.5db */ + { 0X00, 0X3A, 0X21, 0XF3 }, /* -49.0db */ + { 0X00, 0X3D, 0X93, 0XC3 }, /* -48.5db */ + { 0X00, 0X41, 0X39, 0XD3 }, /* -48.0db */ + { 0X00, 0X45, 0X17, 0X3B }, /* -47.5db */ + { 0X00, 0X49, 0X2F, 0X44 }, /* -47.0db */ + { 0X00, 0X4D, 0X85, 0X66 }, /* -46.5db */ + { 0X00, 0X52, 0X1D, 0X50 }, /* -46.0db */ + { 0X00, 0X56, 0XFA, 0XE8 }, /* -45.5db */ + { 0X00, 0X5C, 0X22, 0X4E }, /* -45.0db */ + { 0X00, 0X61, 0X97, 0XE1 }, /* -44.5db */ + { 0X00, 0X67, 0X60, 0X44 }, /* -44.0db */ + { 0X00, 0X6D, 0X80, 0X60 }, /* -43.5db */ + { 0X00, 0X73, 0XFD, 0X65 }, /* -43.0db */ + { 0X00, 0X7A, 0XDC, 0XD7 }, /* -42.5db */ + { 0X00, 0X82, 0X24, 0X8A }, /* -42.0db */ + { 0X00, 0X89, 0XDA, 0XAB }, /* -41.5db */ + { 0X00, 0X92, 0X05, 0XC6 }, /* -41.0db */ + { 0X00, 0X9A, 0XAC, 0XC8 }, /* -40.5db */ + { 0X00, 0XA3, 0XD7, 0X0A }, /* -40.0db */ + { 0X00, 0XAD, 0X8C, 0X52 }, /* -39.5db */ + { 0X00, 0XB7, 0XD4, 0XDD }, /* -39.0db */ + { 0X00, 0XC2, 0XB9, 0X65 }, /* -38.5db */ + { 0X00, 0XCE, 0X43, 0X28 }, /* -38.0db */ + { 0X00, 0XDA, 0X7B, 0XF1 }, /* -37.5db */ + { 0X00, 0XE7, 0X6E, 0X1E }, /* -37.0db */ + { 0X00, 0XF5, 0X24, 0XAC }, /* -36.5db */ + { 0X01, 0X03, 0XAB, 0X3D }, /* -36.0db */ + { 0X01, 0X13, 0X0E, 0X24 }, /* -35.5db */ + { 0X01, 0X23, 0X5A, 0X71 }, /* -35.0db */ + { 0X01, 0X34, 0X9D, 0XF8 }, /* -34.5db */ + { 0X01, 0X46, 0XE7, 0X5D }, /* -34.0db */ + { 0X01, 0X5A, 0X46, 0X27 }, /* -33.5db */ + { 0X01, 0X6E, 0XCA, 0XC5 }, /* -33.0db */ + { 0X01, 0X84, 0X86, 0X9F }, /* -32.5db */ + { 0X01, 0X9B, 0X8C, 0X27 }, /* -32.0db */ + { 0X01, 0XB3, 0XEE, 0XE5 }, /* -31.5db */ + { 0X01, 0XCD, 0XC3, 0X8C }, /* -31.0db */ + { 0X01, 0XE9, 0X20, 0X05 }, /* -30.5db */ + { 0X02, 0X06, 0X1B, 0X89 }, /* -30.0db */ + { 0X02, 0X24, 0XCE, 0XB0 }, /* -29.5db */ + { 0X02, 0X45, 0X53, 0X85 }, /* -29.0db */ + { 0X02, 0X67, 0XC5, 0XA2 }, /* -28.5db */ + { 0X02, 0X8C, 0X42, 0X3F }, /* -28.0db */ + { 0X02, 0XB2, 0XE8, 0X55 }, /* -27.5db */ + { 0X02, 0XDB, 0XD8, 0XAD }, /* -27.0db */ + { 0X03, 0X07, 0X36, 0X05 }, /* -26.5db */ + { 0X03, 0X35, 0X25, 0X29 }, /* -26.0db */ + { 0X03, 0X65, 0XCD, 0X13 }, /* -25.5db */ + { 0X03, 0X99, 0X57, 0X0C }, /* -25.0db */ + { 0X03, 0XCF, 0XEE, 0XCF }, /* -24.5db */ + { 0X04, 0X09, 0XC2, 0XB0 }, /* -24.0db */ + { 0X04, 0X47, 0X03, 0XC1 }, /* -23.5db */ + { 0X04, 0X87, 0XE5, 0XFB }, /* -23.0db */ + { 0X04, 0XCC, 0XA0, 0X6D }, /* -22.5db */ + { 0X05, 0X15, 0X6D, 0X68 }, /* -22.0db */ + { 0X05, 0X62, 0X8A, 0XB3 }, /* -21.5db */ + { 0X05, 0XB4, 0X39, 0XBC }, /* -21.0db */ + { 0X06, 0X0A, 0XBF, 0XD4 }, /* -20.5db */ + { 0X06, 0X66, 0X66, 0X66 }, /* -20.0db */ + { 0X06, 0XC7, 0X7B, 0X36 }, /* -19.5db */ + { 0X07, 0X2E, 0X50, 0XA6 }, /* -19.0db */ + { 0X07, 0X9B, 0X3D, 0XF6 }, /* -18.5db */ + { 0X08, 0X0E, 0X9F, 0X96 }, /* -18.0db */ + { 0X08, 0X88, 0XD7, 0X6D }, /* -17.5db */ + { 0X09, 0X0A, 0X4D, 0X2F }, /* -17.0db */ + { 0X09, 0X93, 0X6E, 0XB8 }, /* -16.5db */ + { 0X0A, 0X24, 0XB0, 0X62 }, /* -16.0db */ + { 0X0A, 0XBE, 0X8D, 0X70 }, /* -15.5db */ + { 0X0B, 0X61, 0X88, 0X71 }, /* -15.0db */ + { 0X0C, 0X0E, 0X2B, 0XB0 }, /* -14.5db */ + { 0X0C, 0XC5, 0X09, 0XAB }, /* -14.0db */ + { 0X0D, 0X86, 0XBD, 0X8D }, /* -13.5db */ + { 0X0E, 0X53, 0XEB, 0XB3 }, /* -13.0db */ + { 0X0F, 0X2D, 0X42, 0X38 }, /* -12.5db */ + { 0X10, 0X13, 0X79, 0X87 }, /* -12.0db */ + { 0X11, 0X07, 0X54, 0XF9 }, /* -11.5db */ + { 0X12, 0X09, 0XA3, 0X7A }, /* -11.0db */ + { 0X13, 0X1B, 0X40, 0X39 }, /* -10.5db */ + { 0X14, 0X3D, 0X13, 0X62 }, /* -10.0db */ + { 0X15, 0X70, 0X12, 0XE1 }, /* -9.5db */ + { 0X16, 0XB5, 0X43, 0X37 }, /* -9.0db */ + { 0X18, 0X0D, 0XB8, 0X54 }, /* -8.5db */ + { 0X19, 0X7A, 0X96, 0X7F }, /* -8.0db */ + { 0X1A, 0XFD, 0X13, 0X54 }, /* -7.5db */ + { 0X1C, 0X96, 0X76, 0XC6 }, /* -7.0db */ + { 0X1E, 0X48, 0X1C, 0X37 }, /* -6.5db */ + { 0X20, 0X13, 0X73, 0X9E }, /* -6.0db */ + { 0X21, 0XFA, 0X02, 0XBF }, /* -5.5db */ + { 0X23, 0XFD, 0X66, 0X78 }, /* -5.0db */ + { 0X26, 0X1F, 0X54, 0X1C }, /* -4.5db */ + { 0X28, 0X61, 0X9A, 0XE9 }, /* -4.0db */ + { 0X2A, 0XC6, 0X25, 0X91 }, /* -3.5db */ + { 0X2D, 0X4E, 0XFB, 0XD5 }, /* -3.0db */ + { 0X2F, 0XFE, 0X44, 0X48 }, /* -2.5db */ + { 0X32, 0XD6, 0X46, 0X17 }, /* -2.0db */ + { 0X35, 0XD9, 0X6B, 0X02 }, /* -1.5db */ + { 0X39, 0X0A, 0X41, 0X5F }, /* -1.0db */ + { 0X3C, 0X6B, 0X7E, 0X4F }, /* -0.5db */ + { 0X40, 0X00, 0X00, 0X00 }, /* 0.0db */ + { 0X43, 0XCA, 0XD0, 0X22 }, /* 0.5db */ + { 0X47, 0XCF, 0X26, 0X7D }, /* 1.0db */ + { 0X4C, 0X10, 0X6B, 0XA5 }, /* 1.5db */ + { 0X50, 0X92, 0X3B, 0XE3 }, /* 2.0db */ + { 0X55, 0X58, 0X6A, 0X46 }, /* 2.5db */ + { 0X5A, 0X67, 0X03, 0XDF }, /* 3.0db */ + { 0X5F, 0XC2, 0X53, 0X32 }, /* 3.5db */ + { 0X65, 0X6E, 0XE3, 0XDB }, /* 4.0db */ + { 0X6B, 0X71, 0X86, 0X68 }, /* 4.5db */ + { 0X71, 0XCF, 0X54, 0X71 }, /* 5.0db */ + { 0X78, 0X8D, 0XB4, 0XE9 }, /* 5.5db */ + { 0XFF, 0XFF, 0XFF, 0XFF }, /* 6.0db */ +}; #endif diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index a43ad6dcb7c7..18161d02a96f 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -50,6 +50,7 @@ #define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E) /* Volume control */ +#define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0C) #define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1A) #define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03) #define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index d5d95ae57c73..e79d613745b4 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -31,6 +31,7 @@ #include #include #include +#include static const struct i2c_device_id tasdevice_id[] = { { "tas2563", TAS2563 }, @@ -140,6 +141,101 @@ static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol, return change; } +static int tas2563_digital_gain_get( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec); + unsigned int l = 0, r = mc->max; + unsigned int target, ar_mid, mid, ar_l, ar_r; + unsigned int reg = mc->reg; + unsigned char data[4]; + int ret; + + mutex_lock(&tas_dev->codec_lock); + /* Read the primary device */ + ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); + if (ret) { + dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); + goto out; + } + + target = get_unaligned_be32(&data[0]); + + while (r > 1 + l) { + mid = (l + r) / 2; + ar_mid = get_unaligned_be32(tas2563_dvc_table[mid]); + if (target < ar_mid) + r = mid; + else + l = mid; + } + + ar_l = get_unaligned_be32(tas2563_dvc_table[l]); + ar_r = get_unaligned_be32(tas2563_dvc_table[r]); + + /* find out the member same as or closer to the current volume */ + ucontrol->value.integer.value[0] = + abs(target - ar_l) <= abs(target - ar_r) ? l : r; +out: + mutex_unlock(&tas_dev->codec_lock); + return 0; +} + +static int tas2563_digital_gain_put( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec); + int vol = ucontrol->value.integer.value[0]; + int status = 0, max = mc->max, rc = 1; + int i, ret; + unsigned int reg = mc->reg; + unsigned int volrd, volwr; + unsigned char data[4]; + + vol = clamp(vol, 0, max); + mutex_lock(&tas_dev->codec_lock); + /* Read the primary device */ + ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); + if (ret) { + dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); + rc = -1; + goto out; + } + + volrd = get_unaligned_be32(&data[0]); + volwr = get_unaligned_be32(tas2563_dvc_table[vol]); + + if (volrd == volwr) { + rc = 0; + goto out; + } + + for (i = 0; i < tas_dev->ndev; i++) { + ret = tasdevice_dev_bulk_write(tas_dev, i, reg, + (unsigned char *)tas2563_dvc_table[vol], 4); + if (ret) { + dev_err(tas_dev->dev, + "%s, set digital vol error in dev %d\n", + __func__, i); + status |= BIT(i); + } + } + + if (status) + rc = -1; +out: + mutex_unlock(&tas_dev->codec_lock); + return rc; +} + static const struct snd_kcontrol_new tasdevice_snd_controls[] = { SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, tasdev_force_fwload_get, tasdev_force_fwload_put), @@ -154,6 +250,13 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { tas2781_digital_putvol, dvc_tlv), }; +static const struct snd_kcontrol_new tas2563_snd_controls[] = { + SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2563_DVC_LVL, 0, + 0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0, + tas2563_digital_gain_get, tas2563_digital_gain_put, + tas2563_dvc_tlv), +}; + static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -593,17 +696,25 @@ static struct snd_soc_dai_driver tasdevice_dai_driver[] = { static int tasdevice_codec_probe(struct snd_soc_component *codec) { struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + struct snd_kcontrol_new *p; + unsigned int size; int rc; - if (tas_priv->chip_id == TAS2781) { - rc = snd_soc_add_component_controls(codec, - tas2781_snd_controls, - ARRAY_SIZE(tas2781_snd_controls)); - if (rc < 0) { - dev_err(tas_priv->dev, "%s: Add control err rc = %d", - __func__, rc); - return rc; - } + switch (tas_priv->chip_id) { + case TAS2781: + p = (struct snd_kcontrol_new *)tas2781_snd_controls; + size = ARRAY_SIZE(tas2781_snd_controls); + break; + default: + p = (struct snd_kcontrol_new *)tas2563_snd_controls; + size = ARRAY_SIZE(tas2563_snd_controls); + } + + rc = snd_soc_add_component_controls(codec, p, size); + if (rc < 0) { + dev_err(tas_priv->dev, "%s: Add control err rc = %d", + __func__, rc); + return rc; } tas_priv->name_prefix = codec->name_prefix; -- cgit v1.2.3