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

ASoC: cs4234: Add support for Cirrus Logic CS4234 codec

The CS4234 is a highly versatile CODEC that combines 4 channels of
high performance analog to digital conversion, 4 channels of high
performance digital to analog conversion for audio, and 1 channel of
digital to analog conversion to provide a nondelayed audio reference
signal to an external Class H tracking power supply.

DAC5 is only supported as a 5th audio channel. Tracking Power Supply
mode is not currently supported by the driver.

In DSP_A mode the slots for DAC1-4 and optionally DAC5 can be set.
The codec always claims 4 slots for DAC1-4 and these must be in the
same nibble of the mask. The codec has a fixed mapping for ADC slots.

In I2S/LJ modes the codec has a fixed mapping for DAC1-4 and ADC1-4.
DAC5 is not available in these modes.

The MCLK source must be preset to a valid frequency before probe()
because it must be running all the time the codec is out of reset.

The VA_SEL bit will be set automatically to 3.3v or 5v during probe()
based on the reported voltage of the regulator supplying VA.

Signed-off-by: Lucas Tanure <tanureal@opensource.cirrus.com>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20200928111821.26967-2-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Lucas Tanure and committed by
Mark Brown
d4edae9c 5ebba5e7

+1213
+6
sound/soc/codecs/Kconfig
··· 64 64 imply SND_SOC_CS42L52 65 65 imply SND_SOC_CS42L56 66 66 imply SND_SOC_CS42L73 67 + imply SND_SOC_CS4234 67 68 imply SND_SOC_CS4265 68 69 imply SND_SOC_CS4270 69 70 imply SND_SOC_CS4271_I2C ··· 592 591 config SND_SOC_CS42L73 593 592 tristate "Cirrus Logic CS42L73 CODEC" 594 593 depends on I2C 594 + 595 + config SND_SOC_CS4234 596 + tristate "Cirrus Logic CS4234 CODEC" 597 + depends on I2C 598 + select REGMAP_I2C 595 599 596 600 config SND_SOC_CS4265 597 601 tristate "Cirrus Logic CS4265 CODEC"
+2
sound/soc/codecs/Makefile
··· 57 57 snd-soc-cs42l52-objs := cs42l52.o 58 58 snd-soc-cs42l56-objs := cs42l56.o 59 59 snd-soc-cs42l73-objs := cs42l73.o 60 + snd-soc-cs4234-objs := cs4234.o 60 61 snd-soc-cs4265-objs := cs4265.o 61 62 snd-soc-cs4270-objs := cs4270.o 62 63 snd-soc-cs4271-objs := cs4271.o ··· 365 364 obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o 366 365 obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o 367 366 obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o 367 + obj-$(CONFIG_SND_SOC_CS4234) += snd-soc-cs4234.o 368 368 obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o 369 369 obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o 370 370 obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
+918
sound/soc/codecs/cs4234.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // cs4234.c -- ALSA SoC CS4234 driver 3 + // 4 + // Copyright (C) 2020 Cirrus Logic, Inc. and 5 + // Cirrus Logic International Semiconductor Ltd. 6 + // 7 + 8 + #include <linux/clk.h> 9 + #include <linux/completion.h> 10 + #include <linux/delay.h> 11 + #include <linux/gpio/consumer.h> 12 + #include <linux/i2c.h> 13 + #include <linux/jiffies.h> 14 + #include <linux/mod_devicetable.h> 15 + #include <linux/module.h> 16 + #include <sound/pcm.h> 17 + #include <sound/pcm_params.h> 18 + #include <linux/pm_runtime.h> 19 + #include <linux/regmap.h> 20 + #include <linux/regulator/consumer.h> 21 + #include <linux/slab.h> 22 + #include <sound/soc.h> 23 + #include <sound/tlv.h> 24 + #include <linux/workqueue.h> 25 + 26 + #include "cs4234.h" 27 + 28 + struct cs4234 { 29 + struct device *dev; 30 + struct regmap *regmap; 31 + struct gpio_desc *reset_gpio; 32 + struct regulator_bulk_data core_supplies[2]; 33 + int num_core_supplies; 34 + struct completion vq_ramp_complete; 35 + struct delayed_work vq_ramp_delay; 36 + struct clk *mclk; 37 + unsigned long mclk_rate; 38 + unsigned long lrclk_rate; 39 + unsigned int format; 40 + struct snd_ratnum rate_dividers[2]; 41 + struct snd_pcm_hw_constraint_ratnums rate_constraint; 42 + }; 43 + 44 + /* -89.92dB to +6.02dB with step of 0.38dB */ 45 + static const DECLARE_TLV_DB_SCALE(dac_tlv, -8992, 38, 0); 46 + 47 + static const char * const cs4234_dac14_delay_text[] = { 48 + "0us", "100us", "150us", "200us", "225us", "250us", "275us", "300us", 49 + "325us", "350us", "375us", "400us", "425us", "450us", "475us", "500us", 50 + }; 51 + static SOC_ENUM_SINGLE_DECL(cs4234_dac14_group_delay, CS4234_TPS_CTRL, 52 + CS4234_GRP_DELAY_SHIFT, cs4234_dac14_delay_text); 53 + 54 + static const char * const cs4234_noise_gate_text[] = { 55 + "72dB", "78dB", "84dB", "90dB", "96dB", "102dB", "138dB", "Disabled", 56 + }; 57 + static SOC_ENUM_SINGLE_DECL(cs4234_ll_noise_gate, CS4234_LOW_LAT_CTRL1, 58 + CS4234_LL_NG_SHIFT, cs4234_noise_gate_text); 59 + static SOC_ENUM_SINGLE_DECL(cs4234_dac14_noise_gate, CS4234_DAC_CTRL1, 60 + CS4234_DAC14_NG_SHIFT, cs4234_noise_gate_text); 61 + static SOC_ENUM_SINGLE_DECL(cs4234_dac5_noise_gate, CS4234_DAC_CTRL2, 62 + CS4234_DAC5_NG_SHIFT, cs4234_noise_gate_text); 63 + 64 + static const char * const cs4234_dac5_config_fltr_sel_text[] = { 65 + "Interpolation Filter", "Sample and Hold" 66 + }; 67 + static SOC_ENUM_SINGLE_DECL(cs4234_dac5_config_fltr_sel, CS4234_DAC_CTRL1, 68 + CS4234_DAC5_CFG_FLTR_SHIFT, 69 + cs4234_dac5_config_fltr_sel_text); 70 + 71 + static const char * const cs4234_mute_delay_text[] = { 72 + "1x", "4x", "16x", "64x", 73 + }; 74 + static SOC_ENUM_SINGLE_DECL(cs4234_mute_delay, CS4234_VOLUME_MODE, 75 + CS4234_MUTE_DELAY_SHIFT, cs4234_mute_delay_text); 76 + 77 + static const char * const cs4234_minmax_delay_text[] = { 78 + "1x", "2x", "4x", "8x", "16x", "32x", "64x", "128x", 79 + }; 80 + static SOC_ENUM_SINGLE_DECL(cs4234_min_delay, CS4234_VOLUME_MODE, 81 + CS4234_MIN_DELAY_SHIFT, cs4234_minmax_delay_text); 82 + static SOC_ENUM_SINGLE_DECL(cs4234_max_delay, CS4234_VOLUME_MODE, 83 + CS4234_MAX_DELAY_SHIFT, cs4234_minmax_delay_text); 84 + 85 + static int cs4234_dac14_grp_delay_put(struct snd_kcontrol *kctrl, 86 + struct snd_ctl_elem_value *uctrl) 87 + { 88 + struct snd_soc_component *component = snd_soc_kcontrol_component(kctrl); 89 + struct cs4234 *cs4234 = snd_soc_component_get_drvdata(component); 90 + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 91 + unsigned int val = 0; 92 + int ret = 0; 93 + 94 + snd_soc_dapm_mutex_lock(dapm); 95 + 96 + regmap_read(cs4234->regmap, CS4234_ADC_CTRL2, &val); 97 + if ((val & 0x0F) != 0x0F) { // are all the ADCs powerdown 98 + ret = -EBUSY; 99 + dev_err(component->dev, "Can't change group delay while ADC are ON\n"); 100 + goto exit; 101 + } 102 + 103 + regmap_read(cs4234->regmap, CS4234_DAC_CTRL4, &val); 104 + if ((val & 0x1F) != 0x1F) { // are all the DACs powerdown 105 + ret = -EBUSY; 106 + dev_err(component->dev, "Can't change group delay while DAC are ON\n"); 107 + goto exit; 108 + } 109 + 110 + ret = snd_soc_put_enum_double(kctrl, uctrl); 111 + exit: 112 + snd_soc_dapm_mutex_unlock(dapm); 113 + 114 + return ret; 115 + } 116 + 117 + static void cs4234_vq_ramp_done(struct work_struct *work) 118 + { 119 + struct delayed_work *dw = to_delayed_work(work); 120 + struct cs4234 *cs4234 = container_of(dw, struct cs4234, vq_ramp_delay); 121 + 122 + complete_all(&cs4234->vq_ramp_complete); 123 + } 124 + 125 + static int cs4234_set_bias_level(struct snd_soc_component *component, 126 + enum snd_soc_bias_level level) 127 + { 128 + struct cs4234 *cs4234 = snd_soc_component_get_drvdata(component); 129 + 130 + switch (level) { 131 + case SND_SOC_BIAS_PREPARE: 132 + switch (snd_soc_component_get_bias_level(component)) { 133 + case SND_SOC_BIAS_STANDBY: 134 + wait_for_completion(&cs4234->vq_ramp_complete); 135 + break; 136 + default: 137 + break; 138 + } 139 + break; 140 + default: 141 + break; 142 + } 143 + 144 + return 0; 145 + } 146 + 147 + static const struct snd_soc_dapm_widget cs4234_dapm_widgets[] = { 148 + SND_SOC_DAPM_AIF_IN("SDRX1", NULL, 0, SND_SOC_NOPM, 0, 0), 149 + SND_SOC_DAPM_AIF_IN("SDRX2", NULL, 1, SND_SOC_NOPM, 0, 0), 150 + SND_SOC_DAPM_AIF_IN("SDRX3", NULL, 2, SND_SOC_NOPM, 0, 0), 151 + SND_SOC_DAPM_AIF_IN("SDRX4", NULL, 3, SND_SOC_NOPM, 0, 0), 152 + SND_SOC_DAPM_AIF_IN("SDRX5", NULL, 4, SND_SOC_NOPM, 0, 0), 153 + 154 + SND_SOC_DAPM_DAC("DAC1", NULL, CS4234_DAC_CTRL4, CS4234_PDN_DAC1_SHIFT, 1), 155 + SND_SOC_DAPM_DAC("DAC2", NULL, CS4234_DAC_CTRL4, CS4234_PDN_DAC2_SHIFT, 1), 156 + SND_SOC_DAPM_DAC("DAC3", NULL, CS4234_DAC_CTRL4, CS4234_PDN_DAC3_SHIFT, 1), 157 + SND_SOC_DAPM_DAC("DAC4", NULL, CS4234_DAC_CTRL4, CS4234_PDN_DAC4_SHIFT, 1), 158 + SND_SOC_DAPM_DAC("DAC5", NULL, CS4234_DAC_CTRL4, CS4234_PDN_DAC5_SHIFT, 1), 159 + 160 + SND_SOC_DAPM_OUTPUT("AOUT1"), 161 + SND_SOC_DAPM_OUTPUT("AOUT2"), 162 + SND_SOC_DAPM_OUTPUT("AOUT3"), 163 + SND_SOC_DAPM_OUTPUT("AOUT4"), 164 + SND_SOC_DAPM_OUTPUT("AOUT5"), 165 + 166 + SND_SOC_DAPM_INPUT("AIN1"), 167 + SND_SOC_DAPM_INPUT("AIN2"), 168 + SND_SOC_DAPM_INPUT("AIN3"), 169 + SND_SOC_DAPM_INPUT("AIN4"), 170 + 171 + SND_SOC_DAPM_ADC("ADC1", NULL, CS4234_ADC_CTRL2, CS4234_PDN_ADC1_SHIFT, 1), 172 + SND_SOC_DAPM_ADC("ADC2", NULL, CS4234_ADC_CTRL2, CS4234_PDN_ADC2_SHIFT, 1), 173 + SND_SOC_DAPM_ADC("ADC3", NULL, CS4234_ADC_CTRL2, CS4234_PDN_ADC3_SHIFT, 1), 174 + SND_SOC_DAPM_ADC("ADC4", NULL, CS4234_ADC_CTRL2, CS4234_PDN_ADC4_SHIFT, 1), 175 + 176 + SND_SOC_DAPM_AIF_OUT("SDTX1", NULL, 0, SND_SOC_NOPM, 0, 1), 177 + SND_SOC_DAPM_AIF_OUT("SDTX2", NULL, 1, SND_SOC_NOPM, 0, 1), 178 + SND_SOC_DAPM_AIF_OUT("SDTX3", NULL, 2, SND_SOC_NOPM, 0, 1), 179 + SND_SOC_DAPM_AIF_OUT("SDTX4", NULL, 3, SND_SOC_NOPM, 0, 1), 180 + }; 181 + 182 + static const struct snd_soc_dapm_route cs4234_dapm_routes[] = { 183 + /* Playback */ 184 + { "AOUT1", NULL, "DAC1" }, 185 + { "AOUT2", NULL, "DAC2" }, 186 + { "AOUT3", NULL, "DAC3" }, 187 + { "AOUT4", NULL, "DAC4" }, 188 + { "AOUT5", NULL, "DAC5" }, 189 + 190 + { "DAC1", NULL, "SDRX1" }, 191 + { "DAC2", NULL, "SDRX2" }, 192 + { "DAC3", NULL, "SDRX3" }, 193 + { "DAC4", NULL, "SDRX4" }, 194 + { "DAC5", NULL, "SDRX5" }, 195 + 196 + { "SDRX1", NULL, "Playback" }, 197 + { "SDRX2", NULL, "Playback" }, 198 + { "SDRX3", NULL, "Playback" }, 199 + { "SDRX4", NULL, "Playback" }, 200 + { "SDRX5", NULL, "Playback" }, 201 + 202 + /* Capture */ 203 + { "ADC1", NULL, "AIN1" }, 204 + { "ADC2", NULL, "AIN2" }, 205 + { "ADC3", NULL, "AIN3" }, 206 + { "ADC4", NULL, "AIN4" }, 207 + 208 + { "SDTX1", NULL, "ADC1" }, 209 + { "SDTX2", NULL, "ADC2" }, 210 + { "SDTX3", NULL, "ADC3" }, 211 + { "SDTX4", NULL, "ADC4" }, 212 + 213 + { "Capture", NULL, "SDTX1" }, 214 + { "Capture", NULL, "SDTX2" }, 215 + { "Capture", NULL, "SDTX3" }, 216 + { "Capture", NULL, "SDTX4" }, 217 + }; 218 + 219 + static const struct snd_kcontrol_new cs4234_snd_controls[] = { 220 + SOC_SINGLE_TLV("Master Volume", CS4234_MASTER_VOL, 0, 0xff, 1, dac_tlv), 221 + SOC_SINGLE_TLV("DAC1 Volume", CS4234_DAC1_VOL, 0, 0xff, 1, dac_tlv), 222 + SOC_SINGLE_TLV("DAC2 Volume", CS4234_DAC2_VOL, 0, 0xff, 1, dac_tlv), 223 + SOC_SINGLE_TLV("DAC3 Volume", CS4234_DAC3_VOL, 0, 0xff, 1, dac_tlv), 224 + SOC_SINGLE_TLV("DAC4 Volume", CS4234_DAC4_VOL, 0, 0xff, 1, dac_tlv), 225 + SOC_SINGLE_TLV("DAC5 Volume", CS4234_DAC5_VOL, 0, 0xff, 1, dac_tlv), 226 + 227 + SOC_SINGLE("DAC5 Soft Ramp Switch", CS4234_DAC_CTRL3, CS4234_DAC5_ATT_SHIFT, 1, 1), 228 + SOC_SINGLE("DAC1-4 Soft Ramp Switch", CS4234_DAC_CTRL3, CS4234_DAC14_ATT_SHIFT, 1, 1), 229 + 230 + SOC_SINGLE("ADC HPF Switch", CS4234_ADC_CTRL1, CS4234_ENA_HPF_SHIFT, 1, 0), 231 + 232 + SOC_ENUM_EXT("DAC1-4 Group Delay", cs4234_dac14_group_delay, 233 + snd_soc_get_enum_double, cs4234_dac14_grp_delay_put), 234 + 235 + SOC_SINGLE("ADC1 Invert Switch", CS4234_ADC_CTRL1, CS4234_INV_ADC1_SHIFT, 1, 0), 236 + SOC_SINGLE("ADC2 Invert Switch", CS4234_ADC_CTRL1, CS4234_INV_ADC2_SHIFT, 1, 0), 237 + SOC_SINGLE("ADC3 Invert Switch", CS4234_ADC_CTRL1, CS4234_INV_ADC3_SHIFT, 1, 0), 238 + SOC_SINGLE("ADC4 Invert Switch", CS4234_ADC_CTRL1, CS4234_INV_ADC4_SHIFT, 1, 0), 239 + 240 + SOC_SINGLE("DAC1 Invert Switch", CS4234_DAC_CTRL2, CS4234_INV_DAC1_SHIFT, 1, 0), 241 + SOC_SINGLE("DAC2 Invert Switch", CS4234_DAC_CTRL2, CS4234_INV_DAC2_SHIFT, 1, 0), 242 + SOC_SINGLE("DAC3 Invert Switch", CS4234_DAC_CTRL2, CS4234_INV_DAC3_SHIFT, 1, 0), 243 + SOC_SINGLE("DAC4 Invert Switch", CS4234_DAC_CTRL2, CS4234_INV_DAC4_SHIFT, 1, 0), 244 + SOC_SINGLE("DAC5 Invert Switch", CS4234_DAC_CTRL2, CS4234_INV_DAC5_SHIFT, 1, 0), 245 + 246 + SOC_SINGLE("ADC1 Switch", CS4234_ADC_CTRL2, CS4234_MUTE_ADC1_SHIFT, 1, 1), 247 + SOC_SINGLE("ADC2 Switch", CS4234_ADC_CTRL2, CS4234_MUTE_ADC2_SHIFT, 1, 1), 248 + SOC_SINGLE("ADC3 Switch", CS4234_ADC_CTRL2, CS4234_MUTE_ADC3_SHIFT, 1, 1), 249 + SOC_SINGLE("ADC4 Switch", CS4234_ADC_CTRL2, CS4234_MUTE_ADC4_SHIFT, 1, 1), 250 + 251 + SOC_SINGLE("DAC1 Switch", CS4234_DAC_CTRL3, CS4234_MUTE_DAC1_SHIFT, 1, 1), 252 + SOC_SINGLE("DAC2 Switch", CS4234_DAC_CTRL3, CS4234_MUTE_DAC2_SHIFT, 1, 1), 253 + SOC_SINGLE("DAC3 Switch", CS4234_DAC_CTRL3, CS4234_MUTE_DAC3_SHIFT, 1, 1), 254 + SOC_SINGLE("DAC4 Switch", CS4234_DAC_CTRL3, CS4234_MUTE_DAC4_SHIFT, 1, 1), 255 + SOC_SINGLE("DAC5 Switch", CS4234_DAC_CTRL3, CS4234_MUTE_DAC5_SHIFT, 1, 1), 256 + SOC_SINGLE("Low-latency Switch", CS4234_DAC_CTRL3, CS4234_MUTE_LL_SHIFT, 1, 1), 257 + 258 + SOC_SINGLE("DAC1 Low-latency Invert Switch", CS4234_LOW_LAT_CTRL1, 259 + CS4234_INV_LL1_SHIFT, 1, 0), 260 + SOC_SINGLE("DAC2 Low-latency Invert Switch", CS4234_LOW_LAT_CTRL1, 261 + CS4234_INV_LL2_SHIFT, 1, 0), 262 + SOC_SINGLE("DAC3 Low-latency Invert Switch", CS4234_LOW_LAT_CTRL1, 263 + CS4234_INV_LL3_SHIFT, 1, 0), 264 + SOC_SINGLE("DAC4 Low-latency Invert Switch", CS4234_LOW_LAT_CTRL1, 265 + CS4234_INV_LL4_SHIFT, 1, 0), 266 + 267 + SOC_ENUM("Low-latency Noise Gate", cs4234_ll_noise_gate), 268 + SOC_ENUM("DAC1-4 Noise Gate", cs4234_dac14_noise_gate), 269 + SOC_ENUM("DAC5 Noise Gate", cs4234_dac5_noise_gate), 270 + 271 + SOC_SINGLE("DAC1-4 De-emphasis Switch", CS4234_DAC_CTRL1, 272 + CS4234_DAC14_DE_SHIFT, 1, 0), 273 + SOC_SINGLE("DAC5 De-emphasis Switch", CS4234_DAC_CTRL1, 274 + CS4234_DAC5_DE_SHIFT, 1, 0), 275 + 276 + SOC_SINGLE("DAC5 Master Controlled Switch", CS4234_DAC_CTRL1, 277 + CS4234_DAC5_MVC_SHIFT, 1, 0), 278 + 279 + SOC_ENUM("DAC5 Filter", cs4234_dac5_config_fltr_sel), 280 + 281 + SOC_ENUM("Mute Delay", cs4234_mute_delay), 282 + SOC_ENUM("Ramp Minimum Delay", cs4234_min_delay), 283 + SOC_ENUM("Ramp Maximum Delay", cs4234_max_delay), 284 + 285 + }; 286 + 287 + static int cs4234_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int format) 288 + { 289 + struct snd_soc_component *component = codec_dai->component; 290 + struct cs4234 *cs4234 = snd_soc_component_get_drvdata(component); 291 + unsigned int sp_ctrl = 0; 292 + 293 + cs4234->format = format & SND_SOC_DAIFMT_FORMAT_MASK; 294 + switch (cs4234->format) { 295 + case SND_SOC_DAIFMT_LEFT_J: 296 + sp_ctrl |= CS4234_LEFT_J << CS4234_SP_FORMAT_SHIFT; 297 + break; 298 + case SND_SOC_DAIFMT_I2S: 299 + sp_ctrl |= CS4234_I2S << CS4234_SP_FORMAT_SHIFT; 300 + break; 301 + case SND_SOC_DAIFMT_DSP_A: /* TDM mode in datasheet */ 302 + sp_ctrl |= CS4234_TDM << CS4234_SP_FORMAT_SHIFT; 303 + break; 304 + default: 305 + dev_err(component->dev, "Unsupported dai format\n"); 306 + return -EINVAL; 307 + } 308 + 309 + switch (format & SND_SOC_DAIFMT_MASTER_MASK) { 310 + case SND_SOC_DAIFMT_CBS_CFS: 311 + break; 312 + case SND_SOC_DAIFMT_CBM_CFM: 313 + if (cs4234->format == SND_SOC_DAIFMT_DSP_A) { 314 + dev_err(component->dev, "Unsupported DSP A format in master mode\n"); 315 + return -EINVAL; 316 + } 317 + sp_ctrl |= CS4234_MST_SLV_MASK; 318 + break; 319 + default: 320 + dev_err(component->dev, "Unsupported master/slave mode\n"); 321 + return -EINVAL; 322 + } 323 + 324 + switch (format & SND_SOC_DAIFMT_INV_MASK) { 325 + case SND_SOC_DAIFMT_NB_NF: 326 + break; 327 + case SND_SOC_DAIFMT_IB_NF: 328 + sp_ctrl |= CS4234_INVT_SCLK_MASK; 329 + break; 330 + default: 331 + dev_err(component->dev, "Unsupported inverted clock setting\n"); 332 + return -EINVAL; 333 + } 334 + 335 + regmap_update_bits(cs4234->regmap, CS4234_SP_CTRL, 336 + CS4234_SP_FORMAT_MASK | CS4234_MST_SLV_MASK | CS4234_INVT_SCLK_MASK, 337 + sp_ctrl); 338 + 339 + return 0; 340 + } 341 + 342 + static int cs4234_dai_hw_params(struct snd_pcm_substream *sub, 343 + struct snd_pcm_hw_params *params, 344 + struct snd_soc_dai *dai) 345 + { 346 + struct snd_soc_component *component = dai->component; 347 + struct cs4234 *cs4234 = snd_soc_component_get_drvdata(component); 348 + unsigned int mclk_mult, double_speed = 0; 349 + int ret = 0, rate_ad, sample_width; 350 + 351 + cs4234->lrclk_rate = params_rate(params); 352 + mclk_mult = cs4234->mclk_rate / cs4234->lrclk_rate; 353 + 354 + if (cs4234->lrclk_rate > 48000) { 355 + double_speed = 1; 356 + mclk_mult *= 2; 357 + } 358 + 359 + switch (mclk_mult) { 360 + case 256: 361 + case 384: 362 + case 512: 363 + regmap_update_bits(cs4234->regmap, CS4234_CLOCK_SP, 364 + CS4234_SPEED_MODE_MASK, 365 + double_speed << CS4234_SPEED_MODE_SHIFT); 366 + regmap_update_bits(cs4234->regmap, CS4234_CLOCK_SP, 367 + CS4234_MCLK_RATE_MASK, 368 + ((mclk_mult / 128) - 2) << CS4234_MCLK_RATE_SHIFT); 369 + break; 370 + default: 371 + dev_err(component->dev, "Unsupported mclk/lrclk rate\n"); 372 + return -EINVAL; 373 + } 374 + 375 + switch (cs4234->lrclk_rate) { 376 + case 48000: 377 + case 96000: 378 + rate_ad = CS4234_48K; 379 + break; 380 + case 44100: 381 + case 88200: 382 + rate_ad = CS4234_44K1; 383 + break; 384 + case 32000: 385 + case 64000: 386 + rate_ad = CS4234_32K; 387 + break; 388 + default: 389 + dev_err(component->dev, "Unsupported LR clock\n"); 390 + return -EINVAL; 391 + } 392 + regmap_update_bits(cs4234->regmap, CS4234_CLOCK_SP, CS4234_BASE_RATE_MASK, 393 + rate_ad << CS4234_BASE_RATE_SHIFT); 394 + 395 + sample_width = params_width(params); 396 + switch (sample_width) { 397 + case 16: 398 + sample_width = 0; 399 + break; 400 + case 18: 401 + sample_width = 1; 402 + break; 403 + case 20: 404 + sample_width = 2; 405 + break; 406 + case 24: 407 + sample_width = 3; 408 + break; 409 + default: 410 + dev_err(component->dev, "Unsupported sample width\n"); 411 + return -EINVAL; 412 + } 413 + if (sub->stream == SNDRV_PCM_STREAM_CAPTURE) 414 + regmap_update_bits(cs4234->regmap, CS4234_SAMPLE_WIDTH, 415 + CS4234_SDOUTX_SW_MASK, 416 + sample_width << CS4234_SDOUTX_SW_SHIFT); 417 + else 418 + regmap_update_bits(cs4234->regmap, CS4234_SAMPLE_WIDTH, 419 + CS4234_INPUT_SW_MASK | CS4234_LOW_LAT_SW_MASK | CS4234_DAC5_SW_MASK, 420 + sample_width << CS4234_INPUT_SW_SHIFT | 421 + sample_width << CS4234_LOW_LAT_SW_SHIFT | 422 + sample_width << CS4234_DAC5_SW_SHIFT); 423 + 424 + return ret; 425 + } 426 + 427 + /* Scale MCLK rate by 64 to avoid overflow in the ratnum calculation */ 428 + #define CS4234_MCLK_SCALE 64 429 + 430 + static const struct snd_ratnum cs4234_dividers[] = { 431 + { 432 + .num = 0, 433 + .den_min = 256 / CS4234_MCLK_SCALE, 434 + .den_max = 512 / CS4234_MCLK_SCALE, 435 + .den_step = 128 / CS4234_MCLK_SCALE, 436 + }, 437 + { 438 + .num = 0, 439 + .den_min = 128 / CS4234_MCLK_SCALE, 440 + .den_max = 192 / CS4234_MCLK_SCALE, 441 + .den_step = 64 / CS4234_MCLK_SCALE, 442 + }, 443 + }; 444 + 445 + static int cs4234_dai_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) 446 + { 447 + struct cs4234 *cs4234 = rule->private; 448 + int mclk = cs4234->mclk_rate; 449 + struct snd_interval ranges[] = { 450 + { /* Single Speed Mode */ 451 + .min = mclk / clamp(mclk / 30000, 256, 512), 452 + .max = mclk / clamp(mclk / 50000, 256, 512), 453 + }, 454 + { /* Double Speed Mode */ 455 + .min = mclk / clamp(mclk / 60000, 128, 256), 456 + .max = mclk / clamp(mclk / 100000, 128, 256), 457 + }, 458 + }; 459 + 460 + return snd_interval_ranges(hw_param_interval(params, rule->var), 461 + ARRAY_SIZE(ranges), ranges, 0); 462 + } 463 + 464 + static int cs4234_dai_startup(struct snd_pcm_substream *sub, struct snd_soc_dai *dai) 465 + { 466 + struct snd_soc_component *comp = dai->component; 467 + struct cs4234 *cs4234 = snd_soc_component_get_drvdata(comp); 468 + int i, ret; 469 + 470 + switch (cs4234->format) { 471 + case SND_SOC_DAIFMT_LEFT_J: 472 + case SND_SOC_DAIFMT_I2S: 473 + cs4234->rate_constraint.nrats = 2; 474 + 475 + /* 476 + * Playback only supports 24-bit samples in these modes. 477 + * Note: SNDRV_PCM_HW_PARAM_SAMPLE_BITS constrains the physical 478 + * width, which we don't care about, so constrain the format. 479 + */ 480 + if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) { 481 + ret = snd_pcm_hw_constraint_mask64( 482 + sub->runtime, 483 + SNDRV_PCM_HW_PARAM_FORMAT, 484 + SNDRV_PCM_FMTBIT_S24_LE | 485 + SNDRV_PCM_FMTBIT_S24_3LE); 486 + if (ret < 0) 487 + return ret; 488 + 489 + ret = snd_pcm_hw_constraint_minmax(sub->runtime, 490 + SNDRV_PCM_HW_PARAM_CHANNELS, 491 + 1, 4); 492 + if (ret < 0) 493 + return ret; 494 + } 495 + 496 + break; 497 + case SND_SOC_DAIFMT_DSP_A: 498 + cs4234->rate_constraint.nrats = 1; 499 + break; 500 + default: 501 + dev_err(comp->dev, "Startup unsupported DAI format\n"); 502 + return -EINVAL; 503 + } 504 + 505 + for (i = 0; i < cs4234->rate_constraint.nrats; i++) 506 + cs4234->rate_dividers[i].num = cs4234->mclk_rate / CS4234_MCLK_SCALE; 507 + 508 + ret = snd_pcm_hw_constraint_ratnums(sub->runtime, 0, 509 + SNDRV_PCM_HW_PARAM_RATE, 510 + &cs4234->rate_constraint); 511 + if (ret < 0) 512 + return ret; 513 + 514 + /* 515 + * MCLK/rate may be a valid ratio but out-of-spec (e.g. 24576000/64000) 516 + * so this rule limits the range of sample rate for given MCLK. 517 + */ 518 + return snd_pcm_hw_rule_add(sub->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 519 + cs4234_dai_rule_rate, cs4234, -1); 520 + } 521 + 522 + static int cs4234_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 523 + unsigned int rx_mask, int slots, int slot_width) 524 + { 525 + struct snd_soc_component *component = dai->component; 526 + struct cs4234 *cs4234 = snd_soc_component_get_drvdata(component); 527 + unsigned int slot_offset, dac5_slot, dac5_mask_group; 528 + uint8_t dac5_masks[4]; 529 + 530 + if (slot_width != 32) { 531 + dev_err(component->dev, "Unsupported slot width\n"); 532 + return -EINVAL; 533 + } 534 + 535 + /* Either 4 or 5 consecutive bits, DAC5 is optional */ 536 + slot_offset = ffs(tx_mask) - 1; 537 + tx_mask >>= slot_offset; 538 + if ((slot_offset % 4) || ((tx_mask != 0x0F) && (tx_mask != 0x1F))) { 539 + dev_err(component->dev, "Unsupported tx slots allocation\n"); 540 + return -EINVAL; 541 + } 542 + 543 + regmap_update_bits(cs4234->regmap, CS4234_SP_DATA_SEL, CS4234_DAC14_SRC_MASK, 544 + (slot_offset / 4) << CS4234_DAC14_SRC_SHIFT); 545 + regmap_update_bits(cs4234->regmap, CS4234_SP_DATA_SEL, CS4234_LL_SRC_MASK, 546 + (slot_offset / 4) << CS4234_LL_SRC_SHIFT); 547 + 548 + if (tx_mask == 0x1F) { 549 + dac5_slot = slot_offset + 4; 550 + memset(dac5_masks, 0xFF, sizeof(dac5_masks)); 551 + dac5_mask_group = dac5_slot / 8; 552 + dac5_slot %= 8; 553 + dac5_masks[dac5_mask_group] ^= BIT(7 - dac5_slot); 554 + regmap_bulk_write(cs4234->regmap, 555 + CS4234_SDIN1_MASK1, 556 + dac5_masks, 557 + ARRAY_SIZE(dac5_masks)); 558 + } 559 + 560 + return 0; 561 + } 562 + 563 + static const struct snd_soc_dai_ops cs4234_dai_ops = { 564 + .set_fmt = cs4234_dai_set_fmt, 565 + .hw_params = cs4234_dai_hw_params, 566 + .startup = cs4234_dai_startup, 567 + .set_tdm_slot = cs4234_dai_set_tdm_slot, 568 + }; 569 + 570 + static struct snd_soc_dai_driver cs4234_dai[] = { 571 + { 572 + .name = "cs4234-dai", 573 + .playback = { 574 + .stream_name = "Playback", 575 + .channels_min = 1, 576 + .channels_max = 5, 577 + .rates = CS4234_PCM_RATES, 578 + .formats = CS4234_FORMATS, 579 + }, 580 + .capture = { 581 + .stream_name = "Capture", 582 + .channels_min = 1, 583 + .channels_max = 4, 584 + .rates = CS4234_PCM_RATES, 585 + .formats = CS4234_FORMATS, 586 + }, 587 + .ops = &cs4234_dai_ops, 588 + .symmetric_rates = 1, 589 + }, 590 + }; 591 + 592 + static const struct reg_default cs4234_default_reg[] = { 593 + { CS4234_CLOCK_SP, 0x04}, 594 + { CS4234_SAMPLE_WIDTH, 0xFF}, 595 + { CS4234_SP_CTRL, 0x48}, 596 + { CS4234_SP_DATA_SEL, 0x01}, 597 + { CS4234_SDIN1_MASK1, 0xFF}, 598 + { CS4234_SDIN1_MASK2, 0xFF}, 599 + { CS4234_SDIN2_MASK1, 0xFF}, 600 + { CS4234_SDIN2_MASK2, 0xFF}, 601 + { CS4234_TPS_CTRL, 0x00}, 602 + { CS4234_ADC_CTRL1, 0xC0}, 603 + { CS4234_ADC_CTRL2, 0xFF}, 604 + { CS4234_LOW_LAT_CTRL1, 0xE0}, 605 + { CS4234_DAC_CTRL1, 0xE0}, 606 + { CS4234_DAC_CTRL2, 0xE0}, 607 + { CS4234_DAC_CTRL3, 0xBF}, 608 + { CS4234_DAC_CTRL4, 0x1F}, 609 + { CS4234_VOLUME_MODE, 0x87}, 610 + { CS4234_MASTER_VOL, 0x10}, 611 + { CS4234_DAC1_VOL, 0x10}, 612 + { CS4234_DAC2_VOL, 0x10}, 613 + { CS4234_DAC3_VOL, 0x10}, 614 + { CS4234_DAC4_VOL, 0x10}, 615 + { CS4234_DAC5_VOL, 0x10}, 616 + { CS4234_INT_CTRL, 0x40}, 617 + { CS4234_INT_MASK1, 0x10}, 618 + { CS4234_INT_MASK2, 0x20}, 619 + }; 620 + 621 + static bool cs4234_readable_register(struct device *dev, unsigned int reg) 622 + { 623 + switch (reg) { 624 + case CS4234_DEVID_AB ... CS4234_DEVID_EF: 625 + case CS4234_REVID ... CS4234_DAC5_VOL: 626 + case CS4234_INT_CTRL ... CS4234_MAX_REGISTER: 627 + return true; 628 + default: 629 + return false; 630 + } 631 + } 632 + 633 + static bool cs4234_volatile_reg(struct device *dev, unsigned int reg) 634 + { 635 + switch (reg) { 636 + case CS4234_INT_NOTIFY1: 637 + case CS4234_INT_NOTIFY2: 638 + return true; 639 + default: 640 + return false; 641 + } 642 + } 643 + 644 + static bool cs4234_writeable_register(struct device *dev, unsigned int reg) 645 + { 646 + switch (reg) { 647 + case CS4234_DEVID_AB ... CS4234_REVID: 648 + case CS4234_INT_NOTIFY1 ... CS4234_INT_NOTIFY2: 649 + return false; 650 + default: 651 + return true; 652 + } 653 + } 654 + 655 + static const struct snd_soc_component_driver soc_component_cs4234 = { 656 + .dapm_widgets = cs4234_dapm_widgets, 657 + .num_dapm_widgets = ARRAY_SIZE(cs4234_dapm_widgets), 658 + .dapm_routes = cs4234_dapm_routes, 659 + .num_dapm_routes = ARRAY_SIZE(cs4234_dapm_routes), 660 + .controls = cs4234_snd_controls, 661 + .num_controls = ARRAY_SIZE(cs4234_snd_controls), 662 + .set_bias_level = cs4234_set_bias_level, 663 + .non_legacy_dai_naming = 1, 664 + .idle_bias_on = 1, 665 + .suspend_bias_off = 1, 666 + }; 667 + 668 + static const struct regmap_config cs4234_regmap = { 669 + .reg_bits = 8, 670 + .val_bits = 8, 671 + 672 + .max_register = CS4234_MAX_REGISTER, 673 + .readable_reg = cs4234_readable_register, 674 + .volatile_reg = cs4234_volatile_reg, 675 + .writeable_reg = cs4234_writeable_register, 676 + .reg_defaults = cs4234_default_reg, 677 + .num_reg_defaults = ARRAY_SIZE(cs4234_default_reg), 678 + .cache_type = REGCACHE_RBTREE, 679 + .use_single_read = true, 680 + .use_single_write = true, 681 + }; 682 + 683 + static const char * const cs4234_core_supplies[] = { 684 + "VA", 685 + "VL", 686 + }; 687 + 688 + static void cs4234_shutdown(struct cs4234 *cs4234) 689 + { 690 + cancel_delayed_work_sync(&cs4234->vq_ramp_delay); 691 + reinit_completion(&cs4234->vq_ramp_complete); 692 + 693 + regmap_update_bits(cs4234->regmap, CS4234_DAC_CTRL4, CS4234_VQ_RAMP_MASK, 694 + CS4234_VQ_RAMP_MASK); 695 + msleep(50); 696 + regcache_cache_only(cs4234->regmap, true); 697 + /* Clear VQ Ramp Bit in cache for the next PowerUp */ 698 + regmap_update_bits(cs4234->regmap, CS4234_DAC_CTRL4, CS4234_VQ_RAMP_MASK, 0); 699 + gpiod_set_value_cansleep(cs4234->reset_gpio, 0); 700 + regulator_bulk_disable(cs4234->num_core_supplies, cs4234->core_supplies); 701 + clk_disable_unprepare(cs4234->mclk); 702 + } 703 + 704 + static int cs4234_powerup(struct cs4234 *cs4234) 705 + { 706 + int ret; 707 + 708 + ret = clk_prepare_enable(cs4234->mclk); 709 + if (ret) { 710 + dev_err(cs4234->dev, "Failed to enable mclk: %d\n", ret); 711 + return ret; 712 + } 713 + 714 + ret = regulator_bulk_enable(cs4234->num_core_supplies, cs4234->core_supplies); 715 + if (ret) { 716 + dev_err(cs4234->dev, "Failed to enable core supplies: %d\n", ret); 717 + clk_disable_unprepare(cs4234->mclk); 718 + return ret; 719 + } 720 + 721 + usleep_range(CS4234_HOLD_RESET_TIME_US, 2 * CS4234_HOLD_RESET_TIME_US); 722 + gpiod_set_value_cansleep(cs4234->reset_gpio, 1); 723 + 724 + /* Make sure hardware reset done 2 ms + (3000/MCLK) */ 725 + usleep_range(CS4234_BOOT_TIME_US, CS4234_BOOT_TIME_US * 2); 726 + 727 + queue_delayed_work(system_power_efficient_wq, 728 + &cs4234->vq_ramp_delay, 729 + msecs_to_jiffies(CS4234_VQ_CHARGE_MS)); 730 + 731 + return 0; 732 + } 733 + 734 + static int cs4234_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) 735 + { 736 + struct cs4234 *cs4234; 737 + struct device *dev = &i2c_client->dev; 738 + unsigned int revid; 739 + uint32_t devid; 740 + uint8_t ids[3]; 741 + int ret = 0, i; 742 + 743 + cs4234 = devm_kzalloc(dev, sizeof(*cs4234), GFP_KERNEL); 744 + if (!cs4234) 745 + return -ENOMEM; 746 + i2c_set_clientdata(i2c_client, cs4234); 747 + cs4234->dev = dev; 748 + init_completion(&cs4234->vq_ramp_complete); 749 + INIT_DELAYED_WORK(&cs4234->vq_ramp_delay, cs4234_vq_ramp_done); 750 + 751 + cs4234->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 752 + if (IS_ERR(cs4234->reset_gpio)) 753 + return PTR_ERR(cs4234->reset_gpio); 754 + 755 + BUILD_BUG_ON(ARRAY_SIZE(cs4234->core_supplies) < ARRAY_SIZE(cs4234_core_supplies)); 756 + 757 + cs4234->num_core_supplies = ARRAY_SIZE(cs4234_core_supplies); 758 + for (i = 0; i < ARRAY_SIZE(cs4234_core_supplies); i++) 759 + cs4234->core_supplies[i].supply = cs4234_core_supplies[i]; 760 + 761 + ret = devm_regulator_bulk_get(dev, cs4234->num_core_supplies, cs4234->core_supplies); 762 + if (ret) { 763 + dev_err(dev, "Failed to request core supplies %d\n", ret); 764 + return ret; 765 + } 766 + 767 + cs4234->mclk = devm_clk_get(dev, "mclk"); 768 + if (IS_ERR(cs4234->mclk)) { 769 + ret = PTR_ERR(cs4234->mclk); 770 + dev_err(dev, "Failed to get the mclk: %d\n", ret); 771 + return ret; 772 + } 773 + cs4234->mclk_rate = clk_get_rate(cs4234->mclk); 774 + 775 + if (cs4234->mclk_rate < 7680000 || cs4234->mclk_rate > 25600000) { 776 + dev_err(dev, "Invalid Master Clock rate\n"); 777 + return -EINVAL; 778 + } 779 + 780 + cs4234->regmap = devm_regmap_init_i2c(i2c_client, &cs4234_regmap); 781 + if (IS_ERR(cs4234->regmap)) { 782 + ret = PTR_ERR(cs4234->regmap); 783 + dev_err(dev, "regmap_init() failed: %d\n", ret); 784 + return ret; 785 + } 786 + 787 + ret = cs4234_powerup(cs4234); 788 + if (ret) 789 + return ret; 790 + 791 + ret = regmap_bulk_read(cs4234->regmap, CS4234_DEVID_AB, ids, ARRAY_SIZE(ids)); 792 + if (ret < 0) { 793 + dev_err(dev, "Failed to read DEVID: %d\n", ret); 794 + goto fail_shutdown; 795 + } 796 + 797 + devid = (ids[0] << 16) | (ids[1] << 8) | ids[2]; 798 + if (devid != CS4234_SUPPORTED_ID) { 799 + dev_err(dev, "Unknown device ID: %x\n", devid); 800 + ret = -EINVAL; 801 + goto fail_shutdown; 802 + } 803 + 804 + ret = regmap_read(cs4234->regmap, CS4234_REVID, &revid); 805 + if (ret < 0) { 806 + dev_err(dev, "Failed to read CS4234_REVID: %d\n", ret); 807 + goto fail_shutdown; 808 + } 809 + 810 + dev_info(dev, "Cirrus Logic CS4234, Alpha Rev: %02X, Numeric Rev: %02X\n", 811 + (revid & 0xF0) >> 4, revid & 0x0F); 812 + 813 + ret = regulator_get_voltage(cs4234->core_supplies[CS4234_SUPPLY_VA].consumer); 814 + switch (ret) { 815 + case 3135000 ... 3650000: 816 + regmap_update_bits(cs4234->regmap, CS4234_ADC_CTRL1, 817 + CS4234_VA_SEL_MASK, 818 + CS4234_3V3 << CS4234_VA_SEL_SHIFT); 819 + break; 820 + case 4750000 ... 5250000: 821 + regmap_update_bits(cs4234->regmap, CS4234_ADC_CTRL1, 822 + CS4234_VA_SEL_MASK, 823 + CS4234_5V << CS4234_VA_SEL_SHIFT); 824 + break; 825 + default: 826 + dev_err(dev, "Invalid VA voltage\n"); 827 + ret = -EINVAL; 828 + goto fail_shutdown; 829 + } 830 + 831 + pm_runtime_set_active(&i2c_client->dev); 832 + pm_runtime_enable(&i2c_client->dev); 833 + 834 + memcpy(&cs4234->rate_dividers, &cs4234_dividers, sizeof(cs4234_dividers)); 835 + cs4234->rate_constraint.rats = cs4234->rate_dividers; 836 + 837 + ret = snd_soc_register_component(dev, &soc_component_cs4234, cs4234_dai, 838 + ARRAY_SIZE(cs4234_dai)); 839 + if (ret < 0) { 840 + dev_err(dev, "Failed to register component:%d\n", ret); 841 + pm_runtime_disable(&i2c_client->dev); 842 + goto fail_shutdown; 843 + } 844 + 845 + return ret; 846 + 847 + fail_shutdown: 848 + cs4234_shutdown(cs4234); 849 + 850 + return ret; 851 + } 852 + 853 + static int cs4234_i2c_remove(struct i2c_client *i2c_client) 854 + { 855 + struct cs4234 *cs4234 = i2c_get_clientdata(i2c_client); 856 + struct device *dev = &i2c_client->dev; 857 + 858 + snd_soc_unregister_component(dev); 859 + pm_runtime_disable(dev); 860 + cs4234_shutdown(cs4234); 861 + 862 + return 0; 863 + } 864 + 865 + static int __maybe_unused cs4234_runtime_resume(struct device *dev) 866 + { 867 + struct cs4234 *cs4234 = dev_get_drvdata(dev); 868 + int ret; 869 + 870 + ret = cs4234_powerup(cs4234); 871 + if (ret) 872 + return ret; 873 + 874 + regcache_mark_dirty(cs4234->regmap); 875 + regcache_cache_only(cs4234->regmap, false); 876 + ret = regcache_sync(cs4234->regmap); 877 + if (ret) { 878 + dev_err(dev, "Failed to sync regmap: %d\n", ret); 879 + cs4234_shutdown(cs4234); 880 + return ret; 881 + } 882 + 883 + return 0; 884 + } 885 + 886 + static int __maybe_unused cs4234_runtime_suspend(struct device *dev) 887 + { 888 + struct cs4234 *cs4234 = dev_get_drvdata(dev); 889 + 890 + cs4234_shutdown(cs4234); 891 + 892 + return 0; 893 + } 894 + 895 + static const struct dev_pm_ops cs4234_pm = { 896 + SET_RUNTIME_PM_OPS(cs4234_runtime_suspend, cs4234_runtime_resume, NULL) 897 + }; 898 + 899 + static const struct of_device_id cs4234_of_match[] = { 900 + { .compatible = "cirrus,cs4234", }, 901 + { } 902 + }; 903 + MODULE_DEVICE_TABLE(of, cs4234_of_match); 904 + 905 + static struct i2c_driver cs4234_i2c_driver = { 906 + .driver = { 907 + .name = "cs4234", 908 + .pm = &cs4234_pm, 909 + .of_match_table = cs4234_of_match, 910 + }, 911 + .probe = cs4234_i2c_probe, 912 + .remove = cs4234_i2c_remove, 913 + }; 914 + module_i2c_driver(cs4234_i2c_driver); 915 + 916 + MODULE_DESCRIPTION("ASoC Cirrus Logic CS4234 driver"); 917 + MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>"); 918 + MODULE_LICENSE("GPL v2");
+287
sound/soc/codecs/cs4234.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * ALSA SoC Audio driver for CS4234 codec 4 + * 5 + * Copyright (C) 2020 Cirrus Logic, Inc. and 6 + * Cirrus Logic International Semiconductor Ltd. 7 + */ 8 + 9 + #ifndef CS4234_H 10 + #define CS4234_H 11 + 12 + #define CS4234_DEVID_AB 0x01 13 + #define CS4234_DEVID_CD 0x02 14 + #define CS4234_DEVID_EF 0x03 15 + #define CS4234_REVID 0x05 16 + 17 + #define CS4234_CLOCK_SP 0x06 18 + #define CS4234_BASE_RATE_MASK 0xC0 19 + #define CS4234_BASE_RATE_SHIFT 6 20 + #define CS4234_SPEED_MODE_MASK 0x30 21 + #define CS4234_SPEED_MODE_SHIFT 4 22 + #define CS4234_MCLK_RATE_MASK 0x0E 23 + #define CS4234_MCLK_RATE_SHIFT 1 24 + 25 + #define CS4234_SAMPLE_WIDTH 0x07 26 + #define CS4234_SDOUTX_SW_MASK 0xC0 27 + #define CS4234_SDOUTX_SW_SHIFT 6 28 + #define CS4234_INPUT_SW_MASK 0x30 29 + #define CS4234_INPUT_SW_SHIFT 4 30 + #define CS4234_LOW_LAT_SW_MASK 0x0C 31 + #define CS4234_LOW_LAT_SW_SHIFT 2 32 + #define CS4234_DAC5_SW_MASK 0x03 33 + #define CS4234_DAC5_SW_SHIFT 0 34 + 35 + #define CS4234_SP_CTRL 0x08 36 + #define CS4234_INVT_SCLK_MASK 0x80 37 + #define CS4234_INVT_SCLK_SHIFT 7 38 + #define CS4234_DAC5_SRC_MASK 0x70 39 + #define CS4234_DAC5_SRC_SHIFT 4 40 + #define CS4234_SP_FORMAT_MASK 0x0C 41 + #define CS4234_SP_FORMAT_SHIFT 2 42 + #define CS4234_SDO_CHAIN_MASK 0x02 43 + #define CS4234_SDO_CHAIN_SHIFT 1 44 + #define CS4234_MST_SLV_MASK 0x01 45 + #define CS4234_MST_SLV_SHIFT 0 46 + 47 + #define CS4234_SP_DATA_SEL 0x09 48 + #define CS4234_DAC14_SRC_MASK 0x38 49 + #define CS4234_DAC14_SRC_SHIFT 3 50 + #define CS4234_LL_SRC_MASK 0x07 51 + #define CS4234_LL_SRC_SHIFT 0 52 + 53 + #define CS4234_SDIN1_MASK1 0x0A 54 + #define CS4234_SDIN1_MASK2 0x0B 55 + #define CS4234_SDIN2_MASK1 0x0C 56 + #define CS4234_SDIN2_MASK2 0x0D 57 + 58 + #define CS4234_TPS_CTRL 0x0E 59 + #define CS4234_TPS_MODE_MASK 0x80 60 + #define CS4234_TPS_MODE_SHIFT 7 61 + #define CS4234_TPS_OFST_MASK 0x70 62 + #define CS4234_TPS_OFST_SHIFT 4 63 + #define CS4234_GRP_DELAY_MASK 0x0F 64 + #define CS4234_GRP_DELAY_SHIFT 0 65 + 66 + #define CS4234_ADC_CTRL1 0x0F 67 + #define CS4234_VA_SEL_MASK 0x20 68 + #define CS4234_VA_SEL_SHIFT 5 69 + #define CS4234_ENA_HPF_MASK 0x10 70 + #define CS4234_ENA_HPF_SHIFT 4 71 + #define CS4234_INV_ADC_MASK 0x0F 72 + #define CS4234_INV_ADC4_MASK 0x08 73 + #define CS4234_INV_ADC4_SHIFT 3 74 + #define CS4234_INV_ADC3_MASK 0x04 75 + #define CS4234_INV_ADC3_SHIFT 2 76 + #define CS4234_INV_ADC2_MASK 0x02 77 + #define CS4234_INV_ADC2_SHIFT 1 78 + #define CS4234_INV_ADC1_MASK 0x01 79 + #define CS4234_INV_ADC1_SHIFT 0 80 + 81 + #define CS4234_ADC_CTRL2 0x10 82 + #define CS4234_MUTE_ADC4_MASK 0x80 83 + #define CS4234_MUTE_ADC4_SHIFT 7 84 + #define CS4234_MUTE_ADC3_MASK 0x40 85 + #define CS4234_MUTE_ADC3_SHIFT 6 86 + #define CS4234_MUTE_ADC2_MASK 0x20 87 + #define CS4234_MUTE_ADC2_SHIFT 5 88 + #define CS4234_MUTE_ADC1_MASK 0x10 89 + #define CS4234_MUTE_ADC1_SHIFT 4 90 + #define CS4234_PDN_ADC4_MASK 0x08 91 + #define CS4234_PDN_ADC4_SHIFT 3 92 + #define CS4234_PDN_ADC3_MASK 0x04 93 + #define CS4234_PDN_ADC3_SHIFT 2 94 + #define CS4234_PDN_ADC2_MASK 0x02 95 + #define CS4234_PDN_ADC2_SHIFT 1 96 + #define CS4234_PDN_ADC1_MASK 0x01 97 + #define CS4234_PDN_ADC1_SHIFT 0 98 + 99 + #define CS4234_LOW_LAT_CTRL1 0x11 100 + #define CS4234_LL_NG_MASK 0xE0 101 + #define CS4234_LL_NG_SHIFT 5 102 + #define CS4234_INV_LL_MASK 0x0F 103 + #define CS4234_INV_LL4_MASK 0x08 104 + #define CS4234_INV_LL4_SHIFT 3 105 + #define CS4234_INV_LL3_MASK 0x04 106 + #define CS4234_INV_LL3_SHIFT 2 107 + #define CS4234_INV_LL2_MASK 0x02 108 + #define CS4234_INV_LL2_SHIFT 1 109 + #define CS4234_INV_LL1_MASK 0x01 110 + #define CS4234_INV_LL1_SHIFT 0 111 + 112 + #define CS4234_DAC_CTRL1 0x12 113 + #define CS4234_DAC14_NG_MASK 0xE0 114 + #define CS4234_DAC14_NG_SHIFT 5 115 + #define CS4234_DAC14_DE_MASK 0x10 116 + #define CS4234_DAC14_DE_SHIFT 4 117 + #define CS4234_DAC5_DE_MASK 0x08 118 + #define CS4234_DAC5_DE_SHIFT 3 119 + #define CS4234_DAC5_MVC_MASK 0x04 120 + #define CS4234_DAC5_MVC_SHIFT 2 121 + #define CS4234_DAC5_CFG_FLTR_MASK 0x03 122 + #define CS4234_DAC5_CFG_FLTR_SHIFT 0 123 + 124 + #define CS4234_DAC_CTRL2 0x13 125 + #define CS4234_DAC5_NG_MASK 0xE0 126 + #define CS4234_DAC5_NG_SHIFT 5 127 + #define CS4234_INV_DAC_MASK 0x1F 128 + #define CS4234_INV_DAC5_MASK 0x10 129 + #define CS4234_INV_DAC5_SHIFT 4 130 + #define CS4234_INV_DAC4_MASK 0x08 131 + #define CS4234_INV_DAC4_SHIFT 3 132 + #define CS4234_INV_DAC3_MASK 0x04 133 + #define CS4234_INV_DAC3_SHIFT 2 134 + #define CS4234_INV_DAC2_MASK 0x02 135 + #define CS4234_INV_DAC2_SHIFT 1 136 + #define CS4234_INV_DAC1_MASK 0x01 137 + #define CS4234_INV_DAC1_SHIFT 0 138 + 139 + #define CS4234_DAC_CTRL3 0x14 140 + #define CS4234_DAC5_ATT_MASK 0x80 141 + #define CS4234_DAC5_ATT_SHIFT 7 142 + #define CS4234_DAC14_ATT_MASK 0x40 143 + #define CS4234_DAC14_ATT_SHIFT 6 144 + #define CS4234_MUTE_LL_MASK 0x20 145 + #define CS4234_MUTE_LL_SHIFT 5 146 + #define CS4234_MUTE_DAC5_MASK 0x10 147 + #define CS4234_MUTE_DAC5_SHIFT 4 148 + #define CS4234_MUTE_DAC4_MASK 0x08 149 + #define CS4234_MUTE_DAC4_SHIFT 3 150 + #define CS4234_MUTE_DAC3_MASK 0x04 151 + #define CS4234_MUTE_DAC3_SHIFT 2 152 + #define CS4234_MUTE_DAC2_MASK 0x02 153 + #define CS4234_MUTE_DAC2_SHIFT 1 154 + #define CS4234_MUTE_DAC1_MASK 0x01 155 + #define CS4234_MUTE_DAC1_SHIFT 0 156 + 157 + #define CS4234_DAC_CTRL4 0x15 158 + #define CS4234_VQ_RAMP_MASK 0x80 159 + #define CS4234_VQ_RAMP_SHIFT 7 160 + #define CS4234_TPS_GAIN_MASK 0x40 161 + #define CS4234_TPS_GAIN_SHIFT 6 162 + #define CS4234_PDN_DAC5_MASK 0x10 163 + #define CS4234_PDN_DAC5_SHIFT 4 164 + #define CS4234_PDN_DAC4_MASK 0x08 165 + #define CS4234_PDN_DAC4_SHIFT 3 166 + #define CS4234_PDN_DAC3_MASK 0x04 167 + #define CS4234_PDN_DAC3_SHIFT 2 168 + #define CS4234_PDN_DAC2_MASK 0x02 169 + #define CS4234_PDN_DAC2_SHIFT 1 170 + #define CS4234_PDN_DAC1_MASK 0x01 171 + #define CS4234_PDN_DAC1_SHIFT 0 172 + 173 + #define CS4234_VOLUME_MODE 0x16 174 + #define CS4234_MUTE_DELAY_MASK 0xC0 175 + #define CS4234_MUTE_DELAY_SHIFT 6 176 + #define CS4234_MIN_DELAY_MASK 0x38 177 + #define CS4234_MIN_DELAY_SHIFT 3 178 + #define CS4234_MAX_DELAY_MASK 0x07 179 + #define CS4234_MAX_DELAY_SHIFT 0 180 + 181 + #define CS4234_MASTER_VOL 0x17 182 + #define CS4234_DAC1_VOL 0x18 183 + #define CS4234_DAC2_VOL 0x19 184 + #define CS4234_DAC3_VOL 0x1A 185 + #define CS4234_DAC4_VOL 0x1B 186 + #define CS4234_DAC5_VOL 0x1C 187 + 188 + #define CS4234_INT_CTRL 0x1E 189 + #define CS4234_INT_MODE_MASK 0x80 190 + #define CS4234_INT_MODE_SHIFT 7 191 + #define CS4234_INT_PIN_MASK 0x60 192 + #define CS4234_INT_PIN_SHIFT 5 193 + 194 + #define CS4234_INT_MASK1 0x1F 195 + #define CS4234_MSK_TST_MODE_MASK 0x80 196 + #define CS4234_MSK_TST_MODE_ERR_SHIFT 7 197 + #define CS4234_MSK_SP_ERR_MASK 0x40 198 + #define CS4234_MSK_SP_ERR_SHIFT 6 199 + #define CS4234_MSK_CLK_ERR_MASK 0x08 200 + #define CS4234_MSK_CLK_ERR_SHIFT 5 201 + #define CS4234_MSK_ADC4_OVFL_MASK 0x08 202 + #define CS4234_MSK_ADC4_OVFL_SHIFT 3 203 + #define CS4234_MSK_ADC3_OVFL_MASK 0x04 204 + #define CS4234_MSK_ADC3_OVFL_SHIFT 2 205 + #define CS4234_MSK_ADC2_OVFL_MASK 0x02 206 + #define CS4234_MSK_ADC2_OVFL_SHIFT 1 207 + #define CS4234_MSK_ADC1_OVFL_MASK 0x01 208 + #define CS4234_MSK_ADC1_OVFL_SHIFT 0 209 + 210 + #define CS4234_INT_MASK2 0x20 211 + #define CS4234_MSK_DAC5_CLIP_MASK 0x10 212 + #define CS4234_MSK_DAC5_CLIP_SHIFT 4 213 + #define CS4234_MSK_DAC4_CLIP_MASK 0x08 214 + #define CS4234_MSK_DAC4_CLIP_SHIFT 3 215 + #define CS4234_MSK_DAC3_CLIP_MASK 0x04 216 + #define CS4234_MSK_DAC3_CLIP_SHIFT 2 217 + #define CS4234_MSK_DAC2_CLIP_MASK 0x02 218 + #define CS4234_MSK_DAC2_CLIP_SHIFT 1 219 + #define CS4234_MSK_DAC1_CLIP_MASK 0x01 220 + #define CS4234_MSK_DAC1_CLIP_SHIFT 0 221 + 222 + #define CS4234_INT_NOTIFY1 0x21 223 + #define CS4234_TST_MODE_MASK 0x80 224 + #define CS4234_TST_MODE_SHIFT 7 225 + #define CS4234_SP_ERR_MASK 0x40 226 + #define CS4234_SP_ERR_SHIFT 6 227 + #define CS4234_CLK_MOD_ERR_MASK 0x08 228 + #define CS4234_CLK_MOD_ERR_SHIFT 5 229 + #define CS4234_ADC4_OVFL_MASK 0x08 230 + #define CS4234_ADC4_OVFL_SHIFT 3 231 + #define CS4234_ADC3_OVFL_MASK 0x04 232 + #define CS4234_ADC3_OVFL_SHIFT 2 233 + #define CS4234_ADC2_OVFL_MASK 0x02 234 + #define CS4234_ADC2_OVFL_SHIFT 1 235 + #define CS4234_ADC1_OVFL_MASK 0x01 236 + #define CS4234_ADC1_OVFL_SHIFT 0 237 + 238 + #define CS4234_INT_NOTIFY2 0x22 239 + #define CS4234_DAC5_CLIP_MASK 0x10 240 + #define CS4234_DAC5_CLIP_SHIFT 4 241 + #define CS4234_DAC4_CLIP_MASK 0x08 242 + #define CS4234_DAC4_CLIP_SHIFT 3 243 + #define CS4234_DAC3_CLIP_MASK 0x04 244 + #define CS4234_DAC3_CLIP_SHIFT 2 245 + #define CS4234_DAC2_CLIP_MASK 0x02 246 + #define CS4234_DAC2_CLIP_SHIFT 1 247 + #define CS4234_DAC1_CLIP_MASK 0x01 248 + #define CS4234_DAC1_CLIP_SHIFT 0 249 + 250 + #define CS4234_MAX_REGISTER CS4234_INT_NOTIFY2 251 + 252 + #define CS4234_SUPPORTED_ID 0x423400 253 + #define CS4234_BOOT_TIME_US 3000 254 + #define CS4234_HOLD_RESET_TIME_US 1000 255 + #define CS4234_VQ_CHARGE_MS 1000 256 + 257 + #define CS4234_PCM_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 258 + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ 259 + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) 260 + 261 + #define CS4234_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ 262 + SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE | \ 263 + SNDRV_PCM_FMTBIT_S24_3LE) 264 + 265 + enum cs4234_supplies { 266 + CS4234_SUPPLY_VA = 0, 267 + CS4234_SUPPLY_VL, 268 + }; 269 + 270 + enum cs4234_va_sel { 271 + CS4234_3V3 = 0, 272 + CS4234_5V, 273 + }; 274 + 275 + enum cs4234_sp_format { 276 + CS4234_LEFT_J = 0, 277 + CS4234_I2S, 278 + CS4234_TDM, 279 + }; 280 + 281 + enum cs4234_base_rate_advisory { 282 + CS4234_48K = 0, 283 + CS4234_44K1, 284 + CS4234_32K, 285 + }; 286 + 287 + #endif