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: add CS42L84 codec driver

Merge series from James Calligeros <jcalligeros99@gmail.com>:

This patch set adds a driver for the Cirrus Logic CS42L84 codec. This chip
is (so far) found only on Apple Silicon Macs. In keeping with proud Apple
tradition, the CS42L84 is essentially just a CS42L42 with a different
regmap and no publicly available datasheet. It may also be missing its
parent's S/PDIF capabilities as none of Apple's devices support S/PDIF out,
however this cannot be positively confirmed.

This driver has lived in the downstream Asahi tree for quite a while now,
and gained some refinements along the way. I have squashed most of these
into the initial driver commit as they were small changes like tweaking
msleep()s or filling out TLVs, but left seperate a larger change to
tip/ring sense IRQ handling as it differs significantly from what is found
in the CS42L42 driver.

+1389
+56
Documentation/devicetree/bindings/sound/cirrus,cs42l84.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/cirrus,cs42l84.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Cirrus Logic CS42L84 audio CODEC 8 + 9 + maintainers: 10 + - Martin Povišer <povik+lin@cutebit.org> 11 + 12 + description: | 13 + The CS42L84 is a headphone jack codec made by Cirrus Logic and embedded 14 + in personal computers sold by Apple. It was first seen in 2021 Macbook 15 + Pro models. It has stereo DAC for playback, mono ADC for capture, and 16 + is somewhat similar to CS42L42 but with a different regmap. 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - cirrus,cs42l84 22 + 23 + reg: 24 + maxItems: 1 25 + 26 + reset-gpios: 27 + maxItems: 1 28 + 29 + interrupts: 30 + maxItems: 1 31 + 32 + '#sound-dai-cells': 33 + const: 0 34 + 35 + required: 36 + - compatible 37 + - reg 38 + 39 + additionalProperties: false 40 + 41 + examples: 42 + - | 43 + #include <dt-bindings/gpio/gpio.h> 44 + #include <dt-bindings/interrupt-controller/irq.h> 45 + i2c { 46 + #address-cells = <1>; 47 + #size-cells = <0>; 48 + 49 + jack_codec: codec@4b { 50 + compatible = "cirrus,cs42l84"; 51 + reg = <0x4b>; 52 + reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_LOW>; 53 + interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>; 54 + #sound-dai-cells = <0>; 55 + }; 56 + };
+2
MAINTAINERS
··· 2132 2132 L: linux-sound@vger.kernel.org 2133 2133 S: Maintained 2134 2134 F: Documentation/devicetree/bindings/sound/adi,ssm3515.yaml 2135 + F: Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml 2135 2136 F: Documentation/devicetree/bindings/sound/apple,* 2136 2137 F: sound/soc/apple/* 2137 2138 F: sound/soc/codecs/cs42l83-i2c.c 2139 + F: sound/soc/codecs/cs42l84.* 2138 2140 F: sound/soc/codecs/ssm3515.c 2139 2141 2140 2142 ARM/APPLE MACHINE SUPPORT
+7
sound/soc/codecs/Kconfig
··· 85 85 imply SND_SOC_CS42L52 86 86 imply SND_SOC_CS42L56 87 87 imply SND_SOC_CS42L73 88 + imply SND_SOC_CS42L84 88 89 imply SND_SOC_CS4234 89 90 imply SND_SOC_CS4265 90 91 imply SND_SOC_CS4270 ··· 929 928 select REGMAP 930 929 select REGMAP_I2C 931 930 select SND_SOC_CS42L42_CORE 931 + 932 + config SND_SOC_CS42L84 933 + tristate "Cirrus Logic CS42L84 CODEC" 934 + depends on I2C 935 + select REGMAP 936 + select REGMAP_I2C 932 937 933 938 config SND_SOC_CS4234 934 939 tristate "Cirrus Logic CS4234 CODEC"
+2
sound/soc/codecs/Makefile
··· 91 91 snd-soc-cs42l56-y := cs42l56.o 92 92 snd-soc-cs42l73-y := cs42l73.o 93 93 snd-soc-cs42l83-i2c-y := cs42l83-i2c.o 94 + snd-soc-cs42l84-objs := cs42l84.o 94 95 snd-soc-cs4234-y := cs4234.o 95 96 snd-soc-cs4265-y := cs4265.o 96 97 snd-soc-cs4270-y := cs4270.o ··· 506 505 obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o 507 506 obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o 508 507 obj-$(CONFIG_SND_SOC_CS42L83) += snd-soc-cs42l83-i2c.o 508 + obj-$(CONFIG_SND_SOC_CS42L84) += snd-soc-cs42l84.o 509 509 obj-$(CONFIG_SND_SOC_CS4234) += snd-soc-cs4234.o 510 510 obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o 511 511 obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
+1112
sound/soc/codecs/cs42l84.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * cs42l84.c -- CS42L84 ALSA SoC audio driver 4 + * 5 + * Copyright (C) The Asahi Linux Contributors 6 + * 7 + * Based on sound/soc/codecs/cs42l42{.c,.h} 8 + * Copyright 2016 Cirrus Logic, Inc. 9 + */ 10 + 11 + #include <linux/bitfield.h> 12 + #include <linux/bits.h> 13 + #include <linux/module.h> 14 + #include <linux/moduleparam.h> 15 + #include <linux/version.h> 16 + #include <linux/kernel.h> 17 + #include <linux/init.h> 18 + #include <linux/delay.h> 19 + #include <linux/i2c.h> 20 + #include <linux/gpio.h> 21 + #include <linux/regmap.h> 22 + #include <linux/slab.h> 23 + #include <linux/acpi.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/property.h> 26 + #include <linux/regulator/consumer.h> 27 + #include <linux/gpio/consumer.h> 28 + #include <linux/of_device.h> 29 + #include <sound/core.h> 30 + #include <sound/jack.h> 31 + #include <sound/pcm.h> 32 + #include <sound/pcm_params.h> 33 + #include <sound/soc.h> 34 + #include <sound/soc-dapm.h> 35 + #include <sound/initval.h> 36 + #include <sound/tlv.h> 37 + 38 + #include "cs42l84.h" 39 + #include "cirrus_legacy.h" 40 + 41 + struct cs42l84_private { 42 + struct regmap *regmap; 43 + struct device *dev; 44 + struct gpio_desc *reset_gpio; 45 + struct snd_soc_jack *jack; 46 + struct mutex irq_lock; 47 + u8 tip_state; 48 + u8 ring_state; 49 + int pll_config; 50 + int bclk; 51 + u8 pll_mclk_f; 52 + u32 srate; 53 + u8 stream_use; 54 + int hs_type; 55 + }; 56 + 57 + static bool cs42l84_volatile_register(struct device *dev, unsigned int reg) 58 + { 59 + switch (reg) { 60 + case CS42L84_DEVID ... CS42L84_DEVID+5: 61 + case CS42L84_TSRS_PLUG_INT_STATUS: 62 + case CS42L84_PLL_LOCK_STATUS: 63 + case CS42L84_TSRS_PLUG_STATUS: 64 + case CS42L84_HS_DET_STATUS2: 65 + return true; 66 + default: 67 + return false; 68 + } 69 + } 70 + 71 + static const struct regmap_config cs42l84_regmap = { 72 + .reg_bits = 16, 73 + .val_bits = 8, 74 + 75 + .volatile_reg = cs42l84_volatile_register, 76 + 77 + .max_register = 0x73fe, 78 + 79 + .cache_type = REGCACHE_MAPLE, 80 + 81 + .use_single_read = true, 82 + .use_single_write = true, 83 + }; 84 + 85 + static int cs42l84_put_dac_vol(struct snd_kcontrol *kctl, 86 + struct snd_ctl_elem_value *val) 87 + { 88 + struct snd_soc_component *component = snd_soc_kcontrol_component(kctl); 89 + struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value; 90 + int vola, volb; 91 + int ret, ret2, updated = 0; 92 + 93 + vola = val->value.integer.value[0] + mc->min; 94 + volb = val->value.integer.value[1] + mc->min; 95 + 96 + if (vola < mc->min || vola > mc->max || volb < mc->min || volb > mc->max) 97 + return -EINVAL; 98 + 99 + ret = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL, 100 + CS42L84_FRZ_CTL_ENGAGE, 101 + CS42L84_FRZ_CTL_ENGAGE); 102 + if (ret < 0) 103 + goto bail; 104 + updated |= ret; 105 + 106 + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_LSB, 107 + 0xff, vola & 0xff); 108 + if (ret < 0) 109 + goto bail; 110 + updated |= ret; 111 + 112 + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_MSB, 113 + 0xff, (vola >> 8) & 0x01); 114 + if (ret < 0) 115 + goto bail; 116 + updated |= ret; 117 + 118 + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_LSB, 119 + 0xff, volb & 0xff); 120 + if (ret < 0) 121 + goto bail; 122 + updated |= ret; 123 + 124 + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_MSB, 125 + 0xff, (volb >> 8) & 0x01); 126 + if (ret < 0) 127 + goto bail; 128 + ret |= updated; 129 + 130 + bail: 131 + ret2 = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL, 132 + CS42L84_FRZ_CTL_ENGAGE, 0); 133 + if (ret2 < 0 && ret >= 0) 134 + ret = ret2; 135 + 136 + return ret; 137 + } 138 + 139 + static int cs42l84_get_dac_vol(struct snd_kcontrol *kctl, 140 + struct snd_ctl_elem_value *val) 141 + { 142 + struct snd_soc_component *component = snd_soc_kcontrol_component(kctl); 143 + struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value; 144 + int vola, volb; 145 + int ret; 146 + 147 + ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_LSB); 148 + if (ret < 0) 149 + return ret; 150 + vola = ret; 151 + 152 + ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_MSB); 153 + if (ret < 0) 154 + return ret; 155 + vola |= (ret & 1) << 8; 156 + 157 + ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_LSB); 158 + if (ret < 0) 159 + return ret; 160 + volb = ret; 161 + 162 + ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_MSB); 163 + if (ret < 0) 164 + return ret; 165 + volb |= (ret & 1) << 8; 166 + 167 + if (vola & BIT(8)) 168 + vola |= ~((int)(BIT(8) - 1)); 169 + if (volb & BIT(8)) 170 + volb |= ~((int)(BIT(8) - 1)); 171 + 172 + val->value.integer.value[0] = vola - mc->min; 173 + val->value.integer.value[1] = volb - mc->min; 174 + 175 + return 0; 176 + } 177 + 178 + static const DECLARE_TLV_DB_SCALE(cs42l84_dac_tlv, -12800, 50, true); 179 + static const DECLARE_TLV_DB_SCALE(cs42l84_adc_tlv, -1200, 50, false); 180 + static const DECLARE_TLV_DB_SCALE(cs42l84_pre_tlv, 0, 1000, false); 181 + 182 + static const struct snd_kcontrol_new cs42l84_snd_controls[] = { 183 + SOC_DOUBLE_R_S_EXT_TLV("DAC Playback Volume", CS42L84_DAC_CHA_VOL_LSB, 184 + CS42L84_DAC_CHB_VOL_LSB, 0, -256, 24, 8, 0, 185 + cs42l84_get_dac_vol, cs42l84_put_dac_vol, cs42l84_dac_tlv), 186 + SOC_SINGLE_TLV("ADC Preamp Capture Volume", CS42L84_ADC_CTL1, 187 + CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT, 2, 0, cs42l84_pre_tlv), 188 + SOC_SINGLE_TLV("ADC PGA Capture Volume", CS42L84_ADC_CTL1, 189 + CS42L84_ADC_CTL1_PGA_GAIN_SHIFT, 24, 0, cs42l84_adc_tlv), 190 + SOC_SINGLE("ADC WNF Switch", CS42L84_ADC_CTL4, 191 + CS42L84_ADC_CTL4_WNF_EN_SHIFT, 1, 0), 192 + SOC_SINGLE("WNF Corner Frequency", CS42L84_ADC_CTL4, 193 + CS42L84_ADC_CTL4_WNF_CF_SHIFT, 3, 0), 194 + SOC_SINGLE("ADC HPF Switch", CS42L84_ADC_CTL4, 195 + CS42L84_ADC_CTL4_HPF_EN_SHIFT, 1, 0), 196 + SOC_SINGLE("HPF Corner Frequency", CS42L84_ADC_CTL4, 197 + CS42L84_ADC_CTL4_HPF_CF_SHIFT, 3, 0), 198 + }; 199 + 200 + static const char * const cs42l84_mux_text[] = { 201 + "Blank", "ADC", "ASP RX CH1", "ASP RX CH2", 202 + }; 203 + 204 + static const unsigned int cs42l84_mux_values[] = { 205 + 0b0000, 0b0111, 0b1101, 0b1110, 206 + }; 207 + 208 + static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_daca_mux_enum, 209 + CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACA_SHIFT, 210 + 0b1111, cs42l84_mux_text, cs42l84_mux_values); 211 + 212 + static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_dacb_mux_enum, 213 + CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACB_SHIFT, 214 + 0b1111, cs42l84_mux_text, cs42l84_mux_values); 215 + 216 + static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_sdout1_mux_enum, 217 + CS42L84_BUS_ASP_TX_SRC, CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT, 218 + 0b1111, cs42l84_mux_text, cs42l84_mux_values); 219 + 220 + static const struct snd_kcontrol_new cs42l84_daca_mux_ctrl = 221 + SOC_DAPM_ENUM("DACA Select", cs42l84_daca_mux_enum); 222 + 223 + static const struct snd_kcontrol_new cs42l84_dacb_mux_ctrl = 224 + SOC_DAPM_ENUM("DACB Select", cs42l84_dacb_mux_enum); 225 + 226 + static const struct snd_kcontrol_new cs42l84_sdout1_mux_ctrl = 227 + SOC_DAPM_ENUM("SDOUT1 Select", cs42l84_sdout1_mux_enum); 228 + 229 + static const struct snd_soc_dapm_widget cs42l84_dapm_widgets[] = { 230 + /* Playback Path */ 231 + SND_SOC_DAPM_OUTPUT("HP"), 232 + SND_SOC_DAPM_DAC("DAC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_DAC_SHIFT, 0), 233 + SND_SOC_DAPM_MUX("DACA Select", SND_SOC_NOPM, 0, 0, &cs42l84_daca_mux_ctrl), 234 + SND_SOC_DAPM_MUX("DACB Select", SND_SOC_NOPM, 0, 0, &cs42l84_dacb_mux_ctrl), 235 + SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH1_SHIFT, 0), 236 + SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH2_SHIFT, 0), 237 + 238 + /* Capture Path */ 239 + SND_SOC_DAPM_INPUT("HS"), 240 + SND_SOC_DAPM_ADC("ADC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ADC_SHIFT, 0), 241 + SND_SOC_DAPM_MUX("SDOUT1 Select", SND_SOC_NOPM, 0, 0, &cs42l84_sdout1_mux_ctrl), 242 + SND_SOC_DAPM_AIF_OUT("SDOUT1", NULL, 0, CS42L84_ASP_TX_EN, CS42L84_ASP_TX_EN_CH1_SHIFT, 0), 243 + 244 + /* Playback/Capture Requirements */ 245 + SND_SOC_DAPM_SUPPLY("BUS", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_BUS_SHIFT, 0, NULL, 0), 246 + SND_SOC_DAPM_SUPPLY("ASP", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ASP_SHIFT, 0, NULL, 0), 247 + SND_SOC_DAPM_SUPPLY("BCLK", CS42L84_ASP_CTL, CS42L84_ASP_CTL_BCLK_EN_SHIFT, 0, NULL, 0), 248 + }; 249 + 250 + static const struct snd_soc_dapm_route cs42l84_audio_map[] = { 251 + /* Playback Path */ 252 + {"HP", NULL, "DAC"}, 253 + {"DAC", NULL, "DACA Select"}, 254 + {"DAC", NULL, "DACB Select"}, 255 + {"DACA Select", "ASP RX CH1", "SDIN1"}, 256 + {"DACA Select", "ASP RX CH2", "SDIN2"}, 257 + {"DACB Select", "ASP RX CH1", "SDIN1"}, 258 + {"DACB Select", "ASP RX CH2", "SDIN2"}, 259 + {"SDIN1", NULL, "Playback"}, 260 + {"SDIN2", NULL, "Playback"}, 261 + 262 + {"ADC", NULL, "HS"}, 263 + {"SDOUT1 Select", "ADC", "ADC"}, 264 + {"SDOUT1", NULL, "SDOUT1 Select"}, 265 + {"Capture", NULL, "SDOUT1"}, 266 + 267 + /* Playback Requirements */ 268 + {"DAC", NULL, "BUS"}, 269 + {"SDIN1", NULL, "ASP"}, 270 + {"SDIN2", NULL, "ASP"}, 271 + {"SDIN1", NULL, "BCLK"}, 272 + {"SDIN2", NULL, "BCLK"}, 273 + 274 + /* Capture Requirements */ 275 + {"SDOUT1", NULL, "BUS"}, 276 + {"SDOUT1", NULL, "ASP"}, 277 + {"SDOUT1", NULL, "BCLK"}, 278 + }; 279 + 280 + static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jk, void *d) 281 + { 282 + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); 283 + 284 + /* Prevent race with interrupt handler */ 285 + mutex_lock(&cs42l84->irq_lock); 286 + cs42l84->jack = jk; 287 + snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET); 288 + mutex_unlock(&cs42l84->irq_lock); 289 + 290 + return 0; 291 + } 292 + 293 + static int cs42l84_component_probe(struct snd_soc_component *component) 294 + { 295 + snd_soc_component_update_bits(component, CS42L84_ASP_CTL, 296 + CS42L84_ASP_CTL_TDM_MODE, 0); 297 + snd_soc_component_update_bits(component, CS42L84_HP_VOL_CTL, 298 + CS42L84_HP_VOL_CTL_SOFT | CS42L84_HP_VOL_CTL_ZERO_CROSS, 299 + CS42L84_HP_VOL_CTL_ZERO_CROSS); 300 + 301 + /* TDM settings */ 302 + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL1, 303 + CS42L84_ASP_RX_CHx_CTL1_EDGE | 304 + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0); 305 + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL2, 306 + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); 307 + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL1, 308 + CS42L84_ASP_RX_CHx_CTL1_EDGE | 309 + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 310 + CS42L84_ASP_RX_CHx_CTL1_EDGE); 311 + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL2, 312 + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); 313 + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL1, 314 + CS42L84_ASP_RX_CHx_CTL1_EDGE | \ 315 + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0); 316 + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL2, 317 + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); 318 + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL1, 319 + CS42L84_ASP_RX_CHx_CTL1_EDGE | \ 320 + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 321 + CS42L84_ASP_RX_CHx_CTL1_EDGE); 322 + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL2, 323 + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); 324 + /* Routing defaults */ 325 + snd_soc_component_write(component, CS42L84_BUS_DAC_SRC, 326 + 0b1101 << CS42L84_BUS_DAC_SRC_DACA_SHIFT | 327 + 0b1110 << CS42L84_BUS_DAC_SRC_DACB_SHIFT); 328 + snd_soc_component_write(component, CS42L84_BUS_ASP_TX_SRC, 329 + 0b0111 << CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT); 330 + 331 + return 0; 332 + } 333 + 334 + static const struct snd_soc_component_driver soc_component_dev_cs42l84 = { 335 + .set_jack = cs42l84_set_jack, 336 + .probe = cs42l84_component_probe, 337 + .controls = cs42l84_snd_controls, 338 + .num_controls = ARRAY_SIZE(cs42l84_snd_controls), 339 + .dapm_widgets = cs42l84_dapm_widgets, 340 + .num_dapm_widgets = ARRAY_SIZE(cs42l84_dapm_widgets), 341 + .dapm_routes = cs42l84_audio_map, 342 + .num_dapm_routes = ARRAY_SIZE(cs42l84_audio_map), 343 + .endianness = 1, 344 + }; 345 + 346 + struct cs42l84_pll_params { 347 + u32 bclk; 348 + u8 mclk_src_sel; 349 + u8 bclk_prediv; 350 + u8 pll_div_int; 351 + u32 pll_div_frac; 352 + u8 pll_mode; 353 + u8 pll_divout; 354 + u32 mclk_int; 355 + }; 356 + 357 + /* 358 + * Common PLL Settings for given BCLK 359 + */ 360 + static const struct cs42l84_pll_params pll_ratio_table[] = { 361 + { 3072000, 1, 0, 0x40, 0x000000, 0x03, 0x10, 12288000}, 362 + { 6144000, 1, 1, 0x40, 0x000000, 0x03, 0x10, 12288000}, 363 + { 12288000, 0, 0, 0, 0, 0, 0, 12288000}, 364 + { 24576000, 1, 3, 0x40, 0x000000, 0x03, 0x10, 12288000}, 365 + }; 366 + 367 + static int cs42l84_pll_config(struct snd_soc_component *component) 368 + { 369 + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); 370 + int i; 371 + u32 clk; 372 + u32 fsync; 373 + 374 + clk = cs42l84->bclk; 375 + 376 + /* Don't reconfigure if there is an audio stream running */ 377 + if (cs42l84->stream_use) { 378 + if (pll_ratio_table[cs42l84->pll_config].bclk == clk) 379 + return 0; 380 + else 381 + return -EBUSY; 382 + } 383 + 384 + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { 385 + if (pll_ratio_table[i].bclk == clk) { 386 + cs42l84->pll_config = i; 387 + break; 388 + } 389 + } 390 + 391 + if (i == ARRAY_SIZE(pll_ratio_table)) 392 + return -EINVAL; 393 + 394 + /* Set up the LRCLK */ 395 + fsync = clk / cs42l84->srate; 396 + if (((fsync * cs42l84->srate) != clk) 397 + || ((fsync % 2) != 0)) { 398 + dev_err(component->dev, 399 + "Unsupported bclk %d/sample rate %d\n", 400 + clk, cs42l84->srate); 401 + return -EINVAL; 402 + } 403 + 404 + /* Set the LRCLK period */ 405 + snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL2, 406 + CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO, 407 + FIELD_PREP(CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO, fsync & 0x7f)); 408 + snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL3, 409 + CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI, 410 + FIELD_PREP(CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI, fsync >> 7)); 411 + 412 + /* Save what the MCLK will be */ 413 + switch (pll_ratio_table[i].mclk_int) { 414 + case 12000000: 415 + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12MHZ; 416 + break; 417 + case 12288000: 418 + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12_288KHZ; 419 + break; 420 + case 24000000: 421 + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24MHZ; 422 + break; 423 + case 24576000: 424 + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24_576KHZ; 425 + break; 426 + } 427 + 428 + snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_EN, 0); 429 + 430 + if (pll_ratio_table[i].mclk_src_sel) { 431 + /* Configure PLL */ 432 + snd_soc_component_update_bits(component, 433 + CS42L84_CCM_CTL3, CS42L84_CCM_CTL3_REFCLK_DIV, 434 + FIELD_PREP(CS42L84_CCM_CTL3_REFCLK_DIV, pll_ratio_table[i].bclk_prediv)); 435 + snd_soc_component_write(component, 436 + CS42L84_PLL_DIV_INT, 437 + pll_ratio_table[i].pll_div_int); 438 + snd_soc_component_write(component, 439 + CS42L84_PLL_DIV_FRAC0, 440 + pll_ratio_table[i].pll_div_frac); 441 + snd_soc_component_write(component, 442 + CS42L84_PLL_DIV_FRAC1, 443 + pll_ratio_table[i].pll_div_frac >> 8); 444 + snd_soc_component_write(component, 445 + CS42L84_PLL_DIV_FRAC2, 446 + pll_ratio_table[i].pll_div_frac >> 16); 447 + snd_soc_component_update_bits(component, 448 + CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_MODE, 449 + FIELD_PREP(CS42L84_PLL_CTL1_MODE, pll_ratio_table[i].pll_mode)); 450 + snd_soc_component_write(component, 451 + CS42L84_PLL_DIVOUT, 452 + pll_ratio_table[i].pll_divout); 453 + } 454 + 455 + return 0; 456 + } 457 + 458 + static int cs42l84_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 459 + { 460 + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 461 + case SND_SOC_DAIFMT_BC_FC: 462 + break; 463 + default: 464 + return -EINVAL; 465 + } 466 + 467 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 468 + case SND_SOC_DAIFMT_I2S: 469 + break; 470 + default: 471 + return -EINVAL; 472 + } 473 + 474 + /* Bitclock/frame inversion */ 475 + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 476 + case SND_SOC_DAIFMT_IB_IF: 477 + break; 478 + default: 479 + return -EINVAL; 480 + } 481 + 482 + return 0; 483 + } 484 + 485 + static int cs42l84_pcm_hw_params(struct snd_pcm_substream *substream, 486 + struct snd_pcm_hw_params *params, 487 + struct snd_soc_dai *dai) 488 + { 489 + struct snd_soc_component *component = dai->component; 490 + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); 491 + int ret; 492 + u32 ccm_samp_rate; 493 + 494 + cs42l84->srate = params_rate(params); 495 + 496 + ret = cs42l84_pll_config(component); 497 + if (ret) 498 + return ret; 499 + 500 + switch (params_rate(params)) { 501 + case 44100: 502 + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_44K1HZ; 503 + break; 504 + case 48000: 505 + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_48KHZ; 506 + break; 507 + case 88200: 508 + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_88K2HZ; 509 + break; 510 + case 96000: 511 + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_96KHZ; 512 + break; 513 + case 176400: 514 + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_176K4HZ; 515 + break; 516 + case 192000: 517 + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_192KHZ; 518 + break; 519 + default: 520 + return -EINVAL; 521 + } 522 + 523 + snd_soc_component_write(component, CS42L84_CCM_SAMP_RATE, ccm_samp_rate); 524 + 525 + switch (substream->stream) { 526 + case SNDRV_PCM_STREAM_PLAYBACK: 527 + snd_soc_component_write(component, CS42L84_ASP_RX_CH1_WIDTH, 528 + params_width(params) - 1); 529 + snd_soc_component_write(component, CS42L84_ASP_RX_CH2_WIDTH, 530 + params_width(params) - 1); 531 + break; 532 + 533 + case SNDRV_PCM_STREAM_CAPTURE: 534 + snd_soc_component_write(component, CS42L84_ASP_TX_CH1_WIDTH, 535 + params_width(params) - 1); 536 + snd_soc_component_write(component, CS42L84_ASP_TX_CH2_WIDTH, 537 + params_width(params) - 1); 538 + break; 539 + } 540 + 541 + return 0; 542 + } 543 + 544 + static int cs42l84_set_sysclk(struct snd_soc_dai *dai, 545 + int clk_id, unsigned int freq, int dir) 546 + { 547 + struct snd_soc_component *component = dai->component; 548 + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); 549 + int i; 550 + 551 + if (freq == 0) { 552 + cs42l84->bclk = 0; 553 + return 0; 554 + } 555 + 556 + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { 557 + if (pll_ratio_table[i].bclk == freq) { 558 + cs42l84->bclk = freq; 559 + return 0; 560 + } 561 + } 562 + 563 + dev_err(component->dev, "BCLK %u not supported\n", freq); 564 + 565 + return -EINVAL; 566 + } 567 + 568 + static int cs42l84_mute_stream(struct snd_soc_dai *dai, int mute, int stream) 569 + { 570 + struct snd_soc_component *component = dai->component; 571 + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); 572 + unsigned int regval; 573 + int ret; 574 + 575 + if (mute) { 576 + /* Mute the headphone */ 577 + if (stream == SNDRV_PCM_STREAM_PLAYBACK) 578 + snd_soc_component_update_bits(component, CS42L84_DAC_CTL1, 579 + CS42L84_DAC_CTL1_UNMUTE, 0); 580 + cs42l84->stream_use &= ~(1 << stream); 581 + if (!cs42l84->stream_use) { 582 + /* Must disconnect PLL before stopping it */ 583 + snd_soc_component_write(component, CS42L84_CCM_CTL1, 584 + CS42L84_CCM_CTL1_RCO); 585 + 586 + usleep_range(150, 300); 587 + 588 + snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, 589 + CS42L84_PLL_CTL1_EN, 0); 590 + 591 + snd_soc_component_update_bits(component, CS42L84_CCM_CTL4, 592 + CS42L84_CCM_CTL4_REFCLK_EN, 0); 593 + } 594 + } else { 595 + if (!cs42l84->stream_use) { 596 + /* SCLK must be running before codec unmute. 597 + * 598 + * Note carried over from CS42L42: 599 + * 600 + * PLL must not be started with ADC and HP both off 601 + * otherwise the FILT+ supply will not charge properly. 602 + * DAPM widgets power-up before stream unmute so at least 603 + * one of the "DAC" or "ADC" widgets will already have 604 + * powered-up. 605 + */ 606 + 607 + snd_soc_component_update_bits(component, CS42L84_CCM_CTL4, 608 + CS42L84_CCM_CTL4_REFCLK_EN, 609 + CS42L84_CCM_CTL4_REFCLK_EN); 610 + 611 + if (pll_ratio_table[cs42l84->pll_config].mclk_src_sel) { 612 + snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, 613 + CS42L84_PLL_CTL1_EN, 614 + CS42L84_PLL_CTL1_EN); 615 + /* TODO: should we be doing something with divout here? */ 616 + 617 + ret = regmap_read_poll_timeout(cs42l84->regmap, 618 + CS42L84_PLL_LOCK_STATUS, 619 + regval, 620 + (regval & CS42L84_PLL_LOCK_STATUS_LOCKED), 621 + CS42L84_PLL_LOCK_POLL_US, 622 + CS42L84_PLL_LOCK_TIMEOUT_US); 623 + if (ret < 0) 624 + dev_warn(component->dev, "PLL failed to lock: %d\n", ret); 625 + 626 + if (regval & CS42L84_PLL_LOCK_STATUS_ERROR) 627 + dev_warn(component->dev, "PLL lock error\n"); 628 + 629 + /* PLL must be running to drive glitchless switch logic */ 630 + snd_soc_component_update_bits(component, 631 + CS42L84_CCM_CTL1, 632 + CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ, 633 + FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_PLL) 634 + | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f)); 635 + usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2); 636 + } else { 637 + snd_soc_component_update_bits(component, 638 + CS42L84_CCM_CTL1, 639 + CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ, 640 + FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_BCLK) 641 + | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f)); 642 + usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2); 643 + } 644 + } 645 + cs42l84->stream_use |= 1 << stream; 646 + 647 + if (stream == SNDRV_PCM_STREAM_PLAYBACK) 648 + /* Un-mute the headphone */ 649 + snd_soc_component_update_bits(component, CS42L84_DAC_CTL1, 650 + CS42L84_DAC_CTL1_UNMUTE, 651 + CS42L84_DAC_CTL1_UNMUTE); 652 + } 653 + 654 + return 0; 655 + } 656 + 657 + static const struct snd_soc_dai_ops cs42l84_ops = { 658 + .hw_params = cs42l84_pcm_hw_params, 659 + .set_fmt = cs42l84_set_dai_fmt, 660 + .set_sysclk = cs42l84_set_sysclk, 661 + .mute_stream = cs42l84_mute_stream, 662 + }; 663 + 664 + #define CS42L84_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 665 + SNDRV_PCM_FMTBIT_S24_LE |\ 666 + SNDRV_PCM_FMTBIT_S32_LE) 667 + 668 + static struct snd_soc_dai_driver cs42l84_dai = { 669 + .name = "cs42l84", 670 + .playback = { 671 + .stream_name = "Playback", 672 + .channels_min = 1, 673 + .channels_max = 2, 674 + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, 675 + .formats = CS42L84_FORMATS, 676 + }, 677 + .capture = { 678 + .stream_name = "Capture", 679 + .channels_min = 1, 680 + .channels_max = 1, 681 + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, 682 + .formats = CS42L84_FORMATS, 683 + }, 684 + .symmetric_rate = 1, 685 + .symmetric_sample_bits = 1, 686 + .ops = &cs42l84_ops, 687 + }; 688 + 689 + struct cs42l84_irq_params { 690 + u16 status_addr; 691 + u16 mask_addr; 692 + u8 mask; 693 + }; 694 + 695 + static const struct cs42l84_irq_params irq_params_table[] = { 696 + {CS42L84_TSRS_PLUG_INT_STATUS, CS42L84_TSRS_PLUG_INT_MASK, 697 + CS42L84_TSRS_PLUG_VAL_MASK} 698 + }; 699 + 700 + static void cs42l84_detect_hs(struct cs42l84_private *cs42l84) 701 + { 702 + unsigned int reg; 703 + 704 + /* Power up HSBIAS */ 705 + regmap_update_bits(cs42l84->regmap, 706 + CS42L84_MISC_DET_CTL, 707 + CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE, 708 + FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 3) | /* 2.7 V */ 709 + FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0)); 710 + 711 + /* Power up level detection circuitry */ 712 + regmap_update_bits(cs42l84->regmap, 713 + CS42L84_MISC_DET_CTL, 714 + CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET, 0); 715 + 716 + /* TODO: Optimize */ 717 + msleep(50); 718 + 719 + /* Connect HSBIAS in CTIA wiring */ 720 + /* TODO: Should likely be subject of detection */ 721 + regmap_write(cs42l84->regmap, 722 + CS42L84_HS_SWITCH_CTL, 723 + CS42L84_HS_SWITCH_CTL_REF_HS3 | \ 724 + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \ 725 + CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \ 726 + CS42L84_HS_SWITCH_CTL_HSB_HS4); 727 + regmap_update_bits(cs42l84->regmap, 728 + CS42L84_HS_DET_CTL2, 729 + CS42L84_HS_DET_CTL2_SET, 730 + FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 0)); 731 + 732 + regmap_update_bits(cs42l84->regmap, 733 + CS42L84_MISC_DET_CTL, 734 + CS42L84_MISC_DET_CTL_DETECT_MODE, 735 + FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 3)); 736 + 737 + /* TODO: Optimize */ 738 + msleep(50); 739 + 740 + regmap_read(cs42l84->regmap, CS42L84_HS_DET_STATUS2, &reg); 741 + regmap_update_bits(cs42l84->regmap, 742 + CS42L84_MISC_DET_CTL, 743 + CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET, 744 + CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET); 745 + 746 + switch (reg & 0b11) { 747 + case 0b11: /* shorted */ 748 + case 0b00: /* open */ 749 + /* Power down HSBIAS */ 750 + regmap_update_bits(cs42l84->regmap, 751 + CS42L84_MISC_DET_CTL, 752 + CS42L84_MISC_DET_CTL_HSBIAS_CTL, 753 + FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1)); /* 0.0 V */ 754 + break; 755 + } 756 + 757 + switch (reg & 0b11) { 758 + case 0b10: /* load */ 759 + dev_dbg(cs42l84->dev, "Detected mic\n"); 760 + cs42l84->hs_type = SND_JACK_HEADSET; 761 + snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADSET, 762 + SND_JACK_HEADSET); 763 + break; 764 + 765 + case 0b00: /* open */ 766 + dev_dbg(cs42l84->dev, "Detected open circuit on HS4\n"); 767 + fallthrough; 768 + case 0b11: /* shorted */ 769 + default: 770 + snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADPHONE, 771 + SND_JACK_HEADSET); 772 + cs42l84->hs_type = SND_JACK_HEADPHONE; 773 + dev_dbg(cs42l84->dev, "Detected bare headphone (no mic)\n"); 774 + break; 775 + } 776 + } 777 + 778 + static void cs42l84_revert_hs(struct cs42l84_private *cs42l84) 779 + { 780 + /* Power down HSBIAS */ 781 + regmap_update_bits(cs42l84->regmap, 782 + CS42L84_MISC_DET_CTL, 783 + CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE, 784 + FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1) | /* 0.0 V */ 785 + FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0)); 786 + 787 + /* Disconnect HSBIAS */ 788 + regmap_write(cs42l84->regmap, 789 + CS42L84_HS_SWITCH_CTL, 790 + CS42L84_HS_SWITCH_CTL_REF_HS3 | \ 791 + CS42L84_HS_SWITCH_CTL_REF_HS4 | \ 792 + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \ 793 + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \ 794 + CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \ 795 + CS42L84_HS_SWITCH_CTL_GNDHS_HS4); 796 + regmap_update_bits(cs42l84->regmap, 797 + CS42L84_HS_DET_CTL2, 798 + CS42L84_HS_DET_CTL2_SET, 799 + FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2)); 800 + } 801 + 802 + static void cs42l84_set_interrupt_masks(struct cs42l84_private *cs42l84, 803 + unsigned int val) 804 + { 805 + regmap_update_bits(cs42l84->regmap, CS42L84_TSRS_PLUG_INT_MASK, 806 + CS42L84_RS_PLUG | CS42L84_RS_UNPLUG | 807 + CS42L84_TS_PLUG | CS42L84_TS_UNPLUG, 808 + val); 809 + } 810 + 811 + static irqreturn_t cs42l84_irq_thread(int irq, void *data) 812 + { 813 + struct cs42l84_private *cs42l84 = (struct cs42l84_private *)data; 814 + unsigned int stickies[1]; 815 + unsigned int masks[1]; 816 + unsigned int reg; 817 + u8 current_tip_state; 818 + u8 current_ring_state; 819 + int i; 820 + 821 + mutex_lock(&cs42l84->irq_lock); 822 + /* Read sticky registers to clear interrupt */ 823 + for (i = 0; i < ARRAY_SIZE(stickies); i++) { 824 + regmap_read(cs42l84->regmap, irq_params_table[i].status_addr, 825 + &(stickies[i])); 826 + regmap_read(cs42l84->regmap, irq_params_table[i].mask_addr, 827 + &(masks[i])); 828 + stickies[i] = stickies[i] & (~masks[i]) & 829 + irq_params_table[i].mask; 830 + } 831 + 832 + /* When handling plug sene IRQs, we only care about EITHER tip OR ring. 833 + * Ring is useless on remove, and is only useful on insert for 834 + * detecting if the plug state has changed AFTER we have handled the 835 + * tip sense IRQ, e.g. if the plug was not fully seated within the tip 836 + * sense debounce time. 837 + */ 838 + 839 + if ((~masks[0]) & irq_params_table[0].mask) { 840 + regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, &reg); 841 + 842 + current_tip_state = (((char) reg) & 843 + (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >> 844 + CS42L84_TS_PLUG_SHIFT; 845 + 846 + if (current_tip_state != cs42l84->tip_state) { 847 + cs42l84->tip_state = current_tip_state; 848 + switch (current_tip_state) { 849 + case CS42L84_PLUG: 850 + dev_dbg(cs42l84->dev, "Plug event\n"); 851 + 852 + cs42l84_detect_hs(cs42l84); 853 + 854 + /* 855 + * Check the tip sense status again, and possibly invalidate 856 + * the detection result 857 + * 858 + * Thanks to debounce, this should reliably indicate if the tip 859 + * was disconnected at any point during the detection procedure. 860 + */ 861 + regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, &reg); 862 + current_tip_state = (((char) reg) & 863 + (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >> 864 + CS42L84_TS_PLUG_SHIFT; 865 + if (current_tip_state != CS42L84_PLUG) { 866 + dev_dbg(cs42l84->dev, "Wobbly connection, detection invalidated\n"); 867 + cs42l84->tip_state = CS42L84_UNPLUG; 868 + cs42l84_revert_hs(cs42l84); 869 + } 870 + 871 + /* Unmask ring sense interrupts */ 872 + cs42l84_set_interrupt_masks(cs42l84, 0); 873 + break; 874 + case CS42L84_UNPLUG: 875 + cs42l84->ring_state = CS42L84_UNPLUG; 876 + dev_dbg(cs42l84->dev, "Unplug event\n"); 877 + 878 + cs42l84_revert_hs(cs42l84); 879 + cs42l84->hs_type = 0; 880 + snd_soc_jack_report(cs42l84->jack, 0, 881 + SND_JACK_HEADSET); 882 + 883 + /* Mask ring sense interrupts */ 884 + cs42l84_set_interrupt_masks(cs42l84, 885 + CS42L84_RS_PLUG | CS42L84_RS_UNPLUG); 886 + break; 887 + default: 888 + cs42l84->ring_state = CS42L84_TRANS; 889 + break; 890 + } 891 + 892 + mutex_unlock(&cs42l84->irq_lock); 893 + 894 + return IRQ_HANDLED; 895 + } 896 + 897 + /* Tip state didn't change, we must've got a ring sense IRQ */ 898 + current_ring_state = (((char) reg) & 899 + (CS42L84_RS_PLUG | CS42L84_RS_UNPLUG)) >> 900 + CS42L84_RS_PLUG_SHIFT; 901 + 902 + if (current_ring_state != cs42l84->ring_state) { 903 + cs42l84->ring_state = current_ring_state; 904 + if (current_ring_state == CS42L84_PLUG) 905 + cs42l84_detect_hs(cs42l84); 906 + } 907 + } 908 + 909 + mutex_unlock(&cs42l84->irq_lock); 910 + 911 + return IRQ_HANDLED; 912 + } 913 + 914 + static void cs42l84_setup_plug_detect(struct cs42l84_private *cs42l84) 915 + { 916 + unsigned int reg; 917 + 918 + /* Set up plug detection */ 919 + regmap_update_bits(cs42l84->regmap, CS42L84_MIC_DET_CTL4, 920 + CS42L84_MIC_DET_CTL4_LATCH_TO_VP, 921 + CS42L84_MIC_DET_CTL4_LATCH_TO_VP); 922 + regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL2, 923 + CS42L84_TIP_SENSE_CTL2_MODE, 924 + FIELD_PREP(CS42L84_TIP_SENSE_CTL2_MODE, CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET)); 925 + regmap_update_bits(cs42l84->regmap, CS42L84_RING_SENSE_CTL, 926 + CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 | 927 + CS42L84_RING_SENSE_CTL_RISETIME | CS42L84_RING_SENSE_CTL_FALLTIME, 928 + CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 | 929 + FIELD_PREP(CS42L84_RING_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_125MS) | 930 + FIELD_PREP(CS42L84_RING_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS)); 931 + regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL, 932 + CS42L84_TIP_SENSE_CTL_INV | 933 + CS42L84_TIP_SENSE_CTL_RISETIME | CS42L84_TIP_SENSE_CTL_FALLTIME, 934 + CS42L84_TIP_SENSE_CTL_INV | 935 + FIELD_PREP(CS42L84_TIP_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_500MS) | 936 + FIELD_PREP(CS42L84_TIP_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS)); 937 + regmap_update_bits(cs42l84->regmap, CS42L84_MSM_BLOCK_EN3, 938 + CS42L84_MSM_BLOCK_EN3_TR_SENSE, 939 + CS42L84_MSM_BLOCK_EN3_TR_SENSE); 940 + 941 + /* Save the initial status of the tip sense */ 942 + regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, &reg); 943 + cs42l84->tip_state = (((char) reg) & 944 + (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >> 945 + CS42L84_TS_PLUG_SHIFT; 946 + 947 + /* Set mic-detection threshold */ 948 + regmap_update_bits(cs42l84->regmap, 949 + CS42L84_MIC_DET_CTL1, CS42L84_MIC_DET_CTL1_HS_DET_LEVEL, 950 + FIELD_PREP(CS42L84_MIC_DET_CTL1_HS_DET_LEVEL, 0x2c)); /* ~1.9 V */ 951 + 952 + /* Disconnect HSBIAS (initially) */ 953 + regmap_write(cs42l84->regmap, 954 + CS42L84_HS_SWITCH_CTL, 955 + CS42L84_HS_SWITCH_CTL_REF_HS3 | \ 956 + CS42L84_HS_SWITCH_CTL_REF_HS4 | \ 957 + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \ 958 + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \ 959 + CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \ 960 + CS42L84_HS_SWITCH_CTL_GNDHS_HS4); 961 + regmap_update_bits(cs42l84->regmap, 962 + CS42L84_HS_DET_CTL2, 963 + CS42L84_HS_DET_CTL2_SET | CS42L84_HS_DET_CTL2_CTL, 964 + FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2) | 965 + FIELD_PREP(CS42L84_HS_DET_CTL2_CTL, 0)); 966 + regmap_update_bits(cs42l84->regmap, 967 + CS42L84_HS_CLAMP_DISABLE, 1, 1); 968 + 969 + } 970 + 971 + static int cs42l84_i2c_probe(struct i2c_client *i2c_client) 972 + { 973 + struct cs42l84_private *cs42l84; 974 + int ret, devid; 975 + unsigned int reg; 976 + 977 + cs42l84 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l84_private), 978 + GFP_KERNEL); 979 + if (!cs42l84) 980 + return -ENOMEM; 981 + 982 + cs42l84->dev = &i2c_client->dev; 983 + i2c_set_clientdata(i2c_client, cs42l84); 984 + mutex_init(&cs42l84->irq_lock); 985 + 986 + cs42l84->regmap = devm_regmap_init_i2c(i2c_client, &cs42l84_regmap); 987 + if (IS_ERR(cs42l84->regmap)) { 988 + ret = PTR_ERR(cs42l84->regmap); 989 + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); 990 + return ret; 991 + } 992 + 993 + /* Reset the Device */ 994 + cs42l84->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, 995 + "reset", GPIOD_OUT_LOW); 996 + if (IS_ERR(cs42l84->reset_gpio)) { 997 + ret = PTR_ERR(cs42l84->reset_gpio); 998 + goto err_disable_noreset; 999 + } 1000 + 1001 + if (cs42l84->reset_gpio) { 1002 + dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); 1003 + gpiod_set_value_cansleep(cs42l84->reset_gpio, 1); 1004 + } 1005 + usleep_range(CS42L84_BOOT_TIME_US, CS42L84_BOOT_TIME_US * 2); 1006 + 1007 + /* Request IRQ if one was specified */ 1008 + if (i2c_client->irq) { 1009 + ret = request_threaded_irq(i2c_client->irq, 1010 + NULL, cs42l84_irq_thread, 1011 + IRQF_ONESHOT, 1012 + "cs42l84", cs42l84); 1013 + if (ret == -EPROBE_DEFER) { 1014 + goto err_disable_noirq; 1015 + } else if (ret != 0) { 1016 + dev_err(&i2c_client->dev, 1017 + "Failed to request IRQ: %d\n", ret); 1018 + goto err_disable_noirq; 1019 + } 1020 + } 1021 + 1022 + /* initialize codec */ 1023 + devid = cirrus_read_device_id(cs42l84->regmap, CS42L84_DEVID); 1024 + if (devid < 0) { 1025 + ret = devid; 1026 + dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); 1027 + goto err_disable; 1028 + } 1029 + 1030 + if (devid != CS42L84_CHIP_ID) { 1031 + dev_err(&i2c_client->dev, 1032 + "CS42L84 Device ID (%X). Expected %X\n", 1033 + devid, CS42L84_CHIP_ID); 1034 + ret = -EINVAL; 1035 + goto err_disable; 1036 + } 1037 + 1038 + ret = regmap_read(cs42l84->regmap, CS42L84_REVID, &reg); 1039 + if (ret < 0) { 1040 + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); 1041 + goto err_shutdown; 1042 + } 1043 + 1044 + dev_info(&i2c_client->dev, 1045 + "Cirrus Logic CS42L84, Revision: %02X\n", reg & 0xFF); 1046 + 1047 + /* Setup plug detection */ 1048 + cs42l84_setup_plug_detect(cs42l84); 1049 + 1050 + /* Mask ring sense interrupts */ 1051 + cs42l84_set_interrupt_masks(cs42l84, CS42L84_RS_PLUG | CS42L84_RS_UNPLUG); 1052 + 1053 + /* Register codec for machine driver */ 1054 + ret = devm_snd_soc_register_component(&i2c_client->dev, 1055 + &soc_component_dev_cs42l84, &cs42l84_dai, 1); 1056 + if (ret < 0) 1057 + goto err_shutdown; 1058 + 1059 + return 0; 1060 + 1061 + err_shutdown: 1062 + /* Nothing to do */ 1063 + 1064 + err_disable: 1065 + if (i2c_client->irq) 1066 + free_irq(i2c_client->irq, cs42l84); 1067 + 1068 + err_disable_noirq: 1069 + gpiod_set_value_cansleep(cs42l84->reset_gpio, 0); 1070 + err_disable_noreset: 1071 + return ret; 1072 + } 1073 + 1074 + static void cs42l84_i2c_remove(struct i2c_client *i2c_client) 1075 + { 1076 + struct cs42l84_private *cs42l84 = i2c_get_clientdata(i2c_client); 1077 + 1078 + if (i2c_client->irq) 1079 + free_irq(i2c_client->irq, cs42l84); 1080 + 1081 + gpiod_set_value_cansleep(cs42l84->reset_gpio, 0); 1082 + } 1083 + 1084 + static const struct of_device_id cs42l84_of_match[] = { 1085 + { .compatible = "cirrus,cs42l84", }, 1086 + {} 1087 + }; 1088 + MODULE_DEVICE_TABLE(of, cs42l84_of_match); 1089 + 1090 + static const struct i2c_device_id cs42l84_id[] = { 1091 + {"cs42l84", 0}, 1092 + {} 1093 + }; 1094 + MODULE_DEVICE_TABLE(i2c, cs42l84_id); 1095 + 1096 + static struct i2c_driver cs42l84_i2c_driver = { 1097 + .driver = { 1098 + .name = "cs42l84", 1099 + .of_match_table = of_match_ptr(cs42l84_of_match), 1100 + }, 1101 + .id_table = cs42l84_id, 1102 + .probe = cs42l84_i2c_probe, 1103 + .remove = cs42l84_i2c_remove, 1104 + }; 1105 + 1106 + module_i2c_driver(cs42l84_i2c_driver); 1107 + 1108 + MODULE_DESCRIPTION("ASoC CS42L84 driver"); 1109 + MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>"); 1110 + MODULE_AUTHOR("Hector Martin <marcan@marcan.st>"); 1111 + MODULE_AUTHOR("James Calligeros <jcalligeros99@gmail.com>"); 1112 + MODULE_LICENSE("GPL");
+210
sound/soc/codecs/cs42l84.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) The Asahi Linux Contributors 4 + * 5 + * Based on sound/soc/codecs/cs42l42.h 6 + * 7 + * Copyright 2016 Cirrus Logic, Inc. 8 + */ 9 + 10 + 11 + #ifndef __CS42L84_H__ 12 + #define __CS42L84_H__ 13 + 14 + #include <linux/bits.h> 15 + 16 + #define CS42L84_CHIP_ID 0x42a84 17 + 18 + #define CS42L84_DEVID 0x0000 19 + #define CS42L84_REVID 0x73fe 20 + #define CS42L84_FRZ_CTL 0x0006 21 + #define CS42L84_FRZ_CTL_ENGAGE BIT(0) 22 + 23 + #define CS42L84_TSRS_PLUG_INT_STATUS 0x0400 24 + #define CS42L84_TSRS_PLUG_INT_MASK 0x0418 25 + #define CS42L84_RS_PLUG_SHIFT 0 26 + #define CS42L84_RS_PLUG BIT(0) 27 + #define CS42L84_RS_UNPLUG BIT(1) 28 + #define CS42L84_TS_PLUG_SHIFT 2 29 + #define CS42L84_TS_PLUG BIT(2) 30 + #define CS42L84_TS_UNPLUG BIT(3) 31 + #define CS42L84_TSRS_PLUG_VAL_MASK GENMASK(3, 0) 32 + #define CS42L84_PLL_LOCK_STATUS 0x040e // probably bit 0x10 33 + #define CS42L84_PLL_LOCK_STATUS_LOCKED BIT(4) 34 + #define CS42L84_PLL_LOCK_STATUS_ERROR BIT(5) 35 + 36 + #define CS42L84_PLUG 3 37 + #define CS42L84_UNPLUG 0 38 + #define CS42L84_TRANS 1 39 + 40 + #define CS42L84_CCM_CTL1 0x0600 41 + #define CS42L84_CCM_CTL1_MCLK_SRC GENMASK(1, 0) 42 + #define CS42L84_CCM_CTL1_MCLK_SRC_RCO 0 43 + #define CS42L84_CCM_CTL1_MCLK_SRC_MCLK 1 44 + #define CS42L84_CCM_CTL1_MCLK_SRC_BCLK 2 45 + #define CS42L84_CCM_CTL1_MCLK_SRC_PLL 3 46 + #define CS42L84_CCM_CTL1_MCLK_FREQ GENMASK(3, 2) 47 + #define CS42L84_CCM_CTL1_MCLK_F_12MHZ 0b00 48 + #define CS42L84_CCM_CTL1_MCLK_F_24MHZ 0b01 49 + #define CS42L84_CCM_CTL1_MCLK_F_12_288KHZ 0b10 50 + #define CS42L84_CCM_CTL1_MCLK_F_24_576KHZ 0b11 51 + #define CS42L84_CCM_CTL1_RCO \ 52 + (FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_RCO) \ 53 + | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, CS42L84_CCM_CTL1_MCLK_F_12MHZ)) 54 + 55 + #define CS42L84_CCM_SAMP_RATE 0x0601 56 + #define CS42L84_CCM_SAMP_RATE_RATE_48KHZ 4 57 + #define CS42L84_CCM_SAMP_RATE_RATE_96KHZ 5 58 + #define CS42L84_CCM_SAMP_RATE_RATE_192KHZ 6 59 + #define CS42L84_CCM_SAMP_RATE_RATE_44K1HZ 12 60 + #define CS42L84_CCM_SAMP_RATE_RATE_88K2HZ 13 61 + #define CS42L84_CCM_SAMP_RATE_RATE_176K4HZ 14 62 + #define CS42L84_CCM_CTL3 0x0602 63 + #define CS42L84_CCM_CTL3_REFCLK_DIV GENMASK(2, 1) 64 + #define CS42L84_CCM_CTL4 0x0603 65 + #define CS42L84_CCM_CTL4_REFCLK_EN BIT(0) 66 + 67 + #define CS42L84_CCM_ASP_CLK_CTRL 0x0608 68 + 69 + #define CS42L84_PLL_CTL1 0x0800 70 + #define CS42L84_PLL_CTL1_EN BIT(0) 71 + #define CS42L84_PLL_CTL1_MODE GENMASK(2, 1) 72 + #define CS42L84_PLL_DIV_FRAC0 0x0804 73 + #define CS42L84_PLL_DIV_FRAC1 0x0805 74 + #define CS42L84_PLL_DIV_FRAC2 0x0806 75 + #define CS42L84_PLL_DIV_INT 0x0807 76 + #define CS42L84_PLL_DIVOUT 0x0808 77 + 78 + #define CS42L84_RING_SENSE_CTL 0x1282 79 + #define CS42L84_RING_SENSE_CTL_INV BIT(7) 80 + #define CS42L84_RING_SENSE_CTL_UNK1 BIT(6) 81 + #define CS42L84_RING_SENSE_CTL_FALLTIME GENMASK(5, 3) 82 + #define CS42L84_RING_SENSE_CTL_RISETIME GENMASK(2, 0) 83 + #define CS42L84_TIP_SENSE_CTL 0x1283 84 + #define CS42L84_TIP_SENSE_CTL_INV BIT(7) 85 + #define CS42L84_TIP_SENSE_CTL_FALLTIME GENMASK(5, 3) 86 + #define CS42L84_TIP_SENSE_CTL_RISETIME GENMASK(2, 0) 87 + 88 + #define CS42L84_TSRS_PLUG_STATUS 0x1288 89 + 90 + #define CS42L84_TIP_SENSE_CTL2 0x1473 91 + #define CS42L84_TIP_SENSE_CTL2_MODE GENMASK(7, 6) 92 + #define CS42L84_TIP_SENSE_CTL2_MODE_DISABLED 0b00 93 + #define CS42L84_TIP_SENSE_CTL2_MODE_DIG_INPUT 0b01 94 + #define CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET 0b11 95 + #define CS42L84_TIP_SENSE_CTL2_INV BIT(5) 96 + 97 + #define CS42L84_MISC_DET_CTL 0x1474 98 + #define CS42L84_MISC_DET_CTL_DETECT_MODE GENMASK(4, 3) 99 + #define CS42L84_MISC_DET_CTL_HSBIAS_CTL GENMASK(2, 1) 100 + #define CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET BIT(0) 101 + 102 + #define CS42L84_MIC_DET_CTL1 0x1475 103 + #define CS42L84_MIC_DET_CTL1_HS_DET_LEVEL GENMASK(5, 0) 104 + 105 + #define CS42L84_MIC_DET_CTL4 0x1477 106 + #define CS42L84_MIC_DET_CTL4_LATCH_TO_VP BIT(1) 107 + 108 + #define CS42L84_HS_DET_STATUS2 0x147d 109 + 110 + #define CS42L84_MSM_BLOCK_EN1 0x1800 111 + #define CS42L84_MSM_BLOCK_EN2 0x1801 112 + #define CS42L84_MSM_BLOCK_EN2_ASP_SHIFT 6 113 + #define CS42L84_MSM_BLOCK_EN2_BUS_SHIFT 5 114 + #define CS42L84_MSM_BLOCK_EN2_DAC_SHIFT 4 115 + #define CS42L84_MSM_BLOCK_EN2_ADC_SHIFT 3 116 + #define CS42L84_MSM_BLOCK_EN3 0x1802 117 + #define CS42L84_MSM_BLOCK_EN3_TR_SENSE BIT(3) 118 + 119 + #define CS42L84_HS_DET_CTL2 0x1811 120 + #define CS42L84_HS_DET_CTL2_CTL GENMASK(7, 6) 121 + #define CS42L84_HS_DET_CTL2_SET GENMASK(5, 4) 122 + #define CS42L84_HS_DET_CTL2_REF BIT(3) 123 + #define CS42L84_HS_DET_CTL2_AUTO_TIME GENMASK(1, 0) 124 + 125 + #define CS42L84_HS_SWITCH_CTL 0x1812 126 + #define CS42L84_HS_SWITCH_CTL_REF_HS3 BIT(7) 127 + #define CS42L84_HS_SWITCH_CTL_REF_HS4 BIT(6) 128 + #define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 BIT(5) 129 + #define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 BIT(4) 130 + #define CS42L84_HS_SWITCH_CTL_HSB_HS3 BIT(3) 131 + #define CS42L84_HS_SWITCH_CTL_HSB_HS4 BIT(2) 132 + #define CS42L84_HS_SWITCH_CTL_GNDHS_HS3 BIT(1) 133 + #define CS42L84_HS_SWITCH_CTL_GNDHS_HS4 BIT(0) 134 + 135 + #define CS42L84_HS_CLAMP_DISABLE 0x1813 136 + 137 + #define CS42L84_ADC_CTL1 0x2000 138 + #define CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT 6 139 + #define CS42L84_ADC_CTL1_PGA_GAIN_SHIFT 0 140 + #define CS42L84_ADC_CTL4 0x2003 141 + #define CS42L84_ADC_CTL4_WNF_CF_SHIFT 4 142 + #define CS42L84_ADC_CTL4_WNF_EN_SHIFT 3 143 + #define CS42L84_ADC_CTL4_HPF_CF_SHIFT 1 144 + #define CS42L84_ADC_CTL4_HPF_EN_SHIFT 0 145 + 146 + #define CS42L84_DAC_CTL1 0x3000 147 + #define CS42L84_DAC_CTL1_UNMUTE BIT(0) 148 + //#define CS42L84_DAC_CTL1_DACB_INV_SHIFT 1 149 + //#define CS42L84_DAC_CTL1_DACA_INV_SHIFT 0 150 + #define CS42L84_DAC_CTL2 0x3001 151 + 152 + #define CS42L84_DAC_CHA_VOL_LSB 0x3004 153 + #define CS42L84_DAC_CHA_VOL_MSB 0x3005 154 + #define CS42L84_DAC_CHB_VOL_LSB 0x3006 155 + #define CS42L84_DAC_CHB_VOL_MSB 0x3007 156 + #define CS42L84_HP_VOL_CTL 0x3020 157 + #define CS42L84_HP_VOL_CTL_ZERO_CROSS BIT(1) 158 + #define CS42L84_HP_VOL_CTL_SOFT BIT(0) 159 + 160 + #define CS42L84_SRC_ASP_RX_CH1 0b1101 161 + #define CS42L84_SRC_ASP_RX_CH2 0b1110 162 + 163 + #define CS42L84_BUS_ASP_TX_SRC 0x4000 164 + #define CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT 0 165 + #define CS42L84_BUS_DAC_SRC 0x4001 166 + #define CS42L84_BUS_DAC_SRC_DACA_SHIFT 0 167 + #define CS42L84_BUS_DAC_SRC_DACB_SHIFT 4 168 + 169 + #define CS42L84_ASP_CTL 0x5000 170 + #define CS42L84_ASP_CTL_BCLK_EN_SHIFT 1 171 + #define CS42L84_ASP_CTL_TDM_MODE BIT(2) 172 + #define CS42L84_ASP_FSYNC_CTL2 0x5010 173 + #define CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO GENMASK(7, 1) 174 + #define CS42L84_ASP_FSYNC_CTL3 0x5011 175 + #define CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI GENMASK(4, 0) 176 + #define CS42L84_ASP_DATA_CTL 0x5018 177 + 178 + #define CS42L84_ASP_RX_EN 0x5020 179 + #define CS42L84_ASP_RX_EN_CH1_SHIFT 0 180 + #define CS42L84_ASP_RX_EN_CH2_SHIFT 1 181 + #define CS42L84_ASP_TX_EN 0x5024 182 + #define CS42L84_ASP_TX_EN_CH1_SHIFT 0 183 + 184 + #define CS42L84_ASP_RX_CH1_CTL1 0x5028 185 + #define CS42L84_ASP_RX_CH1_CTL2 0x5029 186 + #define CS42L84_ASP_RX_CH1_WIDTH 0x502a 187 + #define CS42L84_ASP_RX_CH2_CTL1 0x502c 188 + #define CS42L84_ASP_RX_CH2_CTL2 0x502d 189 + #define CS42L84_ASP_RX_CH2_WIDTH 0x502e 190 + 191 + #define CS42L84_ASP_RX_CHx_CTL1_EDGE BIT(0) 192 + #define CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB GENMASK(7, 1) 193 + #define CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB GENMASK(2, 0) 194 + 195 + #define CS42L84_ASP_TX_CH1_CTL1 0x5068 196 + #define CS42L84_ASP_TX_CH1_CTL2 0x5069 197 + #define CS42L84_ASP_TX_CH1_WIDTH 0x506a 198 + #define CS42L84_ASP_TX_CH2_CTL1 0x506c 199 + #define CS42L84_ASP_TX_CH2_CTL2 0x506d 200 + #define CS42L84_ASP_TX_CH2_WIDTH 0x506e 201 + 202 + #define CS42L84_DEBOUNCE_TIME_125MS 0b001 203 + #define CS42L84_DEBOUNCE_TIME_500MS 0b011 204 + 205 + #define CS42L84_BOOT_TIME_US 3000 206 + #define CS42L84_CLOCK_SWITCH_DELAY_US 150 207 + #define CS42L84_PLL_LOCK_POLL_US 250 208 + #define CS42L84_PLL_LOCK_TIMEOUT_US 1250 209 + 210 + #endif /* __CS42L84_H__ */