// SPDX-License-Identifier: GPL-2.0-or-later /* * it6621-codec.c -- IT6621 ALSA SoC audio codec driver * * Copyright (c) 2024 Rockchip Electronics Co., Ltd. * Author: Jason Zhang */ #include #include #include #include #include #include #include #include #include #include "it6621.h" #include "it6621-clk.h" #include "it6621-earc.h" #include "it6621-uapi.h" #include "it6621-reg-bank0.h" #include "it6621-reg-bank1.h" #include "it6621-reg-cec.h" #define IT6621_I2C_NAME "it6621" static const struct regmap_range_cfg it6621_range = { .range_min = IT6621_REG_VENDOR_ID_LOW, .range_max = IT6621_REG_TX_PKT3_PB15, .selector_reg = IT6621_REG_SYS_CTRL3, .selector_mask = IT6621_BANK_SEL, .selector_shift = 0, .window_start = 0, .window_len = 256, }; static bool it6621_is_accessible_reg(struct device *dev, unsigned int reg) { if (reg >= IT6621_REG_VENDOR_ID_LOW && reg <= IT6621_REG_TX_PKT3_PB15) return true; return false; } static const struct regmap_config it6621_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = IT6621_REG_TX_PKT3_PB15, .readable_reg = it6621_is_accessible_reg, .writeable_reg = it6621_is_accessible_reg, .ranges = &it6621_range, .num_ranges = 1, }; static int it6621_set_audio_src(struct it6621_priv *priv) { unsigned int src; if (priv->audio_ch >= 15) src = IT6621_AUD_SRC7_SRC0_EN; else if (priv->audio_ch >= 13) src = IT6621_AUD_SRC6_SRC0_EN; else if (priv->audio_ch >= 11) src = IT6621_AUD_SRC5_SRC0_EN; else if (priv->audio_ch >= 9) src = IT6621_AUD_SRC4_SRC0_EN; else if (priv->audio_ch >= 7 || priv->i2s_hbr) src = IT6621_AUD_SRC3_SRC0_EN; else if (priv->audio_ch >= 5) src = IT6621_AUD_SRC2_SRC0_EN; else if (priv->audio_ch >= 3) src = IT6621_AUD_SRC1_SRC0_EN; else src = IT6621_AUD_SRC0_EN; /* Set input audio source */ regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_SRC_SEL, IT6621_TX_AUD_SRC, priv->audio_src); /* Update source number */ regmap_write(priv->regmap, IT6621_REG_TX_AUD_SRC_EN, src); /* Update ACLK detect after changing source number */ regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_DIS); regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_EN); return 0; } static int it6621_set_i2s_tdm_fmt(struct it6621_priv *priv) { unsigned int wl; if ((priv->i2s_wl == IEC958_AES4_CON_WORDLEN_24_20) || (priv->i2s_wl == (IEC958_AES4_CON_WORDLEN_20_16 | IEC958_AES4_CON_MAX_WORDLEN_24))) wl = IT6621_I2S_TDM_20BIT; else if (priv->i2s_wl == (IEC958_AES4_CON_WORDLEN_24_20 | IEC958_AES4_CON_MAX_WORDLEN_24)) wl = IT6621_I2S_TDM_24BIT; else wl = IT6621_I2S_TDM_16BIT; regmap_update_bits(priv->regmap, IT6621_REG_TX_I2S, IT6621_I2S_TDM_WORD_LEN | IT6621_I2S_FMT, wl | priv->i2s_fmt); regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL3, IT6621_TX_I2S_HBR_EN_SEL | IT6621_TX_TDM_CH_NUM, priv->i2s_hbr | ((priv->audio_ch / 2) - 1)); return 0; } static int it6621_set_spdif_fmt(struct it6621_priv *priv) { if (priv->audio_type == IT6621_AUD_TYPE_NLPCM) regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, IT6621_TX_V_BIT_VAL, IT6621_TX_V_BIT_NLPCM); else regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, IT6621_TX_V_BIT_VAL, IT6621_TX_V_BIT_LPCM); return 0; } static int it6621_set_auto_audio_fmt(struct it6621_priv *priv) { unsigned int auto_fmt; if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && (priv->audio_ch == 8)) { auto_fmt = IT6621_TX_AUTO_AUD_FMT_DIS; } else { /* NOTE: Disable auto audio format in SPDIF */ if (priv->audio_src == IT6621_AUD_SRC_SPDIF) auto_fmt = IT6621_TX_AUTO_AUD_FMT_DIS; else auto_fmt = IT6621_TX_AUTO_AUD_FMT_EN; } regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, IT6621_TX_AUTO_AUD_FMT_SEL, auto_fmt); return 0; } static int it6621_set_audio_fmt(struct it6621_priv *priv) { int ret; /* Set audio source */ ret = it6621_set_audio_src(priv); if (ret < 0) return ret; /* RX I2S/TDM word length */ ret = it6621_set_i2s_tdm_fmt(priv); if (ret < 0) return ret; /* SPDIF V bit */ ret = it6621_set_spdif_fmt(priv); if (ret < 0) return ret; /* For Compress audio LayoutB */ ret = it6621_set_auto_audio_fmt(priv); if (ret < 0) return ret; /* eARC TX Channel Status */ ret = it6621_set_channel_status(priv); if (ret < 0) return ret; return 0; } static int it6621_update_config(struct it6621_priv *priv) { if (priv->force_16ch) priv->audio_ch = 16; if ((priv->audio_fs == IT6621_AES3_CON_FS_256000) || (priv->audio_fs == IT6621_AES3_CON_FS_352000) || (priv->audio_fs == IT6621_AES3_CON_FS_384000) || (priv->audio_fs == IT6621_AES3_CON_FS_512000) || (priv->audio_fs == IT6621_AES3_CON_FS_705000) || (priv->audio_fs == IEC958_AES3_CON_FS_768000) || (priv->audio_fs == IT6621_AES3_CON_FS_1024000) || (priv->audio_fs == IT6621_AES3_CON_FS_1411000) || (priv->audio_fs == IT6621_AES3_CON_FS_1536000)) priv->audio_hbr = 1; else priv->audio_hbr = 0; if (priv->audio_input_hbr == 1) priv->audio_hbr = 1; if (priv->audio_hbr) priv->audio_type = IT6621_AUD_TYPE_NLPCM; if ((priv->audio_src == IT6621_AUD_SRC_I2S) && priv->audio_hbr && priv->i2s_hbr_enabled) priv->i2s_hbr = IT6621_TX_I2S_HBR_EN; else priv->i2s_hbr = IT6621_TX_I2S_HBR_DIS; if ((priv->audio_src == IT6621_AUD_SRC_I2S) && (priv->audio_type == IT6621_AUD_TYPE_NLPCM)) priv->i2s_nlpcm_enabled = IT6621_TX_NLPCM_I2S_EN; else priv->i2s_nlpcm_enabled = IT6621_TX_NLPCM_I2S_DIS; /* NOTE: For Allion AC3 and Allion Astro VG849C test. */ if ((priv->audio_ch > 2) && (priv->audio_type == IT6621_AUD_TYPE_NLPCM)) priv->audio_ch = 2; regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, IT6621_TX_2CH_LAYOUT_SEL | IT6621_TX_NLPCM_I2S_SEL | IT6621_TX_MCH_LPCM_SEL | IT6621_TX_EXT_MUTE_SEL, IT6621_TX_2CH_LAYOUT_DIS | priv->i2s_nlpcm_enabled | IT6621_TX_MCH_LPCM_DIS | IT6621_TX_EXT_MUTE_EN); return 0; } static int it6621_reconfig_aclk(struct it6621_priv *priv) { if (((priv->audio_src == IT6621_AUD_SRC_I2S) && priv->sck_inv_enabled) || ((priv->audio_src == IT6621_AUD_SRC_TDM) && priv->tck_inv_enabled) || ((priv->audio_src == IT6621_AUD_SRC_SPDIF) && priv->mclk_inv_enabled) || ((priv->audio_src == IT6621_AUD_SRC_DSD) && priv->dclk_inv_enabled)) regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2, IT6621_ACLK_INV_SEL, IT6621_ACLK_INV_EN); else regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2, IT6621_ACLK_INV_SEL, IT6621_ACLK_INV_DIS); return 0; } static int it6621_config_audio(struct it6621_priv *priv) { int ret; ret = it6621_update_config(priv); if (ret < 0) return ret; ret = it6621_reconfig_aclk(priv); if (ret < 0) return ret; ret = it6621_set_audio_fmt(priv); if (ret < 0) return ret; return 0; } static int it6621_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct it6621_priv *priv = snd_soc_component_get_drvdata(dai->component); unsigned int state; if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) return 0; set_bit(IT6621_AUDIO_START, &priv->audio_flag); clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); it6621_get_ddfsm_state(priv, &state); if ((state != IT6621_TX_EARC_MODE) && (state != IT6621_TX_ARC_MODE)) { cancel_work_sync(&priv->hpdio_work); schedule_work(&priv->hpdio_work); } priv->config_audio = true; return 0; } static int it6621_mute(struct snd_soc_dai *dai, int mute, int stream) { struct it6621_priv *priv = snd_soc_component_get_drvdata(dai->component); if (stream != SNDRV_PCM_STREAM_PLAYBACK) return 0; if (!priv->force_mute) return 0; /* FIXME: Sometimes unmuting stream does not work */ regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, IT6621_TX_FORCE_MUTE_SEL, mute ? IT6621_TX_FORCE_MUTE_EN : IT6621_TX_FORCE_MUTE_DIS); return 0; } static void it6621_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct it6621_priv *priv = snd_soc_component_get_drvdata(dai->component); clear_bit(IT6621_AUDIO_START, &priv->audio_flag); clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); } static int it6621_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct it6621_priv *priv = snd_soc_dai_get_drvdata(dai); int ret = 0; if (!freq) return 0; ret = clk_set_rate(priv->mclk, freq); if (ret) dev_err(priv->dev, "failed to set mclk\n"); return ret; } static int it6621_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct it6621_priv *priv = snd_soc_dai_get_drvdata(dai); unsigned int fs; unsigned int wl; unsigned int ch; int ret; switch (snd_pcm_rate_to_rate_bit(params_rate(params))) { case SNDRV_PCM_RATE_32000: fs = IEC958_AES3_CON_FS_32000; break; case SNDRV_PCM_RATE_44100: fs = IEC958_AES3_CON_FS_44100; break; case SNDRV_PCM_RATE_48000: fs = IEC958_AES3_CON_FS_48000; break; case SNDRV_PCM_RATE_64000: fs = IT6621_AES3_CON_FS_64000; break; case SNDRV_PCM_RATE_88200: fs = IEC958_AES3_CON_FS_88200; break; case SNDRV_PCM_RATE_96000: fs = IEC958_AES3_CON_FS_96000; break; case SNDRV_PCM_RATE_176400: fs = IEC958_AES3_CON_FS_176400; break; case SNDRV_PCM_RATE_192000: fs = IEC958_AES3_CON_FS_192000; break; case SNDRV_PCM_RATE_352800: fs = IT6621_AES3_CON_FS_352000; break; case SNDRV_PCM_RATE_384000: fs = IT6621_AES3_CON_FS_384000; break; default: dev_err(priv->dev, "invalid rate: %d\n", params_rate(params)); return -EINVAL; } switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: wl = IEC958_AES4_CON_WORDLEN_20_16; break; case SNDRV_PCM_FORMAT_S20_3LE: wl = IEC958_AES4_CON_WORDLEN_24_20; break; case SNDRV_PCM_FORMAT_S24_LE: wl = IEC958_AES4_CON_WORDLEN_24_20 | IEC958_AES4_CON_MAX_WORDLEN_24; break; default: dev_err(priv->dev, "invalid format: %d\n", params_format(params)); return -EINVAL; } switch (params_channels(params)) { case 32: case 16: case 8: case 6: case 2: ch = params_channels(params); break; default: dev_err(priv->dev, "invalid channel: %d\n", params_channels(params)); return -EINVAL; } if (priv->config_audio || (priv->audio_fs != fs) || (priv->i2s_wl != wl) || (priv->audio_ch != ch)) { priv->audio_fs = fs; priv->i2s_wl = wl; priv->audio_ch = ch; priv->config_audio = false; ret = it6621_config_audio(priv); if (ret) return ret; } return 0; } static int it6621_probe(struct snd_soc_component *component) { struct it6621_priv *priv; priv = snd_soc_component_get_drvdata(component); priv->mclk = devm_clk_get_optional(component->dev, "mclk"); if (IS_ERR(priv->mclk)) return PTR_ERR(priv->mclk); clk_prepare_enable(priv->mclk); return 0; } static int it6621_suspend(struct snd_soc_component *component) { struct it6621_priv *priv = snd_soc_component_get_drvdata(component); clear_bit(IT6621_ARC_START, &priv->events); clear_bit(IT6621_EARC_CAP_CHG, &priv->events); clear_bit(IT6621_EARC_EDID_OK, &priv->events); clear_bit(IT6621_EARC_BCLK_OK, &priv->events); return 0; } static int it6621_resume(struct snd_soc_component *component) { struct it6621_priv *priv = snd_soc_component_get_drvdata(component); return it6621_earc_init(priv); } static int it6621_audio_cap_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->count = sizeof_field(struct it6621_priv, rxcap); return 0; } static int it6621_audio_cap_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct it6621_priv *priv = snd_soc_component_get_drvdata(component); mutex_lock(&priv->rxcap_lock); memcpy(ucontrol->value.bytes.data, priv->rxcap, sizeof(priv->rxcap)); mutex_unlock(&priv->rxcap_lock); return 0; } static const char *const it6621_ddfsm_enum[] = { "ARC", "eARC", "unknown" }; static int it6621_ddfsm_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = ARRAY_SIZE(it6621_ddfsm_enum); if (uinfo->value.enumerated.item >= ARRAY_SIZE(it6621_ddfsm_enum)) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strscpy(uinfo->value.enumerated.name, it6621_ddfsm_enum[uinfo->value.enumerated.item], sizeof(uinfo->value.enumerated.name)); return 0; } static int it6621_ddfsm_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct it6621_priv *priv = snd_soc_component_get_drvdata(component); unsigned int state; it6621_get_ddfsm_state(priv, &state); if (state == IT6621_TX_ARC_MODE) ucontrol->value.enumerated.item[0] = 0; else if (state == IT6621_TX_EARC_MODE) ucontrol->value.enumerated.item[0] = 1; else ucontrol->value.enumerated.item[0] = 2; return 0; } static int it6621_earc_switch_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0; } static int it6621_earc_switch_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct it6621_priv *priv = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = (priv->earc_enabled == IT6621_TX_EARC_EN) ? 1 : 0; return 0; } static int it6621_earc_switch_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct it6621_priv *priv = snd_soc_component_get_drvdata(component); return it6621_set_earc_enabled(priv, !!ucontrol->value.integer.value[0]); } static int it6621_arc_switch_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0; } static int it6621_arc_switch_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct it6621_priv *priv = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = (priv->arc_enabled == IT6621_TX_ARC_EN) ? 1 : 0; return 0; } static int it6621_arc_switch_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct it6621_priv *priv = snd_soc_component_get_drvdata(component); return it6621_set_arc_enabled(priv, !!ucontrol->value.integer.value[0]); } static const struct snd_kcontrol_new it6621_controls[] = { { .access = (SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE), .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "eARC Audio Capabilities", .info = it6621_audio_cap_ctl_info, .get = it6621_audio_cap_ctl_get, }, { .access = (SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE), .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "eARC DD FSM", .info = it6621_ddfsm_ctl_info, .get = it6621_ddfsm_ctl_get, }, { .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_VOLATILE), .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "eARC Switch", .info = it6621_earc_switch_ctl_info, .get = it6621_earc_switch_ctl_get, .put = it6621_earc_switch_ctl_put, }, { .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_VOLATILE), .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "ARC Switch", .info = it6621_arc_switch_ctl_info, .get = it6621_arc_switch_ctl_get, .put = it6621_arc_switch_ctl_put, }, }; static const struct snd_soc_component_driver it6621_component = { .probe = it6621_probe, .suspend = it6621_suspend, .resume = it6621_resume, .controls = it6621_controls, .num_controls = ARRAY_SIZE(it6621_controls), }; static const struct snd_soc_dai_ops it6621_dai_ops = { .startup = it6621_startup, .set_sysclk = it6621_set_dai_sysclk, .hw_params = it6621_hw_params, .mute_stream = it6621_mute, .shutdown = it6621_shutdown, }; #define IT6621_RATES (SNDRV_PCM_RATE_32000 | \ SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | \ SNDRV_PCM_RATE_64000 | \ SNDRV_PCM_RATE_88200 | \ SNDRV_PCM_RATE_96000 | \ SNDRV_PCM_RATE_176400 | \ SNDRV_PCM_RATE_192000 | \ SNDRV_PCM_RATE_352800 | \ SNDRV_PCM_RATE_384000) #define IT6621_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver it6621_dais[] = { { .name = "it6621-i2s", .playback = { .stream_name = "IT6621 I2S Playback", .channels_min = 2, .channels_max = 16, .rates = IT6621_RATES, .formats = IT6621_FORMATS, }, .ops = &it6621_dai_ops, }, { .name = "it6621-spdif", .playback = { .stream_name = "IT6621 SPDIF Playback", .channels_min = 2, .channels_max = 2, .rates = IT6621_RATES, .formats = IT6621_FORMATS, }, .ops = &it6621_dai_ops, }, { .name = "it6621-dsd", .playback = { .stream_name = "IT6621 DSD Playback", .channels_min = 2, .channels_max = 12, .rates = IT6621_RATES, .formats = IT6621_FORMATS, }, .ops = &it6621_dai_ops, }, }; static int it6621_check_dev(struct it6621_priv *priv) { unsigned int val; regmap_bulk_read(priv->regmap, IT6621_REG_VENDOR_ID_LOW, &val, 2); priv->vid = le16_to_cpu(val); if (priv->vid != IT6621_VENDOR_ID) { dev_err(priv->dev, "invalid vendor id %x\n", priv->vid); return -ENODEV; } regmap_bulk_read(priv->regmap, IT6621_REG_DEV_ID_LOW, &val, 2); priv->devid = le16_to_cpu(val); if (priv->devid != IT6621_DEVICE_ID) { dev_err(priv->dev, "invalid device id %x\n", priv->devid); return -ENODEV; } regmap_read(priv->regmap, IT6621_REG_REV_ID, &val); priv->revid = val; if ((priv->revid != IT6621_REVISION_VARIANT_B0) && (priv->revid != IT6621_REVISION_VARIANT_C0) && (priv->revid != IT6621_REVISION_VARIANT_D0)) { dev_err(priv->dev, "invalid revision id %x\n", priv->revid); return -ENODEV; } return 0; } static void it6621_toggle_hpdio(struct it6621_priv *priv) { mutex_lock(&priv->hpdio_lock); dev_dbg(priv->dev, "toggle hpdio\n"); gpiod_set_value_cansleep(priv->hpdio, 0); /* * NOTE: Toggle HPD signal at least 100ms (suggestion time is about * 1 ~ 1.5 second). */ msleep(100); gpiod_set_value_cansleep(priv->hpdio, 1); mutex_unlock(&priv->hpdio_lock); } static void it6621_hpdio_work(struct work_struct *work) { struct it6621_priv *priv = container_of(work, struct it6621_priv, hpdio_work); it6621_toggle_hpdio(priv); } static int it6621_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct it6621_priv *priv; const char *source; int ret; priv = devm_kzalloc(&client->dev, sizeof(struct it6621_priv), GFP_KERNEL); if (!priv) return -ENOMEM; dev_set_drvdata(&client->dev, priv); priv->client = client; priv->dev = &client->dev; priv->regmap = devm_regmap_init_i2c(client, &it6621_regmap_config); if (IS_ERR(priv->regmap)) { dev_err(priv->dev, "failed to initialize regmap\n"); return PTR_ERR(priv->regmap); } ret = it6621_check_dev(priv); if (ret < 0) return ret; priv->audio_type = IT6621_AUD_TYPE_LPCM; priv->audio_ch = 0; priv->audio_fs = IEC958_AES3_CON_FS_NOTID; priv->i2s_wl = IEC958_AES4_CON_WORDLEN_NOTID; priv->mch_lpcm_enabled = IT6621_TX_MCH_LPCM_DIS; priv->layout_2ch_enabled = IT6621_TX_2CH_LAYOUT_DIS; priv->vcm_sel = IT6621_TX_VCM0; priv->i2s_fmt = IT6621_I2S_FMT_32BIT; priv->rclk_sel = IT6621_RCLK_FREQ_REFCLK_DIV_2; priv->update_avg_enabled = IT6621_UPDATE_AVG_EN; priv->sck_inv_enabled = 0; priv->tck_inv_enabled = 1; priv->mclk_inv_enabled = 1; priv->dclk_inv_enabled = 0; priv->cmo_opt = IT6621_TX_CMO_NORMAL; priv->force_cmo_enabled = IT6621_TX_FORCE_CMO_EN; priv->resync_opt = IT6621_TX_RESYNC_NEW; priv->pkt1_enabled = IT6621_TX_PKT1_DIS; priv->pkt2_enabled = IT6621_TX_PKT2_DIS; priv->pkt3_enabled = IT6621_TX_PKT3_DIS; priv->i2s_hbr_enabled = 1; priv->ubit_opt = IT6621_TX_U_BIT_1BIT_FRAME; priv->c_ch_opt = IT6621_TX_C_CH_OPT1; priv->ecc_opt = IT6621_TX_ECC_U_SWAP; priv->enc_seed = 0xa5c3; priv->enc_opt = IT6621_TX_ENC_OPT3; priv->bclk_inv_enabled = IT6621_BCLK_INV_DIS; priv->nxt_pkt_to_sel = IT6621_TX_NEXT_PKT_TIMEOUT_50US; priv->turn_over_sel = IT6621_TX_TURN_OVER_16US; priv->hb_retry_sel = IT6621_TX_HB_RETRY_0MS; priv->hb_retry_enabled = IT6621_TX_HB_RETRY_EN; priv->cmd_to_enabled = 0; priv->enter_arc_now = IT6621_TX_ARC_NOW_DIS; priv->arc_enabled = IT6621_TX_ARC_EN; priv->earc_enabled = IT6621_TX_EARC_EN; INIT_LIST_HEAD(&priv->fhs); mutex_init(&priv->fhs_lock); mutex_init(&priv->hpdio_lock); mutex_init(&priv->rxcap_lock); INIT_WORK(&priv->hpdio_work, it6621_hpdio_work); ret = it6621_uapi_init(priv); if (ret) { dev_err(priv->dev, "failed to initialize uapi\n"); return ret; } ret = devm_add_action_or_reset(priv->dev, (void(*)(void *))it6621_uapi_remove, priv); if (ret) return ret; ret = device_property_read_string(priv->dev, "ite,audio-source", &source); if (ret) { dev_err(priv->dev, "no input audio source\n"); return ret; } if (!strcmp(source, "i2s")) priv->audio_src = IT6621_AUD_SRC_I2S; else if (!strcmp(source, "spdif")) priv->audio_src = IT6621_AUD_SRC_SPDIF; else if (!strcmp(source, "tdm")) priv->audio_src = IT6621_AUD_SRC_TDM; else if (!strcmp(source, "dsd")) priv->audio_src = IT6621_AUD_SRC_DSD; else return -EINVAL; if (device_property_read_bool(priv->dev, "ite,force-arc")) priv->force_arc = 1; if (device_property_read_bool(priv->dev, "ite,force-earc")) priv->force_earc = 1; if (device_property_read_u32(priv->dev, "ite,fixed-lcf", &priv->fixed_lcf)) priv->fixed_lcf = 0x00; priv->hpdio = devm_gpiod_get_optional(&client->dev, "hpdio", GPIOD_OUT_LOW); ret = it6621_earc_init(priv); if (ret) return ret; if (client->irq) { ret = devm_request_threaded_irq(priv->dev, client->irq, NULL, it6621_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "it6621", priv); if (ret) return ret; } return devm_snd_soc_register_component(priv->dev, &it6621_component, it6621_dais, ARRAY_SIZE(it6621_dais)); } static const struct i2c_device_id it6621_i2c_id[] = { { IT6621_I2C_NAME, 0 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, it6621_i2c_id); static const struct of_device_id it6621_dt_match[] = { { .compatible = "ite,it6621" }, { /* sentinel */ }, }; static struct i2c_driver it6621_i2c_driver = { .driver = { .name = IT6621_I2C_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(it6621_dt_match), }, .probe = it6621_i2c_probe, .id_table = it6621_i2c_id, }; module_i2c_driver(it6621_i2c_driver); MODULE_AUTHOR("Jason Zhang "); MODULE_DESCRIPTION("ASoC IT6621 eARC Driver"); MODULE_LICENSE("GPL");