diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-06 14:27:31 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-06 14:27:31 -0700 |
commit | 3f9df56480fc8ce492fc9e988d67bdea884ed15c (patch) | |
tree | 6e1c5ed1e28b72435995b8bcd191daa7dfdf770e /sound/soc/codecs/tlv320adcx140.c | |
parent | 921d2597abfc05e303f08baa6ead8f9ab8a723e1 (diff) | |
parent | c7fabbc51352f50cc58242a6dc3b9c1a3599849b (diff) | |
download | linux-3f9df56480fc8ce492fc9e988d67bdea884ed15c.tar.gz linux-3f9df56480fc8ce492fc9e988d67bdea884ed15c.tar.bz2 linux-3f9df56480fc8ce492fc9e988d67bdea884ed15c.zip |
Merge tag 'sound-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"This became wide and scattered updates all over the sound tree as
diffstat shows: lots of (still ongoing) refactoring works in ASoC,
fixes and cleanups caught by static analysis, inclusive term
conversions as well as lots of new drivers. Below are highlights:
ASoC core:
- API cleanups and conversions to the unified mute_stream() call
- Simplify I/O helper functions
- Use helper macros to retrieve RTD from substreams
ASoC drivers:
- Lots of fixes and cleanups in Intel ASoC drivers
- Lots of new stuff: Freescale MQS and i.MX6sx, Intel KeemBay I2S,
Maxim MAX98360A and MAX98373 SoundWire, various Mediatek boards,
nVidia Tegra 186 and 210, RealTek RL6231, Samsung Midas and Aries
boards, TI J721e EVM
ALSA core:
- Minor code refacotring for SG-buffer handling
HD-audio:
- Generalization of mute-LED handling with LED classdev
- Intel silent stream support for HDMI
- Device-specific fixes: CA0132, Loongson-3
Others:
- Usual USB- and HD-audio quirks for various devices
- Fixes for echoaudio DMA position handling
- Various documents and trivial fixes for sparse warnings
- Conversion to adopt inclusive terms"
* tag 'sound-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (479 commits)
ALSA: pci: delete repeated words in comments
ALSA: isa: delete repeated words in comments
ALSA: hda/tegra: Add 100us dma stop delay
ALSA: hda: Add dma stop delay variable
ASoC: hda/tegra: Set buffer alignment to 128 bytes
ALSA: seq: oss: Serialize ioctls
ALSA: hda/hdmi: Add quirk to force connectivity
ALSA: usb-audio: add startech usb audio dock name
ALSA: usb-audio: Add support for Lenovo ThinkStation P620
Revert "ALSA: hda: call runtime_allow() for all hda controllers"
ALSA: hda/ca0132 - Fix AE-5 microphone selection commands.
ALSA: hda/ca0132 - Add new quirk ID for Recon3D.
ALSA: hda/ca0132 - Fix ZxR Headphone gain control get value.
ALSA: hda/realtek: Add alc269/alc662 pin-tables for Loongson-3 laptops
ALSA: docs: fix typo
ALSA: doc: use correct config variable name
ASoC: core: Two step component registration
ASoC: core: Simplify snd_soc_component_initialize declaration
ASoC: core: Relocate and expose snd_soc_component_initialize
ASoC: sh: Replace 'select' DMADEVICES 'with depends on'
...
Diffstat (limited to 'sound/soc/codecs/tlv320adcx140.c')
-rw-r--r-- | sound/soc/codecs/tlv320adcx140.c | 124 |
1 files changed, 87 insertions, 37 deletions
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 35fe8ee5bce9..5cd50d841177 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // TLV320ADCX140 Sound driver -// Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ +// Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/ #include <linux/module.h> #include <linux/moduleparam.h> @@ -37,6 +37,13 @@ struct adcx140_priv { unsigned int slot_width; }; +static const char * const gpo_config_names[] = { + "ti,gpo-config-1", + "ti,gpo-config-2", + "ti,gpo-config-3", + "ti,gpo-config-4", +}; + static const struct reg_default adcx140_reg_defaults[] = { { ADCX140_PAGE_SELECT, 0x00 }, { ADCX140_SW_RESET, 0x00 }, @@ -60,10 +67,10 @@ static const struct reg_default adcx140_reg_defaults[] = { { ADCX140_PDMCLK_CFG, 0x40 }, { ADCX140_PDM_CFG, 0x00 }, { ADCX140_GPIO_CFG0, 0x22 }, + { ADCX140_GPO_CFG0, 0x00 }, { ADCX140_GPO_CFG1, 0x00 }, { ADCX140_GPO_CFG2, 0x00 }, { ADCX140_GPO_CFG3, 0x00 }, - { ADCX140_GPO_CFG4, 0x00 }, { ADCX140_GPO_VAL, 0x00 }, { ADCX140_GPIO_MON, 0x00 }, { ADCX140_GPI_CFG0, 0x00 }, @@ -218,8 +225,8 @@ static const struct snd_kcontrol_new in4_resistor_controls[] = { }; /* Analog/Digital Selection */ -static const char *adcx140_mic_sel_text[] = {"Analog", "Line In", "Digital"}; -static const char *adcx140_analog_sel_text[] = {"Analog", "Line In"}; +static const char * const adcx140_mic_sel_text[] = {"Analog", "Line In", "Digital"}; +static const char * const adcx140_analog_sel_text[] = {"Analog", "Line In"}; static SOC_ENUM_SINGLE_DECL(adcx140_mic1p_enum, ADCX140_CH1_CFG0, 5, @@ -313,6 +320,14 @@ static const struct snd_kcontrol_new adcx140_dapm_ch3_en_switch = SOC_DAPM_SINGLE("Switch", ADCX140_ASI_OUT_CH_EN, 5, 1, 0); static const struct snd_kcontrol_new adcx140_dapm_ch4_en_switch = SOC_DAPM_SINGLE("Switch", ADCX140_ASI_OUT_CH_EN, 4, 1, 0); +static const struct snd_kcontrol_new adcx140_dapm_ch5_en_switch = + SOC_DAPM_SINGLE("Switch", ADCX140_ASI_OUT_CH_EN, 3, 1, 0); +static const struct snd_kcontrol_new adcx140_dapm_ch6_en_switch = + SOC_DAPM_SINGLE("Switch", ADCX140_ASI_OUT_CH_EN, 2, 1, 0); +static const struct snd_kcontrol_new adcx140_dapm_ch7_en_switch = + SOC_DAPM_SINGLE("Switch", ADCX140_ASI_OUT_CH_EN, 1, 1, 0); +static const struct snd_kcontrol_new adcx140_dapm_ch8_en_switch = + SOC_DAPM_SINGLE("Switch", ADCX140_ASI_OUT_CH_EN, 0, 1, 0); static const struct snd_kcontrol_new adcx140_dapm_ch1_dre_en_switch = SOC_DAPM_SINGLE("Switch", ADCX140_CH1_CFG0, 0, 1, 0); @@ -406,6 +421,15 @@ static const struct snd_soc_dapm_widget adcx140_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("CH4_ASI_EN", SND_SOC_NOPM, 0, 0, &adcx140_dapm_ch4_en_switch), + SND_SOC_DAPM_SWITCH("CH5_ASI_EN", SND_SOC_NOPM, 0, 0, + &adcx140_dapm_ch5_en_switch), + SND_SOC_DAPM_SWITCH("CH6_ASI_EN", SND_SOC_NOPM, 0, 0, + &adcx140_dapm_ch6_en_switch), + SND_SOC_DAPM_SWITCH("CH7_ASI_EN", SND_SOC_NOPM, 0, 0, + &adcx140_dapm_ch7_en_switch), + SND_SOC_DAPM_SWITCH("CH8_ASI_EN", SND_SOC_NOPM, 0, 0, + &adcx140_dapm_ch8_en_switch), + SND_SOC_DAPM_SWITCH("DRE_ENABLE", SND_SOC_NOPM, 0, 0, &adcx140_dapm_dre_en_switch), @@ -446,6 +470,11 @@ static const struct snd_soc_dapm_route adcx140_audio_map[] = { {"CH3_ASI_EN", "Switch", "CH3_ADC"}, {"CH4_ASI_EN", "Switch", "CH4_ADC"}, + {"CH5_ASI_EN", "Switch", "CH5_OUT"}, + {"CH6_ASI_EN", "Switch", "CH6_OUT"}, + {"CH7_ASI_EN", "Switch", "CH7_OUT"}, + {"CH8_ASI_EN", "Switch", "CH8_OUT"}, + {"Decimation Filter", "Linear Phase", "DRE_ENABLE"}, {"Decimation Filter", "Low Latency", "DRE_ENABLE"}, {"Decimation Filter", "Ultra-low Latency", "DRE_ENABLE"}, @@ -576,7 +605,7 @@ static int adcx140_reset(struct adcx140_priv *adcx140) gpiod_direction_output(adcx140->gpio_reset, 1); } else { ret = regmap_write(adcx140->regmap, ADCX140_SW_RESET, - ADCX140_RESET); + ADCX140_RESET); } /* 8.4.2: wait >= 10 ms after entering sleep mode. */ @@ -624,6 +653,8 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai, struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component); u8 iface_reg1 = 0; u8 iface_reg2 = 0; + int offset = 0; + int width = adcx140->slot_width; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -666,7 +697,10 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai, iface_reg1 |= ADCX140_LEFT_JUST_BIT; break; case SND_SOC_DAIFMT_DSP_A: + offset += (adcx140->tdm_delay * width + 1); + break; case SND_SOC_DAIFMT_DSP_B: + offset += adcx140->tdm_delay * width; break; default: dev_err(component->dev, "Invalid DAI interface format\n"); @@ -683,6 +717,11 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai, snd_soc_component_update_bits(component, ADCX140_MST_CFG0, ADCX140_BCLK_FSYNC_MASTER, iface_reg2); + /* Configure data offset */ + snd_soc_component_update_bits(component, ADCX140_ASI_CFG1, + ADCX140_TX_OFFSET_MASK, offset); + + return 0; } @@ -694,11 +733,6 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component); unsigned int lsb; - if (tx_mask != rx_mask) { - dev_err(component->dev, "tx and rx masks must be symmetric\n"); - return -EINVAL; - } - /* TDM based on DSP mode requires slots to be adjacent */ lsb = __ffs(tx_mask); if ((lsb + 1) != __fls(tx_mask)) { @@ -723,36 +757,48 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, return 0; } -static int adcx140_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static const struct snd_soc_dai_ops adcx140_dai_ops = { + .hw_params = adcx140_hw_params, + .set_fmt = adcx140_set_dai_fmt, + .set_tdm_slot = adcx140_set_dai_tdm_slot, +}; + +static int adcx140_configure_gpo(struct adcx140_priv *adcx140) { - struct snd_soc_component *component = dai->component; - struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component); - int offset = 0; - int width = adcx140->slot_width; + u32 gpo_outputs[ADCX140_NUM_GPOS]; + u32 gpo_output_val = 0; + int ret; + int i; - if (!width) - width = substream->runtime->sample_bits; + for (i = 0; i < ADCX140_NUM_GPOS; i++) { + ret = device_property_read_u32_array(adcx140->dev, + gpo_config_names[i], + gpo_outputs, + ADCX140_NUM_GPO_CFGS); + if (ret) + continue; - /* TDM slot selection only valid in DSP_A/_B mode */ - if (adcx140->dai_fmt == SND_SOC_DAIFMT_DSP_A) - offset += (adcx140->tdm_delay * width + 1); - else if (adcx140->dai_fmt == SND_SOC_DAIFMT_DSP_B) - offset += adcx140->tdm_delay * width; + if (gpo_outputs[0] > ADCX140_GPO_CFG_MAX) { + dev_err(adcx140->dev, "GPO%d config out of range\n", i + 1); + return -EINVAL; + } - /* Configure data offset */ - snd_soc_component_update_bits(component, ADCX140_ASI_CFG1, - ADCX140_TX_OFFSET_MASK, offset); + if (gpo_outputs[1] > ADCX140_GPO_DRV_MAX) { + dev_err(adcx140->dev, "GPO%d drive out of range\n", i + 1); + return -EINVAL; + } + + gpo_output_val = gpo_outputs[0] << ADCX140_GPO_SHIFT | + gpo_outputs[1]; + ret = regmap_write(adcx140->regmap, ADCX140_GPO_CFG0 + i, + gpo_output_val); + if (ret) + return ret; + } return 0; -} -static const struct snd_soc_dai_ops adcx140_dai_ops = { - .hw_params = adcx140_hw_params, - .set_fmt = adcx140_set_dai_fmt, - .prepare = adcx140_prepare, - .set_tdm_slot = adcx140_set_dai_tdm_slot, -}; +} static int adcx140_codec_probe(struct snd_soc_component *component) { @@ -792,6 +838,10 @@ static int adcx140_codec_probe(struct snd_soc_component *component) bias_cfg = bias_source << ADCX140_MIC_BIAS_SHIFT | vref_source; + ret = adcx140_reset(adcx140); + if (ret) + goto out; + pdm_count = device_property_count_u32(adcx140->dev, "ti,pdm-edge-select"); if (pdm_count <= ADCX140_NUM_PDM_EDGES && pdm_count > 0) { @@ -835,11 +885,11 @@ static int adcx140_codec_probe(struct snd_soc_component *component) return ret; } - ret = adcx140_reset(adcx140); + ret = adcx140_configure_gpo(adcx140); if (ret) goto out; - if(adcx140->supply_areg == NULL) + if (adcx140->supply_areg == NULL) sleep_cfg_val |= ADCX140_AREG_INTERNAL; ret = regmap_write(adcx140->regmap, ADCX140_SLEEP_CFG, sleep_cfg_val); @@ -940,8 +990,8 @@ static int adcx140_i2c_probe(struct i2c_client *i2c, if (IS_ERR(adcx140->supply_areg)) { if (PTR_ERR(adcx140->supply_areg) == -EPROBE_DEFER) return -EPROBE_DEFER; - else - adcx140->supply_areg = NULL; + + adcx140->supply_areg = NULL; } else { ret = regulator_enable(adcx140->supply_areg); if (ret) { |