diff options
author | Takashi Iwai <tiwai@suse.de> | 2019-11-25 14:27:33 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2019-11-25 14:27:41 +0100 |
commit | 09578eacaaa44149738267083ccc050990409f86 (patch) | |
tree | cf614ee065fe5479e4638abebe12c9e1578b09d9 /sound/soc/codecs | |
parent | c6b6fc206586cc07a18595d2a3d815a806a057d0 (diff) | |
parent | 8c4d2a0bfbd27d030e4652b714cd5a1598f3559b (diff) |
Merge tag 'asoc-v5.5-2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: More updates for v5.5
Some more development work for v5.5. Highlights include:
- More cleanups from Morimoto-san.
- Trigger word detection for RT5677.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/Kconfig | 3 | ||||
-rw-r--r-- | sound/soc/codecs/pcm3168a.c | 48 | ||||
-rw-r--r-- | sound/soc/codecs/rt5645.c | 6 | ||||
-rw-r--r-- | sound/soc/codecs/rt5677-spi.c | 13 | ||||
-rw-r--r-- | sound/soc/codecs/rt5677.c | 445 | ||||
-rw-r--r-- | sound/soc/codecs/rt5677.h | 11 | ||||
-rw-r--r-- | sound/soc/codecs/rt5682.c | 28 | ||||
-rw-r--r-- | sound/soc/codecs/tas2770.c | 10 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic31xx.c | 45 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic31xx.h | 8 | ||||
-rw-r--r-- | sound/soc/codecs/wm2200.c | 5 | ||||
-rw-r--r-- | sound/soc/codecs/wm5100.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8904.c | 73 | ||||
-rw-r--r-- | sound/soc/codecs/wm8904.h | 1 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 81 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.h | 4 |
16 files changed, 646 insertions, 137 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 925e5f852348..4abf37b5083f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -679,7 +679,8 @@ config SND_SOC_DA7210 tristate config SND_SOC_DA7213 - tristate + tristate "Dialog DA7213 CODEC" + depends on I2C config SND_SOC_DA7218 tristate diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 313500ab36df..9711fab296eb 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -9,7 +9,9 @@ #include <linux/clk.h> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/module.h> +#include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> @@ -59,6 +61,7 @@ struct pcm3168a_priv { struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES]; struct regmap *regmap; struct clk *scki; + struct gpio_desc *gpio_rst; unsigned long sysclk; struct pcm3168a_io_params io_params[2]; @@ -643,6 +646,7 @@ static bool pcm3168a_readable_register(struct device *dev, unsigned int reg) static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { + case PCM3168A_RST_SMODE: case PCM3168A_DAC_ZERO: case PCM3168A_ADC_OV: return true; @@ -702,6 +706,25 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) dev_set_drvdata(dev, pcm3168a); + /* + * Request the reset (connected to RST pin) gpio line as non exclusive + * as the same reset line might be connected to multiple pcm3168a codec + * + * The RST is low active, we want the GPIO line to be high initially, so + * request the initial level to LOW which in practice means DEASSERTED: + * The deasserted level of GPIO_ACTIVE_LOW is HIGH. + */ + pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW | + GPIOD_FLAGS_BIT_NONEXCLUSIVE); + if (IS_ERR(pcm3168a->gpio_rst)) { + ret = PTR_ERR(pcm3168a->gpio_rst); + if (ret != -EPROBE_DEFER ) + dev_err(dev, "failed to acquire RST gpio: %d\n", ret); + + return ret; + } + pcm3168a->scki = devm_clk_get(dev, "scki"); if (IS_ERR(pcm3168a->scki)) { ret = PTR_ERR(pcm3168a->scki); @@ -743,10 +766,18 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) goto err_regulator; } - ret = pcm3168a_reset(pcm3168a); - if (ret) { - dev_err(dev, "Failed to reset device: %d\n", ret); - goto err_regulator; + if (pcm3168a->gpio_rst) { + /* + * The device is taken out from reset via GPIO line, wait for + * 3846 SCKI clock cycles for the internal reset de-assertion + */ + msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk)); + } else { + ret = pcm3168a_reset(pcm3168a); + if (ret) { + dev_err(dev, "Failed to reset device: %d\n", ret); + goto err_regulator; + } } pm_runtime_set_active(dev); @@ -785,6 +816,15 @@ static void pcm3168a_disable(struct device *dev) void pcm3168a_remove(struct device *dev) { + struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); + + /* + * The RST is low active, we want the GPIO line to be low when the + * driver is removed, so set level to 1 which in practice means + * ASSERTED: + * The asserted level of GPIO_ACTIVE_LOW is LOW. + */ + gpiod_set_value_cansleep(pcm3168a->gpio_rst, 1); pm_runtime_disable(dev); #ifndef CONFIG_PM pcm3168a_disable(dev); diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a15e4ecd2a24..92d67010aeed 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3270,6 +3270,9 @@ static void rt5645_jack_detect_work(struct work_struct *work) snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); return; + case 4: + val = snd_soc_component_read32(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; + break; default: /* read rt5645 jd1_1 status */ val = snd_soc_component_read32(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000; break; @@ -3603,7 +3606,7 @@ static const struct rt5645_platform_data intel_braswell_platform_data = { static const struct rt5645_platform_data buddy_platform_data = { .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5, .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, - .jd_mode = 3, + .jd_mode = 4, .level_trigger_irq = true, }; @@ -4012,6 +4015,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, RT5645_JD1_MODE_1); break; case 3: + case 4: regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, RT5645_JD1_MODE_MASK, RT5645_JD1_MODE_2); diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 0c90f99b693f..7810b1d7de32 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -26,6 +26,7 @@ #include <sound/soc.h> +#include "rt5677.h" #include "rt5677-spi.h" #define DRV_NAME "rt5677spi" @@ -111,10 +112,16 @@ static int rt5677_spi_pcm_close( struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *codec_component = + snd_soc_rtdcom_lookup(rtd, "rt5677"); + struct rt5677_priv *rt5677 = + snd_soc_component_get_drvdata(codec_component); struct rt5677_dsp *rt5677_dsp = snd_soc_component_get_drvdata(component); cancel_delayed_work_sync(&rt5677_dsp->copy_work); + rt5677->set_dsp_vad(codec_component, false); return 0; } @@ -153,9 +160,15 @@ static int rt5677_spi_prepare( struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *rt5677_component = + snd_soc_rtdcom_lookup(rtd, "rt5677"); + struct rt5677_priv *rt5677 = + snd_soc_component_get_drvdata(rt5677_component); struct rt5677_dsp *rt5677_dsp = snd_soc_component_get_drvdata(component); + rt5677->set_dsp_vad(rt5677_component, true); rt5677_dsp->dma_offset = 0; rt5677_dsp->avail_bytes = 0; return 0; diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 315a3d39bc09..e9a051a50ab2 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -38,6 +38,10 @@ #define RT5677_DEVICE_ID 0x6327 +/* Register controlling boot vector */ +#define RT5677_DSP_BOOT_VECTOR 0x1801f090 +#define RT5677_MODEL_ADDR 0x5FFC9800 + #define RT5677_PR_RANGE_BASE (0xff + 1) #define RT5677_PR_SPACING 0x100 @@ -298,6 +302,7 @@ static bool rt5677_volatile_register(struct device *dev, unsigned int reg) case RT5677_I2C_MASTER_CTRL7: case RT5677_I2C_MASTER_CTRL8: case RT5677_HAP_GENE_CTRL2: + case RT5677_PWR_ANLG2: /* Modified by DSP firmware */ case RT5677_PWR_DSP_ST: case RT5677_PRIV_DATA: case RT5677_ASRC_22: @@ -308,6 +313,8 @@ static bool rt5677_volatile_register(struct device *dev, unsigned int reg) case RT5677_IRQ_CTRL1: case RT5677_IRQ_CTRL2: case RT5677_GPIO_ST: + case RT5677_GPIO_CTRL1: /* Modified by DSP firmware */ + case RT5677_GPIO_CTRL2: /* Modified by DSP firmware */ case RT5677_DSP_INB1_SRC_CTRL4: case RT5677_DSP_INB2_SRC_CTRL4: case RT5677_DSP_INB3_SRC_CTRL4: @@ -686,10 +693,8 @@ static int rt5677_dsp_mode_i2c_read( return ret; } -static void rt5677_set_dsp_mode(struct snd_soc_component *component, bool on) +static void rt5677_set_dsp_mode(struct rt5677_priv *rt5677, bool on) { - struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); - if (on) { regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, RT5677_PWR_DSP, RT5677_PWR_DSP); @@ -701,86 +706,259 @@ static void rt5677_set_dsp_mode(struct snd_soc_component *component, bool on) } } +static unsigned int rt5677_set_vad_source(struct rt5677_priv *rt5677) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(rt5677->component); + /* Force dapm to sync before we enable the + * DSP to prevent write corruption + */ + snd_soc_dapm_sync(dapm); + + /* DMIC1 power = enabled + * DMIC CLK = 256 * fs / 12 + */ + regmap_update_bits(rt5677->regmap, RT5677_DMIC_CTRL1, + RT5677_DMIC_CLK_MASK, 5 << RT5677_DMIC_CLK_SFT); + + /* I2S pre divide 2 = /6 (clk_sys2) */ + regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1, + RT5677_I2S_PD2_MASK, RT5677_I2S_PD2_6); + + /* DSP Clock = MCLK1 (bypassed PLL2) */ + regmap_write(rt5677->regmap, RT5677_GLB_CLK2, + RT5677_DSP_CLK_SRC_BYPASS); + + /* SAD Threshold1 */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL2, 0x013f); + /* SAD Threshold2 */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL3, 0x0ae5); + /* SAD Sample Rate Converter = Up 6 (8K to 48K) + * SAD Output Sample Rate = Same as I2S + * SAD Threshold3 + */ + regmap_update_bits(rt5677->regmap, RT5677_VAD_CTRL4, + RT5677_VAD_OUT_SRC_RATE_MASK | RT5677_VAD_OUT_SRC_MASK | + RT5677_VAD_LV_DIFF_MASK, 0x7f << RT5677_VAD_LV_DIFF_SFT); + /* Minimum frame level within a pre-determined duration = 32 frames + * Bypass ADPCM Encoder/Decoder = Bypass ADPCM + * Automatic Push Data to SAD Buffer Once SAD Flag is triggered = enable + * SAD Buffer Over-Writing = enable + * SAD Buffer Pop Mode Control = disable + * SAD Buffer Push Mode Control = enable + * SAD Detector Control = enable + * SAD Function Control = enable + * SAD Function Reset = normal + */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, + RT5677_VAD_FUNC_RESET | RT5677_VAD_FUNC_ENABLE | + RT5677_VAD_DET_ENABLE | RT5677_VAD_BUF_PUSH | + RT5677_VAD_BUF_OW | RT5677_VAD_FG2ENC | + RT5677_VAD_ADPCM_BYPASS | 1 << RT5677_VAD_MIN_DUR_SFT); + + /* VAD/SAD is not routed to the IRQ output (i.e. MX-BE[14] = 0), but it + * is routed to DSP_IRQ_0, so DSP firmware may use it to sleep and save + * power. See ALC5677 datasheet section 9.17 "GPIO, Interrupt and Jack + * Detection" for more info. + */ + + /* Private register, no doc */ + regmap_update_bits(rt5677->regmap, RT5677_PR_BASE + RT5677_BIAS_CUR4, + 0x0f00, 0x0100); + + /* LDO2 output = 1.2V + * LDO1 output = 1.2V (LDO_IN = 1.8V) + */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, + RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, + 5 << RT5677_LDO1_SEL_SFT | 5 << RT5677_LDO2_SEL_SFT); + + /* Codec core power = power on + * LDO1 power = power on + */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, + RT5677_PWR_CORE | RT5677_PWR_LDO1, + RT5677_PWR_CORE | RT5677_PWR_LDO1); + + /* Isolation for DCVDD4 = normal (set during probe) + * Isolation for DCVDD2 = normal (set during probe) + * Isolation for DSP = normal + * Isolation for Band 0~7 = disable + * Isolation for InBound 4~10 and OutBound 4~10 = disable + */ + regmap_write(rt5677->regmap, RT5677_PWR_DSP2, + RT5677_PWR_CORE_ISO | RT5677_PWR_DSP_ISO | + RT5677_PWR_SR7_ISO | RT5677_PWR_SR6_ISO | + RT5677_PWR_SR5_ISO | RT5677_PWR_SR4_ISO | + RT5677_PWR_SR3_ISO | RT5677_PWR_SR2_ISO | + RT5677_PWR_SR1_ISO | RT5677_PWR_SR0_ISO | + RT5677_PWR_MLT_ISO); + + /* System Band 0~7 = power on + * InBound 4~10 and OutBound 4~10 = power on + * DSP = power on + * DSP CPU = stop (will be set to "run" after firmware loaded) + */ + regmap_write(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_SR7 | RT5677_PWR_SR6 | + RT5677_PWR_SR5 | RT5677_PWR_SR4 | + RT5677_PWR_SR3 | RT5677_PWR_SR2 | + RT5677_PWR_SR1 | RT5677_PWR_SR0 | + RT5677_PWR_MLT | RT5677_PWR_DSP | + RT5677_PWR_DSP_CPU); + + return 0; +} + +static int rt5677_parse_and_load_dsp(struct rt5677_priv *rt5677, const u8 *buf, + unsigned int len) +{ + struct snd_soc_component *component = rt5677->component; + Elf32_Ehdr *elf_hdr; + Elf32_Phdr *pr_hdr; + Elf32_Half i; + int ret = 0; + + if (!buf || (len < sizeof(Elf32_Ehdr))) + return -ENOMEM; + + elf_hdr = (Elf32_Ehdr *)buf; +#ifndef EM_XTENSA +#define EM_XTENSA 94 +#endif + if (strncmp(elf_hdr->e_ident, ELFMAG, sizeof(ELFMAG) - 1)) + dev_err(component->dev, "Wrong ELF header prefix\n"); + if (elf_hdr->e_ehsize != sizeof(Elf32_Ehdr)) + dev_err(component->dev, "Wrong Elf header size\n"); + if (elf_hdr->e_machine != EM_XTENSA) + dev_err(component->dev, "Wrong DSP code file\n"); + + if (len < elf_hdr->e_phoff) + return -ENOMEM; + pr_hdr = (Elf32_Phdr *)(buf + elf_hdr->e_phoff); + for (i = 0; i < elf_hdr->e_phnum; i++) { + /* TODO: handle p_memsz != p_filesz */ + if (pr_hdr->p_paddr && pr_hdr->p_filesz) { + dev_info(component->dev, "Load 0x%x bytes to 0x%x\n", + pr_hdr->p_filesz, pr_hdr->p_paddr); + + ret = rt5677_spi_write(pr_hdr->p_paddr, + buf + pr_hdr->p_offset, + pr_hdr->p_filesz); + if (ret) + dev_err(component->dev, "Load firmware failed %d\n", + ret); + } + pr_hdr++; + } + return ret; +} + +static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677) +{ + const struct firmware *fwp; + struct device *dev = rt5677->component->dev; + int ret = 0; + + /* Load dsp firmware from rt5677_elf_vad file */ + ret = request_firmware(&fwp, "rt5677_elf_vad", dev); + if (ret) { + dev_err(dev, "Request rt5677_elf_vad failed %d\n", ret); + return ret; + } + dev_info(dev, "Requested rt5677_elf_vad (%zu)\n", fwp->size); + + ret = rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size); + release_firmware(fwp); + return ret; +} + static int rt5677_set_dsp_vad(struct snd_soc_component *component, bool on) { struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); - static bool activity; - int ret; + rt5677->dsp_vad_en_request = on; + rt5677->dsp_vad_en = on; if (!IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI)) return -ENXIO; - if (on && !activity) { + schedule_delayed_work(&rt5677->dsp_work, 0); + return 0; +} + +static void rt5677_dsp_work(struct work_struct *work) +{ + struct rt5677_priv *rt5677 = + container_of(work, struct rt5677_priv, dsp_work.work); + static bool activity; + bool enable = rt5677->dsp_vad_en; + int i, val; + + + dev_info(rt5677->component->dev, "DSP VAD: enable=%d, activity=%d\n", + enable, activity); + + if (enable && !activity) { activity = true; - regcache_cache_only(rt5677->regmap, false); - regcache_cache_bypass(rt5677->regmap, true); + /* Before a hotword is detected, GPIO1 pin is configured as IRQ + * output so that jack detect works. When a hotword is detected, + * the DSP firmware configures the GPIO1 pin as GPIO1 and + * drives a 1. rt5677_irq() is called after a rising edge on + * the GPIO1 pin, due to either jack detect event or hotword + * event, or both. All possible events are checked and handled + * in rt5677_irq() where GPIO1 pin is configured back to IRQ + * output if a hotword is detected. + */ - regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1); - regmap_update_bits(rt5677->regmap, - RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00); - regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, - RT5677_LDO1_SEL_MASK, 0x0); - regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, - RT5677_PWR_LDO1, RT5677_PWR_LDO1); - switch (rt5677->type) { - case RT5677: - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, - RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC); - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, - RT5677_PLL2_PR_SRC_MASK | - RT5677_DSP_CLK_SRC_MASK, - RT5677_PLL2_PR_SRC_MCLK2 | - RT5677_DSP_CLK_SRC_BYPASS); - break; - case RT5676: - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, - RT5677_DSP_CLK_SRC_MASK, - RT5677_DSP_CLK_SRC_BYPASS); - break; - default: - break; + rt5677_set_vad_source(rt5677); + rt5677_set_dsp_mode(rt5677, true); + +#define RT5677_BOOT_RETRY 20 + for (i = 0; i < RT5677_BOOT_RETRY; i++) { + regmap_read(rt5677->regmap, RT5677_PWR_DSP_ST, &val); + if (val == 0x3ff) + break; + udelay(500); } - regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff); - regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd); - rt5677_set_dsp_mode(component, true); - - ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, - component->dev); - if (ret == 0) { - rt5677_spi_write_firmware(0x50000000, rt5677->fw1); - release_firmware(rt5677->fw1); + if (i == RT5677_BOOT_RETRY && val != 0x3ff) { + dev_err(rt5677->component->dev, "DSP Boot Timed Out!"); + return; } - ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, - component->dev); - if (ret == 0) { - rt5677_spi_write_firmware(0x60000000, rt5677->fw2); - release_firmware(rt5677->fw2); - } + /* Boot the firmware from IRAM instead of SRAM0. */ + rt5677_dsp_mode_i2c_write_addr(rt5677, RT5677_DSP_BOOT_VECTOR, + 0x0009, 0x0003); + rt5677_dsp_mode_i2c_write_addr(rt5677, RT5677_DSP_BOOT_VECTOR, + 0x0019, 0x0003); + rt5677_dsp_mode_i2c_write_addr(rt5677, RT5677_DSP_BOOT_VECTOR, + 0x0009, 0x0003); - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x0); + rt5677_load_dsp_from_file(rt5677); - regcache_cache_bypass(rt5677->regmap, false); - regcache_cache_only(rt5677->regmap, true); - } else if (!on && activity) { + /* Set DSP CPU to Run */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP_CPU, 0x0); + } else if (!enable && activity) { activity = false; - regcache_cache_only(rt5677->regmap, false); - regcache_cache_bypass(rt5677->regmap, true); + /* Don't turn off the DSP while handling irqs */ + mutex_lock(&rt5677->irq_lock); + /* Set DSP CPU to Stop */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU); - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1); - rt5677_set_dsp_mode(component, false); - regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001); + rt5677_set_dsp_mode(rt5677, false); - regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); + /* Disable and clear VAD interrupt */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184); - regcache_cache_bypass(rt5677->regmap, false); - regcache_mark_dirty(rt5677->regmap); - regcache_sync(rt5677->regmap); - } + /* Set GPIO1 pin back to be IRQ output for jack detect */ + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, + RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); - return 0; + mutex_unlock(&rt5677->irq_lock); + } } static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); @@ -805,7 +983,7 @@ static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); - ucontrol->value.integer.value[0] = rt5677->dsp_vad_en; + ucontrol->value.integer.value[0] = rt5677->dsp_vad_en_request; return 0; } @@ -814,12 +992,8 @@ static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); - - rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0]; - if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) - rt5677_set_dsp_vad(component, rt5677->dsp_vad_en); + rt5677_set_dsp_vad(component, !!ucontrol->value.integer.value[0]); return 0; } @@ -3010,6 +3184,7 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("AIF4TX", "AIF4 Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("SLBRX", "SLIMBus Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("SLBTX", "SLIMBus Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DSPTX", "DSP Buffer", 0, SND_SOC_NOPM, 0, 0), /* Sidetone Mux */ SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0, @@ -3544,11 +3719,24 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "SLBTX", NULL, "SLB ADC3 Mux" }, { "SLBTX", NULL, "SLB ADC4 Mux" }, + { "DSPTX", NULL, "IB01 Bypass Mux" }, + { "IB01 Mux", "IF1 DAC 01", "IF1 DAC01" }, { "IB01 Mux", "IF2 DAC 01", "IF2 DAC01" }, { "IB01 Mux", "SLB DAC 01", "SLB DAC01" }, { "IB01 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, - { "IB01 Mux", "VAD ADC/DAC1 FS", "DAC1 FS" }, + /* The IB01 Mux controls the source for InBound0 and InBound1. + * When the mux option "VAD ADC/DAC1 FS" is selected, "VAD ADC" goes to + * InBound0 and "DAC1 FS" goes to InBound1. "VAD ADC" is used for + * hotwording. "DAC1 FS" is not used currently. + * + * Creating a common widget node for "VAD ADC" + "DAC1 FS" and + * connecting the common widget to IB01 Mux causes the issue where + * there is an active path going from system playback -> "DAC1 FS" -> + * IB01 Mux -> DSP Buffer -> hotword stream. This wrong path confuses + * DAPM. Therefore "DAC1 FS" is ignored for now. + */ + { "IB01 Mux", "VAD ADC/DAC1 FS", "VAD ADC Mux" }, { "IB01 Bypass Mux", "Bypass", "IB01 Mux" }, { "IB01 Bypass Mux", "Pass SRC", "IB01 Mux" }, @@ -4457,14 +4645,15 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); + enum snd_soc_bias_level prev_bias = + snd_soc_component_get_bias_level(component); switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: - if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) { - rt5677_set_dsp_vad(component, false); + if (prev_bias == SND_SOC_BIAS_STANDBY) { regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, @@ -4488,9 +4677,25 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_STANDBY: + if (prev_bias == SND_SOC_BIAS_OFF && + rt5677->dsp_vad_en_request) { + /* Re-enable the DSP if it was turned off at suspend */ + rt5677->dsp_vad_en = true; + /* The delay is to wait for MCLK */ + schedule_delayed_work(&rt5677->dsp_work, + msecs_to_jiffies(1000)); + } break; case SND_SOC_BIAS_OFF: + flush_delayed_work(&rt5677->dsp_work); + if (rt5677->is_dsp_mode) { + /* Turn off the DSP before suspend */ + rt5677->dsp_vad_en = false; + schedule_delayed_work(&rt5677->dsp_work, 0); + flush_delayed_work(&rt5677->dsp_work); + } + regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x0); regmap_write(rt5677->regmap, RT5677_PWR_DIG1, 0x0000); regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, @@ -4740,6 +4945,8 @@ static void rt5677_remove(struct snd_soc_component *component) { struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); + cancel_delayed_work_sync(&rt5677->dsp_work); + regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); gpiod_set_value_cansleep(rt5677->reset_pin, 1); @@ -4750,6 +4957,11 @@ static int rt5677_suspend(struct snd_soc_component *component) { struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); + if (rt5677->irq) { + cancel_delayed_work_sync(&rt5677->resume_irq_check); + disable_irq(rt5677->irq); + } + if (!rt5677->dsp_vad_en) { regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); @@ -4778,6 +4990,11 @@ static int rt5677_resume(struct snd_soc_component *component) regcache_sync(rt5677->regmap); } + if (rt5677->irq) { + enable_irq(rt5677->irq); + schedule_delayed_work(&rt5677->resume_irq_check, 0); + } + return 0; } #else @@ -4842,6 +5059,11 @@ static const struct snd_soc_dai_ops rt5677_aif_dai_ops = { .set_tdm_slot = rt5677_set_tdm_slot, }; +static const struct snd_soc_dai_ops rt5677_dsp_dai_ops = { + .set_sysclk = rt5677_set_dai_sysclk, + .set_pll = rt5677_set_dai_pll, +}; + static struct snd_soc_dai_driver rt5677_dai[] = { { .name = "rt5677-aif1", @@ -4938,6 +5160,18 @@ static struct snd_soc_dai_driver rt5677_dai[] = { }, .ops = &rt5677_aif_dai_ops, }, + { + .name = "rt5677-dspbuffer", + .id = RT5677_DSPBUFF, + .capture = { + .stream_name = "DSP Buffer", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &rt5677_dsp_dai_ops, + }, }; static const struct snd_soc_component_driver soc_component_dev_rt5677 = { @@ -5073,6 +5307,28 @@ static const struct rt5677_irq_desc rt5677_irq_descs[] = { }, }; +static bool rt5677_check_hotword(struct rt5677_priv *rt5677) +{ + int reg_gpio; + + if (!rt5677->is_dsp_mode) + return false; + + if (regmap_read(rt5677->regmap, RT5677_GPIO_CTRL1, ®_gpio)) + return false; + + /* Firmware sets GPIO1 pin to be GPIO1 after hotword is detected */ + if ((reg_gpio & RT5677_GPIO1_PIN_MASK) == RT5677_GPIO1_PIN_IRQ) + return false; + + /* Set GPIO1 pin back to be IRQ output for jack detect */ + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, + RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); + + rt5677_spi_hotword_detected(); + return true; +} + static irqreturn_t rt5677_irq(int unused, void *data) { struct rt5677_priv *rt5677 = data; @@ -5118,7 +5374,13 @@ static irqreturn_t rt5677_irq(int unused, void *data) reg_irq ^= rt5677_irq_descs[i].polarity_mask; } } - if (!irq_fired) + + /* Exit the loop only when we know for sure that GPIO1 pin + * was low at some point since irq_lock was acquired. Any event + * after that point creates a rising edge that triggers another + * call to rt5677_irq(). + */ + if (!irq_fired && !rt5677_check_hotword(rt5677)) goto exit; ret = regmap_write(rt5677->regmap, RT5677_IRQ_CTRL1, reg_irq); @@ -5129,6 +5391,7 @@ static irqreturn_t rt5677_irq(int unused, void *data) } } exit: + WARN_ON_ONCE(loop == 20); mutex_unlock(&rt5677->irq_lock); if (irq_fired) return IRQ_HANDLED; @@ -5136,6 +5399,39 @@ exit: return IRQ_NONE; } +static void rt5677_resume_irq_check(struct work_struct *work) +{ + int i, virq; + struct rt5677_priv *rt5677 = + container_of(work, struct rt5677_priv, resume_irq_check.work); + + /* This is needed to check and clear the interrupt status register + * at resume. If the headset is plugged/unplugged when the device is + * fully suspended, there won't be a rising edge at resume to trigger + * the interrupt. Without this, we miss the next unplug/plug event. + */ + rt5677_irq(0, rt5677); + + /* Call all enabled jack detect irq handlers again. This is needed in + * addition to the above check for a corner case caused by jack gpio + * debounce. After codec irq is disabled at suspend, the delayed work + * scheduled by soc-jack may run and read wrong jack gpio values, since + * the regmap is in cache only mode. At resume, there is no irq because + * rt5677_irq has already ran and cleared the irq status at suspend. + * Without this explicit check, unplug the headset right after suspend + * starts, then after resume the headset is still shown as plugged in. + */ + mutex_lock(&rt5677->irq_lock); + for (i = 0; i < RT5677_IRQ_NUM; i++) { + if (rt5677->irq_en & rt5677_irq_descs[i].enable_mask) { + virq = irq_find_mapping(rt5677->domain, i); + if (virq) + handle_nested_irq(virq); + } + } + mutex_unlock(&rt5677->irq_lock); +} + static void rt5677_irq_bus_lock(struct irq_data *data) { struct rt5677_priv *rt5677 = irq_data_get_irq_chip_data(data); @@ -5211,6 +5507,7 @@ static int rt5677_init_irq(struct i2c_client *i2c) } mutex_init(&rt5677->irq_lock); + INIT_DELAYED_WORK(&rt5677->resume_irq_check, rt5677_resume_irq_check); /* * Select RC as the debounce clock so that GPIO works even when @@ -5256,6 +5553,8 @@ static int rt5677_init_irq(struct i2c_client *i2c) if (ret) dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret); + rt5677->irq = i2c->irq; + return ret; } @@ -5271,6 +5570,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) return -ENOMEM; rt5677->dev = &i2c->dev; + rt5677->set_dsp_vad = rt5677_set_dsp_vad; + INIT_DELAYED_WORK(&rt5677->dsp_work, rt5677_dsp_work); i2c_set_clientdata(i2c, rt5677); if (i2c->dev.of_node) { diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 213f4b8ca269..944ae02aafc2 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1336,6 +1336,8 @@ #define RT5677_PLL_M_SFT 12 #define RT5677_PLL_M_BP (0x1 << 11) #define RT5677_PLL_M_BP_SFT 11 +#define RT5677_PLL_UPDATE_PLL1 (0x1 << 1) +#define RT5677_PLL_UPDATE_PLL1_SFT 1 /* Global Clock Control 1 (0x80) */ #define RT5677_SCLK_SRC_MASK (0x3 << 14) @@ -1730,6 +1732,7 @@ enum { RT5677_AIF4, RT5677_AIF5, RT5677_AIFS, + RT5677_DSPBUFF, }; enum { @@ -1845,14 +1848,20 @@ struct rt5677_priv { #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; #endif - bool dsp_vad_en; + bool dsp_vad_en_request; /* DSP VAD enable/disable request */ + bool dsp_vad_en; /* dsp_work parameter */ bool is_dsp_mode; bool is_vref_slow; + struct delayed_work dsp_work; /* Interrupt handling */ struct irq_domain *domain; struct mutex irq_lock; unsigned int irq_en; + struct delayed_work resume_irq_check; + int irq; + + int (*set_dsp_vad)(struct snd_soc_component *component, bool on); }; int rt5677_sel_asrc_clk_src(struct snd_soc_component *component, diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 35dcec135c8a..b1713fffa3eb 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1003,6 +1003,7 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, RT5682_JD1_EN_MASK, RT5682_JD1_DIS); regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, RT5682_POW_JDH | RT5682_POW_JDL, 0); + cancel_delayed_work_sync(&rt5682->jack_detect_work); return 0; } @@ -1463,28 +1464,6 @@ static const struct snd_kcontrol_new hpor_switch = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1, RT5682_R_MUTE_SFT, 1, 1); -static int rt5682_charge_pump_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_component *component = - snd_soc_dapm_to_component(w->dapm); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - snd_soc_component_update_bits(component, - RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_HV); - break; - case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, - RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_LV); - break; - default: - return 0; - } - - return 0; -} - static int rt5682_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1768,8 +1747,7 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1 |