Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: rt5575: Add the codec driver for the ALC5575

Merge series from Oder Chiou <oder_chiou@realtek.com>:

This patch series adds support for the Realtek ALC5575 audio codec.

+651 -10
+61
Documentation/devicetree/bindings/sound/realtek,rt5575.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/sound/realtek,rt5575.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ALC5575 audio CODEC 8 + 9 + maintainers: 10 + - Oder Chiou <oder_chiou@realtek.com> 11 + 12 + description: 13 + The device supports both I2C and SPI. I2C is mandatory, while SPI is 14 + optional depending on the hardware configuration. SPI is used for 15 + firmware loading if present. 16 + 17 + allOf: 18 + - $ref: dai-common.yaml# 19 + 20 + properties: 21 + compatible: 22 + const: realtek,rt5575 23 + 24 + reg: 25 + maxItems: 1 26 + 27 + spi-parent: 28 + description: 29 + Optional phandle reference to the SPI controller used for firmware 30 + loading. The argument specifies the chip select. 31 + $ref: /schemas/types.yaml#/definitions/phandle-array 32 + 33 + required: 34 + - compatible 35 + - reg 36 + 37 + unevaluatedProperties: false 38 + 39 + examples: 40 + # I2C-only node 41 + - | 42 + i2c { 43 + #address-cells = <1>; 44 + #size-cells = <0>; 45 + codec@57 { 46 + compatible = "realtek,rt5575"; 47 + reg = <0x57>; 48 + }; 49 + }; 50 + 51 + # I2C + optional SPI node 52 + - | 53 + i2c { 54 + #address-cells = <1>; 55 + #size-cells = <0>; 56 + codec@57 { 57 + compatible = "realtek,rt5575"; 58 + reg = <0x57>; 59 + spi-parent = <&spi0 0>; /* chip-select 0 */ 60 + }; 61 + };
+13 -10
drivers/spi/spi.c
··· 4761 4761 4762 4762 /*-------------------------------------------------------------------------*/ 4763 4763 4764 - #if IS_ENABLED(CONFIG_OF_DYNAMIC) 4765 - /* Must call put_device() when done with returned spi_device device */ 4766 - static struct spi_device *of_find_spi_device_by_node(struct device_node *node) 4767 - { 4768 - struct device *dev = bus_find_device_by_of_node(&spi_bus_type, node); 4769 - 4770 - return dev ? to_spi_device(dev) : NULL; 4771 - } 4772 - 4764 + #if IS_ENABLED(CONFIG_OF) 4773 4765 /* The spi controllers are not using spi_bus, so we find it with another way */ 4774 - static struct spi_controller *of_find_spi_controller_by_node(struct device_node *node) 4766 + struct spi_controller *of_find_spi_controller_by_node(struct device_node *node) 4775 4767 { 4776 4768 struct device *dev; 4777 4769 ··· 4775 4783 4776 4784 /* Reference got in class_find_device */ 4777 4785 return container_of(dev, struct spi_controller, dev); 4786 + } 4787 + EXPORT_SYMBOL_GPL(of_find_spi_controller_by_node); 4788 + #endif 4789 + 4790 + #if IS_ENABLED(CONFIG_OF_DYNAMIC) 4791 + /* Must call put_device() when done with returned spi_device device */ 4792 + static struct spi_device *of_find_spi_device_by_node(struct device_node *node) 4793 + { 4794 + struct device *dev = bus_find_device_by_of_node(&spi_bus_type, node); 4795 + 4796 + return dev ? to_spi_device(dev) : NULL; 4778 4797 } 4779 4798 4780 4799 static int of_spi_notify(struct notifier_block *nb, unsigned long action,
+9
include/linux/spi/spi.h
··· 882 882 struct spi_controller *ctlr); 883 883 extern void spi_unregister_controller(struct spi_controller *ctlr); 884 884 885 + #if IS_ENABLED(CONFIG_OF) 886 + extern struct spi_controller *of_find_spi_controller_by_node(struct device_node *node); 887 + #else 888 + static inline struct spi_controller *of_find_spi_controller_by_node(struct device_node *node) 889 + { 890 + return NULL; 891 + } 892 + #endif 893 + 885 894 #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SPI_MASTER) 886 895 extern struct spi_controller *acpi_spi_find_controller_by_adev(struct acpi_device *adev); 887 896 extern struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
+10
sound/soc/codecs/Kconfig
··· 212 212 imply SND_SOC_RT1305 213 213 imply SND_SOC_RT1308 214 214 imply SND_SOC_RT5514 215 + imply SND_SOC_RT5575 215 216 imply SND_SOC_RT5616 216 217 imply SND_SOC_RT5631 217 218 imply SND_SOC_RT5640 ··· 1783 1782 config SND_SOC_RT5514_SPI_BUILTIN 1784 1783 bool # force RT5514_SPI to be built-in to avoid link errors 1785 1784 default SND_SOC_RT5514=y && SND_SOC_RT5514_SPI=m 1785 + 1786 + config SND_SOC_RT5575 1787 + tristate "Realtek ALC5575 Codec - I2C" 1788 + depends on I2C 1789 + 1790 + config SND_SOC_RT5575_SPI 1791 + tristate "Realtek ALC5575 Codec - SPI" 1792 + depends on SPI_MASTER && I2C 1793 + depends on SND_SOC_RT5575 1786 1794 1787 1795 config SND_SOC_RT5616 1788 1796 tristate "Realtek RT5616 CODEC"
+3
sound/soc/codecs/Makefile
··· 253 253 snd-soc-rt298-y := rt298.o 254 254 snd-soc-rt5514-y := rt5514.o 255 255 snd-soc-rt5514-spi-y := rt5514-spi.o 256 + snd-soc-rt5575-y := rt5575.o 257 + snd-soc-rt5575-$(CONFIG_SND_SOC_RT5575_SPI) += rt5575-spi.o 256 258 snd-soc-rt5616-y := rt5616.o 257 259 snd-soc-rt5631-y := rt5631.o 258 260 snd-soc-rt5640-y := rt5640.o ··· 688 686 obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o 689 687 obj-$(CONFIG_SND_SOC_RT5514_SPI) += snd-soc-rt5514-spi.o 690 688 obj-$(CONFIG_SND_SOC_RT5514_SPI_BUILTIN) += snd-soc-rt5514-spi.o 689 + obj-$(CONFIG_SND_SOC_RT5575) += snd-soc-rt5575.o 691 690 obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o 692 691 obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o 693 692 obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
+118
sound/soc/codecs/rt5575-spi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * rt5575-spi.c -- ALC5575 SPI driver 4 + * 5 + * Copyright(c) 2025 Realtek Semiconductor Corp. 6 + * 7 + */ 8 + 9 + #include <linux/firmware.h> 10 + #include <linux/of.h> 11 + #include <linux/spi/spi.h> 12 + 13 + #include "rt5575-spi.h" 14 + 15 + #define RT5575_SPI_CMD_BURST_WRITE 5 16 + #define RT5575_SPI_BUF_LEN 240 17 + 18 + struct rt5575_spi_burst_write { 19 + u8 cmd; 20 + u32 addr; 21 + u8 data[RT5575_SPI_BUF_LEN]; 22 + u8 dummy; 23 + } __packed; 24 + 25 + struct spi_device *rt5575_spi_get_device(struct device *dev) 26 + { 27 + struct spi_device *spi; 28 + struct spi_controller *ctlr; 29 + struct device_node *spi_np; 30 + u32 cs; 31 + 32 + spi_np = of_parse_phandle(dev->of_node, "spi-parent", 0); 33 + if (!spi_np) { 34 + dev_err(dev, "Failed to get spi-parent phandle\n"); 35 + return NULL; 36 + } 37 + 38 + if (of_property_read_u32_index(dev->of_node, "spi-parent", 1, &cs)) 39 + cs = 0; 40 + 41 + ctlr = of_find_spi_controller_by_node(spi_np); 42 + of_node_put(spi_np); 43 + if (!ctlr) { 44 + dev_err(dev, "Failed to get spi_controller\n"); 45 + return NULL; 46 + } 47 + 48 + if (cs >= ctlr->num_chipselect) { 49 + dev_err(dev, "Chip select has wrong number %d\n", cs); 50 + spi_controller_put(ctlr); 51 + return NULL; 52 + } 53 + 54 + spi = spi_new_device(ctlr, &(struct spi_board_info){ 55 + .modalias = "rt5575", 56 + .chip_select = cs, 57 + .max_speed_hz = 10000000, 58 + }); 59 + 60 + spi_controller_put(ctlr); 61 + return spi; 62 + } 63 + 64 + /** 65 + * rt5575_spi_burst_write - Write data to SPI by rt5575 address. 66 + * @spi: SPI device. 67 + * @addr: Start address. 68 + * @txbuf: Data buffer for writing. 69 + * @len: Data length. 70 + * 71 + */ 72 + static void rt5575_spi_burst_write(struct spi_device *spi, u32 addr, const u8 *txbuf, size_t len) 73 + { 74 + struct rt5575_spi_burst_write buf = { 75 + .cmd = RT5575_SPI_CMD_BURST_WRITE, 76 + }; 77 + unsigned int end, offset = 0; 78 + 79 + while (offset < len) { 80 + if (offset + RT5575_SPI_BUF_LEN <= len) 81 + end = RT5575_SPI_BUF_LEN; 82 + else 83 + end = len % RT5575_SPI_BUF_LEN; 84 + 85 + buf.addr = cpu_to_le32(addr + offset); 86 + memcpy(&buf.data, &txbuf[offset], end); 87 + spi_write(spi, &buf, sizeof(buf)); 88 + 89 + offset += RT5575_SPI_BUF_LEN; 90 + } 91 + } 92 + 93 + int rt5575_spi_fw_load(struct spi_device *spi) 94 + { 95 + struct device *dev = &spi->dev; 96 + const struct firmware *firmware; 97 + int i, ret; 98 + static const char * const fw_path[] = { 99 + "realtek/rt5575/rt5575_fw1.bin", 100 + "realtek/rt5575/rt5575_fw2.bin", 101 + "realtek/rt5575/rt5575_fw3.bin", 102 + "realtek/rt5575/rt5575_fw4.bin", 103 + }; 104 + static const u32 fw_addr[] = { 0x5f400000, 0x5f600000, 0x5f7fe000, 0x5f7ff000 }; 105 + 106 + for (i = 0; i < ARRAY_SIZE(fw_addr); i++) { 107 + ret = request_firmware(&firmware, fw_path[i], dev); 108 + if (ret) { 109 + dev_err(dev, "Request firmware failure: %d\n", ret); 110 + return ret; 111 + } 112 + 113 + rt5575_spi_burst_write(spi, fw_addr[i], firmware->data, firmware->size); 114 + release_firmware(firmware); 115 + } 116 + 117 + return 0; 118 + }
+27
sound/soc/codecs/rt5575-spi.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * rt5575-spi.h -- ALC5575 SPI driver 4 + * 5 + * Copyright(c) 2025 Realtek Semiconductor Corp. 6 + * 7 + */ 8 + 9 + #ifndef __RT5575_SPI_H__ 10 + #define __RT5575_SPI_H__ 11 + 12 + #if IS_ENABLED(CONFIG_SND_SOC_RT5575_SPI) 13 + struct spi_device *rt5575_spi_get_device(struct device *dev); 14 + int rt5575_spi_fw_load(struct spi_device *spi); 15 + #else 16 + static inline struct spi_device *rt5575_spi_get_device(struct device *dev) 17 + { 18 + return NULL; 19 + } 20 + 21 + static inline int rt5575_spi_fw_load(struct spi_device *spi) 22 + { 23 + return -EINVAL; 24 + } 25 + #endif 26 + 27 + #endif /* __RT5575_SPI_H__ */
+352
sound/soc/codecs/rt5575.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * rt5575.c -- ALC5575 ALSA SoC audio component driver 4 + * 5 + * Copyright(c) 2025 Realtek Semiconductor Corp. 6 + * 7 + */ 8 + 9 + #include <linux/i2c.h> 10 + #include <sound/soc.h> 11 + #include <sound/tlv.h> 12 + 13 + #include "rt5575.h" 14 + #include "rt5575-spi.h" 15 + 16 + static bool rt5575_readable_register(struct device *dev, unsigned int reg) 17 + { 18 + switch (reg) { 19 + case RT5575_BOOT: 20 + case RT5575_ID: 21 + case RT5575_ID_1: 22 + case RT5575_MIXL_VOL: 23 + case RT5575_MIXR_VOL: 24 + case RT5575_PROMPT_VOL: 25 + case RT5575_SPK01_VOL: 26 + case RT5575_SPK23_VOL: 27 + case RT5575_MIC1_VOL: 28 + case RT5575_MIC2_VOL: 29 + case RT5575_WNC_CTRL: 30 + case RT5575_MODE_CTRL: 31 + case RT5575_I2S_RATE_CTRL: 32 + case RT5575_SLEEP_CTRL: 33 + case RT5575_ALG_BYPASS_CTRL: 34 + case RT5575_PINMUX_CTRL_2: 35 + case RT5575_GPIO_CTRL_1: 36 + case RT5575_DSP_BUS_CTRL: 37 + case RT5575_SW_INT: 38 + case RT5575_DSP_BOOT_ERR: 39 + case RT5575_DSP_READY: 40 + case RT5575_DSP_CMD_ADDR: 41 + case RT5575_EFUSE_DATA_2: 42 + case RT5575_EFUSE_DATA_3: 43 + return true; 44 + default: 45 + return false; 46 + } 47 + } 48 + 49 + static const DECLARE_TLV_DB_SCALE(ob_tlv, -9525, 75, 0); 50 + 51 + static const struct snd_kcontrol_new rt5575_snd_controls[] = { 52 + SOC_DOUBLE("Speaker CH-01 Playback Switch", RT5575_SPK01_VOL, 31, 15, 1, 1), 53 + SOC_DOUBLE_TLV("Speaker CH-01 Playback Volume", RT5575_SPK01_VOL, 17, 1, 167, 0, ob_tlv), 54 + SOC_DOUBLE("Speaker CH-23 Playback Switch", RT5575_SPK23_VOL, 31, 15, 1, 1), 55 + SOC_DOUBLE_TLV("Speaker CH-23 Playback Volume", RT5575_SPK23_VOL, 17, 1, 167, 0, ob_tlv), 56 + SOC_DOUBLE("Mic1 Capture Switch", RT5575_MIC1_VOL, 31, 15, 1, 1), 57 + SOC_DOUBLE_TLV("Mic1 Capture Volume", RT5575_MIC1_VOL, 17, 1, 167, 0, ob_tlv), 58 + SOC_DOUBLE("Mic2 Capture Switch", RT5575_MIC2_VOL, 31, 15, 1, 1), 59 + SOC_DOUBLE_TLV("Mic2 Capture Volume", RT5575_MIC2_VOL, 17, 1, 167, 0, ob_tlv), 60 + SOC_DOUBLE_R("Mix Playback Switch", RT5575_MIXL_VOL, RT5575_MIXR_VOL, 31, 1, 1), 61 + SOC_DOUBLE_R_TLV("Mix Playback Volume", RT5575_MIXL_VOL, RT5575_MIXR_VOL, 1, 127, 0, 62 + ob_tlv), 63 + SOC_DOUBLE("Prompt Playback Switch", RT5575_PROMPT_VOL, 31, 15, 1, 1), 64 + SOC_DOUBLE_TLV("Prompt Playback Volume", RT5575_PROMPT_VOL, 17, 1, 167, 0, ob_tlv), 65 + }; 66 + 67 + static const struct snd_soc_dapm_widget rt5575_dapm_widgets[] = { 68 + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), 69 + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), 70 + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), 71 + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), 72 + SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), 73 + SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), 74 + SND_SOC_DAPM_AIF_IN("AIF4RX", "AIF4 Playback", 0, SND_SOC_NOPM, 0, 0), 75 + SND_SOC_DAPM_AIF_OUT("AIF4TX", "AIF4 Capture", 0, SND_SOC_NOPM, 0, 0), 76 + 77 + SND_SOC_DAPM_INPUT("INPUT"), 78 + SND_SOC_DAPM_OUTPUT("OUTPUT"), 79 + }; 80 + 81 + static const struct snd_soc_dapm_route rt5575_dapm_routes[] = { 82 + { "AIF1TX", NULL, "INPUT" }, 83 + { "AIF2TX", NULL, "INPUT" }, 84 + { "AIF3TX", NULL, "INPUT" }, 85 + { "AIF4TX", NULL, "INPUT" }, 86 + { "OUTPUT", NULL, "AIF1RX" }, 87 + { "OUTPUT", NULL, "AIF2RX" }, 88 + { "OUTPUT", NULL, "AIF3RX" }, 89 + { "OUTPUT", NULL, "AIF4RX" }, 90 + }; 91 + 92 + static long long rt5575_get_priv_id(struct rt5575_priv *rt5575) 93 + { 94 + int priv_id_low, priv_id_high; 95 + 96 + regmap_write(rt5575->regmap, RT5575_EFUSE_PID, 0xa0000000); 97 + regmap_read(rt5575->regmap, RT5575_EFUSE_DATA_2, &priv_id_low); 98 + regmap_read(rt5575->regmap, RT5575_EFUSE_DATA_3, &priv_id_high); 99 + regmap_write(rt5575->regmap, RT5575_EFUSE_PID, 0); 100 + 101 + return ((long long)priv_id_high << 32) | (long long)priv_id_low; 102 + } 103 + 104 + static int rt5575_probe(struct snd_soc_component *component) 105 + { 106 + struct rt5575_priv *rt5575 = snd_soc_component_get_drvdata(component); 107 + struct device *dev = component->dev; 108 + 109 + rt5575->component = component; 110 + 111 + dev_info(dev, "Private ID: %llx\n", rt5575_get_priv_id(rt5575)); 112 + 113 + return 0; 114 + } 115 + 116 + #define RT5575_STEREO_RATES SNDRV_PCM_RATE_8000_192000 117 + #define RT5575_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ 118 + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8 | \ 119 + SNDRV_PCM_FMTBIT_S32_LE) 120 + 121 + static struct snd_soc_dai_driver rt5575_dai[] = { 122 + { 123 + .name = "rt5575-aif1", 124 + .id = RT5575_AIF1, 125 + .playback = { 126 + .stream_name = "AIF1 Playback", 127 + .channels_min = 1, 128 + .channels_max = 8, 129 + .rates = RT5575_STEREO_RATES, 130 + .formats = RT5575_FORMATS, 131 + }, 132 + .capture = { 133 + .stream_name = "AIF1 Capture", 134 + .channels_min = 1, 135 + .channels_max = 8, 136 + .rates = RT5575_STEREO_RATES, 137 + .formats = RT5575_FORMATS, 138 + }, 139 + }, 140 + { 141 + .name = "rt5575-aif2", 142 + .id = RT5575_AIF2, 143 + .playback = { 144 + .stream_name = "AIF2 Playback", 145 + .channels_min = 1, 146 + .channels_max = 8, 147 + .rates = RT5575_STEREO_RATES, 148 + .formats = RT5575_FORMATS, 149 + }, 150 + .capture = { 151 + .stream_name = "AIF2 Capture", 152 + .channels_min = 1, 153 + .channels_max = 8, 154 + .rates = RT5575_STEREO_RATES, 155 + .formats = RT5575_FORMATS, 156 + }, 157 + }, 158 + { 159 + .name = "rt5575-aif3", 160 + .id = RT5575_AIF3, 161 + .playback = { 162 + .stream_name = "AIF3 Playback", 163 + .channels_min = 1, 164 + .channels_max = 8, 165 + .rates = RT5575_STEREO_RATES, 166 + .formats = RT5575_FORMATS, 167 + }, 168 + .capture = { 169 + .stream_name = "AIF3 Capture", 170 + .channels_min = 1, 171 + .channels_max = 8, 172 + .rates = RT5575_STEREO_RATES, 173 + .formats = RT5575_FORMATS, 174 + }, 175 + }, 176 + { 177 + .name = "rt5575-aif4", 178 + .id = RT5575_AIF4, 179 + .playback = { 180 + .stream_name = "AIF4 Playback", 181 + .channels_min = 1, 182 + .channels_max = 8, 183 + .rates = RT5575_STEREO_RATES, 184 + .formats = RT5575_FORMATS, 185 + }, 186 + .capture = { 187 + .stream_name = "AIF4 Capture", 188 + .channels_min = 1, 189 + .channels_max = 8, 190 + .rates = RT5575_STEREO_RATES, 191 + .formats = RT5575_FORMATS, 192 + }, 193 + }, 194 + }; 195 + 196 + static const struct snd_soc_component_driver rt5575_soc_component_dev = { 197 + .probe = rt5575_probe, 198 + .controls = rt5575_snd_controls, 199 + .num_controls = ARRAY_SIZE(rt5575_snd_controls), 200 + .dapm_widgets = rt5575_dapm_widgets, 201 + .num_dapm_widgets = ARRAY_SIZE(rt5575_dapm_widgets), 202 + .dapm_routes = rt5575_dapm_routes, 203 + .num_dapm_routes = ARRAY_SIZE(rt5575_dapm_routes), 204 + .use_pmdown_time = 1, 205 + .endianness = 1, 206 + }; 207 + 208 + static const struct regmap_config rt5575_dsp_regmap = { 209 + .name = "dsp", 210 + .reg_bits = 32, 211 + .val_bits = 32, 212 + .reg_stride = 2, 213 + }; 214 + 215 + static int rt5575_i2c_read(void *context, unsigned int reg, unsigned int *val) 216 + { 217 + struct i2c_client *client = context; 218 + struct rt5575_priv *rt5575 = i2c_get_clientdata(client); 219 + 220 + return regmap_read(rt5575->dsp_regmap, reg | RT5575_DSP_MAPPING, val); 221 + } 222 + 223 + static int rt5575_i2c_write(void *context, unsigned int reg, unsigned int val) 224 + { 225 + struct i2c_client *client = context; 226 + struct rt5575_priv *rt5575 = i2c_get_clientdata(client); 227 + 228 + return regmap_write(rt5575->dsp_regmap, reg | RT5575_DSP_MAPPING, val); 229 + } 230 + 231 + static const struct regmap_config rt5575_regmap = { 232 + .reg_bits = 16, 233 + .val_bits = 32, 234 + .reg_stride = 4, 235 + .max_register = 0xfffc, 236 + .readable_reg = rt5575_readable_register, 237 + .reg_read = rt5575_i2c_read, 238 + .reg_write = rt5575_i2c_write, 239 + .use_single_read = true, 240 + .use_single_write = true, 241 + }; 242 + 243 + static int rt5575_fw_load_by_spi(struct rt5575_priv *rt5575) 244 + { 245 + struct i2c_client *i2c = rt5575->i2c; 246 + struct spi_device *spi; 247 + struct device *dev = &i2c->dev; 248 + int ret; 249 + 250 + spi = rt5575_spi_get_device(dev); 251 + if (!spi) { 252 + dev_err(dev, "Failed to get spi_device\n"); 253 + return -ENODEV; 254 + } 255 + 256 + regmap_write(rt5575->dsp_regmap, 0xfafafafa, 0x00000004); 257 + regmap_write(rt5575->dsp_regmap, 0x18008064, 0x00000000); 258 + regmap_write(rt5575->dsp_regmap, 0x18008068, 0x0002ffff); 259 + 260 + ret = rt5575_spi_fw_load(spi); 261 + if (ret) { 262 + dev_err(dev, "Load firmware failure: %d\n", ret); 263 + return -ENODEV; 264 + } 265 + 266 + regmap_write(rt5575->dsp_regmap, 0x18000000, 0x00000000); 267 + regmap_update_bits(rt5575->regmap, RT5575_SW_INT, 1, 1); 268 + 269 + regmap_read_poll_timeout(rt5575->regmap, RT5575_SW_INT, ret, !ret, 100000, 10000000); 270 + if (ret) { 271 + dev_err(dev, "Run firmware failure: %d\n", ret); 272 + return -ENODEV; 273 + } 274 + 275 + return 0; 276 + } 277 + 278 + static int rt5575_i2c_probe(struct i2c_client *i2c) 279 + { 280 + struct rt5575_priv *rt5575; 281 + int ret, val, boot; 282 + struct device *dev = &i2c->dev; 283 + 284 + rt5575 = devm_kzalloc(dev, sizeof(struct rt5575_priv), GFP_KERNEL); 285 + if (!rt5575) 286 + return -ENOMEM; 287 + 288 + i2c_set_clientdata(i2c, rt5575); 289 + 290 + rt5575->i2c = i2c; 291 + 292 + rt5575->dsp_regmap = devm_regmap_init_i2c(i2c, &rt5575_dsp_regmap); 293 + if (IS_ERR(rt5575->dsp_regmap)) { 294 + ret = PTR_ERR(rt5575->dsp_regmap); 295 + dev_err(dev, "Failed to allocate DSP register map: %d\n", ret); 296 + return ret; 297 + } 298 + 299 + rt5575->regmap = devm_regmap_init(dev, NULL, i2c, &rt5575_regmap); 300 + if (IS_ERR(rt5575->regmap)) { 301 + ret = PTR_ERR(rt5575->regmap); 302 + dev_err(dev, "Failed to allocate register map: %d\n", ret); 303 + return ret; 304 + } 305 + 306 + regmap_read(rt5575->regmap, RT5575_ID, &val); 307 + if (val != RT5575_DEVICE_ID) { 308 + dev_err(dev, "Device with ID register %08x is not rt5575\n", val); 309 + return -ENODEV; 310 + } 311 + 312 + regmap_read(rt5575->regmap, RT5575_BOOT, &boot); 313 + if ((boot & RT5575_BOOT_MASK) == RT5575_BOOT_SPI) { 314 + if (!IS_ENABLED(CONFIG_SND_SOC_RT5575_SPI)) { 315 + dev_err(dev, "Please enable CONFIG_SND_SOC_RT5575_SPI\n"); 316 + return -ENODEV; 317 + } 318 + 319 + if (rt5575_fw_load_by_spi(rt5575)) 320 + return -ENODEV; 321 + } 322 + 323 + return devm_snd_soc_register_component(dev, &rt5575_soc_component_dev, rt5575_dai, 324 + ARRAY_SIZE(rt5575_dai)); 325 + } 326 + 327 + static const struct i2c_device_id rt5575_i2c_id[] = { 328 + { "rt5575" }, 329 + { } 330 + }; 331 + MODULE_DEVICE_TABLE(i2c, rt5575_i2c_id); 332 + 333 + static const struct of_device_id rt5575_of_match[] = { 334 + { .compatible = "realtek,rt5575" }, 335 + { } 336 + }; 337 + MODULE_DEVICE_TABLE(of, rt5575_of_match); 338 + 339 + static struct i2c_driver rt5575_i2c_driver = { 340 + .driver = { 341 + .name = "rt5575", 342 + .owner = THIS_MODULE, 343 + .of_match_table = rt5575_of_match, 344 + }, 345 + .probe = rt5575_i2c_probe, 346 + .id_table = rt5575_i2c_id, 347 + }; 348 + module_i2c_driver(rt5575_i2c_driver); 349 + 350 + MODULE_DESCRIPTION("ASoC ALC5575 driver"); 351 + MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); 352 + MODULE_LICENSE("GPL");
+58
sound/soc/codecs/rt5575.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * rt5575.h -- ALC5575 ALSA SoC audio driver 4 + * 5 + * Copyright(c) 2025 Realtek Semiconductor Corp. 6 + * 7 + */ 8 + 9 + #ifndef __RT5575_H__ 10 + #define __RT5575_H__ 11 + 12 + #define RT5575_DEVICE_ID 0x10ec5575 13 + #define RT5575_DSP_MAPPING 0x18000000 14 + 15 + #define RT5575_BOOT 0x8004 16 + #define RT5575_ID 0x8008 17 + #define RT5575_ID_1 0x800c 18 + #define RT5575_MIXL_VOL 0x8a14 19 + #define RT5575_MIXR_VOL 0x8a18 20 + #define RT5575_PROMPT_VOL 0x8a84 21 + #define RT5575_SPK01_VOL 0x8a88 22 + #define RT5575_SPK23_VOL 0x8a8c 23 + #define RT5575_MIC1_VOL 0x8a98 24 + #define RT5575_MIC2_VOL 0x8a9c 25 + #define RT5575_WNC_CTRL 0x80ec 26 + #define RT5575_MODE_CTRL 0x80f0 27 + #define RT5575_I2S_RATE_CTRL 0x80f4 28 + #define RT5575_SLEEP_CTRL 0x80f8 29 + #define RT5575_ALG_BYPASS_CTRL 0x80fc 30 + #define RT5575_PINMUX_CTRL_2 0x81a4 31 + #define RT5575_GPIO_CTRL_1 0x8208 32 + #define RT5575_DSP_BUS_CTRL 0x880c 33 + #define RT5575_SW_INT 0x0018 34 + #define RT5575_DSP_BOOT_ERR 0x8e14 35 + #define RT5575_DSP_READY 0x8e24 36 + #define RT5575_DSP_CMD_ADDR 0x8e28 37 + #define RT5575_EFUSE_DATA_2 0xc638 38 + #define RT5575_EFUSE_DATA_3 0xc63c 39 + #define RT5575_EFUSE_PID 0xc660 40 + 41 + #define RT5575_BOOT_MASK 0x3 42 + #define RT5575_BOOT_SPI 0x0 43 + 44 + enum { 45 + RT5575_AIF1, 46 + RT5575_AIF2, 47 + RT5575_AIF3, 48 + RT5575_AIF4, 49 + RT5575_AIFS, 50 + }; 51 + 52 + struct rt5575_priv { 53 + struct i2c_client *i2c; 54 + struct snd_soc_component *component; 55 + struct regmap *dsp_regmap, *regmap; 56 + }; 57 + 58 + #endif /* __RT5575_H__ */