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.

Add support for Cirrus Logic CS530x DAC and CODEC

Merge series from Vitaly Rodionov <vitalyr@opensource.cirrus.com>:

This patch series introduces DAC, CODEC, and SPI control bus support
for Cirrus Logic CS530x variants, along with general code cleanup
and resolution of checkpatch.pl warnings.

+636 -106
+8
Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml
··· 15 15 16 16 allOf: 17 17 - $ref: dai-common.yaml# 18 + - $ref: /schemas/spi/spi-peripheral-props.yaml# 18 19 19 20 properties: 20 21 compatible: 21 22 enum: 23 + - cirrus,cs4282 24 + - cirrus,cs4302 25 + - cirrus,cs4304 26 + - cirrus,cs4308 22 27 - cirrus,cs5302 23 28 - cirrus,cs5304 24 29 - cirrus,cs5308 25 30 26 31 reg: 27 32 maxItems: 1 33 + 34 + spi-max-frequency: 35 + maximum: 24000000 28 36 29 37 '#sound-dai-cells': 30 38 const: 1
+10
sound/soc/codecs/Kconfig
··· 106 106 imply SND_SOC_CS48L32 107 107 imply SND_SOC_CS53L30 108 108 imply SND_SOC_CS530X_I2C 109 + imply SND_SOC_CS530X_SPI 109 110 imply SND_SOC_CX20442 110 111 imply SND_SOC_CX2072X 111 112 imply SND_SOC_DA7210 ··· 1100 1099 help 1101 1100 Enable support for Cirrus Logic CS530X ADCs 1102 1101 with I2C control. 1102 + 1103 + config SND_SOC_CS530X_SPI 1104 + tristate "Cirrus Logic CS530x ADCs (SPI)" 1105 + depends on SPI_MASTER 1106 + select REGMAP_SPI 1107 + select SND_SOC_CS530X 1108 + help 1109 + Enable support for Cirrus Logic CS530X ADCs 1110 + with SPI control. 1103 1111 1104 1112 config SND_SOC_CX20442 1105 1113 tristate
+2
sound/soc/codecs/Makefile
··· 115 115 snd-soc-cs53l30-y := cs53l30.o 116 116 snd-soc-cs530x-y := cs530x.o 117 117 snd-soc-cs530x-i2c-y := cs530x-i2c.o 118 + snd-soc-cs530x-spi-y := cs530x-spi.o 118 119 snd-soc-cx20442-y := cx20442.o 119 120 snd-soc-cx2072x-y := cx2072x.o 120 121 snd-soc-da7210-y := da7210.o ··· 547 546 obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o 548 547 obj-$(CONFIG_SND_SOC_CS530X) += snd-soc-cs530x.o 549 548 obj-$(CONFIG_SND_SOC_CS530X_I2C) += snd-soc-cs530x-i2c.o 549 + obj-$(CONFIG_SND_SOC_CS530X_SPI) += snd-soc-cs530x-spi.o 550 550 obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o 551 551 obj-$(CONFIG_SND_SOC_CX2072X) += snd-soc-cx2072x.o 552 552 obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
+20 -4
sound/soc/codecs/cs530x-i2c.c
··· 2 2 // 3 3 // CS530x CODEC driver 4 4 // 5 - // Copyright (C) 2024 Cirrus Logic, Inc. and 6 - // Cirrus Logic International Semiconductor Ltd. 5 + // Copyright (C) 2024-2025 Cirrus Logic, Inc. and 6 + // Cirrus Logic International Semiconductor Ltd. 7 7 8 8 #include <linux/device.h> 9 9 #include <linux/module.h> ··· 14 14 15 15 static const struct of_device_id cs530x_of_match[] = { 16 16 { 17 + .compatible = "cirrus,cs4282", 18 + .data = (void *)CS4282, 19 + }, { 20 + .compatible = "cirrus,cs4302", 21 + .data = (void *)CS4302, 22 + }, { 23 + .compatible = "cirrus,cs4304", 24 + .data = (void *)CS4304, 25 + }, { 26 + .compatible = "cirrus,cs4308", 27 + .data = (void *)CS4308, 28 + }, { 17 29 .compatible = "cirrus,cs5302", 18 30 .data = (void *)CS5302, 19 31 }, { ··· 40 28 MODULE_DEVICE_TABLE(of, cs530x_of_match); 41 29 42 30 static const struct i2c_device_id cs530x_i2c_id[] = { 31 + { "cs4282", CS4282 }, 32 + { "cs4302", CS4302 }, 33 + { "cs4304", CS4304 }, 34 + { "cs4308", CS4308 }, 43 35 { "cs5302", CS5302 }, 44 36 { "cs5304", CS5304 }, 45 37 { "cs5308", CS5308 }, ··· 61 45 62 46 i2c_set_clientdata(client, cs530x); 63 47 64 - cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap); 48 + cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap_i2c); 65 49 if (IS_ERR(cs530x->regmap)) 66 50 return dev_err_probe(&client->dev, PTR_ERR(cs530x->regmap), 67 - "Failed to allocate register map\n"); 51 + "Failed to allocate register map\n"); 68 52 69 53 cs530x->devtype = (uintptr_t)i2c_get_match_data(client); 70 54 cs530x->dev = &client->dev;
+92
sound/soc/codecs/cs530x-spi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // 3 + // CS530x CODEC driver 4 + // 5 + // Copyright (C) 2025 Cirrus Logic, Inc. and 6 + // Cirrus Logic International Semiconductor Ltd. 7 + 8 + #include <linux/module.h> 9 + #include <linux/platform_device.h> 10 + #include <linux/spi/spi.h> 11 + 12 + #include "cs530x.h" 13 + 14 + static const struct of_device_id cs530x_of_match[] = { 15 + { 16 + .compatible = "cirrus,cs4282", 17 + .data = (void *)CS4282, 18 + }, { 19 + .compatible = "cirrus,cs4302", 20 + .data = (void *)CS4302, 21 + }, { 22 + .compatible = "cirrus,cs4304", 23 + .data = (void *)CS4304, 24 + }, { 25 + .compatible = "cirrus,cs4308", 26 + .data = (void *)CS4308, 27 + }, { 28 + .compatible = "cirrus,cs5302", 29 + .data = (void *)CS5302, 30 + }, { 31 + .compatible = "cirrus,cs5304", 32 + .data = (void *)CS5304, 33 + }, { 34 + .compatible = "cirrus,cs5304", 35 + .data = (void *)CS5308, 36 + }, 37 + {} 38 + }; 39 + MODULE_DEVICE_TABLE(of, cs530x_of_match); 40 + 41 + static const struct spi_device_id cs530x_spi_id[] = { 42 + { "cs4282", CS4282 }, 43 + { "cs4302", CS4302 }, 44 + { "cs4304", CS4304 }, 45 + { "cs4308", CS4308 }, 46 + { "cs5302", CS5302 }, 47 + { "cs5304", CS5304 }, 48 + { "cs5308", CS5308 }, 49 + { } 50 + }; 51 + MODULE_DEVICE_TABLE(spi, cs530x_spi_id); 52 + 53 + static int cs530x_spi_probe(struct spi_device *spi) 54 + { 55 + struct cs530x_priv *cs530x; 56 + struct device *dev = &spi->dev; 57 + int ret; 58 + 59 + cs530x = devm_kzalloc(dev, sizeof(struct cs530x_priv), GFP_KERNEL); 60 + if (cs530x == NULL) 61 + return -ENOMEM; 62 + 63 + spi_set_drvdata(spi, cs530x); 64 + 65 + cs530x->regmap = devm_regmap_init_spi(spi, &cs530x_regmap_spi); 66 + if (IS_ERR(cs530x->regmap)) { 67 + ret = PTR_ERR(cs530x->regmap); 68 + dev_err(dev, "Failed to allocate register map: %d\n", ret); 69 + return ret; 70 + } 71 + 72 + cs530x->devtype = (unsigned long)spi_get_device_match_data(spi); 73 + cs530x->dev = &spi->dev; 74 + 75 + return cs530x_probe(cs530x); 76 + } 77 + 78 + static struct spi_driver cs530x_spi_driver = { 79 + .driver = { 80 + .name = "cs530x", 81 + .of_match_table = cs530x_of_match, 82 + }, 83 + .id_table = cs530x_spi_id, 84 + .probe = cs530x_spi_probe, 85 + }; 86 + 87 + module_spi_driver(cs530x_spi_driver); 88 + 89 + MODULE_DESCRIPTION("SPI CS530X driver"); 90 + MODULE_IMPORT_NS("SND_SOC_CS530X"); 91 + MODULE_AUTHOR("Vitaly Rodionov <vitalyr@opensource.cirrus.com>"); 92 + MODULE_LICENSE("GPL");
+444 -72
sound/soc/codecs/cs530x.c
··· 2 2 // 3 3 // CS530x CODEC driver 4 4 // 5 - // Copyright (C) 2024 Cirrus Logic, Inc. and 6 - // Cirrus Logic International Semiconductor Ltd. 5 + // Copyright (C) 2024-2025 Cirrus Logic, Inc. and 6 + // Cirrus Logic International Semiconductor Ltd. 7 7 8 - #include <sound/core.h> 9 8 #include <linux/delay.h> 10 9 #include <linux/i2c.h> 11 10 #include <linux/init.h> 12 - #include <sound/initval.h> 13 11 #include <linux/module.h> 14 - #include <sound/pcm.h> 15 - #include <sound/pcm_params.h> 16 12 #include <linux/pm.h> 17 13 #include <linux/property.h> 18 14 #include <linux/slab.h> 15 + #include <linux/spi/spi.h> 16 + #include <sound/core.h> 17 + #include <sound/initval.h> 18 + #include <sound/pcm.h> 19 + #include <sound/pcm_params.h> 19 20 #include <sound/soc.h> 20 21 #include <sound/tlv.h> 21 22 22 23 #include "cs530x.h" 23 - 24 - #define CS530X_MAX_ADC_CH 8 25 - #define CS530X_MIN_ADC_CH 2 26 24 27 25 static const char *cs530x_supply_names[CS530X_NUM_SUPPLIES] = { 28 26 "vdd-a", ··· 46 48 { CS530X_IN_VOL_CTRL3_1, 0x8000 }, 47 49 { CS530X_IN_VOL_CTRL4_0, 0x8000 }, 48 50 { CS530X_IN_VOL_CTRL4_1, 0x8000 }, 51 + { CS530X_OUT_ENABLES, 0 }, 52 + { CS530X_OUT_RAMP_SUM, 0x0022 }, 53 + { CS530X_OUT_FILTER, 0 }, 54 + { CS530X_OUT_INV, 0 }, 55 + { CS530X_OUT_VOL_CTRL1_0, 0x8000 }, 56 + { CS530X_OUT_VOL_CTRL1_1, 0x8000 }, 57 + { CS530X_OUT_VOL_CTRL2_0, 0x8000 }, 58 + { CS530X_OUT_VOL_CTRL2_1, 0x8000 }, 59 + { CS530X_OUT_VOL_CTRL3_0, 0x8000 }, 60 + { CS530X_OUT_VOL_CTRL3_1, 0x8000 }, 61 + { CS530X_OUT_VOL_CTRL4_0, 0x8000 }, 62 + { CS530X_OUT_VOL_CTRL4_1, 0x8000 }, 49 63 { CS530X_PAD_FN, 0 }, 50 64 { CS530X_PAD_LVL, 0 }, 51 65 }; ··· 83 73 case CS530X_IN_VOL_CTRL3_1: 84 74 case CS530X_IN_VOL_CTRL4_0: 85 75 case CS530X_IN_VOL_CTRL4_1: 76 + case CS530X_OUT_ENABLES: 77 + case CS530X_OUT_RAMP_SUM: 78 + case CS530X_OUT_DEEMPH: 79 + case CS530X_OUT_FILTER: 80 + case CS530X_OUT_INV: 81 + case CS530X_OUT_VOL_CTRL1_0: 82 + case CS530X_OUT_VOL_CTRL1_1: 83 + case CS530X_OUT_VOL_CTRL2_0: 84 + case CS530X_OUT_VOL_CTRL2_1: 85 + case CS530X_OUT_VOL_CTRL3_0: 86 + case CS530X_OUT_VOL_CTRL3_1: 87 + case CS530X_OUT_VOL_CTRL4_0: 88 + case CS530X_OUT_VOL_CTRL4_1: 86 89 case CS530X_PAD_FN: 87 90 case CS530X_PAD_LVL: 88 91 return true; ··· 120 97 switch (reg) { 121 98 case CS530X_SW_RESET: 122 99 case CS530X_IN_VOL_CTRL5: 100 + case CS530X_OUT_VOL_CTRL5: 123 101 return true; 124 102 default: 125 103 return cs530x_read_and_write_regs(reg); ··· 128 104 } 129 105 130 106 static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol, 131 - struct snd_ctl_elem_value *ucontrol) 107 + struct snd_ctl_elem_value *ucontrol) 132 108 { 133 109 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 134 110 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); ··· 142 118 if (ret) 143 119 goto volsw_err; 144 120 145 - /* Write IN_VU bit for the volume change to take effect */ 146 - regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_IN_VU); 121 + /* Write INOUT_VU bit for the volume change to take effect */ 122 + regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_INOUT_VU); 147 123 148 124 volsw_err: 149 125 snd_soc_dapm_mutex_unlock(dapm); ··· 153 129 154 130 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0); 155 131 156 - static const char * const cs530x_in_filter_text[] = { 132 + static const char * const cs530x_inout_filter_text[] = { 157 133 "Min Phase Slow Roll-off", 158 134 "Min Phase Fast Roll-off", 159 135 "Linear Phase Slow Roll-off", ··· 161 137 }; 162 138 163 139 static SOC_ENUM_SINGLE_DECL(cs530x_in_filter_enum, CS530X_IN_FILTER, 164 - CS530X_IN_FILTER_SHIFT, 165 - cs530x_in_filter_text); 140 + CS530X_INOUT_FILTER_SHIFT, 141 + cs530x_inout_filter_text); 166 142 167 - static const char * const cs530x_in_4ch_sum_text[] = { 143 + static SOC_ENUM_SINGLE_DECL(cs530x_out_filter_enum, CS530X_OUT_FILTER, 144 + CS530X_INOUT_FILTER_SHIFT, 145 + cs530x_inout_filter_text); 146 + 147 + static const char * const cs530x_4ch_sum_text[] = { 168 148 "None", 169 149 "Groups of 2", 170 150 "Groups of 4", 171 151 }; 172 152 173 153 static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch4_enum, CS530X_IN_RAMP_SUM, 174 - CS530X_IN_SUM_MODE_SHIFT, 175 - cs530x_in_4ch_sum_text); 154 + CS530X_INOUT_SUM_MODE_SHIFT, 155 + cs530x_4ch_sum_text); 176 156 177 157 static const struct snd_kcontrol_new cs530x_in_sum_4ch_controls[] = { 178 158 SOC_ENUM("IN Sum Select", cs530x_in_sum_ch4_enum), 179 159 }; 180 160 181 - static const char * const cs530x_in_8ch_sum_text[] = { 161 + static SOC_ENUM_SINGLE_DECL(cs530x_out_sum_ch4_enum, CS530X_OUT_RAMP_SUM, 162 + CS530X_INOUT_SUM_MODE_SHIFT, 163 + cs530x_4ch_sum_text); 164 + 165 + static const struct snd_kcontrol_new cs530x_out_sum_4ch_controls[] = { 166 + SOC_ENUM("OUT Sum Select", cs530x_out_sum_ch4_enum), 167 + }; 168 + 169 + static const char * const cs530x_8ch_sum_text[] = { 182 170 "None", 183 171 "Groups of 2", 184 172 "Groups of 4", ··· 198 162 }; 199 163 200 164 static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM, 201 - CS530X_IN_SUM_MODE_SHIFT, 202 - cs530x_in_8ch_sum_text); 165 + CS530X_INOUT_SUM_MODE_SHIFT, 166 + cs530x_8ch_sum_text); 203 167 204 168 static const struct snd_kcontrol_new cs530x_in_sum_8ch_controls[] = { 205 169 SOC_ENUM("IN Sum Select", cs530x_in_sum_ch8_enum), 206 170 }; 207 171 172 + static SOC_ENUM_SINGLE_DECL(cs530x_out_sum_ch8_enum, CS530X_OUT_RAMP_SUM, 173 + CS530X_INOUT_SUM_MODE_SHIFT, 174 + cs530x_8ch_sum_text); 175 + 176 + static const struct snd_kcontrol_new cs530x_out_sum_8ch_controls[] = { 177 + SOC_ENUM("OUT Sum Select", cs530x_out_sum_ch8_enum), 178 + }; 208 179 209 180 static const char * const cs530x_vol_ramp_text[] = { 210 181 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", ··· 236 193 SOC_ENUM("Input Ramp Up", cs530x_ramp_inc_enum), 237 194 SOC_ENUM("Input Ramp Down", cs530x_ramp_dec_enum), 238 195 239 - SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_IN1_INV_SHIFT, 1, 0), 240 - SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_IN2_INV_SHIFT, 1, 0), 196 + SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_INOUT1_INV_SHIFT, 1, 0), 197 + SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_INOUT2_INV_SHIFT, 1, 0), 241 198 }; 242 199 243 200 static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = { ··· 246 203 SOC_SINGLE_EXT_TLV("IN4 Volume", CS530X_IN_VOL_CTRL2_1, 0, 255, 1, 247 204 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 248 205 249 - SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_IN3_INV_SHIFT, 1, 0), 250 - SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_IN4_INV_SHIFT, 1, 0), 206 + SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_INOUT3_INV_SHIFT, 1, 0), 207 + SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_INOUT4_INV_SHIFT, 1, 0), 251 208 }; 252 209 253 210 static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = { ··· 260 217 SOC_SINGLE_EXT_TLV("IN8 Volume", CS530X_IN_VOL_CTRL4_1, 0, 255, 1, 261 218 snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 262 219 263 - SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_IN5_INV_SHIFT, 1, 0), 264 - SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_IN6_INV_SHIFT, 1, 0), 265 - SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_IN7_INV_SHIFT, 1, 0), 266 - SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_IN8_INV_SHIFT, 1, 0), 220 + SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_INOUT5_INV_SHIFT, 1, 0), 221 + SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_INOUT6_INV_SHIFT, 1, 0), 222 + SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_INOUT7_INV_SHIFT, 1, 0), 223 + SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_INOUT8_INV_SHIFT, 1, 0), 267 224 }; 268 225 269 226 static int cs530x_adc_event(struct snd_soc_dapm_widget *w, 270 - struct snd_kcontrol *kcontrol, int event) 227 + struct snd_kcontrol *kcontrol, int event) 271 228 { 272 229 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 273 230 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); ··· 279 236 break; 280 237 case SND_SOC_DAPM_POST_PMU: 281 238 regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + 282 - (w->shift * 2), CS530X_IN_MUTE); 239 + (w->shift * 2), CS530X_INOUT_MUTE); 283 240 regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + 284 - ((w->shift+1) * 2), CS530X_IN_MUTE); 241 + ((w->shift + 1) * 2), CS530X_INOUT_MUTE); 285 242 286 243 cs530x->adc_pairs_count--; 287 244 if (!cs530x->adc_pairs_count) { 288 245 usleep_range(1000, 1100); 289 246 return regmap_write(regmap, CS530X_IN_VOL_CTRL5, 290 - CS530X_IN_VU); 247 + CS530X_INOUT_VU); 291 248 } 292 249 break; 293 250 case SND_SOC_DAPM_PRE_PMD: 294 251 regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + 295 - (w->shift * 2), CS530X_IN_MUTE); 252 + (w->shift * 2), CS530X_INOUT_MUTE); 296 253 regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + 297 - ((w->shift+1) * 2), CS530X_IN_MUTE); 254 + ((w->shift + 1) * 2), CS530X_INOUT_MUTE); 298 255 return regmap_write(regmap, CS530X_IN_VOL_CTRL5, 299 - CS530X_IN_VU); 256 + CS530X_INOUT_VU); 257 + default: 258 + return -EINVAL; 259 + } 260 + 261 + return 0; 262 + } 263 + 264 + static SOC_ENUM_SINGLE_DECL(cs530x_ramp_out_inc_enum, CS530X_OUT_RAMP_SUM, 265 + CS530X_RAMP_RATE_INC_SHIFT, 266 + cs530x_vol_ramp_text); 267 + 268 + static SOC_ENUM_SINGLE_DECL(cs530x_ramp_out_dec_enum, CS530X_OUT_RAMP_SUM, 269 + CS530X_RAMP_RATE_DEC_SHIFT, 270 + cs530x_vol_ramp_text); 271 + 272 + static const struct snd_kcontrol_new cs530x_out_1_to_2_controls[] = { 273 + SOC_SINGLE_EXT_TLV("OUT1 Volume", CS530X_OUT_VOL_CTRL1_0, 0, 255, 1, 274 + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 275 + SOC_SINGLE_EXT_TLV("OUT2 Volume", CS530X_OUT_VOL_CTRL1_1, 0, 255, 1, 276 + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 277 + 278 + SOC_ENUM("OUT DEC Filter Select", cs530x_out_filter_enum), 279 + SOC_ENUM("Output Ramp Up", cs530x_ramp_out_inc_enum), 280 + SOC_ENUM("Output Ramp Down", cs530x_ramp_out_dec_enum), 281 + 282 + SOC_SINGLE("DAC1 Invert Switch", CS530X_OUT_INV, CS530X_INOUT1_INV_SHIFT, 1, 0), 283 + SOC_SINGLE("DAC2 Invert Switch", CS530X_OUT_INV, CS530X_INOUT2_INV_SHIFT, 1, 0), 284 + }; 285 + 286 + static const struct snd_kcontrol_new cs530x_out_3_to_4_controls[] = { 287 + SOC_SINGLE_EXT_TLV("OUT3 Volume", CS530X_OUT_VOL_CTRL2_0, 0, 255, 1, 288 + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 289 + SOC_SINGLE_EXT_TLV("OUT4 Volume", CS530X_OUT_VOL_CTRL2_1, 0, 255, 1, 290 + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 291 + 292 + SOC_SINGLE("DAC3 Invert Switch", CS530X_OUT_INV, CS530X_INOUT3_INV_SHIFT, 1, 0), 293 + SOC_SINGLE("DAC4 Invert Switch", CS530X_OUT_INV, CS530X_INOUT4_INV_SHIFT, 1, 0), 294 + }; 295 + 296 + static const struct snd_kcontrol_new cs530x_out_5_to_8_controls[] = { 297 + SOC_SINGLE_EXT_TLV("OUT5 Volume", CS530X_OUT_VOL_CTRL3_0, 0, 255, 1, 298 + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 299 + SOC_SINGLE_EXT_TLV("OUT6 Volume", CS530X_OUT_VOL_CTRL3_1, 0, 255, 1, 300 + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 301 + SOC_SINGLE_EXT_TLV("OUT7 Volume", CS530X_OUT_VOL_CTRL4_0, 0, 255, 1, 302 + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 303 + SOC_SINGLE_EXT_TLV("OUT8 Volume", CS530X_OUT_VOL_CTRL4_1, 0, 255, 1, 304 + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), 305 + 306 + SOC_SINGLE("DAC5 Invert Switch", CS530X_OUT_INV, CS530X_INOUT5_INV_SHIFT, 1, 0), 307 + SOC_SINGLE("DAC6 Invert Switch", CS530X_OUT_INV, CS530X_INOUT6_INV_SHIFT, 1, 0), 308 + SOC_SINGLE("DAC7 Invert Switch", CS530X_OUT_INV, CS530X_INOUT7_INV_SHIFT, 1, 0), 309 + SOC_SINGLE("DAC8 Invert Switch", CS530X_OUT_INV, CS530X_INOUT8_INV_SHIFT, 1, 0), 310 + }; 311 + 312 + static int cs530x_dac_event(struct snd_soc_dapm_widget *w, 313 + struct snd_kcontrol *kcontrol, int event) 314 + { 315 + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 316 + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 317 + struct regmap *regmap = cs530x->regmap; 318 + 319 + switch (event) { 320 + case SND_SOC_DAPM_PRE_PMU: 321 + cs530x->dac_pairs_count++; 322 + break; 323 + case SND_SOC_DAPM_POST_PMU: 324 + regmap_clear_bits(regmap, CS530X_OUT_VOL_CTRL1_0 + 325 + (w->shift * 2), CS530X_INOUT_MUTE); 326 + regmap_clear_bits(regmap, CS530X_OUT_VOL_CTRL1_0 + 327 + ((w->shift + 1) * 2), CS530X_INOUT_MUTE); 328 + 329 + cs530x->dac_pairs_count--; 330 + if (!cs530x->dac_pairs_count) { 331 + usleep_range(1000, 1100); 332 + return regmap_write(regmap, CS530X_OUT_VOL_CTRL5, 333 + CS530X_INOUT_VU); 334 + } 335 + break; 336 + case SND_SOC_DAPM_PRE_PMD: 337 + regmap_set_bits(regmap, CS530X_OUT_VOL_CTRL1_0 + 338 + (w->shift * 2), CS530X_INOUT_MUTE); 339 + regmap_set_bits(regmap, CS530X_OUT_VOL_CTRL1_0 + 340 + ((w->shift + 1) * 2), CS530X_INOUT_MUTE); 341 + return regmap_write(regmap, CS530X_OUT_VOL_CTRL5, 342 + CS530X_INOUT_VU); 300 343 default: 301 344 return -EINVAL; 302 345 } ··· 392 263 393 264 static const struct snd_kcontrol_new adc12_ctrl = 394 265 SOC_DAPM_SINGLE_VIRT("Switch", 1); 395 - 396 266 static const struct snd_kcontrol_new adc34_ctrl = 397 267 SOC_DAPM_SINGLE_VIRT("Switch", 1); 398 - 399 268 static const struct snd_kcontrol_new adc56_ctrl = 400 269 SOC_DAPM_SINGLE_VIRT("Switch", 1); 401 - 402 270 static const struct snd_kcontrol_new adc78_ctrl = 403 271 SOC_DAPM_SINGLE_VIRT("Switch", 1); 404 - 272 + static const struct snd_kcontrol_new dac12_ctrl = 273 + SOC_DAPM_SINGLE_VIRT("Switch", 1); 274 + static const struct snd_kcontrol_new dac34_ctrl = 275 + SOC_DAPM_SINGLE_VIRT("Switch", 1); 276 + static const struct snd_kcontrol_new dac56_ctrl = 277 + SOC_DAPM_SINGLE_VIRT("Switch", 1); 278 + static const struct snd_kcontrol_new dac78_ctrl = 279 + SOC_DAPM_SINGLE_VIRT("Switch", 1); 405 280 static const struct snd_kcontrol_new in_hpf_ctrl = 281 + SOC_DAPM_SINGLE_VIRT("Switch", 1); 282 + static const struct snd_kcontrol_new out_hpf_ctrl = 406 283 SOC_DAPM_SINGLE_VIRT("Switch", 1); 407 284 408 285 /* General DAPM widgets for all devices */ ··· 426 291 SND_SOC_DAPM_PRE_PMU), 427 292 SND_SOC_DAPM_ADC("ADC2", NULL, CS530X_IN_ENABLES, 1, 0), 428 293 SND_SOC_DAPM_SWITCH("ADC12 Enable", SND_SOC_NOPM, 0, 0, &adc12_ctrl), 429 - SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_IN_HPF_EN_SHIFT, 294 + SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_INOUT_HPF_EN_SHIFT, 430 295 0, &in_hpf_ctrl), 431 296 }; 432 297 ··· 550 415 ARRAY_SIZE(adc_ch3_4_routes)); 551 416 } 552 417 418 + /* DAC's Channels 1 and 2 plus generic DAC DAPM events */ 419 + static const struct snd_soc_dapm_widget cs530x_dac_ch12_dapm_widgets[] = { 420 + SND_SOC_DAPM_OUTPUT("OUT1"), 421 + SND_SOC_DAPM_OUTPUT("OUT2"), 422 + SND_SOC_DAPM_DAC_E("DAC1", NULL, CS530X_OUT_ENABLES, 0, 0, 423 + cs530x_dac_event, 424 + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | 425 + SND_SOC_DAPM_PRE_PMU), 426 + SND_SOC_DAPM_DAC("DAC2", NULL, CS530X_OUT_ENABLES, 1, 0), 427 + SND_SOC_DAPM_SWITCH("DAC12 Enable", SND_SOC_NOPM, 0, 0, &dac12_ctrl), 428 + SND_SOC_DAPM_SWITCH("OUT HPF", CS530X_OUT_FILTER, CS530X_INOUT_HPF_EN_SHIFT, 429 + 0, &out_hpf_ctrl), 430 + }; 431 + 432 + /* DAC's Channels 3 and 4 */ 433 + static const struct snd_soc_dapm_widget cs530x_dac_ch34_dapm_widgets[] = { 434 + SND_SOC_DAPM_OUTPUT("OUT3"), 435 + SND_SOC_DAPM_OUTPUT("OUT4"), 436 + SND_SOC_DAPM_DAC_E("DAC3", NULL, CS530X_OUT_ENABLES, 2, 0, 437 + cs530x_dac_event, 438 + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | 439 + SND_SOC_DAPM_PRE_PMU), 440 + SND_SOC_DAPM_DAC("DAC4", NULL, CS530X_OUT_ENABLES, 3, 0), 441 + SND_SOC_DAPM_SWITCH("DAC34 Enable", SND_SOC_NOPM, 0, 0, &dac34_ctrl), 442 + }; 443 + 444 + /* DAC's Channels 5 to 8 */ 445 + static const struct snd_soc_dapm_widget cs530x_dac_ch58_dapm_widgets[] = { 446 + SND_SOC_DAPM_OUTPUT("OUT5"), 447 + SND_SOC_DAPM_OUTPUT("OUT6"), 448 + SND_SOC_DAPM_OUTPUT("OUT7"), 449 + SND_SOC_DAPM_OUTPUT("OUT8"), 450 + SND_SOC_DAPM_DAC_E("DAC5", NULL, CS530X_OUT_ENABLES, 4, 0, 451 + cs530x_dac_event, 452 + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | 453 + SND_SOC_DAPM_PRE_PMU), 454 + SND_SOC_DAPM_DAC("DAC6", NULL, CS530X_OUT_ENABLES, 5, 0), 455 + SND_SOC_DAPM_SWITCH("DAC56 Enable", SND_SOC_NOPM, 0, 0, &dac56_ctrl), 456 + SND_SOC_DAPM_DAC_E("DAC7", NULL, CS530X_OUT_ENABLES, 6, 0, 457 + cs530x_dac_event, 458 + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | 459 + SND_SOC_DAPM_PRE_PMU), 460 + SND_SOC_DAPM_DAC("DAC8", NULL, CS530X_OUT_ENABLES, 7, 0), 461 + SND_SOC_DAPM_SWITCH("DAC78 Enable", SND_SOC_NOPM, 0, 0, &dac78_ctrl), 462 + }; 463 + 464 + static const struct snd_soc_dapm_route dac_ch1_2_routes[] = { 465 + { "DAC1", NULL, "Global Enable" }, 466 + { "DAC2", NULL, "Global Enable" }, 467 + 468 + { "DAC12 Enable", "Switch", "OUT1" }, 469 + { "DAC12 Enable", "Switch", "OUT2" }, 470 + { "DAC1", NULL, "DAC12 Enable" }, 471 + { "DAC2", NULL, "DAC12 Enable" }, 472 + { "OUT HPF", "Switch", "DAC1" }, 473 + { "OUT HPF", "Switch", "DAC2" }, 474 + 475 + { "OUT HPF", NULL, "AIF Playback" }, 476 + { "DAC1", NULL, "AIF Playback" }, 477 + { "DAC2", NULL, "AIF Playback" }, 478 + 479 + { "OUT1", NULL, "DAC1" }, 480 + { "OUT2", NULL, "DAC2" }, 481 + }; 482 + 483 + static const struct snd_soc_dapm_route dac_ch3_4_routes[] = { 484 + { "DAC3", NULL, "Global Enable" }, 485 + { "DAC4", NULL, "Global Enable" }, 486 + 487 + { "DAC34 Enable", "Switch", "OUT3" }, 488 + { "DAC34 Enable", "Switch", "OUT4" }, 489 + { "DAC3", NULL, "DAC34 Enable" }, 490 + { "DAC4", NULL, "DAC34 Enable" }, 491 + { "OUT HPF", "Switch", "DAC3" }, 492 + { "OUT HPF", "Switch", "DAC4" }, 493 + 494 + { "DAC3", NULL, "AIF Playback" }, 495 + { "DAC4", NULL, "AIF Playback" }, 496 + 497 + { "OUT3", NULL, "DAC3" }, 498 + { "OUT4", NULL, "DAC4" }, 499 + }; 500 + 501 + static const struct snd_soc_dapm_route dac_ch5_8_routes[] = { 502 + { "DAC5", NULL, "Global Enable" }, 503 + { "DAC6", NULL, "Global Enable" }, 504 + 505 + { "DAC56 Enable", "Switch", "OUT5" }, 506 + { "DAC56 Enable", "Switch", "OUT6" }, 507 + { "DAC5", NULL, "DAC56 Enable" }, 508 + { "DAC6", NULL, "DAC56 Enable" }, 509 + { "OUT HPF", "Switch", "DAC5" }, 510 + { "OUT HPF", "Switch", "DAC6" }, 511 + 512 + { "DAC5", NULL, "AIF Playback" }, 513 + { "DAC6", NULL, "AIF Playback" }, 514 + 515 + { "OUT5", NULL, "DAC5" }, 516 + { "OUT6", NULL, "DAC6" }, 517 + 518 + { "DAC7", NULL, "Global Enable" }, 519 + { "DAC8", NULL, "Global Enable" }, 520 + 521 + { "DAC78 Enable", "Switch", "OUT7" }, 522 + { "DAC78 Enable", "Switch", "OUT8" }, 523 + { "DAC7", NULL, "DAC78 Enable" }, 524 + { "DAC8", NULL, "DAC78 Enable" }, 525 + { "OUT HPF", "Switch", "DAC7" }, 526 + { "OUT HPF", "Switch", "DAC8" }, 527 + 528 + { "DAC7", NULL, "AIF Playback" }, 529 + { "DAC8", NULL, "AIF Playback" }, 530 + 531 + { "OUT7", NULL, "DAC7" }, 532 + { "OUT8", NULL, "DAC8" }, 533 + }; 534 + 535 + static void cs530x_add_12_dac_widgets(struct snd_soc_component *component) 536 + { 537 + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 538 + 539 + snd_soc_add_component_controls(component, 540 + cs530x_out_1_to_2_controls, 541 + ARRAY_SIZE(cs530x_out_1_to_2_controls)); 542 + 543 + snd_soc_dapm_new_controls(dapm, cs530x_dac_ch12_dapm_widgets, 544 + ARRAY_SIZE(cs530x_dac_ch12_dapm_widgets)); 545 + 546 + snd_soc_dapm_add_routes(dapm, dac_ch1_2_routes, 547 + ARRAY_SIZE(dac_ch1_2_routes)); 548 + } 549 + 550 + static void cs530x_add_34_dac_widgets(struct snd_soc_component *component) 551 + { 552 + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 553 + 554 + snd_soc_add_component_controls(component, 555 + cs530x_out_3_to_4_controls, 556 + ARRAY_SIZE(cs530x_out_3_to_4_controls)); 557 + 558 + snd_soc_dapm_new_controls(dapm, cs530x_dac_ch34_dapm_widgets, 559 + ARRAY_SIZE(cs530x_dac_ch34_dapm_widgets)); 560 + 561 + snd_soc_dapm_add_routes(dapm, dac_ch3_4_routes, 562 + ARRAY_SIZE(dac_ch3_4_routes)); 563 + } 564 + 553 565 static int cs530x_set_bclk(struct snd_soc_component *component, const int freq) 554 566 { 555 567 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); ··· 732 450 } 733 451 734 452 static int cs530x_set_pll_refclk(struct snd_soc_component *component, 735 - const unsigned int freq) 453 + const unsigned int freq) 736 454 { 737 455 struct cs530x_priv *priv = snd_soc_component_get_drvdata(component); 738 456 struct regmap *regmap = priv->regmap; ··· 774 492 int ret = 0, fs = params_rate(params), bclk; 775 493 unsigned int fs_val; 776 494 777 - 778 495 switch (fs) { 779 496 case 32000: 780 497 fs_val = CS530X_FS_32K; 781 498 break; 782 499 case 44100: 783 500 case 48000: 784 - fs_val = CS530X_FS_48K_44P1K; 501 + fs_val = CS530X_FS_44P1K_48K; 785 502 break; 786 503 case 88200: 787 504 case 96000: 788 - fs_val = CS530X_FS_96K_88P2K; 505 + fs_val = CS530X_FS_88P2K_96K; 789 506 break; 790 507 case 176400: 791 508 case 192000: 792 - fs_val = CS530X_FS_192K_176P4K; 509 + fs_val = CS530X_FS_176P4K_192K; 793 510 break; 794 511 case 356800: 795 512 case 384000: 796 - fs_val = CS530X_FS_384K_356P8K; 513 + fs_val = CS530X_FS_356P8K_384K; 797 514 break; 798 515 case 705600: 799 516 case 768000: 800 - fs_val = CS530X_FS_768K_705P6K; 517 + fs_val = CS530X_FS_705P6K_768K; 801 518 break; 802 519 default: 803 520 dev_err(component->dev, "Invalid sample rate %d\n", fs); 804 521 return -EINVAL; 805 522 } 806 523 807 - cs530x->fs = fs; 808 524 regmap_update_bits(regmap, CS530X_CLK_CFG_1, 809 525 CS530X_SAMPLE_RATE_MASK, fs_val); 810 526 ··· 820 540 } 821 541 822 542 if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0, 823 - CS530X_PLL_REFCLK_SRC_MASK)) { 543 + CS530X_PLL_REFCLK_SRC_MASK)) { 824 544 ret = cs530x_set_pll_refclk(component, bclk); 825 545 if (ret) 826 546 return ret; ··· 894 614 } 895 615 896 616 static int cs530x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 897 - unsigned int rx_mask, int slots, int slot_width) 617 + unsigned int rx_mask, int slots, int slot_width) 898 618 { 899 619 struct snd_soc_component *component = dai->component; 900 620 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); ··· 955 675 .name = "cs530x-dai", 956 676 .capture = { 957 677 .stream_name = "AIF Capture", 958 - .channels_min = 2, 959 - .channels_max = 8, 678 + .rates = SNDRV_PCM_RATE_KNOT, 679 + .formats = SNDRV_PCM_FMTBIT_S32_LE, 680 + }, 681 + .playback = { 682 + .stream_name = "AIF Playback", 960 683 .rates = SNDRV_PCM_RATE_KNOT, 961 684 .formats = SNDRV_PCM_FMTBIT_S32_LE, 962 685 }, ··· 969 686 }; 970 687 971 688 static int cs530x_set_pll(struct snd_soc_component *component, int pll_id, 972 - int source, unsigned int freq_in, 973 - unsigned int freq_out) 689 + int source, unsigned int freq_in, 690 + unsigned int freq_out) 974 691 { 975 692 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 976 693 struct regmap *regmap = cs530x->regmap; ··· 1014 731 ARRAY_SIZE(cs530x_gen_dapm_widgets)); 1015 732 1016 733 switch (cs530x->devtype) { 734 + case CS4282: 735 + cs530x_add_12_adc_widgets(component); 736 + cs530x_add_12_dac_widgets(component); 737 + break; 738 + case CS4302: 739 + cs530x_add_12_dac_widgets(component); 740 + break; 741 + case CS4304: 742 + cs530x_add_12_dac_widgets(component); 743 + cs530x_add_34_dac_widgets(component); 744 + 745 + num_widgets = ARRAY_SIZE(cs530x_out_sum_4ch_controls); 746 + snd_soc_add_component_controls(component, 747 + cs530x_out_sum_4ch_controls, 748 + num_widgets); 749 + break; 750 + case CS4308: 751 + cs530x_add_12_dac_widgets(component); 752 + cs530x_add_34_dac_widgets(component); 753 + 754 + num_widgets = ARRAY_SIZE(cs530x_out_5_to_8_controls); 755 + snd_soc_add_component_controls(component, 756 + cs530x_out_5_to_8_controls, 757 + num_widgets); 758 + 759 + num_widgets = ARRAY_SIZE(cs530x_out_sum_8ch_controls); 760 + snd_soc_add_component_controls(component, 761 + cs530x_out_sum_8ch_controls, 762 + num_widgets); 763 + 764 + num_widgets = ARRAY_SIZE(cs530x_dac_ch58_dapm_widgets); 765 + snd_soc_dapm_new_controls(dapm, cs530x_dac_ch58_dapm_widgets, 766 + num_widgets); 767 + 768 + snd_soc_dapm_add_routes(dapm, dac_ch5_8_routes, 769 + ARRAY_SIZE(dac_ch5_8_routes)); 770 + break; 1017 771 case CS5302: 1018 772 cs530x_add_12_adc_widgets(component); 1019 773 break; ··· 1063 743 cs530x_in_sum_4ch_controls, 1064 744 num_widgets); 1065 745 break; 1066 - 1067 746 case CS5308: 1068 747 cs530x_add_12_adc_widgets(component); 1069 748 cs530x_add_34_adc_widgets(component); ··· 1094 775 } 1095 776 1096 777 static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id, 1097 - int source, unsigned int freq, int dir) 778 + int source, unsigned int freq, int dir) 1098 779 { 1099 780 struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); 1100 781 struct regmap *regmap = cs530x->regmap; 1101 782 1102 783 switch (source) { 1103 784 case CS530X_SYSCLK_SRC_MCLK: 1104 - if (freq != 24560000 && freq != 22572000) { 1105 - dev_err(component->dev, "Invalid MCLK source rate %d\n", 1106 - freq); 785 + switch (freq) { 786 + case CS530X_SYSCLK_REF_45_1MHZ: 787 + case CS530X_SYSCLK_REF_49_1MHZ: 788 + break; 789 + default: 790 + dev_err(component->dev, "Invalid MCLK source rate %d\n", freq); 1107 791 return -EINVAL; 1108 792 } 1109 - 1110 - cs530x->mclk_rate = freq; 1111 793 break; 1112 794 case CS530X_SYSCLK_SRC_PLL: 1113 795 break; ··· 1129 809 .endianness = 1, 1130 810 }; 1131 811 1132 - const struct regmap_config cs530x_regmap = { 812 + const struct regmap_config cs530x_regmap_i2c = { 1133 813 .reg_bits = 16, 1134 814 .val_bits = 16, 1135 815 ··· 1141 821 .reg_defaults = cs530x_reg_defaults, 1142 822 .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults), 1143 823 }; 1144 - EXPORT_SYMBOL_NS_GPL(cs530x_regmap, "SND_SOC_CS530X"); 824 + EXPORT_SYMBOL_NS_GPL(cs530x_regmap_i2c, "SND_SOC_CS530X"); 825 + 826 + const struct regmap_config cs530x_regmap_spi = { 827 + .reg_bits = 16, 828 + .pad_bits = 16, 829 + .val_bits = 16, 830 + 831 + .reg_stride = 2, 832 + 833 + .reg_format_endian = REGMAP_ENDIAN_BIG, 834 + .val_format_endian = REGMAP_ENDIAN_BIG, 835 + 836 + .max_register = CS530X_MAX_REGISTER, 837 + .writeable_reg = cs530x_writeable_register, 838 + .readable_reg = cs530x_readable_register, 839 + 840 + .cache_type = REGCACHE_MAPLE, 841 + .reg_defaults = cs530x_reg_defaults, 842 + .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults), 843 + }; 844 + EXPORT_SYMBOL_NS_GPL(cs530x_regmap_spi, "SND_SOC_CS530X"); 1145 845 1146 846 static int cs530x_check_device_id(struct cs530x_priv *cs530x) 1147 847 { ··· 1177 837 if (ret) 1178 838 return dev_err_probe(dev, ret, "Can't read REV ID\n"); 1179 839 1180 - dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x\n", dev_id, rev); 1181 - 1182 840 switch (dev_id) { 841 + case CS530X_2CH_CODEC_DEV_ID: 842 + cs530x->num_dacs = 2; 843 + cs530x->num_adcs = 2; 844 + break; 845 + case CS530X_2CH_DAC_DEV_ID: 846 + cs530x->num_dacs = 2; 847 + break; 848 + case CS530X_4CH_DAC_DEV_ID: 849 + cs530x->num_dacs = 4; 850 + break; 851 + case CS530X_8CH_DAC_DEV_ID: 852 + cs530x->num_dacs = 8; 853 + break; 1183 854 case CS530X_2CH_ADC_DEV_ID: 1184 855 cs530x->num_adcs = 2; 1185 856 break; ··· 1204 853 return dev_err_probe(dev, -EINVAL, "Invalid device ID 0x%x\n", 1205 854 dev_id); 1206 855 } 856 + 857 + if (cs530x->devtype != dev_id) { 858 + dev_err(dev, "Read device ID 0x%x is not the expected devtype 0x%x\n", 859 + dev_id, cs530x->devtype); 860 + return -EINVAL; 861 + } 862 + 863 + dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x (%d in %d out)\n", dev_id, rev, 864 + cs530x->num_adcs, cs530x->num_dacs); 1207 865 1208 866 return 0; 1209 867 } ··· 1242 882 val |= CS530X_IN12_HIZ; 1243 883 1244 884 return regmap_set_bits(regmap, CS530X_IN_HIZ, val); 885 + case 0: 886 + /* No ADCs */ 887 + return 0; 1245 888 default: 1246 889 return dev_err_probe(dev, -EINVAL, 1247 890 "Invalid number of adcs %d\n", ··· 1258 895 int ret, i; 1259 896 1260 897 cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai, 1261 - sizeof(*(cs530x->dev_dai)), 1262 - GFP_KERNEL); 898 + sizeof(*(cs530x->dev_dai)), 899 + GFP_KERNEL); 1263 900 if (!cs530x->dev_dai) 1264 901 return -ENOMEM; 1265 902 ··· 1277 914 return dev_err_probe(dev, ret, "Failed to enable supplies"); 1278 915 1279 916 cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset", 1280 - GPIOD_OUT_HIGH); 917 + GPIOD_OUT_HIGH); 1281 918 if (IS_ERR(cs530x->reset_gpio)) { 1282 919 ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio), 1283 - "Reset gpio not available\n"); 920 + "Reset gpio not available\n"); 1284 921 goto err_regulator; 1285 922 } 1286 923 ··· 1307 944 if (ret) 1308 945 goto err_reset; 1309 946 1310 - cs530x->dev_dai->capture.channels_max = cs530x->num_adcs; 947 + if (cs530x->num_adcs) { 948 + cs530x->dev_dai->capture.channels_min = 2; 949 + cs530x->dev_dai->capture.channels_max = cs530x->num_adcs; 950 + } 951 + 952 + if (cs530x->num_dacs) { 953 + cs530x->dev_dai->playback.channels_min = 2; 954 + cs530x->dev_dai->playback.channels_max = cs530x->num_dacs; 955 + } 1311 956 1312 957 ret = devm_snd_soc_register_component(dev, 1313 - &soc_component_dev_cs530x, cs530x->dev_dai, 1); 958 + &soc_component_dev_cs530x, 959 + cs530x->dev_dai, 1); 1314 960 if (ret) { 1315 961 dev_err_probe(dev, ret, "Can't register cs530x component\n"); 1316 962 goto err_reset;
+60 -30
sound/soc/codecs/cs530x.h
··· 2 2 /* 3 3 * CS530x CODEC driver internal data 4 4 * 5 - * Copyright (C) 2023-2024 Cirrus Logic, Inc. and 5 + * Copyright (C) 2023-2025 Cirrus Logic, Inc. and 6 6 * Cirrus Logic International Semiconductor Ltd. 7 7 */ 8 8 ··· 15 15 #include <linux/regulator/consumer.h> 16 16 17 17 /* Devices */ 18 + #define CS530X_2CH_CODEC_DEV_ID 0x4282 19 + #define CS530X_2CH_DAC_DEV_ID 0x4302 20 + #define CS530X_4CH_DAC_DEV_ID 0x4304 21 + #define CS530X_8CH_DAC_DEV_ID 0x4308 18 22 #define CS530X_2CH_ADC_DEV_ID 0x5302 19 23 #define CS530X_4CH_ADC_DEV_ID 0x5304 20 24 #define CS530X_8CH_ADC_DEV_ID 0x5308 ··· 49 45 #define CS530X_IN_VOL_CTRL4_1 0x000009E 50 46 #define CS530X_IN_VOL_CTRL5 0x00000A0 51 47 48 + #define CS530X_OUT_ENABLES 0x00000C0 49 + #define CS530X_OUT_RAMP_SUM 0x00000C2 50 + #define CS530X_OUT_DEEMPH 0x00000C4 51 + #define CS530X_OUT_FILTER 0x00000C6 52 + #define CS530X_OUT_INV 0x00000CA 53 + #define CS530X_OUT_VOL_CTRL1_0 0x00000D0 54 + #define CS530X_OUT_VOL_CTRL1_1 0x00000D2 55 + #define CS530X_OUT_VOL_CTRL2_0 0x00000D4 56 + #define CS530X_OUT_VOL_CTRL2_1 0x00000D6 57 + #define CS530X_OUT_VOL_CTRL3_0 0x00000D8 58 + #define CS530X_OUT_VOL_CTRL3_1 0x00000DA 59 + #define CS530X_OUT_VOL_CTRL4_0 0x00000DC 60 + #define CS530X_OUT_VOL_CTRL4_1 0x00000DE 61 + #define CS530X_OUT_VOL_CTRL5 0x00000E0 62 + 52 63 #define CS530X_PAD_FN 0x0003D24 53 64 #define CS530X_PAD_LVL 0x0003D28 54 65 ··· 92 73 /* CLK_CFG_1 */ 93 74 #define CS530X_SAMPLE_RATE_MASK GENMASK(2, 0) 94 75 #define CS530X_FS_32K 0 95 - #define CS530X_FS_48K_44P1K 1 96 - #define CS530X_FS_96K_88P2K 2 97 - #define CS530X_FS_192K_176P4K 3 98 - #define CS530X_FS_384K_356P8K 4 99 - #define CS530X_FS_768K_705P6K 5 76 + #define CS530X_FS_44P1K_48K 1 77 + #define CS530X_FS_88P2K_96K 2 78 + #define CS530X_FS_176P4K_192K 3 79 + #define CS530X_FS_356P8K_384K 4 80 + #define CS530X_FS_705P6K_768K 5 100 81 101 82 /* CHIP_ENABLE */ 102 83 #define CS530X_GLOBAL_EN BIT(0) ··· 118 99 #define CS530X_TDM_EN_MASK BIT(2) 119 100 #define CS530X_ASP_FMT_I2S 0 120 101 #define CS530X_ASP_FMT_LJ 1 121 - #define CS530X_ASP_FMT_DSP_A 0x6 102 + #define CS530X_ASP_FMT_DSP_A 6 122 103 123 104 /* TDM Slots */ 124 105 #define CS530X_0_1_TDM_SLOT_MASK GENMASK(1, 0) ··· 151 132 #define CS530X_14_15_TDM_SLOT_MASK GENMASK(15, 14) 152 133 #define CS530X_14_15_TDM_SLOT_VAL 7 153 134 154 - /* IN_RAMP_SUM */ 135 + /* IN_RAMP_SUM and OUT_RAMP_SUM */ 155 136 #define CS530X_RAMP_RATE_INC_SHIFT 0 156 137 #define CS530X_RAMP_RATE_DEC_SHIFT 4 157 - #define CS530X_IN_SUM_MODE_SHIFT 13 138 + #define CS530X_INOUT_SUM_MODE_SHIFT 13 158 139 159 - /* IN_FILTER */ 160 - #define CS530X_IN_FILTER_SHIFT 8 161 - #define CS530X_IN_HPF_EN_SHIFT 12 140 + /* IN_FILTER and OUT_FILTER */ 141 + #define CS530X_INOUT_FILTER_SHIFT 8 142 + #define CS530X_INOUT_HPF_EN_SHIFT 12 162 143 163 144 /* IN_HIZ */ 164 145 #define CS530X_IN12_HIZ BIT(0) ··· 166 147 #define CS530X_IN56_HIZ BIT(2) 167 148 #define CS530X_IN78_HIZ BIT(3) 168 149 169 - /* IN_INV */ 170 - #define CS530X_IN1_INV_SHIFT 0 171 - #define CS530X_IN2_INV_SHIFT 1 172 - #define CS530X_IN3_INV_SHIFT 2 173 - #define CS530X_IN4_INV_SHIFT 3 174 - #define CS530X_IN5_INV_SHIFT 4 175 - #define CS530X_IN6_INV_SHIFT 5 176 - #define CS530X_IN7_INV_SHIFT 6 177 - #define CS530X_IN8_INV_SHIFT 7 150 + /* IN_INV and OUT_INV */ 151 + #define CS530X_INOUT1_INV_SHIFT 0 152 + #define CS530X_INOUT2_INV_SHIFT 1 153 + #define CS530X_INOUT3_INV_SHIFT 2 154 + #define CS530X_INOUT4_INV_SHIFT 3 155 + #define CS530X_INOUT5_INV_SHIFT 4 156 + #define CS530X_INOUT6_INV_SHIFT 5 157 + #define CS530X_INOUT7_INV_SHIFT 6 158 + #define CS530X_INOUT8_INV_SHIFT 7 178 159 179 - /* IN_VOL_CTLy_z */ 180 - #define CS530X_IN_MUTE BIT(15) 160 + /* IN_VOL_CTLy_z and OUT_VOL_CTLy_z */ 161 + #define CS530X_INOUT_MUTE BIT(15) 181 162 182 163 /* IN_VOL_CTL5 */ 183 164 #define CS530X_IN_VU BIT(0) ··· 197 178 #define CS530X_CONFIG3_LVL BIT(7) 198 179 #define CS530X_CONFIG4_LVL BIT(8) 199 180 #define CS530X_CONFIG5_LVL BIT(9) 181 + /* IN_VOL_CTL5 and OUT_VOL_CTL5 */ 182 + #define CS530X_INOUT_VU BIT(0) 183 + 184 + /* MCLK Reference Source Frequency */ 185 + /* 41KHz related */ 186 + #define CS530X_SYSCLK_REF_45_1MHZ 45158400 187 + /* 48KHz related */ 188 + #define CS530X_SYSCLK_REF_49_1MHZ 49152000 200 189 201 190 /* System Clock Source */ 202 191 #define CS530X_SYSCLK_SRC_MCLK 0 ··· 217 190 #define CS530X_NUM_SUPPLIES 2 218 191 219 192 enum cs530x_type { 220 - CS5302, 221 - CS5304, 222 - CS5308, 193 + CS4282 = CS530X_2CH_CODEC_DEV_ID, 194 + CS4302 = CS530X_2CH_DAC_DEV_ID, 195 + CS4304 = CS530X_4CH_DAC_DEV_ID, 196 + CS4308 = CS530X_8CH_DAC_DEV_ID, 197 + CS5302 = CS530X_2CH_ADC_DEV_ID, 198 + CS5304 = CS530X_4CH_ADC_DEV_ID, 199 + CS5308 = CS530X_8CH_ADC_DEV_ID, 223 200 }; 224 201 225 202 /* codec private data */ ··· 238 207 239 208 struct regulator_bulk_data supplies[CS530X_NUM_SUPPLIES]; 240 209 241 - unsigned int mclk_rate; 242 - 243 210 int tdm_width; 244 211 int tdm_slots; 245 - int fs; 246 212 int adc_pairs_count; 213 + int dac_pairs_count; 247 214 248 215 struct gpio_desc *reset_gpio; 249 216 }; 250 217 251 - extern const struct regmap_config cs530x_regmap; 218 + extern const struct regmap_config cs530x_regmap_i2c; 219 + extern const struct regmap_config cs530x_regmap_spi; 252 220 int cs530x_probe(struct cs530x_priv *cs530x); 253 221 254 222 #endif