diff options
Diffstat (limited to 'sound')
198 files changed, 20943 insertions, 4199 deletions
diff --git a/sound/core/info.c b/sound/core/info.c index 895362a696c9..8ab72e0f5932 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -325,10 +325,15 @@ static ssize_t snd_info_text_entry_write(struct file *file, size_t next; int err = 0; + if (!entry->c.text.write) + return -EIO; pos = *offset; if (!valid_pos(pos, count)) return -EIO; next = pos + count; + /* don't handle too large text inputs */ + if (next > 16 * 1024) + return -EIO; mutex_lock(&entry->access); buf = data->wbuffer; if (!buf) { @@ -366,7 +371,9 @@ static int snd_info_seq_show(struct seq_file *seq, void *p) struct snd_info_private_data *data = seq->private; struct snd_info_entry *entry = data->entry; - if (entry->c.text.read) { + if (!entry->c.text.read) { + return -EIO; + } else { data->rbuffer->buffer = (char *)seq; /* XXX hack! */ entry->c.text.read(entry, data->rbuffer); } diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index dcc102813aef..37d9cfbc29f9 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -448,8 +448,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) ktime_get_ts64(&tm); tm = timespec64_sub(tm, tmr->last_update); - cur_time.tv_nsec = tm.tv_nsec; - cur_time.tv_sec = tm.tv_sec; + cur_time.tv_nsec += tm.tv_nsec; + cur_time.tv_sec += tm.tv_sec; snd_seq_sanity_real_time(&cur_time); } spin_unlock_irqrestore(&tmr->lock, flags); diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index d17937b92331..7e3aa50b21f9 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -111,7 +111,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -EINVAL; hm = kmalloc(sizeof(*hm), GFP_KERNEL); - hr = kmalloc(sizeof(*hr), GFP_KERNEL); + hr = kzalloc(sizeof(*hr), GFP_KERNEL); if (!hm || !hr) { err = -ENOMEM; goto out; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c3469f756ec2..c64d986009a9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -341,8 +341,7 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ - (AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \ - AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\ + (AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\ AZX_DCAPS_SNOOP_TYPE(NVIDIA)) #define AZX_DCAPS_PRESET_CTHDA \ @@ -1716,6 +1715,10 @@ static int azx_first_init(struct azx *chip) } } + /* NVidia hardware normally only supports up to 40 bits of DMA */ + if (chip->pci->vendor == PCI_VENDOR_ID_NVIDIA) + dma_bits = 40; + /* disable 64bit DMA address on some devices */ if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { dev_dbg(card->dev, "Disabling 64bit DMA\n"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b58e8c76346a..ea81c08ddc7a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5811,8 +5811,6 @@ static const struct hda_model_fixup alc269_fixup_models[] = { #define ALC295_STANDARD_PINS \ {0x12, 0xb7a60130}, \ {0x14, 0x90170110}, \ - {0x17, 0x21014020}, \ - {0x18, 0x21a19030}, \ {0x21, 0x04211020} #define ALC298_STANDARD_PINS \ @@ -5859,11 +5857,19 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1b, 0x02011020}, {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x1b, 0x01011020}, + {0x21, 0x0221101f}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x14, 0x90170130}, {0x1b, 0x01014020}, {0x21, 0x0221103f}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x14, 0x90170130}, + {0x1b, 0x01011020}, + {0x21, 0x0221103f}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170130}, {0x1b, 0x02011020}, {0x21, 0x0221103f}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, @@ -6039,7 +6045,13 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { ALC292_STANDARD_PINS, {0x13, 0x90a60140}), SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC295_STANDARD_PINS), + ALC295_STANDARD_PINS, + {0x17, 0x21014020}, + {0x18, 0x21a19030}), + SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC295_STANDARD_PINS, + {0x17, 0x21014040}, + {0x18, 0x21a19050}), SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, ALC298_STANDARD_PINS, {0x17, 0x90170110}), @@ -6613,6 +6625,7 @@ enum { ALC891_FIXUP_HEADSET_MODE, ALC891_FIXUP_DELL_MIC_NO_PRESENCE, ALC662_FIXUP_ACER_VERITON, + ALC892_FIXUP_ASROCK_MOBO, }; static const struct hda_fixup alc662_fixups[] = { @@ -6889,6 +6902,14 @@ static const struct hda_fixup alc662_fixups[] = { { } } }, + [ALC892_FIXUP_ASROCK_MOBO] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x40f000f0 }, /* disabled */ + { 0x16, 0x40f000f0 }, /* disabled */ + { } + } + }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -6926,6 +6947,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), + SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO), SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68), SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON), SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c index 6a23302297c9..4d9d320a7971 100644 --- a/sound/pci/hda/thinkpad_helper.c +++ b/sound/pci/hda/thinkpad_helper.c @@ -13,7 +13,8 @@ static void (*old_vmaster_hook)(void *, int); static bool is_thinkpad(struct hda_codec *codec) { return (codec->core.subsystem_id >> 16 == 0x17aa) && - (acpi_dev_found("LEN0068") || acpi_dev_found("IBM0068")); + (acpi_dev_found("LEN0068") || acpi_dev_found("LEN0268") || + acpi_dev_found("IBM0068")); } static void update_tpacpi_mute_led(void *private_data, int enabled) diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 22aec9a1e9a4..4a56f3dfba51 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -78,4 +78,14 @@ config SND_ATMEL_SOC_PDMIC help Say Y if you want to add support for Atmel ASoC driver for boards using PDMIC. + +config SND_ATMEL_SOC_TSE850_PCM5142 + tristate "ASoC driver for the Axentia TSE-850" + depends on ARCH_AT91 && OF + depends on ATMEL_SSC && I2C + select SND_ATMEL_SOC_SSC_DMA + select SND_SOC_PCM512x_I2C + help + Say Y if you want to add support for the ASoC driver for the + Axentia TSE-850 with a PCM5142 codec. endif diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index a2b127bd9c87..67e10cbd4ed7 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -13,9 +13,11 @@ snd-atmel-soc-wm8904-objs := atmel_wm8904.o snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o snd-atmel-soc-classd-objs := atmel-classd.o snd-atmel-soc-pdmic-objs := atmel-pdmic.o +snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o +obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 16e459aedffe..a1e2c5682dcd 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -380,6 +380,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); /* Clear the SSC dividers */ ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; + ssc_p->forced_divider = 0; } spin_unlock_irq(&ssc_p->lock); @@ -426,14 +427,17 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, else if (div != ssc_p->cmr_div) return -EBUSY; + ssc_p->forced_divider |= BIT(ATMEL_SSC_CMR_DIV); break; case ATMEL_SSC_TCMR_PERIOD: ssc_p->tcmr_period = div; + ssc_p->forced_divider |= BIT(ATMEL_SSC_TCMR_PERIOD); break; case ATMEL_SSC_RCMR_PERIOD: ssc_p->rcmr_period = div; + ssc_p->forced_divider |= BIT(ATMEL_SSC_RCMR_PERIOD); break; default: @@ -443,6 +447,28 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, return 0; } +/* Is the cpu-dai master of the frame clock? */ +static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) +{ + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBS_CFS: + return 1; + } + return 0; +} + +/* Is the cpu-dai master of the bit clock? */ +static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p) +{ + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBS_CFS: + return 1; + } + return 0; +} + /* * Configure the SSC. */ @@ -459,6 +485,9 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, u32 tfmr, rfmr, tcmr, rcmr; int ret; int fslen, fslen_ext; + u32 cmr_div; + u32 tcmr_period; + u32 rcmr_period; /* * Currently, there is only one set of dma params for @@ -470,6 +499,46 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, else dir = 1; + /* + * If the cpu dai should provide BCLK, but noone has provided the + * divider needed for that to work, fall back to something sensible. + */ + cmr_div = ssc_p->cmr_div; + if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_CMR_DIV)) && + atmel_ssc_cbs(ssc_p)) { + int bclk_rate = snd_soc_params_to_bclk(params); + + if (bclk_rate < 0) { + dev_err(dai->dev, "unable to calculate cmr_div: %d\n", + bclk_rate); + return bclk_rate; + } + + cmr_div = DIV_ROUND_CLOSEST(ssc_p->mck_rate, 2 * bclk_rate); + } + + /* + * If the cpu dai should provide LRCLK, but noone has provided the + * dividers needed for that to work, fall back to something sensible. + */ + tcmr_period = ssc_p->tcmr_period; + rcmr_period = ssc_p->rcmr_period; + if (atmel_ssc_cfs(ssc_p)) { + int frame_size = snd_soc_params_to_frame_size(params); + + if (frame_size < 0) { + dev_err(dai->dev, + "unable to calculate tx/rx cmr_period: %d\n", + frame_size); + return frame_size; + } + + if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_TCMR_PERIOD))) + tcmr_period = frame_size / 2 - 1; + if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_RCMR_PERIOD))) + rcmr_period = frame_size / 2 - 1; + } + dma_params = ssc_p->dma_params[dir]; channels = params_channels(params); @@ -524,7 +593,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, fslen_ext = (bits - 1) / 16; fslen = (bits - 1) % 16; - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) | SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) @@ -540,7 +609,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); - tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) | SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) @@ -606,7 +675,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, fslen_ext = (bits - 1) / 16; fslen = (bits - 1) % 16; - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) | SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) @@ -623,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); - tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) | SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) @@ -650,7 +719,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, * MCK divider, and the BCLK signal is output * on the SSC TK line. */ - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) | SSC_BF(RCMR_STTDLY, 1) | SSC_BF(RCMR_START, SSC_START_RISING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) @@ -665,7 +734,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); - tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) | SSC_BF(TCMR_STTDLY, 1) | SSC_BF(TCMR_START, SSC_START_RISING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) @@ -760,7 +829,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, } /* set SSC clock mode register */ - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); + ssc_writel(ssc_p->ssc->regs, CMR, cmr_div); /* set receive clock mode and format */ ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index 80b153857a88..75194f582131 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -113,6 +113,7 @@ struct atmel_ssc_info { unsigned short cmr_div; unsigned short tcmr_period; unsigned short rcmr_period; + unsigned int forced_divider; struct atmel_pcm_dma_params *dma_params[2]; struct atmel_ssc_state ssc_state; unsigned long mck_rate; diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index fdd28ed3e0b9..fbc10f61eb55 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -53,7 +53,7 @@ static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops atmel_asoc_wm8904_ops = { +static const struct snd_soc_ops atmel_asoc_wm8904_ops = { .hw_params = atmel_asoc_wm8904_hw_params, }; diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c new file mode 100644 index 000000000000..ac6a814c8ecf --- /dev/null +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -0,0 +1,472 @@ +/* + * TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec + * + * Copyright (C) 2016 Axentia Technologies AB + * + * Author: Peter Rosin <peda@axentia.se> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * loop1 relays + * IN1 +---o +------------+ o---+ OUT1 + * \ / + * + + + * | / | + * +--o +--. | + * | add | | + * | V | + * | .---. | + * DAC +----------->|Sum|---+ + * | '---' | + * | | + * + + + * + * IN2 +---o--+------------+--o---+ OUT2 + * loop2 relays + * + * The 'loop1' gpio pin controlls two relays, which are either in loop + * position, meaning that input and output are directly connected, or + * they are in mixer position, meaning that the signal is passed through + * the 'Sum' mixer. Similarly for 'loop2'. + * + * In the above, the 'loop1' relays are inactive, thus feeding IN1 to the + * mixer (if 'add' is active) and feeding the mixer output to OUT1. The + * 'loop2' relays are active, short-cutting the TSE-850 from channel 2. + * IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name + * of the (filtered) output from the PCM5142 codec. + */ + +#include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> + +#include <sound/soc.h> +#include <sound/pcm_params.h> + +#include "atmel_ssc_dai.h" + +struct tse850_priv { + int ssc_id; + + struct gpio_desc *add; + struct gpio_desc *loop1; + struct gpio_desc *loop2; + + struct regulator *ana; + + int add_cache; + int loop1_cache; + int loop2_cache; +}; + +static int tse850_get_mux1(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + ucontrol->value.enumerated.item[0] = tse850->loop1_cache; + + return 0; +} + +static int tse850_put_mux1(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + struct soc_enum *e = (struct soc_enum *)kctrl->private_value; + unsigned int val = ucontrol->value.enumerated.item[0]; + + if (val >= e->items) + return -EINVAL; + + gpiod_set_value_cansleep(tse850->loop1, val); + tse850->loop1_cache = val; + + return snd_soc_dapm_put_enum_double(kctrl, ucontrol); +} + +static int tse850_get_mux2(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + ucontrol->value.enumerated.item[0] = tse850->loop2_cache; + + return 0; +} + +static int tse850_put_mux2(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + struct soc_enum *e = (struct soc_enum *)kctrl->private_value; + unsigned int val = ucontrol->value.enumerated.item[0]; + + if (val >= e->items) + return -EINVAL; + + gpiod_set_value_cansleep(tse850->loop2, val); + tse850->loop2_cache = val; + + return snd_soc_dapm_put_enum_double(kctrl, ucontrol); +} + +int tse850_get_mix(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + ucontrol->value.enumerated.item[0] = tse850->add_cache; + + return 0; +} + +int tse850_put_mix(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + int connect = !!ucontrol->value.integer.value[0]; + + if (tse850->add_cache == connect) + return 0; + + /* + * Hmmm, this gpiod_set_value_cansleep call should probably happen + * inside snd_soc_dapm_mixer_update_power in the loop. + */ + gpiod_set_value_cansleep(tse850->add, connect); + tse850->add_cache = connect; + + snd_soc_dapm_mixer_update_power(dapm, kctrl, connect, NULL); + return 1; +} + +int tse850_get_ana(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + int ret; + + ret = regulator_get_voltage(tse850->ana); + if (ret < 0) + return ret; + + /* + * Map regulator output values like so: + * -11.5V to "Low" (enum 0) + * 11.5V-12.5V to "12V" (enum 1) + * 12.5V-13.5V to "13V" (enum 2) + * ... + * 18.5V-19.5V to "19V" (enum 8) + * 19.5V- to "20V" (enum 9) + */ + if (ret < 11000000) + ret = 11000000; + else if (ret > 20000000) + ret = 20000000; + ret -= 11000000; + ret = (ret + 500000) / 1000000; + + ucontrol->value.enumerated.item[0] = ret; + + return 0; +} + +int tse850_put_ana(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + struct soc_enum *e = (struct soc_enum *)kctrl->private_value; + unsigned int uV = ucontrol->value.enumerated.item[0]; + int ret; + + if (uV >= e->items) + return -EINVAL; + + /* + * Map enum zero (Low) to 2 volts on the regulator, do this since + * the ana regulator is supplied by the system 12V voltage and + * requesting anything below the system voltage causes the system + * voltage to be passed through the regulator. Also, the ana + * regulator induces noise when requesting voltages near the + * system voltage. So, by mapping Low to 2V, that noise is + * eliminated when all that is needed is 12V (the system voltage). + */ + if (uV) + uV = 11000000 + (1000000 * uV); + else + uV = 2000000; + + ret = regulator_set_voltage(tse850->ana, uV, uV); + if (ret < 0) + return ret; + + return snd_soc_dapm_put_enum_double(kctrl, ucontrol); +} + +static const char * const mux_text[] = { "Mixer", "Loop" }; + +static const struct soc_enum mux_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, mux_text); + +static const struct snd_kcontrol_new mux1 = + SOC_DAPM_ENUM_EXT("MUX1", mux_enum, tse850_get_mux1, tse850_put_mux1); + +static const struct snd_kcontrol_new mux2 = + SOC_DAPM_ENUM_EXT("MUX2", mux_enum, tse850_get_mux2, tse850_put_mux2); + +#define TSE850_DAPM_SINGLE_EXT(xname, reg, shift, max, invert, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_volsw, \ + .get = xget, \ + .put = xput, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + +static const struct snd_kcontrol_new mix[] = { + TSE850_DAPM_SINGLE_EXT("IN Switch", SND_SOC_NOPM, 0, 1, 0, + tse850_get_mix, tse850_put_mix), +}; + +static const char * const ana_text[] = { + "Low", "12V", "13V", "14V", "15V", "16V", "17V", "18V", "19V", "20V" +}; + +static const struct soc_enum ana_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 9, ana_text); + +static const struct snd_kcontrol_new out = + SOC_DAPM_ENUM_EXT("ANA", ana_enum, tse850_get_ana, tse850_put_ana); + +static const struct snd_soc_dapm_widget tse850_dapm_widgets[] = { + SND_SOC_DAPM_LINE("OUT1", NULL), + SND_SOC_DAPM_LINE("OUT2", NULL), + SND_SOC_DAPM_LINE("IN1", NULL), + SND_SOC_DAPM_LINE("IN2", NULL), + SND_SOC_DAPM_INPUT("DAC"), + SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), + SOC_MIXER_ARRAY("MIX", SND_SOC_NOPM, 0, 0, mix), + SND_SOC_DAPM_MUX("MUX1", SND_SOC_NOPM, 0, 0, &mux1), + SND_SOC_DAPM_MUX("MUX2", SND_SOC_NOPM, 0, 0, &mux2), + SND_SOC_DAPM_OUT_DRV("OUT", SND_SOC_NOPM, 0, 0, &out, 1), +}; + +/* + * These connections are not entirely correct, since both IN1 and IN2 + * are always fed to MIX (if the "IN switch" is set so), i.e. without + * regard to the loop1 and loop2 relays that according to this only + * control MUX1 and MUX2 but in fact also control how the input signals + * are routed. + * But, 1) I don't know how to do it right, and 2) it doesn't seem to + * matter in practice since nothing is powered in those sections anyway. + */ +static const struct snd_soc_dapm_route tse850_intercon[] = { + { "OUT1", NULL, "MUX1" }, + { "OUT2", NULL, "MUX2" }, + + { "MUX1", "Loop", "IN1" }, + { "MUX1", "Mixer", "OUT" }, + + { "MUX2", "Loop", "IN2" }, + { "MUX2", "Mixer", "OUT" }, + + { "OUT", NULL, "MIX" }, + + { "MIX", NULL, "DAC" }, + { "MIX", "IN Switch", "IN1" }, + { "MIX", "IN Switch", "IN2" }, + + /* connect board input to the codec left channel output pin */ + { "DAC", NULL, "OUTL" }, +}; + +static struct snd_soc_dai_link tse850_dailink = { + .name = "TSE-850", + .stream_name = "TSE-850-PCM", + .codec_dai_name = "pcm512x-hifi", + .dai_fmt = SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFS, +}; + +static struct snd_soc_card tse850_card = { + .name = "TSE-850-ASoC", + .owner = THIS_MODULE, + .dai_link = &tse850_dailink, + .num_links = 1, + .dapm_widgets = tse850_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tse850_dapm_widgets), + .dapm_routes = tse850_intercon, + .num_dapm_routes = ARRAY_SIZE(tse850_intercon), + .fully_routed = true, +}; + +static int tse850_dt_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *codec_np, *cpu_np; + struct snd_soc_card *card = &tse850_card; + struct snd_soc_dai_link *dailink = &tse850_dailink; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + if (!np) { + dev_err(&pdev->dev, "only device tree supported\n"); + return -EINVAL; + } + + cpu_np = of_parse_phandle(np, "axentia,ssc-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "failed to get dai and pcm info\n"); + return -EINVAL; + } + dailink->cpu_of_node = cpu_np; + dailink->platform_of_node = cpu_np; + tse850->ssc_id = of_alias_get_id(cpu_np, "ssc"); + of_node_put(cpu_np); + + codec_np = of_parse_phandle(np, "axentia,audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "failed to get codec info\n"); + return -EINVAL; + } + dailink->codec_of_node = codec_np; + of_node_put(codec_np); + + return 0; +} + +static int tse850_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &tse850_card; + struct device *dev = card->dev = &pdev->dev; + struct tse850_priv *tse850; + int ret; + + tse850 = devm_kzalloc(dev, sizeof(*tse850), GFP_KERNEL); + if (!tse850) + return -ENOMEM; + + snd_soc_card_set_drvdata(card, tse850); + + ret = tse850_dt_init(pdev); + if (ret) { + dev_err(dev, "failed to init dt info\n"); + return ret; + } + + tse850->add = devm_gpiod_get(dev, "axentia,add", GPIOD_OUT_HIGH); + if (IS_ERR(tse850->add)) { + if (PTR_ERR(tse850->add) != -EPROBE_DEFER) + dev_err(dev, "failed to get 'add' gpio\n"); + return PTR_ERR(tse850->add); + } + tse850->add_cache = 1; + + tse850->loop1 = devm_gpiod_get(dev, "axentia,loop1", GPIOD_OUT_HIGH); + if (IS_ERR(tse850->loop1)) { + if (PTR_ERR(tse850->loop1) != -EPROBE_DEFER) + dev_err(dev, "failed to get 'loop1' gpio\n"); + return PTR_ERR(tse850->loop1); + } + tse850->loop1_cache = 1; + + tse850->loop2 = devm_gpiod_get(dev, "axentia,loop2", GPIOD_OUT_HIGH); + if (IS_ERR(tse850->loop2)) { + if (PTR_ERR(tse850->loop2) != -EPROBE_DEFER) + dev_err(dev, "failed to get 'loop2' gpio\n"); + return PTR_ERR(tse850->loop2); + } + tse850->loop2_cache = 1; + + tse850->ana = devm_regulator_get(dev, "axentia,ana"); + if (IS_ERR(tse850->ana)) { + if (PTR_ERR(tse850->ana) != -EPROBE_DEFER) + dev_err(dev, "failed to get 'ana' regulator\n"); + return PTR_ERR(tse850->ana); + } + + ret = regulator_enable(tse850->ana); + if (ret < 0) { + dev_err(dev, "failed to enable the 'ana' regulator\n"); + return ret; + } + + ret = atmel_ssc_set_audio(tse850->ssc_id); + if (ret != 0) { + dev_err(dev, + "failed to set SSC %d for audio\n", tse850->ssc_id); + goto err_disable_ana; + } + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(dev, "snd_soc_register_card failed\n"); + goto err_put_audio; + } + + return 0; + +err_put_audio: + atmel_ssc_put_audio(tse850->ssc_id); +err_disable_ana: + regulator_disable(tse850->ana); + return ret; +} + +static int tse850_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + snd_soc_unregister_card(card); + atmel_ssc_put_audio(tse850->ssc_id); + regulator_disable(tse850->ana); + + return 0; +} + +static const struct of_device_id tse850_dt_ids[] = { + { .compatible = "axentia,tse850-pcm5142", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tse850_dt_ids); + +static struct platform_driver tse850_driver = { + .driver = { + .name = "axentia-tse850-pcm5142", + .of_match_table = of_match_ptr(tse850_dt_ids), + }, + .probe = tse850_probe, + .remove = tse850_remove, +}; + +module_platform_driver(tse850_driver); + +/* Module information */ +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); +MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig index d528aaceaad9..edf367100ebd 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig @@ -11,6 +11,7 @@ config SND_BCM2835_SOC_I2S config SND_SOC_CYGNUS tristate "SoC platform audio for Broadcom Cygnus chips" depends on ARCH_BCM_CYGNUS || COMPILE_TEST + depends on HAS_DMA help Say Y if you want to add support for ASoC audio on Broadcom Cygnus chips (bcm958300, bcm958305, bcm911360) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..b4f8dc80105c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -48,6 +48,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC select SND_SOC_CS35L32 if I2C select SND_SOC_CS35L33 if I2C + select SND_SOC_CS35L34 if I2C + select SND_SOC_CS42L42 if I2C select SND_SOC_CS42L51_I2C if I2C select SND_SOC_CS42L52 if I2C && INPUT select SND_SOC_CS42L56 if I2C && INPUT @@ -83,6 +85,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98095 if I2C select SND_SOC_MAX98357A if GPIOLIB select SND_SOC_MAX98371 if I2C + select SND_SOC_MAX98504 if I2C select SND_SOC_MAX9867 if I2C select SND_SOC_MAX98925 if I2C select SND_SOC_MAX98926 if I2C @@ -114,6 +117,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_RT5651 if I2C select SND_SOC_RT5659 if I2C select SND_SOC_RT5660 if I2C + select SND_SOC_RT5665 if I2C select SND_SOC_RT5663 if I2C select SND_SOC_RT5670 if I2C select SND_SOC_RT5677 if I2C && SPI_MASTER @@ -399,6 +403,14 @@ config SND_SOC_CS35L33 tristate "Cirrus Logic CS35L33 CODEC" depends on I2C +config SND_SOC_CS35L34 + tristate "Cirrus Logic CS35L34 CODEC" + depends on I2C + +config SND_SOC_CS42L42 + tristate "Cirrus Logic CS42L42 CODEC" + depends on I2C + config SND_SOC_CS42L51 tristate @@ -581,6 +593,13 @@ config SND_SOC_MAX9860 depends on I2C select REGMAP_I2C +config SND_SOC_MSM8916_WCD_ANALOG + tristate "Qualcomm MSM8916 WCD Analog Codec" + depends on SPMI || COMPILE_TEST + +config SND_SOC_MSM8916_WCD_DIGITAL + tristate "Qualcomm MSM8916 WCD DIGITAL Codec" + config SND_SOC_PCM1681 tristate "Texas Instruments PCM1681 CODEC" depends on I2C @@ -649,6 +668,7 @@ config SND_SOC_RL6231 default y if SND_SOC_RT5651=y default y if SND_SOC_RT5659=y default y if SND_SOC_RT5660=y + default y if SND_SOC_RT5665=y default y if SND_SOC_RT5663=y default y if SND_SOC_RT5670=y default y if SND_SOC_RT5677=y @@ -659,6 +679,7 @@ config SND_SOC_RL6231 default m if SND_SOC_RT5651=m default m if SND_SOC_RT5659=m default m if SND_SOC_RT5660=m + default m if SND_SOC_RT5665=m default m if SND_SOC_RT5663=m default m if SND_SOC_RT5670=m default m if SND_SOC_RT5677=m @@ -672,7 +693,6 @@ config SND_SOC_RL6347A config SND_SOC_RT286 tristate - select SND_SOC_RT5663 depends on I2C config SND_SOC_RT298 @@ -708,6 +728,9 @@ config SND_SOC_RT5659 config SND_SOC_RT5660 tristate +config SND_SOC_RT5665 + tristate + config SND_SOC_RT5663 tristate @@ -874,6 +897,7 @@ config SND_SOC_UDA134X config SND_SOC_UDA1380 tristate + depends on I2C config SND_SOC_WL1273 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 958cd4912fbc..7e1dad79610b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -38,6 +38,8 @@ snd-soc-bt-sco-objs := bt-sco.o snd-soc-cq93vc-objs := cq93vc.o snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs35l33-objs := cs35l33.o +snd-soc-cs35l34-objs := cs35l34.o +snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o @@ -86,6 +88,8 @@ snd-soc-max9850-objs := max9850.o snd-soc-max9860-objs := max9860.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o +snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o +snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o snd-soc-nau8810-objs := nau8810.o snd-soc-nau8825-objs := nau8825.o snd-soc-hdmi-codec-objs := hdmi-codec.o @@ -114,6 +118,7 @@ snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o snd-soc-rt5659-objs := rt5659.o snd-soc-rt5660-objs := rt5660.o +snd-soc-rt5665-objs := rt5665.o snd-soc-rt5663-objs := rt5663.o snd-soc-rt5670-objs := rt5670.o snd-soc-rt5677-objs := rt5677.o @@ -214,7 +219,6 @@ snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o - # Amp snd-soc-max9877-objs := max9877.o snd-soc-max98504-objs := max98504.o @@ -263,6 +267,8 @@ obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o +obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o +obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o @@ -310,6 +316,8 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o +obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o +obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o @@ -338,6 +346,7 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o +obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 935ff7cb71c5..312b2a11abb6 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2587,8 +2587,6 @@ static struct platform_driver ab8500_codec_platform_driver = { }, .probe = ab8500_codec_driver_probe, .remove = ab8500_codec_driver_remove, - .suspend = NULL, - .resume = NULL, }; module_platform_driver(ab8500_codec_platform_driver); diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 439aa3ff1f99..b36511d965c8 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -160,7 +160,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct adau *adau = snd_soc_codec_get_drvdata(codec); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { 0 }; unsigned int stream = e->shift_l; unsigned int val, change; int reg; diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index c91717d08513..ebdaf56c1d61 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -27,7 +27,27 @@ #include <sound/tlv.h> #include <sound/ak4641.h> -#include "ak4641.h" +/* AK4641 register space */ +#define AK4641_PM1 0x00 +#define AK4641_PM2 0x01 +#define AK4641_SIG1 0x02 +#define AK4641_SIG2 0x03 +#define AK4641_MODE1 0x04 +#define AK4641_MODE2 0x05 +#define AK4641_DAC 0x06 +#define AK4641_MIC 0x07 +#define AK4641_TIMER 0x08 +#define AK4641_ALC1 0x09 +#define AK4641_ALC2 0x0a +#define AK4641_PGA 0x0b +#define AK4641_LATT 0x0c +#define AK4641_RATT 0x0d +#define AK4641_VOL 0x0e +#define AK4641_STATUS 0x0f +#define AK4641_EQLO 0x10 +#define AK4641_EQMID 0x11 +#define AK4641_EQHI 0x12 +#define AK4641_BTIF 0x13 /* codec private data */ struct ak4641_priv { diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h deleted file mode 100644 index 4a263248efea..000000000000 --- a/sound/soc/codecs/ak4641.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ak4641.h -- AK4641 SoC Audio driver - * - * Copyright 2008 Harald Welte <laforge@gnufiish.org> - * - * Based on ak4535.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _AK4641_H -#define _AK4641_H - -/* AK4641 register space */ - -#define AK4641_PM1 0x00 -#define AK4641_PM2 0x01 -#define AK4641_SIG1 0x02 -#define AK4641_SIG2 0x03 -#define AK4641_MODE1 0x04 -#define AK4641_MODE2 0x05 -#define AK4641_DAC 0x06 -#define AK4641_MIC 0x07 -#define AK4641_TIMER 0x08 -#define AK4641_ALC1 0x09 -#define AK4641_ALC2 0x0a -#define AK4641_PGA 0x0b -#define AK4641_LATT 0x0c -#define AK4641_RATT 0x0d -#define AK4641_VOL 0x0e -#define AK4641_STATUS 0x0f -#define AK4641_EQLO 0x10 -#define AK4641_EQMID 0x11 -#define AK4641_EQHI 0x12 -#define AK4641_BTIF 0x13 - -#define AK4641_CACHEREGNUM 0x14 - - - -#define AK4641_DAI_HIFI 0 -#define AK4641_DAI_VOICE 1 - - -#endif diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 846ca079845f..0a734d910850 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -191,6 +191,14 @@ int arizona_init_spk(struct snd_soc_codec *codec) break; } + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_spk); + +int arizona_init_spk_irqs(struct arizona *arizona) +{ + int ret; + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, "Thermal warning", arizona_thermal_warn, arizona); @@ -209,19 +217,16 @@ int arizona_init_spk(struct snd_soc_codec *codec) return 0; } -EXPORT_SYMBOL_GPL(arizona_init_spk); +EXPORT_SYMBOL_GPL(arizona_init_spk_irqs); -int arizona_free_spk(struct snd_soc_codec *codec) +int arizona_free_spk_irqs(struct arizona *arizona) { - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; - arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona); arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona); return 0; } -EXPORT_SYMBOL_GPL(arizona_free_spk); +EXPORT_SYMBOL_GPL(arizona_free_spk_irqs); static const struct snd_soc_dapm_route arizona_mono_routes[] = { { "OUT1R", NULL, "OUT1L" }, @@ -252,6 +257,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono); int arizona_init_gpio(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; int i; @@ -259,21 +265,24 @@ int arizona_init_gpio(struct snd_soc_codec *codec) switch (arizona->type) { case WM5110: case WM8280: - snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity"); + snd_soc_component_disable_pin(component, + "DRC2 Signal Activity"); break; default: break; } - snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity"); + snd_soc_component_disable_pin(component, "DRC1 Signal Activity"); for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) { case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT: - snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity"); + snd_soc_component_enable_pin(component, + "DRC1 Signal Activity"); break; case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT: - snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity"); + snd_soc_component_enable_pin(component, + "DRC2 Signal Activity"); break; default: break; @@ -1233,6 +1242,46 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk, return -EINVAL; } +int arizona_clk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + unsigned int val; + int clk_idx; + int ret; + + ret = regmap_read(arizona->regmap, w->reg, &val); + if (ret) { + dev_err(codec->dev, "Failed to check clock source: %d\n", ret); + return ret; + } + + val = (val & ARIZONA_SYSCLK_SRC_MASK) >> ARIZONA_SYSCLK_SRC_SHIFT; + + switch (val) { + case ARIZONA_CLK_SRC_MCLK1: + clk_idx = ARIZONA_MCLK1; + break; + case ARIZONA_CLK_SRC_MCLK2: + clk_idx = ARIZONA_MCLK2; + break; + default: + return 0; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return clk_prepare_enable(arizona->mclk[clk_idx]); + case SND_SOC_DAPM_POST_PMD: + clk_disable_unprepare(arizona->mclk[clk_idx]); + return 0; + default: + return 0; + } +} +EXPORT_SYMBOL_GPL(arizona_clk_ev); + int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { @@ -2242,6 +2291,42 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll, int base) return reg & ARIZONA_FLL1_ENA; } +static int arizona_set_fll_clks(struct arizona_fll *fll, int base, bool ena) +{ + struct arizona *arizona = fll->arizona; + unsigned int val; + struct clk *clk; + int ret; + + ret = regmap_read(arizona->regmap, base + 6, &val); + if (ret != 0) { + arizona_fll_err(fll, "Failed to read current source: %d\n", + ret); + return ret; + } + + val &= ARIZONA_FLL1_CLK_REF_SRC_MASK; + val >>= ARIZONA_FLL1_CLK_REF_SRC_SHIFT; + + switch (val) { + case ARIZONA_FLL_SRC_MCLK1: + clk = arizona->mclk[ARIZONA_MCLK1]; + break; + case ARIZONA_FLL_SRC_MCLK2: + clk = arizona->mclk[ARIZONA_MCLK2]; + break; + default: + return 0; + } + + if (ena) { + return clk_prepare_enable(clk); + } else { + clk_disable_unprepare(clk); + return 0; + } +} + static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; @@ -2264,6 +2349,10 @@ static int arizona_enable_fll(struct arizona_fll *fll) udelay(32); regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, ARIZONA_FLL1_GAIN_MASK, 0); + + if (arizona_is_enabled_fll(fll, fll->base + 0x10) > 0) + arizona_set_fll_clks(fll, fll->base + 0x10, false); + arizona_set_fll_clks(fll, fll->base, false); } /* @@ -2318,10 +2407,13 @@ static int arizona_enable_fll(struct arizona_fll *fll) if (!already_enabled) pm_runtime_get_sync(arizona->dev); - if (use_sync) + if (use_sync) { + arizona_set_fll_clks(fll, fll->base + 0x10, true); regmap_update_bits_async(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); + } + arizona_set_fll_clks(fll, fll->base, true); regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); @@ -2354,19 +2446,24 @@ static int arizona_enable_fll(struct arizona_fll *fll) static void arizona_disable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; - bool change; + bool ref_change, sync_change; regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); regmap_update_bits_check(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, 0, &change); - regmap_update_bits(arizona->regmap, fll->base + 0x11, - ARIZONA_FLL1_SYNC_ENA, 0); + ARIZONA_FLL1_ENA, 0, &ref_change); + regmap_update_bits_check(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, 0, &sync_change); regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, 0); - if (change) + if (sync_change) + arizona_set_fll_clks(fll, fll->base + 0x10, false); + + if (ref_change) { + arizona_set_fll_clks(fll, fll->base, false); pm_runtime_put_autosuspend(arizona->dev); + } } int arizona_set_fll_refclk(struct arizona_fll *fll, int source, @@ -2598,30 +2695,6 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); -int arizona_register_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb, - int (*notify)(struct notifier_block *nb, - unsigned long action, void *data)) -{ - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; - - nb->notifier_call = notify; - - return blocking_notifier_chain_register(&arizona->notifier, nb); -} -EXPORT_SYMBOL_GPL(arizona_register_notifier); - -int arizona_unregister_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb) -{ - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; - - return blocking_notifier_chain_unregister(&arizona->notifier, nb); -} -EXPORT_SYMBOL_GPL(arizona_unregister_notifier); - MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 850aa338ba29..56707860657c 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -14,6 +14,8 @@ #define _ASOC_ARIZONA_H #include <linux/completion.h> +#include <linux/notifier.h> +#include <linux/mfd/arizona/core.h> #include <sound/soc.h> @@ -66,7 +68,6 @@ /* Notifier events */ #define ARIZONA_NOTIFY_VOICE_TRIGGER 0x1 -struct arizona; struct wm_adsp; struct arizona_dai_priv { @@ -255,26 +256,24 @@ extern const struct soc_enum arizona_output_anc_src[]; extern const struct snd_kcontrol_new arizona_voice_trigger_switch[]; -extern int arizona_in_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event); -extern int arizona_out_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event); -extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event); -extern int arizona_anc_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event); - -extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - -extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, - int source, unsigned int freq, int dir); +int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); +int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); +int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); +int arizona_anc_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); + +int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int arizona_clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); +int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, + unsigned int freq, int dir); extern const struct snd_soc_dai_ops arizona_dai_ops; extern const struct snd_soc_dai_ops arizona_simple_dai_ops; @@ -297,41 +296,57 @@ struct arizona_fll { char clock_ok_name[ARIZONA_FLL_NAME_LEN]; }; -extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags); -extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags); -extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event); -extern void arizona_init_dvfs(struct arizona_priv *priv); - -extern int arizona_init_fll(struct arizona *arizona, int id, int base, - int lock_irq, int ok_irq, struct arizona_fll *fll); -extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, - unsigned int Fref, unsigned int Fout); -extern int arizona_set_fll(struct arizona_fll *fll, int source, +int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags); +int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags); +int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); +void arizona_init_dvfs(struct arizona_priv *priv); + +int arizona_init_fll(struct arizona *arizona, int id, int base, + int lock_irq, int ok_irq, struct arizona_fll *fll); +int arizona_set_fll_refclk(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout); +int arizona_set_fll(struct arizona_fll *fll, int source, + unsigned int Fref, unsigned int Fout); -extern int arizona_init_spk(struct snd_soc_codec *codec); -extern int arizona_init_gpio(struct snd_soc_codec *codec); -extern int arizona_init_mono(struct snd_soc_codec *codec); -extern int arizona_init_notifiers(struct snd_soc_codec *codec); +int arizona_init_spk(struct snd_soc_codec *codec); +int arizona_init_gpio(struct snd_soc_codec *codec); +int arizona_init_mono(struct snd_soc_codec *codec); +int arizona_init_notifiers(struct snd_soc_codec *codec); -extern int arizona_free_spk(struct snd_soc_codec *codec); +int arizona_init_spk_irqs(struct arizona *arizona); +int arizona_free_spk_irqs(struct arizona *arizona); -extern int arizona_init_dai(struct arizona_priv *priv, int dai); +int arizona_init_dai(struct arizona_priv *priv, int dai); int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff); -extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift); +bool arizona_input_analog(struct snd_soc_codec *codec, int shift); + +const char *arizona_sample_rate_val_to_name(unsigned int rate_val); + +static inline int arizona_register_notifier(struct snd_soc_codec *codec, + struct notifier_block *nb, + int (*notify) + (struct notifier_block *nb, + unsigned long action, void *data)) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + + nb->notifier_call = notify; + + return blocking_notifier_chain_register(&arizona->notifier, nb); +} -extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val); +static inline int arizona_unregister_notifier(struct snd_soc_codec *codec, + struct notifier_block *nb) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; -extern int arizona_register_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb, - int (*notify)(struct notifier_block *nb, - unsigned long action, - void *data)); -extern int arizona_unregister_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb); + return blocking_notifier_chain_unregister(&arizona->notifier, nb); +} #endif diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c new file mode 100644 index 000000000000..7c5d1510cf2c --- /dev/null +++ b/sound/soc/codecs/cs35l34.c @@ -0,0 +1,1251 @@ +/* + * cs35l34.c -- CS35l34 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: Paul Handrigan <Paul.Handrigan@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/pm_runtime.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/of_irq.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/cs35l34.h> + +#include "cs35l34.h" + +#define PDN_DONE_ATTEMPTS 10 +#define CS35L34_START_DELAY 50 + +struct cs35l34_private { + struct snd_soc_codec *codec; + struct cs35l34_platform_data pdata; + struct regmap *regmap; + struct regulator_bulk_data core_supplies[2]; + int num_core_supplies; + int mclk_int; + bool tdm_mode; + struct gpio_desc *reset_gpio; /* Active-low reset GPIO */ +}; + +static const struct reg_default cs35l34_reg[] = { + {CS35L34_PWRCTL1, 0x01}, + {CS35L34_PWRCTL2, 0x19}, + {CS35L34_PWRCTL3, 0x01}, + {CS35L34_ADSP_CLK_CTL, 0x08}, + {CS35L34_MCLK_CTL, 0x11}, + {CS35L34_AMP_INP_DRV_CTL, 0x01}, + {CS35L34_AMP_DIG_VOL_CTL, 0x12}, + {CS35L34_AMP_DIG_VOL, 0x00}, + {CS35L34_AMP_ANLG_GAIN_CTL, 0x0F}, + {CS35L34_PROTECT_CTL, 0x06}, + {CS35L34_AMP_KEEP_ALIVE_CTL, 0x04}, + {CS35L34_BST_CVTR_V_CTL, 0x00}, + {CS35L34_BST_PEAK_I, 0x10}, + {CS35L34_BST_RAMP_CTL, 0x87}, + {CS35L34_BST_CONV_COEF_1, 0x24}, + {CS35L34_BST_CONV_COEF_2, 0x24}, + {CS35L34_BST_CONV_SLOPE_COMP, 0x4E}, + {CS35L34_BST_CONV_SW_FREQ, 0x08}, + {CS35L34_CLASS_H_CTL, 0x0D}, + {CS35L34_CLASS_H_HEADRM_CTL, 0x0D}, + {CS35L34_CLASS_H_RELEASE_RATE, 0x08}, + {CS35L34_CLASS_H_FET_DRIVE_CTL, 0x41}, + {CS35L34_CLASS_H_STATUS, 0x05}, + {CS35L34_VPBR_CTL, 0x0A}, + {CS35L34_VPBR_VOL_CTL, 0x90}, + {CS35L34_VPBR_TIMING_CTL, 0x6A}, + {CS35L34_PRED_MAX_ATTEN_SPK_LOAD, 0x95}, + {CS35L34_PRED_BROWNOUT_THRESH, 0x1C}, + {CS35L34_PRED_BROWNOUT_VOL_CTL, 0x00}, + {CS35L34_PRED_BROWNOUT_RATE_CTL, 0x10}, + {CS35L34_PRED_WAIT_CTL, 0x10}, + {CS35L34_PRED_ZVP_INIT_IMP_CTL, 0x08}, + {CS35L34_PRED_MAN_SAFE_VPI_CTL, 0x80}, + {CS35L34_VPBR_ATTEN_STATUS, 0x00}, + {CS35L34_PRED_BRWNOUT_ATT_STATUS, 0x00}, + {CS35L34_SPKR_MON_CTL, 0xC6}, + {CS35L34_ADSP_I2S_CTL, 0x00}, + {CS35L34_ADSP_TDM_CTL, 0x00}, + {CS35L34_TDM_TX_CTL_1_VMON, 0x00}, + {CS35L34_TDM_TX_CTL_2_IMON, 0x04}, + {CS35L34_TDM_TX_CTL_3_VPMON, 0x03}, + {CS35L34_TDM_TX_CTL_4_VBSTMON, 0x07}, + {CS35L34_TDM_TX_CTL_5_FLAG1, 0x08}, + {CS35L34_TDM_TX_CTL_6_FLAG2, 0x09}, + {CS35L34_TDM_TX_SLOT_EN_1, 0x00}, + {CS35L34_TDM_TX_SLOT_EN_2, 0x00}, + {CS35L34_TDM_TX_SLOT_EN_3, 0x00}, + {CS35L34_TDM_TX_SLOT_EN_4, 0x00}, + {CS35L34_TDM_RX_CTL_1_AUDIN, 0x40}, + {CS35L34_TDM_RX_CTL_3_ALIVE, 0x04}, + {CS35L34_MULT_DEV_SYNCH1, 0x00}, + {CS35L34_MULT_DEV_SYNCH2, 0x80}, + {CS35L34_PROT_RELEASE_CTL, 0x00}, + {CS35L34_DIAG_MODE_REG_LOCK, 0x00}, + {CS35L34_DIAG_MODE_CTL_1, 0x00}, + {CS35L34_DIAG_MODE_CTL_2, 0x00}, + {CS35L34_INT_MASK_1, 0xFF}, + {CS35L34_INT_MASK_2, 0xFF}, + {CS35L34_INT_MASK_3, 0xFF}, + {CS35L34_INT_MASK_4, 0xFF}, + {CS35L34_INT_STATUS_1, 0x30}, + {CS35L34_INT_STATUS_2, 0x05}, + {CS35L34_INT_STATUS_3, 0x00}, + {CS35L34_INT_STATUS_4, 0x00}, + {CS35L34_OTP_TRIM_STATUS, 0x00}, +}; + +static bool cs35l34_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L34_DEVID_AB: + case CS35L34_DEVID_CD: + case CS35L34_DEVID_E: + case CS35L34_FAB_ID: + case CS35L34_REV_ID: + case CS35L34_INT_STATUS_1: + case CS35L34_INT_STATUS_2: + case CS35L34_INT_STATUS_3: + case CS35L34_INT_STATUS_4: + case CS35L34_CLASS_H_STATUS: + case CS35L34_VPBR_ATTEN_STATUS: + case CS35L34_OTP_TRIM_STATUS: + return true; + default: + return false; + } +} + +static bool cs35l34_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L34_DEVID_AB: + case CS35L34_DEVID_CD: + case CS35L34_DEVID_E: + case CS35L34_FAB_ID: + case CS35L34_REV_ID: + case CS35L34_PWRCTL1: + case CS35L34_PWRCTL2: + case CS35L34_PWRCTL3: + case CS35L34_ADSP_CLK_CTL: + case CS35L34_MCLK_CTL: + case CS35L34_AMP_INP_DRV_CTL: + case CS35L34_AMP_DIG_VOL_CTL: + case CS35L34_AMP_DIG_VOL: + case CS35L34_AMP_ANLG_GAIN_CTL: + case CS35L34_PROTECT_CTL: + case CS35L34_AMP_KEEP_ALIVE_CTL: + case CS35L34_BST_CVTR_V_CTL: + case CS35L34_BST_PEAK_I: + case CS35L34_BST_RAMP_CTL: + case CS35L34_BST_CONV_COEF_1: + case CS35L34_BST_CONV_COEF_2: + case CS35L34_BST_CONV_SLOPE_COMP: + case CS35L34_BST_CONV_SW_FREQ: + case CS35L34_CLASS_H_CTL: + case CS35L34_CLASS_H_HEADRM_CTL: + case CS35L34_CLASS_H_RELEASE_RATE: + case CS35L34_CLASS_H_FET_DRIVE_CTL: + case CS35L34_CLASS_H_STATUS: + case CS35L34_VPBR_CTL: + case CS35L34_VPBR_VOL_CTL: + case CS35L34_VPBR_TIMING_CTL: + case CS35L34_PRED_MAX_ATTEN_SPK_LOAD: + case CS35L34_PRED_BROWNOUT_THRESH: + case CS35L34_PRED_BROWNOUT_VOL_CTL: + case CS35L34_PRED_BROWNOUT_RATE_CTL: + case CS35L34_PRED_WAIT_CTL: + case CS35L34_PRED_ZVP_INIT_IMP_CTL: + case CS35L34_PRED_MAN_SAFE_VPI_CTL: + case CS35L34_VPBR_ATTEN_STATUS: + case CS35L34_PRED_BRWNOUT_ATT_STATUS: + case CS35L34_SPKR_MON_CTL: + case CS35L34_ADSP_I2S_CTL: + case CS35L34_ADSP_TDM_CTL: + case CS35L34_TDM_TX_CTL_1_VMON: + case CS35L34_TDM_TX_CTL_2_IMON: + case CS35L34_TDM_TX_CTL_3_VPMON: + case CS35L34_TDM_TX_CTL_4_VBSTMON: + case CS35L34_TDM_TX_CTL_5_FLAG1: + case CS35L34_TDM_TX_CTL_6_FLAG2: + case CS35L34_TDM_TX_SLOT_EN_1: + case CS35L34_TDM_TX_SLOT_EN_2: + case CS35L34_TDM_TX_SLOT_EN_3: + case CS35L34_TDM_TX_SLOT_EN_4: + case CS35L34_TDM_RX_CTL_1_AUDIN: + case CS35L34_TDM_RX_CTL_3_ALIVE: + case CS35L34_MULT_DEV_SYNCH1: + case CS35L34_MULT_DEV_SYNCH2: + case CS35L34_PROT_RELEASE_CTL: + case CS35L34_DIAG_MODE_REG_LOCK: + case CS35L34_DIAG_MODE_CTL_1: + case CS35L34_DIAG_MODE_CTL_2: + case CS35L34_INT_MASK_1: + case CS35L34_INT_MASK_2: + case CS35L34_INT_MASK_3: + case CS35L34_INT_MASK_4: + case CS35L34_INT_STATUS_1: + case CS35L34_INT_STATUS_2: + case CS35L34_INT_STATUS_3: + case CS35L34_INT_STATUS_4: + case CS35L34_OTP_TRIM_STATUS: + return true; + default: + return false; + } +} + +static bool cs35l34_precious_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L34_INT_STATUS_1: + case CS35L34_INT_STATUS_2: + case CS35L34_INT_STATUS_3: + case CS35L34_INT_STATUS_4: + return true; + default: + return false; + } +} + +static int cs35l34_sdin_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (priv->tdm_mode) + regmap_update_bits(priv->regmap, CS35L34_PWRCTL3, + CS35L34_PDN_TDM, 0x00); + + ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1, + CS35L34_PDN_ALL, 0); + if (ret < 0) { + dev_err(codec->dev, "Cannot set Power bits %d\n", ret); + return ret; + } + usleep_range(5000, 5100); + break; + case SND_SOC_DAPM_POST_PMD: + if (priv->tdm_mode) { + regmap_update_bits(priv->regmap, CS35L34_PWRCTL3, + CS35L34_PDN_TDM, CS35L34_PDN_TDM); + } + ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1, + CS35L34_PDN_ALL, CS35L34_PDN_ALL); + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + +static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + unsigned int reg, bit_pos; + int slot, slot_num; + + if (slot_width != 8) + return -EINVAL; + + priv->tdm_mode = true; + /* scan rx_mask for aud slot */ + slot = ffs(rx_mask) - 1; + if (slot >= 0) + snd_soc_update_bits(codec, CS35L34_TDM_RX_CTL_1_AUDIN, + CS35L34_X_LOC, slot); + + /* scan tx_mask: vmon(2 slots); imon (2 slots); vpmon (1 slot) + * vbstmon (1 slot) + */ + slot = ffs(tx_mask) - 1; + slot_num = 0; + + /* disable vpmon/vbstmon: enable later if set in tx_mask */ + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON, + CS35L34_X_STATE | CS35L34_X_LOC, + CS35L34_X_STATE | CS35L34_X_LOC); + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_4_VBSTMON, + CS35L34_X_STATE | CS35L34_X_LOC, + CS35L34_X_STATE | CS35L34_X_LOC); + + /* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/ + while (slot >= 0) { + /* configure VMON_TX_LOC */ + if (slot_num == 0) + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_1_VMON, + CS35L34_X_STATE | CS35L34_X_LOC, slot); + + /* configure IMON_TX_LOC */ + if (slot_num == 4) { + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_2_IMON, + CS35L34_X_STATE | CS35L34_X_LOC, slot); + } + /* configure VPMON_TX_LOC */ + if (slot_num == 3) { + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON, + CS35L34_X_STATE | CS35L34_X_LOC, slot); + } + /* configure VBSTMON_TX_LOC */ + if (slot_num == 7) { + snd_soc_update_bits(codec, + CS35L34_TDM_TX_CTL_4_VBSTMON, + CS35L34_X_STATE | CS35L34_X_LOC, slot); + } + + /* Enable the relevant tx slot */ + reg = CS35L34_TDM_TX_SLOT_EN_4 - (slot/8); + bit_pos = slot - ((slot / 8) * (8)); + snd_soc_update_bits(codec, reg, + 1 << bit_pos, 1 << bit_pos); + + tx_mask &= ~(1 << slot); + slot = ffs(tx_mask) - 1; + slot_num++; + } + + return 0; +} + +static int cs35l34_main_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL, + CS35L34_BST_CVTL_MASK, priv->pdata.boost_vtge); + usleep_range(5000, 5100); + regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL, + CS35L34_MUTE, 0); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL, + CS35L34_BST_CVTL_MASK, 0); + regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL, + CS35L34_MUTE, CS35L34_MUTE); + usleep_range(5000, 5100); + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + +static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); + +static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 300, 100, 0); + + +static const struct snd_kcontrol_new cs35l34_snd_controls[] = { + SOC_SINGLE_SX_TLV("Digital Volume", CS35L34_AMP_DIG_VOL, + 0, 0x34, 0xE4, dig_vol_tlv), + SOC_SINGLE_TLV("Amp Gain Volume", CS35L34_AMP_ANLG_GAIN_CTL, + 0, 0xF, 0, amp_gain_tlv), +}; + + +static int cs35l34_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + int ret, i; + unsigned int reg; + + switch (event) { + case SND_SOC_DAPM_PRE_PMD: + ret = regmap_read(priv->regmap, CS35L34_AMP_DIG_VOL_CTL, + ®); + if (ret != 0) { + pr_err("%s regmap read failure %d\n", __func__, ret); + return ret; + } + if (reg & CS35L34_AMP_DIGSFT) + msleep(40); + else + usleep_range(2000, 2100); + + for (i = 0; i < PDN_DONE_ATTEMPTS; i++) { + ret = regmap_read(priv->regmap, CS35L34_INT_STATUS_2, + ®); + if (ret != 0) { + pr_err("%s regmap read failure %d\n", + __func__, ret); + return ret; + } + if (reg & CS35L34_PDN_DONE) + break; + + usleep_range(5000, 5100); + } + if (i == PDN_DONE_ATTEMPTS) + pr_err("%s Device did not power down properly\n", + __func__); + break; + default: + pr_err("Invalid event = 0x%x\n", event); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget cs35l34_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L34_PWRCTL3, + 1, 1, cs35l34_sdin_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L34_PWRCTL3, 2, 1), + + SND_SOC_DAPM_SUPPLY("EXTCLK", CS35L34_PWRCTL3, 7, 1, + cs35l34_mclk_event, SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_OUTPUT("SPK"), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("VPST"), + SND_SOC_DAPM_INPUT("ISENSE"), + SND_SOC_DAPM_INPUT("VSENSE"), + + SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L34_PWRCTL2, 7, 1), + SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L34_PWRCTL2, 6, 1), + SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L34_PWRCTL3, 3, 1), + SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L34_PWRCTL3, 4, 1), + SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L34_PWRCTL2, 5, 1), + SND_SOC_DAPM_ADC("BOOST", NULL, CS35L34_PWRCTL2, 2, 1), + + SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L34_PWRCTL2, 0, 1, NULL, 0, + cs35l34_main_amp_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route cs35l34_audio_map[] = { + {"SDIN", NULL, "AMP Playback"}, + {"BOOST", NULL, "SDIN"}, + {"CLASS H", NULL, "BOOST"}, + {"Main AMP", NULL, "CLASS H"}, + {"SPK", NULL, "Main AMP"}, + + {"VPMON ADC", NULL, "CLASS H"}, + {"VBSTMON ADC", NULL, "CLASS H"}, + {"SPK", NULL, "VPMON ADC"}, + {"SPK", NULL, "VBSTMON ADC"}, + + {"IMON ADC", NULL, "ISENSE"}, + {"VMON ADC", NULL, "VSENSE"}, + {"SDOUT", NULL, "IMON ADC"}, + {"SDOUT", NULL, "VMON ADC"}, + {"AMP Capture", NULL, "SDOUT"}, + + {"SDIN", NULL, "EXTCLK"}, + {"SDOUT", NULL, "EXTCLK"}, +}; + +struct cs35l34_mclk_div { + int mclk; + int srate; + u8 adsp_rate; +}; + +static struct cs35l34_mclk_div cs35l34_mclk_coeffs[] = { + + /* MCLK, Sample Rate, adsp_rate */ + + {5644800, 11025, 0x1}, + {5644800, 22050, 0x4}, + {5644800, 44100, 0x7}, + + {6000000, 8000, 0x0}, + {6000000, 11025, 0x1}, + {6000000, 12000, 0x2}, + {6000000, 16000, 0x3}, + {6000000, 22050, 0x4}, + {6000000, 24000, 0x5}, + {6000000, 32000, 0x6}, + {6000000, 44100, 0x7}, + {6000000, 48000, 0x8}, + + {6144000, 8000, 0x0}, + {6144000, 11025, 0x1}, + {6144000, 12000, 0x2}, + {6144000, 16000, 0x3}, + {6144000, 22050, 0x4}, + {6144000, 24000, 0x5}, + {6144000, 32000, 0x6}, + {6144000, 44100, 0x7}, + {6144000, 48000, 0x8}, +}; + +static int cs35l34_get_mclk_coeff(int mclk, int srate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l34_mclk_coeffs); i++) { + if (cs35l34_mclk_coeffs[i].mclk == mclk && + cs35l34_mclk_coeffs[i].srate == srate) + return i; + } + return -EINVAL; +} + +static int cs35l34_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, + 0x80, 0x80); + break; + case SND_SOC_DAIFMT_CBS_CFS: + regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, + 0x80, 0x00); + break; + default: + return -EINVAL; + } + return 0; +} + +static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + int srate = params_rate(params); + int ret; + + int coeff = cs35l34_get_mclk_coeff(priv->mclk_int, srate); + + if (coeff < 0) { + dev_err(codec->dev, "ERROR: Invalid mclk %d and/or srate %d\n", + priv->mclk_int, srate); + return coeff; + } + + ret = regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, + CS35L34_ADSP_RATE, cs35l34_mclk_coeffs[coeff].adsp_rate); + if (ret != 0) + dev_err(codec->dev, "Failed to set clock state %d\n", ret); + + return ret; +} + +static unsigned int cs35l34_src_rates[] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +}; + + +static struct snd_pcm_hw_constraint_list cs35l34_constraints = { + .count = ARRAY_SIZE(cs35l34_src_rates), + .list = cs35l34_src_rates, +}; + +static int cs35l34_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &cs35l34_constraints); + return 0; +} + + +static int cs35l34_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + + struct snd_soc_codec *codec = dai->codec; + + if (tristate) + snd_soc_update_bits(codec, CS35L34_PWRCTL3, + CS35L34_PDN_SDOUT, CS35L34_PDN_SDOUT); + else + snd_soc_update_bits(codec, CS35L34_PWRCTL3, + CS35L34_PDN_SDOUT, 0); + return 0; +} + +static int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec); + unsigned int value; + + switch (freq) { + case CS35L34_MCLK_5644: + value = CS35L34_MCLK_RATE_5P6448; + cs35l34->mclk_int = freq; + break; + case CS35L34_MCLK_6: + value = CS35L34_MCLK_RATE_6P0000; + cs35l34->mclk_int = freq; + break; + case CS35L34_MCLK_6144: + value = CS35L34_MCLK_RATE_6P1440; + cs35l34->mclk_int = freq; + break; + case CS35L34_MCLK_11289: + value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_5P6448; + cs35l34->mclk_int = freq / 2; + break; + case CS35L34_MCLK_12: + value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P0000; + cs35l34->mclk_int = freq / 2; + break; + case CS35L34_MCLK_12288: + value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P1440; + cs35l34->mclk_int = freq / 2; + break; + default: + dev_err(codec->dev, "ERROR: Invalid Frequency %d\n", freq); + cs35l34->mclk_int = 0; + return -EINVAL; + } + regmap_update_bits(cs35l34->regmap, CS35L34_MCLK_CTL, + CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_MASK, value); + return 0; +} + +static const struct snd_soc_dai_ops cs35l34_ops = { + .startup = cs35l34_pcm_startup, + .set_tristate = cs35l34_set_tristate, + .set_fmt = cs35l34_set_dai_fmt, + .hw_params = cs35l34_pcm_hw_params, + .set_sysclk = cs35l34_dai_set_sysclk, + .set_tdm_slot = cs35l34_set_tdm_slot, +}; + +static struct snd_soc_dai_driver cs35l34_dai = { + .name = "cs35l34", + .id = 0, + .playback = { + .stream_name = "AMP Playback", + .channels_min = 1, + .channels_max = 8, + .rates = CS35L34_RATES, + .formats = CS35L34_FORMATS, + }, + .capture = { + .stream_name = "AMP Capture", + .channels_min = 1, + .channels_max = 8, + .rates = CS35L34_RATES, + .formats = CS35L34_FORMATS, + }, + .ops = &cs35l34_ops, + .symmetric_rates = 1, +}; + +static int cs35l34_boost_inductor(struct cs35l34_private *cs35l34, + unsigned int inductor) +{ + struct snd_soc_codec *codec = cs35l34->codec; + + switch (inductor) { + case 1000: /* 1 uH */ + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x24); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x24); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, + 0x4E); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 0); + break; + case 1200: /* 1.2 uH */ + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, + 0x47); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 1); + break; + case 1500: /* 1.5uH */ + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, + 0x3C); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 2); + break; + case 2200: /* 2.2uH */ + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x19); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x25); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, + 0x23); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 3); + break; + default: + dev_err(codec->dev, "%s Invalid Inductor Value %d uH\n", + __func__, inductor); + return -EINVAL; + } + return 0; +} + +static int cs35l34_probe(struct snd_soc_codec *codec) +{ + int ret = 0; + struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec); + + pm_runtime_get_sync(codec->dev); + + /* Set over temperature warning attenuation to 6 dB */ + regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, + CS35L34_OTW_ATTN_MASK, 0x8); + + /* Set Power control registers 2 and 3 to have everything + * powered down at initialization + */ + regmap_write(cs35l34->regmap, CS35L34_PWRCTL2, 0xFD); + regmap_write(cs35l34->regmap, CS35L34_PWRCTL3, 0x1F); + + /* Set mute bit at startup */ + regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, + CS35L34_MUTE, CS35L34_MUTE); + + /* Set Platform Data */ + if (cs35l34->pdata.boost_peak) + regmap_update_bits(cs35l34->regmap, CS35L34_BST_PEAK_I, + CS35L34_BST_PEAK_MASK, + cs35l34->pdata.boost_peak); + + if (cs35l34->pdata.gain_zc_disable) + regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, + CS35L34_GAIN_ZC_MASK, 0); + else + regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, + CS35L34_GAIN_ZC_MASK, CS35L34_GAIN_ZC_MASK); + + if (cs35l34->pdata.aif_half_drv) + regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_CLK_CTL, + CS35L34_ADSP_DRIVE, 0); + + if (cs35l34->pdata.digsft_disable) + regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL, + CS35L34_AMP_DIGSFT, 0); + + if (cs35l34->pdata.amp_inv) + regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL, + CS35L34_INV, CS35L34_INV); + + if (cs35l34->pdata.boost_ind) + ret = cs35l34_boost_inductor(cs35l34, cs35l34->pdata.boost_ind); + + if (cs35l34->pdata.i2s_sdinloc) + regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_I2S_CTL, + CS35L34_I2S_LOC_MASK, + cs35l34->pdata.i2s_sdinloc << CS35L34_I2S_LOC_SHIFT); + + if (cs35l34->pdata.tdm_rising_edge) + regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_TDM_CTL, + 1, 1); + + pm_runtime_put_sync(codec->dev); + + return ret; +} + + +static struct snd_soc_codec_driver soc_codec_dev_cs35l34 = { + .probe = cs35l34_probe, + + .component_driver = { + .dapm_widgets = cs35l34_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l34_dapm_widgets), + .dapm_routes = cs35l34_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l34_audio_map), + .controls = cs35l34_snd_controls, + .num_controls = ARRAY_SIZE(cs35l34_snd_controls), + }, +}; + +static struct regmap_config cs35l34_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS35L34_MAX_REGISTER, + .reg_defaults = cs35l34_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l34_reg), + .volatile_reg = cs35l34_volatile_register, + .readable_reg = cs35l34_readable_register, + .precious_reg = cs35l34_precious_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int cs35l34_handle_of_data(struct i2c_client *i2c_client, + struct cs35l34_platform_data *pdata) +{ + struct device_node *np = i2c_client->dev.of_node; + unsigned int val; + + if (of_property_read_u32(np, "cirrus,boost-vtge-millivolt", + &val) >= 0) { + /* Boost Voltage has a maximum of 8V */ + if (val > 8000 || (val < 3300 && val > 0)) { + dev_err(&i2c_client->dev, + "Invalid Boost Voltage %d mV\n", val); + return -EINVAL; + } + if (val == 0) + pdata->boost_vtge = 0; /* Use VP */ + else + pdata->boost_vtge = ((val - 3300)/100) + 1; + } else { + dev_warn(&i2c_client->dev, + "Boost Voltage not specified. Using VP\n"); + } + + if (of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val) >= 0) { + pdata->boost_ind = val; + } else { + dev_err(&i2c_client->dev, "Inductor not specified.\n"); + return -EINVAL; + } + + if (of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val) >= 0) { + if (val > 3840 || val < 1200) { + dev_err(&i2c_client->dev, + "Invalid Boost Peak Current %d mA\n", val); + return -EINVAL; + } + pdata->boost_peak = ((val - 1200)/80) + 1; + } + + pdata->aif_half_drv = of_property_read_bool(np, + "cirrus,aif-half-drv"); + pdata->digsft_disable = of_property_read_bool(np, + "cirrus,digsft-disable"); + + pdata->gain_zc_disable = of_property_read_bool(np, + "cirrus,gain-zc-disable"); + pdata->amp_inv = of_property_read_bool(np, "cirrus,amp-inv"); + + if (of_property_read_u32(np, "cirrus,i2s-sdinloc", &val) >= 0) + pdata->i2s_sdinloc = val; + if (of_property_read_u32(np, "cirrus,tdm-rising-edge", &val) >= 0) + pdata->tdm_rising_edge = val; + + return 0; +} + +static irqreturn_t cs35l34_irq_thread(int irq, void *data) +{ + struct cs35l34_private *cs35l34 = data; + struct snd_soc_codec *codec = cs35l34->codec; + unsigned int sticky1, sticky2, sticky3, sticky4; + unsigned int mask1, mask2, mask3, mask4, current1; + + + /* ack the irq by reading all status registers */ + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_4, &sticky4); + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_3, &sticky3); + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_2, &sticky2); + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, &sticky1); + + regmap_read(cs35l34->regmap, CS35L34_INT_MASK_4, &mask4); + regmap_read(cs35l34->regmap, CS35L34_INT_MASK_3, &mask3); + regmap_read(cs35l34->regmap, CS35L34_INT_MASK_2, &mask2); + regmap_read(cs35l34->regmap, CS35L34_INT_MASK_1, &mask1); + + if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) + && !(sticky4 & ~mask4)) + return IRQ_NONE; + + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, ¤t1); + + if (sticky1 & CS35L34_CAL_ERR) { + dev_err(codec->dev, "Cal error\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L34_CAL_ERR)) { + dev_dbg(codec->dev, "Cal error release\n"); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_CAL_ERR_RLS, 0); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_CAL_ERR_RLS, + CS35L34_CAL_ERR_RLS); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_CAL_ERR_RLS, 0); + /* note: amp will re-calibrate on next resume */ + } + } + + if (sticky1 & CS35L34_ALIVE_ERR) + dev_err(codec->dev, "Alive error\n"); + + if (sticky1 & CS35L34_AMP_SHORT) { + dev_crit(codec->dev, "Amp short error\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L34_AMP_SHORT)) { + dev_dbg(codec->dev, + "Amp short error release\n"); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_SHORT_RLS, 0); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_SHORT_RLS, + CS35L34_SHORT_RLS); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_SHORT_RLS, 0); + } + } + + if (sticky1 & CS35L34_OTW) { + dev_crit(codec->dev, "Over temperature warning\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L34_OTW)) { + dev_dbg(codec->dev, + "Over temperature warning release\n"); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTW_RLS, 0); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTW_RLS, + CS35L34_OTW_RLS); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTW_RLS, 0); + } + } + + if (sticky1 & CS35L34_OTE) { + dev_crit(codec->dev, "Over temperature error\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L34_OTE)) { + dev_dbg(codec->dev, + "Over temperature error release\n"); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTE_RLS, 0); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTE_RLS, + CS35L34_OTE_RLS); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTE_RLS, 0); + } + } + + if (sticky3 & CS35L34_BST_HIGH) { + dev_crit(codec->dev, "VBST too high error; powering off!\n"); + regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2, + CS35L34_PDN_AMP, CS35L34_PDN_AMP); + regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1, + CS35L34_PDN_ALL, CS35L34_PDN_ALL); + } + + if (sticky3 & CS35L34_LBST_SHORT) { + dev_crit(codec->dev, "LBST short error; powering off!\n"); + regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2, + CS35L34_PDN_AMP, CS35L34_PDN_AMP); + regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1, + CS35L34_PDN_ALL, CS35L34_PDN_ALL); + } + + return IRQ_HANDLED; +} + +static const char * const cs35l34_core_supplies[] = { + "VA", + "VP", +}; + +static int cs35l34_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs35l34_private *cs35l34; + struct cs35l34_platform_data *pdata = + dev_get_platdata(&i2c_client->dev); + int i; + int ret; + unsigned int devid = 0; + unsigned int reg; + + cs35l34 = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs35l34_private), + GFP_KERNEL); + if (!cs35l34) { + dev_err(&i2c_client->dev, "could not allocate codec\n"); + return -ENOMEM; + } + + i2c_set_clientdata(i2c_client, cs35l34); + cs35l34->regmap = devm_regmap_init_i2c(i2c_client, &cs35l34_regmap); + if (IS_ERR(cs35l34->regmap)) { + ret = PTR_ERR(cs35l34->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + cs35l34->num_core_supplies = ARRAY_SIZE(cs35l34_core_supplies); + for (i = 0; i < ARRAY_SIZE(cs35l34_core_supplies); i++) + cs35l34->core_supplies[i].supply = cs35l34_core_supplies[i]; + + ret = devm_regulator_bulk_get(&i2c_client->dev, + cs35l34->num_core_supplies, + cs35l34->core_supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request core supplies %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to enable core supplies: %d\n", ret); + return ret; + } + + if (pdata) { + cs35l34->pdata = *pdata; + } else { + pdata = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs35l34_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&i2c_client->dev, + "could not allocate pdata\n"); + return -ENOMEM; + } + if (i2c_client->dev.of_node) { + ret = cs35l34_handle_of_data(i2c_client, pdata); + if (ret != 0) + return ret; + + } + cs35l34->pdata = *pdata; + } + + ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, + cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs35l34", cs35l34); + if (ret != 0) + dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); + + cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset-gpios", GPIOD_OUT_LOW); + if (IS_ERR(cs35l34->reset_gpio)) + return PTR_ERR(cs35l34->reset_gpio); + + gpiod_set_value_cansleep(cs35l34->reset_gpio, 1); + + msleep(CS35L34_START_DELAY); + + ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_AB, ®); + + devid = (reg & 0xFF) << 12; + ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_CD, ®); + devid |= (reg & 0xFF) << 4; + ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_E, ®); + devid |= (reg & 0xF0) >> 4; + + if (devid != CS35L34_CHIP_ID) { + dev_err(&i2c_client->dev, + "CS35l34 Device ID (%X). Expected ID %X\n", + devid, CS35L34_CHIP_ID); + ret = -ENODEV; + goto err_regulator; + } + + ret = regmap_read(cs35l34->regmap, CS35L34_REV_ID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + goto err_regulator; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS35l34 (%x), Revision: %02X\n", devid, + reg & 0xFF); + + /* Unmask critical interrupts */ + regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_1, + CS35L34_M_CAL_ERR | CS35L34_M_ALIVE_ERR | + CS35L34_M_AMP_SHORT | CS35L34_M_OTW | + CS35L34_M_OTE, 0); + regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_3, + CS35L34_M_BST_HIGH | CS35L34_M_LBST_SHORT, 0); + + pm_runtime_set_autosuspend_delay(&i2c_client->dev, 100); + pm_runtime_use_autosuspend(&i2c_client->dev); + pm_runtime_set_active(&i2c_client->dev); + pm_runtime_enable(&i2c_client->dev); + + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_cs35l34, &cs35l34_dai, 1); + if (ret < 0) { + dev_err(&i2c_client->dev, + "%s: Register codec failed\n", __func__); + goto err_regulator; + } + + return 0; + +err_regulator: + regulator_bulk_disable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + return ret; +} + +static int cs35l34_i2c_remove(struct i2c_client *client) +{ + struct cs35l34_private *cs35l34 = i2c_get_clientdata(client); + + snd_soc_unregister_codec(&client->dev); + + if (cs35l34->reset_gpio) + gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); + + pm_runtime_disable(&client->dev); + regulator_bulk_disable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + return 0; +} + +static int __maybe_unused cs35l34_runtime_resume(struct device *dev) +{ + struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + if (ret != 0) { + dev_err(dev, "Failed to enable core supplies: %d\n", + ret); + return ret; + } + + regcache_cache_only(cs35l34->regmap, false); + + gpiod_set_value_cansleep(cs35l34->reset_gpio, 1); + msleep(CS35L34_START_DELAY); + + ret = regcache_sync(cs35l34->regmap); + if (ret != 0) { + dev_err(dev, "Failed to restore register cache\n"); + goto err; + } + return 0; +err: + regcache_cache_only(cs35l34->regmap, true); + regulator_bulk_disable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + return ret; +} + +static int __maybe_unused cs35l34_runtime_suspend(struct device *dev) +{ + struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); + + regcache_cache_only(cs35l34->regmap, true); + regcache_mark_dirty(cs35l34->regmap); + + gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); + + regulator_bulk_disable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + return 0; +} + +static const struct dev_pm_ops cs35l34_pm_ops = { + SET_RUNTIME_PM_OPS(cs35l34_runtime_suspend, + cs35l34_runtime_resume, + NULL) +}; + +static const struct of_device_id cs35l34_of_match[] = { + {.compatible = "cirrus,cs35l34"}, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l34_of_match); + +static const struct i2c_device_id cs35l34_id[] = { + {"cs35l34", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs35l34_id); + +static struct i2c_driver cs35l34_i2c_driver = { + .driver = { + .name = "cs35l34", + .pm = &cs35l34_pm_ops, + .of_match_table = cs35l34_of_match, + + }, + .id_table = cs35l34_id, + .probe = cs35l34_i2c_probe, + .remove = cs35l34_i2c_remove, + +}; + +static int __init cs35l34_modinit(void) +{ + int ret; + + ret = i2c_add_driver(&cs35l34_i2c_driver); + if (ret != 0) { + pr_err("Failed to register CS35l34 I2C driver: %d\n", ret); + return ret; + } + return 0; +} +module_init(cs35l34_modinit); + +static void __exit cs35l34_exit(void) +{ + i2c_del_driver(&cs35l34_i2c_driver); +} +module_exit(cs35l34_exit); + +MODULE_DESCRIPTION("ASoC CS35l34 driver"); +MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <Paul.Handrigan@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l34.h b/sound/soc/codecs/cs35l34.h new file mode 100644 index 000000000000..bcd54f127559 --- /dev/null +++ b/sound/soc/codecs/cs35l34.h @@ -0,0 +1,269 @@ +/* + * cs35l34.h -- CS35L34 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: Paul Handrigan <Paul.Handrigan@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __CS35L34_H__ +#define __CS35L34_H__ + +#define CS35L34_CHIP_ID 0x00035A34 +#define CS35L34_DEVID_AB 0x01 /* Device ID A & B [RO] */ +#define CS35L34_DEVID_CD 0x02 /* Device ID C & D [RO] */ +#define CS35L34_DEVID_E 0x03 /* Device ID E [RO] */ +#define CS35L34_FAB_ID 0x04 /* Fab ID [RO] */ +#define CS35L34_REV_ID 0x05 /* Revision ID [RO] */ +#define CS35L34_PWRCTL1 0x06 /* Power Ctl 1 */ +#define CS35L34_PWRCTL2 0x07 /* Power Ctl 2 */ +#define CS35L34_PWRCTL3 0x08 /* Power Ctl 3 */ +#define CS35L34_ADSP_CLK_CTL 0x0A /* (ADSP) Clock Ctl */ +#define CS35L34_MCLK_CTL 0x0B /* Master Clocking Ctl */ +#define CS35L34_AMP_INP_DRV_CTL 0x14 /* Amp Input Drive Ctl */ +#define CS35L34_AMP_DIG_VOL_CTL 0x15 /* Amplifier Dig Volume Ctl */ +#define CS35L34_AMP_DIG_VOL 0x16 /* Amplifier Dig Volume */ +#define CS35L34_AMP_ANLG_GAIN_CTL 0x17 /* Amplifier Analog Gain Ctl */ +#define CS35L34_PROTECT_CTL 0x18 /* Amp Gain - Prot Ctl Param */ +#define CS35L34_AMP_KEEP_ALIVE_CTL 0x1A /* Amplifier Keep Alive Ctl */ +#define CS35L34_BST_CVTR_V_CTL 0x1D /* Boost Conv Voltage Ctl */ +#define CS35L34_BST_PEAK_I 0x1E /* Boost Conv Peak Current */ +#define CS35L34_BST_RAMP_CTL 0x20 /* Boost Conv Soft Ramp Ctl */ +#define CS35L34_BST_CONV_COEF_1 0x21 /* Boost Conv Coefficients 1 */ +#define CS35L34_BST_CONV_COEF_2 0x22 /* Boost Conv Coefficients 2 */ +#define CS35L34_BST_CONV_SLOPE_COMP 0x23 /* Boost Conv Slope Comp */ +#define CS35L34_BST_CONV_SW_FREQ 0x24 /* Boost Conv L BST SW Freq */ +#define CS35L34_CLASS_H_CTL 0x30 /* CLS H Control */ +#define CS35L34_CLASS_H_HEADRM_CTL 0x31 /* CLS H Headroom Ctl */ +#define CS35L34_CLASS_H_RELEASE_RATE 0x32 /* CLS H Release Rate */ +#define CS35L34_CLASS_H_FET_DRIVE_CTL 0x33 /* CLS H Weak FET Drive Ctl */ +#define CS35L34_CLASS_H_STATUS 0x38 /* CLS H Status */ +#define CS35L34_VPBR_CTL 0x3A /* VPBR Ctl */ +#define CS35L34_VPBR_VOL_CTL 0x3B /* VPBR Volume Ctl */ +#define CS35L34_VPBR_TIMING_CTL 0x3C /* VPBR Timing Ctl */ +#define CS35L34_PRED_MAX_ATTEN_SPK_LOAD 0x40 /* PRD Max Atten / Spkr Load */ +#define CS35L34_PRED_BROWNOUT_THRESH 0x41 /* PRD Brownout Threshold */ +#define CS35L34_PRED_BROWNOUT_VOL_CTL 0x42 /* PRD Brownout Volume Ctl */ +#define CS35L34_PRED_BROWNOUT_RATE_CTL 0x43 /* PRD Brownout Rate Ctl */ +#define CS35L34_PRED_WAIT_CTL 0x44 /* PRD Wait Ctl */ +#define CS35L34_PRED_ZVP_INIT_IMP_CTL 0x46 /* PRD ZVP Initial Imp Ctl */ +#define CS35L34_PRED_MAN_SAFE_VPI_CTL 0x47 /* PRD Manual Safe VPI Ctl */ +#define CS35L34_VPBR_ATTEN_STATUS 0x4B /* VPBR Attenuation Status */ +#define CS35L34_PRED_BRWNOUT_ATT_STATUS 0x4C /* PRD Brownout Atten Status */ +#define CS35L34_SPKR_MON_CTL 0x4E /* Speaker Monitoring Ctl */ +#define CS35L34_ADSP_I2S_CTL 0x50 /* ADSP I2S Ctl */ +#define CS35L34_ADSP_TDM_CTL 0x51 /* ADSP TDM Ctl */ +#define CS35L34_TDM_TX_CTL_1_VMON 0x52 /* TDM TX Ctl 1 (VMON) */ +#define CS35L34_TDM_TX_CTL_2_IMON 0x53 /* TDM TX Ctl 2 (IMON) */ +#define CS35L34_TDM_TX_CTL_3_VPMON 0x54 /* TDM TX Ctl 3 (VPMON) */ +#define CS35L34_TDM_TX_CTL_4_VBSTMON 0x55 /* TDM TX Ctl 4 (VBSTMON) */ +#define CS35L34_TDM_TX_CTL_5_FLAG1 0x56 /* TDM TX Ctl 5 (FLAG1) */ +#define CS35L34_TDM_TX_CTL_6_FLAG2 0x57 /* TDM TX Ctl 6 (FLAG2) */ +#define CS35L34_TDM_TX_SLOT_EN_1 0x5A /* TDM TX Slot Enable */ +#define CS35L34_TDM_TX_SLOT_EN_2 0x5B /* TDM TX Slot Enable */ +#define CS35L34_TDM_TX_SLOT_EN_3 0x5C /* TDM TX Slot Enable */ +#define CS35L34_TDM_TX_SLOT_EN_4 0x5D /* TDM TX Slot Enable */ +#define CS35L34_TDM_RX_CTL_1_AUDIN 0x5E /* TDM RX Ctl 1 */ +#define CS35L34_TDM_RX_CTL_3_ALIVE 0x60 /* TDM RX Ctl 3 (ALIVE) */ +#define CS35L34_MULT_DEV_SYNCH1 0x62 /* Multidevice Synch */ +#define CS35L34_MULT_DEV_SYNCH2 0x63 /* Multidevice Synch 2 */ +#define CS35L34_PROT_RELEASE_CTL 0x64 /* Protection Release Ctl */ +#define CS35L34_DIAG_MODE_REG_LOCK 0x68 /* Diagnostic Mode Reg Lock */ +#define CS35L34_DIAG_MODE_CTL_1 0x69 /* Diagnostic Mode Ctl 1 */ +#define CS35L34_DIAG_MODE_CTL_2 0x6A /* Diagnostic Mode Ctl 2 */ +#define CS35L34_INT_MASK_1 0x70 /* Interrupt Mask 1 */ +#define CS35L34_INT_MASK_2 0x71 /* Interrupt Mask 2 */ +#define CS35L34_INT_MASK_3 0x72 /* Interrupt Mask 3 */ +#define CS35L34_INT_MASK_4 0x73 /* Interrupt Mask 4 */ +#define CS35L34_INT_STATUS_1 0x74 /* Interrupt Status 1 */ +#define CS35L34_INT_STATUS_2 0x75 /* Interrupt Status 2 */ +#define CS35L34_INT_STATUS_3 0x76 /* Interrupt Status 3 */ +#define CS35L34_INT_STATUS_4 0x77 /* Interrupt Status 4 */ +#define CS35L34_OTP_TRIM_STATUS 0x7E /* OTP Trim Status */ + +#define CS35L34_MAX_REGISTER 0x7F +#define CS35L34_REGISTER_COUNT 0x4E + +#define CS35L34_MCLK_5644 5644800 +#define CS35L34_MCLK_6144 6144000 +#define CS35L34_MCLK_6 6000000 +#define CS35L34_MCLK_11289 11289600 +#define CS35L34_MCLK_12 12000000 +#define CS35L34_MCLK_12288 12288000 + +/* CS35L34_PWRCTL1 */ +#define CS35L34_SFT_RST (1 << 7) +#define CS35L34_DISCHG_FLT (1 << 1) +#define CS35L34_PDN_ALL 1 + +/* CS35L34_PWRCTL2 */ +#define CS35L34_PDN_VMON (1 << 7) +#define CS35L34_PDN_IMON (1 << 6) +#define CS35L34_PDN_CLASSH (1 << 5) +#define CS35L34_PDN_VPBR (1 << 4) +#define CS35L34_PDN_PRED (1 << 3) +#define CS35L34_PDN_BST (1 << 2) +#define CS35L34_PDN_AMP 1 + +/* CS35L34_PWRCTL3 */ +#define CS35L34_MCLK_DIS (1 << 7) +#define CS35L34_PDN_VBSTMON_OUT (1 << 4) +#define CS35L34_PDN_VMON_OUT (1 << 3) +/* Tristate the ADSP SDOUT when in I2C mode */ +#define CS35L34_PDN_SDOUT (1 << 2) +#define CS35L34_PDN_SDIN (1 << 1) +#define CS35L34_PDN_TDM 1 + +/* CS35L34_ADSP_CLK_CTL */ +#define CS35L34_ADSP_RATE 0xF +#define CS35L34_ADSP_DRIVE (1 << 4) +#define CS35L34_ADSP_M_S (1 << 7) + +/* CS35L34_MCLK_CTL */ +#define CS35L34_MCLK_DIV (1 << 4) +#define CS35L34_MCLK_RATE_MASK 0x7 +#define CS35L34_MCLK_RATE_6P1440 0x2 +#define CS35L34_MCLK_RATE_6P0000 0x1 +#define CS35L34_MCLK_RATE_5P6448 0x0 +#define CS35L34_MCLKDIS (1 << 7) +#define CS35L34_MCLKDIV2 (1 << 6) +#define CS35L34_SDOUT_3ST_TDM (1 << 5) +#define CS35L34_INT_FS_RATE (1 << 4) +#define CS35L34_ADSP_FS 0xF + +/* CS35L34_AMP_INP_DRV_CTL */ +#define CS35L34_DRV_STR_SRC (1 << 1) +#define CS35L34_DRV_STR 1 + +/* CS35L34_AMP_DIG_VOL_CTL */ +#define CS35L34_AMP_DSR_RATE_MASK 0xF0 +#define CS35L34_AMP_DSR_RATE_SHIFT (1 << 4) +#define CS35L34_NOTCH_DIS (1 << 3) +#define CS35L34_AMP_DIGSFT (1 << 1) +#define CS35L34_INV 1 + +/* CS35L34_PROTECT_CTL */ +#define CS35L34_OTW_ATTN_MASK 0xC +#define CS35L34_OTW_THRD_MASK 0x3 +#define CS35L34_MUTE (1 << 5) +#define CS35L34_GAIN_ZC (1 << 4) +#define CS35L34_GAIN_ZC_MASK 0x10 +#define CS35L34_GAIN_ZC_SHIFT 4 + +/* CS35L34_AMP_KEEP_ALIVE_CTL */ +#define CS35L34_ALIVE_WD_DIS (1 << 2) + +/* CS35L34_BST_CVTR_V_CTL */ +#define CS35L34_BST_CVTL_MASK 0x3F + +/* CS35L34_BST_PEAK_I */ +#define CS35L34_BST_PEAK_MASK 0x3F + +/* CS35L34_ADSP_I2S_CTL */ +#define CS35L34_I2S_LOC_MASK 0xC +#define CS35L34_I2S_LOC_SHIFT 2 + +/* CS35L34_MULT_DEV_SYNCH2 */ +#define CS35L34_SYNC2_MASK 0xF + +/* CS35L34_PROT_RELEASE_CTL */ +#define CS35L34_CAL_ERR_RLS (1 << 7) +#define CS35L34_SHORT_RLS (1 << 2) +#define CS35L34_OTW_RLS (1 << 1) +#define CS35L34_OTE_RLS 1 + +/* CS35L34_INT_MASK_1 */ +#define CS35L34_M_CAL_ERR_SHIFT 7 +#define CS35L34_M_CAL_ERR (1 << CS35L34_M_CAL_ERR_SHIFT) +#define CS35L34_M_ALIVE_ERR_SHIFT 5 +#define CS35L34_M_ALIVE_ERR (1 << CS35L34_M_ALIVE_ERR_SHIFT) +#define CS35L34_M_ADSP_CLK_SHIFT 4 +#define CS35L34_M_ADSP_CLK_ERR (1 << CS35L34_M_ADSP_CLK_SHIFT) +#define CS35L34_M_MCLK_SHIFT 3 +#define CS35L34_M_MCLK_ERR (1 << CS35L34_M_MCLK_SHIFT) +#define CS35L34_M_AMP_SHORT_SHIFT 2 +#define CS35L34_M_AMP_SHORT (1 << CS35L34_M_AMP_SHORT_SHIFT) +#define CS35L34_M_OTW_SHIFT 1 +#define CS35L34_M_OTW (1 << CS35L34_M_OTW_SHIFT) +#define CS35L34_M_OTE_SHIFT 0 +#define CS35L34_M_OTE (1 << CS35L34_M_OTE_SHIFT) + +/* CS35L34_INT_MASK_2 */ +#define CS35L34_M_PDN_DONE_SHIFT 4 +#define CS35L34_M_PDN_DONE (1 << CS35L34_M_PDN_DONE_SHIFT) +#define CS35L34_M_PRED_SHIFT 3 +#define CS35L34_M_PRED_ERR (1 << CS35L34_M_PRED_SHIFT) +#define CS35L34_M_PRED_CLR_SHIFT 2 +#define CS35L34_M_PRED_CLR (1 << CS35L34_M_PRED_CLR_SHIFT) +#define CS35L34_M_VPBR_SHIFT 1 +#define CS35L34_M_VPBR_ERR (1 << CS35L34_M_VPBR_SHIFT) +#define CS35L34_M_VPBR_CLR_SHIFT 0 +#define CS35L34_M_VPBR_CLR (1 << CS35L34_M_VPBR_CLR_SHIFT) + +/* CS35L34_INT_MASK_3 */ +#define CS35L34_M_BST_HIGH_SHIFT 4 +#define CS35L34_M_BST_HIGH (1 << CS35L34_M_BST_HIGH_SHIFT) +#define CS35L34_M_BST_HIGH_FLAG_SHIFT 3 +#define CS35L34_M_BST_HIGH_FLAG (1 << CS35L34_M_BST_HIGH_FLAG_SHIFT) +#define CS35L34_M_BST_IPK_FLAG_SHIFT 2 +#define CS35L34_M_BST_IPK_FLAG (1 << CS35L34_M_BST_IPK_FLAG_SHIFT) +#define CS35L34_M_LBST_SHORT_SHIFT 0 +#define CS35L34_M_LBST_SHORT (1 << CS35L34_M_LBST_SHORT_SHIFT) + +/* CS35L34_INT_MASK_4 */ +#define CS35L34_M_VMON_OVFL_SHIFT 3 +#define CS35L34_M_VMON_OVFL (1 << CS35L34_M_VMON_OVFL_SHIFT) +#define CS35L34_M_IMON_OVFL_SHIFT 2 +#define CS35L34_M_IMON_OVFL (1 << CS35L34_M_IMON_OVFL_SHIFT) +#define CS35L34_M_VPMON_OVFL_SHIFT 1 +#define CS35L34_M_VPMON_OVFL (1 << CS35L34_M_VPMON_OVFL_SHIFT) +#define CS35L34_M_VBSTMON_OVFL_SHIFT 1 +#define CS35L34_M_VBSTMON_OVFL (1 << CS35L34_M_VBSTMON_OVFL_SHIFT) + +/* CS35L34_INT_1 */ +#define CS35L34_CAL_ERR (1 << CS35L34_M_CAL_ERR_SHIFT) +#define CS35L34_ALIVE_ERR (1 << CS35L34_M_ALIVE_ERR_SHIFT) +#define CS35L34_M_ADSP_CLK_ERR (1 << CS35L34_M_ADSP_CLK_SHIFT) +#define CS35L34_MCLK_ERR (1 << CS35L34_M_MCLK_SHIFT) +#define CS35L34_AMP_SHORT (1 << CS35L34_M_AMP_SHORT_SHIFT) +#define CS35L34_OTW (1 << CS35L34_M_OTW_SHIFT) +#define CS35L34_OTE (1 << CS35L34_M_OTE_SHIFT) + +/* CS35L34_INT_2 */ +#define CS35L34_PDN_DONE (1 << CS35L34_M_PDN_DONE_SHIFT) +#define CS35L34_PRED_ERR (1 << CS35L34_M_PRED_SHIFT) +#define CS35L34_PRED_CLR (1 << CS35L34_M_PRED_CLR_SHIFT) +#define CS35L34_VPBR_ERR (1 << CS35L34_M_VPBR_SHIFT) +#define CS35L34_VPBR_CLR (1 << CS35L34_M_VPBR_CLR_SHIFT) + +/* CS35L34_INT_3 */ +#define CS35L34_BST_HIGH (1 << CS35L34_M_BST_HIGH_SHIFT) +#define CS35L34_BST_HIGH_FLAG (1 << CS35L34_M_BST_HIGH_FLAG_SHIFT) +#define CS35L34_BST_IPK_FLAG (1 << CS35L34_M_BST_IPK_FLAG_SHIFT) +#define CS35L34_LBST_SHORT (1 << CS35L34_M_LBST_SHORT_SHIFT) + +/* CS35L34_INT_4 */ +#define CS35L34_VMON_OVFL (1 << CS35L34_M_VMON_OVFL_SHIFT) +#define CS35L34_IMON_OVFL (1 << CS35L34_M_IMON_OVFL_SHIFT) +#define CS35L34_VPMON_OVFL (1 << CS35L34_M_VPMON_OVFL_SHIFT) +#define CS35L34_VBSTMON_OVFL (1 << CS35L34_M_VBSTMON_OVFL_SHIFT) + +/* CS35L34_{RX,TX}_X */ +#define CS35L34_X_STATE_SHIFT 7 +#define CS35L34_X_STATE (1 << CS35L34_X_STATE_SHIFT) +#define CS35L34_X_LOC_SHIFT 0 +#define CS35L34_X_LOC (0x1F << CS35L34_X_LOC_SHIFT) + +#define CS35L34_RATES (SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_32000) +#define CS35L34_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#endif diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 18baea2f7d65..84f86745c30e 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -148,11 +148,11 @@ SND_SOC_DAPM_OUTPUT("AOUTR"), }; static const struct snd_soc_dapm_route cs4270_dapm_routes[] = { - { "Capture", NULL, "AINA" }, - { "Capture", NULL, "AINB" }, + { "Capture", NULL, "AINL" }, + { "Capture", NULL, "AINR" }, - { "AOUTA", NULL, "Playback" }, - { "AOUTB", NULL, "Playback" }, + { "AOUTL", NULL, "Playback" }, + { "AOUTR", NULL, "Playback" }, }; /** diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c new file mode 100644 index 000000000000..55e4520cdcaf --- /dev/null +++ b/sound/soc/codecs/cs42l42.c @@ -0,0 +1,1986 @@ +/* + * cs42l42.c -- CS42L42 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: James Schulman <james.schulman@cirrus.com> + * Author: Brian Austin <brian.austin@cirrus.com> + * Author: Michael White <michael.white@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <dt-bindings/sound/cs42l42.h> + +#include "cs42l42.h" + +static const struct reg_default cs42l42_reg_defaults[] = { + { CS42L42_FRZ_CTL, 0x00 }, + { CS42L42_SRC_CTL, 0x10 }, + { CS42L42_MCLK_STATUS, 0x02 }, + { CS42L42_MCLK_CTL, 0x02 }, + { CS42L42_SFTRAMP_RATE, 0xA4 }, + { CS42L42_I2C_DEBOUNCE, 0x88 }, + { CS42L42_I2C_STRETCH, 0x03 }, + { CS42L42_I2C_TIMEOUT, 0xB7 }, + { CS42L42_PWR_CTL1, 0xFF }, + { CS42L42_PWR_CTL2, 0x84 }, + { CS42L42_PWR_CTL3, 0x20 }, + { CS42L42_RSENSE_CTL1, 0x40 }, + { CS42L42_RSENSE_CTL2, 0x00 }, + { CS42L42_OSC_SWITCH, 0x00 }, + { CS42L42_OSC_SWITCH_STATUS, 0x05 }, + { CS42L42_RSENSE_CTL3, 0x1B }, + { CS42L42_TSENSE_CTL, 0x1B }, + { CS42L42_TSRS_INT_DISABLE, 0x00 }, + { CS42L42_TRSENSE_STATUS, 0x00 }, + { CS42L42_HSDET_CTL1, 0x77 }, + { CS42L42_HSDET_CTL2, 0x00 }, + { CS42L42_HS_SWITCH_CTL, 0xF3 }, + { CS42L42_HS_DET_STATUS, 0x00 }, + { CS42L42_HS_CLAMP_DISABLE, 0x00 }, + { CS42L42_MCLK_SRC_SEL, 0x00 }, + { CS42L42_SPDIF_CLK_CFG, 0x00 }, + { CS42L42_FSYNC_PW_LOWER, 0x00 }, + { CS42L42_FSYNC_PW_UPPER, 0x00 }, + { CS42L42_FSYNC_P_LOWER, 0xF9 }, + { CS42L42_FSYNC_P_UPPER, 0x00 }, + { CS42L42_ASP_CLK_CFG, 0x00 }, + { CS42L42_ASP_FRM_CFG, 0x10 }, + { CS42L42_FS_RATE_EN, 0x00 }, + { CS42L42_IN_ASRC_CLK, 0x00 }, + { CS42L42_OUT_ASRC_CLK, 0x00 }, + { CS42L42_PLL_DIV_CFG1, 0x00 }, + { CS42L42_ADC_OVFL_STATUS, 0x00 }, + { CS42L42_MIXER_STATUS, 0x00 }, + { CS42L42_SRC_STATUS, 0x00 }, + { CS42L42_ASP_RX_STATUS, 0x00 }, + { CS42L42_ASP_TX_STATUS, 0x00 }, + { CS42L42_CODEC_STATUS, 0x00 }, + { CS42L42_DET_INT_STATUS1, 0x00 }, + { CS42L42_DET_INT_STATUS2, 0x00 }, + { CS42L42_SRCPL_INT_STATUS, 0x00 }, + { CS42L42_VPMON_STATUS, 0x00 }, + { CS42L42_PLL_LOCK_STATUS, 0x00 }, + { CS42L42_TSRS_PLUG_STATUS, 0x00 }, + { CS42L42_ADC_OVFL_INT_MASK, 0x01 }, + { CS42L42_MIXER_INT_MASK, 0x0F }, + { CS42L42_SRC_INT_MASK, 0x0F }, + { CS42L42_ASP_RX_INT_MASK, 0x1F }, + { CS42L42_ASP_TX_INT_MASK, 0x0F }, + { CS42L42_CODEC_INT_MASK, 0x03 }, + { CS42L42_SRCPL_INT_MASK, 0xFF }, + { CS42L42_VPMON_INT_MASK, 0x01 }, + { CS42L42_PLL_LOCK_INT_MASK, 0x01 }, + { CS42L42_TSRS_PLUG_INT_MASK, 0x0F }, + { CS42L42_PLL_CTL1, 0x00 }, + { CS42L42_PLL_DIV_FRAC0, 0x00 }, + { CS42L42_PLL_DIV_FRAC1, 0x00 }, + { CS42L42_PLL_DIV_FRAC2, 0x00 }, + { CS42L42_PLL_DIV_INT, 0x40 }, + { CS42L42_PLL_CTL3, 0x10 }, + { CS42L42_PLL_CAL_RATIO, 0x80 }, + { CS42L42_PLL_CTL4, 0x03 }, + { CS42L42_LOAD_DET_RCSTAT, 0x00 }, + { CS42L42_LOAD_DET_DONE, 0x00 }, + { CS42L42_LOAD_DET_EN, 0x00 }, + { CS42L42_HSBIAS_SC_AUTOCTL, 0x03 }, + { CS42L42_WAKE_CTL, 0xC0 }, + { CS42L42_ADC_DISABLE_MUTE, 0x00 }, + { CS42L42_TIPSENSE_CTL, 0x02 }, + { CS42L42_MISC_DET_CTL, 0x03 }, + { CS42L42_MIC_DET_CTL1, 0x1F }, + { CS42L42_MIC_DET_CTL2, 0x2F }, + { CS42L42_DET_STATUS1, 0x00 }, + { CS42L42_DET_STATUS2, 0x00 }, + { CS42L42_DET_INT1_MASK, 0xE0 }, + { CS42L42_DET_INT2_MASK, 0xFF }, + { CS42L42_HS_BIAS_CTL, 0xC2 }, + { CS42L42_ADC_CTL, 0x00 }, + { CS42L42_ADC_VOLUME, 0x00 }, + { CS42L42_ADC_WNF_HPF_CTL, 0x71 }, + { CS42L42_DAC_CTL1, 0x00 }, + { CS42L42_DAC_CTL2, 0x02 }, + { CS42L42_HP_CTL, 0x0D }, + { CS42L42_CLASSH_CTL, 0x07 }, + { CS42L42_MIXER_CHA_VOL, 0x3F }, + { CS42L42_MIXER_ADC_VOL, 0x3F }, + { CS42L42_MIXER_CHB_VOL, 0x3F }, + { CS42L42_EQ_COEF_IN0, 0x22 }, + { CS42L42_EQ_COEF_IN1, 0x00 }, + { CS42L42_EQ_COEF_IN2, 0x00 }, + { CS42L42_EQ_COEF_IN3, 0x00 }, + { CS42L42_EQ_COEF_RW, 0x00 }, + { CS42L42_EQ_COEF_OUT0, 0x00 }, + { CS42L42_EQ_COEF_OUT1, 0x00 }, + { CS42L42_EQ_COEF_OUT2, 0x00 }, + { CS42L42_EQ_COEF_OUT3, 0x00 }, + { CS42L42_EQ_INIT_STAT, 0x00 }, + { CS42L42_EQ_START_FILT, 0x00 }, + { CS42L42_EQ_MUTE_CTL, 0x00 }, + { CS42L42_SP_RX_CH_SEL, 0x04 }, + { CS42L42_SP_RX_ISOC_CTL, 0x04 }, + { CS42L42_SP_RX_FS, 0x8C }, + { CS42l42_SPDIF_CH_SEL, 0x0E }, + { CS42L42_SP_TX_ISOC_CTL, 0x04 }, + { CS42L42_SP_TX_FS, 0xCC }, + { CS42L42_SPDIF_SW_CTL1, 0x3F }, + { CS42L42_SRC_SDIN_FS, 0x40 }, + { CS42L42_SRC_SDOUT_FS, 0x40 }, + { CS42L42_SPDIF_CTL1, 0x01 }, + { CS42L42_SPDIF_CTL2, 0x00 }, + { CS42L42_SPDIF_CTL3, 0x00 }, + { CS42L42_SPDIF_CTL4, 0x42 }, + { CS42L42_ASP_TX_SZ_EN, 0x00 }, + { CS42L42_ASP_TX_CH_EN, 0x00 }, + { CS42L42_ASP_TX_CH_AP_RES, 0x0F }, + { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_TX_HIZ_DLY_CFG, 0x00 }, + { CS42L42_ASP_TX_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH2_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_EN, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH1_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI1_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH2_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI1_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 }, + { CS42L42_SUB_REVID, 0x03 }, +}; + +static bool cs42l42_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L42_PAGE_REGISTER: + case CS42L42_DEVID_AB: + case CS42L42_DEVID_CD: + case CS42L42_DEVID_E: + case CS42L42_FABID: + case CS42L42_REVID: + case CS42L42_FRZ_CTL: + case CS42L42_SRC_CTL: + case CS42L42_MCLK_STATUS: + case CS42L42_MCLK_CTL: + case CS42L42_SFTRAMP_RATE: + case CS42L42_I2C_DEBOUNCE: + case CS42L42_I2C_STRETCH: + case CS42L42_I2C_TIMEOUT: + case CS42L42_PWR_CTL1: + case CS42L42_PWR_CTL2: + case CS42L42_PWR_CTL3: + case CS42L42_RSENSE_CTL1: + case CS42L42_RSENSE_CTL2: + case CS42L42_OSC_SWITCH: + case CS42L42_OSC_SWITCH_STATUS: + case CS42L42_RSENSE_CTL3: + case CS42L42_TSENSE_CTL: + case CS42L42_TSRS_INT_DISABLE: + case CS42L42_TRSENSE_STATUS: + case CS42L42_HSDET_CTL1: + case CS42L42_HSDET_CTL2: + case CS42L42_HS_SWITCH_CTL: + case CS42L42_HS_DET_STATUS: + case CS42L42_HS_CLAMP_DISABLE: + case CS42L42_MCLK_SRC_SEL: + case CS42L42_SPDIF_CLK_CFG: + case CS42L42_FSYNC_PW_LOWER: + case CS42L42_FSYNC_PW_UPPER: + case CS42L42_FSYNC_P_LOWER: + case CS42L42_FSYNC_P_UPPER: + case CS42L42_ASP_CLK_CFG: + case CS42L42_ASP_FRM_CFG: + case CS42L42_FS_RATE_EN: + case CS42L42_IN_ASRC_CLK: + case CS42L42_OUT_ASRC_CLK: + case CS42L42_PLL_DIV_CFG1: + case CS42L42_ADC_OVFL_STATUS: + case CS42L42_MIXER_STATUS: + case CS42L42_SRC_STATUS: + case CS42L42_ASP_RX_STATUS: + case CS42L42_ASP_TX_STATUS: + case CS42L42_CODEC_STATUS: + case CS42L42_DET_INT_STATUS1: + case CS42L42_DET_INT_STATUS2: + case CS42L42_SRCPL_INT_STATUS: + case CS42L42_VPMON_STATUS: + case CS42L42_PLL_LOCK_STATUS: + case CS42L42_TSRS_PLUG_STATUS: + case CS42L42_ADC_OVFL_INT_MASK: + case CS42L42_MIXER_INT_MASK: + case CS42L42_SRC_INT_MASK: + case CS42L42_ASP_RX_INT_MASK: + case CS42L42_ASP_TX_INT_MASK: + case CS42L42_CODEC_INT_MASK: + case CS42L42_SRCPL_INT_MASK: + case CS42L42_VPMON_INT_MASK: + case CS42L42_PLL_LOCK_INT_MASK: + case CS42L42_TSRS_PLUG_INT_MASK: + case CS42L42_PLL_CTL1: + case CS42L42_PLL_DIV_FRAC0: + case CS42L42_PLL_DIV_FRAC1: + case CS42L42_PLL_DIV_FRAC2: + case CS42L42_PLL_DIV_INT: + case CS42L42_PLL_CTL3: + case CS42L42_PLL_CAL_RATIO: + case CS42L42_PLL_CTL4: + case CS42L42_LOAD_DET_RCSTAT: + case CS42L42_LOAD_DET_DONE: + case CS42L42_LOAD_DET_EN: + case CS42L42_HSBIAS_SC_AUTOCTL: + case CS42L42_WAKE_CTL: + case CS42L42_ADC_DISABLE_MUTE: + case CS42L42_TIPSENSE_CTL: + case CS42L42_MISC_DET_CTL: + case CS42L42_MIC_DET_CTL1: + case CS42L42_MIC_DET_CTL2: + case CS42L42_DET_STATUS1: + case CS42L42_DET_STATUS2: + case CS42L42_DET_INT1_MASK: + case CS42L42_DET_INT2_MASK: + case CS42L42_HS_BIAS_CTL: + case CS42L42_ADC_CTL: + case CS42L42_ADC_VOLUME: + case CS42L42_ADC_WNF_HPF_CTL: + case CS42L42_DAC_CTL1: + case CS42L42_DAC_CTL2: + case CS42L42_HP_CTL: + case CS42L42_CLASSH_CTL: + case CS42L42_MIXER_CHA_VOL: + case CS42L42_MIXER_ADC_VOL: + case CS42L42_MIXER_CHB_VOL: + case CS42L42_EQ_COEF_IN0: + case CS42L42_EQ_COEF_IN1: + case CS42L42_EQ_COEF_IN2: + case CS42L42_EQ_COEF_IN3: + case CS42L42_EQ_COEF_RW: + case CS42L42_EQ_COEF_OUT0: + case CS42L42_EQ_COEF_OUT1: + case CS42L42_EQ_COEF_OUT2: + case CS42L42_EQ_COEF_OUT3: + case CS42L42_EQ_INIT_STAT: + case CS42L42_EQ_START_FILT: + case CS42L42_EQ_MUTE_CTL: + case CS42L42_SP_RX_CH_SEL: + case CS42L42_SP_RX_ISOC_CTL: + case CS42L42_SP_RX_FS: + case CS42l42_SPDIF_CH_SEL: + case CS42L42_SP_TX_ISOC_CTL: + case CS42L42_SP_TX_FS: + case CS42L42_SPDIF_SW_CTL1: + case CS42L42_SRC_SDIN_FS: + case CS42L42_SRC_SDOUT_FS: + case CS42L42_SPDIF_CTL1: + case CS42L42_SPDIF_CTL2: + case CS42L42_SPDIF_CTL3: + case CS42L42_SPDIF_CTL4: + case CS42L42_ASP_TX_SZ_EN: + case CS42L42_ASP_TX_CH_EN: + case CS42L42_ASP_TX_CH_AP_RES: + case CS42L42_ASP_TX_CH1_BIT_MSB: + case CS42L42_ASP_TX_CH1_BIT_LSB: + case CS42L42_ASP_TX_HIZ_DLY_CFG: + case CS42L42_ASP_TX_CH2_BIT_MSB: + case CS42L42_ASP_TX_CH2_BIT_LSB: + case CS42L42_ASP_RX_DAI0_EN: + case CS42L42_ASP_RX_DAI0_CH1_AP_RES: + case CS42L42_ASP_RX_DAI0_CH1_BIT_MSB: + case CS42L42_ASP_RX_DAI0_CH1_BIT_LSB: + case CS42L42_ASP_RX_DAI0_CH2_AP_RES: + case CS42L42_ASP_RX_DAI0_CH2_BIT_MSB: + case CS42L42_ASP_RX_DAI0_CH2_BIT_LSB: + case CS42L42_ASP_RX_DAI0_CH3_AP_RES: + case CS42L42_ASP_RX_DAI0_CH3_BIT_MSB: + case CS42L42_ASP_RX_DAI0_CH3_BIT_LSB: + case CS42L42_ASP_RX_DAI0_CH4_AP_RES: + case CS42L42_ASP_RX_DAI0_CH4_BIT_MSB: + case CS42L42_ASP_RX_DAI0_CH4_BIT_LSB: + case CS42L42_ASP_RX_DAI1_CH1_AP_RES: + case CS42L42_ASP_RX_DAI1_CH1_BIT_MSB: + case CS42L42_ASP_RX_DAI1_CH1_BIT_LSB: + case CS42L42_ASP_RX_DAI1_CH2_AP_RES: + case CS42L42_ASP_RX_DAI1_CH2_BIT_MSB: + case CS42L42_ASP_RX_DAI1_CH2_BIT_LSB: + case CS42L42_SUB_REVID: + return true; + default: + return false; + } +} + +static bool cs42l42_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L42_DEVID_AB: + case CS42L42_DEVID_CD: + case CS42L42_DEVID_E: + case CS42L42_MCLK_STATUS: + case CS42L42_TRSENSE_STATUS: + case CS42L42_HS_DET_STATUS: + case CS42L42_ADC_OVFL_STATUS: + case CS42L42_MIXER_STATUS: + case CS42L42_SRC_STATUS: + case CS42L42_ASP_RX_STATUS: + case CS42L42_ASP_TX_STATUS: + case CS42L42_CODEC_STATUS: + case CS42L42_DET_INT_STATUS1: + case CS42L42_DET_INT_STATUS2: + case CS42L42_SRCPL_INT_STATUS: + case CS42L42_VPMON_STATUS: + case CS42L42_PLL_LOCK_STATUS: + case CS42L42_TSRS_PLUG_STATUS: + case CS42L42_LOAD_DET_RCSTAT: + case CS42L42_LOAD_DET_DONE: + case CS42L42_DET_STATUS1: + case CS42L42_DET_STATUS2: + return true; + default: + return false; + } +} + +static const struct regmap_range_cfg cs42l42_page_range = { + .name = "Pages", + .range_min = 0, + .range_max = CS42L42_MAX_REGISTER, + .selector_reg = CS42L42_PAGE_REGISTER, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 256, +}; + +static const struct regmap_config cs42l42_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .readable_reg = cs42l42_readable_register, + .volatile_reg = cs42l42_volatile_register, + + .ranges = &cs42l42_page_range, + .num_ranges = 1, + + .max_register = CS42L42_MAX_REGISTER, + .reg_defaults = cs42l42_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + +static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false); +static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false); + +static const char * const cs42l42_hpf_freq_text[] = { + "1.86Hz", "120Hz", "235Hz", "466Hz" +}; + +static SOC_ENUM_SINGLE_DECL(cs42l42_hpf_freq_enum, CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_HPF_CF_SHIFT, + cs42l42_hpf_freq_text); + +static const char * const cs42l42_wnf3_freq_text[] = { + "160Hz", "180Hz", "200Hz", "220Hz", + "240Hz", "260Hz", "280Hz", "300Hz" +}; + +static SOC_ENUM_SINGLE_DECL(cs42l42_wnf3_freq_enum, CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_WNF_CF_SHIFT, + cs42l42_wnf3_freq_text); + +static const char * const cs42l42_wnf05_freq_text[] = { + "280Hz", "315Hz", "350Hz", "385Hz", + "420Hz", "455Hz", "490Hz", "525Hz" +}; + +static SOC_ENUM_SINGLE_DECL(cs42l42_wnf05_freq_enum, CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_WNF_CF_SHIFT, + cs42l42_wnf05_freq_text); + +static const struct snd_kcontrol_new cs42l42_snd_controls[] = { + /* ADC Volume and Filter Controls */ + SOC_SINGLE("ADC Notch Switch", CS42L42_ADC_CTL, + CS42L42_ADC_NOTCH_DIS_SHIFT, true, false), + SOC_SINGLE("ADC Weak Force Switch", CS42L42_ADC_CTL, + CS42L42_ADC_FORCE_WEAK_VCM_SHIFT, true, false), + SOC_SINGLE("ADC Invert Switch", CS42L42_ADC_CTL, + CS42L42_ADC_INV_SHIFT, true, false), + SOC_SINGLE("ADC Boost Switch", CS42L42_ADC_CTL, + CS42L42_ADC_DIG_BOOST_SHIFT, true, false), + SOC_SINGLE_SX_TLV("ADC Volume", CS42L42_ADC_VOLUME, + CS42L42_ADC_VOL_SHIFT, 0xA0, 0x6C, adc_tlv), + SOC_SINGLE("ADC WNF Switch", CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_WNF_EN_SHIFT, true, false), + SOC_SINGLE("ADC HPF Switch", CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_HPF_EN_SHIFT, true, false), + SOC_ENUM("HPF Corner Freq", cs42l42_hpf_freq_enum), + SOC_ENUM("WNF 3dB Freq", cs42l42_wnf3_freq_enum), + SOC_ENUM("WNF 05dB Freq", cs42l42_wnf05_freq_enum), + + /* DAC Volume and Filter Controls */ + SOC_SINGLE("DACA Invert Switch", CS42L42_DAC_CTL1, + CS42L42_DACA_INV_SHIFT, true, false), + SOC_SINGLE("DACB Invert Switch", CS42L42_DAC_CTL1, + CS42L42_DACB_INV_SHIFT, true, false), + SOC_SINGLE("DAC HPF Switch", CS42L42_DAC_CTL2, + CS42L42_DAC_HPF_EN_SHIFT, true, false), + SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL, + CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT, + 0x3e, 1, mixer_tlv) +}; + +static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + if (event & SND_SOC_DAPM_POST_PMU) { + /* Enable the channels */ + snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN, + CS42L42_ASP_RX0_CH_EN_MASK, + (CS42L42_ASP_RX0_CH1_EN | + CS42L42_ASP_RX0_CH2_EN) << + CS42L42_ASP_RX0_CH_EN_SHIFT); + + /* Power up */ + snd_soc_update_bits(codec, CS42L42_PWR_CTL1, + CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | + CS42L42_HP_PDN_MASK, 0); + } else if (event & SND_SOC_DAPM_PRE_PMD) { + /* Disable the channels */ + snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN, + CS42L42_ASP_RX0_CH_EN_MASK, 0); + + /* Power down */ + snd_soc_update_bits(codec, CS42L42_PWR_CTL1, + CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | + CS42L42_HP_PDN_MASK, + CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | + CS42L42_HP_PDN_MASK); + } else { + dev_err(codec->dev, "Invalid event 0x%x\n", event); + } + return 0; +} + +static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS42L42_ASP_CLK_CFG, + CS42L42_ASP_SCLK_EN_SHIFT, false), + SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0, + 0, NULL, 0, cs42l42_hpdrv_evt, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD) +}; + +static const struct snd_soc_dapm_route cs42l42_audio_map[] = { + {"SDIN", NULL, "Playback"}, + {"HPDRV", NULL, "SDIN"}, + {"HP", NULL, "HPDRV"} +}; + +static int cs42l42_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + regcache_cache_only(cs42l42->regmap, false); + regcache_sync(cs42l42->regmap); + ret = regulator_bulk_enable( + ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + if (ret != 0) { + dev_err(codec->dev, + "Failed to enable regulators: %d\n", + ret); + return ret; + } + } + break; + case SND_SOC_BIAS_OFF: + + regcache_cache_only(cs42l42->regmap, true); + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + break; + } + + return 0; +} + +static int cs42l42_codec_probe(struct snd_soc_codec *codec) +{ + struct cs42l42_private *cs42l42 = + (struct cs42l42_private *)snd_soc_codec_get_drvdata(codec); + + cs42l42->codec = codec; + + return 0; +} + +static const struct snd_soc_codec_driver soc_codec_dev_cs42l42 = { + .probe = cs42l42_codec_probe, + .set_bias_level = cs42l42_set_bias_level, + .ignore_pmdown_time = true, + + .component_driver = { + .dapm_widgets = cs42l42_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets), + .dapm_routes = cs42l42_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs42l42_audio_map), + + .controls = cs42l42_snd_controls, + .num_controls = ARRAY_SIZE(cs42l42_snd_controls), + }, +}; + +struct cs42l42_pll_params { + u32 sclk; + u8 mclk_div; + u8 mclk_src_sel; + u8 sclk_prediv; + u8 pll_div_int; + u32 pll_div_frac; + u8 pll_mode; + u8 pll_divout; + u32 mclk_int; + u8 pll_cal_ratio; +}; + +/* + * Common PLL Settings for given SCLK + * Table 4-5 from the Datasheet + */ +static const struct cs42l42_pll_params pll_ratio_table[] = { + { 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125 }, + { 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, + { 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, + { 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, + { 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96 }, + { 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94 }, + { 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, + { 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, + { 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, + { 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0 }, + { 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0 }, + { 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0 }, + { 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0 }, + { 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0 }, + { 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0 } +}; + +static int cs42l42_pll_config(struct snd_soc_codec *codec) +{ + struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); + int i; + u32 fsync; + + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { + if (pll_ratio_table[i].sclk == cs42l42->sclk) { + /* Configure the internal sample rate */ + snd_soc_update_bits(codec, CS42L42_MCLK_CTL, + CS42L42_INTERNAL_FS_MASK, + ((pll_ratio_table[i].mclk_int != + 12000000) && + (pll_ratio_table[i].mclk_int != + 24000000)) << + CS42L42_INTERNAL_FS_SHIFT); + /* Set the MCLK src (PLL or SCLK) and the divide + * ratio + */ + snd_soc_update_bits(codec, CS42L42_MCLK_SRC_SEL, + CS42L42_MCLK_SRC_SEL_MASK | + CS42L42_MCLKDIV_MASK, + (pll_ratio_table[i].mclk_src_sel + << CS42L42_MCLK_SRC_SEL_SHIFT) | + (pll_ratio_table[i].mclk_div << + CS42L42_MCLKDIV_SHIFT)); + /* Set up the LRCLK */ + fsync = cs42l42->sclk / cs42l42->srate; + if (((fsync * cs42l42->srate) != cs42l42->sclk) + || ((fsync % 2) != 0)) { + dev_err(codec->dev, + "Unsupported sclk %d/sample rate %d\n", + cs42l42->sclk, + cs42l42->srate); + return -EINVAL; + } + /* Set the LRCLK period */ + snd_soc_update_bits(codec, + CS42L42_FSYNC_P_LOWER, + CS42L42_FSYNC_PERIOD_MASK, + CS42L42_FRAC0_VAL(fsync - 1) << + CS42L42_FSYNC_PERIOD_SHIFT); + snd_soc_update_bits(codec, + CS42L42_FSYNC_P_UPPER, + CS42L42_FSYNC_PERIOD_MASK, + CS42L42_FRAC1_VAL(fsync - 1) << + CS42L42_FSYNC_PERIOD_SHIFT); + /* Set the LRCLK to 50% duty cycle */ + fsync = fsync / 2; + snd_soc_update_bits(codec, + CS42L42_FSYNC_PW_LOWER, + CS42L42_FSYNC_PULSE_WIDTH_MASK, + CS42L42_FRAC0_VAL(fsync - 1) << + CS42L42_FSYNC_PULSE_WIDTH_SHIFT); + snd_soc_update_bits(codec, + CS42L42_FSYNC_PW_UPPER, + CS42L42_FSYNC_PULSE_WIDTH_MASK, + CS42L42_FRAC1_VAL(fsync - 1) << + CS42L42_FSYNC_PULSE_WIDTH_SHIFT); + snd_soc_update_bits(codec, + CS42L42_ASP_FRM_CFG, + CS42L42_ASP_5050_MASK, + CS42L42_ASP_5050_MASK); + /* Set the frame delay to 1.0 SCLK clocks */ + snd_soc_update_bits(codec, CS42L42_ASP_FRM_CFG, + CS42L42_ASP_FSD_MASK, + CS42L42_ASP_FSD_1_0 << + CS42L42_ASP_FSD_SHIFT); + /* Set the sample rates (96k or lower) */ + snd_soc_update_bits(codec, CS42L42_FS_RATE_EN, + CS42L42_FS_EN_MASK, + (CS42L42_FS_EN_IASRC_96K | + CS42L42_FS_EN_OASRC_96K) << + CS42L42_FS_EN_SHIFT); + /* Set the input/output internal MCLK clock ~12 MHz */ + snd_soc_update_bits(codec, CS42L42_IN_ASRC_CLK, + CS42L42_CLK_IASRC_SEL_MASK, + CS42L42_CLK_IASRC_SEL_12 << + CS42L42_CLK_IASRC_SEL_SHIFT); + snd_soc_update_bits(codec, + CS42L42_OUT_ASRC_CLK, + CS42L42_CLK_OASRC_SEL_MASK, + CS42L42_CLK_OASRC_SEL_12 << + CS42L42_CLK_OASRC_SEL_SHIFT); + /* channel 1 on low LRCLK, 32 bit */ + snd_soc_update_bits(codec, + CS42L42_ASP_RX_DAI0_CH1_AP_RES, + CS42L42_ASP_RX_CH_AP_MASK | + CS42L42_ASP_RX_CH_RES_MASK, + (CS42L42_ASP_RX_CH_AP_LOW << + CS42L42_ASP_RX_CH_AP_SHIFT) | + (CS42L42_ASP_RX_CH_RES_32 << + CS42L42_ASP_RX_CH_RES_SHIFT)); + /* Channel 2 on high LRCLK, 32 bit */ + snd_soc_update_bits(codec, + CS42L42_ASP_RX_DAI0_CH2_AP_RES, + CS42L42_ASP_RX_CH_AP_MASK | + CS42L42_ASP_RX_CH_RES_MASK, + (CS42L42_ASP_RX_CH_AP_HI << + CS42L42_ASP_RX_CH_AP_SHIFT) | + (CS42L42_ASP_RX_CH_RES_32 << + CS42L42_ASP_RX_CH_RES_SHIFT)); + if (pll_ratio_table[i].mclk_src_sel == 0) { + /* Pass the clock straight through */ + snd_soc_update_bits(codec, + CS42L42_PLL_CTL1, + CS42L42_PLL_START_MASK, 0); + } else { + /* Configure PLL per table 4-5 */ + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_CFG1, + CS42L42_SCLK_PREDIV_MASK, + pll_ratio_table[i].sclk_prediv + << CS42L42_SCLK_PREDIV_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_INT, + CS42L42_PLL_DIV_INT_MASK, + pll_ratio_table[i].pll_div_int + << CS42L42_PLL_DIV_INT_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_FRAC0, + CS42L42_PLL_DIV_FRAC_MASK, + CS42L42_FRAC0_VAL( + pll_ratio_table[i].pll_div_frac) + << CS42L42_PLL_DIV_FRAC_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_FRAC1, + CS42L42_PLL_DIV_FRAC_MASK, + CS42L42_FRAC1_VAL( + pll_ratio_table[i].pll_div_frac) + << CS42L42_PLL_DIV_FRAC_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_FRAC2, + CS42L42_PLL_DIV_FRAC_MASK, + CS42L42_FRAC2_VAL( + pll_ratio_table[i].pll_div_frac) + << CS42L42_PLL_DIV_FRAC_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_CTL4, + CS42L42_PLL_MODE_MASK, + pll_ratio_table[i].pll_mode + << CS42L42_PLL_MODE_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_CTL3, + CS42L42_PLL_DIVOUT_MASK, + pll_ratio_table[i].pll_divout + << CS42L42_PLL_DIVOUT_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_CAL_RATIO, + CS42L42_PLL_CAL_RATIO_MASK, + pll_ratio_table[i].pll_cal_ratio + << CS42L42_PLL_CAL_RATIO_SHIFT); + } + return 0; + } + } + + return -EINVAL; +} + +static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u32 asp_cfg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFM: + asp_cfg_val |= CS42L42_ASP_MASTER_MODE << + CS42L42_ASP_MODE_SHIFT; + break; + case SND_SOC_DAIFMT_CBS_CFS: + asp_cfg_val |= CS42L42_ASP_SLAVE_MODE << + CS42L42_ASP_MODE_SHIFT; + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + /* Bitclock/frame inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + asp_cfg_val |= CS42L42_ASP_POL_INV << + CS42L42_ASP_LCPOL_IN_SHIFT; + break; + case SND_SOC_DAIFMT_IB_NF: + asp_cfg_val |= CS42L42_ASP_POL_INV << + CS42L42_ASP_SCPOL_IN_DAC_SHIFT; + break; + case SND_SOC_DAIFMT_IB_IF: + asp_cfg_val |= CS42L42_ASP_POL_INV << + CS42L42_ASP_LCPOL_IN_SHIFT; + asp_cfg_val |= CS42L42_ASP_POL_INV << + CS42L42_ASP_SCPOL_IN_DAC_SHIFT; + break; + } + + snd_soc_update_bits(codec, CS42L42_ASP_CLK_CFG, + CS42L42_ASP_MODE_MASK | + CS42L42_ASP_SCPOL_IN_DAC_MASK | + CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val); + + return 0; +} + +static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); + int retval; + + cs42l42->srate = params_rate(params); + cs42l42->swidth = params_width(params); + + retval = cs42l42_pll_config(codec); + + return retval; +} + +static int cs42l42_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); + + cs42l42->sclk = freq; + + return 0; +} + +static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int regval; + u8 fullScaleVol; + + if (mute) { + /* Mark SCLK as not present to turn on the internal + * oscillator. + */ + snd_soc_update_bits(codec, CS42L42_OSC_SWITCH, + CS42L42_SCLK_PRESENT_MASK, 0); + + snd_soc_update_bits(codec, CS42L42_PLL_CTL1, + CS42L42_PLL_START_MASK, + 0 << CS42L42_PLL_START_SHIFT); + + /* Mute the headphone */ + snd_soc_update_bits(codec, CS42L42_HP_CTL, + CS42L42_HP_ANA_AMUTE_MASK | + CS42L42_HP_ANA_BMUTE_MASK, + CS42L42_HP_ANA_AMUTE_MASK | + CS42L42_HP_ANA_BMUTE_MASK); + } else { + snd_soc_update_bits(codec, CS42L42_PLL_CTL1, + CS42L42_PLL_START_MASK, + 1 << CS42L42_PLL_START_SHIFT); + /* Read the headphone load */ + regval = snd_soc_read(codec, CS42L42_LOAD_DET_RCSTAT); + if (((regval & CS42L42_RLA_STAT_MASK) >> + CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) { + fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK; + } else { + fullScaleVol = 0; + } + + /* Un-mute the headphone, set the full scale volume flag */ + snd_soc_update_bits(codec, CS42L42_HP_CTL, + CS42L42_HP_ANA_AMUTE_MASK | + CS42L42_HP_ANA_BMUTE_MASK | + CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol); + + /* Mark SCLK as present, turn off internal oscillator */ + snd_soc_update_bits(codec, CS42L42_OSC_SWITCH, + CS42L42_SCLK_PRESENT_MASK, + CS42L42_SCLK_PRESENT_MASK); + } + + return 0; +} + +#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + + +static struct snd_soc_dai_ops cs42l42_ops = { + .hw_params = cs42l42_pcm_hw_params, + .set_fmt = cs42l42_set_dai_fmt, + .set_sysclk = cs42l42_set_sysclk, + .digital_mute = cs42l42_digital_mute +}; + +static struct snd_soc_dai_driver cs42l42_dai = { + .name = "cs42l42", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = CS42L42_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = CS42L42_FORMATS, + }, + .ops = &cs42l42_ops, +}; + +static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) +{ + unsigned int hs_det_status; + unsigned int int_status; + + /* Mask the auto detect interrupt */ + regmap_update_bits(cs42l42->regmap, + CS42L42_CODEC_INT_MASK, + CS42L42_PDN_DONE_MASK | + CS42L42_HSDET_AUTO_DONE_MASK, + (1 << CS42L42_PDN_DONE_SHIFT) | + (1 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + + /* Set hs detect to automatic, disabled mode */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (2 << CS42L42_HSDET_CTRL_SHIFT) | + (2 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); + + /* Read and save the hs detection result */ + regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status); + + cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >> + CS42L42_HSDET_TYPE_SHIFT; + + /* Set up button detection */ + if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) || + (cs42l42->hs_type == CS42L42_PLUG_OMTP)) { + /* Set auto HS bias settings to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSBIAS_SC_AUTOCTL, + CS42L42_HSBIAS_SENSE_EN_MASK | + CS42L42_AUTO_HSBIAS_HIZ_MASK | + CS42L42_TIP_SENSE_EN_MASK | + CS42L42_HSBIAS_SENSE_TRIP_MASK, + (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | + (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | + (0 << CS42L42_TIP_SENSE_EN_SHIFT) | + (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + + /* Set up hs detect level sensitivity */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MIC_DET_CTL1, + CS42L42_LATCH_TO_VP_MASK | + CS42L42_EVENT_STAT_SEL_MASK | + CS42L42_HS_DET_LEVEL_MASK, + (1 << CS42L42_LATCH_TO_VP_SHIFT) | + (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | + (cs42l42->bias_thresholds[0] << + CS42L42_HS_DET_LEVEL_SHIFT)); + + /* Set auto HS bias settings to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSBIAS_SC_AUTOCTL, + CS42L42_HSBIAS_SENSE_EN_MASK | + CS42L42_AUTO_HSBIAS_HIZ_MASK | + CS42L42_TIP_SENSE_EN_MASK | + CS42L42_HSBIAS_SENSE_TRIP_MASK, + (1 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | + (1 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | + (0 << CS42L42_TIP_SENSE_EN_SHIFT) | + (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + + /* Turn on level detect circuitry */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (3 << CS42L42_HSBIAS_CTL_SHIFT) | + (0 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + + msleep(cs42l42->btn_det_init_dbnce); + + /* Clear any button interrupts before unmasking them */ + regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, + &int_status); + + /* Unmask button detect interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (0 << CS42L42_M_DETECT_TF_SHIFT) | + (0 << CS42L42_M_DETECT_FT_SHIFT) | + (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); + } else { + /* Make sure button detect and HS bias circuits are off */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (1 << CS42L42_HSBIAS_CTL_SHIFT) | + (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + } + + regmap_update_bits(cs42l42->regmap, + CS42L42_DAC_CTL2, + CS42L42_HPOUT_PULLDOWN_MASK | + CS42L42_HPOUT_LOAD_MASK | + CS42L42_HPOUT_CLAMP_MASK | + CS42L42_DAC_HPF_EN_MASK | + CS42L42_DAC_MON_EN_MASK, + (0 << CS42L42_HPOUT_PULLDOWN_SHIFT) | + (0 << CS42L42_HPOUT_LOAD_SHIFT) | + (0 << CS42L42_HPOUT_CLAMP_SHIFT) | + (1 << CS42L42_DAC_HPF_EN_SHIFT) | + (0 << CS42L42_DAC_MON_EN_SHIFT)); + + /* Unmask tip sense interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_TSRS_PLUG_INT_MASK, + CS42L42_RS_PLUG_MASK | + CS42L42_RS_UNPLUG_MASK | + CS42L42_TS_PLUG_MASK | + CS42L42_TS_UNPLUG_MASK, + (1 << CS42L42_RS_PLUG_SHIFT) | + (1 << CS42L42_RS_UNPLUG_SHIFT) | + (0 << CS42L42_TS_PLUG_SHIFT) | + (0 << CS42L42_TS_UNPLUG_SHIFT)); +} + +static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42) +{ + /* Mask tip sense interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_TSRS_PLUG_INT_MASK, + CS42L42_RS_PLUG_MASK | + CS42L42_RS_UNPLUG_MASK | + CS42L42_TS_PLUG_MASK | + CS42L42_TS_UNPLUG_MASK, + (1 << CS42L42_RS_PLUG_SHIFT) | + (1 << CS42L42_RS_UNPLUG_SHIFT) | + (1 << CS42L42_TS_PLUG_SHIFT) | + (1 << CS42L42_TS_UNPLUG_SHIFT)); + + /* Make sure button detect and HS bias circuits are off */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (1 << CS42L42_HSBIAS_CTL_SHIFT) | + (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + + /* Set auto HS bias settings to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSBIAS_SC_AUTOCTL, + CS42L42_HSBIAS_SENSE_EN_MASK | + CS42L42_AUTO_HSBIAS_HIZ_MASK | + CS42L42_TIP_SENSE_EN_MASK | + CS42L42_HSBIAS_SENSE_TRIP_MASK, + (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | + (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | + (0 << CS42L42_TIP_SENSE_EN_SHIFT) | + (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + + /* Set hs detect to manual, disabled mode */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (0 << CS42L42_HSDET_CTRL_SHIFT) | + (2 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); + + regmap_update_bits(cs42l42->regmap, + CS42L42_DAC_CTL2, + CS42L42_HPOUT_PULLDOWN_MASK | + CS42L42_HPOUT_LOAD_MASK | + CS42L42_HPOUT_CLAMP_MASK | + CS42L42_DAC_HPF_EN_MASK | + CS42L42_DAC_MON_EN_MASK, + (8 << CS42L42_HPOUT_PULLDOWN_SHIFT) | + (0 << CS42L42_HPOUT_LOAD_SHIFT) | + (1 << CS42L42_HPOUT_CLAMP_SHIFT) | + (1 << CS42L42_DAC_HPF_EN_SHIFT) | + (1 << CS42L42_DAC_MON_EN_SHIFT)); + + /* Power up HS bias to 2.7V */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (3 << CS42L42_HSBIAS_CTL_SHIFT) | + (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + + /* Wait for HS bias to ramp up */ + msleep(cs42l42->hs_bias_ramp_time); + + /* Unmask auto detect interrupt */ + regmap_update_bits(cs42l42->regmap, + CS42L42_CODEC_INT_MASK, + CS42L42_PDN_DONE_MASK | + CS42L42_HSDET_AUTO_DONE_MASK, + (1 << CS42L42_PDN_DONE_SHIFT) | + (0 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + + /* Set hs detect to automatic, enabled mode */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (3 << CS42L42_HSDET_CTRL_SHIFT) | + (2 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); +} + +static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42) +{ + /* Mask button detect interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (1 << CS42L42_M_DETECT_TF_SHIFT) | + (1 << CS42L42_M_DETECT_FT_SHIFT) | + (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); + + /* Ground HS bias */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (1 << CS42L42_HSBIAS_CTL_SHIFT) | + (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + + /* Set auto HS bias settings to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSBIAS_SC_AUTOCTL, + CS42L42_HSBIAS_SENSE_EN_MASK | + CS42L42_AUTO_HSBIAS_HIZ_MASK | + CS42L42_TIP_SENSE_EN_MASK | + CS42L42_HSBIAS_SENSE_TRIP_MASK, + (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | + (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | + (0 << CS42L42_TIP_SENSE_EN_SHIFT) | + (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + + /* Set hs detect to manual, disabled mode */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (0 << CS42L42_HSDET_CTRL_SHIFT) | + (2 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); +} + +static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42) +{ + int bias_level; + unsigned int detect_status; + + /* Mask button detect interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (1 << CS42L42_M_DETECT_TF_SHIFT) | + (1 << CS42L42_M_DETECT_FT_SHIFT) | + (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); + + usleep_range(cs42l42->btn_det_event_dbnce * 1000, + cs42l42->btn_det_event_dbnce * 2000); + + /* Test all 4 level detect biases */ + bias_level = 1; + do { + /* Adjust button detect level sensitivity */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MIC_DET_CTL1, + CS42L42_LATCH_TO_VP_MASK | + CS42L42_EVENT_STAT_SEL_MASK | + CS42L42_HS_DET_LEVEL_MASK, + (1 << CS42L42_LATCH_TO_VP_SHIFT) | + (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | + (cs42l42->bias_thresholds[bias_level] << + CS42L42_HS_DET_LEVEL_SHIFT)); + + regmap_read(cs42l42->regmap, CS42L42_DET_STATUS2, + &detect_status); + } while ((detect_status & CS42L42_HS_TRUE_MASK) && + (++bias_level < CS42L42_NUM_BIASES)); + + switch (bias_level) { + case 1: /* Function C button press */ + dev_dbg(cs42l42->codec->dev, "Function C button press\n"); + break; + case 2: /* Function B button press */ + dev_dbg(cs42l42->codec->dev, "Function B button press\n"); + break; + case 3: /* Function D button press */ + dev_dbg(cs42l42->codec->dev, "Function D button press\n"); + break; + case 4: /* Function A button press */ + dev_dbg(cs42l42->codec->dev, "Function A button press\n"); + break; + } + + /* Set button detect level sensitivity back to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MIC_DET_CTL1, + CS42L42_LATCH_TO_VP_MASK | + CS42L42_EVENT_STAT_SEL_MASK | + CS42L42_HS_DET_LEVEL_MASK, + (1 << CS42L42_LATCH_TO_VP_SHIFT) | + (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | + (cs42l42->bias_thresholds[0] << CS42L42_HS_DET_LEVEL_SHIFT)); + + /* Clear any button interrupts before unmasking them */ + regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, + &detect_status); + + /* Unmask button detect interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (0 << CS42L42_M_DETECT_TF_SHIFT) | + (0 << CS42L42_M_DETECT_FT_SHIFT) | + (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); +} + +struct cs42l42_irq_params { + u16 status_addr; + u16 mask_addr; + u8 mask; +}; + +static const struct cs42l42_irq_params irq_params_table[] = { + {CS42L42_ADC_OVFL_STATUS, CS42L42_ADC_OVFL_INT_MASK, + CS42L42_ADC_OVFL_VAL_MASK}, + {CS42L42_MIXER_STATUS, CS42L42_MIXER_INT_MASK, + CS42L42_MIXER_VAL_MASK}, + {CS42L42_SRC_STATUS, CS42L42_SRC_INT_MASK, + CS42L42_SRC_VAL_MASK}, + {CS42L42_ASP_RX_STATUS, CS42L42_ASP_RX_INT_MASK, + CS42L42_ASP_RX_VAL_MASK}, + {CS42L42_ASP_TX_STATUS, CS42L42_ASP_TX_INT_MASK, + CS42L42_ASP_TX_VAL_MASK}, + {CS42L42_CODEC_STATUS, CS42L42_CODEC_INT_MASK, + CS42L42_CODEC_VAL_MASK}, + {CS42L42_DET_INT_STATUS1, CS42L42_DET_INT1_MASK, + CS42L42_DET_INT_VAL1_MASK}, + {CS42L42_DET_INT_STATUS2, CS42L42_DET_INT2_MASK, + CS42L42_DET_INT_VAL2_MASK}, + {CS42L42_SRCPL_INT_STATUS, CS42L42_SRCPL_INT_MASK, + CS42L42_SRCPL_VAL_MASK}, + {CS42L42_VPMON_STATUS, CS42L42_VPMON_INT_MASK, + CS42L42_VPMON_VAL_MASK}, + {CS42L42_PLL_LOCK_STATUS, CS42L42_PLL_LOCK_INT_MASK, + CS42L42_PLL_LOCK_VAL_MASK}, + {CS42L42_TSRS_PLUG_STATUS, CS42L42_TSRS_PLUG_INT_MASK, + CS42L42_TSRS_PLUG_VAL_MASK} +}; + +static irqreturn_t cs42l42_irq_thread(int irq, void *data) +{ + struct cs42l42_private *cs42l42 = (struct cs42l42_private *)data; + struct snd_soc_codec *codec = cs42l42->codec; + unsigned int stickies[12]; + unsigned int masks[12]; + unsigned int current_plug_status; + unsigned int current_button_status; + unsigned int i; + + /* Read sticky registers to clear interurpt */ + for (i = 0; i < ARRAY_SIZE(stickies); i++) { + regmap_read(cs42l42->regmap, irq_params_table[i].status_addr, + &(stickies[i])); + regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr, + &(masks[i])); + stickies[i] = stickies[i] & (~masks[i]) & + irq_params_table[i].mask; + } + + /* Read tip sense status before handling type detect */ + current_plug_status = (stickies[11] & + (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >> + CS42L42_TS_PLUG_SHIFT; + + /* Read button sense status */ + current_button_status = stickies[7] & + (CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK); + + /* Check auto-detect status */ + if ((~masks[5]) & irq_params_table[5].mask) { + if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { + cs42l42_process_hs_type_detect(cs42l42); + dev_dbg(codec->dev, + "Auto detect done (%d)\n", + cs42l42->hs_type); + } + } + + /* Check tip sense status */ + if ((~masks[11]) & irq_params_table[11].mask) { + switch (current_plug_status) { + case CS42L42_TS_PLUG: + if (cs42l42->plug_state != CS42L42_TS_PLUG) { + cs42l42->plug_state = CS42L42_TS_PLUG; + cs42l42_init_hs_type_detect(cs42l42); + } + break; + + case CS42L42_TS_UNPLUG: + if (cs42l42->plug_state != CS42L42_TS_UNPLUG) { + cs42l42->plug_state = CS42L42_TS_UNPLUG; + cs42l42_cancel_hs_type_detect(cs42l42); + dev_dbg(codec->dev, + "Unplug event\n"); + } + break; + + default: + if (cs42l42->plug_state != CS42L42_TS_TRANS) + cs42l42->plug_state = CS42L42_TS_TRANS; + } + } + + /* Check button detect status */ + if ((~masks[7]) & irq_params_table[7].mask) { + if (!(current_button_status & + CS42L42_M_HSBIAS_HIZ_MASK)) { + + if (current_button_status & + CS42L42_M_DETECT_TF_MASK) { + dev_dbg(codec->dev, + "Button released\n"); + } else if (current_button_status & + CS42L42_M_DETECT_FT_MASK) { + cs42l42_handle_button_press(cs42l42); + } + } + } + + return IRQ_HANDLED; +} + +static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42) +{ + regmap_update_bits(cs42l42->regmap, CS42L42_ADC_OVFL_INT_MASK, + CS42L42_ADC_OVFL_MASK, + (1 << CS42L42_ADC_OVFL_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_MIXER_INT_MASK, + CS42L42_MIX_CHB_OVFL_MASK | + CS42L42_MIX_CHA_OVFL_MASK | + CS42L42_EQ_OVFL_MASK | + CS42L42_EQ_BIQUAD_OVFL_MASK, + (1 << CS42L42_MIX_CHB_OVFL_SHIFT) | + (1 << CS42L42_MIX_CHA_OVFL_SHIFT) | + (1 << CS42L42_EQ_OVFL_SHIFT) | + (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_SRC_INT_MASK, + CS42L42_SRC_ILK_MASK | + CS42L42_SRC_OLK_MASK | + CS42L42_SRC_IUNLK_MASK | + CS42L42_SRC_OUNLK_MASK, + (1 << CS42L42_SRC_ILK_SHIFT) | + (1 << CS42L42_SRC_OLK_SHIFT) | + (1 << CS42L42_SRC_IUNLK_SHIFT) | + (1 << CS42L42_SRC_OUNLK_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_ASP_RX_INT_MASK, + CS42L42_ASPRX_NOLRCK_MASK | + CS42L42_ASPRX_EARLY_MASK | + CS42L42_ASPRX_LATE_MASK | + CS42L42_ASPRX_ERROR_MASK | + CS42L42_ASPRX_OVLD_MASK, + (1 << CS42L42_ASPRX_NOLRCK_SHIFT) | + (1 << CS42L42_ASPRX_EARLY_SHIFT) | + (1 << CS42L42_ASPRX_LATE_SHIFT) | + (1 << CS42L42_ASPRX_ERROR_SHIFT) | + (1 << CS42L42_ASPRX_OVLD_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_ASP_TX_INT_MASK, + CS42L42_ASPTX_NOLRCK_MASK | + CS42L42_ASPTX_EARLY_MASK | + CS42L42_ASPTX_LATE_MASK | + CS42L42_ASPTX_SMERROR_MASK, + (1 << CS42L42_ASPTX_NOLRCK_SHIFT) | + (1 << CS42L42_ASPTX_EARLY_SHIFT) | + (1 << CS42L42_ASPTX_LATE_SHIFT) | + (1 << CS42L42_ASPTX_SMERROR_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK, + CS42L42_PDN_DONE_MASK | + CS42L42_HSDET_AUTO_DONE_MASK, + (1 << CS42L42_PDN_DONE_SHIFT) | + (1 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_SRCPL_INT_MASK, + CS42L42_SRCPL_ADC_LK_MASK | + CS42L42_SRCPL_DAC_LK_MASK | + CS42L42_SRCPL_ADC_UNLK_MASK | + CS42L42_SRCPL_DAC_UNLK_MASK, + (1 << CS42L42_SRCPL_ADC_LK_SHIFT) | + (1 << CS42L42_SRCPL_DAC_LK_SHIFT) | + (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) | + (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT1_MASK, + CS42L42_TIP_SENSE_UNPLUG_MASK | + CS42L42_TIP_SENSE_PLUG_MASK | + CS42L42_HSBIAS_SENSE_MASK, + (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) | + (1 << CS42L42_TIP_SENSE_PLUG_SHIFT) | + (1 << CS42L42_HSBIAS_SENSE_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (1 << CS42L42_M_DETECT_TF_SHIFT) | + (1 << CS42L42_M_DETECT_FT_SHIFT) | + (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_VPMON_INT_MASK, + CS42L42_VPMON_MASK, + (1 << CS42L42_VPMON_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_PLL_LOCK_INT_MASK, + CS42L42_PLL_LOCK_MASK, + (1 << CS42L42_PLL_LOCK_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, + CS42L42_RS_PLUG_MASK | + CS42L42_RS_UNPLUG_MASK | + CS42L42_TS_PLUG_MASK | + CS42L42_TS_UNPLUG_MASK, + (1 << CS42L42_RS_PLUG_SHIFT) | + (1 << CS42L42_RS_UNPLUG_SHIFT) | + (0 << CS42L42_TS_PLUG_SHIFT) | + (0 << CS42L42_TS_UNPLUG_SHIFT)); +} + +static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42) +{ + unsigned int reg; + + cs42l42->hs_type = CS42L42_PLUG_INVALID; + + /* Latch analog controls to VP power domain */ + regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, + CS42L42_LATCH_TO_VP_MASK | + CS42L42_EVENT_STAT_SEL_MASK | + CS42L42_HS_DET_LEVEL_MASK, + (1 << CS42L42_LATCH_TO_VP_SHIFT) | + (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | + (cs42l42->bias_thresholds[0] << + CS42L42_HS_DET_LEVEL_SHIFT)); + + /* Remove ground noise-suppression clamps */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HS_CLAMP_DISABLE, + CS42L42_HS_CLAMP_DISABLE_MASK, + (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT)); + + /* Enable the tip sense circuit */ + regmap_update_bits(cs42l42->regmap, CS42L42_TIPSENSE_CTL, + CS42L42_TIP_SENSE_CTRL_MASK | + CS42L42_TIP_SENSE_INV_MASK | + CS42L42_TIP_SENSE_DEBOUNCE_MASK, + (3 << CS42L42_TIP_SENSE_CTRL_SHIFT) | + (0 << CS42L42_TIP_SENSE_INV_SHIFT) | + (2 << CS42L42_TIP_SENSE_DEBOUNCE_SHIFT)); + + /* Save the initial status of the tip sense */ + regmap_read(cs42l42->regmap, + CS42L42_TSRS_PLUG_STATUS, + ®); + cs42l42->plug_state = (((char) reg) & + (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >> + CS42L42_TS_PLUG_SHIFT; +} + +static const unsigned int threshold_defaults[] = { + CS42L42_HS_DET_LEVEL_15, + CS42L42_HS_DET_LEVEL_8, + CS42L42_HS_DET_LEVEL_4, + CS42L42_HS_DET_LEVEL_1 +}; + +static int cs42l42_handle_device_data(struct i2c_client *i2c_client, + struct cs42l42_private *cs42l42) +{ + struct device_node *np = i2c_client->dev.of_node; + unsigned int val; + unsigned int thresholds[CS42L42_NUM_BIASES]; + int ret; + int i; + + ret = of_property_read_u32(np, "cirrus,ts-inv", &val); + + if (!ret) { + switch (val) { + case CS42L42_TS_INV_EN: + case CS42L42_TS_INV_DIS: + cs42l42->ts_inv = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,ts-inv DT value %d\n", + val); + cs42l42->ts_inv = CS42L42_TS_INV_DIS; + } + } else { + cs42l42->ts_inv = CS42L42_TS_INV_DIS; + } + + regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, + CS42L42_TS_INV_MASK, + (cs42l42->ts_inv << CS42L42_TS_INV_SHIFT)); + + ret = of_property_read_u32(np, "cirrus,ts-dbnc-rise", &val); + + if (!ret) { + switch (val) { + case CS42L42_TS_DBNCE_0: + case CS42L42_TS_DBNCE_125: + case CS42L42_TS_DBNCE_250: + case CS42L42_TS_DBNCE_500: + case CS42L42_TS_DBNCE_750: + case CS42L42_TS_DBNCE_1000: + case CS42L42_TS_DBNCE_1250: + case CS42L42_TS_DBNCE_1500: + cs42l42->ts_dbnc_rise = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,ts-dbnc-rise DT value %d\n", + val); + cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000; + } + } else { + cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000; + } + + regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, + CS42L42_TS_RISE_DBNCE_TIME_MASK, + (cs42l42->ts_dbnc_rise << + CS42L42_TS_RISE_DBNCE_TIME_SHIFT)); + + ret = of_property_read_u32(np, "cirrus,ts-dbnc-fall", &val); + + if (!ret) { + switch (val) { + case CS42L42_TS_DBNCE_0: + case CS42L42_TS_DBNCE_125: + case CS42L42_TS_DBNCE_250: + case CS42L42_TS_DBNCE_500: + case CS42L42_TS_DBNCE_750: + case CS42L42_TS_DBNCE_1000: + case CS42L42_TS_DBNCE_1250: + case CS42L42_TS_DBNCE_1500: + cs42l42->ts_dbnc_fall = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,ts-dbnc-fall DT value %d\n", + val); + cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0; + } + } else { + cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0; + } + + regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, + CS42L42_TS_FALL_DBNCE_TIME_MASK, + (cs42l42->ts_dbnc_fall << + CS42L42_TS_FALL_DBNCE_TIME_SHIFT)); + + ret = of_property_read_u32(np, "cirrus,btn-det-init-dbnce", &val); + + if (!ret) { + if ((val >= CS42L42_BTN_DET_INIT_DBNCE_MIN) && + (val <= CS42L42_BTN_DET_INIT_DBNCE_MAX)) + cs42l42->btn_det_init_dbnce = val; + else { + dev_err(&i2c_client->dev, + "Wrong cirrus,btn-det-init-dbnce DT value %d\n", + val); + cs42l42->btn_det_init_dbnce = + CS42L42_BTN_DET_INIT_DBNCE_DEFAULT; + } + } else { + cs42l42->btn_det_init_dbnce = + CS42L42_BTN_DET_INIT_DBNCE_DEFAULT; + } + + ret = of_property_read_u32(np, "cirrus,btn-det-event-dbnce", &val); + + if (!ret) { + if ((val >= CS42L42_BTN_DET_EVENT_DBNCE_MIN) && + (val <= CS42L42_BTN_DET_EVENT_DBNCE_MAX)) + cs42l42->btn_det_event_dbnce = val; + else { + dev_err(&i2c_client->dev, + "Wrong cirrus,btn-det-event-dbnce DT value %d\n", val); + cs42l42->btn_det_event_dbnce = + CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; + } + } else { + cs42l42->btn_det_event_dbnce = + CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; + } + + ret = of_property_read_u32_array(np, "cirrus,bias-lvls", + (u32 *)thresholds, CS42L42_NUM_BIASES); + + if (!ret) { + for (i = 0; i < CS42L42_NUM_BIASES; i++) { + if ((thresholds[i] >= CS42L42_HS_DET_LEVEL_MIN) && + (thresholds[i] <= CS42L42_HS_DET_LEVEL_MAX)) + cs42l42->bias_thresholds[i] = thresholds[i]; + else { + dev_err(&i2c_client->dev, + "Wrong cirrus,bias-lvls[%d] DT value %d\n", i, + thresholds[i]); + cs42l42->bias_thresholds[i] = + threshold_defaults[i]; + } + } + } else { + for (i = 0; i < CS42L42_NUM_BIASES; i++) + cs42l42->bias_thresholds[i] = threshold_defaults[i]; + } + + ret = of_property_read_u32(np, "cirrus,hs-bias-ramp-rate", &val); + + if (!ret) { + switch (val) { + case CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL: + cs42l42->hs_bias_ramp_rate = val; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME0; + break; + case CS42L42_HSBIAS_RAMP_FAST: + cs42l42->hs_bias_ramp_rate = val; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME1; + break; + case CS42L42_HSBIAS_RAMP_SLOW: + cs42l42->hs_bias_ramp_rate = val; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; + break; + case CS42L42_HSBIAS_RAMP_SLOWEST: + cs42l42->hs_bias_ramp_rate = val; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME3; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,hs-bias-ramp-rate DT value %d\n", + val); + cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; + } + } else { + cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; + } + + regmap_update_bits(cs42l42->regmap, CS42L42_HS_BIAS_CTL, + CS42L42_HSBIAS_RAMP_MASK, + (cs42l42->hs_bias_ramp_rate << + CS42L42_HSBIAS_RAMP_SHIFT)); + + return 0; +} + +static int cs42l42_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs42l42_private *cs42l42; + int ret, i; + unsigned int devid = 0; + unsigned int reg; + + cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private), + GFP_KERNEL); + if (!cs42l42) + return -ENOMEM; + + i2c_set_clientdata(i2c_client, cs42l42); + + cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); + if (IS_ERR(cs42l42->regmap)) { + ret = PTR_ERR(cs42l42->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++) + cs42l42->supplies[i].supply = cs42l42_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c_client->dev, + ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to enable supplies: %d\n", ret); + return ret; + } + + /* Reset the Device */ + cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs42l42->reset_gpio)) + return PTR_ERR(cs42l42->reset_gpio); + + if (cs42l42->reset_gpio) { + dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); + gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); + } + mdelay(3); + + /* Request IRQ */ + ret = devm_request_threaded_irq(&i2c_client->dev, + i2c_client->irq, + NULL, cs42l42_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs42l42", cs42l42); + + if (ret != 0) + dev_err(&i2c_client->dev, + "Failed to request IRQ: %d\n", ret); + + /* initialize codec */ + ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_AB, ®); + devid = (reg & 0xFF) << 12; + + ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_CD, ®); + devid |= (reg & 0xFF) << 4; + + ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_E, ®); + devid |= (reg & 0xF0) >> 4; + + if (devid != CS42L42_CHIP_ID) { + ret = -ENODEV; + dev_err(&i2c_client->dev, + "CS42L42 Device ID (%X). Expected %X\n", + devid, CS42L42_CHIP_ID); + return ret; + } + + ret = regmap_read(cs42l42->regmap, CS42L42_REVID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + return ret; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF); + + /* Power up the codec */ + regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1, + CS42L42_ASP_DAO_PDN_MASK | + CS42L42_ASP_DAI_PDN_MASK | + CS42L42_MIXER_PDN_MASK | + CS42L42_EQ_PDN_MASK | + CS42L42_HP_PDN_MASK | + CS42L42_ADC_PDN_MASK | + CS42L42_PDN_ALL_MASK, + (1 << CS42L42_ASP_DAO_PDN_SHIFT) | + (1 << CS42L42_ASP_DAI_PDN_SHIFT) | + (1 << CS42L42_MIXER_PDN_SHIFT) | + (1 << CS42L42_EQ_PDN_SHIFT) | + (1 << CS42L42_HP_PDN_SHIFT) | + (1 << CS42L42_ADC_PDN_SHIFT) | + (0 << CS42L42_PDN_ALL_SHIFT)); + + if (i2c_client->dev.of_node) { + ret = cs42l42_handle_device_data(i2c_client, cs42l42); + if (ret != 0) + return ret; + } + + /* Setup headset detection */ + cs42l42_setup_hs_type_detect(cs42l42); + + /* Mask/Unmask Interrupts */ + cs42l42_set_interrupt_masks(cs42l42); + + /* Register codec for machine driver */ + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_cs42l42, &cs42l42_dai, 1); + if (ret < 0) + goto err_disable; + return 0; + +err_disable: + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + return ret; +} + +static int cs42l42_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client); + + snd_soc_unregister_codec(&i2c_client->dev); + + /* Hold down reset */ + if (cs42l42->reset_gpio) + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int cs42l42_runtime_suspend(struct device *dev) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); + + regcache_cache_only(cs42l42->regmap, true); + regcache_mark_dirty(cs42l42->regmap); + + /* Hold down reset */ + if (cs42l42->reset_gpio) + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + + /* remove power */ + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + + return 0; +} + +static int cs42l42_runtime_resume(struct device *dev) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); + int ret; + + /* Enable power */ + ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", + ret); + return ret; + } + + if (cs42l42->reset_gpio) + gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); + + regcache_cache_only(cs42l42->regmap, false); + regcache_sync(cs42l42->regmap); + + return 0; +} +#endif + +static const struct dev_pm_ops cs42l42_runtime_pm = { + SET_RUNTIME_PM_OPS(cs42l42_runtime_suspend, cs42l42_runtime_resume, + NULL) +}; + +static const struct of_device_id cs42l42_of_match[] = { + { .compatible = "cirrus,cs42l42", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs42l42_of_match); + + +static const struct i2c_device_id cs42l42_id[] = { + {"cs42l42", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs42l42_id); + +static struct i2c_driver cs42l42_i2c_driver = { + .driver = { + .name = "cs42l42", + .pm = &cs42l42_runtime_pm, + .of_match_table = cs42l42_of_match, + }, + .id_table = cs42l42_id, + .probe = cs42l42_i2c_probe, + .remove = cs42l42_i2c_remove, +}; + +module_i2c_driver(cs42l42_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L42 driver"); +MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); +MODULE_AUTHOR("Michael White, Cirrus Logic Inc, <michael.white@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h new file mode 100644 index 000000000000..d87a0a5322d5 --- /dev/null +++ b/sound/soc/codecs/cs42l42.h @@ -0,0 +1,776 @@ +/* + * cs42l42.h -- CS42L42 ALSA SoC audio driver header + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: James Schulman <james.schulman@cirrus.com> + * Author: Brian Austin <brian.austin@cirrus.com> + * Author: Michael White <michael.white@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __CS42L42_H__ +#define __CS42L42_H__ + +#define CS42L42_PAGE_REGISTER 0x00 /* Page Select Register */ +#define CS42L42_WIN_START 0x00 +#define CS42L42_WIN_LEN 0x100 +#define CS42L42_RANGE_MIN 0x00 +#define CS42L42_RANGE_MAX 0x7F + +#define CS42L42_PAGE_10 0x1000 +#define CS42L42_PAGE_11 0x1100 +#define CS42L42_PAGE_12 0x1200 +#define CS42L42_PAGE_13 0x1300 +#define CS42L42_PAGE_15 0x1500 +#define CS42L42_PAGE_19 0x1900 +#define CS42L42_PAGE_1B 0x1B00 +#define CS42L42_PAGE_1C 0x1C00 +#define CS42L42_PAGE_1D 0x1D00 +#define CS42L42_PAGE_1F 0x1F00 +#define CS42L42_PAGE_20 0x2000 +#define CS42L42_PAGE_21 0x2100 +#define CS42L42_PAGE_23 0x2300 +#define CS42L42_PAGE_24 0x2400 +#define CS42L42_PAGE_25 0x2500 +#define CS42L42_PAGE_26 0x2600 +#define CS42L42_PAGE_28 0x2800 +#define CS42L42_PAGE_29 0x2900 +#define CS42L42_PAGE_2A 0x2A00 +#define CS42L42_PAGE_30 0x3000 + +#define CS42L42_CHIP_ID 0x42A42 + +/* Page 0x10 Global Registers */ +#define CS42L42_DEVID_AB (CS42L42_PAGE_10 + 0x01) +#define CS42L42_DEVID_CD (CS42L42_PAGE_10 + 0x02) +#define CS42L42_DEVID_E (CS42L42_PAGE_10 + 0x03) +#define CS42L42_FABID (CS42L42_PAGE_10 + 0x04) +#define CS42L42_REVID (CS42L42_PAGE_10 + 0x05) +#define CS42L42_FRZ_CTL (CS42L42_PAGE_10 + 0x06) + +#define CS42L42_SRC_CTL (CS42L42_PAGE_10 + 0x07) +#define CS42L42_SRC_BYPASS_DAC_SHIFT 1 +#define CS42L42_SRC_BYPASS_DAC_MASK (1 << CS42L42_SRC_BYPASS_DAC_SHIFT) + +#define CS42L42_MCLK_STATUS (CS42L42_PAGE_10 + 0x08) + +#define CS42L42_MCLK_CTL (CS42L42_PAGE_10 + 0x09) +#define CS42L42_INTERNAL_FS_SHIFT 1 +#define CS42L42_INTERNAL_FS_MASK (1 << CS42L42_INTERNAL_FS_SHIFT) + +#define CS42L42_SFTRAMP_RATE (CS42L42_PAGE_10 + 0x0A) +#define CS42L42_I2C_DEBOUNCE (CS42L42_PAGE_10 + 0x0E) +#define CS42L42_I2C_STRETCH (CS42L42_PAGE_10 + 0x0F) +#define CS42L42_I2C_TIMEOUT (CS42L42_PAGE_10 + 0x10) + +/* Page 0x11 Power and Headset Detect Registers */ +#define CS42L42_PWR_CTL1 (CS42L42_PAGE_11 + 0x01) +#define CS42L42_ASP_DAO_PDN_SHIFT 7 +#define CS42L42_ASP_DAO_PDN_MASK (1 << CS42L42_ASP_DAO_PDN_SHIFT) +#define CS42L42_ASP_DAI_PDN_SHIFT 6 +#define CS42L42_ASP_DAI_PDN_MASK (1 << CS42L42_ASP_DAI_PDN_SHIFT) +#define CS42L42_MIXER_PDN_SHIFT 5 +#define CS42L42_MIXER_PDN_MASK (1 << CS42L42_MIXER_PDN_SHIFT) +#define CS42L42_EQ_PDN_SHIFT 4 +#define CS42L42_EQ_PDN_MASK (1 << CS42L42_EQ_PDN_SHIFT) +#define CS42L42_HP_PDN_SHIFT 3 +#define CS42L42_HP_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT) +#define CS42L42_ADC_PDN_SHIFT 2 +#define CS42L42_ADC_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT) +#define CS42L42_PDN_ALL_SHIFT 0 +#define CS42L42_PDN_ALL_MASK (1 << CS42L42_PDN_ALL_SHIFT) + +#define CS42L42_PWR_CTL2 (CS42L42_PAGE_11 + 0x02) +#define CS42L42_ADC_SRC_PDNB_SHIFT 0 +#define CS42L42_ADC_SRC_PDNB_MASK (1 << CS42L42_ADC_SRC_PDNB_SHIFT) +#define CS42L42_DAC_SRC_PDNB_SHIFT 1 +#define CS42L42_DAC_SRC_PDNB_MASK (1 << CS42L42_DAC_SRC_PDNB_SHIFT) +#define CS42L42_ASP_DAI1_PDN_SHIFT 2 +#define CS42L42_ASP_DAI1_PDN_MASK (1 << CS42L42_ASP_DAI1_PDN_SHIFT) +#define CS42L42_SRC_PDN_OVERRIDE_SHIFT 3 +#define CS42L42_SRC_PDN_OVERRIDE_MASK (1 << CS42L42_SRC_PDN_OVERRIDE_SHIFT) +#define CS42L42_DISCHARGE_FILT_SHIFT 4 +#define CS42L42_DISCHARGE_FILT_MASK (1 << CS42L42_DISCHARGE_FILT_SHIFT) + +#define CS42L42_PWR_CTL3 (CS42L42_PAGE_11 + 0x03) +#define CS42L42_RING_SENSE_PDNB_SHIFT 1 +#define CS42L42_RING_SENSE_PDNB_MASK (1 << \ + CS42L42_RING_SENSE_PDNB_SHIFT) +#define CS42L42_VPMON_PDNB_SHIFT 2 +#define CS42L42_VPMON_PDNB_MASK (1 << \ + CS42L42_VPMON_PDNB_SHIFT) +#define CS42L42_SW_CLK_STP_STAT_SEL_SHIFT 5 +#define CS42L42_SW_CLK_STP_STAT_SEL_MASK (3 << \ + CS42L42_SW_CLK_STP_STAT_SEL_SHIFT) + +#define CS42L42_RSENSE_CTL1 (CS42L42_PAGE_11 + 0x04) +#define CS42L42_RS_TRIM_R_SHIFT 0 +#define CS42L42_RS_TRIM_R_MASK (1 << \ + CS42L42_RS_TRIM_R_SHIFT) +#define CS42L42_RS_TRIM_T_SHIFT 1 +#define CS42L42_RS_TRIM_T_MASK (1 << \ + CS42L42_RS_TRIM_T_SHIFT) +#define CS42L42_HPREF_RS_SHIFT 2 +#define CS42L42_HPREF_RS_MASK (1 << \ + CS42L42_HPREF_RS_SHIFT) +#define CS42L42_HSBIAS_FILT_REF_RS_SHIFT 3 +#define CS42L42_HSBIAS_FILT_REF_RS_MASK (1 << \ + CS42L42_HSBIAS_FILT_REF_RS_SHIFT) +#define CS42L42_RING_SENSE_PU_HIZ_SHIFT 6 +#define CS42L42_RING_SENSE_PU_HIZ_MASK (1 << \ + CS42L42_RING_SENSE_PU_HIZ_SHIFT) + +#define CS42L42_RSENSE_CTL2 (CS42L42_PAGE_11 + 0x05) +#define CS42L42_TS_RS_GATE_SHIFT 7 +#define CS42L42_TS_RS_GATE_MAS (1 << CS42L42_TS_RS_GATE_SHIFT) + +#define CS42L42_OSC_SWITCH (CS42L42_PAGE_11 + 0x07) +#define CS42L42_SCLK_PRESENT_SHIFT 0 +#define CS42L42_SCLK_PRESENT_MASK (1 << CS42L42_SCLK_PRESENT_SHIFT) + +#define CS42L42_OSC_SWITCH_STATUS (CS42L42_PAGE_11 + 0x09) +#define CS42L42_OSC_SW_SEL_STAT_SHIFT 0 +#define CS42L42_OSC_SW_SEL_STAT_MASK (3 << CS42L42_OSC_SW_SEL_STAT_SHIFT) +#define CS42L42_OSC_PDNB_STAT_SHIFT 2 +#define CS42L42_OSC_PDNB_STAT_MASK (1 << CS42L42_OSC_SW_SEL_STAT_SHIFT) + +#define CS42L42_RSENSE_CTL3 (CS42L42_PAGE_11 + 0x12) +#define CS42L42_RS_RISE_DBNCE_TIME_SHIFT 0 +#define CS42L42_RS_RISE_DBNCE_TIME_MASK (7 << \ + CS42L42_RS_RISE_DBNCE_TIME_SHIFT) +#define CS42L42_RS_FALL_DBNCE_TIME_SHIFT 3 +#define CS42L42_RS_FALL_DBNCE_TIME_MASK (7 << \ + CS42L42_RS_FALL_DBNCE_TIME_SHIFT) +#define CS42L42_RS_PU_EN_SHIFT 6 +#define CS42L42_RS_PU_EN_MASK (1 << \ + CS42L42_RS_PU_EN_SHIFT) +#define CS42L42_RS_INV_SHIFT 7 +#define CS42L42_RS_INV_MASK (1 << \ + CS42L42_RS_INV_SHIFT) + +#define CS42L42_TSENSE_CTL (CS42L42_PAGE_11 + 0x13) +#define CS42L42_TS_RISE_DBNCE_TIME_SHIFT 0 +#define CS42L42_TS_RISE_DBNCE_TIME_MASK (7 << \ + CS42L42_TS_RISE_DBNCE_TIME_SHIFT) +#define CS42L42_TS_FALL_DBNCE_TIME_SHIFT 3 +#define CS42L42_TS_FALL_DBNCE_TIME_MASK (7 << \ + CS42L42_TS_FALL_DBNCE_TIME_SHIFT) +#define CS42L42_TS_INV_SHIFT 7 +#define CS42L42_TS_INV_MASK (1 << \ + CS42L42_TS_INV_SHIFT) + +#define CS42L42_TSRS_INT_DISABLE (CS42L42_PAGE_11 + 0x14) +#define CS42L42_D_RS_PLUG_DBNC_SHIFT 0 +#define CS42L42_D_RS_PLUG_DBNC_MASK (1 << CS42L42_D_RS_PLUG_DBNC_SHIFT) +#define CS42L42_D_RS_UNPLUG_DBNC_SHIFT 1 +#define CS42L42_D_RS_UNPLUG_DBNC_MASK (1 << CS42L42_D_RS_UNPLUG_DBNC_SHIFT) +#define CS42L42_D_TS_PLUG_DBNC_SHIFT 2 +#define CS42L42_D_TS_PLUG_DBNC_MASK (1 << CS42L42_D_TS_PLUG_DBNC_SHIFT) +#define CS42L42_D_TS_UNPLUG_DBNC_SHIFT 3 +#define CS42L42_D_TS_UNPLUG_DBNC_MASK (1 << CS42L42_D_TS_UNPLUG_DBNC_SHIFT) + +#define CS42L42_TRSENSE_STATUS (CS42L42_PAGE_11 + 0x15) +#define CS42L42_RS_PLUG_DBNC_SHIFT 0 +#define CS42L42_RS_PLUG_DBNC_MASK (1 << CS42L42_RS_PLUG_DBNC_SHIFT) +#define CS42L42_RS_UNPLUG_DBNC_SHIFT 1 +#define CS42L42_RS_UNPLUG_DBNC_MASK (1 << CS42L42_RS_UNPLUG_DBNC_SHIFT) +#define CS42L42_TS_PLUG_DBNC_SHIFT 2 +#define CS42L42_TS_PLUG_DBNC_MASK (1 << CS42L42_TS_PLUG_DBNC_SHIFT) +#define CS42L42_TS_UNPLUG_DBNC_SHIFT 3 +#define CS42L42_TS_UNPLUG_DBNC_MASK (1 << CS42L42_TS_UNPLUG_DBNC_SHIFT) + +#define CS42L42_HSDET_CTL1 (CS42L42_PAGE_11 + 0x1F) +#define CS42L42_HSDET_COMP1_LVL_SHIFT 0 +#define CS42L42_HSDET_COMP1_LVL_MASK (15 << CS42L42_HSDET_COMP1_LVL_SHIFT) +#define CS42L42_HSDET_COMP2_LVL_SHIFT 4 +#define CS42L42_HSDET_COMP2_LVL_MASK (15 << CS42L42_HSDET_COMP2_LVL_SHIFT) + +#define CS42L42_HSDET_CTL2 (CS42L42_PAGE_11 + 0x20) +#define CS42L42_HSDET_AUTO_TIME_SHIFT 0 +#define CS42L42_HSDET_AUTO_TIME_MASK (3 << CS42L42_HSDET_AUTO_TIME_SHIFT) +#define CS42L42_HSBIAS_REF_SHIFT 3 +#define CS42L42_HSBIAS_REF_MASK (1 << CS42L42_HSBIAS_REF_SHIFT) +#define CS42L42_HSDET_SET_SHIFT 4 +#define CS42L42_HSDET_SET_MASK (3 << CS42L42_HSDET_SET_SHIFT) +#define CS42L42_HSDET_CTRL_SHIFT 6 +#define CS42L42_HSDET_CTRL_MASK (3 << CS42L42_HSDET_CTRL_SHIFT) + +#define CS42L42_HS_SWITCH_CTL (CS42L42_PAGE_11 + 0x21) +#define CS42L42_SW_GNDHS_HS4_SHIFT 0 +#define CS42L42_SW_GNDHS_HS4_MASK (1 << CS42L42_SW_GNDHS_HS4_SHIFT) +#define CS42L42_SW_GNDHS_HS3_SHIFT 1 +#define CS42L42_SW_GNDHS_HS3_MASK (1 << CS42L42_SW_GNDHS_HS3_SHIFT) +#define CS42L42_SW_HSB_HS4_SHIFT 2 +#define CS42L42_SW_HSB_HS4_MASK (1 << CS42L42_SW_HSB_HS4_SHIFT) +#define CS42L42_SW_HSB_HS3_SHIFT 3 +#define CS42L42_SW_HSB_HS3_MASK (1 << CS42L42_SW_HSB_HS3_SHIFT) +#define CS42L42_SW_HSB_FILT_HS4_SHIFT 4 +#define CS42L42_SW_HSB_FILT_HS4_MASK (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) +#define CS42L42_SW_HSB_FILT_HS3_SHIFT 5 +#define CS42L42_SW_HSB_FILT_HS3_MASK (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) +#define CS42L42_SW_REF_HS4_SHIFT 6 +#define CS42L42_SW_REF_HS4_MASK (1 << CS42L42_SW_REF_HS4_SHIFT) +#define CS42L42_SW_REF_HS3_SHIFT 7 +#define CS42L42_SW_REF_HS3_MASK (1 << CS42L42_SW_REF_HS3_SHIFT) + +#define CS42L42_HS_DET_STATUS (CS42L42_PAGE_11 + 0x24) +#define CS42L42_HSDET_TYPE_SHIFT 0 +#define CS42L42_HSDET_TYPE_MASK (3 << CS42L42_HSDET_TYPE_SHIFT) +#define CS42L42_HSDET_COMP1_OUT_SHIFT 6 +#define CS42L42_HSDET_COMP1_OUT_MASK (1 << CS42L42_HSDET_COMP1_OUT_SHIFT) +#define CS42L42_HSDET_COMP2_OUT_SHIFT 7 +#define CS42L42_HSDET_COMP2_OUT_MASK (1 << CS42L42_HSDET_COMP2_OUT_SHIFT) +#define CS42L42_PLUG_CTIA 0 +#define CS42L42_PLUG_OMTP 1 +#define CS42L42_PLUG_HEADPHONE 2 +#define CS42L42_PLUG_INVALID 3 + +#define CS42L42_HS_CLAMP_DISABLE (CS42L42_PAGE_11 + 0x29) +#define CS42L42_HS_CLAMP_DISABLE_SHIFT 0 +#define CS42L42_HS_CLAMP_DISABLE_MASK (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT) + +/* Page 0x12 Clocking Registers */ +#define CS42L42_MCLK_SRC_SEL (CS42L42_PAGE_12 + 0x01) +#define CS42L42_MCLKDIV_SHIFT 1 +#define CS42L42_MCLKDIV_MASK (1 << CS42L42_MCLKDIV_SHIFT) +#define CS42L42_MCLK_SRC_SEL_SHIFT 0 +#define CS42L42_MCLK_SRC_SEL_MASK (1 << CS42L42_MCLK_SRC_SEL_SHIFT) + +#define CS42L42_SPDIF_CLK_CFG (CS42L42_PAGE_12 + 0x02) +#define CS42L42_FSYNC_PW_LOWER (CS42L42_PAGE_12 + 0x03) + +#define CS42L42_FSYNC_PW_UPPER (CS42L42_PAGE_12 + 0x04) +#define CS42L42_FSYNC_PULSE_WIDTH_SHIFT 0 +#define CS42L42_FSYNC_PULSE_WIDTH_MASK (0xff << \ + CS42L42_FSYNC_PULSE_WIDTH_SHIFT) + +#define CS42L42_FSYNC_P_LOWER (CS42L42_PAGE_12 + 0x05) + +#define CS42L42_FSYNC_P_UPPER (CS42L42_PAGE_12 + 0x06) +#define CS42L42_FSYNC_PERIOD_SHIFT 0 +#define CS42L42_FSYNC_PERIOD_MASK (0xff << CS42L42_FSYNC_PERIOD_SHIFT) + +#define CS42L42_ASP_CLK_CFG (CS42L42_PAGE_12 + 0x07) +#define CS42L42_ASP_SCLK_EN_SHIFT 5 +#define CS42L42_ASP_SCLK_EN_MASK (1 << CS42L42_ASP_SCLK_EN_SHIFT) +#define CS42L42_ASP_MASTER_MODE 0x01 +#define CS42L42_ASP_SLAVE_MODE 0x00 +#define CS42L42_ASP_MODE_SHIFT 4 +#define CS42L42_ASP_MODE_MASK (1 << CS42L42_ASP_MODE_SHIFT) +#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT 2 +#define CS42L42_ASP_SCPOL_IN_DAC_MASK (1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT) +#define CS42L42_ASP_LCPOL_IN_SHIFT 0 +#define CS42L42_ASP_LCPOL_IN_MASK (1 << CS42L42_ASP_LCPOL_IN_SHIFT) +#define CS42L42_ASP_POL_INV 1 + +#define CS42L42_ASP_FRM_CFG (CS42L42_PAGE_12 + 0x08) +#define CS42L42_ASP_STP_SHIFT 4 +#define CS42L42_ASP_STP_MASK (1 << CS42L42_ASP_STP_SHIFT) +#define CS42L42_ASP_5050_SHIFT 3 +#define CS42L42_ASP_5050_MASK (1 << CS42L42_ASP_5050_SHIFT) +#define CS42L42_ASP_FSD_SHIFT 0 +#define CS42L42_ASP_FSD_MASK (7 << CS42L42_ASP_FSD_SHIFT) +#define CS42L42_ASP_FSD_0_5 1 +#define CS42L42_ASP_FSD_1_0 2 +#define CS42L42_ASP_FSD_1_5 3 +#define CS42L42_ASP_FSD_2_0 4 + +#define CS42L42_FS_RATE_EN (CS42L42_PAGE_12 + 0x09) +#define CS42L42_FS_EN_SHIFT 0 +#define CS42L42_FS_EN_MASK (0xf << CS42L42_FS_EN_SHIFT) +#define CS42L42_FS_EN_IASRC_96K 0x1 +#define CS42L42_FS_EN_OASRC_96K 0x2 + +#define CS42L42_IN_ASRC_CLK (CS42L42_PAGE_12 + 0x0A) +#define CS42L42_CLK_IASRC_SEL_SHIFT 0 +#define CS42L42_CLK_IASRC_SEL_MASK (1 << CS42L42_CLK_IASRC_SEL_SHIFT) +#define CS42L42_CLK_IASRC_SEL_12 1 + +#define CS42L42_OUT_ASRC_CLK (CS42L42_PAGE_12 + 0x0B) +#define CS42L42_CLK_OASRC_SEL_SHIFT 0 +#define CS42L42_CLK_OASRC_SEL_MASK (1 << CS42L42_CLK_OASRC_SEL_SHIFT) +#define CS42L42_CLK_OASRC_SEL_12 1 + +#define CS42L42_PLL_DIV_CFG1 (CS42L42_PAGE_12 + 0x0C) +#define CS42L42_SCLK_PREDIV_SHIFT 0 +#define CS42L42_SCLK_PREDIV_MASK (3 << CS42L42_SCLK_PREDIV_SHIFT) + +/* Page 0x13 Interrupt Registers */ +/* Interrupts */ +#define CS42L42_ADC_OVFL_STATUS (CS42L42_PAGE_13 + 0x01) +#define CS42L42_MIXER_STATUS (CS42L42_PAGE_13 + 0x02) +#define CS42L42_SRC_STATUS (CS42L42_PAGE_13 + 0x03) +#define CS42L42_ASP_RX_STATUS (CS42L42_PAGE_13 + 0x04) +#define CS42L42_ASP_TX_STATUS (CS42L42_PAGE_13 + 0x05) +#define CS42L42_CODEC_STATUS (CS42L42_PAGE_13 + 0x08) +#define CS42L42_DET_INT_STATUS1 (CS42L42_PAGE_13 + 0x09) +#define CS42L42_DET_INT_STATUS2 (CS42L42_PAGE_13 + 0x0A) +#define CS42L42_SRCPL_INT_STATUS (CS42L42_PAGE_13 + 0x0B) +#define CS42L42_VPMON_STATUS (CS42L42_PAGE_13 + 0x0D) +#define CS42L42_PLL_LOCK_STATUS (CS42L42_PAGE_13 + 0x0E) +#define CS42L42_TSRS_PLUG_STATUS (CS42L42_PAGE_13 + 0x0F) +/* Masks */ +#define CS42L42_ADC_OVFL_INT_MASK (CS42L42_PAGE_13 + 0x16) +#define CS42L42_ADC_OVFL_SHIFT 0 +#define CS42L42_ADC_OVFL_MASK (1 << CS42L42_ADC_OVFL_SHIFT) +#define CS42L42_ADC_OVFL_VAL_MASK CS42L42_ADC_OVFL_MASK + +#define CS42L42_MIXER_INT_MASK (CS42L42_PAGE_13 + 0x17) +#define CS42L42_MIX_CHB_OVFL_SHIFT 0 +#define CS42L42_MIX_CHB_OVFL_MASK (1 << CS42L42_MIX_CHB_OVFL_SHIFT) +#define CS42L42_MIX_CHA_OVFL_SHIFT 1 +#define CS42L42_MIX_CHA_OVFL_MASK (1 << CS42L42_MIX_CHA_OVFL_SHIFT) +#define CS42L42_EQ_OVFL_SHIFT 2 +#define CS42L42_EQ_OVFL_MASK (1 << CS42L42_EQ_OVFL_SHIFT) +#define CS42L42_EQ_BIQUAD_OVFL_SHIFT 3 +#define CS42L42_EQ_BIQUAD_OVFL_MASK (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT) +#define CS42L42_MIXER_VAL_MASK (CS42L42_MIX_CHB_OVFL_MASK | \ + CS42L42_MIX_CHA_OVFL_MASK | \ + CS42L42_EQ_OVFL_MASK | \ + CS42L42_EQ_BIQUAD_OVFL_MASK) + +#define CS42L42_SRC_INT_MASK (CS42L42_PAGE_13 + 0x18) +#define CS42L42_SRC_ILK_SHIFT 0 +#define CS42L42_SRC_ILK_MASK (1 << CS42L42_SRC_ILK_SHIFT) +#define CS42L42_SRC_OLK_SHIFT 1 +#define CS42L42_SRC_OLK_MASK (1 << CS42L42_SRC_OLK_SHIFT) +#define CS42L42_SRC_IUNLK_SHIFT 2 +#define CS42L42_SRC_IUNLK_MASK (1 << CS42L42_SRC_IUNLK_SHIFT) +#define CS42L42_SRC_OUNLK_SHIFT 3 +#define CS42L42_SRC_OUNLK_MASK (1 << CS42L42_SRC_OUNLK_SHIFT) +#define CS42L42_SRC_VAL_MASK (CS42L42_SRC_ILK_MASK | \ + CS42L42_SRC_OLK_MASK | \ + CS42L42_SRC_IUNLK_MASK | \ + CS42L42_SRC_OUNLK_MASK) + +#define CS42L42_ASP_RX_INT_MASK (CS42L42_PAGE_13 + 0x19) +#define CS42L42_ASPRX_NOLRCK_SHIFT 0 +#define CS42L42_ASPRX_NOLRCK_MASK (1 << CS42L42_ASPRX_NOLRCK_SHIFT) +#define CS42L42_ASPRX_EARLY_SHIFT 1 +#define CS42L42_ASPRX_EARLY_MASK (1 << CS42L42_ASPRX_EARLY_SHIFT) +#define CS42L42_ASPRX_LATE_SHIFT 2 +#define CS42L42_ASPRX_LATE_MASK (1 << CS42L42_ASPRX_LATE_SHIFT) +#define CS42L42_ASPRX_ERROR_SHIFT 3 +#define CS42L42_ASPRX_ERROR_MASK (1 << CS42L42_ASPRX_ERROR_SHIFT) +#define CS42L42_ASPRX_OVLD_SHIFT 4 +#define CS42L42_ASPRX_OVLD_MASK (1 << CS42L42_ASPRX_OVLD_SHIFT) +#define CS42L42_ASP_RX_VAL_MASK (CS42L42_ASPRX_NOLRCK_MASK | \ + CS42L42_ASPRX_EARLY_MASK | \ + CS42L42_ASPRX_LATE_MASK | \ + CS42L42_ASPRX_ERROR_MASK | \ + CS42L42_ASPRX_OVLD_MASK) + +#define CS42L42_ASP_TX_INT_MASK (CS42L42_PAGE_13 + 0x1A) +#define CS42L42_ASPTX_NOLRCK_SHIFT 0 +#define CS42L42_ASPTX_NOLRCK_MASK (1 << CS42L42_ASPTX_NOLRCK_SHIFT) +#define CS42L42_ASPTX_EARLY_SHIFT 1 +#define CS42L42_ASPTX_EARLY_MASK (1 << CS42L42_ASPTX_EARLY_SHIFT) +#define CS42L42_ASPTX_LATE_SHIFT 2 +#define CS42L42_ASPTX_LATE_MASK (1 << CS42L42_ASPTX_LATE_SHIFT) +#define CS42L42_ASPTX_SMERROR_SHIFT 3 +#define CS42L42_ASPTX_SMERROR_MASK (1 << CS42L42_ASPTX_SMERROR_SHIFT) +#define CS42L42_ASP_TX_VAL_MASK (CS42L42_ASPTX_NOLRCK_MASK | \ + CS42L42_ASPTX_EARLY_MASK | \ + CS42L42_ASPTX_LATE_MASK | \ + CS42L42_ASPTX_SMERROR_MASK) + +#define CS42L42_CODEC_INT_MASK (CS42L42_PAGE_13 + 0x1B) +#define CS42L42_PDN_DONE_SHIFT 0 +#define CS42L42_PDN_DONE_MASK (1 << CS42L42_PDN_DONE_SHIFT) +#define CS42L42_HSDET_AUTO_DONE_SHIFT 1 +#define CS42L42_HSDET_AUTO_DONE_MASK (1 << CS42L42_HSDET_AUTO_DONE_SHIFT) +#define CS42L42_CODEC_VAL_MASK (CS42L42_PDN_DONE_MASK | \ + CS42L42_HSDET_AUTO_DONE_MASK) + +#define CS42L42_SRCPL_INT_MASK (CS42L42_PAGE_13 + 0x1C) +#define CS42L42_SRCPL_ADC_LK_SHIFT 0 +#define CS42L42_SRCPL_ADC_LK_MASK (1 << CS42L42_SRCPL_ADC_LK_SHIFT) +#define CS42L42_SRCPL_DAC_LK_SHIFT 2 +#define CS42L42_SRCPL_DAC_LK_MASK (1 << CS42L42_SRCPL_DAC_LK_SHIFT) +#define CS42L42_SRCPL_ADC_UNLK_SHIFT 5 +#define CS42L42_SRCPL_ADC_UNLK_MASK (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) +#define CS42L42_SRCPL_DAC_UNLK_SHIFT 6 +#define CS42L42_SRCPL_DAC_UNLK_MASK (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT) +#define CS42L42_SRCPL_VAL_MASK (CS42L42_SRCPL_ADC_LK_MASK | \ + CS42L42_SRCPL_DAC_LK_MASK | \ + CS42L42_SRCPL_ADC_UNLK_MASK | \ + CS42L42_SRCPL_DAC_UNLK_MASK) + +#define CS42L42_VPMON_INT_MASK (CS42L42_PAGE_13 + 0x1E) +#define CS42L42_VPMON_SHIFT 0 +#define CS42L42_VPMON_MASK (1 << CS42L42_VPMON_SHIFT) +#define CS42L42_VPMON_VAL_MASK CS42L42_VPMON_MASK + +#define CS42L42_PLL_LOCK_INT_MASK (CS42L42_PAGE_13 + 0x1F) +#define CS42L42_PLL_LOCK_SHIFT 0 +#define CS42L42_PLL_LOCK_MASK (1 << CS42L42_PLL_LOCK_SHIFT) +#define CS42L42_PLL_LOCK_VAL_MASK CS42L42_PLL_LOCK_MASK + +#define CS42L42_TSRS_PLUG_INT_MASK (CS42L42_PAGE_13 + 0x20) +#define CS42L42_RS_PLUG_SHIFT 0 +#define CS42L42_RS_PLUG_MASK (1 << CS42L42_RS_PLUG_SHIFT) +#define CS42L42_RS_UNPLUG_SHIFT 1 +#define CS42L42_RS_UNPLUG_MASK (1 << CS42L42_RS_UNPLUG_SHIFT) +#define CS42L42_TS_PLUG_SHIFT 2 +#define CS42L42_TS_PLUG_MASK (1 << CS42L42_TS_PLUG_SHIFT) +#define CS42L42_TS_UNPLUG_SHIFT 3 +#define CS42L42_TS_UNPLUG_MASK (1 << CS42L42_TS_UNPLUG_SHIFT) +#define CS42L42_TSRS_PLUG_VAL_MASK (CS42L42_RS_PLUG_MASK | \ + CS42L42_RS_UNPLUG_MASK | \ + CS42L42_TS_PLUG_MASK | \ + CS42L42_TS_UNPLUG_MASK) +#define CS42L42_TS_PLUG 3 +#define CS42L42_TS_UNPLUG 0 +#define CS42L42_TS_TRANS 1 + +/* Page 0x15 Fractional-N PLL Registers */ +#define CS42L42_PLL_CTL1 (CS42L42_PAGE_15 + 0x01) +#define CS42L42_PLL_START_SHIFT 0 +#define CS42L42_PLL_START_MASK (1 << CS42L42_PLL_START_SHIFT) + +#define CS42L42_PLL_DIV_FRAC0 (CS42L42_PAGE_15 + 0x02) +#define CS42L42_PLL_DIV_FRAC_SHIFT 0 +#define CS42L42_PLL_DIV_FRAC_MASK (0xff << CS42L42_PLL_DIV_FRAC_SHIFT) + +#define CS42L42_PLL_DIV_FRAC1 (CS42L42_PAGE_15 + 0x03) +#define CS42L42_PLL_DIV_FRAC2 (CS42L42_PAGE_15 + 0x04) + +#define CS42L42_PLL_DIV_INT (CS42L42_PAGE_15 + 0x05) +#define CS42L42_PLL_DIV_INT_SHIFT 0 +#define CS42L42_PLL_DIV_INT_MASK (0xff << CS42L42_PLL_DIV_INT_SHIFT) + +#define CS42L42_PLL_CTL3 (CS42L42_PAGE_15 + 0x08) +#define CS42L42_PLL_DIVOUT_SHIFT 0 +#define CS42L42_PLL_DIVOUT_MASK (0xff << CS42L42_PLL_DIVOUT_SHIFT) + +#define CS42L42_PLL_CAL_RATIO (CS42L42_PAGE_15 + 0x0A) +#define CS42L42_PLL_CAL_RATIO_SHIFT 0 +#define CS42L42_PLL_CAL_RATIO_MASK (0xff << CS42L42_PLL_CAL_RATIO_SHIFT) + +#define CS42L42_PLL_CTL4 (CS42L42_PAGE_15 + 0x1B) +#define CS42L42_PLL_MODE_SHIFT 0 +#define CS42L42_PLL_MODE_MASK (3 << CS42L42_PLL_MODE_SHIFT) + +/* Page 0x19 HP Load Detect Registers */ +#define CS42L42_LOAD_DET_RCSTAT (CS42L42_PAGE_19 + 0x25) +#define CS42L42_RLA_STAT_SHIFT 0 +#define CS42L42_RLA_STAT_MASK (3 << CS42L42_RLA_STAT_SHIFT) +#define CS42L42_RLA_STAT_15_OHM 0 + +#define CS42L42_LOAD_DET_DONE (CS42L42_PAGE_19 + 0x26) +#define CS42L42_HPLOAD_DET_DONE_SHIFT 0 +#define CS42L42_HPLOAD_DET_DONE_MASK (1 << CS42L42_HPLOAD_DET_DONE_SHIFT) + +#define CS42L42_LOAD_DET_EN (CS42L42_PAGE_19 + 0x27) +#define CS42L42_HP_LD_EN_SHIFT 0 +#define CS42L42_HP_LD_EN_MASK (1 << CS42L42_HP_LD_EN_SHIFT) + +/* Page 0x1B Headset Interface Registers */ +#define CS42L42_HSBIAS_SC_AUTOCTL (CS42L42_PAGE_1B + 0x70) +#define CS42L42_HSBIAS_SENSE_TRIP_SHIFT 0 +#define CS42L42_HSBIAS_SENSE_TRIP_MASK (7 << \ + CS42L42_HSBIAS_SENSE_TRIP_SHIFT) +#define CS42L42_TIP_SENSE_EN_SHIFT 5 +#define CS42L42_TIP_SENSE_EN_MASK (1 << \ + CS42L42_TIP_SENSE_EN_SHIFT) +#define CS42L42_AUTO_HSBIAS_HIZ_SHIFT 6 +#define CS42L42_AUTO_HSBIAS_HIZ_MASK (1 << \ + CS42L42_AUTO_HSBIAS_HIZ_SHIFT) +#define CS42L42_HSBIAS_SENSE_EN_SHIFT 7 +#define CS42L42_HSBIAS_SENSE_EN_MASK (1 << \ + CS42L42_HSBIAS_SENSE_EN_SHIFT) + +#define CS42L42_WAKE_CTL (CS42L42_PAGE_1B + 0x71) +#define CS42L42_WAKEB_CLEAR_SHIFT 0 +#define CS42L42_WAKEB_CLEAR_MASK (1 << CS42L42_WAKEB_CLEAR_SHIFT) +#define CS42L42_WAKEB_MODE_SHIFT 5 +#define CS42L42_WAKEB_MODE_MASK (1 << CS42L42_WAKEB_MODE_SHIFT) +#define CS42L42_M_HP_WAKE_SHIFT 6 +#define CS42L42_M_HP_WAKE_MASK (1 << CS42L42_M_HP_WAKE_SHIFT) +#define CS42L42_M_MIC_WAKE_SHIFT 7 +#define CS42L42_M_MIC_WAKE_MASK (1 << CS42L42_M_MIC_WAKE_SHIFT) + +#define CS42L42_ADC_DISABLE_MUTE (CS42L42_PAGE_1B + 0x72) +#define CS42L42_ADC_DISABLE_S0_MUTE_SHIFT 7 +#define CS42L42_ADC_DISABLE_S0_MUTE_MASK (1 << \ + CS42L42_ADC_DISABLE_S0_MUTE_SHIFT) + +#define CS42L42_TIPSENSE_CTL (CS42L42_PAGE_1B + 0x73) +#define CS42L42_TIP_SENSE_DEBOUNCE_SHIFT 0 +#define CS42L42_TIP_SENSE_DEBOUNCE_MASK (3 << \ + CS42L42_TIP_SENSE_DEBOUNCE_SHIFT) +#define CS42L42_TIP_SENSE_INV_SHIFT 5 +#define CS42L42_TIP_SENSE_INV_MASK (1 << \ + CS42L42_TIP_SENSE_INV_SHIFT) +#define CS42L42_TIP_SENSE_CTRL_SHIFT 6 +#define CS42L42_TIP_SENSE_CTRL_MASK (3 << \ + CS42L42_TIP_SENSE_CTRL_SHIFT) + +#define CS42L42_MISC_DET_CTL (CS42L42_PAGE_1B + 0x74) +#define CS42L42_PDN_MIC_LVL_DET_SHIFT 0 +#define CS42L42_PDN_MIC_LVL_DET_MASK (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT) +#define CS42L42_HSBIAS_CTL_SHIFT 1 +#define CS42L42_HSBIAS_CTL_MASK (3 << CS42L42_HSBIAS_CTL_SHIFT) +#define CS42L42_DETECT_MODE_SHIFT 3 +#define CS42L42_DETECT_MODE_MASK (3 << CS42L42_DETECT_MODE_SHIFT) + +#define CS42L42_MIC_DET_CTL1 (CS42L42_PAGE_1B + 0x75) +#define CS42L42_HS_DET_LEVEL_SHIFT 0 +#define CS42L42_HS_DET_LEVEL_MASK (0x3F << CS42L42_HS_DET_LEVEL_SHIFT) +#define CS42L42_EVENT_STAT_SEL_SHIFT 6 +#define CS42L42_EVENT_STAT_SEL_MASK (1 << CS42L42_EVENT_STAT_SEL_SHIFT) +#define CS42L42_LATCH_TO_VP_SHIFT 7 +#define CS42L42_LATCH_TO_VP_MASK (1 << CS42L42_LATCH_TO_VP_SHIFT) + +#define CS42L42_MIC_DET_CTL2 (CS42L42_PAGE_1B + 0x76) +#define CS42L42_DEBOUNCE_TIME_SHIFT 5 +#define CS42L42_DEBOUNCE_TIME_MASK (0x07 << CS42L42_DEBOUNCE_TIME_SHIFT) + +#define CS42L42_DET_STATUS1 (CS42L42_PAGE_1B + 0x77) +#define CS42L42_HSBIAS_HIZ_MODE_SHIFT 6 +#define CS42L42_HSBIAS_HIZ_MODE_MASK (1 << CS42L42_HSBIAS_HIZ_MODE_SHIFT) +#define CS42L42_TIP_SENSE_SHIFT 7 +#define CS42L42_TIP_SENSE_MASK (1 << CS42L42_TIP_SENSE_SHIFT) + +#define CS42L42_DET_STATUS2 (CS42L42_PAGE_1B + 0x78) +#define CS42L42_SHORT_TRUE_SHIFT 0 +#define CS42L42_SHORT_TRUE_MASK (1 << CS42L42_SHORT_TRUE_SHIFT) +#define CS42L42_HS_TRUE_SHIFT 1 +#define CS42L42_HS_TRUE_MASK (1 << CS42L42_HS_TRUE_SHIFT) + +#define CS42L42_DET_INT1_MASK (CS42L42_PAGE_1B + 0x79) +#define CS42L42_TIP_SENSE_UNPLUG_SHIFT 5 +#define CS42L42_TIP_SENSE_UNPLUG_MASK (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) +#define CS42L42_TIP_SENSE_PLUG_SHIFT 6 +#define CS42L42_TIP_SENSE_PLUG_MASK (1 << CS42L42_TIP_SENSE_PLUG_SHIFT) +#define CS42L42_HSBIAS_SENSE_SHIFT 7 +#define CS42L42_HSBIAS_SENSE_MASK (1 << CS42L42_HSBIAS_SENSE_SHIFT) +#define CS42L42_DET_INT_VAL1_MASK (CS42L42_TIP_SENSE_UNPLUG_MASK | \ + CS42L42_TIP_SENSE_PLUG_MASK | \ + CS42L42_HSBIAS_SENSE_MASK) + +#define CS42L42_DET_INT2_MASK (CS42L42_PAGE_1B + 0x7A) +#define CS42L42_M_SHORT_DET_SHIFT 0 +#define CS42L42_M_SHORT_DET_MASK (1 << \ + CS42L42_M_SHORT_DET_SHIFT) +#define CS42L42_M_SHORT_RLS_SHIFT 1 +#define CS42L42_M_SHORT_RLS_MASK (1 << \ + CS42L42_M_SHORT_RLS_SHIFT) +#define CS42L42_M_HSBIAS_HIZ_SHIFT 2 +#define CS42L42_M_HSBIAS_HIZ_MASK (1 << \ + CS42L42_M_HSBIAS_HIZ_SHIFT) +#define CS42L42_M_DETECT_FT_SHIFT 6 +#define CS42L42_M_DETECT_FT_MASK (1 << \ + CS42L42_M_DETECT_FT_SHIFT) +#define CS42L42_M_DETECT_TF_SHIFT 7 +#define CS42L42_M_DETECT_TF_MASK (1 << \ + CS42L42_M_DETECT_TF_SHIFT) +#define CS42L42_DET_INT_VAL2_MASK (CS42L42_M_SHORT_DET_MASK | \ + CS42L42_M_SHORT_RLS_MASK | \ + CS42L42_M_HSBIAS_HIZ_MASK | \ + CS42L42_M_DETECT_FT_MASK | \ + CS42L42_M_DETECT_TF_MASK) + +/* Page 0x1C Headset Bias Registers */ +#define CS42L42_HS_BIAS_CTL (CS42L42_PAGE_1C + 0x03) +#define CS42L42_HSBIAS_RAMP_SHIFT 0 +#define CS42L42_HSBIAS_RAMP_MASK (3 << CS42L42_HSBIAS_RAMP_SHIFT) +#define CS42L42_HSBIAS_PD_SHIFT 4 +#define CS42L42_HSBIAS_PD_MASK (1 << CS42L42_HSBIAS_PD_SHIFT) +#define CS42L42_HSBIAS_CAPLESS_SHIFT 7 +#define CS42L42_HSBIAS_CAPLESS_MASK (1 << CS42L42_HSBIAS_CAPLESS_SHIFT) + +/* Page 0x1D ADC Registers */ +#define CS42L42_ADC_CTL (CS42L42_PAGE_1D + 0x01) +#define CS42L42_ADC_NOTCH_DIS_SHIFT 5 +#define CS42L42_ADC_FORCE_WEAK_VCM_SHIFT 4 +#define CS42L42_ADC_INV_SHIFT 2 +#define CS42L42_ADC_DIG_BOOST_SHIFT 0 + +#define CS42L42_ADC_VOLUME (CS42L42_PAGE_1D + 0x03) +#define CS42L42_ADC_VOL_SHIFT 0 + +#define CS42L42_ADC_WNF_HPF_CTL (CS42L42_PAGE_1D + 0x04) +#define CS42L42_ADC_WNF_CF_SHIFT 4 +#define CS42L42_ADC_WNF_EN_SHIFT 3 +#define CS42L42_ADC_HPF_CF_SHIFT 1 +#define CS42L42_ADC_HPF_EN_SHIFT 0 + +/* Page 0x1F DAC Registers */ +#define CS42L42_DAC_CTL1 (CS42L42_PAGE_1F + 0x01) +#define CS42L42_DACB_INV_SHIFT 1 +#define CS42L42_DACA_INV_SHIFT 0 + +#define CS42L42_DAC_CTL2 (CS42L42_PAGE_1F + 0x06) +#define CS42L42_HPOUT_PULLDOWN_SHIFT 4 +#define CS42L42_HPOUT_PULLDOWN_MASK (15 << CS42L42_HPOUT_PULLDOWN_SHIFT) +#define CS42L42_HPOUT_LOAD_SHIFT 3 +#define CS42L42_HPOUT_LOAD_MASK (1 << CS42L42_HPOUT_LOAD_SHIFT) +#define CS42L42_HPOUT_CLAMP_SHIFT 2 +#define CS42L42_HPOUT_CLAMP_MASK (1 << CS42L42_HPOUT_CLAMP_SHIFT) +#define CS42L42_DAC_HPF_EN_SHIFT 1 +#define CS42L42_DAC_HPF_EN_MASK (1 << CS42L42_DAC_HPF_EN_SHIFT) +#define CS42L42_DAC_MON_EN_SHIFT 0 +#define CS42L42_DAC_MON_EN_MASK (1 << CS42L42_DAC_MON_EN_SHIFT) + +/* Page 0x20 HP CTL Registers */ +#define CS42L42_HP_CTL (CS42L42_PAGE_20 + 0x01) +#define CS42L42_HP_ANA_BMUTE_SHIFT 3 +#define CS42L42_HP_ANA_BMUTE_MASK (1 << CS42L42_HP_ANA_BMUTE_SHIFT) +#define CS42L42_HP_ANA_AMUTE_SHIFT 2 +#define CS42L42_HP_ANA_AMUTE_MASK (1 << CS42L42_HP_ANA_AMUTE_SHIFT) +#define CS42L42_HP_FULL_SCALE_VOL_SHIFT 1 +#define CS42L42_HP_FULL_SCALE_VOL_MASK (1 << CS42L42_HP_FULL_SCALE_VOL_SHIFT) + +/* Page 0x21 Class H Registers */ +#define CS42L42_CLASSH_CTL (CS42L42_PAGE_21 + 0x01) + +/* Page 0x23 Mixer Volume Registers */ +#define CS42L42_MIXER_CHA_VOL (CS42L42_PAGE_23 + 0x01) +#define CS42L42_MIXER_ADC_VOL (CS42L42_PAGE_23 + 0x02) + +#define CS42L42_MIXER_CHB_VOL (CS42L42_PAGE_23 + 0x03) +#define CS42L42_MIXER_CH_VOL_SHIFT 0 +#define CS42L42_MIXER_CH_VOL_MASK (0x3f << CS42L42_MIXER_CH_VOL_SHIFT) + +/* Page 0x24 EQ Registers */ +#define CS42L42_EQ_COEF_IN0 (CS42L42_PAGE_24 + 0x01) +#define CS42L42_EQ_COEF_IN1 (CS42L42_PAGE_24 + 0x02) +#define CS42L42_EQ_COEF_IN2 (CS42L42_PAGE_24 + 0x03) +#define CS42L42_EQ_COEF_IN3 (CS42L42_PAGE_24 + 0x04) +#define CS42L42_EQ_COEF_RW (CS42L42_PAGE_24 + 0x06) +#define CS42L42_EQ_COEF_OUT0 (CS42L42_PAGE_24 + 0x07) +#define CS42L42_EQ_COEF_OUT1 (CS42L42_PAGE_24 + 0x08) +#define CS42L42_EQ_COEF_OUT2 (CS42L42_PAGE_24 + 0x09) +#define CS42L42_EQ_COEF_OUT3 (CS42L42_PAGE_24 + 0x0A) +#define CS42L42_EQ_INIT_STAT (CS42L42_PAGE_24 + 0x0B) +#define CS42L42_EQ_START_FILT (CS42L42_PAGE_24 + 0x0C) +#define CS42L42_EQ_MUTE_CTL (CS42L42_PAGE_24 + 0x0E) + +/* Page 0x25 Audio Port Registers */ +#define CS42L42_SP_RX_CH_SEL (CS42L42_PAGE_25 + 0x01) + +#define CS42L42_SP_RX_ISOC_CTL (CS42L42_PAGE_25 + 0x02) +#define CS42L42_SP_RX_RSYNC_SHIFT 6 +#define CS42L42_SP_RX_RSYNC_MASK (1 << CS42L42_SP_RX_RSYNC_SHIFT) +#define CS42L42_SP_RX_NSB_POS_SHIFT 3 +#define CS42L42_SP_RX_NSB_POS_MASK (7 << CS42L42_SP_RX_NSB_POS_SHIFT) +#define CS42L42_SP_RX_NFS_NSBB_SHIFT 2 +#define CS42L42_SP_RX_NFS_NSBB_MASK (1 << CS42L42_SP_RX_NFS_NSBB_SHIFT) +#define CS42L42_SP_RX_ISOC_MODE_SHIFT 0 +#define CS42L42_SP_RX_ISOC_MODE_MASK (3 << CS42L42_SP_RX_ISOC_MODE_SHIFT) + +#define CS42L42_SP_RX_FS (CS42L42_PAGE_25 + 0x03) +#define CS42l42_SPDIF_CH_SEL (CS42L42_PAGE_25 + 0x04) +#define CS42L42_SP_TX_ISOC_CTL (CS42L42_PAGE_25 + 0x05) +#define CS42L42_SP_TX_FS (CS42L42_PAGE_25 + 0x06) +#define CS42L42_SPDIF_SW_CTL1 (CS42L42_PAGE_25 + 0x07) + +/* Page 0x26 SRC Registers */ +#define CS42L42_SRC_SDIN_FS (CS42L42_PAGE_26 + 0x01) +#define CS42L42_SRC_SDIN_FS_SHIFT 0 +#define CS42L42_SRC_SDIN_FS_MASK (0x1f << CS42L42_SRC_SDIN_FS_SHIFT) + +#define CS42L42_SRC_SDOUT_FS (CS42L42_PAGE_26 + 0x09) + +/* Page 0x28 S/PDIF Registers */ +#define CS42L42_SPDIF_CTL1 (CS42L42_PAGE_28 + 0x01) +#define CS42L42_SPDIF_CTL2 (CS42L42_PAGE_28 + 0x02) +#define CS42L42_SPDIF_CTL3 (CS42L42_PAGE_28 + 0x03) +#define CS42L42_SPDIF_CTL4 (CS42L42_PAGE_28 + 0x04) + +/* Page 0x29 Serial Port TX Registers */ +#define CS42L42_ASP_TX_SZ_EN (CS42L42_PAGE_29 + 0x01) +#define CS42L42_ASP_TX_CH_EN (CS42L42_PAGE_29 + 0x02) +#define CS42L42_ASP_TX_CH_AP_RES (CS42L42_PAGE_29 + 0x03) +#define CS42L42_ASP_TX_CH1_BIT_MSB (CS42L42_PAGE_29 + 0x04) +#define CS42L42_ASP_TX_CH1_BIT_LSB (CS42L42_PAGE_29 + 0x05) +#define CS42L42_ASP_TX_HIZ_DLY_CFG (CS42L42_PAGE_29 + 0x06) +#define CS42L42_ASP_TX_CH2_BIT_MSB (CS42L42_PAGE_29 + 0x0A) +#define CS42L42_ASP_TX_CH2_BIT_LSB (CS42L42_PAGE_29 + 0x0B) + +/* Page 0x2A Serial Port RX Registers */ +#define CS42L42_ASP_RX_DAI0_EN (CS42L42_PAGE_2A + 0x01) +#define CS42L42_ASP_RX0_CH_EN_SHIFT 2 +#define CS42L42_ASP_RX0_CH_EN_MASK (0xf << CS42L42_ASP_RX0_CH_EN_SHIFT) +#define CS42L42_ASP_RX0_CH1_EN 1 +#define CS42L42_ASP_RX0_CH2_EN 2 +#define CS42L42_ASP_RX0_CH3_EN 4 +#define CS42L42_ASP_RX0_CH4_EN 8 + +#define CS42L42_ASP_RX_DAI0_CH1_AP_RES (CS42L42_PAGE_2A + 0x02) +#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x03) +#define CS42L42_ASP_RX_DAI0_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x04) +#define CS42L42_ASP_RX_DAI0_CH2_AP_RES (CS42L42_PAGE_2A + 0x05) +#define CS42L42_ASP_RX_DAI0_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x06) +#define CS42L42_ASP_RX_DAI0_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x07) +#define CS42L42_ASP_RX_DAI0_CH3_AP_RES (CS42L42_PAGE_2A + 0x08) +#define CS42L42_ASP_RX_DAI0_CH3_BIT_MSB (CS42L42_PAGE_2A + 0x09) +#define CS42L42_ASP_RX_DAI0_CH3_BIT_LSB (CS42L42_PAGE_2A + 0x0A) +#define CS42L42_ASP_RX_DAI0_CH4_AP_RES (CS42L42_PAGE_2A + 0x0B) +#define CS42L42_ASP_RX_DAI0_CH4_BIT_MSB (CS42L42_PAGE_2A + 0x0C) +#define CS42L42_ASP_RX_DAI0_CH4_BIT_LSB (CS42L42_PAGE_2A + 0x0D) +#define CS42L42_ASP_RX_DAI1_CH1_AP_RES (CS42L42_PAGE_2A + 0x0E) +#define CS42L42_ASP_RX_DAI1_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x0F) +#define CS42L42_ASP_RX_DAI1_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x10) +#define CS42L42_ASP_RX_DAI1_CH2_AP_RES (CS42L42_PAGE_2A + 0x11) +#define CS42L42_ASP_RX_DAI1_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x12) +#define CS42L42_ASP_RX_DAI1_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x13) + +#define CS42L42_ASP_RX_CH_AP_SHIFT 6 +#define CS42L42_ASP_RX_CH_AP_MASK (1 << CS42L42_ASP_RX_CH_AP_SHIFT) +#define CS42L42_ASP_RX_CH_AP_LOW 0 +#define CS42L42_ASP_RX_CH_AP_HI 1 +#define CS42L42_ASP_RX_CH_RES_SHIFT 0 +#define CS42L42_ASP_RX_CH_RES_MASK (3 << CS42L42_ASP_RX_CH_RES_SHIFT) +#define CS42L42_ASP_RX_CH_RES_32 3 +#define CS42L42_ASP_RX_CH_RES_16 1 +#define CS42L42_ASP_RX_CH_BIT_ST_SHIFT 0 +#define CS42L42_ASP_RX_CH_BIT_ST_MASK (0xff << CS42L42_ASP_RX_CH_BIT_ST_SHIFT) + +/* Page 0x30 ID Registers */ +#define CS42L42_SUB_REVID (CS42L42_PAGE_30 + 0x14) +#define CS42L42_MAX_REGISTER (CS42L42_PAGE_30 + 0x14) + +/* Defines for fracturing values spread across multiple registers */ +#define CS42L42_FRAC0_VAL(val) ((val) & 0x0000ff) +#define CS42L42_FRAC1_VAL(val) (((val) & 0x00ff00) >> 8) +#define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16) + +#define CS42L42_NUM_SUPPLIES 5 + +static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { + "VA", + "VP", + "VCP", + "VD_FILT", + "VL", +}; + +struct cs42l42_private { + struct regmap *regmap; + struct snd_soc_codec *codec; + struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES]; + struct gpio_desc *reset_gpio; + struct completion pdn_done; + u32 sclk; + u32 srate; + u32 swidth; + u8 plug_state; + u8 hs_type; + u8 ts_inv; + u8 ts_dbnc_rise; + u8 ts_dbnc_fall; + u8 btn_det_init_dbnce; + u8 btn_det_event_dbnce; + u8 bias_thresholds[CS42L42_NUM_BIASES]; + u8 hs_bias_ramp_rate; + u8 hs_bias_ramp_time; +}; + +#endif /* __CS42L42_H__ */ diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 54c1768bc818..cb6ca85f1536 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -64,8 +64,6 @@ struct cs42l56_private { }; static const struct reg_default cs42l56_reg_defaults[] = { - { 1, 0x56 }, /* r01 - ID 1 */ - { 2, 0x04 }, /* r02 - ID 2 */ { 3, 0x7f }, /* r03 - Power Ctl 1 */ { 4, 0xff }, /* r04 - Power Ctl 2 */ { 5, 0x00 }, /* ro5 - Clocking Ctl 1 */ @@ -1262,8 +1260,6 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, return ret; } - regcache_cache_bypass(cs42l56->regmap, true); - ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, ®); devid = reg & CS42L56_CHIP_ID_MASK; if (devid != CS42L56_DEVID) { @@ -1279,23 +1275,25 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n", alpha_rev, metal_rev); - regcache_cache_bypass(cs42l56->regmap, false); - if (cs42l56->pdata.ain1a_ref_cfg) regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, - CS42L56_AIN1A_REF_MASK, 1); + CS42L56_AIN1A_REF_MASK, + CS42L56_AIN1A_REF_MASK); if (cs42l56->pdata.ain1b_ref_cfg) regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, - CS42L56_AIN1B_REF_MASK, 1); + CS42L56_AIN1B_REF_MASK, + CS42L56_AIN1B_REF_MASK); if (cs42l56->pdata.ain2a_ref_cfg) regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, - CS42L56_AIN2A_REF_MASK, 1); + CS42L56_AIN2A_REF_MASK, + CS42L56_AIN2A_REF_MASK); if (cs42l56->pdata.ain2b_ref_cfg) regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, - CS42L56_AIN2B_REF_MASK, 1); + CS42L56_AIN2B_REF_MASK, + CS42L56_AIN2B_REF_MASK); if (cs42l56->pdata.micbias_lvl) regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL, diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 71ba5605495f..3df2c473ab88 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1337,8 +1337,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1); } - regcache_cache_bypass(cs42l73->regmap, true); - /* initialize codec */ ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); devid = (reg & 0xFF) << 12; @@ -1366,8 +1364,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, dev_info(&i2c_client->dev, "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF); - regcache_cache_bypass(cs42l73->regmap, false); - ret = snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_cs42l73, cs42l73_dai, ARRAY_SIZE(cs42l73_dai)); diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index b4d87379d2bc..c1785bd4ff19 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -321,7 +321,6 @@ static struct snd_soc_dai_driver cs42xx8_dai = { }; static const struct reg_default cs42xx8_reg[] = { - { 0x01, 0x01 }, /* Chip I.D. and Revision Register */ { 0x02, 0x00 }, /* Power Control */ { 0x03, 0xF0 }, /* Functional Mode */ { 0x04, 0x46 }, /* Interface Formats */ @@ -498,13 +497,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap) /* Make sure hardware reset done */ msleep(5); - /* - * We haven't marked the chip revision as volatile due to - * sharing a register with the right input volume; explicitly - * bypass the cache to read it. - */ - regcache_cache_bypass(cs42xx8->regmap, true); - /* Validate the chip ID */ ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val); if (ret < 0) { @@ -523,8 +515,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap) dev_info(dev, "found device, revision %X\n", val & CS42XX8_CHIPID_REV_ID_MASK); - regcache_cache_bypass(cs42xx8->regmap, false); - cs42xx8_dai.name = cs42xx8->drvdata->name; /* Each adc supports stereo input */ diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 5b22564f037c..73559ae864b6 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -335,9 +335,11 @@ static const struct snd_kcontrol_new cs47l24_aec_loopback_mux = static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, - ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -1064,7 +1066,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { static int cs47l24_open(struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + struct cs47l24_priv *priv = snd_soc_platform_get_drvdata(rtd->platform); struct arizona *arizona = priv->core.arizona; int n_adsp; @@ -1113,8 +1115,8 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) static int cs47l24_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; int ret; priv->core.arizona->dapm = dapm; @@ -1124,14 +1126,6 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) arizona_init_mono(codec); arizona_init_notifiers(codec); - ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, - "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, - priv); - if (ret != 0) { - dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; - } - ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec); if (ret) goto err_adsp2_codec_probe; @@ -1145,7 +1139,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) if (ret) goto err_adsp2_codec_probe; - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); return 0; @@ -1159,17 +1153,12 @@ err_adsp2_codec_probe: static int cs47l24_codec_remove(struct snd_soc_codec *codec) { struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; wm_adsp2_codec_remove(&priv->core.adsp[1], codec); wm_adsp2_codec_remove(&priv->core.adsp[2], codec); priv->core.arizona->dapm = NULL; - arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - - arizona_free_spk(codec); - return 0; } @@ -1285,25 +1274,47 @@ static int cs47l24_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, + cs47l24); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + goto err_dsp_irq; + ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform); if (ret < 0) { dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); - return ret; + goto err_spk_irqs; } ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); if (ret < 0) { dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); - snd_soc_unregister_platform(&pdev->dev); + goto err_platform; } return ret; + +err_platform: + snd_soc_unregister_platform(&pdev->dev); +err_spk_irqs: + arizona_free_spk_irqs(arizona); +err_dsp_irq: + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24); + + return ret; } static int cs47l24_remove(struct platform_device *pdev) { struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev); + struct arizona *arizona = cs47l24->core.arizona; snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_codec(&pdev->dev); @@ -1312,6 +1323,10 @@ static int cs47l24_remove(struct platform_device *pdev) wm_adsp2_remove(&cs47l24->core.adsp[1]); wm_adsp2_remove(&cs47l24->core.adsp[2]); + arizona_free_spk_irqs(arizona); + + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24); + return 0; } diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 2b8914dd5990..6274d79c1353 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -204,10 +204,19 @@ static void da7219_aad_hptest_work(struct work_struct *work) snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL, DA7219_MIXOUT_R_AMP_EN_MASK, DA7219_MIXOUT_R_AMP_EN_MASK); - snd_soc_write(codec, DA7219_HP_L_CTRL, - DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK); - snd_soc_write(codec, DA7219_HP_R_CTRL, - DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7219_HP_L_CTRL, + DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK, + DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7219_HP_R_CTRL, + DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK, + DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); + msleep(DA7219_SETTLING_DELAY); + snd_soc_update_bits(codec, DA7219_HP_L_CTRL, + DA7219_HP_L_AMP_MUTE_EN_MASK | + DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0); + snd_soc_update_bits(codec, DA7219_HP_R_CTRL, + DA7219_HP_R_AMP_MUTE_EN_MASK | + DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0); /* * If we're running from the internal oscillator then give audio paths @@ -244,6 +253,7 @@ static void da7219_aad_hptest_work(struct work_struct *work) regcache_mark_dirty(da7219->regmap); regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL, DA7219_HP_R_CTRL); + msleep(DA7219_SETTLING_DELAY); regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL, DA7219_MIXOUT_R_CTRL); regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L, diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 1152aa5e7c39..99601627f83c 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -823,6 +823,85 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, } } +static int da7219_settling_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_POST_PMD: + msleep(DA7219_SETTLING_DELAY); + break; + default: + break; + } + + return 0; +} + +static int da7219_mixout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + u8 hp_ctrl, min_gain_mask; + + switch (w->reg) { + case DA7219_MIXOUT_L_CTRL: + hp_ctrl = DA7219_HP_L_CTRL; + min_gain_mask = DA7219_HP_L_AMP_MIN_GAIN_EN_MASK; + break; + case DA7219_MIXOUT_R_CTRL: + hp_ctrl = DA7219_HP_R_CTRL; + min_gain_mask = DA7219_HP_R_AMP_MIN_GAIN_EN_MASK; + break; + default: + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMD: + /* Enable minimum gain on HP to avoid pops */ + snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, + min_gain_mask); + + msleep(DA7219_MIN_GAIN_DELAY); + + break; + case SND_SOC_DAPM_POST_PMU: + /* Remove minimum gain on HP */ + snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, 0); + + break; + } + + return 0; +} + +static int da7219_gain_ramp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_PRE_PMD: + /* Ensure nominal gain ramping for DAPM sequence */ + da7219->gain_ramp_ctrl = + snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL); + snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, + DA7219_GAIN_RAMP_RATE_NOMINAL); + break; + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_POST_PMD: + /* Restore previous gain ramp settings */ + snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, + da7219->gain_ramp_ctrl); + break; + } + + return 0; +} + /* * DAPM Widgets @@ -880,7 +959,8 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = { SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), /* DAI */ - SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, DA7219_DAI_TDM_CTRL, + DA7219_DAI_OE_SHIFT, DA7219_NO_INVERT), SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0), /* Output Muxes */ @@ -906,30 +986,46 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = { ARRAY_SIZE(da7219_st_out_filtr_mix_controls)), /* DACs */ - SND_SOC_DAPM_DAC("DACL", NULL, DA7219_DAC_L_CTRL, DA7219_DAC_L_EN_SHIFT, - DA7219_NO_INVERT), - SND_SOC_DAPM_DAC("DACR", NULL, DA7219_DAC_R_CTRL, DA7219_DAC_R_EN_SHIFT, - DA7219_NO_INVERT), + SND_SOC_DAPM_DAC_E("DACL", NULL, DA7219_DAC_L_CTRL, + DA7219_DAC_L_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("DACR", NULL, DA7219_DAC_R_CTRL, + DA7219_DAC_R_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* Output PGAs */ - SND_SOC_DAPM_PGA("Mixout Left PGA", DA7219_MIXOUT_L_CTRL, - DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT, - NULL, 0), - SND_SOC_DAPM_PGA("Mixout Right PGA", DA7219_MIXOUT_R_CTRL, - DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT, - NULL, 0), - SND_SOC_DAPM_PGA("Headphone Left PGA", DA7219_HP_L_CTRL, - DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0), - SND_SOC_DAPM_PGA("Headphone Right PGA", DA7219_HP_R_CTRL, - DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA_E("Mixout Left PGA", DA7219_MIXOUT_L_CTRL, + DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT, + NULL, 0, da7219_mixout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Mixout Right PGA", DA7219_MIXOUT_R_CTRL, + DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT, + NULL, 0, da7219_mixout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("Headphone Left PGA", 1, DA7219_HP_L_CTRL, + DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("Headphone Right PGA", 1, DA7219_HP_R_CTRL, + DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* Output Supplies */ - SND_SOC_DAPM_SUPPLY("Charge Pump", DA7219_CP_CTRL, DA7219_CP_EN_SHIFT, - DA7219_NO_INVERT, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("Charge Pump", 0, DA7219_CP_CTRL, + DA7219_CP_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU), /* Outputs */ SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), + + /* Pre/Post Power */ + SND_SOC_DAPM_PRE("Pre Power Gain Ramp", da7219_gain_ramp_event), + SND_SOC_DAPM_POST("Post Power Gain Ramp", da7219_gain_ramp_event), }; @@ -1002,8 +1098,8 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = { {"Mixout Left PGA", NULL, "DACL"}, {"Mixout Right PGA", NULL, "DACR"}, - {"Headphone Left PGA", NULL, "Mixout Left PGA"}, - {"Headphone Right PGA", NULL, "Mixout Right PGA"}, + {"HPL", NULL, "Mixout Left PGA"}, + {"HPR", NULL, "Mixout Right PGA"}, {"HPL", NULL, "Headphone Left PGA"}, {"HPR", NULL, "Headphone Right PGA"}, @@ -1711,6 +1807,14 @@ static int da7219_probe(struct snd_soc_codec *codec) DA7219_HP_R_AMP_RAMP_EN_MASK, DA7219_HP_R_AMP_RAMP_EN_MASK); + /* Default minimum gain on HP to avoid pops during DAPM sequencing */ + snd_soc_update_bits(codec, DA7219_HP_L_CTRL, + DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, + DA7219_HP_L_AMP_MIN_GAIN_EN_MASK); + snd_soc_update_bits(codec, DA7219_HP_R_CTRL, + DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, + DA7219_HP_R_AMP_MIN_GAIN_EN_MASK); + /* Default infinite tone gen, start/stop by Kcontrol */ snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK); diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 66d3bad86739..6baba7455fa1 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -777,6 +777,10 @@ #define DA7219_SYS_STAT_CHECK_RETRIES 6 #define DA7219_SYS_STAT_CHECK_DELAY 50 +/* Power up/down Delays */ +#define DA7219_SETTLING_DELAY 40 +#define DA7219_MIN_GAIN_DELAY 30 + enum da7219_clk_src { DA7219_CLKSRC_MCLK = 0, DA7219_CLKSRC_MCLK_SQR, @@ -814,6 +818,7 @@ struct da7219_priv { bool master; bool alc_en; + u8 gain_ramp_ctrl; }; #endif /* __DA7219_H */ diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h index 1a736e72a929..8930322d712b 100644 --- a/sound/soc/codecs/es8328.h +++ b/sound/soc/codecs/es8328.h @@ -278,43 +278,6 @@ int es8328_probe(struct device *dev, struct regmap *regmap); #define ES8328_REG_MAX 0x35 -#define ES8328_PLL1 0 -#define ES8328_PLL2 1 - -/* clock inputs */ -#define ES8328_MCLK 0 -#define ES8328_PCMCLK 1 - -/* clock divider id's */ -#define ES8328_PCMDIV 0 -#define ES8328_BCLKDIV 1 -#define ES8328_VXCLKDIV 2 - -/* PCM clock dividers */ -#define ES8328_PCM_DIV_1 (0 << 6) -#define ES8328_PCM_DIV_3 (2 << 6) -#define ES8328_PCM_DIV_5_5 (3 << 6) -#define ES8328_PCM_DIV_2 (4 << 6) -#define ES8328_PCM_DIV_4 (5 << 6) -#define ES8328_PCM_DIV_6 (6 << 6) -#define ES8328_PCM_DIV_8 (7 << 6) - -/* BCLK clock dividers */ -#define ES8328_BCLK_DIV_1 (0 << 7) -#define ES8328_BCLK_DIV_2 (1 << 7) -#define ES8328_BCLK_DIV_4 (2 << 7) -#define ES8328_BCLK_DIV_8 (3 << 7) - -/* VXCLK clock dividers */ -#define ES8328_VXCLK_DIV_1 (0 << 6) -#define ES8328_VXCLK_DIV_2 (1 << 6) -#define ES8328_VXCLK_DIV_4 (2 << 6) -#define ES8328_VXCLK_DIV_8 (3 << 6) -#define ES8328_VXCLK_DIV_16 (4 << 6) - -#define ES8328_DAI_HIFI 0 -#define ES8328_DAI_VOICE 1 - #define ES8328_1536FS 1536 #define ES8328_1024FS 1024 #define ES8328_768FS 768 diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index b904492d7744..90b5948e0ff3 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -364,7 +364,12 @@ static int hdmi_of_xlate_dai_name(struct snd_soc_component *component, struct of_phandle_args *args, const char **dai_name) { - int id = args->args[0]; + int id; + + if (args->args_count) + id = args->args[0]; + else + id = 0; if (id < ARRAY_SIZE(hdmi_dai_name)) { *dai_name = hdmi_dai_name[id]; diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c new file mode 100644 index 000000000000..d8e8590746af --- /dev/null +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -0,0 +1,890 @@ +#include <linux/module.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/tlv.h> + +#define CDC_D_REVISION1 (0xf000) +#define CDC_D_PERPH_SUBTYPE (0xf005) +#define CDC_D_CDC_RST_CTL (0xf046) +#define RST_CTL_DIG_SW_RST_N_MASK BIT(7) +#define RST_CTL_DIG_SW_RST_N_RESET 0 +#define RST_CTL_DIG_SW_RST_N_REMOVE_RESET BIT(7) + +#define CDC_D_CDC_TOP_CLK_CTL (0xf048) +#define TOP_CLK_CTL_A_MCLK_MCLK2_EN_MASK (BIT(2) | BIT(3)) +#define TOP_CLK_CTL_A_MCLK_EN_ENABLE BIT(2) +#define TOP_CLK_CTL_A_MCLK2_EN_ENABLE BIT(3) + +#define CDC_D_CDC_ANA_CLK_CTL (0xf049) +#define ANA_CLK_CTL_EAR_HPHR_CLK_EN_MASK BIT(0) +#define ANA_CLK_CTL_EAR_HPHR_CLK_EN BIT(0) +#define ANA_CLK_CTL_EAR_HPHL_CLK_EN BIT(1) +#define ANA_CLK_CTL_SPKR_CLK_EN_MASK BIT(4) +#define ANA_CLK_CTL_SPKR_CLK_EN BIT(4) +#define ANA_CLK_CTL_TXA_CLK25_EN BIT(5) + +#define CDC_D_CDC_DIG_CLK_CTL (0xf04A) +#define DIG_CLK_CTL_RXD1_CLK_EN BIT(0) +#define DIG_CLK_CTL_RXD2_CLK_EN BIT(1) +#define DIG_CLK_CTL_RXD3_CLK_EN BIT(3) +#define DIG_CLK_CTL_TXD_CLK_EN BIT(4) +#define DIG_CLK_CTL_NCP_CLK_EN_MASK BIT(6) +#define DIG_CLK_CTL_NCP_CLK_EN BIT(6) +#define DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK BIT(7) +#define DIG_CLK_CTL_RXD_PDM_CLK_EN BIT(7) + +#define CDC_D_CDC_CONN_TX1_CTL (0xf050) +#define CONN_TX1_SERIAL_TX1_MUX GENMASK(1, 0) +#define CONN_TX1_SERIAL_TX1_ADC_1 0x0 +#define CONN_TX1_SERIAL_TX1_RX_PDM_LB 0x1 +#define CONN_TX1_SERIAL_TX1_ZERO 0x2 + +#define CDC_D_CDC_CONN_TX2_CTL (0xf051) +#define CONN_TX2_SERIAL_TX2_MUX GENMASK(1, 0) +#define CONN_TX2_SERIAL_TX2_ADC_2 0x0 +#define CONN_TX2_SERIAL_TX2_RX_PDM_LB 0x1 +#define CONN_TX2_SERIAL_TX2_ZERO 0x2 +#define CDC_D_CDC_CONN_HPHR_DAC_CTL (0xf052) +#define CDC_D_CDC_CONN_RX1_CTL (0xf053) +#define CDC_D_CDC_CONN_RX2_CTL (0xf054) +#define CDC_D_CDC_CONN_RX3_CTL (0xf055) +#define CDC_D_CDC_CONN_RX_LB_CTL (0xf056) +#define CDC_D_SEC_ACCESS (0xf0D0) +#define CDC_D_PERPH_RESET_CTL3 (0xf0DA) +#define CDC_D_PERPH_RESET_CTL4 (0xf0DB) +#define CDC_A_REVISION1 (0xf100) +#define CDC_A_REVISION2 (0xf101) +#define CDC_A_REVISION3 (0xf102) +#define CDC_A_REVISION4 (0xf103) +#define CDC_A_PERPH_TYPE (0xf104) +#define CDC_A_PERPH_SUBTYPE (0xf105) +#define CDC_A_INT_RT_STS (0xf110) +#define CDC_A_INT_SET_TYPE (0xf111) +#define CDC_A_INT_POLARITY_HIGH (0xf112) +#define CDC_A_INT_POLARITY_LOW (0xf113) +#define CDC_A_INT_LATCHED_CLR (0xf114) +#define CDC_A_INT_EN_SET (0xf115) +#define CDC_A_INT_EN_CLR (0xf116) +#define CDC_A_INT_LATCHED_STS (0xf118) +#define CDC_A_INT_PENDING_STS (0xf119) +#define CDC_A_INT_MID_SEL (0xf11A) +#define CDC_A_INT_PRIORITY (0xf11B) +#define CDC_A_MICB_1_EN (0xf140) +#define MICB_1_EN_MICB_ENABLE BIT(7) +#define MICB_1_EN_BYP_CAP_MASK BIT(6) +#define MICB_1_EN_NO_EXT_BYP_CAP BIT(6) +#define MICB_1_EN_EXT_BYP_CAP 0 +#define MICB_1_EN_PULL_DOWN_EN_MASK BIT(5) +#define MICB_1_EN_PULL_DOWN_EN_ENABLE BIT(5) +#define MICB_1_EN_OPA_STG2_TAIL_CURR_MASK GENMASK(3, 1) +#define MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA (0x4) +#define MICB_1_EN_PULL_UP_EN_MASK BIT(4) +#define MICB_1_EN_TX3_GND_SEL_MASK BIT(0) +#define MICB_1_EN_TX3_GND_SEL_TX_GND 0 + +#define CDC_A_MICB_1_VAL (0xf141) +#define MICB_1_VAL_MICB_OUT_VAL_MASK GENMASK(7, 3) +#define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16) << 3) +#define CDC_A_MICB_1_CTL (0xf142) + +#define MICB_1_CTL_CFILT_REF_SEL_MASK BIT(1) +#define MICB_1_CTL_CFILT_REF_SEL_HPF_REF BIT(1) +#define MICB_1_CTL_EXT_PRECHARG_EN_MASK BIT(5) +#define MICB_1_CTL_EXT_PRECHARG_EN_ENABLE BIT(5) +#define MICB_1_CTL_INT_PRECHARG_BYP_MASK BIT(6) +#define MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL BIT(6) + +#define CDC_A_MICB_1_INT_RBIAS (0xf143) +#define MICB_1_INT_TX1_INT_RBIAS_EN_MASK BIT(7) +#define MICB_1_INT_TX1_INT_RBIAS_EN_ENABLE BIT(7) +#define MICB_1_INT_TX1_INT_RBIAS_EN_DISABLE 0 + +#define MICB_1_INT_TX1_INT_PULLUP_EN_MASK BIT(6) +#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(6) +#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_GND 0 + +#define MICB_1_INT_TX2_INT_RBIAS_EN_MASK BIT(4) +#define MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE BIT(4) +#define MICB_1_INT_TX2_INT_RBIAS_EN_DISABLE 0 +#define MICB_1_INT_TX2_INT_PULLUP_EN_MASK BIT(3) +#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(3) +#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_GND 0 + +#define MICB_1_INT_TX3_INT_RBIAS_EN_MASK BIT(1) +#define MICB_1_INT_TX3_INT_RBIAS_EN_ENABLE BIT(1) +#define MICB_1_INT_TX3_INT_RBIAS_EN_DISABLE 0 +#define MICB_1_INT_TX3_INT_PULLUP_EN_MASK BIT(0) +#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(0) +#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND 0 + +#define CDC_A_MICB_2_EN (0xf144) +#define CDC_A_TX_1_2_ATEST_CTL_2 (0xf145) +#define CDC_A_MASTER_BIAS_CTL (0xf146) +#define CDC_A_TX_1_EN (0xf160) +#define CDC_A_TX_2_EN (0xf161) +#define CDC_A_TX_1_2_TEST_CTL_1 (0xf162) +#define CDC_A_TX_1_2_TEST_CTL_2 (0xf163) +#define CDC_A_TX_1_2_ATEST_CTL (0xf164) +#define CDC_A_TX_1_2_OPAMP_BIAS (0xf165) +#define CDC_A_TX_3_EN (0xf167) +#define CDC_A_NCP_EN (0xf180) +#define CDC_A_NCP_CLK (0xf181) +#define CDC_A_NCP_FBCTRL (0xf183) +#define CDC_A_NCP_FBCTRL_FB_CLK_INV_MASK BIT(5) +#define CDC_A_NCP_FBCTRL_FB_CLK_INV BIT(5) +#define CDC_A_NCP_BIAS (0xf184) +#define CDC_A_NCP_VCTRL (0xf185) +#define CDC_A_NCP_TEST (0xf186) +#define CDC_A_NCP_CLIM_ADDR (0xf187) +#define CDC_A_RX_CLOCK_DIVIDER (0xf190) +#define CDC_A_RX_COM_OCP_CTL (0xf191) +#define CDC_A_RX_COM_OCP_COUNT (0xf192) +#define CDC_A_RX_COM_BIAS_DAC (0xf193) +#define RX_COM_BIAS_DAC_RX_BIAS_EN_MASK BIT(7) +#define RX_COM_BIAS_DAC_RX_BIAS_EN_ENABLE BIT(7) +#define RX_COM_BIAS_DAC_DAC_REF_EN_MASK BIT(0) +#define RX_COM_BIAS_DAC_DAC_REF_EN_ENABLE BIT(0) + +#define CDC_A_RX_HPH_BIAS_PA (0xf194) +#define CDC_A_RX_HPH_BIAS_LDO_OCP (0xf195) +#define CDC_A_RX_HPH_BIAS_CNP (0xf196) +#define CDC_A_RX_HPH_CNP_EN (0xf197) +#define CDC_A_RX_HPH_L_PA_DAC_CTL (0xf19B) +#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK BIT(1) +#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET BIT(1) +#define CDC_A_RX_HPH_R_PA_DAC_CTL (0xf19D) +#define RX_HPH_R_PA_DAC_CTL_DATA_RESET BIT(1) +#define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1) + +#define CDC_A_RX_EAR_CTL (0xf19E) +#define RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK BIT(0) +#define RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE BIT(0) + +#define CDC_A_SPKR_DAC_CTL (0xf1B0) +#define SPKR_DAC_CTL_DAC_RESET_MASK BIT(4) +#define SPKR_DAC_CTL_DAC_RESET_NORMAL 0 + +#define CDC_A_SPKR_DRV_CTL (0xf1B2) +#define SPKR_DRV_CTL_DEF_MASK 0xEF +#define SPKR_DRV_CLASSD_PA_EN_MASK BIT(7) +#define SPKR_DRV_CLASSD_PA_EN_ENABLE BIT(7) +#define SPKR_DRV_CAL_EN BIT(6) +#define SPKR_DRV_SETTLE_EN BIT(5) +#define SPKR_DRV_FW_EN BIT(3) +#define SPKR_DRV_BOOST_SET BIT(2) +#define SPKR_DRV_CMFB_SET BIT(1) +#define SPKR_DRV_GAIN_SET BIT(0) +#define SPKR_DRV_CTL_DEF_VAL (SPKR_DRV_CLASSD_PA_EN_ENABLE | \ + SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \ + SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \ + SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET) +#define CDC_A_SPKR_OCP_CTL (0xf1B4) +#define CDC_A_SPKR_PWRSTG_CTL (0xf1B5) +#define SPKR_PWRSTG_CTL_DAC_EN_MASK BIT(0) +#define SPKR_PWRSTG_CTL_DAC_EN BIT(0) +#define SPKR_PWRSTG_CTL_MASK 0xE0 +#define SPKR_PWRSTG_CTL_BBM_MASK BIT(7) +#define SPKR_PWRSTG_CTL_BBM_EN BIT(7) +#define SPKR_PWRSTG_CTL_HBRDGE_EN_MASK BIT(6) +#define SPKR_PWRSTG_CTL_HBRDGE_EN BIT(6) +#define SPKR_PWRSTG_CTL_CLAMP_EN_MASK BIT(5) +#define SPKR_PWRSTG_CTL_CLAMP_EN BIT(5) + +#define CDC_A_SPKR_DRV_DBG (0xf1B7) +#define CDC_A_CURRENT_LIMIT (0xf1C0) +#define CDC_A_BOOST_EN_CTL (0xf1C3) +#define CDC_A_SLOPE_COMP_IP_ZERO (0xf1C4) +#define CDC_A_SEC_ACCESS (0xf1D0) +#define CDC_A_PERPH_RESET_CTL3 (0xf1DA) +#define CDC_A_PERPH_RESET_CTL4 (0xf1DB) + +#define MSM8916_WCD_ANALOG_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000) +#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static const char * const supply_names[] = { + "vdd-cdc-io", + "vdd-cdc-tx-rx-cx", +}; + +struct pm8916_wcd_analog_priv { + u16 pmic_rev; + u16 codec_version; + struct clk *mclk; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; + bool micbias1_cap_mode; + bool micbias2_cap_mode; +}; + +static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; +static const char *const rdac2_mux_text[] = { "ZERO", "RX2", "RX1" }; +static const char *const hph_text[] = { "ZERO", "Switch", }; + +static const struct soc_enum hph_enum = SOC_ENUM_SINGLE_VIRT( + ARRAY_SIZE(hph_text), hph_text); + +static const struct snd_kcontrol_new hphl_mux = SOC_DAPM_ENUM("HPHL", hph_enum); +static const struct snd_kcontrol_new hphr_mux = SOC_DAPM_ENUM("HPHR", hph_enum); + +/* ADC2 MUX */ +static const struct soc_enum adc2_enum = SOC_ENUM_SINGLE_VIRT( + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + +/* RDAC2 MUX */ +static const struct soc_enum rdac2_mux_enum = SOC_ENUM_SINGLE( + CDC_D_CDC_CONN_HPHR_DAC_CTL, 0, 3, rdac2_mux_text); + +static const struct snd_kcontrol_new spkr_switch[] = { + SOC_DAPM_SINGLE("Switch", CDC_A_SPKR_DAC_CTL, 7, 1, 0) +}; + +static const struct snd_kcontrol_new rdac2_mux = SOC_DAPM_ENUM( + "RDAC2 MUX Mux", rdac2_mux_enum); +static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM( + "ADC2 MUX Mux", adc2_enum); + +/* Analog Gain control 0 dB to +24 dB in 6 dB steps */ +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 600, 0); + +static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = { + SOC_SINGLE_TLV("ADC1 Volume", CDC_A_TX_1_EN, 3, 8, 0, analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", CDC_A_TX_2_EN, 3, 8, 0, analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", CDC_A_TX_3_EN, 3, 8, 0, analog_gain), +}; + +static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec) +{ + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, + MICB_1_CTL_EXT_PRECHARG_EN_MASK | + MICB_1_CTL_INT_PRECHARG_BYP_MASK, + MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL + | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE); + + snd_soc_write(codec, CDC_A_MICB_1_VAL, MICB_1_VAL_MICB_OUT_VAL_V2P70V); + /* + * Special headset needs MICBIAS as 2.7V so wait for + * 50 msec for the MICBIAS to reach 2.7 volts. + */ + msleep(50); + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, + MICB_1_CTL_EXT_PRECHARG_EN_MASK | + MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0); + +} + +static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec + *codec, int event, + int reg, u32 cap_mode) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + pm8916_wcd_analog_micbias_enable(codec); + snd_soc_update_bits(codec, CDC_A_MICB_1_EN, + MICB_1_EN_BYP_CAP_MASK, cap_mode); + break; + } + + return 0; +} + +static int pm8916_wcd_analog_enable_micbias_int(struct snd_soc_codec + *codec, int event, + int reg, u32 cap_mode) +{ + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS, + MICB_1_INT_TX2_INT_RBIAS_EN_MASK, + MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE); + snd_soc_update_bits(codec, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0); + snd_soc_update_bits(codec, CDC_A_MICB_1_EN, + MICB_1_EN_OPA_STG2_TAIL_CURR_MASK, + MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA); + + break; + case SND_SOC_DAPM_POST_PMU: + pm8916_wcd_analog_micbias_enable(codec); + snd_soc_update_bits(codec, CDC_A_MICB_1_EN, + MICB_1_EN_BYP_CAP_MASK, cap_mode); + break; + } + + return 0; +} + +static int pm8916_wcd_analog_enable_micbias_ext1(struct + snd_soc_dapm_widget + *w, struct snd_kcontrol + *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + + return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg, + wcd->micbias1_cap_mode); +} + +static int pm8916_wcd_analog_enable_micbias_ext2(struct + snd_soc_dapm_widget + *w, struct snd_kcontrol + *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + + return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg, + wcd->micbias2_cap_mode); + +} + +static int pm8916_wcd_analog_enable_micbias_int1(struct + snd_soc_dapm_widget + *w, struct snd_kcontrol + *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + + return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg, + wcd->micbias1_cap_mode); +} + +static int pm8916_wcd_analog_enable_micbias_int2(struct + snd_soc_dapm_widget + *w, struct snd_kcontrol + *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + + return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg, + wcd->micbias2_cap_mode); +} + +static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + u16 adc_reg = CDC_A_TX_1_2_TEST_CTL_2; + u8 init_bit_shift; + + if (w->reg == CDC_A_TX_1_EN) + init_bit_shift = 5; + else + init_bit_shift = 4; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (w->reg == CDC_A_TX_2_EN) + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, + MICB_1_CTL_CFILT_REF_SEL_MASK, + MICB_1_CTL_CFILT_REF_SEL_HPF_REF); + /* + * Add delay of 10 ms to give sufficient time for the voltage + * to shoot up and settle so that the txfe init does not + * happen when the input voltage is changing too much. + */ + usleep_range(10000, 10010); + snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, + 1 << init_bit_shift); + switch (w->reg) { + case CDC_A_TX_1_EN: + snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL, + CONN_TX1_SERIAL_TX1_MUX, + CONN_TX1_SERIAL_TX1_ADC_1); + break; + case CDC_A_TX_2_EN: + case CDC_A_TX_3_EN: + snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL, + CONN_TX2_SERIAL_TX2_MUX, + CONN_TX2_SERIAL_TX2_ADC_2); + break; + } + break; + case SND_SOC_DAPM_POST_PMU: + /* + * Add delay of 12 ms before deasserting the init + * to reduce the tx pop + */ + usleep_range(12000, 12010); + snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + switch (w->reg) { + case CDC_A_TX_1_EN: + snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL, + CONN_TX1_SERIAL_TX1_MUX, + CONN_TX1_SERIAL_TX1_ZERO); + break; + case CDC_A_TX_2_EN: + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, + MICB_1_CTL_CFILT_REF_SEL_MASK, 0); + case CDC_A_TX_3_EN: + snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL, + CONN_TX2_SERIAL_TX2_MUX, + CONN_TX2_SERIAL_TX2_ZERO); + break; + } + + + break; + } + return 0; +} + +static int pm8916_wcd_analog_enable_spk_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL, + SPKR_PWRSTG_CTL_DAC_EN_MASK | + SPKR_PWRSTG_CTL_BBM_MASK | + SPKR_PWRSTG_CTL_HBRDGE_EN_MASK | + SPKR_PWRSTG_CTL_CLAMP_EN_MASK, + SPKR_PWRSTG_CTL_DAC_EN| + SPKR_PWRSTG_CTL_BBM_EN | + SPKR_PWRSTG_CTL_HBRDGE_EN | + SPKR_PWRSTG_CTL_CLAMP_EN); + + snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL, + RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, + RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, CDC_A_SPKR_DRV_CTL, + SPKR_DRV_CTL_DEF_MASK, + SPKR_DRV_CTL_DEF_VAL); + snd_soc_update_bits(codec, w->reg, + SPKR_DRV_CLASSD_PA_EN_MASK, + SPKR_DRV_CLASSD_PA_EN_ENABLE); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL, + SPKR_PWRSTG_CTL_DAC_EN_MASK| + SPKR_PWRSTG_CTL_BBM_MASK | + SPKR_PWRSTG_CTL_HBRDGE_EN_MASK | + SPKR_PWRSTG_CTL_CLAMP_EN_MASK, 0); + + snd_soc_update_bits(codec, CDC_A_SPKR_DAC_CTL, + SPKR_DAC_CTL_DAC_RESET_MASK, + SPKR_DAC_CTL_DAC_RESET_NORMAL); + snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL, + RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, 0); + break; + } + return 0; +} + +static const struct reg_default wcd_reg_defaults_2_0[] = { + {CDC_A_RX_COM_OCP_CTL, 0xD1}, + {CDC_A_RX_COM_OCP_COUNT, 0xFF}, + {CDC_D_SEC_ACCESS, 0xA5}, + {CDC_D_PERPH_RESET_CTL3, 0x0F}, + {CDC_A_TX_1_2_OPAMP_BIAS, 0x4F}, + {CDC_A_NCP_FBCTRL, 0x28}, + {CDC_A_SPKR_DRV_CTL, 0x69}, + {CDC_A_SPKR_DRV_DBG, 0x01}, + {CDC_A_BOOST_EN_CTL, 0x5F}, + {CDC_A_SLOPE_COMP_IP_ZERO, 0x88}, + {CDC_A_SEC_ACCESS, 0xA5}, + {CDC_A_PERPH_RESET_CTL3, 0x0F}, + {CDC_A_CURRENT_LIMIT, 0x82}, + {CDC_A_SPKR_DAC_CTL, 0x03}, + {CDC_A_SPKR_OCP_CTL, 0xE1}, + {CDC_A_MASTER_BIAS_CTL, 0x30}, +}; + +static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec) +{ + struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev); + int err, reg; + + err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); + if (err != 0) { + dev_err(codec->dev, "failed to enable regulators (%d)\n", err); + return err; + } + + snd_soc_codec_set_drvdata(codec, priv); + priv->pmic_rev = snd_soc_read(codec, CDC_D_REVISION1); + priv->codec_version = snd_soc_read(codec, CDC_D_PERPH_SUBTYPE); + + dev_info(codec->dev, "PMIC REV: %d\t CODEC Version: %d\n", + priv->pmic_rev, priv->codec_version); + + snd_soc_write(codec, CDC_D_PERPH_RESET_CTL4, 0x01); + snd_soc_write(codec, CDC_A_PERPH_RESET_CTL4, 0x01); + + for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++) + snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg, + wcd_reg_defaults_2_0[reg].def); + + return 0; +} + +static int pm8916_wcd_analog_remove(struct snd_soc_codec *codec) +{ + struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev); + + return regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + priv->supplies); +} + +static const struct snd_soc_dapm_route pm8916_wcd_analog_audio_map[] = { + + {"PDM_RX1", NULL, "PDM Playback"}, + {"PDM_RX2", NULL, "PDM Playback"}, + {"PDM_RX3", NULL, "PDM Playback"}, + {"PDM Capture", NULL, "PDM_TX"}, + + /* ADC Connections */ + {"PDM_TX", NULL, "ADC2"}, + {"PDM_TX", NULL, "ADC3"}, + {"ADC2", NULL, "ADC2 MUX"}, + {"ADC3", NULL, "ADC2 MUX"}, + {"ADC2 MUX", "INP2", "ADC2_INP2"}, + {"ADC2 MUX", "INP3", "ADC2_INP3"}, + + {"PDM_TX", NULL, "ADC1"}, + {"ADC1", NULL, "AMIC1"}, + {"ADC2_INP2", NULL, "AMIC2"}, + {"ADC2_INP3", NULL, "AMIC3"}, + + /* RDAC Connections */ + {"HPHR DAC", NULL, "RDAC2 MUX"}, + {"RDAC2 MUX", "RX1", "PDM_RX1"}, + {"RDAC2 MUX", "RX2", "PDM_RX2"}, + {"HPHL DAC", NULL, "PDM_RX1"}, + {"PDM_RX1", NULL, "RXD1_CLK"}, + {"PDM_RX2", NULL, "RXD2_CLK"}, + {"PDM_RX3", NULL, "RXD3_CLK"}, + + {"PDM_RX1", NULL, "RXD_PDM_CLK"}, + {"PDM_RX2", NULL, "RXD_PDM_CLK"}, + {"PDM_RX3", NULL, "RXD_PDM_CLK"}, + + {"ADC1", NULL, "TXD_CLK"}, + {"ADC2", NULL, "TXD_CLK"}, + {"ADC3", NULL, "TXD_CLK"}, + + {"ADC1", NULL, "TXA_CLK25"}, + {"ADC2", NULL, "TXA_CLK25"}, + {"ADC3", NULL, "TXA_CLK25"}, + + {"PDM_RX1", NULL, "A_MCLK2"}, + {"PDM_RX2", NULL, "A_MCLK2"}, + {"PDM_RX3", NULL, "A_MCLK2"}, + + {"PDM_TX", NULL, "A_MCLK2"}, + {"A_MCLK2", NULL, "A_MCLK"}, + + /* Headset (RX MIX1 and RX MIX2) */ + {"HEADPHONE", NULL, "HPHL PA"}, + {"HEADPHONE", NULL, "HPHR PA"}, + + {"HPHL PA", NULL, "EAR_HPHL_CLK"}, + {"HPHR PA", NULL, "EAR_HPHR_CLK"}, + + {"CP", NULL, "NCP_CLK"}, + + {"HPHL PA", NULL, "HPHL"}, + {"HPHR PA", NULL, "HPHR"}, + {"HPHL PA", NULL, "CP"}, + {"HPHL PA", NULL, "RX_BIAS"}, + {"HPHR PA", NULL, "CP"}, + {"HPHR PA", NULL, "RX_BIAS"}, + {"HPHL", "Switch", "HPHL DAC"}, + {"HPHR", "Switch", "HPHR DAC"}, + + {"RX_BIAS", NULL, "DAC_REF"}, + + {"SPK_OUT", NULL, "SPK PA"}, + {"SPK PA", NULL, "RX_BIAS"}, + {"SPK PA", NULL, "SPKR_CLK"}, + {"SPK PA", NULL, "SPK DAC"}, + {"SPK DAC", "Switch", "PDM_RX3"}, + + {"MIC BIAS Internal1", NULL, "INT_LDO_H"}, + {"MIC BIAS Internal2", NULL, "INT_LDO_H"}, + {"MIC BIAS External1", NULL, "INT_LDO_H"}, + {"MIC BIAS External2", NULL, "INT_LDO_H"}, + {"MIC BIAS Internal1", NULL, "vdd-micbias"}, + {"MIC BIAS Internal2", NULL, "vdd-micbias"}, + {"MIC BIAS External1", NULL, "vdd-micbias"}, + {"MIC BIAS External2", NULL, "vdd-micbias"}, +}; + +static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { + + SND_SOC_DAPM_AIF_IN("PDM_RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("PDM_RX2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("PDM_RX3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("PDM_TX", NULL, 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_OUTPUT("HEADPHONE"), + + /* RX stuff */ + SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0), + + SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0), + SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux), + SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL, + 0), + SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0), + SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux), + SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL, + 0), + SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0, + spkr_switch, ARRAY_SIZE(spkr_switch)), + + /* Speaker */ + SND_SOC_DAPM_OUTPUT("SPK_OUT"), + SND_SOC_DAPM_PGA_E("SPK PA", CDC_A_SPKR_DRV_CTL, + 6, 0, NULL, 0, + pm8916_wcd_analog_enable_spk_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micbias", 0, 0), + SND_SOC_DAPM_SUPPLY("CP", CDC_A_NCP_EN, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC_REF", CDC_A_RX_COM_BIAS_DAC, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RX_BIAS", CDC_A_RX_COM_BIAS_DAC, 7, 0, NULL, 0), + + /* TX */ + SND_SOC_DAPM_SUPPLY("MIC BIAS Internal1", CDC_A_MICB_1_EN, 7, 0, + pm8916_wcd_analog_enable_micbias_int1, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS Internal2", CDC_A_MICB_2_EN, 7, 0, + pm8916_wcd_analog_enable_micbias_int2, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0, + pm8916_wcd_analog_enable_micbias_ext1, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0, + pm8916_wcd_analog_enable_micbias_ext2, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0, + pm8916_wcd_analog_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, CDC_A_TX_2_EN, 7, 0, + pm8916_wcd_analog_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, CDC_A_TX_3_EN, 7, 0, + pm8916_wcd_analog_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux), + SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux), + + /* Analog path clocks */ + SND_SOC_DAPM_SUPPLY("EAR_HPHR_CLK", CDC_D_CDC_ANA_CLK_CTL, 0, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY("EAR_HPHL_CLK", CDC_D_CDC_ANA_CLK_CTL, 1, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY("SPKR_CLK", CDC_D_CDC_ANA_CLK_CTL, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TXA_CLK25", CDC_D_CDC_ANA_CLK_CTL, 5, 0, NULL, 0), + + /* Digital path clocks */ + + SND_SOC_DAPM_SUPPLY("RXD1_CLK", CDC_D_CDC_DIG_CLK_CTL, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RXD2_CLK", CDC_D_CDC_DIG_CLK_CTL, 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RXD3_CLK", CDC_D_CDC_DIG_CLK_CTL, 2, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("TXD_CLK", CDC_D_CDC_DIG_CLK_CTL, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("NCP_CLK", CDC_D_CDC_DIG_CLK_CTL, 6, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RXD_PDM_CLK", CDC_D_CDC_DIG_CLK_CTL, 7, 0, NULL, + 0), + + /* System Clock source */ + SND_SOC_DAPM_SUPPLY("A_MCLK", CDC_D_CDC_TOP_CLK_CTL, 2, 0, NULL, 0), + /* TX ADC and RX DAC Clock source. */ + SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0), +}; + +static struct regmap *pm8916_get_regmap(struct device *dev) +{ + return dev_get_regmap(dev->parent, NULL); +} + +static int pm8916_wcd_analog_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL, + RST_CTL_DIG_SW_RST_N_MASK, + RST_CTL_DIG_SW_RST_N_REMOVE_RESET); + + return 0; +} + +static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL, + RST_CTL_DIG_SW_RST_N_MASK, 0); +} + +static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = { + .startup = pm8916_wcd_analog_startup, + .shutdown = pm8916_wcd_analog_shutdown, +}; + +static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { + [0] = { + .name = "pm8916_wcd_analog_pdm_rx", + .id = 0, + .playback = { + .stream_name = "PDM Playback", + .rates = MSM8916_WCD_ANALOG_RATES, + .formats = MSM8916_WCD_ANALOG_FORMATS, + .channels_min = 1, + .channels_max = 3, + }, + .ops = &pm8916_wcd_analog_dai_ops, + }, + [1] = { + .name = "pm8916_wcd_analog_pdm_tx", + .id = 1, + .capture = { + .stream_name = "PDM Capture", + .rates = MSM8916_WCD_ANALOG_RATES, + .formats = MSM8916_WCD_ANALOG_FORMATS, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &pm8916_wcd_analog_dai_ops, + }, +}; + +static struct snd_soc_codec_driver pm8916_wcd_analog = { + .probe = pm8916_wcd_analog_probe, + .remove = pm8916_wcd_analog_remove, + .get_regmap = pm8916_get_regmap, + .component_driver = { + .controls = pm8916_wcd_analog_snd_controls, + .num_controls = ARRAY_SIZE(pm8916_wcd_analog_snd_controls), + .dapm_widgets = pm8916_wcd_analog_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pm8916_wcd_analog_dapm_widgets), + .dapm_routes = pm8916_wcd_analog_audio_map, + .num_dapm_routes = ARRAY_SIZE(pm8916_wcd_analog_audio_map), + }, +}; + +static int pm8916_wcd_analog_parse_dt(struct device *dev, + struct pm8916_wcd_analog_priv *priv) +{ + + if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap")) + priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP; + else + priv->micbias1_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP; + + if (of_property_read_bool(dev->of_node, "qcom,micbias2-ext-cap")) + priv->micbias2_cap_mode = MICB_1_EN_EXT_BYP_CAP; + else + priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP; + + return 0; +} + +static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) +{ + struct pm8916_wcd_analog_priv *priv; + struct device *dev = &pdev->dev; + int ret, i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + ret = pm8916_wcd_analog_parse_dt(dev, priv); + if (ret < 0) + return ret; + + priv->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(priv->mclk)) { + dev_err(dev, "failed to get mclk\n"); + return PTR_ERR(priv->mclk); + } + + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + priv->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret) { + dev_err(dev, "Failed to get regulator supplies %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(priv->mclk); + if (ret < 0) { + dev_err(dev, "failed to enable mclk %d\n", ret); + return ret; + } + + dev_set_drvdata(dev, priv); + + return snd_soc_register_codec(dev, &pm8916_wcd_analog, + pm8916_wcd_analog_dai, + ARRAY_SIZE(pm8916_wcd_analog_dai)); +} + +static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev) +{ + struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_codec(&pdev->dev); + clk_disable_unprepare(priv->mclk); + + return 0; +} + +static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { + { .compatible = "qcom,pm8916-wcd-analog-codec", }, + { } +}; + +static struct platform_driver pm8916_wcd_analog_spmi_driver = { + .driver = { + .name = "qcom,pm8916-wcd-spmi-codec", + .of_match_table = pm8916_wcd_analog_spmi_match_table, + }, + .probe = pm8916_wcd_analog_spmi_probe, + .remove = pm8916_wcd_analog_spmi_remove, +}; + +module_platform_driver(pm8916_wcd_analog_spmi_driver); + +MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>"); +MODULE_DESCRIPTION("PMIC PM8916 WCD Analog Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c new file mode 100644 index 000000000000..f690442af8c9 --- /dev/null +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -0,0 +1,923 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> +#include <sound/soc.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/tlv.h> + +#define LPASS_CDC_CLK_RX_RESET_CTL (0x000) +#define LPASS_CDC_CLK_TX_RESET_B1_CTL (0x004) +#define CLK_RX_RESET_B1_CTL_TX1_RESET_MASK BIT(0) +#define CLK_RX_RESET_B1_CTL_TX2_RESET_MASK BIT(1) +#define LPASS_CDC_CLK_DMIC_B1_CTL (0x008) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_MASK GENMASK(3, 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV2 (0x0 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3 (0x1 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV4 (0x2 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV6 (0x3 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV16 (0x4 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_EN_MASK BIT(0) +#define DMIC_B1_CTL_DMIC0_CLK_EN_ENABLE BIT(0) + +#define LPASS_CDC_CLK_RX_I2S_CTL (0x00C) +#define RX_I2S_CTL_RX_I2S_MODE_MASK BIT(5) +#define RX_I2S_CTL_RX_I2S_MODE_16 BIT(5) +#define RX_I2S_CTL_RX_I2S_MODE_32 0 +#define RX_I2S_CTL_RX_I2S_FS_RATE_MASK GENMASK(2, 0) +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ 0x0 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ 0x1 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ 0x2 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ 0x3 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_96_KHZ 0x4 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_192_KHZ 0x5 +#define LPASS_CDC_CLK_TX_I2S_CTL (0x010) +#define TX_I2S_CTL_TX_I2S_MODE_MASK BIT(5) +#define TX_I2S_CTL_TX_I2S_MODE_16 BIT(5) +#define TX_I2S_CTL_TX_I2S_MODE_32 0 +#define TX_I2S_CTL_TX_I2S_FS_RATE_MASK GENMASK(2, 0) +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ 0x0 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ 0x1 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ 0x2 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ 0x3 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_96_KHZ 0x4 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_192_KHZ 0x5 + +#define LPASS_CDC_CLK_OTHR_RESET_B1_CTL (0x014) +#define LPASS_CDC_CLK_TX_CLK_EN_B1_CTL (0x018) +#define LPASS_CDC_CLK_OTHR_CTL (0x01C) +#define LPASS_CDC_CLK_RX_B1_CTL (0x020) +#define LPASS_CDC_CLK_MCLK_CTL (0x024) +#define MCLK_CTL_MCLK_EN_MASK BIT(0) +#define MCLK_CTL_MCLK_EN_ENABLE BIT(0) +#define MCLK_CTL_MCLK_EN_DISABLE 0 +#define LPASS_CDC_CLK_PDM_CTL (0x028) +#define LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK BIT(0) +#define LPASS_CDC_CLK_PDM_CTL_PDM_EN BIT(0) +#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK BIT(1) +#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB BIT(1) +#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_PDM_CLK 0 + +#define LPASS_CDC_CLK_SD_CTL (0x02C) +#define LPASS_CDC_RX1_B1_CTL (0x040) +#define LPASS_CDC_RX2_B1_CTL (0x060) +#define LPASS_CDC_RX3_B1_CTL (0x080) +#define LPASS_CDC_RX1_B2_CTL (0x044) +#define LPASS_CDC_RX2_B2_CTL (0x064) +#define LPASS_CDC_RX3_B2_CTL (0x084) +#define LPASS_CDC_RX1_B3_CTL (0x048) +#define LPASS_CDC_RX2_B3_CTL (0x068) +#define LPASS_CDC_RX3_B3_CTL (0x088) +#define LPASS_CDC_RX1_B4_CTL (0x04C) +#define LPASS_CDC_RX2_B4_CTL (0x06C) +#define LPASS_CDC_RX3_B4_CTL (0x08C) +#define LPASS_CDC_RX1_B5_CTL (0x050) +#define LPASS_CDC_RX2_B5_CTL (0x070) +#define LPASS_CDC_RX3_B5_CTL (0x090) +#define LPASS_CDC_RX1_B6_CTL (0x054) +#define RXn_B6_CTL_MUTE_MASK BIT(0) +#define RXn_B6_CTL_MUTE_ENABLE BIT(0) +#define RXn_B6_CTL_MUTE_DISABLE 0 +#define LPASS_CDC_RX2_B6_CTL (0x074) +#define LPASS_CDC_RX3_B6_CTL (0x094) +#define LPASS_CDC_RX1_VOL_CTL_B1_CTL (0x058) +#define LPASS_CDC_RX2_VOL_CTL_B1_CTL (0x078) +#define LPASS_CDC_RX3_VOL_CTL_B1_CTL (0x098) +#define LPASS_CDC_RX1_VOL_CTL_B2_CTL (0x05C) +#define LPASS_CDC_RX2_VOL_CTL_B2_CTL (0x07C) +#define LPASS_CDC_RX3_VOL_CTL_B2_CTL (0x09C) +#define LPASS_CDC_TOP_GAIN_UPDATE (0x0A0) +#define LPASS_CDC_TOP_CTL (0x0A4) +#define TOP_CTL_DIG_MCLK_FREQ_MASK BIT(0) +#define TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ 0 +#define TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ BIT(0) + +#define LPASS_CDC_DEBUG_DESER1_CTL (0x0E0) +#define LPASS_CDC_DEBUG_DESER2_CTL (0x0E4) +#define LPASS_CDC_DEBUG_B1_CTL_CFG (0x0E8) +#define LPASS_CDC_DEBUG_B2_CTL_CFG (0x0EC) +#define LPASS_CDC_DEBUG_B3_CTL_CFG (0x0F0) +#define LPASS_CDC_IIR1_GAIN_B1_CTL (0x100) +#define LPASS_CDC_IIR2_GAIN_B1_CTL (0x140) +#define LPASS_CDC_IIR1_GAIN_B2_CTL (0x104) +#define LPASS_CDC_IIR2_GAIN_B2_CTL (0x144) +#define LPASS_CDC_IIR1_GAIN_B3_CTL (0x108) +#define LPASS_CDC_IIR2_GAIN_B3_CTL (0x148) +#define LPASS_CDC_IIR1_GAIN_B4_CTL (0x10C) +#define LPASS_CDC_IIR2_GAIN_B4_CTL (0x14C) +#define LPASS_CDC_IIR1_GAIN_B5_CTL (0x110) +#define LPASS_CDC_IIR2_GAIN_B5_CTL (0x150) +#define LPASS_CDC_IIR1_GAIN_B6_CTL (0x114) +#define LPASS_CDC_IIR2_GAIN_B6_CTL (0x154) +#define LPASS_CDC_IIR1_GAIN_B7_CTL (0x118) +#define LPASS_CDC_IIR2_GAIN_B7_CTL (0x158) +#define LPASS_CDC_IIR1_GAIN_B8_CTL (0x11C) +#define LPASS_CDC_IIR2_GAIN_B8_CTL (0x15C) +#define LPASS_CDC_IIR1_CTL (0x120) +#define LPASS_CDC_IIR2_CTL (0x160) +#define LPASS_CDC_IIR1_GAIN_TIMER_CTL (0x124) +#define LPASS_CDC_IIR2_GAIN_TIMER_CTL (0x164) +#define LPASS_CDC_IIR1_COEF_B1_CTL (0x128) +#define LPASS_CDC_IIR2_COEF_B1_CTL (0x168) +#define LPASS_CDC_IIR1_COEF_B2_CTL (0x12C) +#define LPASS_CDC_IIR2_COEF_B2_CTL (0x16C) +#define LPASS_CDC_CONN_RX1_B1_CTL (0x180) +#define LPASS_CDC_CONN_RX1_B2_CTL (0x184) +#define LPASS_CDC_CONN_RX1_B3_CTL (0x188) +#define LPASS_CDC_CONN_RX2_B1_CTL (0x18C) +#define LPASS_CDC_CONN_RX2_B2_CTL (0x190) +#define LPASS_CDC_CONN_RX2_B3_CTL (0x194) +#define LPASS_CDC_CONN_RX3_B1_CTL (0x198) +#define LPASS_CDC_CONN_RX3_B2_CTL (0x19C) +#define LPASS_CDC_CONN_TX_B1_CTL (0x1A0) +#define LPASS_CDC_CONN_EQ1_B1_CTL (0x1A8) +#define LPASS_CDC_CONN_EQ1_B2_CTL (0x1AC) +#define LPASS_CDC_CONN_EQ1_B3_CTL (0x1B0) +#define LPASS_CDC_CONN_EQ1_B4_CTL (0x1B4) +#define LPASS_CDC_CONN_EQ2_B1_CTL (0x1B8) +#define LPASS_CDC_CONN_EQ2_B2_CTL (0x1BC) +#define LPASS_CDC_CONN_EQ2_B3_CTL (0x1C0) +#define LPASS_CDC_CONN_EQ2_B4_CTL (0x1C4) +#define LPASS_CDC_CONN_TX_I2S_SD1_CTL (0x1C8) +#define LPASS_CDC_TX1_VOL_CTL_TIMER (0x280) +#define LPASS_CDC_TX2_VOL_CTL_TIMER (0x2A0) +#define LPASS_CDC_TX1_VOL_CTL_GAIN (0x284) +#define LPASS_CDC_TX2_VOL_CTL_GAIN (0x2A4) +#define LPASS_CDC_TX1_VOL_CTL_CFG (0x288) +#define TX_VOL_CTL_CFG_MUTE_EN_MASK BIT(0) +#define TX_VOL_CTL_CFG_MUTE_EN_ENABLE BIT(0) + +#define LPASS_CDC_TX2_VOL_CTL_CFG (0x2A8) +#define LPASS_CDC_TX1_MUX_CTL (0x28C) +#define TX_MUX_CTL_CUT_OFF_FREQ_MASK GENMASK(5, 4) +#define TX_MUX_CTL_CUT_OFF_FREQ_SHIFT 4 +#define TX_MUX_CTL_CF_NEG_3DB_4HZ (0x0 << 4) +#define TX_MUX_CTL_CF_NEG_3DB_75HZ (0x1 << 4) +#define TX_MUX_CTL_CF_NEG_3DB_150HZ (0x2 << 4) +#define TX_MUX_CTL_HPF_BP_SEL_MASK BIT(3) +#define TX_MUX_CTL_HPF_BP_SEL_BYPASS BIT(3) +#define TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS 0 + +#define LPASS_CDC_TX2_MUX_CTL (0x2AC) +#define LPASS_CDC_TX1_CLK_FS_CTL (0x290) +#define LPASS_CDC_TX2_CLK_FS_CTL (0x2B0) +#define LPASS_CDC_TX1_DMIC_CTL (0x294) +#define LPASS_CDC_TX2_DMIC_CTL (0x2B4) +#define TXN_DMIC_CTL_CLK_SEL_MASK GENMASK(2, 0) +#define TXN_DMIC_CTL_CLK_SEL_DIV2 0x0 +#define TXN_DMIC_CTL_CLK_SEL_DIV3 0x1 +#define TXN_DMIC_CTL_CLK_SEL_DIV4 0x2 +#define TXN_DMIC_CTL_CLK_SEL_DIV6 0x3 +#define TXN_DMIC_CTL_CLK_SEL_DIV16 0x4 + +#define MSM8916_WCD_DIGITAL_RATES (SNDRV_PCM_RATE_8000 | \ + SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_48000) +#define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +struct msm8916_wcd_digital_priv { + struct clk *ahbclk, *mclk; +}; + +static const unsigned long rx_gain_reg[] = { + LPASS_CDC_RX1_VOL_CTL_B2_CTL, + LPASS_CDC_RX2_VOL_CTL_B2_CTL, + LPASS_CDC_RX3_VOL_CTL_B2_CTL, +}; + +static const unsigned long tx_gain_reg[] = { + LPASS_CDC_TX1_VOL_CTL_GAIN, + LPASS_CDC_TX2_VOL_CTL_GAIN, +}; + +static const char *const rx_mix1_text[] = { + "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3" +}; + +static const char *const dec_mux_text[] = { + "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2" +}; +static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" }; +static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; + +/* RX1 MIX1 */ +static const struct soc_enum rx_mix1_inp_enum[] = { + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text), +}; + +/* RX1 MIX2 */ +static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( + LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text); + +/* RX2 MIX1 */ +static const struct soc_enum rx2_mix1_inp_enum[] = { + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), +}; + +/* RX2 MIX2 */ +static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( + LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text); + +/* RX3 MIX1 */ +static const struct soc_enum rx3_mix1_inp_enum[] = { + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), +}; + +/* DEC */ +static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE( + LPASS_CDC_CONN_TX_B1_CTL, 0, 6, dec_mux_text); +static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE( + LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text); + +/* RDAC2 MUX */ +static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM( + "DEC1 MUX Mux", dec1_mux_enum); +static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM( + "DEC2 MUX Mux", dec2_mux_enum); +static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM( + "RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]); +static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM( + "RX1 MIX1 INP2 Mux", rx_mix1_inp_enum[1]); +static const struct snd_kcontrol_new rx_mix1_inp3_mux = SOC_DAPM_ENUM( + "RX1 MIX1 INP3 Mux", rx_mix1_inp_enum[2]); +static const struct snd_kcontrol_new rx2_mix1_inp1_mux = SOC_DAPM_ENUM( + "RX2 MIX1 INP1 Mux", rx2_mix1_inp_enum[0]); +static const struct snd_kcontrol_new rx2_mix1_inp2_mux = SOC_DAPM_ENUM( + "RX2 MIX1 INP2 Mux", rx2_mix1_inp_enum[1]); +static const struct snd_kcontrol_new rx2_mix1_inp3_mux = SOC_DAPM_ENUM( + "RX2 MIX1 INP3 Mux", rx2_mix1_inp_enum[2]); +static const struct snd_kcontrol_new rx3_mix1_inp1_mux = SOC_DAPM_ENUM( + "RX3 MIX1 INP1 Mux", rx3_mix1_inp_enum[0]); +static const struct snd_kcontrol_new rx3_mix1_inp2_mux = SOC_DAPM_ENUM( + "RX3 MIX1 INP2 Mux", rx3_mix1_inp_enum[1]); +static const struct snd_kcontrol_new rx3_mix1_inp3_mux = SOC_DAPM_ENUM( + "RX3 MIX1 INP3 Mux", rx3_mix1_inp_enum[2]); + +/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */ +static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0); + +/* Cutoff Freq for High Pass Filter at -3dB */ +static const char * const hpf_cutoff_text[] = { + "4Hz", "75Hz", "150Hz", +}; + +static SOC_ENUM_SINGLE_DECL(tx1_hpf_cutoff_enum, LPASS_CDC_TX1_MUX_CTL, 4, + hpf_cutoff_text); +static SOC_ENUM_SINGLE_DECL(tx2_hpf_cutoff_enum, LPASS_CDC_TX2_MUX_CTL, 4, + hpf_cutoff_text); + +/* cut off for dc blocker inside rx chain */ +static const char * const dc_blocker_cutoff_text[] = { + "4Hz", "75Hz", "150Hz", +}; + +static SOC_ENUM_SINGLE_DECL(rx1_dcb_cutoff_enum, LPASS_CDC_RX1_B4_CTL, 0, + dc_blocker_cutoff_text); +static SOC_ENUM_SINGLE_DECL(rx2_dcb_cutoff_enum, LPASS_CDC_RX2_B4_CTL, 0, + dc_blocker_cutoff_text); +static SOC_ENUM_SINGLE_DECL(rx3_dcb_cutoff_enum, LPASS_CDC_RX3_B4_CTL, 0, + dc_blocker_cutoff_text); + +static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { + SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL, + -128, 127, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL, + -128, 127, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL, + -128, 127, digital_gain), + SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN, + -128, 127, digital_gain), + SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN, + -128, 127, digital_gain), + SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum), + SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum), + SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0), + SOC_SINGLE("TX2 HPF Switch", LPASS_CDC_TX2_MUX_CTL, 3, 1, 0), + SOC_ENUM("RX1 DCB Cutoff", rx1_dcb_cutoff_enum), + SOC_ENUM("RX2 DCB Cutoff", rx2_dcb_cutoff_enum), + SOC_ENUM("RX3 DCB Cutoff", rx3_dcb_cutoff_enum), + SOC_SINGLE("RX1 DCB Switch", LPASS_CDC_RX1_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX2 DCB Switch", LPASS_CDC_RX2_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX3 DCB Switch", LPASS_CDC_RX3_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX1 Mute Switch", LPASS_CDC_RX1_B6_CTL, 0, 1, 0), + SOC_SINGLE("RX2 Mute Switch", LPASS_CDC_RX2_B6_CTL, 0, 1, 0), + SOC_SINGLE("RX3 Mute Switch", LPASS_CDC_RX3_B6_CTL, 0, 1, 0), +}; + +static int msm8916_wcd_digital_enable_interpolator( + struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* apply the digital gain after the interpolator is enabled */ + usleep_range(10000, 10100); + snd_soc_write(codec, rx_gain_reg[w->shift], + snd_soc_read(codec, rx_gain_reg[w->shift])); + break; + } + return 0; +} + +static int msm8916_wcd_digital_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + unsigned int decimator = w->shift + 1; + u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg; + u8 dec_hpf_cut_of_freq; + + dec_reset_reg = LPASS_CDC_CLK_TX_RESET_B1_CTL; + tx_vol_ctl_reg = LPASS_CDC_TX1_VOL_CTL_CFG + 32 * (decimator - 1); + tx_mux_ctl_reg = LPASS_CDC_TX1_MUX_CTL + 32 * (decimator - 1); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable TX digital mute */ + snd_soc_update_bits(codec, tx_vol_ctl_reg, + TX_VOL_CTL_CFG_MUTE_EN_MASK, + TX_VOL_CTL_CFG_MUTE_EN_ENABLE); + dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg) & + TX_MUX_CTL_CUT_OFF_FREQ_MASK; + dec_hpf_cut_of_freq >>= TX_MUX_CTL_CUT_OFF_FREQ_SHIFT; + if (dec_hpf_cut_of_freq != TX_MUX_CTL_CF_NEG_3DB_150HZ) { + /* set cut of freq to CF_MIN_3DB_150HZ (0x1) */ + snd_soc_update_bits(codec, tx_mux_ctl_reg, + TX_MUX_CTL_CUT_OFF_FREQ_MASK, + TX_MUX_CTL_CF_NEG_3DB_150HZ); + } + break; + case SND_SOC_DAPM_POST_PMU: + /* enable HPF */ + snd_soc_update_bits(codec, tx_mux_ctl_reg, + TX_MUX_CTL_HPF_BP_SEL_MASK, + TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS); + /* apply the digital gain after the decimator is enabled */ + snd_soc_write(codec, tx_gain_reg[w->shift], + snd_soc_read(codec, tx_gain_reg[w->shift])); + snd_soc_update_bits(codec, tx_vol_ctl_reg, + TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, tx_vol_ctl_reg, + TX_VOL_CTL_CFG_MUTE_EN_MASK, + TX_VOL_CTL_CFG_MUTE_EN_ENABLE); + snd_soc_update_bits(codec, tx_mux_ctl_reg, + TX_MUX_CTL_HPF_BP_SEL_MASK, + TX_MUX_CTL_HPF_BP_SEL_BYPASS); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, + 1 << w->shift); + snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0); + snd_soc_update_bits(codec, tx_mux_ctl_reg, + TX_MUX_CTL_HPF_BP_SEL_MASK, + TX_MUX_CTL_HPF_BP_SEL_BYPASS); + snd_soc_update_bits(codec, tx_vol_ctl_reg, + TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); + break; + } + + return 0; +} + +static int msm8916_wcd_digital_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + unsigned int dmic; + int ret; + /* get dmic number out of widget name */ + char *dmic_num = strpbrk(w->name, "12"); + + if (dmic_num == NULL) { + dev_err(codec->dev, "Invalid DMIC\n"); + return -EINVAL; + } + ret = kstrtouint(dmic_num, 10, &dmic); + if (ret < 0 || dmic > 2) { + dev_err(codec->dev, "Invalid DMIC line on the codec\n"); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, LPASS_CDC_CLK_DMIC_B1_CTL, + DMIC_B1_CTL_DMIC0_CLK_SEL_MASK, + DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3); + switch (dmic) { + case 1: + snd_soc_update_bits(codec, LPASS_CDC_TX1_DMIC_CTL, + TXN_DMIC_CTL_CLK_SEL_MASK, + TXN_DMIC_CTL_CLK_SEL_DIV3); + break; + case 2: + snd_soc_update_bits(codec, LPASS_CDC_TX2_DMIC_CTL, + TXN_DMIC_CTL_CLK_SEL_MASK, + TXN_DMIC_CTL_CLK_SEL_DIV3); + break; + } + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = { + /*RX stuff */ + SND_SOC_DAPM_AIF_IN("I2S RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("I2S RX2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("I2S RX3", NULL, 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("PDM_RX1"), + SND_SOC_DAPM_OUTPUT("PDM_RX2"), + SND_SOC_DAPM_OUTPUT("PDM_RX3"), + + SND_SOC_DAPM_INPUT("LPASS_PDM_TX"), + + SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Interpolator */ + SND_SOC_DAPM_MIXER_E("RX1 INT", LPASS_CDC_CLK_RX_B1_CTL, 0, 0, NULL, + 0, msm8916_wcd_digital_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX2 INT", LPASS_CDC_CLK_RX_B1_CTL, 1, 0, NULL, + 0, msm8916_wcd_digital_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX3 INT", LPASS_CDC_CLK_RX_B1_CTL, 2, 0, NULL, + 0, msm8916_wcd_digital_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_mix1_inp1_mux), + SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_mix1_inp2_mux), + SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0, + &rx_mix1_inp3_mux), + SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx2_mix1_inp1_mux), + SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx2_mix1_inp2_mux), + SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0, + &rx2_mix1_inp3_mux), + SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx3_mix1_inp1_mux), + SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx3_mix1_inp2_mux), + SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0, + &rx3_mix1_inp3_mux), + + /* TX */ + SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("DEC1 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0, + &dec1_mux, msm8916_wcd_digital_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("DEC2 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0, + &dec2_mux, msm8916_wcd_digital_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT("I2S TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("I2S TX2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("I2S TX3", NULL, 0, SND_SOC_NOPM, 0, 0), + + /* Digital Mic Inputs */ + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + msm8916_wcd_digital_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, + msm8916_wcd_digital_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("DMIC_CLK", LPASS_CDC_CLK_DMIC_B1_CTL, 0, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", LPASS_CDC_CLK_RX_I2S_CTL, + 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", LPASS_CDC_CLK_TX_I2S_CTL, 4, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PDM_CLK", LPASS_CDC_CLK_PDM_CTL, 0, 0, NULL, 0), + /* Connectivity Clock */ + SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0, + NULL, 0), + +}; + +static int msm8916_wcd_digital_get_clks(struct platform_device *pdev, + struct msm8916_wcd_digital_priv *priv) +{ + struct device *dev = &pdev->dev; + + priv->ahbclk = devm_clk_get(dev, "ahbix-clk"); + if (IS_ERR(priv->ahbclk)) { + dev_err(dev, "failed to get ahbix clk\n"); + return PTR_ERR(priv->ahbclk); + } + + priv->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(priv->mclk)) { + dev_err(dev, "failed to get mclk\n"); + return PTR_ERR(priv->mclk); + } + + return 0; +} + +static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec) +{ + struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(codec->dev); + + snd_soc_codec_set_drvdata(codec, priv); + + return 0; +} + +static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + u8 tx_fs_rate; + u8 rx_fs_rate; + + switch (params_rate(params)) { + case 8000: + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ; + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ; + break; + case 16000: + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ; + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ; + break; + case 32000: + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ; + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ; + break; + case 48000: + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ; + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ; + break; + default: + dev_err(dai->codec->dev, "Invalid sampling rate %d\n", + params_rate(params)); + return -EINVAL; + } + + switch (substream->stream) { + case SNDRV_PCM_STREAM_CAPTURE: + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, + TX_I2S_CTL_TX_I2S_FS_RATE_MASK, tx_fs_rate); + break; + case SNDRV_PCM_STREAM_PLAYBACK: + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, + RX_I2S_CTL_RX_I2S_FS_RATE_MASK, rx_fs_rate); + break; + default: + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, + TX_I2S_CTL_TX_I2S_MODE_MASK, + TX_I2S_CTL_TX_I2S_MODE_16); + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, + RX_I2S_CTL_RX_I2S_MODE_MASK, + RX_I2S_CTL_RX_I2S_MODE_16); + break; + case SNDRV_PCM_FORMAT_S24_LE: + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, + TX_I2S_CTL_TX_I2S_MODE_MASK, + TX_I2S_CTL_TX_I2S_MODE_32); + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, + RX_I2S_CTL_RX_I2S_MODE_MASK, + RX_I2S_CTL_RX_I2S_MODE_32); + break; + default: + dev_err(dai->dev, "%s: wrong format selected\n", __func__); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = { + + {"I2S RX1", NULL, "AIF1 Playback"}, + {"I2S RX2", NULL, "AIF1 Playback"}, + {"I2S RX3", NULL, "AIF1 Playback"}, + + {"AIF1 Capture", NULL, "I2S TX1"}, + {"AIF1 Capture", NULL, "I2S TX2"}, + {"AIF1 Capture", NULL, "I2S TX3"}, + + /* Decimator Inputs */ + {"DEC1 MUX", "DMIC1", "DMIC1"}, + {"DEC1 MUX", "DMIC2", "DMIC2"}, + {"DEC1 MUX", "ADC1", "ADC1"}, + {"DEC1 MUX", "ADC2", "ADC2"}, + {"DEC1 MUX", "ADC3", "ADC3"}, + {"DEC1 MUX", NULL, "CDC_CONN"}, + + {"DEC2 MUX", "DMIC1", "DMIC1"}, + {"DEC2 MUX", "DMIC2", "DMIC2"}, + {"DEC2 MUX", "ADC1", "ADC1"}, + {"DEC2 MUX", "ADC2", "ADC2"}, + {"DEC2 MUX", "ADC3", "ADC3"}, + {"DEC2 MUX", NULL, "CDC_CONN"}, + + {"DMIC1", NULL, "DMIC_CLK"}, + {"DMIC2", NULL, "DMIC_CLK"}, + + {"I2S TX1", NULL, "DEC1 MUX"}, + {"I2S TX2", NULL, "DEC2 MUX"}, + + {"I2S TX1", NULL, "TX_I2S_CLK"}, + {"I2S TX2", NULL, "TX_I2S_CLK"}, + + {"TX_I2S_CLK", NULL, "MCLK"}, + {"TX_I2S_CLK", NULL, "PDM_CLK"}, + + {"ADC1", NULL, "LPASS_PDM_TX"}, + {"ADC2", NULL, "LPASS_PDM_TX"}, + {"ADC3", NULL, "LPASS_PDM_TX"}, + + {"I2S RX1", NULL, "RX_I2S_CLK"}, + {"I2S RX2", NULL, "RX_I2S_CLK"}, + {"I2S RX3", NULL, "RX_I2S_CLK"}, + + {"RX_I2S_CLK", NULL, "PDM_CLK"}, + {"RX_I2S_CLK", NULL, "MCLK"}, + {"RX_I2S_CLK", NULL, "CDC_CONN"}, + + /* RX1 PATH.. */ + {"PDM_RX1", NULL, "RX1 INT"}, + {"RX1 INT", NULL, "RX1 MIX1"}, + + {"RX1 MIX1", NULL, "RX1 MIX1 INP1"}, + {"RX1 MIX1", NULL, "RX1 MIX1 INP2"}, + {"RX1 MIX1", NULL, "RX1 MIX1 INP3"}, + + {"RX1 MIX1 INP1", "RX1", "I2S RX1"}, + {"RX1 MIX1 INP1", "RX2", "I2S RX2"}, + {"RX1 MIX1 INP1", "RX3", "I2S RX3"}, + + {"RX1 MIX1 INP2", "RX1", "I2S RX1"}, + {"RX1 MIX1 INP2", "RX2", "I2S RX2"}, + {"RX1 MIX1 INP2", "RX3", "I2S RX3"}, + + {"RX1 MIX1 INP3", "RX1", "I2S RX1"}, + {"RX1 MIX1 INP3", "RX2", "I2S RX2"}, + {"RX1 MIX1 INP3", "RX3", "I2S RX3"}, + + /* RX2 PATH */ + {"PDM_RX2", NULL, "RX2 INT"}, + {"RX2 INT", NULL, "RX2 MIX1"}, + + {"RX2 MIX1", NULL, "RX2 MIX1 INP1"}, + {"RX2 MIX1", NULL, "RX2 MIX1 INP2"}, + {"RX2 MIX1", NULL, "RX2 MIX1 INP3"}, + + {"RX2 MIX1 INP1", "RX1", "I2S RX1"}, + {"RX2 MIX1 INP1", "RX2", "I2S RX2"}, + {"RX2 MIX1 INP1", "RX3", "I2S RX3"}, + + {"RX2 MIX1 INP2", "RX1", "I2S RX1"}, + {"RX2 MIX1 INP2", "RX2", "I2S RX2"}, + {"RX2 MIX1 INP2", "RX3", "I2S RX3"}, + + {"RX2 MIX1 INP3", "RX1", "I2S RX1"}, + {"RX2 MIX1 INP3", "RX2", "I2S RX2"}, + {"RX2 MIX1 INP3", "RX3", "I2S RX3"}, + + /* RX3 PATH */ + {"PDM_RX3", NULL, "RX3 INT"}, + {"RX3 INT", NULL, "RX3 MIX1"}, + + {"RX3 MIX1", NULL, "RX3 MIX1 INP1"}, + {"RX3 MIX1", NULL, "RX3 MIX1 INP2"}, + {"RX3 MIX1", NULL, "RX3 MIX1 INP3"}, + + {"RX3 MIX1 INP1", "RX1", "I2S RX1"}, + {"RX3 MIX1 INP1", "RX2", "I2S RX2"}, + {"RX3 MIX1 INP1", "RX3", "I2S RX3"}, + + {"RX3 MIX1 INP2", "RX1", "I2S RX1"}, + {"RX3 MIX1 INP2", "RX2", "I2S RX2"}, + {"RX3 MIX1 INP2", "RX3", "I2S RX3"}, + + {"RX3 MIX1 INP3", "RX1", "I2S RX1"}, + {"RX3 MIX1 INP3", "RX2", "I2S RX2"}, + {"RX3 MIX1 INP3", "RX3", "I2S RX3"}, + +}; + +static int msm8916_wcd_digital_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct msm8916_wcd_digital_priv *msm8916_wcd; + unsigned long mclk_rate; + + msm8916_wcd = snd_soc_codec_get_drvdata(codec); + snd_soc_update_bits(codec, LPASS_CDC_CLK_MCLK_CTL, + MCLK_CTL_MCLK_EN_MASK, + MCLK_CTL_MCLK_EN_ENABLE); + snd_soc_update_bits(codec, LPASS_CDC_CLK_PDM_CTL, + LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, + LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB); + + mclk_rate = clk_get_rate(msm8916_wcd->mclk); + switch (mclk_rate) { + case 12288000: + snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, + TOP_CTL_DIG_MCLK_FREQ_MASK, + TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ); + break; + case 9600000: + snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, + TOP_CTL_DIG_MCLK_FREQ_MASK, + TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ); + break; + default: + dev_err(codec->dev, "Invalid mclk rate %ld\n", mclk_rate); + break; + } + return 0; +} + +static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_PDM_CTL, + LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0); +} + +static struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = { + .startup = msm8916_wcd_digital_startup, + .shutdown = msm8916_wcd_digital_shutdown, + .hw_params = msm8916_wcd_digital_hw_params, +}; + +static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = { + [0] = { + .name = "msm8916_wcd_digital_i2s_rx1", + .id = 0, + .playback = { + .stream_name = "AIF1 Playback", + .rates = MSM8916_WCD_DIGITAL_RATES, + .formats = MSM8916_WCD_DIGITAL_FORMATS, + .channels_min = 1, + .channels_max = 3, + }, + .ops = &msm8916_wcd_digital_dai_ops, + }, + [1] = { + .name = "msm8916_wcd_digital_i2s_tx1", + .id = 1, + .capture = { + .stream_name = "AIF1 Capture", + .rates = MSM8916_WCD_DIGITAL_RATES, + .formats = MSM8916_WCD_DIGITAL_FORMATS, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &msm8916_wcd_digital_dai_ops, + }, +}; + +static struct snd_soc_codec_driver msm8916_wcd_digital = { + .probe = msm8916_wcd_digital_codec_probe, + .component_driver = { + .controls = msm8916_wcd_digital_snd_controls, + .num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls), + .dapm_widgets = msm8916_wcd_digital_dapm_widgets, + .num_dapm_widgets = + ARRAY_SIZE(msm8916_wcd_digital_dapm_widgets), + .dapm_routes = msm8916_wcd_digital_audio_map, + .num_dapm_routes = ARRAY_SIZE(msm8916_wcd_digital_audio_map), + }, +}; + +static const struct regmap_config msm8916_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = LPASS_CDC_TX2_DMIC_CTL, + .cache_type = REGCACHE_FLAT, +}; + +static int msm8916_wcd_digital_probe(struct platform_device *pdev) +{ + struct msm8916_wcd_digital_priv *priv; + struct device *dev = &pdev->dev; + void __iomem *base; + struct resource *mem_res; + struct regmap *digital_map; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, mem_res); + if (IS_ERR(base)) + return PTR_ERR(base); + + digital_map = + devm_regmap_init_mmio(&pdev->dev, base, + &msm8916_codec_regmap_config); + if (IS_ERR(digital_map)) + return PTR_ERR(digital_map); + + ret = msm8916_wcd_digital_get_clks(pdev, priv); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(priv->ahbclk); + if (ret < 0) { + dev_err(dev, "failed to enable ahbclk %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(priv->mclk); + if (ret < 0) { + dev_err(dev, "failed to enable mclk %d\n", ret); + return ret; + } + + dev_set_drvdata(dev, priv); + + return snd_soc_register_codec(dev, &msm8916_wcd_digital, + msm8916_wcd_digital_dai, + ARRAY_SIZE(msm8916_wcd_digital_dai)); +} + +static int msm8916_wcd_digital_remove(struct platform_device *pdev) +{ + struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_codec(&pdev->dev); + clk_disable_unprepare(priv->mclk); + clk_disable_unprepare(priv->ahbclk); + + return 0; +} + +static const struct of_device_id msm8916_wcd_digital_match_table[] = { + { .compatible = "qcom,msm8916-wcd-digital-codec" }, + { } +}; + +MODULE_DEVICE_TABLE(of, msm8916_wcd_digital_match_table); + +static struct platform_driver msm8916_wcd_digital_driver = { + .driver = { + .name = "msm8916-wcd-digital-codec", + .of_match_table = msm8916_wcd_digital_match_table, + }, + .probe = msm8916_wcd_digital_probe, + .remove = msm8916_wcd_digital_remove, +}; + +module_platform_driver(msm8916_wcd_digital_driver); + +MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>"); +MODULE_DESCRIPTION("MSM8916 WCD Digital Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index e643be91d762..efe3a44658d5 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -43,6 +43,8 @@ #define GAIN_AUGMENT 22500 #define SIDETONE_BASE 207000 +/* the maximum frequency of CLK_ADC and CLK_DAC */ +#define CLK_DA_AD_MAX 6144000 static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, unsigned int freq); @@ -95,6 +97,27 @@ static const struct nau8825_fll_attr fll_pre_scalar[] = { { 8, 0x3 }, }; +/* over sampling rate */ +struct nau8825_osr_attr { + unsigned int osr; + unsigned int clk_src; +}; + +static const struct nau8825_osr_attr osr_dac_sel[] = { + { 64, 2 }, /* OSR 64, SRC 1/4 */ + { 256, 0 }, /* OSR 256, SRC 1 */ + { 128, 1 }, /* OSR 128, SRC 1/2 */ + { 0, 0 }, + { 32, 3 }, /* OSR 32, SRC 1/8 */ +}; + +static const struct nau8825_osr_attr osr_adc_sel[] = { + { 32, 3 }, /* OSR 32, SRC 1/8 */ + { 64, 2 }, /* OSR 64, SRC 1/4 */ + { 128, 1 }, /* OSR 128, SRC 1/2 */ + { 256, 0 }, /* OSR 256, SRC 1 */ +}; + static const struct reg_default nau8825_reg_defaults[] = { { NAU8825_REG_ENA_CTRL, 0x00ff }, { NAU8825_REG_IIC_ADDR_SET, 0x0 }, @@ -1179,15 +1202,64 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = { {"HPOR", NULL, "Class G"}, }; +static int nau8825_clock_check(struct nau8825 *nau8825, + int stream, int rate, int osr) +{ + int osrate; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (osr >= ARRAY_SIZE(osr_dac_sel)) + return -EINVAL; + osrate = osr_dac_sel[osr].osr; + } else { + if (osr >= ARRAY_SIZE(osr_adc_sel)) + return -EINVAL; + osrate = osr_adc_sel[osr].osr; + } + + if (!osrate || rate * osr > CLK_DA_AD_MAX) { + dev_err(nau8825->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n"); + return -EINVAL; + } + + return 0; +} + static int nau8825_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); - unsigned int val_len = 0; + unsigned int val_len = 0, osr; + + nau8825_sema_acquire(nau8825, 3 * HZ); - nau8825_sema_acquire(nau8825, 2 * HZ); + /* CLK_DAC or CLK_ADC = OSR * FS + * DAC or ADC clock frequency is defined as Over Sampling Rate (OSR) + * multiplied by the audio sample rate (Fs). Note that the OSR and Fs + * values must be selected such that the maximum frequency is less + * than 6.144 MHz. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr); + osr &= NAU8825_DAC_OVERSAMPLE_MASK; + if (nau8825_clock_check(nau8825, substream->stream, + params_rate(params), osr)) + return -EINVAL; + regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, + NAU8825_CLK_DAC_SRC_MASK, + osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT); + } else { + regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr); + osr &= NAU8825_ADC_SYNC_DOWN_MASK; + if (nau8825_clock_check(nau8825, substream->stream, + params_rate(params), osr)) + return -EINVAL; + regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, + NAU8825_CLK_ADC_SRC_MASK, + osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT); + } switch (params_width(params)) { case 16: @@ -1221,7 +1293,7 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); unsigned int ctrl1_val = 0, ctrl2_val = 0; - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: @@ -1774,9 +1846,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825) * (audible hiss). Set it to something better. */ regmap_update_bits(regmap, NAU8825_REG_ADC_RATE, - NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128); + NAU8825_ADC_SYNC_DOWN_MASK | NAU8825_ADC_SINC4_EN, + NAU8825_ADC_SYNC_DOWN_64); regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1, - NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128); + NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_64); /* Disable DACR/L power */ regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP, NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, @@ -1811,6 +1884,9 @@ static void nau8825_init_regs(struct nau8825 *nau8825) NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_L); regmap_update_bits(nau8825->regmap, NAU8825_REG_DACR_CTRL, NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_R); + /* Disable short Frame Sync detection logic */ + regmap_update_bits(regmap, NAU8825_REG_LEFT_TIME_SLOT, + NAU8825_DIS_FS_SHORT_DET, NAU8825_DIS_FS_SHORT_DET); } static const struct regmap_config nau8825_regmap_config = { @@ -1919,8 +1995,10 @@ static void nau8825_fll_apply(struct nau8825 *nau8825, regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_SRC_MASK | NAU8825_CLK_MCLK_SRC_MASK, NAU8825_CLK_SRC_MCLK | fll_param->mclk_src); + /* Make DSP operate at high speed for better performance. */ regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1, - NAU8825_FLL_RATIO_MASK, fll_param->ratio); + NAU8825_FLL_RATIO_MASK | NAU8825_ICTRL_LATCH_MASK, + fll_param->ratio | (0x6 << NAU8825_ICTRL_LATCH_SFT)); /* FLL 16-bit fractional input */ regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac); /* FLL 10-bit integer input */ @@ -1936,19 +2014,22 @@ static void nau8825_fll_apply(struct nau8825 *nau8825, regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN, 0); if (fll_param->fll_frac) { + /* set FLL loop filter enable and cutoff frequency at 500Khz */ regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN | NAU8825_FLL_FTR_SW_MASK, NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN | NAU8825_FLL_FTR_SW_FILTER); regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, - NAU8825_SDM_EN, NAU8825_SDM_EN); + NAU8825_SDM_EN | NAU8825_CUTOFF500, + NAU8825_SDM_EN | NAU8825_CUTOFF500); } else { + /* disable FLL loop filter and cutoff frequency */ regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN | NAU8825_FLL_FTR_SW_MASK, NAU8825_FLL_FTR_SW_ACCU); - regmap_update_bits(nau8825->regmap, - NAU8825_REG_FLL6, NAU8825_SDM_EN, 0); + regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, + NAU8825_SDM_EN | NAU8825_CUTOFF500, 0); } } @@ -2014,6 +2095,9 @@ static void nau8825_configure_mclk_as_sysclk(struct regmap *regmap) NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_MCLK); regmap_update_bits(regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN, 0); + /* Make DSP operate as default setting for power saving. */ + regmap_update_bits(regmap, NAU8825_REG_FLL1, + NAU8825_ICTRL_LATCH_MASK, 0); } static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, @@ -2038,7 +2122,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. */ - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); nau8825_configure_mclk_as_sysclk(regmap); /* MCLK not changed by clock tree */ regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, @@ -2057,10 +2141,13 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, NAU8825_DCO_EN, NAU8825_DCO_EN); regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO); - /* Decrease the VCO frequency for power saving */ + /* Decrease the VCO frequency and make DSP operate + * as default setting for power saving. + */ regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_MCLK_SRC_MASK, 0xf); regmap_update_bits(regmap, NAU8825_REG_FLL1, + NAU8825_ICTRL_LATCH_MASK | NAU8825_FLL_RATIO_MASK, 0x10); regmap_update_bits(regmap, NAU8825_REG_FLL6, NAU8825_SDM_EN, NAU8825_SDM_EN); @@ -2083,9 +2170,14 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. */ - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); + /* Higher FLL reference input frequency can only set lower + * gain error, such as 0000 for input reference from MCLK + * 12.288Mhz. + */ regmap_update_bits(regmap, NAU8825_REG_FLL3, - NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_MCLK); + NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, + NAU8825_FLL_CLK_SRC_MCLK | 0); /* Release the semaphone. */ nau8825_sema_release(nau8825); @@ -2100,9 +2192,17 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. */ - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); + /* If FLL reference input is from low frequency source, + * higher error gain can apply such as 0xf which has + * the most sensitive gain error correction threshold, + * Therefore, FLL has the most accurate DCO to + * target frequency. + */ regmap_update_bits(regmap, NAU8825_REG_FLL3, - NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_BLK); + NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, + NAU8825_FLL_CLK_SRC_BLK | + (0xf << NAU8825_GAIN_ERR_SFT)); /* Release the semaphone. */ nau8825_sema_release(nau8825); @@ -2118,9 +2218,17 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. */ - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); + /* If FLL reference input is from low frequency source, + * higher error gain can apply such as 0xf which has + * the most sensitive gain error correction threshold, + * Therefore, FLL has the most accurate DCO to + * target frequency. + */ regmap_update_bits(regmap, NAU8825_REG_FLL3, - NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_FS); + NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, + NAU8825_FLL_CLK_SRC_FS | + (0xf << NAU8825_GAIN_ERR_SFT)); /* Release the semaphone. */ nau8825_sema_release(nau8825); diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 1c63e2abafa9..5d1704e73241 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -115,12 +115,20 @@ #define NAU8825_CLK_SRC_MASK (1 << NAU8825_CLK_SRC_SFT) #define NAU8825_CLK_SRC_VCO (1 << NAU8825_CLK_SRC_SFT) #define NAU8825_CLK_SRC_MCLK (0 << NAU8825_CLK_SRC_SFT) +#define NAU8825_CLK_ADC_SRC_SFT 6 +#define NAU8825_CLK_ADC_SRC_MASK (0x3 << NAU8825_CLK_ADC_SRC_SFT) +#define NAU8825_CLK_DAC_SRC_SFT 4 +#define NAU8825_CLK_DAC_SRC_MASK (0x3 << NAU8825_CLK_DAC_SRC_SFT) #define NAU8825_CLK_MCLK_SRC_MASK (0xf << 0) /* FLL1 (0x04) */ +#define NAU8825_ICTRL_LATCH_SFT 10 +#define NAU8825_ICTRL_LATCH_MASK (0x7 << NAU8825_ICTRL_LATCH_SFT) #define NAU8825_FLL_RATIO_MASK (0x7f << 0) /* FLL3 (0x06) */ +#define NAU8825_GAIN_ERR_SFT 12 +#define NAU8825_GAIN_ERR_MASK (0xf << NAU8825_GAIN_ERR_SFT) #define NAU8825_FLL_INTEGER_MASK (0x3ff << 0) #define NAU8825_FLL_CLK_SRC_SFT 10 #define NAU8825_FLL_CLK_SRC_MASK (0x3 << NAU8825_FLL_CLK_SRC_SFT) @@ -144,6 +152,7 @@ /* FLL6 (0x9) */ #define NAU8825_DCO_EN (0x1 << 15) #define NAU8825_SDM_EN (0x1 << 14) +#define NAU8825_CUTOFF500 (0x1 << 13) /* HSD_CTRL (0xc) */ #define NAU8825_HSD_AUTO_MODE (1 << 6) @@ -246,6 +255,11 @@ #define NAU8825_I2S_MS_SLAVE (0 << NAU8825_I2S_MS_SFT) #define NAU8825_I2S_BLK_DIV_MASK 0x7 +/* LEFT_TIME_SLOT (0x1e) */ +#define NAU8825_FS_ERR_CMP_SEL_SFT 14 +#define NAU8825_FS_ERR_CMP_SEL_MASK (0x3 << NAU8825_FS_ERR_CMP_SEL_SFT) +#define NAU8825_DIS_FS_SHORT_DET (1 << 13) + /* BIQ_CTRL (0x20) */ #define NAU8825_BIQ_WRT_SFT 4 #define NAU8825_BIQ_WRT_EN (1 << NAU8825_BIQ_WRT_SFT) @@ -255,6 +269,8 @@ #define NAU8825_BIQ_PATH_DAC (1 << NAU8825_BIQ_PATH_SFT) /* ADC_RATE (0x2b) */ +#define NAU8825_ADC_SINC4_SFT 4 +#define NAU8825_ADC_SINC4_EN (1 << NAU8825_ADC_SINC4_SFT) #define NAU8825_ADC_SYNC_DOWN_SFT 0 #define NAU8825_ADC_SYNC_DOWN_MASK 0x3 #define NAU8825_ADC_SYNC_DOWN_32 0 diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 1dc68ab08a17..7b447d0b173a 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -102,6 +102,7 @@ struct pll_calc_map { }; static const struct pll_calc_map pll_preset_table[] = { + {19200000, 4096000, 23, 14, 1, false}, {19200000, 24576000, 3, 30, 3, false}, }; diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c index a4b910efbd45..8f571cf8edd4 100644 --- a/sound/soc/codecs/rl6347a.c +++ b/sound/soc/codecs/rl6347a.c @@ -51,7 +51,7 @@ int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value) if (ret == 4) return 0; else - pr_err("ret=%d\n", ret); + dev_err(&client->dev, "I2C error %d\n", ret); if (ret < 0) return ret; else diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 55558643166f..7150a407ffd9 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -249,6 +249,11 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic) snd_soc_dapm_force_enable_pin(dapm, "LDO1"); snd_soc_dapm_sync(dapm); + regmap_update_bits(rt298->regmap, + RT298_POWER_CTRL1, 0x1001, 0); + regmap_update_bits(rt298->regmap, + RT298_POWER_CTRL2, 0x4, 0x4); + regmap_write(rt298->regmap, RT298_SET_MIC1, 0x24); msleep(50); @@ -321,11 +326,31 @@ static void rt298_jack_detect_work(struct work_struct *work) int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) { struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm; + bool hp = false; + bool mic = false; + int status = 0; + + /* If jack in NULL, disable HS jack */ + if (!jack) { + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x0); + dapm = snd_soc_codec_get_dapm(codec); + snd_soc_dapm_disable_pin(dapm, "LDO1"); + snd_soc_dapm_sync(dapm); + return 0; + } rt298->jack = jack; + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); + + rt298_jack_detect(rt298, &hp, &mic); + if (hp == true) + status |= SND_JACK_HEADPHONE; - /* Send an initial empty report */ - snd_soc_jack_report(rt298->jack, 0, + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt298->jack, status, SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); return 0; diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 09103aab0cb2..0901e25d6db6 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -20,7 +20,6 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/sched.h> -#include <linux/kthread.h> #include <linux/uaccess.h> #include <linux/miscdevice.h> #include <linux/regulator/consumer.h> diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index f24b7cfd3a89..b281a46d769d 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -452,6 +452,9 @@ static int rt5514_set_dmic_clk(struct snd_soc_dapm_widget *w, RT5514_CLK_DMIC_OUT_SEL_MASK, idx << RT5514_CLK_DMIC_OUT_SEL_SFT); + if (rt5514->pdata.dmic_init_delay) + msleep(rt5514->pdata.dmic_init_delay); + return idx; } @@ -1073,9 +1076,18 @@ static const struct of_device_id rt5514_of_match[] = { MODULE_DEVICE_TABLE(of, rt5514_of_match); #endif +static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev) +{ + device_property_read_u32(dev, "realtek,dmic-init-delay-ms", + &rt5514->pdata.dmic_init_delay); + + return 0; +} + static int rt5514_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct rt5514_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5514_priv *rt5514; int ret; unsigned int val; @@ -1087,6 +1099,11 @@ static int rt5514_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5514); + if (pdata) + rt5514->pdata = *pdata; + else if (i2c->dev.of_node) + rt5514_parse_dt(rt5514, &i2c->dev); + rt5514->i2c_regmap = devm_regmap_init_i2c(i2c, &rt5514_i2c_regmap); if (IS_ERR(rt5514->i2c_regmap)) { ret = PTR_ERR(rt5514->i2c_regmap); diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 229de0e2c88c..5d343fb6d125 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -13,6 +13,7 @@ #define __RT5514_H__ #include <linux/clk.h> +#include <sound/rt5514.h> #define RT5514_DEVICE_ID 0x10ec5514 @@ -243,6 +244,7 @@ enum { }; struct rt5514_priv { + struct rt5514_platform_data pdata; struct snd_soc_codec *codec; struct regmap *i2c_regmap, *regmap; struct clk *mclk; diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index d1f273b24991..7d6e0823f98f 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -960,8 +960,7 @@ static int rt5616_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_codec *codec = dai->codec; struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); unsigned int val_len = 0, val_clk, mask_clk; int pre_div, bclk_ms, frame_size; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 3cc1135fc2cd..e29a6defefa0 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -423,6 +423,8 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = { SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("Mono ADC Capture Switch", RT5640_DUMMY1, + RT5640_M_MONO_ADC_L_SFT, RT5640_M_MONO_ADC_R_SFT, 1, 1), SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 127, 0, adc_vol_tlv), @@ -2407,6 +2409,9 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, + RT5640_MCLK_DET, RT5640_MCLK_DET); + if (rt5640->pdata.in1_diff) regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, RT5640_IN_DF1, RT5640_IN_DF1); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 90c88711c72a..b8a811732a52 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -1970,6 +1970,12 @@ #define RT5640_ZCD_HP_DIS (0x0 << 15) #define RT5640_ZCD_HP_EN (0x1 << 15) +/* General Control 1 (0xfa) */ +#define RT5640_M_MONO_ADC_L (0x1 << 13) +#define RT5640_M_MONO_ADC_L_SFT 13 +#define RT5640_M_MONO_ADC_R (0x1 << 12) +#define RT5640_M_MONO_ADC_R_SFT 12 +#define RT5640_MCLK_DET (0x1 << 11) /* Codec Private Register definition */ /* 3D Speaker Control (0x63) */ diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 9f0933ced804..76cf76a2e9b6 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1311,6 +1311,10 @@ static int rt5660_i2c_probe(struct i2c_client *i2c, if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + regmap_update_bits(rt5660->regmap, RT5660_GEN_CTRL1, + RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET, + RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET); + if (rt5660->pdata.dmic1_data_pin) { regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1, RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL); diff --git a/sound/soc/codecs/rt5660.h b/sound/soc/codecs/rt5660.h index 6cdb9269ec9e..bba18fb66b6f 100644 --- a/sound/soc/codecs/rt5660.h +++ b/sound/soc/codecs/rt5660.h @@ -810,6 +810,9 @@ /* General Control 1 (0xfa) */ #define RT5660_PWR_VREF_HP (0x1 << 11) #define RT5660_PWR_VREF_HP_SFT 11 +#define RT5660_AUTO_DIS_AMP (0x1 << 6) +#define RT5660_MCLK_DET (0x1 << 5) +#define RT5660_POW_CLKDET (0x1 << 1) #define RT5660_DIG_GATE_CTRL (0x1) #define RT5660_DIG_GATE_CTRL_SFT 0 diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 01a18d88f1eb..a32508d7dcfd 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -1,5 +1,5 @@ /* - * rt5663.c -- RT5668/RT5663 ALSA SoC audio codec driver + * rt5663.c -- RT5663 ALSA SoC audio codec driver * * Copyright 2016 Realtek Semiconductor Corp. * Author: Jack Yu <jack.yu@realtek.com> @@ -30,12 +30,12 @@ #include "rt5663.h" #include "rl6231.h" -#define RT5668_DEVICE_ID 0x6451 -#define RT5663_DEVICE_ID 0x6406 +#define RT5663_DEVICE_ID_2 0x6451 +#define RT5663_DEVICE_ID_1 0x6406 enum { - CODEC_TYPE_RT5668, - CODEC_TYPE_RT5663, + CODEC_VER_1, + CODEC_VER_0, }; struct rt5663_priv { @@ -45,7 +45,7 @@ struct rt5663_priv { struct snd_soc_jack *hs_jack; struct timer_list btn_check_timer; - int codec_type; + int codec_ver; int sysclk; int sysclk_src; int lrck; @@ -57,7 +57,7 @@ struct rt5663_priv { int jack_type; }; -static const struct reg_default rt5668_reg[] = { +static const struct reg_default rt5663_v2_reg[] = { { 0x0000, 0x0000 }, { 0x0001, 0xc8c8 }, { 0x0002, 0x8080 }, @@ -730,7 +730,7 @@ static bool rt5663_volatile_register(struct device *dev, unsigned int reg) case RT5663_ADC_EQ_1: case RT5663_INT_ST_1: case RT5663_INT_ST_2: - case RT5663_GPIO_STA: + case RT5663_GPIO_STA1: case RT5663_SIN_GEN_1: case RT5663_IL_CMD_1: case RT5663_IL_CMD_5: @@ -846,7 +846,7 @@ static bool rt5663_readable_register(struct device *dev, unsigned int reg) case RT5663_INT_ST_2: case RT5663_GPIO_1: case RT5663_GPIO_2: - case RT5663_GPIO_STA: + case RT5663_GPIO_STA1: case RT5663_SIN_GEN_1: case RT5663_SIN_GEN_2: case RT5663_SIN_GEN_3: @@ -1036,23 +1036,23 @@ static bool rt5663_readable_register(struct device *dev, unsigned int reg) } } -static bool rt5668_volatile_register(struct device *dev, unsigned int reg) +static bool rt5663_v2_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case RT5663_RESET: - case RT5668_CBJ_TYPE_2: - case RT5668_PDM_OUT_CTL: - case RT5668_PDM_I2C_DATA_CTL1: - case RT5668_PDM_I2C_DATA_CTL4: - case RT5668_ALC_BK_GAIN: + case RT5663_CBJ_TYPE_2: + case RT5663_PDM_OUT_CTL: + case RT5663_PDM_I2C_DATA_CTL1: + case RT5663_PDM_I2C_DATA_CTL4: + case RT5663_ALC_BK_GAIN: case RT5663_PLL_2: case RT5663_MICBIAS_1: case RT5663_ADC_EQ_1: case RT5663_INT_ST_1: - case RT5668_GPIO_STA: + case RT5663_GPIO_STA2: case RT5663_IL_CMD_1: case RT5663_IL_CMD_5: - case RT5668_A_JD_CTRL: + case RT5663_A_JD_CTRL: case RT5663_JD_CTRL2: case RT5663_VENDOR_ID: case RT5663_VENDOR_ID_1: @@ -1061,15 +1061,15 @@ static bool rt5668_volatile_register(struct device *dev, unsigned int reg) case RT5663_STO_DRE_5: case RT5663_STO_DRE_6: case RT5663_STO_DRE_7: - case RT5668_MONO_DYNA_6: - case RT5668_STO1_SIL_DET: - case RT5668_MONOL_SIL_DET: - case RT5668_MONOR_SIL_DET: - case RT5668_STO2_DAC_SIL: - case RT5668_MONO_AMP_CAL_ST1: - case RT5668_MONO_AMP_CAL_ST2: - case RT5668_MONO_AMP_CAL_ST3: - case RT5668_MONO_AMP_CAL_ST4: + case RT5663_MONO_DYNA_6: + case RT5663_STO1_SIL_DET: + case RT5663_MONOL_SIL_DET: + case RT5663_MONOR_SIL_DET: + case RT5663_STO2_DAC_SIL: + case RT5663_MONO_AMP_CAL_ST1: + case RT5663_MONO_AMP_CAL_ST2: + case RT5663_MONO_AMP_CAL_ST3: + case RT5663_MONO_AMP_CAL_ST4: case RT5663_HP_IMP_SEN_2: case RT5663_HP_IMP_SEN_3: case RT5663_HP_IMP_SEN_4: @@ -1083,218 +1083,218 @@ static bool rt5668_volatile_register(struct device *dev, unsigned int reg) case RT5663_HP_CALIB_ST7: case RT5663_HP_CALIB_ST8: case RT5663_HP_CALIB_ST9: - case RT5668_HP_CALIB_ST10: - case RT5668_HP_CALIB_ST11: + case RT5663_HP_CALIB_ST10: + case RT5663_HP_CALIB_ST11: return true; default: return false; } } -static bool rt5668_readable_register(struct device *dev, unsigned int reg) +static bool rt5663_v2_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case RT5668_LOUT_CTRL: - case RT5668_HP_AMP_2: - case RT5668_MONO_OUT: - case RT5668_MONO_GAIN: - case RT5668_AEC_BST: - case RT5668_IN1_IN2: - case RT5668_IN3_IN4: - case RT5668_INL1_INR1: - case RT5668_CBJ_TYPE_2: - case RT5668_CBJ_TYPE_3: - case RT5668_CBJ_TYPE_4: - case RT5668_CBJ_TYPE_5: - case RT5668_CBJ_TYPE_8: - case RT5668_DAC3_DIG_VOL: - case RT5668_DAC3_CTRL: - case RT5668_MONO_ADC_DIG_VOL: - case RT5668_STO2_ADC_DIG_VOL: - case RT5668_MONO_ADC_BST_GAIN: - case RT5668_STO2_ADC_BST_GAIN: - case RT5668_SIDETONE_CTRL: - case RT5668_MONO1_ADC_MIXER: - case RT5668_STO2_ADC_MIXER: - case RT5668_MONO_DAC_MIXER: - case RT5668_DAC2_SRC_CTRL: - case RT5668_IF_3_4_DATA_CTL: - case RT5668_IF_5_DATA_CTL: - case RT5668_PDM_OUT_CTL: - case RT5668_PDM_I2C_DATA_CTL1: - case RT5668_PDM_I2C_DATA_CTL2: - case RT5668_PDM_I2C_DATA_CTL3: - case RT5668_PDM_I2C_DATA_CTL4: - case RT5668_RECMIX1_NEW: - case RT5668_RECMIX1L_0: - case RT5668_RECMIX1L: - case RT5668_RECMIX1R_0: - case RT5668_RECMIX1R: - case RT5668_RECMIX2_NEW: - case RT5668_RECMIX2_L_2: - case RT5668_RECMIX2_R: - case RT5668_RECMIX2_R_2: - case RT5668_CALIB_REC_LR: - case RT5668_ALC_BK_GAIN: - case RT5668_MONOMIX_GAIN: - case RT5668_MONOMIX_IN_GAIN: - case RT5668_OUT_MIXL_GAIN: - case RT5668_OUT_LMIX_IN_GAIN: - case RT5668_OUT_RMIX_IN_GAIN: - case RT5668_OUT_RMIX_IN_GAIN1: - case RT5668_LOUT_MIXER_CTRL: - case RT5668_PWR_VOL: - case RT5668_ADCDAC_RST: - case RT5668_I2S34_SDP: - case RT5668_I2S5_SDP: - case RT5668_TDM_5: - case RT5668_TDM_6: - case RT5668_TDM_7: - case RT5668_TDM_8: - case RT5668_ASRC_3: - case RT5668_ASRC_6: - case RT5668_ASRC_7: - case RT5668_PLL_TRK_13: - case RT5668_I2S_M_CLK_CTL: - case RT5668_FDIV_I2S34_M_CLK: - case RT5668_FDIV_I2S34_M_CLK2: - case RT5668_FDIV_I2S5_M_CLK: - case RT5668_FDIV_I2S5_M_CLK2: - case RT5668_IRQ_4: - case RT5668_GPIO_3: - case RT5668_GPIO_4: - case RT5668_GPIO_STA: - case RT5668_HP_AMP_DET1: - case RT5668_HP_AMP_DET2: - case RT5668_HP_AMP_DET3: - case RT5668_MID_BD_HP_AMP: - case RT5668_LOW_BD_HP_AMP: - case RT5668_SOF_VOL_ZC2: - case RT5668_ADC_STO2_ADJ1: - case RT5668_ADC_STO2_ADJ2: - case RT5668_A_JD_CTRL: - case RT5668_JD1_TRES_CTRL: - case RT5668_JD2_TRES_CTRL: - case RT5668_JD_CTRL2: - case RT5668_DUM_REG_2: - case RT5668_DUM_REG_3: + case RT5663_LOUT_CTRL: + case RT5663_HP_AMP_2: + case RT5663_MONO_OUT: + case RT5663_MONO_GAIN: + case RT5663_AEC_BST: + case RT5663_IN1_IN2: + case RT5663_IN3_IN4: + case RT5663_INL1_INR1: + case RT5663_CBJ_TYPE_2: + case RT5663_CBJ_TYPE_3: + case RT5663_CBJ_TYPE_4: + case RT5663_CBJ_TYPE_5: + case RT5663_CBJ_TYPE_8: + case RT5663_DAC3_DIG_VOL: + case RT5663_DAC3_CTRL: + case RT5663_MONO_ADC_DIG_VOL: + case RT5663_STO2_ADC_DIG_VOL: + case RT5663_MONO_ADC_BST_GAIN: + case RT5663_STO2_ADC_BST_GAIN: + case RT5663_SIDETONE_CTRL: + case RT5663_MONO1_ADC_MIXER: + case RT5663_STO2_ADC_MIXER: + case RT5663_MONO_DAC_MIXER: + case RT5663_DAC2_SRC_CTRL: + case RT5663_IF_3_4_DATA_CTL: + case RT5663_IF_5_DATA_CTL: + case RT5663_PDM_OUT_CTL: + case RT5663_PDM_I2C_DATA_CTL1: + case RT5663_PDM_I2C_DATA_CTL2: + case RT5663_PDM_I2C_DATA_CTL3: + case RT5663_PDM_I2C_DATA_CTL4: + case RT5663_RECMIX1_NEW: + case RT5663_RECMIX1L_0: + case RT5663_RECMIX1L: + case RT5663_RECMIX1R_0: + case RT5663_RECMIX1R: + case RT5663_RECMIX2_NEW: + case RT5663_RECMIX2_L_2: + case RT5663_RECMIX2_R: + case RT5663_RECMIX2_R_2: + case RT5663_CALIB_REC_LR: + case RT5663_ALC_BK_GAIN: + case RT5663_MONOMIX_GAIN: + case RT5663_MONOMIX_IN_GAIN: + case RT5663_OUT_MIXL_GAIN: + case RT5663_OUT_LMIX_IN_GAIN: + case RT5663_OUT_RMIX_IN_GAIN: + case RT5663_OUT_RMIX_IN_GAIN1: + case RT5663_LOUT_MIXER_CTRL: + case RT5663_PWR_VOL: + case RT5663_ADCDAC_RST: + case RT5663_I2S34_SDP: + case RT5663_I2S5_SDP: + case RT5663_TDM_6: + case RT5663_TDM_7: + case RT5663_TDM_8: + case RT5663_TDM_9: + case RT5663_ASRC_3: + case RT5663_ASRC_6: + case RT5663_ASRC_7: + case RT5663_PLL_TRK_13: + case RT5663_I2S_M_CLK_CTL: + case RT5663_FDIV_I2S34_M_CLK: + case RT5663_FDIV_I2S34_M_CLK2: + case RT5663_FDIV_I2S5_M_CLK: + case RT5663_FDIV_I2S5_M_CLK2: + case RT5663_V2_IRQ_4: + case RT5663_GPIO_3: + case RT5663_GPIO_4: + case RT5663_GPIO_STA2: + case RT5663_HP_AMP_DET1: + case RT5663_HP_AMP_DET2: + case RT5663_HP_AMP_DET3: + case RT5663_MID_BD_HP_AMP: + case RT5663_LOW_BD_HP_AMP: + case RT5663_SOF_VOL_ZC2: + case RT5663_ADC_STO2_ADJ1: + case RT5663_ADC_STO2_ADJ2: + case RT5663_A_JD_CTRL: + case RT5663_JD1_TRES_CTRL: + case RT5663_JD2_TRES_CTRL: + case RT5663_V2_JD_CTRL2: + case RT5663_DUM_REG_2: + case RT5663_DUM_REG_3: case RT5663_VENDOR_ID: case RT5663_VENDOR_ID_1: case RT5663_VENDOR_ID_2: - case RT5668_DACADC_DIG_VOL2: - case RT5668_DIG_IN_PIN2: - case RT5668_PAD_DRV_CTL1: - case RT5668_SOF_RAM_DEPOP: - case RT5668_VOL_TEST: - case RT5668_TEST_MODE_3: - case RT5668_TEST_MODE_4: + case RT5663_DACADC_DIG_VOL2: + case RT5663_DIG_IN_PIN2: + case RT5663_PAD_DRV_CTL1: + case RT5663_SOF_RAM_DEPOP: + case RT5663_VOL_TEST: + case RT5663_TEST_MODE_4: + case RT5663_TEST_MODE_5: case RT5663_STO_DRE_9: - case RT5668_MONO_DYNA_1: - case RT5668_MONO_DYNA_2: - case RT5668_MONO_DYNA_3: - case RT5668_MONO_DYNA_4: - case RT5668_MONO_DYNA_5: - case RT5668_MONO_DYNA_6: - case RT5668_STO1_SIL_DET: - case RT5668_MONOL_SIL_DET: - case RT5668_MONOR_SIL_DET: - case RT5668_STO2_DAC_SIL: - case RT5668_PWR_SAV_CTL1: - case RT5668_PWR_SAV_CTL2: - case RT5668_PWR_SAV_CTL3: - case RT5668_PWR_SAV_CTL4: - case RT5668_PWR_SAV_CTL5: - case RT5668_PWR_SAV_CTL6: - case RT5668_MONO_AMP_CAL1: - case RT5668_MONO_AMP_CAL2: - case RT5668_MONO_AMP_CAL3: - case RT5668_MONO_AMP_CAL4: - case RT5668_MONO_AMP_CAL5: - case RT5668_MONO_AMP_CAL6: - case RT5668_MONO_AMP_CAL7: - case RT5668_MONO_AMP_CAL_ST1: - case RT5668_MONO_AMP_CAL_ST2: - case RT5668_MONO_AMP_CAL_ST3: - case RT5668_MONO_AMP_CAL_ST4: - case RT5668_MONO_AMP_CAL_ST5: - case RT5668_HP_IMP_SEN_13: - case RT5668_HP_IMP_SEN_14: - case RT5668_HP_IMP_SEN_6: - case RT5668_HP_IMP_SEN_7: - case RT5668_HP_IMP_SEN_8: - case RT5668_HP_IMP_SEN_9: - case RT5668_HP_IMP_SEN_10: - case RT5668_HP_LOGIC_3: - case RT5668_HP_CALIB_ST10: - case RT5668_HP_CALIB_ST11: - case RT5668_PRO_REG_TBL_4: - case RT5668_PRO_REG_TBL_5: - case RT5668_PRO_REG_TBL_6: - case RT5668_PRO_REG_TBL_7: - case RT5668_PRO_REG_TBL_8: - case RT5668_PRO_REG_TBL_9: - case RT5668_SAR_ADC_INL_1: - case RT5668_SAR_ADC_INL_2: - case RT5668_SAR_ADC_INL_3: - case RT5668_SAR_ADC_INL_4: - case RT5668_SAR_ADC_INL_5: - case RT5668_SAR_ADC_INL_6: - case RT5668_SAR_ADC_INL_7: - case RT5668_SAR_ADC_INL_8: - case RT5668_SAR_ADC_INL_9: - case RT5668_SAR_ADC_INL_10: - case RT5668_SAR_ADC_INL_11: - case RT5668_SAR_ADC_INL_12: - case RT5668_DRC_CTRL_1: - case RT5668_DRC1_CTRL_2: - case RT5668_DRC1_CTRL_3: - case RT5668_DRC1_CTRL_4: - case RT5668_DRC1_CTRL_5: - case RT5668_DRC1_CTRL_6: - case RT5668_DRC1_HD_CTRL_1: - case RT5668_DRC1_HD_CTRL_2: - case RT5668_DRC1_PRI_REG_1: - case RT5668_DRC1_PRI_REG_2: - case RT5668_DRC1_PRI_REG_3: - case RT5668_DRC1_PRI_REG_4: - case RT5668_DRC1_PRI_REG_5: - case RT5668_DRC1_PRI_REG_6: - case RT5668_DRC1_PRI_REG_7: - case RT5668_DRC1_PRI_REG_8: - case RT5668_ALC_PGA_CTL_1: - case RT5668_ALC_PGA_CTL_2: - case RT5668_ALC_PGA_CTL_3: - case RT5668_ALC_PGA_CTL_4: - case RT5668_ALC_PGA_CTL_5: - case RT5668_ALC_PGA_CTL_6: - case RT5668_ALC_PGA_CTL_7: - case RT5668_ALC_PGA_CTL_8: - case RT5668_ALC_PGA_REG_1: - case RT5668_ALC_PGA_REG_2: - case RT5668_ALC_PGA_REG_3: - case RT5668_ADC_EQ_RECOV_1: - case RT5668_ADC_EQ_RECOV_2: - case RT5668_ADC_EQ_RECOV_3: - case RT5668_ADC_EQ_RECOV_4: - case RT5668_ADC_EQ_RECOV_5: - case RT5668_ADC_EQ_RECOV_6: - case RT5668_ADC_EQ_RECOV_7: - case RT5668_ADC_EQ_RECOV_8: - case RT5668_ADC_EQ_RECOV_9: - case RT5668_ADC_EQ_RECOV_10: - case RT5668_ADC_EQ_RECOV_11: - case RT5668_ADC_EQ_RECOV_12: - case RT5668_ADC_EQ_RECOV_13: - case RT5668_VID_HIDDEN: - case RT5668_VID_CUSTOMER: - case RT5668_SCAN_MODE: - case RT5668_I2C_BYPA: + case RT5663_MONO_DYNA_1: + case RT5663_MONO_DYNA_2: + case RT5663_MONO_DYNA_3: + case RT5663_MONO_DYNA_4: + case RT5663_MONO_DYNA_5: + case RT5663_MONO_DYNA_6: + case RT5663_STO1_SIL_DET: + case RT5663_MONOL_SIL_DET: + case RT5663_MONOR_SIL_DET: + case RT5663_STO2_DAC_SIL: + case RT5663_PWR_SAV_CTL1: + case RT5663_PWR_SAV_CTL2: + case RT5663_PWR_SAV_CTL3: + case RT5663_PWR_SAV_CTL4: + case RT5663_PWR_SAV_CTL5: + case RT5663_PWR_SAV_CTL6: + case RT5663_MONO_AMP_CAL1: + case RT5663_MONO_AMP_CAL2: + case RT5663_MONO_AMP_CAL3: + case RT5663_MONO_AMP_CAL4: + case RT5663_MONO_AMP_CAL5: + case RT5663_MONO_AMP_CAL6: + case RT5663_MONO_AMP_CAL7: + case RT5663_MONO_AMP_CAL_ST1: + case RT5663_MONO_AMP_CAL_ST2: + case RT5663_MONO_AMP_CAL_ST3: + case RT5663_MONO_AMP_CAL_ST4: + case RT5663_MONO_AMP_CAL_ST5: + case RT5663_V2_HP_IMP_SEN_13: + case RT5663_V2_HP_IMP_SEN_14: + case RT5663_V2_HP_IMP_SEN_6: + case RT5663_V2_HP_IMP_SEN_7: + case RT5663_V2_HP_IMP_SEN_8: + case RT5663_V2_HP_IMP_SEN_9: + case RT5663_V2_HP_IMP_SEN_10: + case RT5663_HP_LOGIC_3: + case RT5663_HP_CALIB_ST10: + case RT5663_HP_CALIB_ST11: + case RT5663_PRO_REG_TBL_4: + case RT5663_PRO_REG_TBL_5: + case RT5663_PRO_REG_TBL_6: + case RT5663_PRO_REG_TBL_7: + case RT5663_PRO_REG_TBL_8: + case RT5663_PRO_REG_TBL_9: + case RT5663_SAR_ADC_INL_1: + case RT5663_SAR_ADC_INL_2: + case RT5663_SAR_ADC_INL_3: + case RT5663_SAR_ADC_INL_4: + case RT5663_SAR_ADC_INL_5: + case RT5663_SAR_ADC_INL_6: + case RT5663_SAR_ADC_INL_7: + case RT5663_SAR_ADC_INL_8: + case RT5663_SAR_ADC_INL_9: + case RT5663_SAR_ADC_INL_10: + case RT5663_SAR_ADC_INL_11: + case RT5663_SAR_ADC_INL_12: + case RT5663_DRC_CTRL_1: + case RT5663_DRC1_CTRL_2: + case RT5663_DRC1_CTRL_3: + case RT5663_DRC1_CTRL_4: + case RT5663_DRC1_CTRL_5: + case RT5663_DRC1_CTRL_6: + case RT5663_DRC1_HD_CTRL_1: + case RT5663_DRC1_HD_CTRL_2: + case RT5663_DRC1_PRI_REG_1: + case RT5663_DRC1_PRI_REG_2: + case RT5663_DRC1_PRI_REG_3: + case RT5663_DRC1_PRI_REG_4: + case RT5663_DRC1_PRI_REG_5: + case RT5663_DRC1_PRI_REG_6: + case RT5663_DRC1_PRI_REG_7: + case RT5663_DRC1_PRI_REG_8: + case RT5663_ALC_PGA_CTL_1: + case RT5663_ALC_PGA_CTL_2: + case RT5663_ALC_PGA_CTL_3: + case RT5663_ALC_PGA_CTL_4: + case RT5663_ALC_PGA_CTL_5: + case RT5663_ALC_PGA_CTL_6: + case RT5663_ALC_PGA_CTL_7: + case RT5663_ALC_PGA_CTL_8: + case RT5663_ALC_PGA_REG_1: + case RT5663_ALC_PGA_REG_2: + case RT5663_ALC_PGA_REG_3: + case RT5663_ADC_EQ_RECOV_1: + case RT5663_ADC_EQ_RECOV_2: + case RT5663_ADC_EQ_RECOV_3: + case RT5663_ADC_EQ_RECOV_4: + case RT5663_ADC_EQ_RECOV_5: + case RT5663_ADC_EQ_RECOV_6: + case RT5663_ADC_EQ_RECOV_7: + case RT5663_ADC_EQ_RECOV_8: + case RT5663_ADC_EQ_RECOV_9: + case RT5663_ADC_EQ_RECOV_10: + case RT5663_ADC_EQ_RECOV_11: + case RT5663_ADC_EQ_RECOV_12: + case RT5663_ADC_EQ_RECOV_13: + case RT5663_VID_HIDDEN: + case RT5663_VID_CUSTOMER: + case RT5663_SCAN_MODE: + case RT5663_I2C_BYPA: return true; case RT5663_TDM_1: case RT5663_DEPOP_3: case RT5663_ASRC_11_2: case RT5663_INT_ST_2: - case RT5663_GPIO_STA: + case RT5663_GPIO_STA1: case RT5663_SIN_GEN_1: case RT5663_SIN_GEN_2: case RT5663_SIN_GEN_3: @@ -1344,7 +1344,7 @@ static bool rt5668_readable_register(struct device *dev, unsigned int reg) } static const DECLARE_TLV_DB_SCALE(rt5663_hp_vol_tlv, -2400, 150, 0); -static const DECLARE_TLV_DB_SCALE(rt5668_hp_vol_tlv, -2250, 150, 0); +static const DECLARE_TLV_DB_SCALE(rt5663_v2_hp_vol_tlv, -2250, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); @@ -1374,57 +1374,57 @@ static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec, if (enable) { snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_EN); + RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_EN); /* reset in-line command */ snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_RESET_4BTN_INL_MASK, - RT5668_RESET_4BTN_INL_RESET); + RT5663_RESET_4BTN_INL_MASK, + RT5663_RESET_4BTN_INL_RESET); snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_RESET_4BTN_INL_MASK, - RT5668_RESET_4BTN_INL_NOR); - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + RT5663_RESET_4BTN_INL_MASK, + RT5663_RESET_4BTN_INL_NOR); + switch (rt5663->codec_ver) { + case CODEC_VER_1: snd_soc_update_bits(codec, RT5663_IRQ_3, - RT5668_EN_IRQ_INLINE_MASK, - RT5668_EN_IRQ_INLINE_NOR); + RT5663_V2_EN_IRQ_INLINE_MASK, + RT5663_V2_EN_IRQ_INLINE_NOR); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: snd_soc_update_bits(codec, RT5663_IRQ_2, RT5663_EN_IRQ_INLINE_MASK, RT5663_EN_IRQ_INLINE_NOR); break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } } else { - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: snd_soc_update_bits(codec, RT5663_IRQ_3, - RT5668_EN_IRQ_INLINE_MASK, - RT5668_EN_IRQ_INLINE_BYP); + RT5663_V2_EN_IRQ_INLINE_MASK, + RT5663_V2_EN_IRQ_INLINE_BYP); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: snd_soc_update_bits(codec, RT5663_IRQ_2, RT5663_EN_IRQ_INLINE_MASK, RT5663_EN_IRQ_INLINE_BYP); break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_DIS); + RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_DIS); /* reset in-line command */ snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_RESET_4BTN_INL_MASK, - RT5668_RESET_4BTN_INL_RESET); + RT5663_RESET_4BTN_INL_MASK, + RT5663_RESET_4BTN_INL_RESET); snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_RESET_4BTN_INL_MASK, - RT5668_RESET_4BTN_INL_NOR); + RT5663_RESET_4BTN_INL_MASK, + RT5663_RESET_4BTN_INL_NOR); } } /** - * rt5668_jack_detect - Detect headset. + * rt5663_v2_jack_detect - Detect headset. * @codec: SoC audio codec device. * @jack_insert: Jack insert or not. * @@ -1433,16 +1433,16 @@ static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec, * Returns detect status. */ -static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) +static int rt5663_v2_jack_detect(struct snd_soc_codec *codec, int jack_insert) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30}; dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert); if (jack_insert) { - snd_soc_write(codec, RT5668_CBJ_TYPE_2, 0x8040); - snd_soc_write(codec, RT5668_CBJ_TYPE_3, 0x1484); + snd_soc_write(codec, RT5663_CBJ_TYPE_2, 0x8040); + snd_soc_write(codec, RT5663_CBJ_TYPE_3, 0x1484); snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2"); @@ -1450,12 +1450,12 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_force_enable_pin(dapm, "CBJ Power"); snd_soc_dapm_sync(dapm); snd_soc_update_bits(codec, RT5663_RC_CLK, - RT5668_DIG_1M_CLK_MASK, RT5668_DIG_1M_CLK_EN); + RT5663_DIG_1M_CLK_MASK, RT5663_DIG_1M_CLK_EN); snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x8); while (i < 5) { msleep(sleep_time[i]); - val = snd_soc_read(codec, RT5668_CBJ_TYPE_2) & 0x0003; + val = snd_soc_read(codec, RT5663_CBJ_TYPE_2) & 0x0003; if (val == 0x1 || val == 0x2 || val == 0x3) break; dev_dbg(codec->dev, "%s: MX-0011 val=%x sleep %d\n", @@ -1466,7 +1466,7 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) switch (val) { case 1: case 2: - rt5668->jack_type = SND_JACK_HEADSET; + rt5663->jack_type = SND_JACK_HEADSET; rt5663_enable_push_button_irq(codec, true); break; default: @@ -1475,13 +1475,13 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); snd_soc_dapm_disable_pin(dapm, "CBJ Power"); snd_soc_dapm_sync(dapm); - rt5668->jack_type = SND_JACK_HEADPHONE; + rt5663->jack_type = SND_JACK_HEADPHONE; break; } } else { snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x0); - if (rt5668->jack_type == SND_JACK_HEADSET) { + if (rt5663->jack_type == SND_JACK_HEADSET) { rt5663_enable_push_button_irq(codec, false); snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); snd_soc_dapm_disable_pin(dapm, "MICBIAS2"); @@ -1489,11 +1489,11 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_disable_pin(dapm, "CBJ Power"); snd_soc_dapm_sync(dapm); } - rt5668->jack_type = 0; + rt5663->jack_type = 0; } - dev_dbg(codec->dev, "jack_type = %d\n", rt5668->jack_type); - return rt5668->jack_type; + dev_dbg(codec->dev, "jack_type = %d\n", rt5663->jack_type); + return rt5663->jack_type; } /** @@ -1514,11 +1514,11 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) if (jack_insert) { snd_soc_update_bits(codec, RT5663_DIG_MISC, - RT5668_DIG_GATE_CTRL_MASK, RT5668_DIG_GATE_CTRL_EN); + RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN); snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, - RT5663_SI_HP_MASK | RT5668_OSW_HP_L_MASK | - RT5668_OSW_HP_R_MASK, RT5663_SI_HP_EN | - RT5668_OSW_HP_L_DIS | RT5668_OSW_HP_R_DIS); + RT5663_SI_HP_MASK | RT5663_OSW_HP_L_MASK | + RT5663_OSW_HP_R_MASK, RT5663_SI_HP_EN | + RT5663_OSW_HP_L_DIS | RT5663_OSW_HP_R_DIS); snd_soc_update_bits(codec, RT5663_DUMMY_1, RT5663_EMB_CLK_MASK | RT5663_HPA_CPL_BIAS_MASK | RT5663_HPA_CPR_BIAS_MASK, RT5663_EMB_CLK_EN | @@ -1530,28 +1530,28 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) RT5663_PWR_MIC_DET_MASK, RT5663_PWR_MIC_DET_ON); /* BST1 power on for JD */ snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, - RT5668_PWR_BST1_MASK, RT5668_PWR_BST1_ON); + RT5663_PWR_BST1_MASK, RT5663_PWR_BST1_ON); snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1, RT5663_CBJ_DET_MASK | RT5663_EXT_JD_MASK | RT5663_POL_EXT_JD_MASK, RT5663_CBJ_DET_EN | RT5663_EXT_JD_EN | RT5663_POL_EXT_JD_EN); snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, - RT5668_PWR_MB_MASK | RT5668_LDO1_DVO_MASK | - RT5668_AMP_HP_MASK, RT5668_PWR_MB | - RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); + RT5663_PWR_MB_MASK | RT5663_LDO1_DVO_MASK | + RT5663_AMP_HP_MASK, RT5663_PWR_MB | + RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X); snd_soc_update_bits(codec, RT5663_AUTO_1MRC_CLK, - RT5668_IRQ_POW_SAV_MASK, RT5668_IRQ_POW_SAV_EN); + RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN); snd_soc_update_bits(codec, RT5663_IRQ_1, RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); while (i < 5) { msleep(sleep_time[i]); val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & 0x0003; + dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n", + __func__, val, sleep_time[i]); i++; if (val == 0x1 || val == 0x2 || val == 0x3) break; - dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n", - __func__, val, sleep_time[i]); } dev_dbg(codec->dev, "%s val = %d\n", __func__, val); switch (val) { @@ -1619,13 +1619,13 @@ static bool rt5663_check_jd_status(struct snd_soc_codec *codec) dev_dbg(codec->dev, "%s val=%x\n", __func__, val); /* JD1 */ - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: return !(val & 0x2000); - case CODEC_TYPE_RT5663: + case CODEC_VER_0: return !(val & 0x1000); default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } return false; @@ -1645,15 +1645,16 @@ static void rt5663_jack_detect_work(struct work_struct *work) /* jack in */ if (rt5663->jack_type == 0) { /* jack was out, report jack type */ - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - report = rt5668_jack_detect(rt5663->codec, 1); + switch (rt5663->codec_ver) { + case CODEC_VER_1: + report = rt5663_v2_jack_detect( + rt5663->codec, 1); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: report = rt5663_jack_detect(rt5663->codec, 1); break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } } else { /* jack is already in, report button event */ @@ -1702,15 +1703,15 @@ static void rt5663_jack_detect_work(struct work_struct *work) } } else { /* jack out */ - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - report = rt5668_jack_detect(rt5663->codec, 0); + switch (rt5663->codec_ver) { + case CODEC_VER_1: + report = rt5663_v2_jack_detect(rt5663->codec, 0); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: report = rt5663_jack_detect(rt5663->codec, 0); break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } } dev_dbg(codec->dev, "%s jack report: 0x%04x\n", __func__, report); @@ -1722,24 +1723,24 @@ static void rt5663_jack_detect_work(struct work_struct *work) static const struct snd_kcontrol_new rt5663_snd_controls[] = { /* DAC Digital Volume */ SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL, - RT5668_DAC_L1_VOL_SHIFT + 1, RT5668_DAC_R1_VOL_SHIFT + 1, + RT5663_DAC_L1_VOL_SHIFT + 1, RT5663_DAC_R1_VOL_SHIFT + 1, 87, 0, dac_vol_tlv), /* ADC Digital Volume Control */ SOC_DOUBLE("ADC Capture Switch", RT5663_STO1_ADC_DIG_VOL, - RT5668_ADC_L_MUTE_SHIFT, RT5668_ADC_R_MUTE_SHIFT, 1, 1), + RT5663_ADC_L_MUTE_SHIFT, RT5663_ADC_R_MUTE_SHIFT, 1, 1), SOC_DOUBLE_TLV("ADC Capture Volume", RT5663_STO1_ADC_DIG_VOL, - RT5668_ADC_L_VOL_SHIFT + 1, RT5668_ADC_R_VOL_SHIFT + 1, + RT5663_ADC_L_VOL_SHIFT + 1, RT5663_ADC_R_VOL_SHIFT + 1, 63, 0, adc_vol_tlv), }; -static const struct snd_kcontrol_new rt5668_specific_controls[] = { +static const struct snd_kcontrol_new rt5663_v2_specific_controls[] = { /* Headphone Output Volume */ SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_HP_LCH_DRE, - RT5663_HP_RCH_DRE, RT5668_GAIN_HP_SHIFT, 15, 1, - rt5668_hp_vol_tlv), + RT5663_HP_RCH_DRE, RT5663_GAIN_HP_SHIFT, 15, 1, + rt5663_v2_hp_vol_tlv), /* Mic Boost Volume */ - SOC_SINGLE_TLV("IN1 Capture Volume", RT5668_AEC_BST, - RT5668_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_AEC_BST, + RT5663_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv), }; static const struct snd_kcontrol_new rt5663_specific_controls[] = { @@ -1775,15 +1776,15 @@ static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { switch (w->shift) { - case RT5668_ADC_STO1_ASRC_SHIFT: - reg = RT5668_ASRC_3; - shift = RT5668_AD_STO1_TRACK_SHIFT; + case RT5663_ADC_STO1_ASRC_SHIFT: + reg = RT5663_ASRC_3; + shift = RT5663_V2_AD_STO1_TRACK_SHIFT; break; - case RT5668_DAC_STO1_ASRC_SHIFT: + case RT5663_DAC_STO1_ASRC_SHIFT: reg = RT5663_ASRC_2; - shift = RT5668_DA_STO1_TRACK_SHIFT; + shift = RT5663_DA_STO1_TRACK_SHIFT; break; default: return 0; @@ -1820,17 +1821,17 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source, da_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) & RT5663_DA_STO1_TRACK_MASK) ? 1 : 0; - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - ad_asrc_en = (snd_soc_read(codec, RT5668_ASRC_3) & - RT5668_AD_STO1_TRACK_MASK) ? 1 : 0; + switch (rt5663->codec_ver) { + case CODEC_VER_1: + ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_3) & + RT5663_V2_AD_STO1_TRACK_MASK) ? 1 : 0; break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) & RT5663_AD_STO1_TRACK_MASK) ? 1 : 0; break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); return 1; } @@ -1849,7 +1850,7 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source, * @filter_mask: mask of filters. * @clk_src: clock source * - * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5668 can + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5663 can * only support standard 32fs or 64fs i2s format, ASRC should be enabled to * support special i2s clock format such as Intel's 100fs(100 * sampling rate). * ASRC function will track i2s clock and generate a corresponding system clock @@ -1860,7 +1861,7 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source, int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, unsigned int filter_mask, unsigned int clk_src) { - struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); unsigned int asrc2_mask = 0; unsigned int asrc2_value = 0; unsigned int asrc3_mask = 0; @@ -1876,22 +1877,22 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, } if (filter_mask & RT5663_DA_STEREO_FILTER) { - asrc2_mask |= RT5668_DA_STO1_TRACK_MASK; - asrc2_value |= clk_src << RT5668_DA_STO1_TRACK_SHIFT; + asrc2_mask |= RT5663_DA_STO1_TRACK_MASK; + asrc2_value |= clk_src << RT5663_DA_STO1_TRACK_SHIFT; } if (filter_mask & RT5663_AD_STEREO_FILTER) { - switch (rt5668->codec_type) { - case CODEC_TYPE_RT5668: - asrc3_mask |= RT5668_AD_STO1_TRACK_MASK; - asrc3_value |= clk_src << RT5668_AD_STO1_TRACK_SHIFT; + switch (rt5663->codec_ver) { + case CODEC_VER_1: + asrc3_mask |= RT5663_V2_AD_STO1_TRACK_MASK; + asrc3_value |= clk_src << RT5663_V2_AD_STO1_TRACK_SHIFT; break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: asrc2_mask |= RT5663_AD_STO1_TRACK_MASK; asrc2_value |= clk_src << RT5663_AD_STO1_TRACK_SHIFT; break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } } @@ -1900,7 +1901,7 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, asrc2_value); if (asrc3_mask) - snd_soc_update_bits(codec, RT5668_ASRC_3, asrc3_mask, + snd_soc_update_bits(codec, RT5663_ASRC_3, asrc3_mask, asrc3_value); return 0; @@ -1908,82 +1909,82 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, EXPORT_SYMBOL_GPL(rt5663_sel_asrc_clk_src); /* Analog Mixer */ -static const struct snd_kcontrol_new rt5668_recmix1l[] = { - SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1L, - RT5668_RECMIX1L_BST2_SHIFT, 1, 1), - SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5668_RECMIX1L, - RT5668_RECMIX1L_BST1_CBJ_SHIFT, 1, 1), +static const struct snd_kcontrol_new rt5663_recmix1l[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5663_RECMIX1L, + RT5663_RECMIX1L_BST2_SHIFT, 1, 1), + SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5663_RECMIX1L, + RT5663_RECMIX1L_BST1_CBJ_SHIFT, 1, 1), }; -static const struct snd_kcontrol_new rt5668_recmix1r[] = { - SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1R, - RT5668_RECMIX1R_BST2_SHIFT, 1, 1), +static const struct snd_kcontrol_new rt5663_recmix1r[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5663_RECMIX1R, + RT5663_RECMIX1R_BST2_SHIFT, 1, 1), }; /* Digital Mixer */ static const struct snd_kcontrol_new rt5663_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, - RT5668_M_STO1_ADC_L1_SHIFT, 1, 1), + RT5663_M_STO1_ADC_L1_SHIFT, 1, 1), SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, - RT5668_M_STO1_ADC_L2_SHIFT, 1, 1), + RT5663_M_STO1_ADC_L2_SHIFT, 1, 1), }; -static const struct snd_kcontrol_new rt5668_sto1_adc_r_mix[] = { +static const struct snd_kcontrol_new rt5663_sto1_adc_r_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, - RT5668_M_STO1_ADC_R1_SHIFT, 1, 1), + RT5663_M_STO1_ADC_R1_SHIFT, 1, 1), SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, - RT5668_M_STO1_ADC_R2_SHIFT, 1, 1), + RT5663_M_STO1_ADC_R2_SHIFT, 1, 1), }; static const struct snd_kcontrol_new rt5663_adda_l_mix[] = { SOC_DAPM_SINGLE("ADC L Switch", RT5663_AD_DA_MIXER, - RT5668_M_ADCMIX_L_SHIFT, 1, 1), + RT5663_M_ADCMIX_L_SHIFT, 1, 1), SOC_DAPM_SINGLE("DAC L Switch", RT5663_AD_DA_MIXER, - RT5668_M_DAC1_L_SHIFT, 1, 1), + RT5663_M_DAC1_L_SHIFT, 1, 1), }; static const struct snd_kcontrol_new rt5663_adda_r_mix[] = { SOC_DAPM_SINGLE("ADC R Switch", RT5663_AD_DA_MIXER, - RT5668_M_ADCMIX_R_SHIFT, 1, 1), + RT5663_M_ADCMIX_R_SHIFT, 1, 1), SOC_DAPM_SINGLE("DAC R Switch", RT5663_AD_DA_MIXER, - RT5668_M_DAC1_R_SHIFT, 1, 1), + RT5663_M_DAC1_R_SHIFT, 1, 1), }; static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = { SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, - RT5668_M_DAC_L1_STO_L_SHIFT, 1, 1), + RT5663_M_DAC_L1_STO_L_SHIFT, 1, 1), SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, - RT5668_M_DAC_R1_STO_L_SHIFT, 1, 1), + RT5663_M_DAC_R1_STO_L_SHIFT, 1, 1), }; static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = { SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, - RT5668_M_DAC_L1_STO_R_SHIFT, 1, 1), + RT5663_M_DAC_L1_STO_R_SHIFT, 1, 1), SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, - RT5668_M_DAC_R1_STO_R_SHIFT, 1, 1), + RT5663_M_DAC_R1_STO_R_SHIFT, 1, 1), }; /* Out Switch */ -static const struct snd_kcontrol_new rt5668_hpo_switch = - SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_AMP_2, - RT5668_EN_DAC_HPO_SHIFT, 1, 0); +static const struct snd_kcontrol_new rt5663_hpo_switch = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5663_HP_AMP_2, + RT5663_EN_DAC_HPO_SHIFT, 1, 0); /* Stereo ADC source */ -static const char * const rt5668_sto1_adc_src[] = { +static const char * const rt5663_sto1_adc_src[] = { "ADC L", "ADC R" }; -static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcl_enum, RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_L_SRC_SHIFT, rt5668_sto1_adc_src); +static SOC_ENUM_SINGLE_DECL(rt5663_sto1_adcl_enum, RT5663_STO1_ADC_MIXER, + RT5663_STO1_ADC_L_SRC_SHIFT, rt5663_sto1_adc_src); -static const struct snd_kcontrol_new rt5668_sto1_adcl_mux = - SOC_DAPM_ENUM("STO1 ADC L Mux", rt5668_sto1_adcl_enum); +static const struct snd_kcontrol_new rt5663_sto1_adcl_mux = + SOC_DAPM_ENUM("STO1 ADC L Mux", rt5663_sto1_adcl_enum); -static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcr_enum, RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_R_SRC_SHIFT, rt5668_sto1_adc_src); +static SOC_ENUM_SINGLE_DECL(rt5663_sto1_adcr_enum, RT5663_STO1_ADC_MIXER, + RT5663_STO1_ADC_R_SRC_SHIFT, rt5663_sto1_adc_src); -static const struct snd_kcontrol_new rt5668_sto1_adcr_mux = - SOC_DAPM_ENUM("STO1 ADC R Mux", rt5668_sto1_adcr_enum); +static const struct snd_kcontrol_new rt5663_sto1_adcr_mux = + SOC_DAPM_ENUM("STO1 ADC R Mux", rt5663_sto1_adcr_enum); /* RT5663: Analog DACL1 input source */ static const char * const rt5663_alg_dacl_src[] = { @@ -2015,12 +2016,12 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, - RT5668_SEL_PM_HP_SHIFT, RT5668_SEL_PM_HP_HIGH); + RT5663_SEL_PM_HP_SHIFT, RT5663_SEL_PM_HP_HIGH); snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, - RT5668_HP_SIG_SRC1_MASK, - RT5668_HP_SIG_SRC1_SILENCE); + RT5663_HP_SIG_SRC1_MASK, + RT5663_HP_SIG_SRC1_SILENCE); } else { snd_soc_write(codec, RT5663_DEPOP_2, 0x3003); snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, @@ -2028,7 +2029,7 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0030); snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, - RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_DIS); + RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS); snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371); snd_soc_write(codec, RT5663_HP_BIAS, 0xabba); snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224); @@ -2041,14 +2042,14 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, - RT5668_HP_SIG_SRC1_MASK, - RT5668_HP_SIG_SRC1_REG); + RT5663_HP_SIG_SRC1_MASK, + RT5663_HP_SIG_SRC1_REG); } else { snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0); snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, - RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_EN); + RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN); snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0); snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, 0x000b); @@ -2062,7 +2063,7 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, return 0; } -static int rt5668_bst2_power(struct snd_soc_dapm_widget *w, +static int rt5663_bst2_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); @@ -2070,13 +2071,13 @@ static int rt5668_bst2_power(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, - RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, - RT5668_PWR_BST2 | RT5668_PWR_BST2_OP); + RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK, + RT5663_PWR_BST2 | RT5663_PWR_BST2_OP); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, - RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, 0); + RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK, 0); break; default: @@ -2110,14 +2111,14 @@ static int rt5663_pre_div_power(struct snd_soc_dapm_widget *w, } static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { - SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5668_PWR_PLL_SHIFT, 0, + SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5663_PWR_PLL_SHIFT, 0, NULL, 0), /* micbias */ SND_SOC_DAPM_MICBIAS("MICBIAS1", RT5663_PWR_ANLG_2, - RT5668_PWR_MB1_SHIFT, 0), + RT5663_PWR_MB1_SHIFT, 0), SND_SOC_DAPM_MICBIAS("MICBIAS2", RT5663_PWR_ANLG_2, - RT5668_PWR_MB2_SHIFT, 0), + RT5663_PWR_MB2_SHIFT, 0), /* Input Lines */ SND_SOC_DAPM_INPUT("IN1P"), @@ -2125,14 +2126,14 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { /* REC Mixer Power */ SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5663_PWR_ANLG_2, - RT5668_PWR_RECMIX1_SHIFT, 0, NULL, 0), + RT5663_PWR_RECMIX1_SHIFT, 0, NULL, 0), /* ADCs */ SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("ADC L Power", RT5663_PWR_DIG_1, - RT5668_PWR_ADC_L1_SHIFT, 0, NULL, 0), + RT5663_PWR_ADC_L1_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ADC Clock", RT5663_CHOP_ADC, - RT5668_CKGEN_ADCC_SHIFT, 0, NULL, 0), + RT5663_CKGEN_ADCC_SHIFT, 0, NULL, 0), /* ADC Mixer */ SND_SOC_DAPM_MIXER("STO1 ADC MIXL", SND_SOC_NOPM, @@ -2141,10 +2142,10 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { /* ADC Filter Power */ SND_SOC_DAPM_SUPPLY("STO1 ADC Filter", RT5663_PWR_DIG_2, - RT5668_PWR_ADC_S1F_SHIFT, 0, NULL, 0), + RT5663_PWR_ADC_S1F_SHIFT, 0, NULL, 0), /* Digital Interface */ - SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5668_PWR_I2S1_SHIFT, 0, + SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5663_PWR_I2S1_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("IF DAC", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -2166,7 +2167,7 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { /* DAC Mixer */ SND_SOC_DAPM_SUPPLY("STO1 DAC Filter", RT5663_PWR_DIG_2, - RT5668_PWR_DAC_S1F_SHIFT, 0, NULL, 0), + RT5663_PWR_DAC_S1F_SHIFT, 0, NULL, 0), SND_SOC_DAPM_MIXER("STO1 DAC MIXL", SND_SOC_NOPM, 0, 0, rt5663_sto1_dac_l_mix, ARRAY_SIZE(rt5663_sto1_dac_l_mix)), SND_SOC_DAPM_MIXER("STO1 DAC MIXR", SND_SOC_NOPM, 0, 0, @@ -2174,9 +2175,9 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { /* DACs */ SND_SOC_DAPM_SUPPLY("STO1 DAC L Power", RT5663_PWR_DIG_1, - RT5668_PWR_DAC_L1_SHIFT, 0, NULL, 0), + RT5663_PWR_DAC_L1_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("STO1 DAC R Power", RT5663_PWR_DIG_1, - RT5668_PWR_DAC_R1_SHIFT, 0, NULL, 0), + RT5663_PWR_DAC_R1_SHIFT, 0, NULL, 0), SND_SOC_DAPM_DAC("DAC L", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0), @@ -2189,21 +2190,21 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HPOR"), }; -static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = { +static const struct snd_soc_dapm_widget rt5663_v2_specific_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("LDO2", RT5663_PWR_ANLG_3, - RT5668_PWR_LDO2_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5668_PWR_VOL, - RT5668_PWR_MIC_DET_SHIFT, 0, NULL, 0), + RT5663_PWR_LDO2_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5663_PWR_VOL, + RT5663_V2_PWR_MIC_DET_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("LDO DAC", RT5663_PWR_DIG_1, - RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), + RT5663_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), /* ASRC */ SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, - RT5668_I2S1_ASRC_SHIFT, 0, NULL, 0), + RT5663_I2S1_ASRC_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1, - RT5668_DAC_STO1_ASRC_SHIFT, 0, NULL, 0), + RT5663_DAC_STO1_ASRC_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1, - RT5668_ADC_STO1_ASRC_SHIFT, 0, NULL, 0), + RT5663_ADC_STO1_ASRC_SHIFT, 0, NULL, 0), /* Input Lines */ SND_SOC_DAPM_INPUT("IN2P"), @@ -2212,51 +2213,51 @@ static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = { /* Boost */ SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("CBJ Power", RT5663_PWR_ANLG_3, - RT5668_PWR_CBJ_SHIFT, 0, NULL, 0), + RT5663_PWR_CBJ_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("BST2 Power", SND_SOC_NOPM, 0, 0, - rt5668_bst2_power, SND_SOC_DAPM_PRE_PMD | + rt5663_bst2_power, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), /* REC Mixer */ - SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5668_recmix1l, - ARRAY_SIZE(rt5668_recmix1l)), - SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5668_recmix1r, - ARRAY_SIZE(rt5668_recmix1r)), + SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5663_recmix1l, + ARRAY_SIZE(rt5663_recmix1l)), + SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5663_recmix1r, + ARRAY_SIZE(rt5663_recmix1r)), SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5663_PWR_ANLG_2, - RT5668_PWR_RECMIX2_SHIFT, 0, NULL, 0), + RT5663_PWR_RECMIX2_SHIFT, 0, NULL, 0), /* ADC */ SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("ADC R Power", RT5663_PWR_DIG_1, - RT5668_PWR_ADC_R1_SHIFT, 0, NULL, 0), + RT5663_PWR_ADC_R1_SHIFT, 0, NULL, 0), /* ADC Mux */ SND_SOC_DAPM_PGA("STO1 ADC L1", RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0), + RT5663_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("STO1 ADC R1", RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0), + RT5663_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("STO1 ADC L2", RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0), + RT5663_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0), SND_SOC_DAPM_PGA("STO1 ADC R2", RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0), + RT5663_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0), SND_SOC_DAPM_MUX("STO1 ADC L Mux", SND_SOC_NOPM, 0, 0, - &rt5668_sto1_adcl_mux), + &rt5663_sto1_adcl_mux), SND_SOC_DAPM_MUX("STO1 ADC R Mux", SND_SOC_NOPM, 0, 0, - &rt5668_sto1_adcr_mux), + &rt5663_sto1_adcr_mux), /* ADC Mix */ SND_SOC_DAPM_MIXER("STO1 ADC MIXR", SND_SOC_NOPM, 0, 0, - rt5668_sto1_adc_r_mix, ARRAY_SIZE(rt5668_sto1_adc_r_mix)), + rt5663_sto1_adc_r_mix, ARRAY_SIZE(rt5663_sto1_adc_r_mix)), /* Analog DAC Clock */ SND_SOC_DAPM_SUPPLY("DAC Clock", RT5663_CHOP_DAC_L, - RT5668_CKGEN_DAC1_SHIFT, 0, NULL, 0), + RT5663_CKGEN_DAC1_SHIFT, 0, NULL, 0), /* Headphone out */ SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0, - &rt5668_hpo_switch), + &rt5663_hpo_switch), }; static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = { @@ -2267,7 +2268,7 @@ static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = { /* LDO */ SND_SOC_DAPM_SUPPLY("LDO ADC", RT5663_PWR_DIG_1, - RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), + RT5663_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), /* ASRC */ SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, @@ -2341,7 +2342,7 @@ static const struct snd_soc_dapm_route rt5663_dapm_routes[] = { { "HP Amp", NULL, "DAC R" }, }; -static const struct snd_soc_dapm_route rt5668_specific_dapm_routes[] = { +static const struct snd_soc_dapm_route rt5663_v2_specific_dapm_routes[] = { { "MICBIAS1", NULL, "LDO2" }, { "MICBIAS2", NULL, "LDO2" }, @@ -2440,26 +2441,26 @@ static int rt5663_hw_params(struct snd_pcm_substream *substream, switch (params_width(params)) { case 8: - val_len = RT5668_I2S_DL_8; + val_len = RT5663_I2S_DL_8; break; case 16: - val_len = RT5668_I2S_DL_16; + val_len = RT5663_I2S_DL_16; break; case 20: - val_len = RT5668_I2S_DL_20; + val_len = RT5663_I2S_DL_20; break; case 24: - val_len = RT5668_I2S_DL_24; + val_len = RT5663_I2S_DL_24; break; default: return -EINVAL; } snd_soc_update_bits(codec, RT5663_I2S1_SDP, - RT5668_I2S_DL_MASK, val_len); + RT5663_I2S_DL_MASK, val_len); snd_soc_update_bits(codec, RT5663_ADDA_CLK_1, - RT5668_I2S_PD1_MASK, pre_div << RT5668_I2S_PD1_SHIFT); + RT5663_I2S_PD1_MASK, pre_div << RT5663_I2S_PD1_SHIFT); return 0; } @@ -2473,7 +2474,7 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_CBM_CFM: break; case SND_SOC_DAIFMT_CBS_CFS: - reg_val |= RT5668_I2S_MS_S; + reg_val |= RT5663_I2S_MS_S; break; default: return -EINVAL; @@ -2483,7 +2484,7 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_IB_NF: - reg_val |= RT5668_I2S_BP_INV; + reg_val |= RT5663_I2S_BP_INV; break; default: return -EINVAL; @@ -2493,20 +2494,20 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_I2S: break; case SND_SOC_DAIFMT_LEFT_J: - reg_val |= RT5668_I2S_DF_LEFT; + reg_val |= RT5663_I2S_DF_LEFT; break; case SND_SOC_DAIFMT_DSP_A: - reg_val |= RT5668_I2S_DF_PCM_A; + reg_val |= RT5663_I2S_DF_PCM_A; break; case SND_SOC_DAIFMT_DSP_B: - reg_val |= RT5668_I2S_DF_PCM_B; + reg_val |= RT5663_I2S_DF_PCM_B; break; default: return -EINVAL; } - snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5668_I2S_MS_MASK | - RT5668_I2S_BP_MASK | RT5668_I2S_DF_MASK, reg_val); + snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5663_I2S_MS_MASK | + RT5663_I2S_BP_MASK | RT5663_I2S_DF_MASK, reg_val); return 0; } @@ -2535,7 +2536,7 @@ static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); return -EINVAL; } - snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5668_SCLK_SRC_MASK, + snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK, reg_val); rt5663->sysclk = freq; rt5663->sysclk_src = clk_id; @@ -2569,17 +2570,17 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, return 0; } - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - mask = RT5668_PLL1_SRC_MASK; - shift = RT5668_PLL1_SRC_SHIFT; + switch (rt5663->codec_ver) { + case CODEC_VER_1: + mask = RT5663_V2_PLL1_SRC_MASK; + shift = RT5663_V2_PLL1_SRC_SHIFT; break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: mask = RT5663_PLL1_SRC_MASK; shift = RT5663_PLL1_SRC_SHIFT; break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); return -EINVAL; } @@ -2607,10 +2608,10 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, pll_code.k_code); snd_soc_write(codec, RT5663_PLL_1, - pll_code.n_code << RT5668_PLL_N_SHIFT | pll_code.k_code); + pll_code.n_code << RT5663_PLL_N_SHIFT | pll_code.k_code); snd_soc_write(codec, RT5663_PLL_2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SHIFT | - pll_code.m_bp << RT5668_PLL_M_BP_SHIFT); + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT | + pll_code.m_bp << RT5663_PLL_M_BP_SHIFT); rt5663->pll_in = freq_in; rt5663->pll_out = freq_out; @@ -2627,20 +2628,20 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int val = 0, reg; if (rx_mask || tx_mask) - val |= RT5668_TDM_MODE_TDM; + val |= RT5663_TDM_MODE_TDM; switch (slots) { case 4: - val |= RT5668_TDM_IN_CH_4; - val |= RT5668_TDM_OUT_CH_4; + val |= RT5663_TDM_IN_CH_4; + val |= RT5663_TDM_OUT_CH_4; break; case 6: - val |= RT5668_TDM_IN_CH_6; - val |= RT5668_TDM_OUT_CH_6; + val |= RT5663_TDM_IN_CH_6; + val |= RT5663_TDM_OUT_CH_6; break; case 8: - val |= RT5668_TDM_IN_CH_8; - val |= RT5668_TDM_OUT_CH_8; + val |= RT5663_TDM_IN_CH_8; + val |= RT5663_TDM_OUT_CH_8; break; case 2: break; @@ -2650,16 +2651,16 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, switch (slot_width) { case 20: - val |= RT5668_TDM_IN_LEN_20; - val |= RT5668_TDM_OUT_LEN_20; + val |= RT5663_TDM_IN_LEN_20; + val |= RT5663_TDM_OUT_LEN_20; break; case 24: - val |= RT5668_TDM_IN_LEN_24; - val |= RT5668_TDM_OUT_LEN_24; + val |= RT5663_TDM_IN_LEN_24; + val |= RT5663_TDM_OUT_LEN_24; break; case 32: - val |= RT5668_TDM_IN_LEN_32; - val |= RT5668_TDM_OUT_LEN_32; + val |= RT5663_TDM_IN_LEN_32; + val |= RT5663_TDM_OUT_LEN_32; break; case 16: break; @@ -2667,21 +2668,21 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, return -EINVAL; } - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: reg = RT5663_TDM_2; break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: reg = RT5663_TDM_1; break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); return -EINVAL; } - snd_soc_update_bits(codec, reg, RT5668_TDM_MODE_MASK | - RT5668_TDM_IN_CH_MASK | RT5668_TDM_OUT_CH_MASK | - RT5668_TDM_IN_LEN_MASK | RT5668_TDM_OUT_LEN_MASK, val); + snd_soc_update_bits(codec, reg, RT5663_TDM_MODE_MASK | + RT5663_TDM_IN_CH_MASK | RT5663_TDM_OUT_CH_MASK | + RT5663_TDM_IN_LEN_MASK | RT5663_TDM_OUT_LEN_MASK, val); return 0; } @@ -2694,8 +2695,8 @@ static int rt5663_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) dev_dbg(codec->dev, "%s ratio = %d\n", __func__, ratio); - if (rt5663->codec_type == CODEC_TYPE_RT5668) - reg = RT5668_TDM_8; + if (rt5663->codec_ver == CODEC_VER_1) + reg = RT5663_TDM_9; else reg = RT5663_TDM_5; @@ -2736,47 +2737,47 @@ static int rt5663_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, - RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK, - RT5668_PWR_FV1 | RT5668_PWR_FV2); + RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK, + RT5663_PWR_FV1 | RT5663_PWR_FV2); break; case SND_SOC_BIAS_PREPARE: - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { snd_soc_update_bits(codec, RT5663_DIG_MISC, - RT5668_DIG_GATE_CTRL_MASK, - RT5668_DIG_GATE_CTRL_EN); + RT5663_DIG_GATE_CTRL_MASK, + RT5663_DIG_GATE_CTRL_EN); snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, - RT5668_EN_ANA_CLK_DET_MASK | - RT5668_PWR_CLK_DET_MASK, - RT5668_EN_ANA_CLK_DET_AUTO | - RT5668_PWR_CLK_DET_EN); + RT5663_EN_ANA_CLK_DET_MASK | + RT5663_PWR_CLK_DET_MASK, + RT5663_EN_ANA_CLK_DET_AUTO | + RT5663_PWR_CLK_DET_EN); } break; case SND_SOC_BIAS_STANDBY: - if (rt5663->codec_type == CODEC_TYPE_RT5668) + if (rt5663->codec_ver == CODEC_VER_1) snd_soc_update_bits(codec, RT5663_DIG_MISC, - RT5668_DIG_GATE_CTRL_MASK, - RT5668_DIG_GATE_CTRL_DIS); + RT5663_DIG_GATE_CTRL_MASK, + RT5663_DIG_GATE_CTRL_DIS); snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, - RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | - RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK | - RT5668_PWR_MB_MASK, RT5668_PWR_VREF1 | - RT5668_PWR_VREF2 | RT5668_PWR_MB); + RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK | + RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK | + RT5663_PWR_MB_MASK, RT5663_PWR_VREF1 | + RT5663_PWR_VREF2 | RT5663_PWR_MB); usleep_range(10000, 10005); - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, - RT5668_EN_ANA_CLK_DET_MASK | - RT5668_PWR_CLK_DET_MASK, - RT5668_EN_ANA_CLK_DET_DIS | - RT5668_PWR_CLK_DET_DIS); + RT5663_EN_ANA_CLK_DET_MASK | + RT5663_PWR_CLK_DET_MASK, + RT5663_EN_ANA_CLK_DET_DIS | + RT5663_PWR_CLK_DET_DIS); } break; case SND_SOC_BIAS_OFF: snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, - RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | - RT5668_PWR_FV1 | RT5668_PWR_FV2, 0x0); + RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK | + RT5663_PWR_FV1 | RT5663_PWR_FV2, 0x0); break; default: @@ -2793,18 +2794,18 @@ static int rt5663_probe(struct snd_soc_codec *codec) rt5663->codec = codec; - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: snd_soc_dapm_new_controls(dapm, - rt5668_specific_dapm_widgets, - ARRAY_SIZE(rt5668_specific_dapm_widgets)); + rt5663_v2_specific_dapm_widgets, + ARRAY_SIZE(rt5663_v2_specific_dapm_widgets)); snd_soc_dapm_add_routes(dapm, - rt5668_specific_dapm_routes, - ARRAY_SIZE(rt5668_specific_dapm_routes)); - snd_soc_add_codec_controls(codec, rt5668_specific_controls, - ARRAY_SIZE(rt5668_specific_controls)); + rt5663_v2_specific_dapm_routes, + ARRAY_SIZE(rt5663_v2_specific_dapm_routes)); + snd_soc_add_codec_controls(codec, rt5663_v2_specific_controls, + ARRAY_SIZE(rt5663_v2_specific_controls)); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: snd_soc_dapm_new_controls(dapm, rt5663_specific_dapm_widgets, ARRAY_SIZE(rt5663_specific_dapm_widgets)); @@ -2905,16 +2906,16 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5663 = { } }; -static const struct regmap_config rt5668_regmap = { +static const struct regmap_config rt5663_v2_regmap = { .reg_bits = 16, .val_bits = 16, .use_single_rw = true, .max_register = 0x07fa, - .volatile_reg = rt5668_volatile_register, - .readable_reg = rt5668_readable_register, + .volatile_reg = rt5663_v2_volatile_register, + .readable_reg = rt5663_v2_readable_register, .cache_type = REGCACHE_RBTREE, - .reg_defaults = rt5668_reg, - .num_reg_defaults = ARRAY_SIZE(rt5668_reg), + .reg_defaults = rt5663_v2_reg, + .num_reg_defaults = ARRAY_SIZE(rt5663_v2_reg), }; static const struct regmap_config rt5663_regmap = { @@ -2939,7 +2940,6 @@ static const struct regmap_config temp_regmap = { }; static const struct i2c_device_id rt5663_i2c_id[] = { - { "rt5668", 0 }, { "rt5663", 0 }, {} }; @@ -2947,7 +2947,6 @@ MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id); #if defined(CONFIG_OF) static const struct of_device_id rt5663_of_match[] = { - { .compatible = "realtek,rt5668", }, { .compatible = "realtek,rt5663", }, {}, }; @@ -2956,80 +2955,79 @@ MODULE_DEVICE_TABLE(of, rt5663_of_match); #ifdef CONFIG_ACPI static struct acpi_device_id rt5663_acpi_match[] = { - { "10EC5668", 0}, { "10EC5663", 0}, {}, }; MODULE_DEVICE_TABLE(acpi, rt5663_acpi_match); #endif -static void rt5668_calibrate(struct rt5663_priv *rt5668) +static void rt5663_v2_calibrate(struct rt5663_priv *rt5663) { - regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0xa402); - regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x0100); - regmap_write(rt5668->regmap, RT5663_RECMIX, 0x4040); - regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x0001); - regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0380); - regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); - regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1000); - regmap_write(rt5668->regmap, RT5663_CHOP_DAC_L, 0x3030); - regmap_write(rt5668->regmap, RT5663_CALIB_ADC, 0x3c05); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa23e); + regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402); + regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x0100); + regmap_write(rt5663->regmap, RT5663_RECMIX, 0x4040); + regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x0001); + regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0380); + regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000); + regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1000); + regmap_write(rt5663->regmap, RT5663_CHOP_DAC_L, 0x3030); + regmap_write(rt5663->regmap, RT5663_CALIB_ADC, 0x3c05); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa23e); msleep(40); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf23e); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x0321); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0xfc00); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23e); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x0321); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0xfc00); msleep(500); } -static void rt5663_calibrate(struct rt5663_priv *rt5668) +static void rt5663_calibrate(struct rt5663_priv *rt5663) { int value, count; - regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0280); - regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); - regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x8001); - regmap_write(rt5668->regmap, RT5663_VREF_RECMIX, 0x0032); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa2be); + regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0280); + regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000); + regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001); + regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be); msleep(20); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf2be); - regmap_write(rt5668->regmap, RT5663_PWR_DIG_2, 0x8400); - regmap_write(rt5668->regmap, RT5663_CHOP_ADC, 0x3000); - regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); - regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x8df8); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_2, 0x0003); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_3, 0x018c); - regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1111); - regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_1, 0xffff); - regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_2, 0xffff); - regmap_write(rt5668->regmap, RT5663_DEPOP_2, 0x3003); - regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); - regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); - regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371); - regmap_write(rt5668->regmap, RT5663_DACREF_LDO, 0x3b0b); - regmap_write(rt5668->regmap, RT5663_STO_DAC_MIXER, 0x2080); - regmap_write(rt5668->regmap, RT5663_BYPASS_STO_DAC, 0x000c); - regmap_write(rt5668->regmap, RT5663_HP_BIAS, 0xabba); - regmap_write(rt5668->regmap, RT5663_CHARGE_PUMP_1, 0x2224); - regmap_write(rt5668->regmap, RT5663_HP_OUT_EN, 0x8088); - regmap_write(rt5668->regmap, RT5663_STO_DRE_9, 0x0017); - regmap_write(rt5668->regmap, RT5663_STO_DRE_10, 0x0017); - regmap_write(rt5668->regmap, RT5663_STO1_ADC_MIXER, 0x4040); - regmap_write(rt5668->regmap, RT5663_RECMIX, 0x0005); - regmap_write(rt5668->regmap, RT5663_ADDA_RST, 0xc000); - regmap_write(rt5668->regmap, RT5663_STO1_HPF_ADJ1, 0x3320); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x00c9); - regmap_write(rt5668->regmap, RT5663_DUMMY_1, 0x004c); - regmap_write(rt5668->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766); - regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0x4702); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be); + regmap_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400); + regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000); + regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b); + regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0003); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c); + regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1111); + regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_1, 0xffff); + regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_2, 0xffff); + regmap_write(rt5663->regmap, RT5663_DEPOP_2, 0x3003); + regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b); + regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); + regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371); + regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b); + regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x2080); + regmap_write(rt5663->regmap, RT5663_BYPASS_STO_DAC, 0x000c); + regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xabba); + regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_1, 0x2224); + regmap_write(rt5663->regmap, RT5663_HP_OUT_EN, 0x8088); + regmap_write(rt5663->regmap, RT5663_STO_DRE_9, 0x0017); + regmap_write(rt5663->regmap, RT5663_STO_DRE_10, 0x0017); + regmap_write(rt5663->regmap, RT5663_STO1_ADC_MIXER, 0x4040); + regmap_write(rt5663->regmap, RT5663_RECMIX, 0x0005); + regmap_write(rt5663->regmap, RT5663_ADDA_RST, 0xc000); + regmap_write(rt5663->regmap, RT5663_STO1_HPF_ADJ1, 0x3320); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x00c9); + regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x004c); + regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766); + regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4702); msleep(200); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0x0069); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_3, 0x06c2); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0x7b00); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0xfb00); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0x0069); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06c2); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x7b00); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xfb00); count = 0; while (true) { - regmap_read(rt5668->regmap, RT5663_HP_CALIB_1_1, &value); + regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value); if (value & 0x8000) usleep_range(10000, 10005); else @@ -3066,17 +3064,17 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, } regmap_read(regmap, RT5663_VENDOR_ID_2, &val); switch (val) { - case RT5668_DEVICE_ID: - rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5668_regmap); - rt5663->codec_type = CODEC_TYPE_RT5668; + case RT5663_DEVICE_ID_2: + rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_v2_regmap); + rt5663->codec_ver = CODEC_VER_1; break; - case RT5663_DEVICE_ID: + case RT5663_DEVICE_ID_1: rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_regmap); - rt5663->codec_type = CODEC_TYPE_RT5663; + rt5663->codec_ver = CODEC_VER_0; break; default: dev_err(&i2c->dev, - "Device with ID register %#x is not rt5663 or rt5668\n", + "Device with ID register %#x is not rt5663\n", val); return -ENODEV; } @@ -3091,11 +3089,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, /* reset and calibrate */ regmap_write(rt5663->regmap, RT5663_RESET, 0); regcache_cache_bypass(rt5663->regmap, true); - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - rt5668_calibrate(rt5663); + switch (rt5663->codec_ver) { + case CODEC_VER_1: + rt5663_v2_calibrate(rt5663); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: rt5663_calibrate(rt5663); break; default: @@ -3106,46 +3104,55 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, dev_dbg(&i2c->dev, "calibrate done\n"); /* GPIO1 as IRQ */ - regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5668_GP1_PIN_MASK, - RT5668_GP1_PIN_IRQ); + regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5663_GP1_PIN_MASK, + RT5663_GP1_PIN_IRQ); /* 4btn inline command debounce */ regmap_update_bits(rt5663->regmap, RT5663_IL_CMD_5, - RT5668_4BTN_CLK_DEB_MASK, RT5668_4BTN_CLK_DEB_65MS); + RT5663_4BTN_CLK_DEB_MASK, RT5663_4BTN_CLK_DEB_65MS); - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402); /* JD1 */ regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, - RT5668_IRQ_POW_SAV_MASK | RT5668_IRQ_POW_SAV_JD1_MASK, - RT5668_IRQ_POW_SAV_EN | RT5668_IRQ_POW_SAV_JD1_EN); + RT5663_IRQ_POW_SAV_MASK | RT5663_IRQ_POW_SAV_JD1_MASK, + RT5663_IRQ_POW_SAV_EN | RT5663_IRQ_POW_SAV_JD1_EN); regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_2, - RT5668_PWR_JD1_MASK, RT5668_PWR_JD1); + RT5663_PWR_JD1_MASK, RT5663_PWR_JD1); regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, - RT5668_EN_CB_JD_MASK, RT5668_EN_CB_JD_EN); + RT5663_EN_CB_JD_MASK, RT5663_EN_CB_JD_EN); regmap_update_bits(rt5663->regmap, RT5663_HP_LOGIC_2, - RT5668_HP_SIG_SRC1_MASK, RT5668_HP_SIG_SRC1_REG); + RT5663_HP_SIG_SRC1_MASK, RT5663_HP_SIG_SRC1_REG); regmap_update_bits(rt5663->regmap, RT5663_RECMIX, - RT5668_VREF_BIAS_MASK | RT5668_CBJ_DET_MASK | - RT5668_DET_TYPE_MASK, RT5668_VREF_BIAS_REG | - RT5668_CBJ_DET_EN | RT5668_DET_TYPE_QFN); + RT5663_VREF_BIAS_MASK | RT5663_CBJ_DET_MASK | + RT5663_DET_TYPE_MASK, RT5663_VREF_BIAS_REG | + RT5663_CBJ_DET_EN | RT5663_DET_TYPE_QFN); /* Set GPIO4 and GPIO8 as input for combo jack */ regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, - RT5668_GP4_PIN_CONF_MASK, RT5668_GP4_PIN_CONF_INPUT); - regmap_update_bits(rt5663->regmap, RT5668_GPIO_3, - RT5668_GP8_PIN_CONF_MASK, RT5668_GP8_PIN_CONF_INPUT); + RT5663_GP4_PIN_CONF_MASK, RT5663_GP4_PIN_CONF_INPUT); + regmap_update_bits(rt5663->regmap, RT5663_GPIO_3, + RT5663_GP8_PIN_CONF_MASK, RT5663_GP8_PIN_CONF_INPUT); regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_1, - RT5668_LDO1_DVO_MASK | RT5668_AMP_HP_MASK, - RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); + RT5663_LDO1_DVO_MASK | RT5663_AMP_HP_MASK, + RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: + regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC, + RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN); + regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, + RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN); + regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, + RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); + regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, + RT5663_GPIO1_TYPE_MASK, RT5663_GPIO1_TYPE_EN); regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032); regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be); msleep(20); regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be); regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, - RT5663_GP1_PIN_CONF_MASK, RT5663_GP1_PIN_CONF_OUTPUT); + RT5663_GP1_PIN_CONF_MASK | RT5663_SEL_GPIO1_MASK, + RT5663_GP1_PIN_CONF_OUTPUT | RT5663_SEL_GPIO1_EN); /* DACREF LDO control */ regmap_update_bits(rt5663->regmap, RT5663_DACREF_LDO, 0x3e0e, 0x3a0a); diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h index 2cc8f28080f6..d77fae619f2f 100644 --- a/sound/soc/codecs/rt5663.h +++ b/sound/soc/codecs/rt5663.h @@ -18,655 +18,652 @@ #define RT5663_VENDOR_ID_1 0x00fe #define RT5663_VENDOR_ID_2 0x00ff -#define RT5668_LOUT_CTRL 0x0001 -#define RT5668_HP_AMP_2 0x0003 -#define RT5668_MONO_OUT 0x0004 -#define RT5668_MONO_GAIN 0x0007 - -#define RT5668_AEC_BST 0x000b -#define RT5668_IN1_IN2 0x000c -#define RT5668_IN3_IN4 0x000d -#define RT5668_INL1_INR1 0x000f -#define RT5668_CBJ_TYPE_2 0x0011 -#define RT5668_CBJ_TYPE_3 0x0012 -#define RT5668_CBJ_TYPE_4 0x0013 -#define RT5668_CBJ_TYPE_5 0x0014 -#define RT5668_CBJ_TYPE_8 0x0017 +#define RT5663_LOUT_CTRL 0x0001 +#define RT5663_HP_AMP_2 0x0003 +#define RT5663_MONO_OUT 0x0004 +#define RT5663_MONO_GAIN 0x0007 + +#define RT5663_AEC_BST 0x000b +#define RT5663_IN1_IN2 0x000c +#define RT5663_IN3_IN4 0x000d +#define RT5663_INL1_INR1 0x000f +#define RT5663_CBJ_TYPE_2 0x0011 +#define RT5663_CBJ_TYPE_3 0x0012 +#define RT5663_CBJ_TYPE_4 0x0013 +#define RT5663_CBJ_TYPE_5 0x0014 +#define RT5663_CBJ_TYPE_8 0x0017 /* I/O - ADC/DAC/DMIC */ -#define RT5668_DAC3_DIG_VOL 0x001a -#define RT5668_DAC3_CTRL 0x001b -#define RT5668_MONO_ADC_DIG_VOL 0x001d -#define RT5668_STO2_ADC_DIG_VOL 0x001e -#define RT5668_MONO_ADC_BST_GAIN 0x0020 -#define RT5668_STO2_ADC_BST_GAIN 0x0021 -#define RT5668_SIDETONE_CTRL 0x0024 +#define RT5663_DAC3_DIG_VOL 0x001a +#define RT5663_DAC3_CTRL 0x001b +#define RT5663_MONO_ADC_DIG_VOL 0x001d +#define RT5663_STO2_ADC_DIG_VOL 0x001e +#define RT5663_MONO_ADC_BST_GAIN 0x0020 +#define RT5663_STO2_ADC_BST_GAIN 0x0021 +#define RT5663_SIDETONE_CTRL 0x0024 /* Mixer - D-D */ -#define RT5668_MONO1_ADC_MIXER 0x0027 -#define RT5668_STO2_ADC_MIXER 0x0028 -#define RT5668_MONO_DAC_MIXER 0x002b -#define RT5668_DAC2_SRC_CTRL 0x002e -#define RT5668_IF_3_4_DATA_CTL 0x002f -#define RT5668_IF_5_DATA_CTL 0x0030 -#define RT5668_PDM_OUT_CTL 0x0031 -#define RT5668_PDM_I2C_DATA_CTL1 0x0032 -#define RT5668_PDM_I2C_DATA_CTL2 0x0033 -#define RT5668_PDM_I2C_DATA_CTL3 0x0034 -#define RT5668_PDM_I2C_DATA_CTL4 0x0035 +#define RT5663_MONO1_ADC_MIXER 0x0027 +#define RT5663_STO2_ADC_MIXER 0x0028 +#define RT5663_MONO_DAC_MIXER 0x002b +#define RT5663_DAC2_SRC_CTRL 0x002e +#define RT5663_IF_3_4_DATA_CTL 0x002f +#define RT5663_IF_5_DATA_CTL 0x0030 +#define RT5663_PDM_OUT_CTL 0x0031 +#define RT5663_PDM_I2C_DATA_CTL1 0x0032 +#define RT5663_PDM_I2C_DATA_CTL2 0x0033 +#define RT5663_PDM_I2C_DATA_CTL3 0x0034 +#define RT5663_PDM_I2C_DATA_CTL4 0x0035 /*Mixer - Analog*/ -#define RT5668_RECMIX1_NEW 0x003a -#define RT5668_RECMIX1L_0 0x003b -#define RT5668_RECMIX1L 0x003c -#define RT5668_RECMIX1R_0 0x003d -#define RT5668_RECMIX1R 0x003e -#define RT5668_RECMIX2_NEW 0x003f -#define RT5668_RECMIX2_L_2 0x0041 -#define RT5668_RECMIX2_R 0x0042 -#define RT5668_RECMIX2_R_2 0x0043 -#define RT5668_CALIB_REC_LR 0x0044 -#define RT5668_ALC_BK_GAIN 0x0049 -#define RT5668_MONOMIX_GAIN 0x004a -#define RT5668_MONOMIX_IN_GAIN 0x004b -#define RT5668_OUT_MIXL_GAIN 0x004d -#define RT5668_OUT_LMIX_IN_GAIN 0x004e -#define RT5668_OUT_RMIX_IN_GAIN 0x004f -#define RT5668_OUT_RMIX_IN_GAIN1 0x0050 -#define RT5668_LOUT_MIXER_CTRL 0x0052 +#define RT5663_RECMIX1_NEW 0x003a +#define RT5663_RECMIX1L_0 0x003b +#define RT5663_RECMIX1L 0x003c +#define RT5663_RECMIX1R_0 0x003d +#define RT5663_RECMIX1R 0x003e +#define RT5663_RECMIX2_NEW 0x003f +#define RT5663_RECMIX2_L_2 0x0041 +#define RT5663_RECMIX2_R 0x0042 +#define RT5663_RECMIX2_R_2 0x0043 +#define RT5663_CALIB_REC_LR 0x0044 +#define RT5663_ALC_BK_GAIN 0x0049 +#define RT5663_MONOMIX_GAIN 0x004a +#define RT5663_MONOMIX_IN_GAIN 0x004b +#define RT5663_OUT_MIXL_GAIN 0x004d +#define RT5663_OUT_LMIX_IN_GAIN 0x004e +#define RT5663_OUT_RMIX_IN_GAIN 0x004f +#define RT5663_OUT_RMIX_IN_GAIN1 0x0050 +#define RT5663_LOUT_MIXER_CTRL 0x0052 /* Power */ -#define RT5668_PWR_VOL 0x0067 +#define RT5663_PWR_VOL 0x0067 -#define RT5668_ADCDAC_RST 0x006d +#define RT5663_ADCDAC_RST 0x006d /* Format - ADC/DAC */ -#define RT5668_I2S34_SDP 0x0071 -#define RT5668_I2S5_SDP 0x0072 -/* Format - TDM Control */ -#define RT5668_TDM_5 0x007c -#define RT5668_TDM_6 0x007d -#define RT5668_TDM_7 0x007e -#define RT5668_TDM_8 0x007f +#define RT5663_I2S34_SDP 0x0071 +#define RT5663_I2S5_SDP 0x0072 /* Function - Analog */ -#define RT5668_ASRC_3 0x0085 -#define RT5668_ASRC_6 0x0088 -#define RT5668_ASRC_7 0x0089 -#define RT5668_PLL_TRK_13 0x0099 -#define RT5668_I2S_M_CLK_CTL 0x00a0 -#define RT5668_FDIV_I2S34_M_CLK 0x00a1 -#define RT5668_FDIV_I2S34_M_CLK2 0x00a2 -#define RT5668_FDIV_I2S5_M_CLK 0x00a3 -#define RT5668_FDIV_I2S5_M_CLK2 0x00a4 +#define RT5663_ASRC_3 0x0085 +#define RT5663_ASRC_6 0x0088 +#define RT5663_ASRC_7 0x0089 +#define RT5663_PLL_TRK_13 0x0099 +#define RT5663_I2S_M_CLK_CTL 0x00a0 +#define RT5663_FDIV_I2S34_M_CLK 0x00a1 +#define RT5663_FDIV_I2S34_M_CLK2 0x00a2 +#define RT5663_FDIV_I2S5_M_CLK 0x00a3 +#define RT5663_FDIV_I2S5_M_CLK2 0x00a4 /* Function - Digital */ -#define RT5668_IRQ_4 0x00b9 -#define RT5668_GPIO_3 0x00c2 -#define RT5668_GPIO_4 0x00c3 -#define RT5668_GPIO_STA 0x00c4 -#define RT5668_HP_AMP_DET1 0x00d0 -#define RT5668_HP_AMP_DET2 0x00d1 -#define RT5668_HP_AMP_DET3 0x00d2 -#define RT5668_MID_BD_HP_AMP 0x00d3 -#define RT5668_LOW_BD_HP_AMP 0x00d4 -#define RT5668_SOF_VOL_ZC2 0x00da -#define RT5668_ADC_STO2_ADJ1 0x00ee -#define RT5668_ADC_STO2_ADJ2 0x00ef +#define RT5663_V2_IRQ_4 0x00b9 +#define RT5663_GPIO_3 0x00c2 +#define RT5663_GPIO_4 0x00c3 +#define RT5663_GPIO_STA2 0x00c4 +#define RT5663_HP_AMP_DET1 0x00d0 +#define RT5663_HP_AMP_DET2 0x00d1 +#define RT5663_HP_AMP_DET3 0x00d2 +#define RT5663_MID_BD_HP_AMP 0x00d3 +#define RT5663_LOW_BD_HP_AMP 0x00d4 +#define RT5663_SOF_VOL_ZC2 0x00da +#define RT5663_ADC_STO2_ADJ1 0x00ee +#define RT5663_ADC_STO2_ADJ2 0x00ef /* General Control */ -#define RT5668_A_JD_CTRL 0x00f0 -#define RT5668_JD1_TRES_CTRL 0x00f1 -#define RT5668_JD2_TRES_CTRL 0x00f2 -#define RT5668_JD_CTRL2 0x00f7 -#define RT5668_DUM_REG_2 0x00fb -#define RT5668_DUM_REG_3 0x00fc - - -#define RT5668_DACADC_DIG_VOL2 0x0101 -#define RT5668_DIG_IN_PIN2 0x0133 -#define RT5668_PAD_DRV_CTL1 0x0136 -#define RT5668_SOF_RAM_DEPOP 0x0138 -#define RT5668_VOL_TEST 0x013f -#define RT5668_TEST_MODE_3 0x0147 -#define RT5668_TEST_MODE_4 0x0148 -#define RT5668_MONO_DYNA_1 0x0170 -#define RT5668_MONO_DYNA_2 0x0171 -#define RT5668_MONO_DYNA_3 0x0172 -#define RT5668_MONO_DYNA_4 0x0173 -#define RT5668_MONO_DYNA_5 0x0174 -#define RT5668_MONO_DYNA_6 0x0175 -#define RT5668_STO1_SIL_DET 0x0190 -#define RT5668_MONOL_SIL_DET 0x0191 -#define RT5668_MONOR_SIL_DET 0x0192 -#define RT5668_STO2_DAC_SIL 0x0193 -#define RT5668_PWR_SAV_CTL1 0x0194 -#define RT5668_PWR_SAV_CTL2 0x0195 -#define RT5668_PWR_SAV_CTL3 0x0196 -#define RT5668_PWR_SAV_CTL4 0x0197 -#define RT5668_PWR_SAV_CTL5 0x0198 -#define RT5668_PWR_SAV_CTL6 0x0199 -#define RT5668_MONO_AMP_CAL1 0x01a0 -#define RT5668_MONO_AMP_CAL2 0x01a1 -#define RT5668_MONO_AMP_CAL3 0x01a2 -#define RT5668_MONO_AMP_CAL4 0x01a3 -#define RT5668_MONO_AMP_CAL5 0x01a4 -#define RT5668_MONO_AMP_CAL6 0x01a5 -#define RT5668_MONO_AMP_CAL7 0x01a6 -#define RT5668_MONO_AMP_CAL_ST1 0x01a7 -#define RT5668_MONO_AMP_CAL_ST2 0x01a8 -#define RT5668_MONO_AMP_CAL_ST3 0x01a9 -#define RT5668_MONO_AMP_CAL_ST4 0x01aa -#define RT5668_MONO_AMP_CAL_ST5 0x01ab -#define RT5668_HP_IMP_SEN_13 0x01b9 -#define RT5668_HP_IMP_SEN_14 0x01ba -#define RT5668_HP_IMP_SEN_6 0x01bb -#define RT5668_HP_IMP_SEN_7 0x01bc -#define RT5668_HP_IMP_SEN_8 0x01bd -#define RT5668_HP_IMP_SEN_9 0x01be -#define RT5668_HP_IMP_SEN_10 0x01bf -#define RT5668_HP_LOGIC_3 0x01dc -#define RT5668_HP_CALIB_ST10 0x01f3 -#define RT5668_HP_CALIB_ST11 0x01f4 -#define RT5668_PRO_REG_TBL_4 0x0203 -#define RT5668_PRO_REG_TBL_5 0x0204 -#define RT5668_PRO_REG_TBL_6 0x0205 -#define RT5668_PRO_REG_TBL_7 0x0206 -#define RT5668_PRO_REG_TBL_8 0x0207 -#define RT5668_PRO_REG_TBL_9 0x0208 -#define RT5668_SAR_ADC_INL_1 0x0210 -#define RT5668_SAR_ADC_INL_2 0x0211 -#define RT5668_SAR_ADC_INL_3 0x0212 -#define RT5668_SAR_ADC_INL_4 0x0213 -#define RT5668_SAR_ADC_INL_5 0x0214 -#define RT5668_SAR_ADC_INL_6 0x0215 -#define RT5668_SAR_ADC_INL_7 0x0216 -#define RT5668_SAR_ADC_INL_8 0x0217 -#define RT5668_SAR_ADC_INL_9 0x0218 -#define RT5668_SAR_ADC_INL_10 0x0219 -#define RT5668_SAR_ADC_INL_11 0x021a -#define RT5668_SAR_ADC_INL_12 0x021b -#define RT5668_DRC_CTRL_1 0x02ff -#define RT5668_DRC1_CTRL_2 0x0301 -#define RT5668_DRC1_CTRL_3 0x0302 -#define RT5668_DRC1_CTRL_4 0x0303 -#define RT5668_DRC1_CTRL_5 0x0304 -#define RT5668_DRC1_CTRL_6 0x0305 -#define RT5668_DRC1_HD_CTRL_1 0x0306 -#define RT5668_DRC1_HD_CTRL_2 0x0307 -#define RT5668_DRC1_PRI_REG_1 0x0310 -#define RT5668_DRC1_PRI_REG_2 0x0311 -#define RT5668_DRC1_PRI_REG_3 0x0312 -#define RT5668_DRC1_PRI_REG_4 0x0313 -#define RT5668_DRC1_PRI_REG_5 0x0314 -#define RT5668_DRC1_PRI_REG_6 0x0315 -#define RT5668_DRC1_PRI_REG_7 0x0316 -#define RT5668_DRC1_PRI_REG_8 0x0317 -#define RT5668_ALC_PGA_CTL_1 0x0330 -#define RT5668_ALC_PGA_CTL_2 0x0331 -#define RT5668_ALC_PGA_CTL_3 0x0332 -#define RT5668_ALC_PGA_CTL_4 0x0333 -#define RT5668_ALC_PGA_CTL_5 0x0334 -#define RT5668_ALC_PGA_CTL_6 0x0335 -#define RT5668_ALC_PGA_CTL_7 0x0336 -#define RT5668_ALC_PGA_CTL_8 0x0337 -#define RT5668_ALC_PGA_REG_1 0x0338 -#define RT5668_ALC_PGA_REG_2 0x0339 -#define RT5668_ALC_PGA_REG_3 0x033a -#define RT5668_ADC_EQ_RECOV_1 0x03c0 -#define RT5668_ADC_EQ_RECOV_2 0x03c1 -#define RT5668_ADC_EQ_RECOV_3 0x03c2 -#define RT5668_ADC_EQ_RECOV_4 0x03c3 -#define RT5668_ADC_EQ_RECOV_5 0x03c4 -#define RT5668_ADC_EQ_RECOV_6 0x03c5 -#define RT5668_ADC_EQ_RECOV_7 0x03c6 -#define RT5668_ADC_EQ_RECOV_8 0x03c7 -#define RT5668_ADC_EQ_RECOV_9 0x03c8 -#define RT5668_ADC_EQ_RECOV_10 0x03c9 -#define RT5668_ADC_EQ_RECOV_11 0x03ca -#define RT5668_ADC_EQ_RECOV_12 0x03cb -#define RT5668_ADC_EQ_RECOV_13 0x03cc -#define RT5668_VID_HIDDEN 0x03fe -#define RT5668_VID_CUSTOMER 0x03ff -#define RT5668_SCAN_MODE 0x07f0 -#define RT5668_I2C_BYPA 0x07fa +#define RT5663_A_JD_CTRL 0x00f0 +#define RT5663_JD1_TRES_CTRL 0x00f1 +#define RT5663_JD2_TRES_CTRL 0x00f2 +#define RT5663_V2_JD_CTRL2 0x00f7 +#define RT5663_DUM_REG_2 0x00fb +#define RT5663_DUM_REG_3 0x00fc + + +#define RT5663_DACADC_DIG_VOL2 0x0101 +#define RT5663_DIG_IN_PIN2 0x0133 +#define RT5663_PAD_DRV_CTL1 0x0136 +#define RT5663_SOF_RAM_DEPOP 0x0138 +#define RT5663_VOL_TEST 0x013f +#define RT5663_MONO_DYNA_1 0x0170 +#define RT5663_MONO_DYNA_2 0x0171 +#define RT5663_MONO_DYNA_3 0x0172 +#define RT5663_MONO_DYNA_4 0x0173 +#define RT5663_MONO_DYNA_5 0x0174 +#define RT5663_MONO_DYNA_6 0x0175 +#define RT5663_STO1_SIL_DET 0x0190 +#define RT5663_MONOL_SIL_DET 0x0191 +#define RT5663_MONOR_SIL_DET 0x0192 +#define RT5663_STO2_DAC_SIL 0x0193 +#define RT5663_PWR_SAV_CTL1 0x0194 +#define RT5663_PWR_SAV_CTL2 0x0195 +#define RT5663_PWR_SAV_CTL3 0x0196 +#define RT5663_PWR_SAV_CTL4 0x0197 +#define RT5663_PWR_SAV_CTL5 0x0198 +#define RT5663_PWR_SAV_CTL6 0x0199 +#define RT5663_MONO_AMP_CAL1 0x01a0 +#define RT5663_MONO_AMP_CAL2 0x01a1 +#define RT5663_MONO_AMP_CAL3 0x01a2 +#define RT5663_MONO_AMP_CAL4 0x01a3 +#define RT5663_MONO_AMP_CAL5 0x01a4 +#define RT5663_MONO_AMP_CAL6 0x01a5 +#define RT5663_MONO_AMP_CAL7 0x01a6 +#define RT5663_MONO_AMP_CAL_ST1 0x01a7 +#define RT5663_MONO_AMP_CAL_ST2 0x01a8 +#define RT5663_MONO_AMP_CAL_ST3 0x01a9 +#define RT5663_MONO_AMP_CAL_ST4 0x01aa +#define RT5663_MONO_AMP_CAL_ST5 0x01ab +#define RT5663_V2_HP_IMP_SEN_13 0x01b9 +#define RT5663_V2_HP_IMP_SEN_14 0x01ba +#define RT5663_V2_HP_IMP_SEN_6 0x01bb +#define RT5663_V2_HP_IMP_SEN_7 0x01bc +#define RT5663_V2_HP_IMP_SEN_8 0x01bd +#define RT5663_V2_HP_IMP_SEN_9 0x01be +#define RT5663_V2_HP_IMP_SEN_10 0x01bf +#define RT5663_HP_LOGIC_3 0x01dc +#define RT5663_HP_CALIB_ST10 0x01f3 +#define RT5663_HP_CALIB_ST11 0x01f4 +#define RT5663_PRO_REG_TBL_4 0x0203 +#define RT5663_PRO_REG_TBL_5 0x0204 +#define RT5663_PRO_REG_TBL_6 0x0205 +#define RT5663_PRO_REG_TBL_7 0x0206 +#define RT5663_PRO_REG_TBL_8 0x0207 +#define RT5663_PRO_REG_TBL_9 0x0208 +#define RT5663_SAR_ADC_INL_1 0x0210 +#define RT5663_SAR_ADC_INL_2 0x0211 +#define RT5663_SAR_ADC_INL_3 0x0212 +#define RT5663_SAR_ADC_INL_4 0x0213 +#define RT5663_SAR_ADC_INL_5 0x0214 +#define RT5663_SAR_ADC_INL_6 0x0215 +#define RT5663_SAR_ADC_INL_7 0x0216 +#define RT5663_SAR_ADC_INL_8 0x0217 +#define RT5663_SAR_ADC_INL_9 0x0218 +#define RT5663_SAR_ADC_INL_10 0x0219 +#define RT5663_SAR_ADC_INL_11 0x021a +#define RT5663_SAR_ADC_INL_12 0x021b +#define RT5663_DRC_CTRL_1 0x02ff +#define RT5663_DRC1_CTRL_2 0x0301 +#define RT5663_DRC1_CTRL_3 0x0302 +#define RT5663_DRC1_CTRL_4 0x0303 +#define RT5663_DRC1_CTRL_5 0x0304 +#define RT5663_DRC1_CTRL_6 0x0305 +#define RT5663_DRC1_HD_CTRL_1 0x0306 +#define RT5663_DRC1_HD_CTRL_2 0x0307 +#define RT5663_DRC1_PRI_REG_1 0x0310 +#define RT5663_DRC1_PRI_REG_2 0x0311 +#define RT5663_DRC1_PRI_REG_3 0x0312 +#define RT5663_DRC1_PRI_REG_4 0x0313 +#define RT5663_DRC1_PRI_REG_5 0x0314 +#define RT5663_DRC1_PRI_REG_6 0x0315 +#define RT5663_DRC1_PRI_REG_7 0x0316 +#define RT5663_DRC1_PRI_REG_8 0x0317 +#define RT5663_ALC_PGA_CTL_1 0x0330 +#define RT5663_ALC_PGA_CTL_2 0x0331 +#define RT5663_ALC_PGA_CTL_3 0x0332 +#define RT5663_ALC_PGA_CTL_4 0x0333 +#define RT5663_ALC_PGA_CTL_5 0x0334 +#define RT5663_ALC_PGA_CTL_6 0x0335 +#define RT5663_ALC_PGA_CTL_7 0x0336 +#define RT5663_ALC_PGA_CTL_8 0x0337 +#define RT5663_ALC_PGA_REG_1 0x0338 +#define RT5663_ALC_PGA_REG_2 0x0339 +#define RT5663_ALC_PGA_REG_3 0x033a +#define RT5663_ADC_EQ_RECOV_1 0x03c0 +#define RT5663_ADC_EQ_RECOV_2 0x03c1 +#define RT5663_ADC_EQ_RECOV_3 0x03c2 +#define RT5663_ADC_EQ_RECOV_4 0x03c3 +#define RT5663_ADC_EQ_RECOV_5 0x03c4 +#define RT5663_ADC_EQ_RECOV_6 0x03c5 +#define RT5663_ADC_EQ_RECOV_7 0x03c6 +#define RT5663_ADC_EQ_RECOV_8 0x03c7 +#define RT5663_ADC_EQ_RECOV_9 0x03c8 +#define RT5663_ADC_EQ_RECOV_10 0x03c9 +#define RT5663_ADC_EQ_RECOV_11 0x03ca +#define RT5663_ADC_EQ_RECOV_12 0x03cb +#define RT5663_ADC_EQ_RECOV_13 0x03cc +#define RT5663_VID_HIDDEN 0x03fe +#define RT5663_VID_CUSTOMER 0x03ff +#define RT5663_SCAN_MODE 0x07f0 +#define RT5663_I2C_BYPA 0x07fa /* Headphone Amp Control 2 (0x0003) */ -#define RT5668_EN_DAC_HPO_MASK (0x1 << 14) -#define RT5668_EN_DAC_HPO_SHIFT 14 -#define RT5668_EN_DAC_HPO_DIS (0x0 << 14) -#define RT5668_EN_DAC_HPO_EN (0x1 << 14) +#define RT5663_EN_DAC_HPO_MASK (0x1 << 14) +#define RT5663_EN_DAC_HPO_SHIFT 14 +#define RT5663_EN_DAC_HPO_DIS (0x0 << 14) +#define RT5663_EN_DAC_HPO_EN (0x1 << 14) /*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ -#define RT5668_GAIN_HP (0x1f << 8) -#define RT5668_GAIN_HP_SHIFT 8 +#define RT5663_GAIN_HP (0x1f << 8) +#define RT5663_GAIN_HP_SHIFT 8 /* AEC BST Control (0x000b) */ -#define RT5668_GAIN_CBJ_MASK (0xf << 8) -#define RT5668_GAIN_CBJ_SHIFT 8 +#define RT5663_GAIN_CBJ_MASK (0xf << 8) +#define RT5663_GAIN_CBJ_SHIFT 8 /* IN1 Control / MIC GND REF (0x000c) */ -#define RT5668_IN1_DF_MASK (0x1 << 15) -#define RT5668_IN1_DF_SHIFT 15 +#define RT5663_IN1_DF_MASK (0x1 << 15) +#define RT5663_IN1_DF_SHIFT 15 /* Combo Jack and Type Detection Control 1 (0x0010) */ -#define RT5668_CBJ_DET_MASK (0x1 << 15) -#define RT5668_CBJ_DET_SHIFT 15 -#define RT5668_CBJ_DET_DIS (0x0 << 15) -#define RT5668_CBJ_DET_EN (0x1 << 15) -#define RT5668_DET_TYPE_MASK (0x1 << 12) -#define RT5668_DET_TYPE_SHIFT 12 -#define RT5668_DET_TYPE_WLCSP (0x0 << 12) -#define RT5668_DET_TYPE_QFN (0x1 << 12) -#define RT5668_VREF_BIAS_MASK (0x1 << 6) -#define RT5668_VREF_BIAS_SHIFT 6 -#define RT5668_VREF_BIAS_FSM (0x0 << 6) -#define RT5668_VREF_BIAS_REG (0x1 << 6) +#define RT5663_CBJ_DET_MASK (0x1 << 15) +#define RT5663_CBJ_DET_SHIFT 15 +#define RT5663_CBJ_DET_DIS (0x0 << 15) +#define RT5663_CBJ_DET_EN (0x1 << 15) +#define RT5663_DET_TYPE_MASK (0x1 << 12) +#define RT5663_DET_TYPE_SHIFT 12 +#define RT5663_DET_TYPE_WLCSP (0x0 << 12) +#define RT5663_DET_TYPE_QFN (0x1 << 12) +#define RT5663_VREF_BIAS_MASK (0x1 << 6) +#define RT5663_VREF_BIAS_SHIFT 6 +#define RT5663_VREF_BIAS_FSM (0x0 << 6) +#define RT5663_VREF_BIAS_REG (0x1 << 6) /* REC Left Mixer Control 2 (0x003c) */ -#define RT5668_RECMIX1L_BST1_CBJ (0x1 << 7) -#define RT5668_RECMIX1L_BST1_CBJ_SHIFT 7 -#define RT5668_RECMIX1L_BST2 (0x1 << 4) -#define RT5668_RECMIX1L_BST2_SHIFT 4 +#define RT5663_RECMIX1L_BST1_CBJ (0x1 << 7) +#define RT5663_RECMIX1L_BST1_CBJ_SHIFT 7 +#define RT5663_RECMIX1L_BST2 (0x1 << 4) +#define RT5663_RECMIX1L_BST2_SHIFT 4 /* REC Right Mixer Control 2 (0x003e) */ -#define RT5668_RECMIX1R_BST2 (0x1 << 4) -#define RT5668_RECMIX1R_BST2_SHIFT 4 +#define RT5663_RECMIX1R_BST2 (0x1 << 4) +#define RT5663_RECMIX1R_BST2_SHIFT 4 /* DAC1 Digital Volume (0x0019) */ -#define RT5668_DAC_L1_VOL_MASK (0xff << 8) -#define RT5668_DAC_L1_VOL_SHIFT 8 -#define RT5668_DAC_R1_VOL_MASK (0xff) -#define RT5668_DAC_R1_VOL_SHIFT 0 +#define RT5663_DAC_L1_VOL_MASK (0xff << 8) +#define RT5663_DAC_L1_VOL_SHIFT 8 +#define RT5663_DAC_R1_VOL_MASK (0xff) +#define RT5663_DAC_R1_VOL_SHIFT 0 /* ADC Digital Volume Control (0x001c) */ -#define RT5668_ADC_L_MUTE_MASK (0x1 << 15) -#define RT5668_ADC_L_MUTE_SHIFT 15 -#define RT5668_ADC_L_VOL_MASK (0x7f << 8) -#define RT5668_ADC_L_VOL_SHIFT 8 -#define RT5668_ADC_R_MUTE_MASK (0x1 << 7) -#define RT5668_ADC_R_MUTE_SHIFT 7 -#define RT5668_ADC_R_VOL_MASK (0x7f) -#define RT5668_ADC_R_VOL_SHIFT 0 +#define RT5663_ADC_L_MUTE_MASK (0x1 << 15) +#define RT5663_ADC_L_MUTE_SHIFT 15 +#define RT5663_ADC_L_VOL_MASK (0x7f << 8) +#define RT5663_ADC_L_VOL_SHIFT 8 +#define RT5663_ADC_R_MUTE_MASK (0x1 << 7) +#define RT5663_ADC_R_MUTE_SHIFT 7 +#define RT5663_ADC_R_VOL_MASK (0x7f) +#define RT5663_ADC_R_VOL_SHIFT 0 /* Stereo ADC Mixer Control (0x0026) */ -#define RT5668_M_STO1_ADC_L1 (0x1 << 15) -#define RT5668_M_STO1_ADC_L1_SHIFT 15 -#define RT5668_M_STO1_ADC_L2 (0x1 << 14) -#define RT5668_M_STO1_ADC_L2_SHIFT 14 -#define RT5668_STO1_ADC_L1_SRC (0x1 << 13) -#define RT5668_STO1_ADC_L1_SRC_SHIFT 13 -#define RT5668_STO1_ADC_L2_SRC (0x1 << 12) -#define RT5668_STO1_ADC_L2_SRC_SHIFT 12 -#define RT5668_STO1_ADC_L_SRC (0x3 << 10) -#define RT5668_STO1_ADC_L_SRC_SHIFT 10 -#define RT5668_M_STO1_ADC_R1 (0x1 << 7) -#define RT5668_M_STO1_ADC_R1_SHIFT 7 -#define RT5668_M_STO1_ADC_R2 (0x1 << 6) -#define RT5668_M_STO1_ADC_R2_SHIFT 6 -#define RT5668_STO1_ADC_R1_SRC (0x1 << 5) -#define RT5668_STO1_ADC_R1_SRC_SHIFT 5 -#define RT5668_STO1_ADC_R2_SRC (0x1 << 4) -#define RT5668_STO1_ADC_R2_SRC_SHIFT 4 -#define RT5668_STO1_ADC_R_SRC (0x3 << 2) -#define RT5668_STO1_ADC_R_SRC_SHIFT 2 +#define RT5663_M_STO1_ADC_L1 (0x1 << 15) +#define RT5663_M_STO1_ADC_L1_SHIFT 15 +#define RT5663_M_STO1_ADC_L2 (0x1 << 14) +#define RT5663_M_STO1_ADC_L2_SHIFT 14 +#define RT5663_STO1_ADC_L1_SRC (0x1 << 13) +#define RT5663_STO1_ADC_L1_SRC_SHIFT 13 +#define RT5663_STO1_ADC_L2_SRC (0x1 << 12) +#define RT5663_STO1_ADC_L2_SRC_SHIFT 12 +#define RT5663_STO1_ADC_L_SRC (0x3 << 10) +#define RT5663_STO1_ADC_L_SRC_SHIFT 10 +#define RT5663_M_STO1_ADC_R1 (0x1 << 7) +#define RT5663_M_STO1_ADC_R1_SHIFT 7 +#define RT5663_M_STO1_ADC_R2 (0x1 << 6) +#define RT5663_M_STO1_ADC_R2_SHIFT 6 +#define RT5663_STO1_ADC_R1_SRC (0x1 << 5) +#define RT5663_STO1_ADC_R1_SRC_SHIFT 5 +#define RT5663_STO1_ADC_R2_SRC (0x1 << 4) +#define RT5663_STO1_ADC_R2_SRC_SHIFT 4 +#define RT5663_STO1_ADC_R_SRC (0x3 << 2) +#define RT5663_STO1_ADC_R_SRC_SHIFT 2 /* ADC Mixer to DAC Mixer Control (0x0029) */ -#define RT5668_M_ADCMIX_L (0x1 << 15) -#define RT5668_M_ADCMIX_L_SHIFT 15 -#define RT5668_M_DAC1_L (0x1 << 14) -#define RT5668_M_DAC1_L_SHIFT 14 -#define RT5668_M_ADCMIX_R (0x1 << 7) -#define RT5668_M_ADCMIX_R_SHIFT 7 -#define RT5668_M_DAC1_R (0x1 << 6) -#define RT5668_M_DAC1_R_SHIFT 6 +#define RT5663_M_ADCMIX_L (0x1 << 15) +#define RT5663_M_ADCMIX_L_SHIFT 15 +#define RT5663_M_DAC1_L (0x1 << 14) +#define RT5663_M_DAC1_L_SHIFT 14 +#define RT5663_M_ADCMIX_R (0x1 << 7) +#define RT5663_M_ADCMIX_R_SHIFT 7 +#define RT5663_M_DAC1_R (0x1 << 6) +#define RT5663_M_DAC1_R_SHIFT 6 /* Stereo DAC Mixer Control (0x002a) */ -#define RT5668_M_DAC_L1_STO_L (0x1 << 15) -#define RT5668_M_DAC_L1_STO_L_SHIFT 15 -#define RT5668_M_DAC_R1_STO_L (0x1 << 13) -#define RT5668_M_DAC_R1_STO_L_SHIFT 13 -#define RT5668_M_DAC_L1_STO_R (0x1 << 7) -#define RT5668_M_DAC_L1_STO_R_SHIFT 7 -#define RT5668_M_DAC_R1_STO_R (0x1 << 5) -#define RT5668_M_DAC_R1_STO_R_SHIFT 5 +#define RT5663_M_DAC_L1_STO_L (0x1 << 15) +#define RT5663_M_DAC_L1_STO_L_SHIFT 15 +#define RT5663_M_DAC_R1_STO_L (0x1 << 13) +#define RT5663_M_DAC_R1_STO_L_SHIFT 13 +#define RT5663_M_DAC_L1_STO_R (0x1 << 7) +#define RT5663_M_DAC_L1_STO_R_SHIFT 7 +#define RT5663_M_DAC_R1_STO_R (0x1 << 5) +#define RT5663_M_DAC_R1_STO_R_SHIFT 5 /* Power Management for Digital 1 (0x0061) */ -#define RT5668_PWR_I2S1 (0x1 << 15) -#define RT5668_PWR_I2S1_SHIFT 15 -#define RT5668_PWR_DAC_L1 (0x1 << 11) -#define RT5668_PWR_DAC_L1_SHIFT 11 -#define RT5668_PWR_DAC_R1 (0x1 << 10) -#define RT5668_PWR_DAC_R1_SHIFT 10 -#define RT5668_PWR_LDO_DACREF_MASK (0x1 << 8) -#define RT5668_PWR_LDO_DACREF_SHIFT 8 -#define RT5668_PWR_LDO_DACREF_ON (0x1 << 8) -#define RT5668_PWR_LDO_DACREF_DOWN (0x0 << 8) -#define RT5668_PWR_LDO_SHIFT 8 -#define RT5668_PWR_ADC_L1 (0x1 << 4) -#define RT5668_PWR_ADC_L1_SHIFT 4 -#define RT5668_PWR_ADC_R1 (0x1 << 3) -#define RT5668_PWR_ADC_R1_SHIFT 3 +#define RT5663_PWR_I2S1 (0x1 << 15) +#define RT5663_PWR_I2S1_SHIFT 15 +#define RT5663_PWR_DAC_L1 (0x1 << 11) +#define RT5663_PWR_DAC_L1_SHIFT 11 +#define RT5663_PWR_DAC_R1 (0x1 << 10) +#define RT5663_PWR_DAC_R1_SHIFT 10 +#define RT5663_PWR_LDO_DACREF_MASK (0x1 << 8) +#define RT5663_PWR_LDO_DACREF_SHIFT 8 +#define RT5663_PWR_LDO_DACREF_ON (0x1 << 8) +#define RT5663_PWR_LDO_DACREF_DOWN (0x0 << 8) +#define RT5663_PWR_LDO_SHIFT 8 +#define RT5663_PWR_ADC_L1 (0x1 << 4) +#define RT5663_PWR_ADC_L1_SHIFT 4 +#define RT5663_PWR_ADC_R1 (0x1 << 3) +#define RT5663_PWR_ADC_R1_SHIFT 3 /* Power Management for Digital 2 (0x0062) */ -#define RT5668_PWR_ADC_S1F (0x1 << 15) -#define RT5668_PWR_ADC_S1F_SHIFT 15 -#define RT5668_PWR_DAC_S1F (0x1 << 10) -#define RT5668_PWR_DAC_S1F_SHIFT 10 +#define RT5663_PWR_ADC_S1F (0x1 << 15) +#define RT5663_PWR_ADC_S1F_SHIFT 15 +#define RT5663_PWR_DAC_S1F (0x1 << 10) +#define RT5663_PWR_DAC_S1F_SHIFT 10 /* Power Management for Analog 1 (0x0063) */ -#define RT5668_PWR_VREF1 (0x1 << 15) -#define RT5668_PWR_VREF1_MASK (0x1 << 15) -#define RT5668_PWR_VREF1_SHIFT 15 -#define RT5668_PWR_FV1 (0x1 << 14) -#define RT5668_PWR_FV1_MASK (0x1 << 14) -#define RT5668_PWR_FV1_SHIFT 14 -#define RT5668_PWR_VREF2 (0x1 << 13) -#define RT5668_PWR_VREF2_MASK (0x1 << 13) -#define RT5668_PWR_VREF2_SHIFT 13 -#define RT5668_PWR_FV2 (0x1 << 12) -#define RT5668_PWR_FV2_MASK (0x1 << 12) -#define RT5668_PWR_FV2_SHIFT 12 -#define RT5668_PWR_MB (0x1 << 9) -#define RT5668_PWR_MB_MASK (0x1 << 9) -#define RT5668_PWR_MB_SHIFT 9 -#define RT5668_AMP_HP_MASK (0x3 << 2) -#define RT5668_AMP_HP_SHIFT 2 -#define RT5668_AMP_HP_1X (0x0 << 2) -#define RT5668_AMP_HP_3X (0x1 << 2) -#define RT5668_AMP_HP_5X (0x3 << 2) -#define RT5668_LDO1_DVO_MASK (0x3) -#define RT5668_LDO1_DVO_SHIFT 0 -#define RT5668_LDO1_DVO_0_9V (0x0) -#define RT5668_LDO1_DVO_1_0V (0x1) -#define RT5668_LDO1_DVO_1_2V (0x2) -#define RT5668_LDO1_DVO_1_4V (0x3) +#define RT5663_PWR_VREF1 (0x1 << 15) +#define RT5663_PWR_VREF1_MASK (0x1 << 15) +#define RT5663_PWR_VREF1_SHIFT 15 +#define RT5663_PWR_FV1 (0x1 << 14) +#define RT5663_PWR_FV1_MASK (0x1 << 14) +#define RT5663_PWR_FV1_SHIFT 14 +#define RT5663_PWR_VREF2 (0x1 << 13) +#define RT5663_PWR_VREF2_MASK (0x1 << 13) +#define RT5663_PWR_VREF2_SHIFT 13 +#define RT5663_PWR_FV2 (0x1 << 12) +#define RT5663_PWR_FV2_MASK (0x1 << 12) +#define RT5663_PWR_FV2_SHIFT 12 +#define RT5663_PWR_MB (0x1 << 9) +#define RT5663_PWR_MB_MASK (0x1 << 9) +#define RT5663_PWR_MB_SHIFT 9 +#define RT5663_AMP_HP_MASK (0x3 << 2) +#define RT5663_AMP_HP_SHIFT 2 +#define RT5663_AMP_HP_1X (0x0 << 2) +#define RT5663_AMP_HP_3X (0x1 << 2) +#define RT5663_AMP_HP_5X (0x3 << 2) +#define RT5663_LDO1_DVO_MASK (0x3) +#define RT5663_LDO1_DVO_SHIFT 0 +#define RT5663_LDO1_DVO_0_9V (0x0) +#define RT5663_LDO1_DVO_1_0V (0x1) +#define RT5663_LDO1_DVO_1_2V (0x2) +#define RT5663_LDO1_DVO_1_4V (0x3) /* Power Management for Analog 2 (0x0064) */ -#define RT5668_PWR_BST1 (0x1 << 15) -#define RT5668_PWR_BST1_MASK (0x1 << 15) -#define RT5668_PWR_BST1_SHIFT 15 -#define RT5668_PWR_BST1_OFF (0x0 << 15) -#define RT5668_PWR_BST1_ON (0x1 << 15) -#define RT5668_PWR_BST2 (0x1 << 14) -#define RT5668_PWR_BST2_MASK (0x1 << 14) -#define RT5668_PWR_BST2_SHIFT 14 -#define RT5668_PWR_MB1 (0x1 << 11) -#define RT5668_PWR_MB1_SHIFT 11 -#define RT5668_PWR_MB2 (0x1 << 10) -#define RT5668_PWR_MB2_SHIFT 10 -#define RT5668_PWR_BST2_OP (0x1 << 6) -#define RT5668_PWR_BST2_OP_MASK (0x1 << 6) -#define RT5668_PWR_BST2_OP_SHIFT 6 -#define RT5668_PWR_JD1 (0x1 << 3) -#define RT5668_PWR_JD1_MASK (0x1 << 3) -#define RT5668_PWR_JD1_SHIFT 3 -#define RT5668_PWR_JD2 (0x1 << 2) -#define RT5668_PWR_JD2_MASK (0x1 << 2) -#define RT5668_PWR_JD2_SHIFT 2 -#define RT5668_PWR_RECMIX1 (0x1 << 1) -#define RT5668_PWR_RECMIX1_SHIFT 1 -#define RT5668_PWR_RECMIX2 (0x1) -#define RT5668_PWR_RECMIX2_SHIFT 0 +#define RT5663_PWR_BST1 (0x1 << 15) +#define RT5663_PWR_BST1_MASK (0x1 << 15) +#define RT5663_PWR_BST1_SHIFT 15 +#define RT5663_PWR_BST1_OFF (0x0 << 15) +#define RT5663_PWR_BST1_ON (0x1 << 15) +#define RT5663_PWR_BST2 (0x1 << 14) +#define RT5663_PWR_BST2_MASK (0x1 << 14) +#define RT5663_PWR_BST2_SHIFT 14 +#define RT5663_PWR_MB1 (0x1 << 11) +#define RT5663_PWR_MB1_SHIFT 11 +#define RT5663_PWR_MB2 (0x1 << 10) +#define RT5663_PWR_MB2_SHIFT 10 +#define RT5663_PWR_BST2_OP (0x1 << 6) +#define RT5663_PWR_BST2_OP_MASK (0x1 << 6) +#define RT5663_PWR_BST2_OP_SHIFT 6 +#define RT5663_PWR_JD1 (0x1 << 3) +#define RT5663_PWR_JD1_MASK (0x1 << 3) +#define RT5663_PWR_JD1_SHIFT 3 +#define RT5663_PWR_JD2 (0x1 << 2) +#define RT5663_PWR_JD2_MASK (0x1 << 2) +#define RT5663_PWR_JD2_SHIFT 2 +#define RT5663_PWR_RECMIX1 (0x1 << 1) +#define RT5663_PWR_RECMIX1_SHIFT 1 +#define RT5663_PWR_RECMIX2 (0x1) +#define RT5663_PWR_RECMIX2_SHIFT 0 /* Power Management for Analog 3 (0x0065) */ -#define RT5668_PWR_CBJ_MASK (0x1 << 9) -#define RT5668_PWR_CBJ_SHIFT 9 -#define RT5668_PWR_CBJ_OFF (0x0 << 9) -#define RT5668_PWR_CBJ_ON (0x1 << 9) -#define RT5668_PWR_PLL (0x1 << 6) -#define RT5668_PWR_PLL_SHIFT 6 -#define RT5668_PWR_LDO2 (0x1 << 2) -#define RT5668_PWR_LDO2_SHIFT 2 +#define RT5663_PWR_CBJ_MASK (0x1 << 9) +#define RT5663_PWR_CBJ_SHIFT 9 +#define RT5663_PWR_CBJ_OFF (0x0 << 9) +#define RT5663_PWR_CBJ_ON (0x1 << 9) +#define RT5663_PWR_PLL (0x1 << 6) +#define RT5663_PWR_PLL_SHIFT 6 +#define RT5663_PWR_LDO2 (0x1 << 2) +#define RT5663_PWR_LDO2_SHIFT 2 /* Power Management for Volume (0x0067) */ -#define RT5668_PWR_MIC_DET (0x1 << 5) -#define RT5668_PWR_MIC_DET_SHIFT 5 +#define RT5663_V2_PWR_MIC_DET (0x1 << 5) +#define RT5663_V2_PWR_MIC_DET_SHIFT 5 /* MCLK and System Clock Detection Control (0x006b) */ -#define RT5668_EN_ANA_CLK_DET_MASK (0x1 << 15) -#define RT5668_EN_ANA_CLK_DET_SHIFT 15 -#define RT5668_EN_ANA_CLK_DET_DIS (0x0 << 15) -#define RT5668_EN_ANA_CLK_DET_AUTO (0x1 << 15) -#define RT5668_PWR_CLK_DET_MASK (0x1) -#define RT5668_PWR_CLK_DET_SHIFT 0 -#define RT5668_PWR_CLK_DET_DIS (0x0) -#define RT5668_PWR_CLK_DET_EN (0x1) +#define RT5663_EN_ANA_CLK_DET_MASK (0x1 << 15) +#define RT5663_EN_ANA_CLK_DET_SHIFT 15 +#define RT5663_EN_ANA_CLK_DET_DIS (0x0 << 15) +#define RT5663_EN_ANA_CLK_DET_AUTO (0x1 << 15) +#define RT5663_PWR_CLK_DET_MASK (0x1) +#define RT5663_PWR_CLK_DET_SHIFT 0 +#define RT5663_PWR_CLK_DET_DIS (0x0) +#define RT5663_PWR_CLK_DET_EN (0x1) /* I2S1 Audio Serial Data Port Control (0x0070) */ -#define RT5668_I2S_MS_MASK (0x1 << 15) -#define RT5668_I2S_MS_SHIFT 15 -#define RT5668_I2S_MS_M (0x0 << 15) -#define RT5668_I2S_MS_S (0x1 << 15) -#define RT5668_I2S_BP_MASK (0x1 << 8) -#define RT5668_I2S_BP_SHIFT 8 -#define RT5668_I2S_BP_NOR (0x0 << 8) -#define RT5668_I2S_BP_INV (0x1 << 8) -#define RT5668_I2S_DL_MASK (0x3 << 4) -#define RT5668_I2S_DL_SHIFT 4 -#define RT5668_I2S_DL_16 (0x0 << 4) -#define RT5668_I2S_DL_20 (0x1 << 4) -#define RT5668_I2S_DL_24 (0x2 << 4) -#define RT5668_I2S_DL_8 (0x3 << 4) -#define RT5668_I2S_DF_MASK (0x7) -#define RT5668_I2S_DF_SHIFT 0 -#define RT5668_I2S_DF_I2S (0x0) -#define RT5668_I2S_DF_LEFT (0x1) -#define RT5668_I2S_DF_PCM_A (0x2) -#define RT5668_I2S_DF_PCM_B (0x3) -#define RT5668_I2S_DF_PCM_A_N (0x6) -#define RT5668_I2S_DF_PCM_B_N (0x7) +#define RT5663_I2S_MS_MASK (0x1 << 15) +#define RT5663_I2S_MS_SHIFT 15 +#define RT5663_I2S_MS_M (0x0 << 15) +#define RT5663_I2S_MS_S (0x1 << 15) +#define RT5663_I2S_BP_MASK (0x1 << 8) +#define RT5663_I2S_BP_SHIFT 8 +#define RT5663_I2S_BP_NOR (0x0 << 8) +#define RT5663_I2S_BP_INV (0x1 << 8) +#define RT5663_I2S_DL_MASK (0x3 << 4) +#define RT5663_I2S_DL_SHIFT 4 +#define RT5663_I2S_DL_16 (0x0 << 4) +#define RT5663_I2S_DL_20 (0x1 << 4) +#define RT5663_I2S_DL_24 (0x2 << 4) +#define RT5663_I2S_DL_8 (0x3 << 4) +#define RT5663_I2S_DF_MASK (0x7) +#define RT5663_I2S_DF_SHIFT 0 +#define RT5663_I2S_DF_I2S (0x0) +#define RT5663_I2S_DF_LEFT (0x1) +#define RT5663_I2S_DF_PCM_A (0x2) +#define RT5663_I2S_DF_PCM_B (0x3) +#define RT5663_I2S_DF_PCM_A_N (0x6) +#define RT5663_I2S_DF_PCM_B_N (0x7) /* ADC/DAC Clock Control 1 (0x0073) */ -#define RT5668_I2S_PD1_MASK (0x7 << 12) -#define RT5668_I2S_PD1_SHIFT 12 -#define RT5668_M_I2S_DIV_MASK (0x7 << 8) -#define RT5668_M_I2S_DIV_SHIFT 8 -#define RT5668_CLK_SRC_MASK (0x3 << 4) -#define RT5668_CLK_SRC_MCLK (0x0 << 4) -#define RT5668_CLK_SRC_PLL_OUT (0x1 << 4) -#define RT5668_CLK_SRC_DIV (0x2 << 4) -#define RT5668_CLK_SRC_RC (0x3 << 4) -#define RT5668_DAC_OSR_MASK (0x3 << 2) -#define RT5668_DAC_OSR_SHIFT 2 -#define RT5668_DAC_OSR_128 (0x0 << 2) -#define RT5668_DAC_OSR_64 (0x1 << 2) -#define RT5668_DAC_OSR_32 (0x2 << 2) -#define RT5668_ADC_OSR_MASK (0x3) -#define RT5668_ADC_OSR_SHIFT 0 -#define RT5668_ADC_OSR_128 (0x0) -#define RT5668_ADC_OSR_64 (0x1) -#define RT5668_ADC_OSR_32 (0x2) +#define RT5663_I2S_PD1_MASK (0x7 << 12) +#define RT5663_I2S_PD1_SHIFT 12 +#define RT5663_M_I2S_DIV_MASK (0x7 << 8) +#define RT5663_M_I2S_DIV_SHIFT 8 +#define RT5663_CLK_SRC_MASK (0x3 << 4) +#define RT5663_CLK_SRC_MCLK (0x0 << 4) +#define RT5663_CLK_SRC_PLL_OUT (0x1 << 4) +#define RT5663_CLK_SRC_DIV (0x2 << 4) +#define RT5663_CLK_SRC_RC (0x3 << 4) +#define RT5663_DAC_OSR_MASK (0x3 << 2) +#define RT5663_DAC_OSR_SHIFT 2 +#define RT5663_DAC_OSR_128 (0x0 << 2) +#define RT5663_DAC_OSR_64 (0x1 << 2) +#define RT5663_DAC_OSR_32 (0x2 << 2) +#define RT5663_ADC_OSR_MASK (0x3) +#define RT5663_ADC_OSR_SHIFT 0 +#define RT5663_ADC_OSR_128 (0x0) +#define RT5663_ADC_OSR_64 (0x1) +#define RT5663_ADC_OSR_32 (0x2) /* TDM1 control 1 (0x0078) */ -#define RT5668_TDM_MODE_MASK (0x1 << 15) -#define RT5668_TDM_MODE_SHIFT 15 -#define RT5668_TDM_MODE_I2S (0x0 << 15) -#define RT5668_TDM_MODE_TDM (0x1 << 15) -#define RT5668_TDM_IN_CH_MASK (0x3 << 10) -#define RT5668_TDM_IN_CH_SHIFT 10 -#define RT5668_TDM_IN_CH_2 (0x0 << 10) -#define RT5668_TDM_IN_CH_4 (0x1 << 10) -#define RT5668_TDM_IN_CH_6 (0x2 << 10) -#define RT5668_TDM_IN_CH_8 (0x3 << 10) -#define RT5668_TDM_OUT_CH_MASK (0x3 << 8) -#define RT5668_TDM_OUT_CH_SHIFT 8 -#define RT5668_TDM_OUT_CH_2 (0x0 << 8) -#define RT5668_TDM_OUT_CH_4 (0x1 << 8) -#define RT5668_TDM_OUT_CH_6 (0x2 << 8) -#define RT5668_TDM_OUT_CH_8 (0x3 << 8) -#define RT5668_TDM_IN_LEN_MASK (0x3 << 6) -#define RT5668_TDM_IN_LEN_SHIFT 6 -#define RT5668_TDM_IN_LEN_16 (0x0 << 6) -#define RT5668_TDM_IN_LEN_20 (0x1 << 6) -#define RT5668_TDM_IN_LEN_24 (0x2 << 6) -#define RT5668_TDM_IN_LEN_32 (0x3 << 6) -#define RT5668_TDM_OUT_LEN_MASK (0x3 << 4) -#define RT5668_TDM_OUT_LEN_SHIFT 4 -#define RT5668_TDM_OUT_LEN_16 (0x0 << 4) -#define RT5668_TDM_OUT_LEN_20 (0x1 << 4) -#define RT5668_TDM_OUT_LEN_24 (0x2 << 4) -#define RT5668_TDM_OUT_LEN_32 (0x3 << 4) +#define RT5663_TDM_MODE_MASK (0x1 << 15) +#define RT5663_TDM_MODE_SHIFT 15 +#define RT5663_TDM_MODE_I2S (0x0 << 15) +#define RT5663_TDM_MODE_TDM (0x1 << 15) +#define RT5663_TDM_IN_CH_MASK (0x3 << 10) +#define RT5663_TDM_IN_CH_SHIFT 10 +#define RT5663_TDM_IN_CH_2 (0x0 << 10) +#define RT5663_TDM_IN_CH_4 (0x1 << 10) +#define RT5663_TDM_IN_CH_6 (0x2 << 10) +#define RT5663_TDM_IN_CH_8 (0x3 << 10) +#define RT5663_TDM_OUT_CH_MASK (0x3 << 8) +#define RT5663_TDM_OUT_CH_SHIFT 8 +#define RT5663_TDM_OUT_CH_2 (0x0 << 8) +#define RT5663_TDM_OUT_CH_4 (0x1 << 8) +#define RT5663_TDM_OUT_CH_6 (0x2 << 8) +#define RT5663_TDM_OUT_CH_8 (0x3 << 8) +#define RT5663_TDM_IN_LEN_MASK (0x3 << 6) +#define RT5663_TDM_IN_LEN_SHIFT 6 +#define RT5663_TDM_IN_LEN_16 (0x0 << 6) +#define RT5663_TDM_IN_LEN_20 (0x1 << 6) +#define RT5663_TDM_IN_LEN_24 (0x2 << 6) +#define RT5663_TDM_IN_LEN_32 (0x3 << 6) +#define RT5663_TDM_OUT_LEN_MASK (0x3 << 4) +#define RT5663_TDM_OUT_LEN_SHIFT 4 +#define RT5663_TDM_OUT_LEN_16 (0x0 << 4) +#define RT5663_TDM_OUT_LEN_20 (0x1 << 4) +#define RT5663_TDM_OUT_LEN_24 (0x2 << 4) +#define RT5663_TDM_OUT_LEN_32 (0x3 << 4) /* Global Clock Control (0x0080) */ -#define RT5668_SCLK_SRC_MASK (0x3 << 14) -#define RT5668_SCLK_SRC_SHIFT 14 -#define RT5668_SCLK_SRC_MCLK (0x0 << 14) -#define RT5668_SCLK_SRC_PLL1 (0x1 << 14) -#define RT5668_SCLK_SRC_RCCLK (0x2 << 14) -#define RT5668_PLL1_SRC_MASK (0x7 << 8) -#define RT5668_PLL1_SRC_SHIFT 8 -#define RT5668_PLL1_SRC_MCLK (0x0 << 8) -#define RT5668_PLL1_SRC_BCLK1 (0x1 << 8) -#define RT5668_PLL1_PD_MASK (0x1 << 4) -#define RT5668_PLL1_PD_SHIFT 4 - -#define RT5668_PLL_INP_MAX 40000000 -#define RT5668_PLL_INP_MIN 256000 +#define RT5663_SCLK_SRC_MASK (0x3 << 14) +#define RT5663_SCLK_SRC_SHIFT 14 +#define RT5663_SCLK_SRC_MCLK (0x0 << 14) +#define RT5663_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5663_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5663_PLL1_SRC_MASK (0x7 << 11) +#define RT5663_PLL1_SRC_SHIFT 11 +#define RT5663_PLL1_SRC_MCLK (0x0 << 11) +#define RT5663_PLL1_SRC_BCLK1 (0x1 << 11) +#define RT5663_V2_PLL1_SRC_MASK (0x7 << 8) +#define RT5663_V2_PLL1_SRC_SHIFT 8 +#define RT5663_V2_PLL1_SRC_MCLK (0x0 << 8) +#define RT5663_V2_PLL1_SRC_BCLK1 (0x1 << 8) +#define RT5663_PLL1_PD_MASK (0x1 << 4) +#define RT5663_PLL1_PD_SHIFT 4 + +#define RT5663_PLL_INP_MAX 40000000 +#define RT5663_PLL_INP_MIN 256000 /* PLL M/N/K Code Control 1 (0x0081) */ -#define RT5668_PLL_N_MAX 0x001ff -#define RT5668_PLL_N_MASK (RT5668_PLL_N_MAX << 7) -#define RT5668_PLL_N_SHIFT 7 -#define RT5668_PLL_K_MAX 0x001f -#define RT5668_PLL_K_MASK (RT5668_PLL_K_MAX) -#define RT5668_PLL_K_SHIFT 0 +#define RT5663_PLL_N_MAX 0x001ff +#define RT5663_PLL_N_MASK (RT5663_PLL_N_MAX << 7) +#define RT5663_PLL_N_SHIFT 7 +#define RT5663_PLL_K_MAX 0x001f +#define RT5663_PLL_K_MASK (RT5663_PLL_K_MAX) +#define RT5663_PLL_K_SHIFT 0 /* PLL M/N/K Code Control 2 (0x0082) */ -#define RT5668_PLL_M_MAX 0x00f -#define RT5668_PLL_M_MASK (RT5668_PLL_M_MAX << 12) -#define RT5668_PLL_M_SHIFT 12 -#define RT5668_PLL_M_BP (0x1 << 11) -#define RT5668_PLL_M_BP_SHIFT 11 +#define RT5663_PLL_M_MAX 0x00f +#define RT5663_PLL_M_MASK (RT5663_PLL_M_MAX << 12) +#define RT5663_PLL_M_SHIFT 12 +#define RT5663_PLL_M_BP (0x1 << 11) +#define RT5663_PLL_M_BP_SHIFT 11 /* PLL tracking mode 1 (0x0083) */ -#define RT5668_I2S1_ASRC_MASK (0x1 << 13) -#define RT5668_I2S1_ASRC_SHIFT 13 -#define RT5668_DAC_STO1_ASRC_MASK (0x1 << 12) -#define RT5668_DAC_STO1_ASRC_SHIFT 12 -#define RT5668_ADC_STO1_ASRC_MASK (0x1 << 4) -#define RT5668_ADC_STO1_ASRC_SHIFT 4 +#define RT5663_V2_I2S1_ASRC_MASK (0x1 << 13) +#define RT5663_V2_I2S1_ASRC_SHIFT 13 +#define RT5663_V2_DAC_STO1_ASRC_MASK (0x1 << 12) +#define RT5663_V2_DAC_STO1_ASRC_SHIFT 12 +#define RT5663_V2_ADC_STO1_ASRC_MASK (0x1 << 4) +#define RT5663_V2_ADC_STO1_ASRC_SHIFT 4 /* PLL tracking mode 2 (0x0084)*/ -#define RT5668_DA_STO1_TRACK_MASK (0x7 << 12) -#define RT5668_DA_STO1_TRACK_SHIFT 12 -#define RT5668_DA_STO1_TRACK_SYSCLK (0x0 << 12) -#define RT5668_DA_STO1_TRACK_I2S1 (0x1 << 12) +#define RT5663_DA_STO1_TRACK_MASK (0x7 << 12) +#define RT5663_DA_STO1_TRACK_SHIFT 12 +#define RT5663_DA_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5663_DA_STO1_TRACK_I2S1 (0x1 << 12) /* PLL tracking mode 3 (0x0085)*/ -#define RT5668_AD_STO1_TRACK_MASK (0x7 << 12) -#define RT5668_AD_STO1_TRACK_SHIFT 12 -#define RT5668_AD_STO1_TRACK_SYSCLK (0x0 << 12) -#define RT5668_AD_STO1_TRACK_I2S1 (0x1 << 12) +#define RT5663_V2_AD_STO1_TRACK_MASK (0x7 << 12) +#define RT5663_V2_AD_STO1_TRACK_SHIFT 12 +#define RT5663_V2_AD_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5663_V2_AD_STO1_TRACK_I2S1 (0x1 << 12) /* HPOUT Charge pump control 1 (0x0091) */ -#define RT5668_OSW_HP_L_MASK (0x1 << 11) -#define RT5668_OSW_HP_L_SHIFT 11 -#define RT5668_OSW_HP_L_EN (0x1 << 11) -#define RT5668_OSW_HP_L_DIS (0x0 << 11) -#define RT5668_OSW_HP_R_MASK (0x1 << 10) -#define RT5668_OSW_HP_R_SHIFT 10 -#define RT5668_OSW_HP_R_EN (0x1 << 10) -#define RT5668_OSW_HP_R_DIS (0x0 << 10) -#define RT5668_SEL_PM_HP_MASK (0x3 << 8) -#define RT5668_SEL_PM_HP_SHIFT 8 -#define RT5668_SEL_PM_HP_0_6 (0x0 << 8) -#define RT5668_SEL_PM_HP_0_9 (0x1 << 8) -#define RT5668_SEL_PM_HP_1_8 (0x2 << 8) -#define RT5668_SEL_PM_HP_HIGH (0x3 << 8) -#define RT5668_OVCD_HP_MASK (0x1 << 2) -#define RT5668_OVCD_HP_SHIFT 2 -#define RT5668_OVCD_HP_EN (0x1 << 2) -#define RT5668_OVCD_HP_DIS (0x0 << 2) +#define RT5663_OSW_HP_L_MASK (0x1 << 11) +#define RT5663_OSW_HP_L_SHIFT 11 +#define RT5663_OSW_HP_L_EN (0x1 << 11) +#define RT5663_OSW_HP_L_DIS (0x0 << 11) +#define RT5663_OSW_HP_R_MASK (0x1 << 10) +#define RT5663_OSW_HP_R_SHIFT 10 +#define RT5663_OSW_HP_R_EN (0x1 << 10) +#define RT5663_OSW_HP_R_DIS (0x0 << 10) +#define RT5663_SEL_PM_HP_MASK (0x3 << 8) +#define RT5663_SEL_PM_HP_SHIFT 8 +#define RT5663_SEL_PM_HP_0_6 (0x0 << 8) +#define RT5663_SEL_PM_HP_0_9 (0x1 << 8) +#define RT5663_SEL_PM_HP_1_8 (0x2 << 8) +#define RT5663_SEL_PM_HP_HIGH (0x3 << 8) +#define RT5663_OVCD_HP_MASK (0x1 << 2) +#define RT5663_OVCD_HP_SHIFT 2 +#define RT5663_OVCD_HP_EN (0x1 << 2) +#define RT5663_OVCD_HP_DIS (0x0 << 2) /* RC Clock Control (0x0094) */ -#define RT5668_DIG_25M_CLK_MASK (0x1 << 9) -#define RT5668_DIG_25M_CLK_SHIFT 9 -#define RT5668_DIG_25M_CLK_DIS (0x0 << 9) -#define RT5668_DIG_25M_CLK_EN (0x1 << 9) -#define RT5668_DIG_1M_CLK_MASK (0x1 << 8) -#define RT5668_DIG_1M_CLK_SHIFT 8 -#define RT5668_DIG_1M_CLK_DIS (0x0 << 8) -#define RT5668_DIG_1M_CLK_EN (0x1 << 8) +#define RT5663_DIG_25M_CLK_MASK (0x1 << 9) +#define RT5663_DIG_25M_CLK_SHIFT 9 +#define RT5663_DIG_25M_CLK_DIS (0x0 << 9) +#define RT5663_DIG_25M_CLK_EN (0x1 << 9) +#define RT5663_DIG_1M_CLK_MASK (0x1 << 8) +#define RT5663_DIG_1M_CLK_SHIFT 8 +#define RT5663_DIG_1M_CLK_DIS (0x0 << 8) +#define RT5663_DIG_1M_CLK_EN (0x1 << 8) /* Auto Turn On 1M RC CLK (0x009f) */ -#define RT5668_IRQ_POW_SAV_MASK (0x1 << 15) -#define RT5668_IRQ_POW_SAV_SHIFT 15 -#define RT5668_IRQ_POW_SAV_DIS (0x0 << 15) -#define RT5668_IRQ_POW_SAV_EN (0x1 << 15) -#define RT5668_IRQ_POW_SAV_JD1_MASK (0x1 << 14) -#define RT5668_IRQ_POW_SAV_JD1_SHIFT 14 -#define RT5668_IRQ_POW_SAV_JD1_DIS (0x0 << 14) -#define RT5668_IRQ_POW_SAV_JD1_EN (0x1 << 14) +#define RT5663_IRQ_POW_SAV_MASK (0x1 << 15) +#define RT5663_IRQ_POW_SAV_SHIFT 15 +#define RT5663_IRQ_POW_SAV_DIS (0x0 << 15) +#define RT5663_IRQ_POW_SAV_EN (0x1 << 15) +#define RT5663_IRQ_POW_SAV_JD1_MASK (0x1 << 14) +#define RT5663_IRQ_POW_SAV_JD1_SHIFT 14 +#define RT5663_IRQ_POW_SAV_JD1_DIS (0x0 << 14) +#define RT5663_IRQ_POW_SAV_JD1_EN (0x1 << 14) /* IRQ Control 1 (0x00b6) */ -#define RT5668_EN_CB_JD_MASK (0x1 << 3) -#define RT5668_EN_CB_JD_SHIFT 3 -#define RT5668_EN_CB_JD_EN (0x1 << 3) -#define RT5668_EN_CB_JD_DIS (0x0 << 3) +#define RT5663_EN_CB_JD_MASK (0x1 << 3) +#define RT5663_EN_CB_JD_SHIFT 3 +#define RT5663_EN_CB_JD_EN (0x1 << 3) +#define RT5663_EN_CB_JD_DIS (0x0 << 3) /* IRQ Control 3 (0x00b8) */ -#define RT5668_EN_IRQ_INLINE_MASK (0x1 << 6) -#define RT5668_EN_IRQ_INLINE_SHIFT 6 -#define RT5668_EN_IRQ_INLINE_BYP (0x0 << 6) -#define RT5668_EN_IRQ_INLINE_NOR (0x1 << 6) +#define RT5663_V2_EN_IRQ_INLINE_MASK (0x1 << 6) +#define RT5663_V2_EN_IRQ_INLINE_SHIFT 6 +#define RT5663_V2_EN_IRQ_INLINE_BYP (0x0 << 6) +#define RT5663_V2_EN_IRQ_INLINE_NOR (0x1 << 6) /* GPIO Control 1 (0x00c0) */ -#define RT5668_GP1_PIN_MASK (0x1 << 15) -#define RT5668_GP1_PIN_SHIFT 15 -#define RT5668_GP1_PIN_GPIO1 (0x0 << 15) -#define RT5668_GP1_PIN_IRQ (0x1 << 15) +#define RT5663_GP1_PIN_MASK (0x1 << 15) +#define RT5663_GP1_PIN_SHIFT 15 +#define RT5663_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5663_GP1_PIN_IRQ (0x1 << 15) /* GPIO Control 2 (0x00c1) */ -#define RT5668_GP4_PIN_CONF_MASK (0x1 << 5) -#define RT5668_GP4_PIN_CONF_SHIFT 5 -#define RT5668_GP4_PIN_CONF_INPUT (0x0 << 5) -#define RT5668_GP4_PIN_CONF_OUTPUT (0x1 << 5) +#define RT5663_GP4_PIN_CONF_MASK (0x1 << 5) +#define RT5663_GP4_PIN_CONF_SHIFT 5 +#define RT5663_GP4_PIN_CONF_INPUT (0x0 << 5) +#define RT5663_GP4_PIN_CONF_OUTPUT (0x1 << 5) /* GPIO Control 2 (0x00c2) */ -#define RT5668_GP8_PIN_CONF_MASK (0x1 << 13) -#define RT5668_GP8_PIN_CONF_SHIFT 13 -#define RT5668_GP8_PIN_CONF_INPUT (0x0 << 13) -#define RT5668_GP8_PIN_CONF_OUTPUT (0x1 << 13) +#define RT5663_GP8_PIN_CONF_MASK (0x1 << 13) +#define RT5663_GP8_PIN_CONF_SHIFT 13 +#define RT5663_GP8_PIN_CONF_INPUT (0x0 << 13) +#define RT5663_GP8_PIN_CONF_OUTPUT (0x1 << 13) /* 4 Buttons Inline Command Function 1 (0x00df) */ -#define RT5668_4BTN_CLK_DEB_MASK (0x3 << 2) -#define RT5668_4BTN_CLK_DEB_SHIFT 2 -#define RT5668_4BTN_CLK_DEB_8MS (0x0 << 2) -#define RT5668_4BTN_CLK_DEB_16MS (0x1 << 2) -#define RT5668_4BTN_CLK_DEB_32MS (0x2 << 2) -#define RT5668_4BTN_CLK_DEB_65MS (0x3 << 2) +#define RT5663_4BTN_CLK_DEB_MASK (0x3 << 2) +#define RT5663_4BTN_CLK_DEB_SHIFT 2 +#define RT5663_4BTN_CLK_DEB_8MS (0x0 << 2) +#define RT5663_4BTN_CLK_DEB_16MS (0x1 << 2) +#define RT5663_4BTN_CLK_DEB_32MS (0x2 << 2) +#define RT5663_4BTN_CLK_DEB_65MS (0x3 << 2) /* Inline Command Function 6 (0x00e0) */ -#define RT5668_EN_4BTN_INL_MASK (0x1 << 15) -#define RT5668_EN_4BTN_INL_SHIFT 15 -#define RT5668_EN_4BTN_INL_DIS (0x0 << 15) -#define RT5668_EN_4BTN_INL_EN (0x1 << 15) -#define RT5668_RESET_4BTN_INL_MASK (0x1 << 14) -#define RT5668_RESET_4BTN_INL_SHIFT 14 -#define RT5668_RESET_4BTN_INL_RESET (0x0 << 14) -#define RT5668_RESET_4BTN_INL_NOR (0x1 << 14) +#define RT5663_EN_4BTN_INL_MASK (0x1 << 15) +#define RT5663_EN_4BTN_INL_SHIFT 15 +#define RT5663_EN_4BTN_INL_DIS (0x0 << 15) +#define RT5663_EN_4BTN_INL_EN (0x1 << 15) +#define RT5663_RESET_4BTN_INL_MASK (0x1 << 14) +#define RT5663_RESET_4BTN_INL_SHIFT 14 +#define RT5663_RESET_4BTN_INL_RESET (0x0 << 14) +#define RT5663_RESET_4BTN_INL_NOR (0x1 << 14) /* Digital Misc Control (0x00fa) */ -#define RT5668_DIG_GATE_CTRL_MASK 0x1 -#define RT5668_DIG_GATE_CTRL_SHIFT (0) -#define RT5668_DIG_GATE_CTRL_DIS 0x0 -#define RT5668_DIG_GATE_CTRL_EN 0x1 +#define RT5663_DIG_GATE_CTRL_MASK 0x1 +#define RT5663_DIG_GATE_CTRL_SHIFT (0) +#define RT5663_DIG_GATE_CTRL_DIS 0x0 +#define RT5663_DIG_GATE_CTRL_EN 0x1 /* Chopper and Clock control for DAC L (0x013a)*/ -#define RT5668_CKXEN_DAC1_MASK (0x1 << 13) -#define RT5668_CKXEN_DAC1_SHIFT 13 -#define RT5668_CKGEN_DAC1_MASK (0x1 << 12) -#define RT5668_CKGEN_DAC1_SHIFT 12 +#define RT5663_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5663_CKXEN_DAC1_SHIFT 13 +#define RT5663_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5663_CKGEN_DAC1_SHIFT 12 /* Chopper and Clock control for ADC (0x013b)*/ -#define RT5668_CKXEN_ADCC_MASK (0x1 << 13) -#define RT5668_CKXEN_ADCC_SHIFT 13 -#define RT5668_CKGEN_ADCC_MASK (0x1 << 12) -#define RT5668_CKGEN_ADCC_SHIFT 12 +#define RT5663_CKXEN_ADCC_MASK (0x1 << 13) +#define RT5663_CKXEN_ADCC_SHIFT 13 +#define RT5663_CKGEN_ADCC_MASK (0x1 << 12) +#define RT5663_CKGEN_ADCC_SHIFT 12 /* HP Behavior Logic Control 2 (0x01db) */ -#define RT5668_HP_SIG_SRC1_MASK (0x3) -#define RT5668_HP_SIG_SRC1_SHIFT 0 -#define RT5668_HP_SIG_SRC1_HP_DC (0x0) -#define RT5668_HP_SIG_SRC1_HP_CALIB (0x1) -#define RT5668_HP_SIG_SRC1_REG (0x2) -#define RT5668_HP_SIG_SRC1_SILENCE (0x3) +#define RT5663_HP_SIG_SRC1_MASK (0x3) +#define RT5663_HP_SIG_SRC1_SHIFT 0 +#define RT5663_HP_SIG_SRC1_HP_DC (0x0) +#define RT5663_HP_SIG_SRC1_HP_CALIB (0x1) +#define RT5663_HP_SIG_SRC1_REG (0x2) +#define RT5663_HP_SIG_SRC1_SILENCE (0x3) /* RT5663 specific register */ #define RT5663_HP_OUT_EN 0x0002 @@ -707,6 +704,10 @@ #define RT5663_TDM_3 0x0079 #define RT5663_TDM_4 0x007a #define RT5663_TDM_5 0x007b +#define RT5663_TDM_6 0x007c +#define RT5663_TDM_7 0x007d +#define RT5663_TDM_8 0x007e +#define RT5663_TDM_9 0x007f #define RT5663_GLB_CLK 0x0080 #define RT5663_PLL_1 0x0081 #define RT5663_PLL_2 0x0082 @@ -739,7 +740,7 @@ #define RT5663_INT_ST_2 0x00bf #define RT5663_GPIO_1 0x00c0 #define RT5663_GPIO_2 0x00c1 -#define RT5663_GPIO_STA 0x00c5 +#define RT5663_GPIO_STA1 0x00c5 #define RT5663_SIN_GEN_1 0x00cb #define RT5663_SIN_GEN_2 0x00cc #define RT5663_SIN_GEN_3 0x00cd @@ -800,6 +801,8 @@ #define RT5663_TEST_MODE_1 0x0144 #define RT5663_TEST_MODE_2 0x0145 #define RT5663_TEST_MODE_3 0x0146 +#define RT5663_TEST_MODE_4 0x0147 +#define RT5663_TEST_MODE_5 0x0148 #define RT5663_STO_DRE_1 0x0160 #define RT5663_STO_DRE_2 0x0161 #define RT5663_STO_DRE_3 0x0162 @@ -921,19 +924,19 @@ #define RT5663_ADC_EQ_POST_VOL_L 0x03f2 #define RT5663_ADC_EQ_POST_VOL_R 0x03f3 -/* RT5663: RECMIX Control (0x0010) */ +/* RECMIX Control (0x0010) */ #define RT5663_RECMIX1_BST1_MASK (0x1) #define RT5663_RECMIX1_BST1_SHIFT 0 #define RT5663_RECMIX1_BST1_ON (0x0) #define RT5663_RECMIX1_BST1_OFF (0x1) -/* RT5663: Bypass Stereo1 DAC Mixer Control (0x002d) */ +/* Bypass Stereo1 DAC Mixer Control (0x002d) */ #define RT5663_DACL1_SRC_MASK (0x1 << 3) #define RT5663_DACL1_SRC_SHIFT 3 #define RT5663_DACR1_SRC_MASK (0x1 << 2) #define RT5663_DACR1_SRC_SHIFT 2 -/* RT5663: TDM control 2 (0x0078) */ +/* TDM control 2 (0x0078) */ #define RT5663_DATA_SWAP_ADCDAT1_MASK (0x3 << 14) #define RT5663_DATA_SWAP_ADCDAT1_SHIFT 14 #define RT5663_DATA_SWAP_ADCDAT1_LR (0x0 << 14) @@ -941,7 +944,7 @@ #define RT5663_DATA_SWAP_ADCDAT1_LL (0x2 << 14) #define RT5663_DATA_SWAP_ADCDAT1_RR (0x3 << 14) -/* RT5663: TDM control 5 (0x007b) */ +/* TDM control 5 (0x007b) */ #define RT5663_TDM_LENGTN_MASK (0x3) #define RT5663_TDM_LENGTN_SHIFT 0 #define RT5663_TDM_LENGTN_16 (0x0) @@ -949,17 +952,6 @@ #define RT5663_TDM_LENGTN_24 (0x2) #define RT5663_TDM_LENGTN_32 (0x3) -/* RT5663: Global Clock Control (0x0080) */ -#define RT5663_SCLK_SRC_MASK (0x3 << 14) -#define RT5663_SCLK_SRC_SHIFT 14 -#define RT5663_SCLK_SRC_MCLK (0x0 << 14) -#define RT5663_SCLK_SRC_PLL1 (0x1 << 14) -#define RT5663_SCLK_SRC_RCCLK (0x2 << 14) -#define RT5663_PLL1_SRC_MASK (0x7 << 11) -#define RT5663_PLL1_SRC_SHIFT 11 -#define RT5663_PLL1_SRC_MCLK (0x0 << 11) -#define RT5663_PLL1_SRC_BCLK1 (0x1 << 11) - /* PLL tracking mode 1 (0x0083) */ #define RT5663_I2S1_ASRC_MASK (0x1 << 11) #define RT5663_I2S1_ASRC_SHIFT 11 @@ -978,37 +970,47 @@ #define RT5663_AD_STO1_TRACK_SYSCLK (0x0) #define RT5663_AD_STO1_TRACK_I2S1 (0x1) -/* RT5663: HPOUT Charge pump control 1 (0x0091) */ +/* HPOUT Charge pump control 1 (0x0091) */ #define RT5663_SI_HP_MASK (0x1 << 12) #define RT5663_SI_HP_SHIFT 12 #define RT5663_SI_HP_EN (0x1 << 12) #define RT5663_SI_HP_DIS (0x0 << 12) -/* RT5663: GPIO Control 2 (0x00b6) */ +/* GPIO Control 2 (0x00b6) */ #define RT5663_GP1_PIN_CONF_MASK (0x1 << 2) #define RT5663_GP1_PIN_CONF_SHIFT 2 #define RT5663_GP1_PIN_CONF_OUTPUT (0x1 << 2) #define RT5663_GP1_PIN_CONF_INPUT (0x0 << 2) -/* RT5663: GPIO Control 2 (0x00b7) */ +/* GPIO Control 2 (0x00b7) */ #define RT5663_EN_IRQ_INLINE_MASK (0x1 << 3) #define RT5663_EN_IRQ_INLINE_SHIFT 3 #define RT5663_EN_IRQ_INLINE_NOR (0x1 << 3) #define RT5663_EN_IRQ_INLINE_BYP (0x0 << 3) -/* RT5663: IRQ Control 1 (0x00c1) */ +/* GPIO Control 1 (0x00c0) */ +#define RT5663_GPIO1_TYPE_MASK (0x1 << 15) +#define RT5663_GPIO1_TYPE_SHIFT 15 +#define RT5663_GPIO1_TYPE_EN (0x1 << 15) +#define RT5663_GPIO1_TYPE_DIS (0x0 << 15) + +/* IRQ Control 1 (0x00c1) */ #define RT5663_EN_IRQ_JD1_MASK (0x1 << 6) #define RT5663_EN_IRQ_JD1_SHIFT 6 #define RT5663_EN_IRQ_JD1_EN (0x1 << 6) #define RT5663_EN_IRQ_JD1_DIS (0x0 << 6) +#define RT5663_SEL_GPIO1_MASK (0x1 << 2) +#define RT5663_SEL_GPIO1_SHIFT 6 +#define RT5663_SEL_GPIO1_EN (0x1 << 2) +#define RT5663_SEL_GPIO1_DIS (0x0 << 2) -/* RT5663: Inline Command Function 2 (0x00dc) */ +/* Inline Command Function 2 (0x00dc) */ #define RT5663_PWR_MIC_DET_MASK (0x1) #define RT5663_PWR_MIC_DET_SHIFT 0 #define RT5663_PWR_MIC_DET_ON (0x1) #define RT5663_PWR_MIC_DET_OFF (0x0) -/* RT5663: Embeeded Jack and Type Detection Control 1 (0x00e6)*/ +/* Embeeded Jack and Type Detection Control 1 (0x00e6)*/ #define RT5663_CBJ_DET_MASK (0x1 << 15) #define RT5663_CBJ_DET_SHIFT 15 #define RT5663_CBJ_DET_DIS (0x0 << 15) @@ -1022,17 +1024,17 @@ #define RT5663_POL_EXT_JD_EN (0x1 << 10) #define RT5663_POL_EXT_JD_DIS (0x0 << 10) -/* RT5663: DACREF LDO Control (0x0112)*/ +/* DACREF LDO Control (0x0112)*/ #define RT5663_PWR_LDO_DACREFL_MASK (0x1 << 9) #define RT5663_PWR_LDO_DACREFL_SHIFT 9 #define RT5663_PWR_LDO_DACREFR_MASK (0x1 << 1) #define RT5663_PWR_LDO_DACREFR_SHIFT 1 -/* RT5663: Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/ +/* Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/ #define RT5663_DRE_GAIN_HP_MASK (0x1f) #define RT5663_DRE_GAIN_HP_SHIFT 0 -/* RT5663: Combo Jack Control (0x0250) */ +/* Combo Jack Control (0x0250) */ #define RT5663_INBUF_CBJ_BST1_MASK (0x1 << 11) #define RT5663_INBUF_CBJ_BST1_SHIFT 11 #define RT5663_INBUF_CBJ_BST1_ON (0x1 << 11) @@ -1042,11 +1044,11 @@ #define RT5663_CBJ_SENSE_BST1_L (0x1 << 10) #define RT5663_CBJ_SENSE_BST1_R (0x0 << 10) -/* RT5663: Combo Jack Control (0x0251) */ +/* Combo Jack Control (0x0251) */ #define RT5663_GAIN_BST1_MASK (0xf) #define RT5663_GAIN_BST1_SHIFT 0 -/* RT5663: Dummy register 1 (0x02fa) */ +/* Dummy register 1 (0x02fa) */ #define RT5663_EMB_CLK_MASK (0x1 << 9) #define RT5663_EMB_CLK_SHIFT 9 #define RT5663_EMB_CLK_EN (0x1 << 9) diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c new file mode 100644 index 000000000000..324461e985b3 --- /dev/null +++ b/sound/soc/codecs/rt5665.c @@ -0,0 +1,4874 @@ +/* + * rt5665.c -- RT5665/RT5658 ALSA SoC audio codec driver + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> +#include <linux/mutex.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/rt5665.h> + +#include "rl6231.h" +#include "rt5665.h" + +#define RT5665_NUM_SUPPLIES 3 + +static const char *rt5665_supply_names[RT5665_NUM_SUPPLIES] = { + "AVDD", + "MICVDD", + "VBAT", +}; + +struct rt5665_priv { + struct snd_soc_codec *codec; + struct rt5665_platform_data pdata; + struct regmap *regmap; + struct gpio_desc *gpiod_ldo1_en; + struct gpio_desc *gpiod_reset; + struct snd_soc_jack *hs_jack; + struct regulator_bulk_data supplies[RT5665_NUM_SUPPLIES]; + struct delayed_work jack_detect_work; + struct delayed_work calibrate_work; + struct delayed_work jd_check_work; + struct mutex calibrate_mutex; + + int sysclk; + int sysclk_src; + int lrck[RT5665_AIFS]; + int bclk[RT5665_AIFS]; + int master[RT5665_AIFS]; + int id; + + int pll_src; + int pll_in; + int pll_out; + + int jack_type; + int irq_work_delay_time; + unsigned int sar_adc_value; +}; + +static const struct reg_default rt5665_reg[] = { + {0x0000, 0x0000}, + {0x0001, 0xc8c8}, + {0x0002, 0x8080}, + {0x0003, 0x8000}, + {0x0004, 0xc80a}, + {0x0005, 0x0000}, + {0x0006, 0x0000}, + {0x0007, 0x0000}, + {0x000a, 0x0000}, + {0x000b, 0x0000}, + {0x000c, 0x0000}, + {0x000d, 0x0000}, + {0x000f, 0x0808}, + {0x0010, 0x4040}, + {0x0011, 0x0000}, + {0x0012, 0x1404}, + {0x0013, 0x1000}, + {0x0014, 0xa00a}, + {0x0015, 0x0404}, + {0x0016, 0x0404}, + {0x0017, 0x0011}, + {0x0018, 0xafaf}, + {0x0019, 0xafaf}, + {0x001a, 0xafaf}, + {0x001b, 0x0011}, + {0x001c, 0x2f2f}, + {0x001d, 0x2f2f}, + {0x001e, 0x2f2f}, + {0x001f, 0x0000}, + {0x0020, 0x0000}, + {0x0021, 0x0000}, + {0x0022, 0x5757}, + {0x0023, 0x0039}, + {0x0026, 0xc0c0}, + {0x0027, 0xc0c0}, + {0x0028, 0xc0c0}, + {0x0029, 0x8080}, + {0x002a, 0xaaaa}, + {0x002b, 0xaaaa}, + {0x002c, 0xaba8}, + {0x002d, 0x0000}, + {0x002e, 0x0000}, + {0x002f, 0x0000}, + {0x0030, 0x0000}, + {0x0031, 0x5000}, + {0x0032, 0x0000}, + {0x0033, 0x0000}, + {0x0034, 0x0000}, + {0x0035, 0x0000}, + {0x003a, 0x0000}, + {0x003b, 0x0000}, + {0x003c, 0x00ff}, + {0x003d, 0x0000}, + {0x003e, 0x00ff}, + {0x003f, 0x0000}, + {0x0040, 0x0000}, + {0x0041, 0x00ff}, + {0x0042, 0x0000}, + {0x0043, 0x00ff}, + {0x0044, 0x0c0c}, + {0x0049, 0xc00b}, + {0x004a, 0x0000}, + {0x004b, 0x031f}, + {0x004d, 0x0000}, + {0x004e, 0x001f}, + {0x004f, 0x0000}, + {0x0050, 0x001f}, + {0x0052, 0xf000}, + {0x0061, 0x0000}, + {0x0062, 0x0000}, + {0x0063, 0x003e}, + {0x0064, 0x0000}, + {0x0065, 0x0000}, + {0x0066, 0x003f}, + {0x0067, 0x0000}, + {0x006b, 0x0000}, + {0x006d, 0xff00}, + {0x006e, 0x2808}, + {0x006f, 0x000a}, + {0x0070, 0x8000}, + {0x0071, 0x8000}, + {0x0072, 0x8000}, + {0x0073, 0x7000}, + {0x0074, 0x7770}, + {0x0075, 0x0002}, + {0x0076, 0x0001}, + {0x0078, 0x00f0}, + {0x0079, 0x0000}, + {0x007a, 0x0000}, + {0x007b, 0x0000}, + {0x007c, 0x0000}, + {0x007d, 0x0123}, + {0x007e, 0x4500}, + {0x007f, 0x8003}, + {0x0080, 0x0000}, + {0x0081, 0x0000}, + {0x0082, 0x0000}, + {0x0083, 0x0000}, + {0x0084, 0x0000}, + {0x0085, 0x0000}, + {0x0086, 0x0008}, + {0x0087, 0x0000}, + {0x0088, 0x0000}, + {0x0089, 0x0000}, + {0x008a, 0x0000}, + {0x008b, 0x0000}, + {0x008c, 0x0003}, + {0x008e, 0x0060}, + {0x008f, 0x1000}, + {0x0091, 0x0c26}, + {0x0092, 0x0073}, + {0x0093, 0x0000}, + {0x0094, 0x0080}, + {0x0098, 0x0000}, + {0x0099, 0x0000}, + {0x009a, 0x0007}, + {0x009f, 0x0000}, + {0x00a0, 0x0000}, + {0x00a1, 0x0002}, + {0x00a2, 0x0001}, + {0x00a3, 0x0002}, + {0x00a4, 0x0001}, + {0x00ae, 0x2040}, + {0x00af, 0x0000}, + {0x00b6, 0x0000}, + {0x00b7, 0x0000}, + {0x00b8, 0x0000}, + {0x00b9, 0x0000}, + {0x00ba, 0x0002}, + {0x00bb, 0x0000}, + {0x00be, 0x0000}, + {0x00c0, 0x0000}, + {0x00c1, 0x0aaa}, + {0x00c2, 0xaa80}, + {0x00c3, 0x0003}, + {0x00c4, 0x0000}, + {0x00d0, 0x0000}, + {0x00d1, 0x2244}, + {0x00d3, 0x3300}, + {0x00d4, 0x2200}, + {0x00d9, 0x0809}, + {0x00da, 0x0000}, + {0x00db, 0x0008}, + {0x00dc, 0x00c0}, + {0x00dd, 0x6724}, + {0x00de, 0x3131}, + {0x00df, 0x0008}, + {0x00e0, 0x4000}, + {0x00e1, 0x3131}, + {0x00e2, 0x600c}, + {0x00ea, 0xb320}, + {0x00eb, 0x0000}, + {0x00ec, 0xb300}, + {0x00ed, 0x0000}, + {0x00ee, 0xb320}, + {0x00ef, 0x0000}, + {0x00f0, 0x0201}, + {0x00f1, 0x0ddd}, + {0x00f2, 0x0ddd}, + {0x00f6, 0x0000}, + {0x00f7, 0x0000}, + {0x00f8, 0x0000}, + {0x00fa, 0x0000}, + {0x00fb, 0x0000}, + {0x00fc, 0x0000}, + {0x00fd, 0x0000}, + {0x00fe, 0x10ec}, + {0x00ff, 0x6451}, + {0x0100, 0xaaaa}, + {0x0101, 0x000a}, + {0x010a, 0xaaaa}, + {0x010b, 0xa0a0}, + {0x010c, 0xaeae}, + {0x010d, 0xaaaa}, + {0x010e, 0xaaaa}, + {0x010f, 0xaaaa}, + {0x0110, 0xe002}, + {0x0111, 0xa402}, + {0x0112, 0xaaaa}, + {0x0113, 0x2000}, + {0x0117, 0x0f00}, + {0x0125, 0x0410}, + {0x0132, 0x0000}, + {0x0133, 0x0000}, + {0x0137, 0x5540}, + {0x0138, 0x3700}, + {0x0139, 0x79a1}, + {0x013a, 0x2020}, + {0x013b, 0x2020}, + {0x013c, 0x2005}, + {0x013f, 0x0000}, + {0x0145, 0x0002}, + {0x0146, 0x0000}, + {0x0147, 0x0000}, + {0x0148, 0x0000}, + {0x0150, 0x0000}, + {0x0160, 0x4eff}, + {0x0161, 0x0080}, + {0x0162, 0x0200}, + {0x0163, 0x0800}, + {0x0164, 0x0000}, + {0x0165, 0x0000}, + {0x0166, 0x0000}, + {0x0167, 0x000f}, + {0x0170, 0x4e87}, + {0x0171, 0x0080}, + {0x0172, 0x0200}, + {0x0173, 0x0800}, + {0x0174, 0x00ff}, + {0x0175, 0x0000}, + {0x0190, 0x413d}, + {0x0191, 0x4139}, + {0x0192, 0x4135}, + {0x0193, 0x413d}, + {0x0194, 0x0000}, + {0x0195, 0x0000}, + {0x0196, 0x0000}, + {0x0197, 0x0000}, + {0x0198, 0x0000}, + {0x0199, 0x0000}, + {0x01a0, 0x1e64}, + {0x01a1, 0x06a3}, + {0x01a2, 0x0000}, + {0x01a3, 0x0000}, + {0x01a4, 0x0000}, + {0x01a5, 0x0000}, + {0x01a6, 0x0000}, + {0x01a7, 0x8000}, + {0x01a8, 0x0000}, + {0x01a9, 0x0000}, + {0x01aa, 0x0000}, + {0x01ab, 0x0000}, + {0x01b5, 0x0000}, + {0x01b6, 0x01c3}, + {0x01b7, 0x02a0}, + {0x01b8, 0x03e9}, + {0x01b9, 0x1389}, + {0x01ba, 0xc351}, + {0x01bb, 0x0009}, + {0x01bc, 0x0018}, + {0x01bd, 0x002a}, + {0x01be, 0x004c}, + {0x01bf, 0x0097}, + {0x01c0, 0x433d}, + {0x01c1, 0x0000}, + {0x01c2, 0x0000}, + {0x01c3, 0x0000}, + {0x01c4, 0x0000}, + {0x01c5, 0x0000}, + {0x01c6, 0x0000}, + {0x01c7, 0x0000}, + {0x01c8, 0x40af}, + {0x01c9, 0x0702}, + {0x01ca, 0x0000}, + {0x01cb, 0x0000}, + {0x01cc, 0x5757}, + {0x01cd, 0x5757}, + {0x01ce, 0x5757}, + {0x01cf, 0x5757}, + {0x01d0, 0x5757}, + {0x01d1, 0x5757}, + {0x01d2, 0x5757}, + {0x01d3, 0x5757}, + {0x01d4, 0x5757}, + {0x01d5, 0x5757}, + {0x01d6, 0x003c}, + {0x01da, 0x0000}, + {0x01db, 0x0000}, + {0x01dc, 0x0000}, + {0x01de, 0x7c00}, + {0x01df, 0x0320}, + {0x01e0, 0x06a1}, + {0x01e1, 0x0000}, + {0x01e2, 0x0000}, + {0x01e3, 0x0000}, + {0x01e4, 0x0000}, + {0x01e6, 0x0001}, + {0x01e7, 0x0000}, + {0x01e8, 0x0000}, + {0x01ea, 0xbf3f}, + {0x01eb, 0x0000}, + {0x01ec, 0x0000}, + {0x01ed, 0x0000}, + {0x01ee, 0x0000}, + {0x01ef, 0x0000}, + {0x01f0, 0x0000}, + {0x01f1, 0x0000}, + {0x01f2, 0x0000}, + {0x01f3, 0x0000}, + {0x01f4, 0x0000}, + {0x0200, 0x0000}, + {0x0201, 0x0000}, + {0x0202, 0x0000}, + {0x0203, 0x0000}, + {0x0204, 0x0000}, + {0x0205, 0x0000}, + {0x0206, 0x0000}, + {0x0207, 0x0000}, + {0x0208, 0x0000}, + {0x0210, 0x60b1}, + {0x0211, 0xa005}, + {0x0212, 0x024c}, + {0x0213, 0xf7ff}, + {0x0214, 0x024c}, + {0x0215, 0x0102}, + {0x0216, 0x00a3}, + {0x0217, 0x0048}, + {0x0218, 0xa2c0}, + {0x0219, 0x0400}, + {0x021a, 0x00c8}, + {0x021b, 0x00c0}, + {0x02ff, 0x0110}, + {0x0300, 0x001f}, + {0x0301, 0x032c}, + {0x0302, 0x5f21}, + {0x0303, 0x4000}, + {0x0304, 0x4000}, + {0x0305, 0x06d5}, + {0x0306, 0x8000}, + {0x0307, 0x0700}, + {0x0310, 0x4560}, + {0x0311, 0xa4a8}, + {0x0312, 0x7418}, + {0x0313, 0x0000}, + {0x0314, 0x0006}, + {0x0315, 0xffff}, + {0x0316, 0xc400}, + {0x0317, 0x0000}, + {0x0330, 0x00a6}, + {0x0331, 0x04c3}, + {0x0332, 0x27c8}, + {0x0333, 0xbf50}, + {0x0334, 0x0045}, + {0x0335, 0x0007}, + {0x0336, 0x7418}, + {0x0337, 0x0501}, + {0x0338, 0x0000}, + {0x0339, 0x0010}, + {0x033a, 0x1010}, + {0x03c0, 0x7e00}, + {0x03c1, 0x8000}, + {0x03c2, 0x8000}, + {0x03c3, 0x8000}, + {0x03c4, 0x8000}, + {0x03c5, 0x8000}, + {0x03c6, 0x8000}, + {0x03c7, 0x8000}, + {0x03c8, 0x8000}, + {0x03c9, 0x8000}, + {0x03ca, 0x8000}, + {0x03cb, 0x8000}, + {0x03cc, 0x8000}, + {0x03d0, 0x0000}, + {0x03d1, 0x0000}, + {0x03d2, 0x0000}, + {0x03d3, 0x0000}, + {0x03d4, 0x2000}, + {0x03d5, 0x2000}, + {0x03d6, 0x0000}, + {0x03d7, 0x0000}, + {0x03d8, 0x2000}, + {0x03d9, 0x2000}, + {0x03da, 0x2000}, + {0x03db, 0x2000}, + {0x03dc, 0x0000}, + {0x03dd, 0x0000}, + {0x03de, 0x0000}, + {0x03df, 0x2000}, + {0x03e0, 0x0000}, + {0x03e1, 0x0000}, + {0x03e2, 0x0000}, + {0x03e3, 0x0000}, + {0x03e4, 0x0000}, + {0x03e5, 0x0000}, + {0x03e6, 0x0000}, + {0x03e7, 0x0000}, + {0x03e8, 0x0000}, + {0x03e9, 0x0000}, + {0x03ea, 0x0000}, + {0x03eb, 0x0000}, + {0x03ec, 0x0000}, + {0x03ed, 0x0000}, + {0x03ee, 0x0000}, + {0x03ef, 0x0000}, + {0x03f0, 0x0800}, + {0x03f1, 0x0800}, + {0x03f2, 0x0800}, + {0x03f3, 0x0800}, +}; + +static bool rt5665_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5665_RESET: + case RT5665_EJD_CTRL_2: + case RT5665_GPIO_STA: + case RT5665_INT_ST_1: + case RT5665_IL_CMD_1: + case RT5665_4BTN_IL_CMD_1: + case RT5665_PSV_IL_CMD_1: + case RT5665_AJD1_CTRL: + case RT5665_JD_CTRL_3: + case RT5665_STO_NG2_CTRL_1: + case RT5665_SAR_IL_CMD_4: + case RT5665_DEVICE_ID: + case RT5665_STO1_DAC_SIL_DET ... RT5665_STO2_DAC_SIL_DET: + case RT5665_MONO_AMP_CALIB_STA1 ... RT5665_MONO_AMP_CALIB_STA6: + case RT5665_HP_IMP_SENS_CTRL_12 ... RT5665_HP_IMP_SENS_CTRL_15: + case RT5665_HP_CALIB_STA_1 ... RT5665_HP_CALIB_STA_11: + return true; + default: + return false; + } +} + +static bool rt5665_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5665_RESET: + case RT5665_VENDOR_ID: + case RT5665_VENDOR_ID_1: + case RT5665_DEVICE_ID: + case RT5665_LOUT: + case RT5665_HP_CTRL_1: + case RT5665_HP_CTRL_2: + case RT5665_MONO_OUT: + case RT5665_HPL_GAIN: + case RT5665_HPR_GAIN: + case RT5665_MONO_GAIN: + case RT5665_CAL_BST_CTRL: + case RT5665_CBJ_BST_CTRL: + case RT5665_IN1_IN2: + case RT5665_IN3_IN4: + case RT5665_INL1_INR1_VOL: + case RT5665_EJD_CTRL_1: + case RT5665_EJD_CTRL_2: + case RT5665_EJD_CTRL_3: + case RT5665_EJD_CTRL_4: + case RT5665_EJD_CTRL_5: + case RT5665_EJD_CTRL_6: + case RT5665_EJD_CTRL_7: + case RT5665_DAC2_CTRL: + case RT5665_DAC2_DIG_VOL: + case RT5665_DAC1_DIG_VOL: + case RT5665_DAC3_DIG_VOL: + case RT5665_DAC3_CTRL: + case RT5665_STO1_ADC_DIG_VOL: + case RT5665_MONO_ADC_DIG_VOL: + case RT5665_STO2_ADC_DIG_VOL: + case RT5665_STO1_ADC_BOOST: + case RT5665_MONO_ADC_BOOST: + case RT5665_STO2_ADC_BOOST: + case RT5665_HP_IMP_GAIN_1: + case RT5665_HP_IMP_GAIN_2: + case RT5665_STO1_ADC_MIXER: + case RT5665_MONO_ADC_MIXER: + case RT5665_STO2_ADC_MIXER: + case RT5665_AD_DA_MIXER: + case RT5665_STO1_DAC_MIXER: + case RT5665_MONO_DAC_MIXER: + case RT5665_STO2_DAC_MIXER: + case RT5665_A_DAC1_MUX: + case RT5665_A_DAC2_MUX: + case RT5665_DIG_INF2_DATA: + case RT5665_DIG_INF3_DATA: + case RT5665_PDM_OUT_CTRL: + case RT5665_PDM_DATA_CTRL_1: + case RT5665_PDM_DATA_CTRL_2: + case RT5665_PDM_DATA_CTRL_3: + case RT5665_PDM_DATA_CTRL_4: + case RT5665_REC1_GAIN: + case RT5665_REC1_L1_MIXER: + case RT5665_REC1_L2_MIXER: + case RT5665_REC1_R1_MIXER: + case RT5665_REC1_R2_MIXER: + case RT5665_REC2_GAIN: + case RT5665_REC2_L1_MIXER: + case RT5665_REC2_L2_MIXER: + case RT5665_REC2_R1_MIXER: + case RT5665_REC2_R2_MIXER: + case RT5665_CAL_REC: + case RT5665_ALC_BACK_GAIN: + case RT5665_MONOMIX_GAIN: + case RT5665_MONOMIX_IN_GAIN: + case RT5665_OUT_L_GAIN: + case RT5665_OUT_L_MIXER: + case RT5665_OUT_R_GAIN: + case RT5665_OUT_R_MIXER: + case RT5665_LOUT_MIXER: + case RT5665_PWR_DIG_1: + case RT5665_PWR_DIG_2: + case RT5665_PWR_ANLG_1: + case RT5665_PWR_ANLG_2: + case RT5665_PWR_ANLG_3: + case RT5665_PWR_MIXER: + case RT5665_PWR_VOL: + case RT5665_CLK_DET: + case RT5665_HPF_CTRL1: + case RT5665_DMIC_CTRL_1: + case RT5665_DMIC_CTRL_2: + case RT5665_I2S1_SDP: + case RT5665_I2S2_SDP: + case RT5665_I2S3_SDP: + case RT5665_ADDA_CLK_1: + case RT5665_ADDA_CLK_2: + case RT5665_I2S1_F_DIV_CTRL_1: + case RT5665_I2S1_F_DIV_CTRL_2: + case RT5665_TDM_CTRL_1: + case RT5665_TDM_CTRL_2: + case RT5665_TDM_CTRL_3: + case RT5665_TDM_CTRL_4: + case RT5665_TDM_CTRL_5: + case RT5665_TDM_CTRL_6: + case RT5665_TDM_CTRL_7: + case RT5665_TDM_CTRL_8: + case RT5665_GLB_CLK: + case RT5665_PLL_CTRL_1: + case RT5665_PLL_CTRL_2: + case RT5665_ASRC_1: + case RT5665_ASRC_2: + case RT5665_ASRC_3: + case RT5665_ASRC_4: + case RT5665_ASRC_5: + case RT5665_ASRC_6: + case RT5665_ASRC_7: + case RT5665_ASRC_8: + case RT5665_ASRC_9: + case RT5665_ASRC_10: + case RT5665_DEPOP_1: + case RT5665_DEPOP_2: + case RT5665_HP_CHARGE_PUMP_1: + case RT5665_HP_CHARGE_PUMP_2: + case RT5665_MICBIAS_1: + case RT5665_MICBIAS_2: + case RT5665_ASRC_12: + case RT5665_ASRC_13: + case RT5665_ASRC_14: + case RT5665_RC_CLK_CTRL: + case RT5665_I2S_M_CLK_CTRL_1: + case RT5665_I2S2_F_DIV_CTRL_1: + case RT5665_I2S2_F_DIV_CTRL_2: + case RT5665_I2S3_F_DIV_CTRL_1: + case RT5665_I2S3_F_DIV_CTRL_2: + case RT5665_EQ_CTRL_1: + case RT5665_EQ_CTRL_2: + case RT5665_IRQ_CTRL_1: + case RT5665_IRQ_CTRL_2: + case RT5665_IRQ_CTRL_3: + case RT5665_IRQ_CTRL_4: + case RT5665_IRQ_CTRL_5: + case RT5665_IRQ_CTRL_6: + case RT5665_INT_ST_1: + case RT5665_GPIO_CTRL_1: + case RT5665_GPIO_CTRL_2: + case RT5665_GPIO_CTRL_3: + case RT5665_GPIO_CTRL_4: + case RT5665_GPIO_STA: + case RT5665_HP_AMP_DET_CTRL_1: + case RT5665_HP_AMP_DET_CTRL_2: + case RT5665_MID_HP_AMP_DET: + case RT5665_LOW_HP_AMP_DET: + case RT5665_SV_ZCD_1: + case RT5665_SV_ZCD_2: + case RT5665_IL_CMD_1: + case RT5665_IL_CMD_2: + case RT5665_IL_CMD_3: + case RT5665_IL_CMD_4: + case RT5665_4BTN_IL_CMD_1: + case RT5665_4BTN_IL_CMD_2: + case RT5665_4BTN_IL_CMD_3: + case RT5665_PSV_IL_CMD_1: + case RT5665_ADC_STO1_HP_CTRL_1: + case RT5665_ADC_STO1_HP_CTRL_2: + case RT5665_ADC_MONO_HP_CTRL_1: + case RT5665_ADC_MONO_HP_CTRL_2: + case RT5665_ADC_STO2_HP_CTRL_1: + case RT5665_ADC_STO2_HP_CTRL_2: + case RT5665_AJD1_CTRL: + case RT5665_JD1_THD: + case RT5665_JD2_THD: + case RT5665_JD_CTRL_1: + case RT5665_JD_CTRL_2: + case RT5665_JD_CTRL_3: + case RT5665_DIG_MISC: + case RT5665_DUMMY_2: + case RT5665_DUMMY_3: + case RT5665_DAC_ADC_DIG_VOL1: + case RT5665_DAC_ADC_DIG_VOL2: + case RT5665_BIAS_CUR_CTRL_1: + case RT5665_BIAS_CUR_CTRL_2: + case RT5665_BIAS_CUR_CTRL_3: + case RT5665_BIAS_CUR_CTRL_4: + case RT5665_BIAS_CUR_CTRL_5: + case RT5665_BIAS_CUR_CTRL_6: + case RT5665_BIAS_CUR_CTRL_7: + case RT5665_BIAS_CUR_CTRL_8: + case RT5665_BIAS_CUR_CTRL_9: + case RT5665_BIAS_CUR_CTRL_10: + case RT5665_VREF_REC_OP_FB_CAP_CTRL: + case RT5665_CHARGE_PUMP_1: + case RT5665_DIG_IN_CTRL_1: + case RT5665_DIG_IN_CTRL_2: + case RT5665_PAD_DRIVING_CTRL: + case RT5665_SOFT_RAMP_DEPOP: + case RT5665_PLL: + case RT5665_CHOP_DAC: + case RT5665_CHOP_ADC: + case RT5665_CALIB_ADC_CTRL: + case RT5665_VOL_TEST: + case RT5665_TEST_MODE_CTRL_1: + case RT5665_TEST_MODE_CTRL_2: + case RT5665_TEST_MODE_CTRL_3: + case RT5665_TEST_MODE_CTRL_4: + case RT5665_BASSBACK_CTRL: + case RT5665_STO_NG2_CTRL_1: + case RT5665_STO_NG2_CTRL_2: + case RT5665_STO_NG2_CTRL_3: + case RT5665_STO_NG2_CTRL_4: + case RT5665_STO_NG2_CTRL_5: + case RT5665_STO_NG2_CTRL_6: + case RT5665_STO_NG2_CTRL_7: + case RT5665_STO_NG2_CTRL_8: + case RT5665_MONO_NG2_CTRL_1: + case RT5665_MONO_NG2_CTRL_2: + case RT5665_MONO_NG2_CTRL_3: + case RT5665_MONO_NG2_CTRL_4: + case RT5665_MONO_NG2_CTRL_5: + case RT5665_MONO_NG2_CTRL_6: + case RT5665_STO1_DAC_SIL_DET: + case RT5665_MONOL_DAC_SIL_DET: + case RT5665_MONOR_DAC_SIL_DET: + case RT5665_STO2_DAC_SIL_DET: + case RT5665_SIL_PSV_CTRL1: + case RT5665_SIL_PSV_CTRL2: + case RT5665_SIL_PSV_CTRL3: + case RT5665_SIL_PSV_CTRL4: + case RT5665_SIL_PSV_CTRL5: + case RT5665_SIL_PSV_CTRL6: + case RT5665_MONO_AMP_CALIB_CTRL_1: + case RT5665_MONO_AMP_CALIB_CTRL_2: + case RT5665_MONO_AMP_CALIB_CTRL_3: + case RT5665_MONO_AMP_CALIB_CTRL_4: + case RT5665_MONO_AMP_CALIB_CTRL_5: + case RT5665_MONO_AMP_CALIB_CTRL_6: + case RT5665_MONO_AMP_CALIB_CTRL_7: + case RT5665_MONO_AMP_CALIB_STA1: + case RT5665_MONO_AMP_CALIB_STA2: + case RT5665_MONO_AMP_CALIB_STA3: + case RT5665_MONO_AMP_CALIB_STA4: + case RT5665_MONO_AMP_CALIB_STA6: + case RT5665_HP_IMP_SENS_CTRL_01: + case RT5665_HP_IMP_SENS_CTRL_02: + case RT5665_HP_IMP_SENS_CTRL_03: + case RT5665_HP_IMP_SENS_CTRL_04: + case RT5665_HP_IMP_SENS_CTRL_05: + case RT5665_HP_IMP_SENS_CTRL_06: + case RT5665_HP_IMP_SENS_CTRL_07: + case RT5665_HP_IMP_SENS_CTRL_08: + case RT5665_HP_IMP_SENS_CTRL_09: + case RT5665_HP_IMP_SENS_CTRL_10: + case RT5665_HP_IMP_SENS_CTRL_11: + case RT5665_HP_IMP_SENS_CTRL_12: + case RT5665_HP_IMP_SENS_CTRL_13: + case RT5665_HP_IMP_SENS_CTRL_14: + case RT5665_HP_IMP_SENS_CTRL_15: + case RT5665_HP_IMP_SENS_CTRL_16: + case RT5665_HP_IMP_SENS_CTRL_17: + case RT5665_HP_IMP_SENS_CTRL_18: + case RT5665_HP_IMP_SENS_CTRL_19: + case RT5665_HP_IMP_SENS_CTRL_20: + case RT5665_HP_IMP_SENS_CTRL_21: + case RT5665_HP_IMP_SENS_CTRL_22: + case RT5665_HP_IMP_SENS_CTRL_23: + case RT5665_HP_IMP_SENS_CTRL_24: + case RT5665_HP_IMP_SENS_CTRL_25: + case RT5665_HP_IMP_SENS_CTRL_26: + case RT5665_HP_IMP_SENS_CTRL_27: + case RT5665_HP_IMP_SENS_CTRL_28: + case RT5665_HP_IMP_SENS_CTRL_29: + case RT5665_HP_IMP_SENS_CTRL_30: + case RT5665_HP_IMP_SENS_CTRL_31: + case RT5665_HP_IMP_SENS_CTRL_32: + case RT5665_HP_IMP_SENS_CTRL_33: + case RT5665_HP_IMP_SENS_CTRL_34: + case RT5665_HP_LOGIC_CTRL_1: + case RT5665_HP_LOGIC_CTRL_2: + case RT5665_HP_LOGIC_CTRL_3: + case RT5665_HP_CALIB_CTRL_1: + case RT5665_HP_CALIB_CTRL_2: + case RT5665_HP_CALIB_CTRL_3: + case RT5665_HP_CALIB_CTRL_4: + case RT5665_HP_CALIB_CTRL_5: + case RT5665_HP_CALIB_CTRL_6: + case RT5665_HP_CALIB_CTRL_7: + case RT5665_HP_CALIB_CTRL_9: + case RT5665_HP_CALIB_CTRL_10: + case RT5665_HP_CALIB_CTRL_11: + case RT5665_HP_CALIB_STA_1: + case RT5665_HP_CALIB_STA_2: + case RT5665_HP_CALIB_STA_3: + case RT5665_HP_CALIB_STA_4: + case RT5665_HP_CALIB_STA_5: + case RT5665_HP_CALIB_STA_6: + case RT5665_HP_CALIB_STA_7: + case RT5665_HP_CALIB_STA_8: + case RT5665_HP_CALIB_STA_9: + case RT5665_HP_CALIB_STA_10: + case RT5665_HP_CALIB_STA_11: + case RT5665_PGM_TAB_CTRL1: + case RT5665_PGM_TAB_CTRL2: + case RT5665_PGM_TAB_CTRL3: + case RT5665_PGM_TAB_CTRL4: + case RT5665_PGM_TAB_CTRL5: + case RT5665_PGM_TAB_CTRL6: + case RT5665_PGM_TAB_CTRL7: + case RT5665_PGM_TAB_CTRL8: + case RT5665_PGM_TAB_CTRL9: + case RT5665_SAR_IL_CMD_1: + case RT5665_SAR_IL_CMD_2: + case RT5665_SAR_IL_CMD_3: + case RT5665_SAR_IL_CMD_4: + case RT5665_SAR_IL_CMD_5: + case RT5665_SAR_IL_CMD_6: + case RT5665_SAR_IL_CMD_7: + case RT5665_SAR_IL_CMD_8: + case RT5665_SAR_IL_CMD_9: + case RT5665_SAR_IL_CMD_10: + case RT5665_SAR_IL_CMD_11: + case RT5665_SAR_IL_CMD_12: + case RT5665_DRC1_CTRL_0: + case RT5665_DRC1_CTRL_1: + case RT5665_DRC1_CTRL_2: + case RT5665_DRC1_CTRL_3: + case RT5665_DRC1_CTRL_4: + case RT5665_DRC1_CTRL_5: + case RT5665_DRC1_CTRL_6: + case RT5665_DRC1_HARD_LMT_CTRL_1: + case RT5665_DRC1_HARD_LMT_CTRL_2: + case RT5665_DRC1_PRIV_1: + case RT5665_DRC1_PRIV_2: + case RT5665_DRC1_PRIV_3: + case RT5665_DRC1_PRIV_4: + case RT5665_DRC1_PRIV_5: + case RT5665_DRC1_PRIV_6: + case RT5665_DRC1_PRIV_7: + case RT5665_DRC1_PRIV_8: + case RT5665_ALC_PGA_CTRL_1: + case RT5665_ALC_PGA_CTRL_2: + case RT5665_ALC_PGA_CTRL_3: + case RT5665_ALC_PGA_CTRL_4: + case RT5665_ALC_PGA_CTRL_5: + case RT5665_ALC_PGA_CTRL_6: + case RT5665_ALC_PGA_CTRL_7: + case RT5665_ALC_PGA_CTRL_8: + case RT5665_ALC_PGA_STA_1: + case RT5665_ALC_PGA_STA_2: + case RT5665_ALC_PGA_STA_3: + case RT5665_EQ_AUTO_RCV_CTRL1: + case RT5665_EQ_AUTO_RCV_CTRL2: + case RT5665_EQ_AUTO_RCV_CTRL3: + case RT5665_EQ_AUTO_RCV_CTRL4: + case RT5665_EQ_AUTO_RCV_CTRL5: + case RT5665_EQ_AUTO_RCV_CTRL6: + case RT5665_EQ_AUTO_RCV_CTRL7: + case RT5665_EQ_AUTO_RCV_CTRL8: + case RT5665_EQ_AUTO_RCV_CTRL9: + case RT5665_EQ_AUTO_RCV_CTRL10: + case RT5665_EQ_AUTO_RCV_CTRL11: + case RT5665_EQ_AUTO_RCV_CTRL12: + case RT5665_EQ_AUTO_RCV_CTRL13: + case RT5665_ADC_L_EQ_LPF1_A1: + case RT5665_R_EQ_LPF1_A1: + case RT5665_L_EQ_LPF1_H0: + case RT5665_R_EQ_LPF1_H0: + case RT5665_L_EQ_BPF1_A1: + case RT5665_R_EQ_BPF1_A1: + case RT5665_L_EQ_BPF1_A2: + case RT5665_R_EQ_BPF1_A2: + case RT5665_L_EQ_BPF1_H0: + case RT5665_R_EQ_BPF1_H0: + case RT5665_L_EQ_BPF2_A1: + case RT5665_R_EQ_BPF2_A1: + case RT5665_L_EQ_BPF2_A2: + case RT5665_R_EQ_BPF2_A2: + case RT5665_L_EQ_BPF2_H0: + case RT5665_R_EQ_BPF2_H0: + case RT5665_L_EQ_BPF3_A1: + case RT5665_R_EQ_BPF3_A1: + case RT5665_L_EQ_BPF3_A2: + case RT5665_R_EQ_BPF3_A2: + case RT5665_L_EQ_BPF3_H0: + case RT5665_R_EQ_BPF3_H0: + case RT5665_L_EQ_BPF4_A1: + case RT5665_R_EQ_BPF4_A1: + case RT5665_L_EQ_BPF4_A2: + case RT5665_R_EQ_BPF4_A2: + case RT5665_L_EQ_BPF4_H0: + case RT5665_R_EQ_BPF4_H0: + case RT5665_L_EQ_HPF1_A1: + case RT5665_R_EQ_HPF1_A1: + case RT5665_L_EQ_HPF1_H0: + case RT5665_R_EQ_HPF1_H0: + case RT5665_L_EQ_PRE_VOL: + case RT5665_R_EQ_PRE_VOL: + case RT5665_L_EQ_POST_VOL: + case RT5665_R_EQ_POST_VOL: + case RT5665_SCAN_MODE_CTRL: + case RT5665_I2C_MODE: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0); +static const DECLARE_TLV_DB_SCALE(mono_vol_tlv, -1400, 150, 0); +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static const DECLARE_TLV_DB_RANGE(bst_tlv, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), + 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); + +/* Interface data select */ +static const char * const rt5665_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_01_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT01_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_23_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT23_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_45_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT45_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_67_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT67_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_01_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT01_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_23_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT23_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_45_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT45_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_67_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT67_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_dac_enum, + RT5665_DIG_INF2_DATA, RT5665_IF2_1_DAC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_adc_enum, + RT5665_DIG_INF2_DATA, RT5665_IF2_1_ADC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_dac_enum, + RT5665_DIG_INF2_DATA, RT5665_IF2_2_DAC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_adc_enum, + RT5665_DIG_INF2_DATA, RT5665_IF2_2_ADC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if3_dac_enum, + RT5665_DIG_INF3_DATA, RT5665_IF3_DAC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if3_adc_enum, + RT5665_DIG_INF3_DATA, RT5665_IF3_ADC_SEL_SFT, rt5665_data_select); + +static const struct snd_kcontrol_new rt5665_if1_1_01_adc_swap_mux = + SOC_DAPM_ENUM("IF1_1 01 ADC Swap Mux", rt5665_if1_1_01_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_1_23_adc_swap_mux = + SOC_DAPM_ENUM("IF1_1 23 ADC Swap Mux", rt5665_if1_1_23_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_1_45_adc_swap_mux = + SOC_DAPM_ENUM("IF1_1 45 ADC Swap Mux", rt5665_if1_1_45_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_1_67_adc_swap_mux = + SOC_DAPM_ENUM("IF1_1 67 ADC Swap Mux", rt5665_if1_1_67_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_01_adc_swap_mux = + SOC_DAPM_ENUM("IF1_2 01 ADC Swap Mux", rt5665_if1_2_01_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_23_adc_swap_mux = + SOC_DAPM_ENUM("IF1_2 23 ADC1 Swap Mux", rt5665_if1_2_23_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_45_adc_swap_mux = + SOC_DAPM_ENUM("IF1_2 45 ADC1 Swap Mux", rt5665_if1_2_45_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_67_adc_swap_mux = + SOC_DAPM_ENUM("IF1_2 67 ADC1 Swap Mux", rt5665_if1_2_67_adc_enum); + +static const struct snd_kcontrol_new rt5665_if2_1_dac_swap_mux = + SOC_DAPM_ENUM("IF2_1 DAC Swap Source", rt5665_if2_1_dac_enum); + +static const struct snd_kcontrol_new rt5665_if2_1_adc_swap_mux = + SOC_DAPM_ENUM("IF2_1 ADC Swap Source", rt5665_if2_1_adc_enum); + +static const struct snd_kcontrol_new rt5665_if2_2_dac_swap_mux = + SOC_DAPM_ENUM("IF2_2 DAC Swap Source", rt5665_if2_2_dac_enum); + +static const struct snd_kcontrol_new rt5665_if2_2_adc_swap_mux = + SOC_DAPM_ENUM("IF2_2 ADC Swap Source", rt5665_if2_2_adc_enum); + +static const struct snd_kcontrol_new rt5665_if3_dac_swap_mux = + SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5665_if3_dac_enum); + +static const struct snd_kcontrol_new rt5665_if3_adc_swap_mux = + SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5665_if3_adc_enum); + +static int rt5665_hp_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int ret = snd_soc_put_volsw(kcontrol, ucontrol); + + if (snd_soc_read(codec, RT5665_STO_NG2_CTRL_1) & RT5665_NG2_EN) { + snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_DIS); + snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_EN); + } + + return ret; +} + +static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int ret = snd_soc_put_volsw(kcontrol, ucontrol); + + if (snd_soc_read(codec, RT5665_MONO_NG2_CTRL_1) & RT5665_NG2_EN) { + snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_DIS); + snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_EN); + } + + return ret; +} + +/** + * rt5665_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5665 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + unsigned int asrc2_mask = 0; + unsigned int asrc2_value = 0; + unsigned int asrc3_mask = 0; + unsigned int asrc3_value = 0; + + switch (clk_src) { + case RT5665_CLK_SEL_SYS: + case RT5665_CLK_SEL_I2S1_ASRC: + case RT5665_CLK_SEL_I2S2_ASRC: + case RT5665_CLK_SEL_I2S3_ASRC: + case RT5665_CLK_SEL_SYS2: + case RT5665_CLK_SEL_SYS3: + case RT5665_CLK_SEL_SYS4: + break; + + default: + return -EINVAL; + } + + if (filter_mask & RT5665_DA_STEREO1_FILTER) { + asrc2_mask |= RT5665_DA_STO1_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5665_DA_STO1_CLK_SEL_MASK) + | (clk_src << RT5665_DA_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_DA_STEREO2_FILTER) { + asrc2_mask |= RT5665_DA_STO2_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5665_DA_STO2_CLK_SEL_MASK) + | (clk_src << RT5665_DA_STO2_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_DA_MONO_L_FILTER) { + asrc2_mask |= RT5665_DA_MONOL_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5665_DA_MONOL_CLK_SEL_MASK) + | (clk_src << RT5665_DA_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_DA_MONO_R_FILTER) { + asrc2_mask |= RT5665_DA_MONOR_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5665_DA_MONOR_CLK_SEL_MASK) + | (clk_src << RT5665_DA_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_AD_STEREO1_FILTER) { + asrc3_mask |= RT5665_AD_STO1_CLK_SEL_MASK; + asrc3_value = (asrc2_value & ~RT5665_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5665_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_AD_STEREO2_FILTER) { + asrc3_mask |= RT5665_AD_STO2_CLK_SEL_MASK; + asrc3_value = (asrc2_value & ~RT5665_AD_STO2_CLK_SEL_MASK) + | (clk_src << RT5665_AD_STO2_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_AD_MONO_L_FILTER) { + asrc3_mask |= RT5665_AD_MONOL_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5665_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5665_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_AD_MONO_R_FILTER) { + asrc3_mask |= RT5665_AD_MONOR_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5665_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5665_AD_MONOR_CLK_SEL_SFT); + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5665_ASRC_2, + asrc2_mask, asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5665_ASRC_3, + asrc3_mask, asrc3_value); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5665_sel_asrc_clk_src); + +static int rt5665_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5665_4BTN_IL_CMD_1); + btn_type = val & 0xfff0; + snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, val); + + return btn_type; +} + +static void rt5665_enable_push_button_irq(struct snd_soc_codec *codec, + bool enable) +{ + if (enable) { + snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, 0x000b); + snd_soc_write(codec, RT5665_IL_CMD_1, 0x0048); + snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, + RT5665_4BTN_IL_MASK | RT5665_4BTN_IL_RST_MASK, + RT5665_4BTN_IL_EN | RT5665_4BTN_IL_NOR); + snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3, + RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_EN); + } else { + snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3, + RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_DIS); + snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, + RT5665_4BTN_IL_MASK, RT5665_4BTN_IL_DIS); + snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, + RT5665_4BTN_IL_RST_MASK, RT5665_4BTN_IL_RST); + } +} + +/** + * rt5665_headset_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ +static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + unsigned int sar_hs_type, val; + + if (jack_insert) { + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_sync(dapm); + + regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100, + 0x100); + + regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val); + if (val & 0x4) { + regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, + 0x100, 0); + + regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val); + while (val & 0x4) { + usleep_range(10000, 15000); + regmap_read(rt5665->regmap, RT5665_GPIO_STA, + &val); + } + } + + regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, + 0x180, 0x180); + regmap_write(rt5665->regmap, RT5665_EJD_CTRL_3, 0x3424); + regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0xa291); + + rt5665->sar_adc_value = snd_soc_read(rt5665->codec, + RT5665_SAR_IL_CMD_4) & 0x7ff; + + sar_hs_type = rt5665->pdata.sar_hs_type ? + rt5665->pdata.sar_hs_type : 729; + + if (rt5665->sar_adc_value > sar_hs_type) { + rt5665->jack_type = SND_JACK_HEADSET; + rt5665_enable_push_button_irq(codec, true); + } else { + rt5665->jack_type = SND_JACK_HEADPHONE; + regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, + 0x2291); + regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, + 0x100, 0); + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_sync(dapm); + } + } else { + regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0x2291); + regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100, 0); + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_sync(dapm); + if (rt5665->jack_type == SND_JACK_HEADSET) + rt5665_enable_push_button_irq(codec, false); + rt5665->jack_type = 0; + } + + dev_dbg(codec->dev, "jack_type = %d\n", rt5665->jack_type); + return rt5665->jack_type; +} + +static irqreturn_t rt5665_irq(int irq, void *data) +{ + struct rt5665_priv *rt5665 = data; + + mod_delayed_work(system_power_efficient_wq, + &rt5665->jack_detect_work, msecs_to_jiffies(250)); + + return IRQ_HANDLED; +} + +static void rt5665_jd_check_handler(struct work_struct *work) +{ + struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv, + calibrate_work.work); + + if (snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010) { + /* jack out */ + rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0); + + snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + } else { + schedule_delayed_work(&rt5665->jd_check_work, 500); + } +} + +int rt5665_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + switch (rt5665->pdata.jd_src) { + case RT5665_JD1: + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, + RT5665_GP1_PIN_MASK, RT5665_GP1_PIN_IRQ); + regmap_update_bits(rt5665->regmap, RT5665_RC_CLK_CTRL, + 0xc000, 0xc000); + regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_2, + RT5665_PWR_JD1, RT5665_PWR_JD1); + regmap_update_bits(rt5665->regmap, RT5665_IRQ_CTRL_1, 0x8, 0x8); + break; + + case RT5665_JD_NULL: + break; + + default: + dev_warn(codec->dev, "Wrong JD source\n"); + break; + } + + rt5665->hs_jack = hs_jack; + + return 0; +} +EXPORT_SYMBOL_GPL(rt5665_set_jack_detect); + +static void rt5665_jack_detect_handler(struct work_struct *work) +{ + struct rt5665_priv *rt5665 = + container_of(work, struct rt5665_priv, jack_detect_work.work); + int val, btn_type; + + while (!rt5665->codec) { + pr_debug("%s codec = null\n", __func__); + usleep_range(10000, 15000); + } + + while (!rt5665->codec->component.card->instantiated) { + pr_debug("%s\n", __func__); + usleep_range(10000, 15000); + } + + mutex_lock(&rt5665->calibrate_mutex); + + val = snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010; + if (!val) { + /* jack in */ + if (rt5665->jack_type == 0) { + /* jack was out, report jack type */ + rt5665->jack_type = + rt5665_headset_detect(rt5665->codec, 1); + } else { + /* jack is already in, report button event */ + rt5665->jack_type = SND_JACK_HEADSET; + btn_type = rt5665_button_detect(rt5665->codec); + /** + * rt5665 can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + rt5665->jack_type |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + rt5665->jack_type |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + rt5665->jack_type |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + rt5665->jack_type |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + btn_type = 0; + dev_err(rt5665->codec->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } + } + } else { + /* jack out */ + rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0); + } + + snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (rt5665->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3)) + schedule_delayed_work(&rt5665->jd_check_work, 0); + else + cancel_delayed_work_sync(&rt5665->jd_check_work); + + mutex_unlock(&rt5665->calibrate_mutex); +} + +static const struct snd_kcontrol_new rt5665_snd_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5665_HPL_GAIN, + RT5665_HPR_GAIN, RT5665_G_HP_SFT, 15, 1, snd_soc_get_volsw, + rt5665_hp_vol_put, hp_vol_tlv), + + /* Mono Output Volume */ + SOC_SINGLE_EXT_TLV("Mono Playback Volume", RT5665_MONO_GAIN, + RT5665_L_VOL_SFT, 15, 1, snd_soc_get_volsw, + rt5665_mono_vol_put, mono_vol_tlv), + + /* Output Volume */ + SOC_DOUBLE_TLV("OUT Playback Volume", RT5665_LOUT, RT5665_L_VOL_SFT, + RT5665_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5665_DAC1_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv), + SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5665_DAC2_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv), + SOC_DOUBLE("DAC2 Playback Switch", RT5665_DAC2_CTRL, + RT5665_M_DAC2_L_VOL_SFT, RT5665_M_DAC2_R_VOL_SFT, 1, 1), + + /* IN1/IN2/IN3/IN4 Volume */ + SOC_SINGLE_TLV("IN1 Boost Volume", RT5665_IN1_IN2, + RT5665_BST1_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN2 Boost Volume", RT5665_IN1_IN2, + RT5665_BST2_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN3 Boost Volume", RT5665_IN3_IN4, + RT5665_BST3_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN4 Boost Volume", RT5665_IN3_IN4, + RT5665_BST4_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("CBJ Boost Volume", RT5665_CBJ_BST_CTRL, + RT5665_BST_CBJ_SFT, 8, 0, bst_tlv), + + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5665_INL1_INR1_VOL, + RT5665_INL_VOL_SFT, RT5665_INR_VOL_SFT, 31, 1, in_vol_tlv), + + /* ADC Digital Volume Control */ + SOC_DOUBLE("STO1 ADC Capture Switch", RT5665_STO1_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5665_STO1_ADC_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("Mono ADC Capture Switch", RT5665_MONO_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5665_MONO_ADC_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("STO2 ADC Capture Switch", RT5665_STO2_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5665_STO2_ADC_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5665_STO1_ADC_BOOST, + RT5665_STO1_ADC_L_BST_SFT, RT5665_STO1_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5665_MONO_ADC_BOOST, + RT5665_MONO_ADC_L_BST_SFT, RT5665_MONO_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5665_STO2_ADC_BOOST, + RT5665_STO2_ADC_L_BST_SFT, RT5665_STO2_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + int pd, idx = -EINVAL; + + pd = rl6231_get_pre_div(rt5665->regmap, + RT5665_ADDA_CLK_1, RT5665_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rt5665->sysclk / pd); + + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else { + snd_soc_update_bits(codec, RT5665_DMIC_CTRL_1, + RT5665_DMIC_CLK_MASK, idx << RT5665_DMIC_CLK_SFT); + } + return idx; +} + +static int rt5665_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1, + RT5665_PM_HP_MASK | RT5665_OSW_L_MASK, + RT5665_PM_HP_HV | RT5665_OSW_L_EN); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1, + RT5665_PM_HP_MASK | RT5665_OSW_L_MASK, + RT5665_PM_HP_LV | RT5665_OSW_L_DIS); + break; + default: + return 0; + } + + return 0; +} + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + val = snd_soc_read(codec, RT5665_GLB_CLK); + val &= RT5665_SCLK_SRC_MASK; + if (val == RT5665_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +static int is_using_asrc(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, shift, val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (w->shift) { + case RT5665_ADC_MONO_R_ASRC_SFT: + reg = RT5665_ASRC_3; + shift = RT5665_AD_MONOR_CLK_SEL_SFT; + break; + case RT5665_ADC_MONO_L_ASRC_SFT: + reg = RT5665_ASRC_3; + shift = RT5665_AD_MONOL_CLK_SEL_SFT; + break; + case RT5665_ADC_STO1_ASRC_SFT: + reg = RT5665_ASRC_3; + shift = RT5665_AD_STO1_CLK_SEL_SFT; + break; + case RT5665_ADC_STO2_ASRC_SFT: + reg = RT5665_ASRC_3; + shift = RT5665_AD_STO2_CLK_SEL_SFT; + break; + case RT5665_DAC_MONO_R_ASRC_SFT: + reg = RT5665_ASRC_2; + shift = RT5665_DA_MONOR_CLK_SEL_SFT; + break; + case RT5665_DAC_MONO_L_ASRC_SFT: + reg = RT5665_ASRC_2; + shift = RT5665_DA_MONOL_CLK_SEL_SFT; + break; + case RT5665_DAC_STO1_ASRC_SFT: + reg = RT5665_ASRC_2; + shift = RT5665_DA_STO1_CLK_SEL_SFT; + break; + case RT5665_DAC_STO2_ASRC_SFT: + reg = RT5665_ASRC_2; + shift = RT5665_DA_STO2_CLK_SEL_SFT; + break; + default: + return 0; + } + + val = (snd_soc_read(codec, reg) >> shift) & 0xf; + switch (val) { + case RT5665_CLK_SEL_I2S1_ASRC: + case RT5665_CLK_SEL_I2S2_ASRC: + case RT5665_CLK_SEL_I2S3_ASRC: + /* I2S_Pre_Div1 should be 1 in asrc mode */ + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_I2S_PD1_MASK, RT5665_I2S_PD1_2); + return 1; + default: + return 0; + } + +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5665_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER, + RT5665_M_STO1_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER, + RT5665_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER, + RT5665_M_STO1_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER, + RT5665_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER, + RT5665_M_STO2_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER, + RT5665_M_STO2_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER, + RT5665_M_STO2_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER, + RT5665_M_STO2_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER, + RT5665_M_MONO_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER, + RT5665_M_MONO_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER, + RT5665_M_MONO_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER, + RT5665_M_MONO_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER, + RT5665_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER, + RT5665_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER, + RT5665_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER, + RT5665_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto1_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_L1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_R1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_L2_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_R2_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto1_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_L1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_R1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_L2_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_R2_STO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_L1_STO2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_L2_STO2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L3 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_L3_STO2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_R1_STO2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_R2_STO2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R3 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_R3_STO2_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_L1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_R1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_L2_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_R2_MONO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_L1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_R1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_L2_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_R2_MONO_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5665_rec1_l_mix[] = { + SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC1_L2_MIXER, + RT5665_M_CBJ_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5665_REC1_L2_MIXER, + RT5665_M_INL_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_L2_MIXER, + RT5665_M_INR_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_L2_MIXER, + RT5665_M_BST4_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_L2_MIXER, + RT5665_M_BST3_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_L2_MIXER, + RT5665_M_BST2_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_L2_MIXER, + RT5665_M_BST1_RM1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_rec1_r_mix[] = { + SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC1_R2_MIXER, + RT5665_M_AEC_REF_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_R2_MIXER, + RT5665_M_INR_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_R2_MIXER, + RT5665_M_BST4_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_R2_MIXER, + RT5665_M_BST3_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_R2_MIXER, + RT5665_M_BST2_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_R2_MIXER, + RT5665_M_BST1_RM1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_rec2_l_mix[] = { + SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_L2_MIXER, + RT5665_M_INL_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_L2_MIXER, + RT5665_M_INR_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC2_L2_MIXER, + RT5665_M_CBJ_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_L2_MIXER, + RT5665_M_BST4_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_L2_MIXER, + RT5665_M_BST3_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_L2_MIXER, + RT5665_M_BST2_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_L2_MIXER, + RT5665_M_BST1_RM2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_rec2_r_mix[] = { + SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC2_R2_MIXER, + RT5665_M_MONOVOL_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_R2_MIXER, + RT5665_M_INL_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_R2_MIXER, + RT5665_M_INR_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_R2_MIXER, + RT5665_M_BST4_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_R2_MIXER, + RT5665_M_BST3_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_R2_MIXER, + RT5665_M_BST2_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_R2_MIXER, + RT5665_M_BST1_RM2_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_monovol_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_DAC_L2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("RECMIX2L Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_RECMIC2L_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_BST1_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_BST2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_BST3_MM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_out_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_OUT_L_MIXER, + RT5665_M_DAC_L2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5665_OUT_L_MIXER, + RT5665_M_IN_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_OUT_L_MIXER, + RT5665_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_L_MIXER, + RT5665_M_BST2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_L_MIXER, + RT5665_M_BST3_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_out_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_OUT_R_MIXER, + RT5665_M_DAC_R2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_OUT_R_MIXER, + RT5665_M_IN_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_R_MIXER, + RT5665_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_R_MIXER, + RT5665_M_BST3_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_OUT_R_MIXER, + RT5665_M_BST4_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_DAC_L2_MA_SFT, 1, 1), + SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_MONOVOL_MA_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_lout_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_LOUT_MIXER, + RT5665_M_DAC_L2_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL L Switch", RT5665_LOUT_MIXER, + RT5665_M_OV_L_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_lout_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_LOUT_MIXER, + RT5665_M_DAC_R2_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL R Switch", RT5665_LOUT_MIXER, + RT5665_M_OV_R_LM_SFT, 1, 1), +}; + +/*DAC L2, DAC R2*/ +/*MX-17 [6:4], MX-17 [2:0]*/ +static const char * const rt5665_dac2_src[] = { + "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "Mono ADC MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_l2_enum, RT5665_DAC2_CTRL, + RT5665_DAC_L2_SEL_SFT, rt5665_dac2_src); + +static const struct snd_kcontrol_new rt5665_dac_l2_mux = + SOC_DAPM_ENUM("Digital DAC L2 Source", rt5665_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_r2_enum, RT5665_DAC2_CTRL, + RT5665_DAC_R2_SEL_SFT, rt5665_dac2_src); + +static const struct snd_kcontrol_new rt5665_dac_r2_mux = + SOC_DAPM_ENUM("Digital DAC R2 Source", rt5665_dac_r2_enum); + +/*DAC L3, DAC R3*/ +/*MX-1B [6:4], MX-1B [2:0]*/ +static const char * const rt5665_dac3_src[] = { + "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "STO2 ADC MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_l3_enum, RT5665_DAC3_CTRL, + RT5665_DAC_L3_SEL_SFT, rt5665_dac3_src); + +static const struct snd_kcontrol_new rt5665_dac_l3_mux = + SOC_DAPM_ENUM("Digital DAC L3 Source", rt5665_dac_l3_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_r3_enum, RT5665_DAC3_CTRL, + RT5665_DAC_R3_SEL_SFT, rt5665_dac3_src); + +static const struct snd_kcontrol_new rt5665_dac_r3_mux = + SOC_DAPM_ENUM("Digital DAC R3 Source", rt5665_dac_r3_enum); + +/* STO1 ADC1 Source */ +/* MX-26 [13] [5] */ +static const char * const rt5665_sto1_adc1_src[] = { + "DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adc1l_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADC1L_SRC_SFT, rt5665_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc1l_mux = + SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adc1r_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADC1R_SRC_SFT, rt5665_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc1r_mux = + SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1r_enum); + +/* STO1 ADC Source */ +/* MX-26 [11:10] [3:2] */ +static const char * const rt5665_sto1_adc_src[] = { + "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adcl_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADCL_SRC_SFT, rt5665_sto1_adc_src); + +static const struct snd_kcontrol_new rt5665_sto1_adcl_mux = + SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5665_sto1_adcl_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adcr_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADCR_SRC_SFT, rt5665_sto1_adc_src); + +static const struct snd_kcontrol_new rt5665_sto1_adcr_mux = + SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5665_sto1_adcr_enum); + +/* STO1 ADC2 Source */ +/* MX-26 [12] [4] */ +static const char * const rt5665_sto1_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adc2l_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADC2L_SRC_SFT, rt5665_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc2l_mux = + SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5665_sto1_adc2l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adc2r_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADC2R_SRC_SFT, rt5665_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc2r_mux = + SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5665_sto1_adc2r_enum); + +/* STO1 DMIC Source */ +/* MX-26 [8] */ +static const char * const rt5665_sto1_dmic_src[] = { + "DMIC1", "DMIC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_dmic_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_DMIC_SRC_SFT, rt5665_sto1_dmic_src); + +static const struct snd_kcontrol_new rt5665_sto1_dmic_mux = + SOC_DAPM_ENUM("Stereo1 DMIC Mux", rt5665_sto1_dmic_enum); + +/* MX-26 [9] */ +static const char * const rt5665_sto1_dd_l_src[] = { + "STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_dd_l_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_DD_L_SRC_SFT, rt5665_sto1_dd_l_src); + +static const struct snd_kcontrol_new rt5665_sto1_dd_l_mux = + SOC_DAPM_ENUM("Stereo1 DD L Source", rt5665_sto1_dd_l_enum); + +/* MX-26 [1:0] */ +static const char * const rt5665_sto1_dd_r_src[] = { + "STO2 DAC", "MONO DAC", "AEC REF" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_dd_r_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_DD_R_SRC_SFT, rt5665_sto1_dd_r_src); + +static const struct snd_kcontrol_new rt5665_sto1_dd_r_mux = + SOC_DAPM_ENUM("Stereo1 DD R Source", rt5665_sto1_dd_r_enum); + +/* MONO ADC L2 Source */ +/* MX-27 [12] */ +static const char * const rt5665_mono_adc_l2_src[] = { + "DAC MIXL", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_l2_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_L2_SRC_SFT, rt5665_mono_adc_l2_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_l2_mux = + SOC_DAPM_ENUM("Mono ADC L2 Source", rt5665_mono_adc_l2_enum); + + +/* MONO ADC L1 Source */ +/* MX-27 [13] */ +static const char * const rt5665_mono_adc_l1_src[] = { + "DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_l1_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_L1_SRC_SFT, rt5665_mono_adc_l1_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_l1_mux = + SOC_DAPM_ENUM("Mono ADC L1 Source", rt5665_mono_adc_l1_enum); + +/* MX-27 [9][1]*/ +static const char * const rt5665_mono_dd_src[] = { + "STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_dd_l_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_DD_L_SRC_SFT, rt5665_mono_dd_src); + +static const struct snd_kcontrol_new rt5665_mono_dd_l_mux = + SOC_DAPM_ENUM("Mono DD L Source", rt5665_mono_dd_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_dd_r_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_DD_R_SRC_SFT, rt5665_mono_dd_src); + +static const struct snd_kcontrol_new rt5665_mono_dd_r_mux = + SOC_DAPM_ENUM("Mono DD R Source", rt5665_mono_dd_r_enum); + +/* MONO ADC L Source, MONO ADC R Source*/ +/* MX-27 [11:10], MX-27 [3:2] */ +static const char * const rt5665_mono_adc_src[] = { + "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_l_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_L_SRC_SFT, rt5665_mono_adc_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_l_mux = + SOC_DAPM_ENUM("Mono ADC L Source", rt5665_mono_adc_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adcr_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_R_SRC_SFT, rt5665_mono_adc_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_r_mux = + SOC_DAPM_ENUM("Mono ADC R Source", rt5665_mono_adcr_enum); + +/* MONO DMIC L Source */ +/* MX-27 [8] */ +static const char * const rt5665_mono_dmic_l_src[] = { + "DMIC1 L", "DMIC2 L" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_dmic_l_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_DMIC_L_SRC_SFT, rt5665_mono_dmic_l_src); + +static const struct snd_kcontrol_new rt5665_mono_dmic_l_mux = + SOC_DAPM_ENUM("Mono DMIC L Source", rt5665_mono_dmic_l_enum); + +/* MONO ADC R2 Source */ +/* MX-27 [4] */ +static const char * const rt5665_mono_adc_r2_src[] = { + "DAC MIXR", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_r2_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_R2_SRC_SFT, rt5665_mono_adc_r2_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_r2_mux = + SOC_DAPM_ENUM("Mono ADC R2 Source", rt5665_mono_adc_r2_enum); + +/* MONO ADC R1 Source */ +/* MX-27 [5] */ +static const char * const rt5665_mono_adc_r1_src[] = { + "DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_r1_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_R1_SRC_SFT, rt5665_mono_adc_r1_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_r1_mux = + SOC_DAPM_ENUM("Mono ADC R1 Source", rt5665_mono_adc_r1_enum); + +/* MONO DMIC R Source */ +/* MX-27 [0] */ +static const char * const rt5665_mono_dmic_r_src[] = { + "DMIC1 R", "DMIC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_dmic_r_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_DMIC_R_SRC_SFT, rt5665_mono_dmic_r_src); + +static const struct snd_kcontrol_new rt5665_mono_dmic_r_mux = + SOC_DAPM_ENUM("Mono DMIC R Source", rt5665_mono_dmic_r_enum); + + +/* STO2 ADC1 Source */ +/* MX-28 [13] [5] */ +static const char * const rt5665_sto2_adc1_src[] = { + "DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adc1l_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADC1L_SRC_SFT, rt5665_sto2_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc1l_mux = + SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adc1r_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADC1R_SRC_SFT, rt5665_sto2_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc1r_mux = + SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1r_enum); + +/* STO2 ADC Source */ +/* MX-28 [11:10] [3:2] */ +static const char * const rt5665_sto2_adc_src[] = { + "ADC1 L", "ADC1 R", "ADC2 L" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adcl_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADCL_SRC_SFT, rt5665_sto2_adc_src); + +static const struct snd_kcontrol_new rt5665_sto2_adcl_mux = + SOC_DAPM_ENUM("Stereo2 ADCL Source", rt5665_sto2_adcl_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adcr_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADCR_SRC_SFT, rt5665_sto2_adc_src); + +static const struct snd_kcontrol_new rt5665_sto2_adcr_mux = + SOC_DAPM_ENUM("Stereo2 ADCR Source", rt5665_sto2_adcr_enum); + +/* STO2 ADC2 Source */ +/* MX-28 [12] [4] */ +static const char * const rt5665_sto2_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adc2l_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADC2L_SRC_SFT, rt5665_sto2_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc2l_mux = + SOC_DAPM_ENUM("Stereo2 ADC2L Source", rt5665_sto2_adc2l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adc2r_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADC2R_SRC_SFT, rt5665_sto2_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc2r_mux = + SOC_DAPM_ENUM("Stereo2 ADC2R Source", rt5665_sto2_adc2r_enum); + +/* STO2 DMIC Source */ +/* MX-28 [8] */ +static const char * const rt5665_sto2_dmic_src[] = { + "DMIC1", "DMIC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_dmic_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_DMIC_SRC_SFT, rt5665_sto2_dmic_src); + +static const struct snd_kcontrol_new rt5665_sto2_dmic_mux = + SOC_DAPM_ENUM("Stereo2 DMIC Source", rt5665_sto2_dmic_enum); + +/* MX-28 [9] */ +static const char * const rt5665_sto2_dd_l_src[] = { + "STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_dd_l_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_DD_L_SRC_SFT, rt5665_sto2_dd_l_src); + +static const struct snd_kcontrol_new rt5665_sto2_dd_l_mux = + SOC_DAPM_ENUM("Stereo2 DD L Source", rt5665_sto2_dd_l_enum); + +/* MX-28 [1] */ +static const char * const rt5665_sto2_dd_r_src[] = { + "STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_dd_r_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_DD_R_SRC_SFT, rt5665_sto2_dd_r_src); + +static const struct snd_kcontrol_new rt5665_sto2_dd_r_mux = + SOC_DAPM_ENUM("Stereo2 DD R Source", rt5665_sto2_dd_r_enum); + +/* DAC R1 Source, DAC L1 Source*/ +/* MX-29 [11:10], MX-29 [9:8]*/ +static const char * const rt5665_dac1_src[] = { + "IF1 DAC1", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_r1_enum, RT5665_AD_DA_MIXER, + RT5665_DAC1_R_SEL_SFT, rt5665_dac1_src); + +static const struct snd_kcontrol_new rt5665_dac_r1_mux = + SOC_DAPM_ENUM("DAC R1 Source", rt5665_dac_r1_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_l1_enum, RT5665_AD_DA_MIXER, + RT5665_DAC1_L_SEL_SFT, rt5665_dac1_src); + +static const struct snd_kcontrol_new rt5665_dac_l1_mux = + SOC_DAPM_ENUM("DAC L1 Source", rt5665_dac_l1_enum); + +/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/ +/* MX-2D [13:12], MX-2D [9:8]*/ +static const char * const rt5665_dig_dac_mix_src[] = { + "Stereo1 DAC Mixer", "Stereo2 DAC Mixer", "Mono DAC Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dig_dac_mixl_enum, RT5665_A_DAC1_MUX, + RT5665_DAC_MIX_L_SFT, rt5665_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5665_dig_dac_mixl_mux = + SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5665_dig_dac_mixl_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dig_dac_mixr_enum, RT5665_A_DAC1_MUX, + RT5665_DAC_MIX_R_SFT, rt5665_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5665_dig_dac_mixr_mux = + SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5665_dig_dac_mixr_enum); + +/* Analog DAC L1 Source, Analog DAC R1 Source*/ +/* MX-2D [5:4], MX-2D [1:0]*/ +static const char * const rt5665_alg_dac1_src[] = { + "Stereo1 DAC Mixer", "DAC1", "DMIC1" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_alg_dac_l1_enum, RT5665_A_DAC1_MUX, + RT5665_A_DACL1_SFT, rt5665_alg_dac1_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_l1_mux = + SOC_DAPM_ENUM("Analog DAC L1 Source", rt5665_alg_dac_l1_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_alg_dac_r1_enum, RT5665_A_DAC1_MUX, + RT5665_A_DACR1_SFT, rt5665_alg_dac1_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_r1_mux = + SOC_DAPM_ENUM("Analog DAC R1 Source", rt5665_alg_dac_r1_enum); + +/* Analog DAC LR Source, Analog DAC R2 Source*/ +/* MX-2E [5:4], MX-2E [0]*/ +static const char * const rt5665_alg_dac2_src[] = { + "Mono DAC Mixer", "DAC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_alg_dac_l2_enum, RT5665_A_DAC2_MUX, + RT5665_A_DACL2_SFT, rt5665_alg_dac2_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_l2_mux = + SOC_DAPM_ENUM("Analog DAC L2 Source", rt5665_alg_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_alg_dac_r2_enum, RT5665_A_DAC2_MUX, + RT5665_A_DACR2_SFT, rt5665_alg_dac2_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_r2_mux = + SOC_DAPM_ENUM("Analog DAC R2 Source", rt5665_alg_dac_r2_enum); + +/* Interface2 ADC Data Input*/ +/* MX-2F [14:12] */ +static const char * const rt5665_if2_1_adc_in_src[] = { + "STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1", + "IF1 DAC2", "IF2_2 DAC", "IF3 DAC", "DAC1 MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if2_1_adc_in_enum, RT5665_DIG_INF2_DATA, + RT5665_IF3_ADC_IN_SFT, rt5665_if2_1_adc_in_src); + +static const struct snd_kcontrol_new rt5665_if2_1_adc_in_mux = + SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_1_adc_in_enum); + +/* MX-2F [6:4] */ +static const char * const rt5665_if2_2_adc_in_src[] = { + "STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1", + "IF1 DAC2", "IF2_1 DAC", "IF3 DAC", "DAC1 MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if2_2_adc_in_enum, RT5665_DIG_INF2_DATA, + RT5665_IF2_2_ADC_IN_SFT, rt5665_if2_2_adc_in_src); + +static const struct snd_kcontrol_new rt5665_if2_2_adc_in_mux = + SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_2_adc_in_enum); + +/* Interface3 ADC Data Input*/ +/* MX-30 [6:4] */ +static const char * const rt5665_if3_adc_in_src[] = { + "STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1", + "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "DAC1 MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if3_adc_in_enum, RT5665_DIG_INF3_DATA, + RT5665_IF3_ADC_IN_SFT, rt5665_if3_adc_in_src); + +static const struct snd_kcontrol_new rt5665_if3_adc_in_mux = + SOC_DAPM_ENUM("IF3 ADC IN Source", rt5665_if3_adc_in_enum); + +/* PDM 1 L/R*/ +/* MX-31 [11:10] [9:8] */ +static const char * const rt5665_pdm_src[] = { + "Stereo1 DAC", "Stereo2 DAC", "Mono DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_pdm_l_enum, RT5665_PDM_OUT_CTRL, + RT5665_PDM1_L_SFT, rt5665_pdm_src); + +static const struct snd_kcontrol_new rt5665_pdm_l_mux = + SOC_DAPM_ENUM("PDM L Source", rt5665_pdm_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_pdm_r_enum, RT5665_PDM_OUT_CTRL, + RT5665_PDM1_R_SFT, rt5665_pdm_src); + +static const struct snd_kcontrol_new rt5665_pdm_r_mux = + SOC_DAPM_ENUM("PDM R Source", rt5665_pdm_r_enum); + + +/* I2S1 TDM ADCDAT Source */ +/* MX-7a[10] */ +static const char * const rt5665_if1_1_adc1_data_src[] = { + "STO1 ADC", "IF2_1 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_1_adc1_data_enum, RT5665_TDM_CTRL_3, + RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_1_adc1_data_src); + +static const struct snd_kcontrol_new rt5665_if1_1_adc1_mux = + SOC_DAPM_ENUM("IF1_1 ADC1 Source", rt5665_if1_1_adc1_data_enum); + +/* MX-7a[9] */ +static const char * const rt5665_if1_1_adc2_data_src[] = { + "STO2 ADC", "IF2_2 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_1_adc2_data_enum, RT5665_TDM_CTRL_3, + RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_1_adc2_data_src); + +static const struct snd_kcontrol_new rt5665_if1_1_adc2_mux = + SOC_DAPM_ENUM("IF1_1 ADC2 Source", rt5665_if1_1_adc2_data_enum); + +/* MX-7a[8] */ +static const char * const rt5665_if1_1_adc3_data_src[] = { + "MONO ADC", "IF3 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_1_adc3_data_enum, RT5665_TDM_CTRL_3, + RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_1_adc3_data_src); + +static const struct snd_kcontrol_new rt5665_if1_1_adc3_mux = + SOC_DAPM_ENUM("IF1_1 ADC3 Source", rt5665_if1_1_adc3_data_enum); + +/* MX-7b[10] */ +static const char * const rt5665_if1_2_adc1_data_src[] = { + "STO1 ADC", "IF1 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_2_adc1_data_enum, RT5665_TDM_CTRL_4, + RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_2_adc1_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc1_mux = + SOC_DAPM_ENUM("IF1_2 ADC1 Source", rt5665_if1_2_adc1_data_enum); + +/* MX-7b[9] */ +static const char * const rt5665_if1_2_adc2_data_src[] = { + "STO2 ADC", "IF2_1 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_2_adc2_data_enum, RT5665_TDM_CTRL_4, + RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_2_adc2_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc2_mux = + SOC_DAPM_ENUM("IF1_2 ADC2 Source", rt5665_if1_2_adc2_data_enum); + +/* MX-7b[8] */ +static const char * const rt5665_if1_2_adc3_data_src[] = { + "MONO ADC", "IF2_2 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_2_adc3_data_enum, RT5665_TDM_CTRL_4, + RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_2_adc3_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc3_mux = + SOC_DAPM_ENUM("IF1_2 ADC3 Source", rt5665_if1_2_adc3_data_enum); + +/* MX-7b[7] */ +static const char * const rt5665_if1_2_adc4_data_src[] = { + "DAC1", "IF3 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_2_adc4_data_enum, RT5665_TDM_CTRL_4, + RT5665_IF1_ADC4_SEL_SFT, rt5665_if1_2_adc4_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc4_mux = + SOC_DAPM_ENUM("IF1_2 ADC4 Source", rt5665_if1_2_adc4_data_enum); + +/* MX-7a[4:0] MX-7b[4:0] */ +static const char * const rt5665_tdm_adc_data_src[] = { + "1234", "1243", "1324", "1342", "1432", "1423", + "2134", "2143", "2314", "2341", "2431", "2413", + "3124", "3142", "3214", "3241", "3412", "3421", + "4123", "4132", "4213", "4231", "4312", "4321" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_tdm1_adc_data_enum, RT5665_TDM_CTRL_3, + RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src); + +static const struct snd_kcontrol_new rt5665_tdm1_adc_mux = + SOC_DAPM_ENUM("TDM1 ADC Mux", rt5665_tdm1_adc_data_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_tdm2_adc_data_enum, RT5665_TDM_CTRL_4, + RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src); + +static const struct snd_kcontrol_new rt5665_tdm2_adc_mux = + SOC_DAPM_ENUM("TDM2 ADCDAT Source", rt5665_tdm2_adc_data_enum); + +/* Out Volume Switch */ +static const struct snd_kcontrol_new monovol_switch = + SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_l_switch = + SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_r_switch = + SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_R_SFT, 1, 1); + +/* Out Switch */ +static const struct snd_kcontrol_new mono_switch = + SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_switch = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5665_HP_CTRL_2, + RT5665_VOL_L_SFT, 1, 0); + +static const struct snd_kcontrol_new lout_l_switch = + SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_switch = + SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new pdm_l_switch = + SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL, + RT5665_M_PDM1_L_SFT, 1, 1); + +static const struct snd_kcontrol_new pdm_r_switch = + SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL, + RT5665_M_PDM1_R_SFT, 1, 1); + +static int rt5665_mono_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_EN); + snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40, + 0x0); + snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0x10); + snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0x20); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0); + snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0); + snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40, + 0x40); + snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_DIS); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5665_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_EN); + snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0003); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0002); + snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_DIS); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5665_lout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5665_DEPOP_1, + RT5665_PUMP_EN, RT5665_PUMP_EN); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5665_DEPOP_1, + RT5665_PUMP_EN, 0); + break; + + default: + return 0; + } + + return 0; + +} + +static int set_dmic_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /*Add delay to avoid pop noise*/ + msleep(150); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5655_set_verf(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (w->shift) { + case RT5665_PWR_VREF1_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV1, 0); + break; + + case RT5665_PWR_VREF2_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV2, 0); + break; + + case RT5665_PWR_VREF3_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV3, 0); + break; + + default: + break; + } + break; + + case SND_SOC_DAPM_POST_PMU: + usleep_range(15000, 20000); + switch (w->shift) { + case RT5665_PWR_VREF1_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV1, RT5665_PWR_FV1); + break; + + case RT5665_PWR_VREF2_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV2, RT5665_PWR_FV2); + break; + + case RT5665_PWR_VREF3_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV3, RT5665_PWR_FV3); + break; + + default: + break; + } + break; + + default: + return 0; + } + + return 0; +} + + +static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO2", RT5665_PWR_ANLG_3, RT5665_PWR_LDO2_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", RT5665_PWR_ANLG_3, RT5665_PWR_PLL_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5665_PWR_VOL, + RT5665_PWR_MIC_DET_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Vref1", RT5665_PWR_ANLG_1, RT5665_PWR_VREF1_BIT, 0, + rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("Vref2", RT5665_PWR_ANLG_1, RT5665_PWR_VREF2_BIT, 0, + rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("Vref3", RT5665_PWR_ANLG_1, RT5665_PWR_VREF3_BIT, 0, + rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5665_ASRC_1, + RT5665_I2S1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5665_ASRC_1, + RT5665_I2S2_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5665_ASRC_1, + RT5665_I2S3_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5665_ASRC_1, + RT5665_DAC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO2 ASRC", 1, RT5665_ASRC_1, + RT5665_DAC_STO2_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5665_ASRC_1, + RT5665_DAC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5665_ASRC_1, + RT5665_DAC_MONO_R_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5665_ASRC_1, + RT5665_ADC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5665_ASRC_1, + RT5665_ADC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5665_ASRC_1, + RT5665_ADC_MONO_R_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5665_ASRC_1, + RT5665_DMIC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5665_ASRC_1, + RT5665_DMIC_STO2_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5665_ASRC_1, + RT5665_DMIC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5665_ASRC_1, + RT5665_DMIC_MONO_R_ASRC_SFT, 0, NULL, 0), + + /* Input Side */ + SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5665_PWR_ANLG_2, RT5665_PWR_MB1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5665_PWR_ANLG_2, RT5665_PWR_MB2_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5665_PWR_ANLG_2, RT5665_PWR_MB3_BIT, + 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + SND_SOC_DAPM_INPUT("DMIC L2"), + SND_SOC_DAPM_INPUT("DMIC R2"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + SND_SOC_DAPM_INPUT("IN3P"), + SND_SOC_DAPM_INPUT("IN3N"), + SND_SOC_DAPM_INPUT("IN4P"), + SND_SOC_DAPM_INPUT("IN4N"), + + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5665_DMIC_CTRL_1, + RT5665_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5665_DMIC_CTRL_1, + RT5665_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST3", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST4", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST1 Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST2 Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST3 Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST3_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST4 Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST4_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST1P Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST1_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST2P Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST2_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST3P Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST3_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST4P Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST4_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CBJ Power", RT5665_PWR_ANLG_3, + RT5665_PWR_CBJ_BIT, 0, NULL, 0), + + + /* Input Volume */ + SND_SOC_DAPM_PGA("INL VOL", RT5665_PWR_VOL, RT5665_PWR_IN_L_BIT, + 0, NULL, 0), + SND_SOC_DAPM_PGA("INR VOL", RT5665_PWR_VOL, RT5665_PWR_IN_R_BIT, + 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5665_rec1_l_mix, + ARRAY_SIZE(rt5665_rec1_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5665_rec1_r_mix, + ARRAY_SIZE(rt5665_rec1_r_mix)), + SND_SOC_DAPM_MIXER("RECMIX2L", SND_SOC_NOPM, 0, 0, rt5665_rec2_l_mix, + ARRAY_SIZE(rt5665_rec2_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX2R", SND_SOC_NOPM, 0, 0, rt5665_rec2_r_mix, + ARRAY_SIZE(rt5665_rec2_r_mix)), + SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5665_PWR_ANLG_2, + RT5665_PWR_RM1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5665_PWR_ANLG_2, + RT5665_PWR_RM1_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RECMIX2L Power", RT5665_PWR_MIXER, + RT5665_PWR_RM2_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RECMIX2R Power", RT5665_PWR_MIXER, + RT5665_PWR_RM2_R_BIT, 0, NULL, 0), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5665_PWR_DIG_1, + RT5665_PWR_ADC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5665_PWR_DIG_1, + RT5665_PWR_ADC_R1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5665_PWR_DIG_1, + RT5665_PWR_ADC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5665_PWR_DIG_1, + RT5665_PWR_ADC_R2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5665_CHOP_ADC, + RT5665_CKGEN_ADC1_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 clock", RT5665_CHOP_ADC, + RT5665_CKGEN_ADC2_SFT, 0, NULL, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adc1l_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adc1r_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adc2l_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adc2r_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adcl_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adcr_mux), + SND_SOC_DAPM_MUX("Stereo1 DD L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_dd_l_mux), + SND_SOC_DAPM_MUX("Stereo1 DD R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_dd_r_mux), + SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_l2_mux), + SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_r2_mux), + SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_l1_mux), + SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_r1_mux), + SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_dmic_l_mux), + SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_dmic_r_mux), + SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_l_mux), + SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_r_mux), + SND_SOC_DAPM_MUX("Mono DD L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_dd_l_mux), + SND_SOC_DAPM_MUX("Mono DD R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_dd_r_mux), + SND_SOC_DAPM_MUX("Stereo2 DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_dmic_mux), + SND_SOC_DAPM_MUX("Stereo2 DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_dmic_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adc1l_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adc1r_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adc2l_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adc2r_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adcl_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adcr_mux), + SND_SOC_DAPM_MUX("Stereo2 DD L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_dd_l_mux), + SND_SOC_DAPM_MUX("Stereo2 DD R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_dd_r_mux), + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5665_PWR_DIG_2, + RT5665_PWR_ADC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5665_PWR_DIG_2, + RT5665_PWR_ADC_S2F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5665_STO1_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, 1, rt5665_sto1_adc_l_mix, + ARRAY_SIZE(rt5665_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5665_STO1_ADC_DIG_VOL, + RT5665_R_MUTE_SFT, 1, rt5665_sto1_adc_r_mix, + ARRAY_SIZE(rt5665_sto1_adc_r_mix)), + SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", RT5665_STO2_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, 1, rt5665_sto2_adc_l_mix, + ARRAY_SIZE(rt5665_sto2_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", RT5665_STO2_ADC_DIG_VOL, + RT5665_R_MUTE_SFT, 1, rt5665_sto2_adc_r_mix, + ARRAY_SIZE(rt5665_sto2_adc_r_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5665_PWR_DIG_2, + RT5665_PWR_ADC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5665_MONO_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, 1, rt5665_mono_adc_l_mix, + ARRAY_SIZE(rt5665_mono_adc_l_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5665_PWR_DIG_2, + RT5665_PWR_ADC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5665_MONO_ADC_DIG_VOL, + RT5665_R_MUTE_SFT, 1, rt5665_mono_adc_r_mix, + ARRAY_SIZE(rt5665_mono_adc_r_mix)), + + /* ADC PGA */ + SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S1_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_2_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S2_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S2_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_2_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S3", RT5665_PWR_DIG_1, RT5665_PWR_I2S3_BIT, + 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC3 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC3 R", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_PGA("IF2_1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + SND_SOC_DAPM_MUX("IF1_1_ADC1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_adc1_mux), + SND_SOC_DAPM_MUX("IF1_1_ADC2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_adc2_mux), + SND_SOC_DAPM_MUX("IF1_1_ADC3 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_adc3_mux), + SND_SOC_DAPM_PGA("IF1_1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("IF1_2_ADC1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_adc1_mux), + SND_SOC_DAPM_MUX("IF1_2_ADC2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_adc2_mux), + SND_SOC_DAPM_MUX("IF1_2_ADC3 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_adc3_mux), + SND_SOC_DAPM_MUX("IF1_2_ADC4 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_adc4_mux), + SND_SOC_DAPM_MUX("TDM1 slot 01 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm1_adc_mux), + SND_SOC_DAPM_MUX("TDM1 slot 23 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm1_adc_mux), + SND_SOC_DAPM_MUX("TDM1 slot 45 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm1_adc_mux), + SND_SOC_DAPM_MUX("TDM1 slot 67 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm1_adc_mux), + SND_SOC_DAPM_MUX("TDM2 slot 01 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm2_adc_mux), + SND_SOC_DAPM_MUX("TDM2 slot 23 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm2_adc_mux), + SND_SOC_DAPM_MUX("TDM2 slot 45 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm2_adc_mux), + SND_SOC_DAPM_MUX("TDM2 slot 67 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm2_adc_mux), + SND_SOC_DAPM_MUX("IF2_1 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_1_adc_in_mux), + SND_SOC_DAPM_MUX("IF2_2 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_2_adc_in_mux), + SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if3_adc_in_mux), + SND_SOC_DAPM_MUX("IF1_1 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF2_1 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_1_dac_swap_mux), + SND_SOC_DAPM_MUX("IF2_1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_1_adc_swap_mux), + SND_SOC_DAPM_MUX("IF2_2 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_2_dac_swap_mux), + SND_SOC_DAPM_MUX("IF2_2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_2_adc_swap_mux), + SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if3_dac_swap_mux), + SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if3_adc_swap_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 0", "AIF1_1 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 1", "AIF1_1 Capture", + 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 2", "AIF1_1 Capture", + 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 3", "AIF1_1 Capture", + 3, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 4", "AIF1_1 Capture", + 4, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 5", "AIF1_1 Capture", + 5, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 6", "AIF1_1 Capture", + 6, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 7", "AIF1_1 Capture", + 7, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 0", "AIF1_2 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 1", "AIF1_2 Capture", + 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 2", "AIF1_2 Capture", + 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 3", "AIF1_2 Capture", + 3, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 4", "AIF1_2 Capture", + 4, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 5", "AIF1_2 Capture", + 5, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 6", "AIF1_2 Capture", + 6, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 7", "AIF1_2 Capture", + 7, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2_1TX", "AIF2_1 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2_2TX", "AIF2_2 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2_1RX", "AIF2_1 Playback", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2_2RX", "AIF2_2 Playback", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", + 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, + rt5665_dac_l_mix, ARRAY_SIZE(rt5665_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, + rt5665_dac_r_mix, ARRAY_SIZE(rt5665_dac_r_mix)), + + /* DAC channel Mux */ + SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r1_mux), + SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r2_mux), + SND_SOC_DAPM_MUX("DAC L3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l3_mux), + SND_SOC_DAPM_MUX("DAC R3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r3_mux), + + SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0, + &rt5665_alg_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0, + &rt5665_alg_dac_r1_mux), + SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0, + &rt5665_alg_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0, + &rt5665_alg_dac_r2_mux), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5665_PWR_DIG_2, + RT5665_PWR_DAC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Stereo2 Filter", RT5665_PWR_DIG_2, + RT5665_PWR_DAC_S2F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5665_PWR_DIG_2, + RT5665_PWR_DAC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5665_PWR_DIG_2, + RT5665_PWR_DAC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5665_sto1_dac_l_mix, ARRAY_SIZE(rt5665_sto1_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5665_sto1_dac_r_mix, ARRAY_SIZE(rt5665_sto1_dac_r_mix)), + SND_SOC_DAPM_MIXER("Stereo2 DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5665_sto2_dac_l_mix, ARRAY_SIZE(rt5665_sto2_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo2 DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5665_sto2_dac_r_mix, ARRAY_SIZE(rt5665_sto2_dac_r_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5665_mono_dac_l_mix, ARRAY_SIZE(rt5665_mono_dac_l_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5665_mono_dac_r_mix, ARRAY_SIZE(rt5665_mono_dac_r_mix)), + SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0, + &rt5665_dig_dac_mixl_mux), + SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0, + &rt5665_dig_dac_mixr_mux), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5665_PWR_DIG_1, + RT5665_PWR_DAC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5665_PWR_DIG_1, + RT5665_PWR_DAC_R2_BIT, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA("DAC1 MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 1, RT5665_CHOP_DAC, + RT5665_CKGEN_DAC1_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC 2 Clock", 1, RT5665_CHOP_DAC, + RT5665_CKGEN_DAC2_SFT, 0, NULL, 0), + + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5665_PWR_MIXER, RT5665_PWR_MM_BIT, + 0, rt5665_monovol_mix, ARRAY_SIZE(rt5665_monovol_mix)), + SND_SOC_DAPM_MIXER("OUT MIXL", RT5665_PWR_MIXER, RT5665_PWR_OM_L_BIT, + 0, rt5665_out_l_mix, ARRAY_SIZE(rt5665_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5665_PWR_MIXER, RT5665_PWR_OM_R_BIT, + 0, rt5665_out_r_mix, ARRAY_SIZE(rt5665_out_r_mix)), + + /* Output Volume */ + SND_SOC_DAPM_SWITCH("MONOVOL", RT5665_PWR_VOL, RT5665_PWR_MV_BIT, 0, + &monovol_switch), + SND_SOC_DAPM_SWITCH("OUTVOL L", RT5665_PWR_VOL, RT5665_PWR_OV_L_BIT, 0, + &outvol_l_switch), + SND_SOC_DAPM_SWITCH("OUTVOL R", RT5665_PWR_VOL, RT5665_PWR_OV_R_BIT, 0, + &outvol_r_switch), + + /* MONO/HPO/LOUT */ + SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0, 0, rt5665_mono_mix, + ARRAY_SIZE(rt5665_mono_mix)), + SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_l_mix, + ARRAY_SIZE(rt5665_lout_l_mix)), + SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_r_mix, + ARRAY_SIZE(rt5665_lout_r_mix)), + SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5665_PWR_ANLG_1, RT5665_PWR_MA_BIT, + 0, rt5665_mono_event, SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5665_hp_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_S("LOUT Amp", 1, RT5665_PWR_ANLG_1, + RT5665_PWR_LM_BIT, 0, rt5665_lout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, + rt5665_charge_pump_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0, + &mono_switch), + SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0, + &hpo_switch), + SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0, + &lout_l_switch), + SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0, + &lout_r_switch), + SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0, + &pdm_l_switch), + SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0, + &pdm_r_switch), + + /* PDM */ + SND_SOC_DAPM_SUPPLY("PDM Power", RT5665_PWR_DIG_2, + RT5665_PWR_PDM1_BIT, 0, NULL, 0), + SND_SOC_DAPM_MUX("PDM L Mux", SND_SOC_NOPM, + 0, 1, &rt5665_pdm_l_mux), + SND_SOC_DAPM_MUX("PDM R Mux", SND_SOC_NOPM, + 0, 1, &rt5665_pdm_r_mux), + + /* CLK DET */ + SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5665_CLK_DET, RT5665_SYS_CLK_DET, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET HP", RT5665_CLK_DET, RT5665_HP_CLK_DET, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET MONO", RT5665_CLK_DET, RT5665_MONO_CLK_DET, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET LOUT", RT5665_CLK_DET, RT5665_LOUT_CLK_DET, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET", RT5665_CLK_DET, RT5665_POW_CLK_DET, + 0, NULL, 0), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), + SND_SOC_DAPM_OUTPUT("MONOOUT"), + SND_SOC_DAPM_OUTPUT("PDML"), + SND_SOC_DAPM_OUTPUT("PDMR"), +}; + +static const struct snd_soc_dapm_route rt5665_dapm_routes[] = { + /*PLL*/ + {"ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"DAC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll}, + + /*ASRC*/ + {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, + {"ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc}, + {"ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc}, + {"DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc}, + {"DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc}, + {"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc}, + {"DAC Stereo2 Filter", NULL, "DAC STO2 ASRC", is_using_asrc}, + + /*Vref*/ + {"Mic Det Power", NULL, "Vref2"}, + {"MICBIAS1", NULL, "Vref1"}, + {"MICBIAS1", NULL, "Vref2"}, + {"MICBIAS2", NULL, "Vref1"}, + {"MICBIAS2", NULL, "Vref2"}, + {"MICBIAS3", NULL, "Vref1"}, + {"MICBIAS3", NULL, "Vref2"}, + + {"Stereo1 DMIC L Mux", NULL, "DMIC STO1 ASRC"}, + {"Stereo1 DMIC R Mux", NULL, "DMIC STO1 ASRC"}, + {"Stereo2 DMIC L Mux", NULL, "DMIC STO2 ASRC"}, + {"Stereo2 DMIC R Mux", NULL, "DMIC STO2 ASRC"}, + {"Mono DMIC L Mux", NULL, "DMIC MONO L ASRC"}, + {"Mono DMIC R Mux", NULL, "DMIC MONO R ASRC"}, + + {"I2S1_1", NULL, "I2S1 ASRC"}, + {"I2S1_2", NULL, "I2S1 ASRC"}, + {"I2S2_1", NULL, "I2S2 ASRC"}, + {"I2S2_2", NULL, "I2S2 ASRC"}, + {"I2S3", NULL, "I2S3 ASRC"}, + + {"CLKDET SYS", NULL, "CLKDET"}, + {"CLKDET HP", NULL, "CLKDET"}, + {"CLKDET MONO", NULL, "CLKDET"}, + {"CLKDET LOUT", NULL, "CLKDET"}, + + {"IN1P", NULL, "LDO2"}, + {"IN2P", NULL, "LDO2"}, + {"IN3P", NULL, "LDO2"}, + {"IN4P", NULL, "LDO2"}, + + {"DMIC1", NULL, "DMIC L1"}, + {"DMIC1", NULL, "DMIC R1"}, + {"DMIC2", NULL, "DMIC L2"}, + {"DMIC2", NULL, "DMIC R2"}, + + {"BST1", NULL, "IN1P"}, + {"BST1", NULL, "IN1N"}, + {"BST1", NULL, "BST1 Power"}, + {"BST1", NULL, "BST1P Power"}, + {"BST2", NULL, "IN2P"}, + {"BST2", NULL, "IN2N"}, + {"BST2", NULL, "BST2 Power"}, + {"BST2", NULL, "BST2P Power"}, + {"BST3", NULL, "IN3P"}, + {"BST3", NULL, "IN3N"}, + {"BST3", NULL, "BST3 Power"}, + {"BST3", NULL, "BST3P Power"}, + {"BST4", NULL, "IN4P"}, + {"BST4", NULL, "IN4N"}, + {"BST4", NULL, "BST4 Power"}, + {"BST4", NULL, "BST4P Power"}, + {"BST1 CBJ", NULL, "IN1P"}, + {"BST1 CBJ", NULL, "IN1N"}, + {"BST1 CBJ", NULL, "CBJ Power"}, + {"CBJ Power", NULL, "Vref2"}, + + {"INL VOL", NULL, "IN3P"}, + {"INR VOL", NULL, "IN3N"}, + + {"RECMIX1L", "CBJ Switch", "BST1 CBJ"}, + {"RECMIX1L", "INL Switch", "INL VOL"}, + {"RECMIX1L", "INR Switch", "INR VOL"}, + {"RECMIX1L", "BST4 Switch", "BST4"}, + {"RECMIX1L", "BST3 Switch", "BST3"}, + {"RECMIX1L", "BST2 Switch", "BST2"}, + {"RECMIX1L", "BST1 Switch", "BST1"}, + {"RECMIX1L", NULL, "RECMIX1L Power"}, + + {"RECMIX1R", "MONOVOL Switch", "MONOVOL"}, + {"RECMIX1R", "INR Switch", "INR VOL"}, + {"RECMIX1R", "BST4 Switch", "BST4"}, + {"RECMIX1R", "BST3 Switch", "BST3"}, + {"RECMIX1R", "BST2 Switch", "BST2"}, + {"RECMIX1R", "BST1 Switch", "BST1"}, + {"RECMIX1R", NULL, "RECMIX1R Power"}, + + {"RECMIX2L", "CBJ Switch", "BST1 CBJ"}, + {"RECMIX2L", "INL Switch", "INL VOL"}, + {"RECMIX2L", "INR Switch", "INR VOL"}, + {"RECMIX2L", "BST4 Switch", "BST4"}, + {"RECMIX2L", "BST3 Switch", "BST3"}, + {"RECMIX2L", "BST2 Switch", "BST2"}, + {"RECMIX2L", "BST1 Switch", "BST1"}, + {"RECMIX2L", NULL, "RECMIX2L Power"}, + + {"RECMIX2R", "MONOVOL Switch", "MONOVOL"}, + {"RECMIX2R", "INL Switch", "INL VOL"}, + {"RECMIX2R", "INR Switch", "INR VOL"}, + {"RECMIX2R", "BST4 Switch", "BST4"}, + {"RECMIX2R", "BST3 Switch", "BST3"}, + {"RECMIX2R", "BST2 Switch", "BST2"}, + {"RECMIX2R", "BST1 Switch", "BST1"}, + {"RECMIX2R", NULL, "RECMIX2R Power"}, + + {"ADC1 L", NULL, "RECMIX1L"}, + {"ADC1 L", NULL, "ADC1 L Power"}, + {"ADC1 L", NULL, "ADC1 clock"}, + {"ADC1 R", NULL, "RECMIX1R"}, + {"ADC1 R", NULL, "ADC1 R Power"}, + {"ADC1 R", NULL, "ADC1 clock"}, + + {"ADC2 L", NULL, "RECMIX2L"}, + {"ADC2 L", NULL, "ADC2 L Power"}, + {"ADC2 L", NULL, "ADC2 clock"}, + {"ADC2 R", NULL, "RECMIX2R"}, + {"ADC2 R", NULL, "ADC2 R Power"}, + {"ADC2 R", NULL, "ADC2 clock"}, + + {"DMIC L1", NULL, "DMIC CLK"}, + {"DMIC L1", NULL, "DMIC1 Power"}, + {"DMIC R1", NULL, "DMIC CLK"}, + {"DMIC R1", NULL, "DMIC1 Power"}, + {"DMIC L2", NULL, "DMIC CLK"}, + {"DMIC L2", NULL, "DMIC2 Power"}, + {"DMIC R2", NULL, "DMIC CLK"}, + {"DMIC R2", NULL, "DMIC2 Power"}, + + {"Stereo1 DMIC L Mux", "DMIC1", "DMIC L1"}, + {"Stereo1 DMIC L Mux", "DMIC2", "DMIC L2"}, + + {"Stereo1 DMIC R Mux", "DMIC1", "DMIC R1"}, + {"Stereo1 DMIC R Mux", "DMIC2", "DMIC R2"}, + + {"Mono DMIC L Mux", "DMIC1 L", "DMIC L1"}, + {"Mono DMIC L Mux", "DMIC2 L", "DMIC L2"}, + + {"Mono DMIC R Mux", "DMIC1 R", "DMIC R1"}, + {"Mono DMIC R Mux", "DMIC2 R", "DMIC R2"}, + + {"Stereo2 DMIC L Mux", "DMIC1", "DMIC L1"}, + {"Stereo2 DMIC L Mux", "DMIC2", "DMIC L2"}, + + {"Stereo2 DMIC R Mux", "DMIC1", "DMIC R1"}, + {"Stereo2 DMIC R Mux", "DMIC2", "DMIC R2"}, + + {"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"}, + {"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"}, + {"Stereo1 ADC L Mux", "ADC2 L", "ADC2 L"}, + {"Stereo1 ADC L Mux", "ADC2 R", "ADC2 R"}, + {"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"}, + {"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"}, + {"Stereo1 ADC R Mux", "ADC2 L", "ADC2 L"}, + {"Stereo1 ADC R Mux", "ADC2 R", "ADC2 R"}, + + {"Stereo1 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"}, + {"Stereo1 DD L Mux", "MONO DAC", "Mono DAC MIXL"}, + + {"Stereo1 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"}, + {"Stereo1 DD R Mux", "MONO DAC", "Mono DAC MIXR"}, + + {"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"}, + {"Stereo1 ADC L1 Mux", "DD Mux", "Stereo1 DD L Mux"}, + {"Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux"}, + {"Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL"}, + + {"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"}, + {"Stereo1 ADC R1 Mux", "DD Mux", "Stereo1 DD R Mux"}, + {"Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux"}, + {"Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR"}, + + {"Mono ADC L Mux", "ADC1 L", "ADC1 L"}, + {"Mono ADC L Mux", "ADC1 R", "ADC1 R"}, + {"Mono ADC L Mux", "ADC2 L", "ADC2 L"}, + {"Mono ADC L Mux", "ADC2 R", "ADC2 R"}, + + {"Mono ADC R Mux", "ADC1 L", "ADC1 L"}, + {"Mono ADC R Mux", "ADC1 R", "ADC1 R"}, + {"Mono ADC R Mux", "ADC2 L", "ADC2 L"}, + {"Mono ADC R Mux", "ADC2 R", "ADC2 R"}, + + {"Mono DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"}, + {"Mono DD L Mux", "MONO DAC", "Mono DAC MIXL"}, + + {"Mono DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"}, + {"Mono DD R Mux", "MONO DAC", "Mono DAC MIXR"}, + + {"Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux"}, + {"Mono ADC L2 Mux", "DAC MIXL", "DAC MIXL"}, + {"Mono ADC L1 Mux", "DD Mux", "Mono DD L Mux"}, + {"Mono ADC L1 Mux", "ADC", "Mono ADC L Mux"}, + + {"Mono ADC R1 Mux", "DD Mux", "Mono DD R Mux"}, + {"Mono ADC R1 Mux", "ADC", "Mono ADC R Mux"}, + {"Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux"}, + {"Mono ADC R2 Mux", "DAC MIXR", "DAC MIXR"}, + + {"Stereo2 ADC L Mux", "ADC1 L", "ADC1 L"}, + {"Stereo2 ADC L Mux", "ADC2 L", "ADC2 L"}, + {"Stereo2 ADC L Mux", "ADC1 R", "ADC1 R"}, + {"Stereo2 ADC R Mux", "ADC1 L", "ADC1 L"}, + {"Stereo2 ADC R Mux", "ADC2 L", "ADC2 L"}, + {"Stereo2 ADC R Mux", "ADC1 R", "ADC1 R"}, + + {"Stereo2 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"}, + {"Stereo2 DD L Mux", "MONO DAC", "Mono DAC MIXL"}, + + {"Stereo2 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"}, + {"Stereo2 DD R Mux", "MONO DAC", "Mono DAC MIXR"}, + + {"Stereo2 ADC L1 Mux", "ADC", "Stereo2 ADC L Mux"}, + {"Stereo2 ADC L1 Mux", "DD Mux", "Stereo2 DD L Mux"}, + {"Stereo2 ADC L2 Mux", "DMIC", "Stereo2 DMIC L Mux"}, + {"Stereo2 ADC L2 Mux", "DAC MIX", "DAC MIXL"}, + + {"Stereo2 ADC R1 Mux", "ADC", "Stereo2 ADC R Mux"}, + {"Stereo2 ADC R1 Mux", "DD Mux", "Stereo2 DD R Mux"}, + {"Stereo2 ADC R2 Mux", "DMIC", "Stereo2 DMIC R Mux"}, + {"Stereo2 ADC R2 Mux", "DAC MIX", "DAC MIXR"}, + + {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"}, + {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"}, + {"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"}, + + {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"}, + {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"}, + {"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"}, + + {"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"}, + {"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"}, + {"Mono ADC MIXL", NULL, "ADC Mono Left Filter"}, + + {"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"}, + {"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"}, + {"Mono ADC MIXR", NULL, "ADC Mono Right Filter"}, + + {"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"}, + {"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"}, + {"Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter"}, + + {"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"}, + {"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"}, + {"Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter"}, + + {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"}, + {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"}, + {"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL"}, + {"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR"}, + {"Mono ADC MIX", NULL, "Mono ADC MIXL"}, + {"Mono ADC MIX", NULL, "Mono ADC MIXR"}, + + {"IF1_1_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF1_1_ADC1 Mux", "IF2_1 DAC", "IF2_1 DAC"}, + {"IF1_1_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF1_1_ADC2 Mux", "IF2_2 DAC", "IF2_2 DAC"}, + {"IF1_1_ADC3 Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF1_1_ADC3 Mux", "IF3 DAC", "IF3 DAC"}, + {"IF1_1_ADC4", NULL, "DAC1 MIX"}, + + {"IF1_2_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF1_2_ADC1 Mux", "IF1 DAC", "IF1 DAC1"}, + {"IF1_2_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF1_2_ADC2 Mux", "IF2_1 DAC", "IF2_1 DAC"}, + {"IF1_2_ADC3 Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF1_2_ADC3 Mux", "IF2_2 DAC", "IF2_2 DAC"}, + {"IF1_2_ADC4 Mux", "DAC1", "DAC1 MIX"}, + {"IF1_2_ADC4 Mux", "IF3 DAC", "IF3 DAC"}, + + {"TDM1 slot 01 Data Mux", "1234", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1243", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1324", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1342", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1432", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1423", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "2134", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2143", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2314", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2341", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2431", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2413", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "3124", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3142", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3214", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3241", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3412", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3421", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "4123", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4132", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4213", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4231", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4312", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4321", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", NULL, "I2S1_1"}, + + {"TDM1 slot 23 Data Mux", "1234", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "1243", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "1324", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "1342", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "1432", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "1423", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "2134", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "2143", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "2314", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "2341", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "2431", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "2413", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "3124", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "3142", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "3214", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "3241", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "3412", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "3421", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "4123", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "4132", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "4213", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "4231", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "4312", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "4321", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", NULL, "I2S1_1"}, + + {"TDM1 slot 45 Data Mux", "1234", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "1243", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "1324", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "1342", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "1432", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "1423", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "2134", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "2143", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "2314", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "2341", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "2431", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "2413", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "3124", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "3142", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "3214", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "3241", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "3412", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "3421", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "4123", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "4132", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "4213", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "4231", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "4312", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "4321", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", NULL, "I2S1_1"}, + + {"TDM1 slot 67 Data Mux", "1234", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "1243", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "1324", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "1342", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "1432", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "1423", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "2134", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "2143", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "2314", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "2341", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "2431", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "2413", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "3124", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "3142", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "3214", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "3241", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "3412", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "3421", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "4123", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "4132", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "4213", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "4231", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "4312", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "4321", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", NULL, "I2S1_1"}, + + + {"TDM2 slot 01 Data Mux", "1234", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1243", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1324", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1342", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1432", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1423", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "2134", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2143", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2314", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2341", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2431", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2413", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "3124", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3142", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3214", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3241", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3412", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3421", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "4123", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4132", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4213", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4231", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4312", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4321", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", NULL, "I2S1_2"}, + + {"TDM2 slot 23 Data Mux", "1234", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "1243", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "1324", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "1342", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "1432", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "1423", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "2134", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "2143", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "2314", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "2341", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "2431", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "2413", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "3124", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "3142", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "3214", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "3241", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "3412", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "3421", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "4123", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "4132", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "4213", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "4231", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "4312", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "4321", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", NULL, "I2S1_2"}, + + {"TDM2 slot 45 Data Mux", "1234", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "1243", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "1324", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "1342", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "1432", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "1423", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "2134", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "2143", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "2314", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "2341", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "2431", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "2413", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "3124", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "3142", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "3214", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "3241", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "3412", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "3421", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "4123", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "4132", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "4213", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "4231", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "4312", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "4321", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", NULL, "I2S1_2"}, + + {"TDM2 slot 67 Data Mux", "1234", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "1243", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "1324", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "1342", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "1432", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "1423", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "2134", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "2143", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "2314", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "2341", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "2431", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "2413", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "3124", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "3142", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "3214", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "3241", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "3412", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "3421", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "4123", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "4132", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "4213", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "4231", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "4312", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "4321", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", NULL, "I2S1_2"}, + + {"IF1_1 0 ADC Swap Mux", "L/R", "TDM1 slot 01 Data Mux"}, + {"IF1_1 0 ADC Swap Mux", "L/L", "TDM1 slot 01 Data Mux"}, + {"IF1_1 1 ADC Swap Mux", "R/L", "TDM1 slot 01 Data Mux"}, + {"IF1_1 1 ADC Swap Mux", "R/R", "TDM1 slot 01 Data Mux"}, + {"IF1_1 2 ADC Swap Mux", "L/R", "TDM1 slot 23 Data Mux"}, + {"IF1_1 2 ADC Swap Mux", "R/L", "TDM1 slot 23 Data Mux"}, + {"IF1_1 3 ADC Swap Mux", "L/L", "TDM1 slot 23 Data Mux"}, + {"IF1_1 3 ADC Swap Mux", "R/R", "TDM1 slot 23 Data Mux"}, + {"IF1_1 4 ADC Swap Mux", "L/R", "TDM1 slot 45 Data Mux"}, + {"IF1_1 4 ADC Swap Mux", "R/L", "TDM1 slot 45 Data Mux"}, + {"IF1_1 5 ADC Swap Mux", "L/L", "TDM1 slot 45 Data Mux"}, + {"IF1_1 5 ADC Swap Mux", "R/R", "TDM1 slot 45 Data Mux"}, + {"IF1_1 6 ADC Swap Mux", "L/R", "TDM1 slot 67 Data Mux"}, + {"IF1_1 6 ADC Swap Mux", "R/L", "TDM1 slot 67 Data Mux"}, + {"IF1_1 7 ADC Swap Mux", "L/L", "TDM1 slot 67 Data Mux"}, + {"IF1_1 7 ADC Swap Mux", "R/R", "TDM1 slot 67 Data Mux"}, + {"IF1_2 0 ADC Swap Mux", "L/R", "TDM2 slot 01 Data Mux"}, + {"IF1_2 0 ADC Swap Mux", "R/L", "TDM2 slot 01 Data Mux"}, + {"IF1_2 1 ADC Swap Mux", "L/L", "TDM2 slot 01 Data Mux"}, + {"IF1_2 1 ADC Swap Mux", "R/R", "TDM2 slot 01 Data Mux"}, + {"IF1_2 2 ADC Swap Mux", "L/R", "TDM2 slot 23 Data Mux"}, + {"IF1_2 2 ADC Swap Mux", "R/L", "TDM2 slot 23 Data Mux"}, + {"IF1_2 3 ADC Swap Mux", "L/L", "TDM2 slot 23 Data Mux"}, + {"IF1_2 3 ADC Swap Mux", "R/R", "TDM2 slot 23 Data Mux"}, + {"IF1_2 4 ADC Swap Mux", "L/R", "TDM2 slot 45 Data Mux"}, + {"IF1_2 4 ADC Swap Mux", "R/L", "TDM2 slot 45 Data Mux"}, + {"IF1_2 5 ADC Swap Mux", "L/L", "TDM2 slot 45 Data Mux"}, + {"IF1_2 5 ADC Swap Mux", "R/R", "TDM2 slot 45 Data Mux"}, + {"IF1_2 6 ADC Swap Mux", "L/R", "TDM2 slot 67 Data Mux"}, + {"IF1_2 6 ADC Swap Mux", "R/L", "TDM2 slot 67 Data Mux"}, + {"IF1_2 7 ADC Swap Mux", "L/L", "TDM2 slot 67 Data Mux"}, + {"IF1_2 7 ADC Swap Mux", "R/R", "TDM2 slot 67 Data Mux"}, + + {"IF2_1 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF2_1 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF2_1 ADC Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF2_1 ADC Mux", "IF1 DAC1", "IF1 DAC1"}, + {"IF2_1 ADC Mux", "IF1 DAC2", "IF1 DAC2"}, + {"IF2_1 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"}, + {"IF2_1 ADC Mux", "IF3 DAC", "IF3 DAC"}, + {"IF2_1 ADC Mux", "DAC1 MIX", "DAC1 MIX"}, + {"IF2_1 ADC", NULL, "IF2_1 ADC Mux"}, + {"IF2_1 ADC", NULL, "I2S2_1"}, + + {"IF2_2 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF2_2 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF2_2 ADC Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF2_2 ADC Mux", "IF1 DAC1", "IF1 DAC1"}, + {"IF2_2 ADC Mux", "IF1 DAC2", "IF1 DAC2"}, + {"IF2_2 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"}, + {"IF2_2 ADC Mux", "IF3 DAC", "IF3 DAC"}, + {"IF2_2 ADC Mux", "DAC1 MIX", "DAC1 MIX"}, + {"IF2_2 ADC", NULL, "IF2_2 ADC Mux"}, + {"IF2_2 ADC", NULL, "I2S2_2"}, + + {"IF3 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF3 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF3 ADC Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF3 ADC Mux", "IF1 DAC1", "IF1 DAC1"}, + {"IF3 ADC Mux", "IF1 DAC2", "IF1 DAC2"}, + {"IF3 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"}, + {"IF3 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"}, + {"IF3 ADC Mux", "DAC1 MIX", "DAC1 MIX"}, + {"IF3 ADC", NULL, "IF3 ADC Mux"}, + {"IF3 ADC", NULL, "I2S3"}, + + {"AIF1_1TX slot 0", NULL, "IF1_1 0 ADC Swap Mux"}, + {"AIF1_1TX slot 1", NULL, "IF1_1 1 ADC Swap Mux"}, + {"AIF1_1TX slot 2", NULL, "IF1_1 2 ADC Swap Mux"}, + {"AIF1_1TX slot 3", NULL, "IF1_1 3 ADC Swap Mux"}, + {"AIF1_1TX slot 4", NULL, "IF1_1 4 ADC Swap Mux"}, + {"AIF1_1TX slot 5", NULL, "IF1_1 5 ADC Swap Mux"}, + {"AIF1_1TX slot 6", NULL, "IF1_1 6 ADC Swap Mux"}, + {"AIF1_1TX slot 7", NULL, "IF1_1 7 ADC Swap Mux"}, + {"AIF1_2TX slot 0", NULL, "IF1_2 0 ADC Swap Mux"}, + {"AIF1_2TX slot 1", NULL, "IF1_2 1 ADC Swap Mux"}, + {"AIF1_2TX slot 2", NULL, "IF1_2 2 ADC Swap Mux"}, + {"AIF1_2TX slot 3", NULL, "IF1_2 3 ADC Swap Mux"}, + {"AIF1_2TX slot 4", NULL, "IF1_2 4 ADC Swap Mux"}, + {"AIF1_2TX slot 5", NULL, "IF1_2 5 ADC Swap Mux"}, + {"AIF1_2TX slot 6", NULL, "IF1_2 6 ADC Swap Mux"}, + {"AIF1_2TX slot 7", NULL, "IF1_2 7 ADC Swap Mux"}, + {"IF2_1 ADC Swap Mux", "L/R", "IF2_1 ADC"}, + {"IF2_1 ADC Swap Mux", "R/L", "IF2_1 ADC"}, + {"IF2_1 ADC Swap Mux", "L/L", "IF2_1 ADC"}, + {"IF2_1 ADC Swap Mux", "R/R", "IF2_1 ADC"}, + {"AIF2_1TX", NULL, "IF2_1 ADC Swap Mux"}, + {"IF2_2 ADC Swap Mux", "L/R", "IF2_2 ADC"}, + {"IF2_2 ADC Swap Mux", "R/L", "IF2_2 ADC"}, + {"IF2_2 ADC Swap Mux", "L/L", "IF2_2 ADC"}, + {"IF2_2 ADC Swap Mux", "R/R", "IF2_2 ADC"}, + {"AIF2_2TX", NULL, "IF2_2 ADC Swap Mux"}, + {"IF3 ADC Swap Mux", "L/R", "IF3 ADC"}, + {"IF3 ADC Swap Mux", "R/L", "IF3 ADC"}, + {"IF3 ADC Swap Mux", "L/L", "IF3 ADC"}, + {"IF3 ADC Swap Mux", "R/R", "IF3 ADC"}, + {"AIF3TX", NULL, "IF3 ADC Swap Mux"}, + + {"IF1 DAC1", NULL, "AIF1RX"}, + {"IF1 DAC2", NULL, "AIF1RX"}, + {"IF1 DAC3", NULL, "AIF1RX"}, + {"IF2_1 DAC Swap Mux", "L/R", "AIF2_1RX"}, + {"IF2_1 DAC Swap Mux", "R/L", "AIF2_1RX"}, + {"IF2_1 DAC Swap Mux", "L/L", "AIF2_1RX"}, + {"IF2_1 DAC Swap Mux", "R/R", "AIF2_1RX"}, + {"IF2_2 DAC Swap Mux", "L/R", "AIF2_2RX"}, + {"IF2_2 DAC Swap Mux", "R/L", "AIF2_2RX"}, + {"IF2_2 DAC Swap Mux", "L/L", "AIF2_2RX"}, + {"IF2_2 DAC Swap Mux", "R/R", "AIF2_2RX"}, + {"IF2_1 DAC", NULL, "IF2_1 DAC Swap Mux"}, + {"IF2_2 DAC", NULL, "IF2_2 DAC Swap Mux"}, + {"IF3 DAC Swap Mux", "L/R", "AIF3RX"}, + {"IF3 DAC Swap Mux", "R/L", "AIF3RX"}, + {"IF3 DAC Swap Mux", "L/L", "AIF3RX"}, + {"IF3 DAC Swap Mux", "R/R", "AIF3RX"}, + {"IF3 DAC", NULL, "IF3 DAC Swap Mux"}, + + {"IF1 DAC1", NULL, "I2S1_1"}, + {"IF1 DAC2", NULL, "I2S1_1"}, + {"IF1 DAC3", NULL, "I2S1_1"}, + {"IF2_1 DAC", NULL, "I2S2_1"}, + {"IF2_2 DAC", NULL, "I2S2_2"}, + {"IF3 DAC", NULL, "I2S3"}, + + {"IF1 DAC1 L", NULL, "IF1 DAC1"}, + {"IF1 DAC1 R", NULL, "IF1 DAC1"}, + {"IF1 DAC2 L", NULL, "IF1 DAC2"}, + {"IF1 DAC2 R", NULL, "IF1 DAC2"}, + {"IF1 DAC3 L", NULL, "IF1 DAC3"}, + {"IF1 DAC3 R", NULL, "IF1 DAC3"}, + {"IF2_1 DAC L", NULL, "IF2_1 DAC"}, + {"IF2_1 DAC R", NULL, "IF2_1 DAC"}, + {"IF2_2 DAC L", NULL, "IF2_2 DAC"}, + {"IF2_2 DAC R", NULL, "IF2_2 DAC"}, + {"IF3 DAC L", NULL, "IF3 DAC"}, + {"IF3 DAC R", NULL, "IF3 DAC"}, + + {"DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L"}, + {"DAC L1 Mux", "IF2_1 DAC", "IF2_1 DAC L"}, + {"DAC L1 Mux", "IF2_2 DAC", "IF2_2 DAC L"}, + {"DAC L1 Mux", "IF3 DAC", "IF3 DAC L"}, + {"DAC L1 Mux", NULL, "DAC Stereo1 Filter"}, + + {"DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R"}, + {"DAC R1 Mux", "IF2_1 DAC", "IF2_1 DAC R"}, + {"DAC R1 Mux", "IF2_2 DAC", "IF2_2 DAC R"}, + {"DAC R1 Mux", "IF3 DAC", "IF3 DAC R"}, + {"DAC R1 Mux", NULL, "DAC Stereo1 Filter"}, + + {"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, + {"DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux"}, + {"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, + {"DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux"}, + + {"DAC1 MIX", NULL, "DAC1 MIXL"}, + {"DAC1 MIX", NULL, "DAC1 MIXR"}, + + {"DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L"}, + {"DAC L2 Mux", "IF2_1 DAC", "IF2_1 DAC L"}, + {"DAC L2 Mux", "IF2_2 DAC", "IF2_2 DAC L"}, + {"DAC L2 Mux", "IF3 DAC", "IF3 DAC L"}, + {"DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL"}, + {"DAC L2 Mux", NULL, "DAC Mono Left Filter"}, + + {"DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R"}, + {"DAC R2 Mux", "IF2_1 DAC", "IF2_1 DAC R"}, + {"DAC R2 Mux", "IF2_2 DAC", "IF2_2 DAC R"}, + {"DAC R2 Mux", "IF3 DAC", "IF3 DAC R"}, + {"DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR"}, + {"DAC R2 Mux", NULL, "DAC Mono Right Filter"}, + + {"DAC L3 Mux", "IF1 DAC2", "IF1 DAC2 L"}, + {"DAC L3 Mux", "IF2_1 DAC", "IF2_1 DAC L"}, + {"DAC L3 Mux", "IF2_2 DAC", "IF2_2 DAC L"}, + {"DAC L3 Mux", "IF3 DAC", "IF3 DAC L"}, + {"DAC L3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXL"}, + {"DAC L3 Mux", NULL, "DAC Stereo2 Filter"}, + + {"DAC R3 Mux", "IF1 DAC2", "IF1 DAC2 R"}, + {"DAC R3 Mux", "IF2_1 DAC", "IF2_1 DAC R"}, + {"DAC R3 Mux", "IF2_2 DAC", "IF2_2 DAC R"}, + {"DAC R3 Mux", "IF3 DAC", "IF3 DAC R"}, + {"DAC R3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXR"}, + {"DAC R3 Mux", NULL, "DAC Stereo2 Filter"}, + + {"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, + {"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"}, + {"Stereo1 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + {"Stereo1 DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, + + {"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, + {"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"}, + {"Stereo1 DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, + {"Stereo1 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + + {"Stereo2 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, + {"Stereo2 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + {"Stereo2 DAC MIXL", "DAC L3 Switch", "DAC L3 Mux"}, + + {"Stereo2 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, + {"Stereo2 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + {"Stereo2 DAC MIXR", "DAC R3 Switch", "DAC R3 Mux"}, + + {"Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, + {"Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"}, + {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, + {"Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"}, + {"Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, + {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, + {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + + {"DAC MIXL", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"}, + {"DAC MIXL", "Stereo2 DAC Mixer", "Stereo2 DAC MIXL"}, + {"DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL"}, + {"DAC MIXR", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"}, + {"DAC MIXR", "Stereo2 DAC Mixer", "Stereo2 DAC MIXR"}, + {"DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR"}, + + {"DAC L1 Source", "DAC1", "DAC1 MIXL"}, + {"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"}, + {"DAC L1 Source", "DMIC1", "DMIC L1"}, + {"DAC R1 Source", "DAC1", "DAC1 MIXR"}, + {"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"}, + {"DAC R1 Source", "DMIC1", "DMIC R1"}, + + {"DAC L2 Source", "DAC2", "DAC L2 Mux"}, + {"DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL"}, + {"DAC L2 Source", NULL, "DAC L2 Power"}, + {"DAC R2 Source", "DAC2", "DAC R2 Mux"}, + {"DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR"}, + {"DAC R2 Source", NULL, "DAC R2 Power"}, + + {"DAC L1", NULL, "DAC L1 Source"}, + {"DAC R1", NULL, "DAC R1 Source"}, + {"DAC L2", NULL, "DAC L2 Source"}, + {"DAC R2", NULL, "DAC R2 Source"}, + + {"DAC L1", NULL, "DAC 1 Clock"}, + {"DAC R1", NULL, "DAC 1 Clock"}, + {"DAC L2", NULL, "DAC 2 Clock"}, + {"DAC R2", NULL, "DAC 2 Clock"}, + + {"MONOVOL MIX", "DAC L2 Switch", "DAC L2"}, + {"MONOVOL MIX", "RECMIX2L Switch", "RECMIX2L"}, + {"MONOVOL MIX", "BST1 Switch", "BST1"}, + {"MONOVOL MIX", "BST2 Switch", "BST2"}, + {"MONOVOL MIX", "BST3 Switch", "BST3"}, + + {"OUT MIXL", "DAC L2 Switch", "DAC L2"}, + {"OUT MIXL", "INL Switch", "INL VOL"}, + {"OUT MIXL", "BST1 Switch", "BST1"}, + {"OUT MIXL", "BST2 Switch", "BST2"}, + {"OUT MIXL", "BST3 Switch", "BST3"}, + {"OUT MIXR", "DAC R2 Switch", "DAC R2"}, + {"OUT MIXR", "INR Switch", "INR VOL"}, + {"OUT MIXR", "BST2 Switch", "BST2"}, + {"OUT MIXR", "BST3 Switch", "BST3"}, + {"OUT MIXR", "BST4 Switch", "BST4"}, + + {"MONOVOL", "Switch", "MONOVOL MIX"}, + {"Mono MIX", "DAC L2 Switch", "DAC L2"}, + {"Mono MIX", "MONOVOL Switch", "MONOVOL"}, + {"Mono Amp", NULL, "Mono MIX"}, + {"Mono Amp", NULL, "Vref2"}, + {"Mono Amp", NULL, "CLKDET SYS"}, + {"Mono Amp", NULL, "CLKDET MONO"}, + {"Mono Playback", "Switch", "Mono Amp"}, + {"MONOOUT", NULL, "Mono Playback"}, + + {"HP Amp", NULL, "DAC L1"}, + {"HP Amp", NULL, "DAC R1"}, + {"HP Amp", NULL, "Charge Pump"}, + {"HP Amp", NULL, "CLKDET SYS"}, + {"HP Amp", NULL, "CLKDET HP"}, + {"HP Amp", NULL, "CBJ Power"}, + {"HP Amp", NULL, "Vref2"}, + {"HPO Playback", "Switch", "HP Amp"}, + {"HPOL", NULL, "HPO Playback"}, + {"HPOR", NULL, "HPO Playback"}, + + {"OUTVOL L", "Switch", "OUT MIXL"}, + {"OUTVOL R", "Switch", "OUT MIXR"}, + {"LOUT L MIX", "DAC L2 Switch", "DAC L2"}, + {"LOUT L MIX", "OUTVOL L Switch", "OUTVOL L"}, + {"LOUT R MIX", "DAC R2 Switch", "DAC R2"}, + {"LOUT R MIX", "OUTVOL R Switch", "OUTVOL R"}, + {"LOUT Amp", NULL, "LOUT L MIX"}, + {"LOUT Amp", NULL, "LOUT R MIX"}, + {"LOUT Amp", NULL, "Vref1"}, + {"LOUT Amp", NULL, "Vref2"}, + {"LOUT Amp", NULL, "CLKDET SYS"}, + {"LOUT Amp", NULL, "CLKDET LOUT"}, + {"LOUT L Playback", "Switch", "LOUT Amp"}, + {"LOUT R Playback", "Switch", "LOUT Amp"}, + {"LOUTL", NULL, "LOUT L Playback"}, + {"LOUTR", NULL, "LOUT R Playback"}, + + {"PDM L Mux", "Mono DAC", "Mono DAC MIXL"}, + {"PDM L Mux", "Stereo1 DAC", "Stereo1 DAC MIXL"}, + {"PDM L Mux", "Stereo2 DAC", "Stereo2 DAC MIXL"}, + {"PDM L Mux", NULL, "PDM Power"}, + {"PDM R Mux", "Mono DAC", "Mono DAC MIXR"}, + {"PDM R Mux", "Stereo1 DAC", "Stereo1 DAC MIXR"}, + {"PDM R Mux", "Stereo2 DAC", "Stereo2 DAC MIXR"}, + {"PDM R Mux", NULL, "PDM Power"}, + {"PDM L Playback", "Switch", "PDM L Mux"}, + {"PDM R Playback", "Switch", "PDM R Mux"}, + {"PDML", NULL, "PDM L Playback"}, + {"PDMR", NULL, "PDM R Playback"}, +}; + +static int rt5665_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk, val_bits = 0x0100; + int pre_div, frame_size; + + rt5665->lrck[dai->id] = params_rate(params); + pre_div = rl6231_get_clk_info(rt5665->sysclk, rt5665->lrck[dai->id]); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5665->lrck[dai->id], dai->id); + return -EINVAL; + } + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + + dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n", + rt5665->lrck[dai->id], pre_div, dai->id); + + switch (params_width(params)) { + case 16: + val_bits = 0x0100; + break; + case 20: + val_len |= RT5665_I2S_DL_20; + val_bits = 0x1300; + break; + case 24: + val_len |= RT5665_I2S_DL_24; + val_bits = 0x2500; + break; + case 8: + val_len |= RT5665_I2S_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5665_AIF1_1: + case RT5665_AIF1_2: + mask_clk = RT5665_I2S_PD1_MASK; + val_clk = pre_div << RT5665_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5665_I2S1_SDP, + RT5665_I2S_DL_MASK, val_len); + break; + case RT5665_AIF2_1: + case RT5665_AIF2_2: + mask_clk = RT5665_I2S_PD2_MASK; + val_clk = pre_div << RT5665_I2S_PD2_SFT; + snd_soc_update_bits(codec, RT5665_I2S2_SDP, + RT5665_I2S_DL_MASK, val_len); + break; + case RT5665_AIF3: + mask_clk = RT5665_I2S_PD3_MASK; + val_clk = pre_div << RT5665_I2S_PD3_SFT; + snd_soc_update_bits(codec, RT5665_I2S3_SDP, + RT5665_I2S_DL_MASK, val_len); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, mask_clk, val_clk); + snd_soc_update_bits(codec, RT5665_STO1_DAC_SIL_DET, 0x3700, val_bits); + + switch (rt5665->lrck[dai->id]) { + case 192000: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK, + RT5665_DAC_OSR_32 | RT5665_ADC_OSR_32); + break; + case 96000: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK, + RT5665_DAC_OSR_64 | RT5665_ADC_OSR_64); + break; + default: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK, + RT5665_DAC_OSR_128 | RT5665_ADC_OSR_128); + break; + } + + return 0; +} + +static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5665->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5665_I2S_MS_S; + rt5665->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5665_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5665_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5665_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5665_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5665_AIF1_1: + case RT5665_AIF1_2: + snd_soc_update_bits(codec, RT5665_I2S1_SDP, + RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK | + RT5665_I2S_DF_MASK, reg_val); + break; + case RT5665_AIF2_1: + case RT5665_AIF2_2: + snd_soc_update_bits(codec, RT5665_I2S2_SDP, + RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK | + RT5665_I2S_DF_MASK, reg_val); + break; + case RT5665_AIF3: + snd_soc_update_bits(codec, RT5665_I2S3_SDP, + RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK | + RT5665_I2S_DF_MASK, reg_val); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + return 0; +} + +static int rt5665_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5665->sysclk && clk_id == rt5665->sysclk_src) + return 0; + + switch (clk_id) { + case RT5665_SCLK_S_MCLK: + reg_val |= RT5665_SCLK_SRC_MCLK; + break; + case RT5665_SCLK_S_PLL1: + reg_val |= RT5665_SCLK_SRC_PLL1; + break; + case RT5665_SCLK_S_RCCLK: + reg_val |= RT5665_SCLK_SRC_RCCLK; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_SCLK_SRC_MASK, reg_val); + rt5665->sysclk = freq; + rt5665->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (Source == rt5665->pll_src && freq_in == rt5665->pll_in && + freq_out == rt5665->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5665->pll_in = 0; + rt5665->pll_out = 0; + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_SCLK_SRC_MASK, RT5665_SCLK_SRC_MCLK); + return 0; + } + + switch (Source) { + case RT5665_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_MCLK); + break; + case RT5665_PLL1_S_BCLK1: + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK1); + break; + case RT5665_PLL1_S_BCLK2: + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK2); + break; + case RT5665_PLL1_S_BCLK3: + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK3); + break; + default: + dev_err(codec->dev, "Unknown PLL Source %d\n", Source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_write(codec, RT5665_PLL_CTRL_1, + pll_code.n_code << RT5665_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5665_PLL_CTRL_2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT | + pll_code.m_bp << RT5665_PLL_M_BP_SFT); + + rt5665->pll_in = freq_in; + rt5665->pll_out = freq_out; + rt5665->pll_src = Source; + + return 0; +} + +static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val = 0; + + if (rx_mask || tx_mask) + val |= RT5665_I2S1_MODE_TDM; + + switch (slots) { + case 4: + val |= RT5665_TDM_IN_CH_4; + val |= RT5665_TDM_OUT_CH_4; + break; + case 6: + val |= RT5665_TDM_IN_CH_6; + val |= RT5665_TDM_OUT_CH_6; + break; + case 8: + val |= RT5665_TDM_IN_CH_8; + val |= RT5665_TDM_OUT_CH_8; + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + val |= RT5665_TDM_IN_LEN_20; + val |= RT5665_TDM_OUT_LEN_20; + break; + case 24: + val |= RT5665_TDM_IN_LEN_24; + val |= RT5665_TDM_OUT_LEN_24; + break; + case 32: + val |= RT5665_TDM_IN_LEN_32; + val |= RT5665_TDM_OUT_LEN_32; + break; + case 16: + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5665_TDM_CTRL_1, + RT5665_I2S1_MODE_MASK | RT5665_TDM_IN_CH_MASK | + RT5665_TDM_OUT_CH_MASK | RT5665_TDM_IN_LEN_MASK | + RT5665_TDM_OUT_LEN_MASK, val); + + return 0; +} + +static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); + + rt5665->bclk[dai->id] = ratio; + + if (ratio == 64) { + switch (dai->id) { + case RT5665_AIF2_1: + case RT5665_AIF2_2: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_I2S_BCLK_MS2_MASK, + RT5665_I2S_BCLK_MS2_64); + break; + case RT5665_AIF3: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_I2S_BCLK_MS3_MASK, + RT5665_I2S_BCLK_MS3_64); + break; + } + } + + return 0; +} + +static int rt5665_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_PREPARE: + regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC, + RT5665_DIG_GATE_CTRL, RT5665_DIG_GATE_CTRL); + break; + + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1, + RT5665_PWR_LDO, RT5665_PWR_LDO); + regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1, + RT5665_PWR_MB, RT5665_PWR_MB); + regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC, + RT5665_DIG_GATE_CTRL, 0); + break; + case SND_SOC_BIAS_OFF: + regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1, + RT5665_PWR_LDO, 0); + regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1, + RT5665_PWR_MB, 0); + break; + + default: + break; + } + + return 0; +} + +static int rt5665_probe(struct snd_soc_codec *codec) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + rt5665->codec = codec; + + schedule_delayed_work(&rt5665->calibrate_work, msecs_to_jiffies(100)); + + return 0; +} + +static int rt5665_remove(struct snd_soc_codec *codec) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + regmap_write(rt5665->regmap, RT5665_RESET, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int rt5665_suspend(struct snd_soc_codec *codec) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5665->regmap, true); + regcache_mark_dirty(rt5665->regmap); + return 0; +} + +static int rt5665_resume(struct snd_soc_codec *codec) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5665->regmap, false); + regcache_sync(rt5665->regmap); + + return 0; +} +#else +#define rt5665_suspend NULL +#define rt5665_resume NULL +#endif + +#define RT5665_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5665_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt5665_aif_dai_ops = { + .hw_params = rt5665_hw_params, + .set_fmt = rt5665_set_dai_fmt, + .set_sysclk = rt5665_set_dai_sysclk, + .set_tdm_slot = rt5665_set_tdm_slot, + .set_pll = rt5665_set_dai_pll, + .set_bclk_ratio = rt5665_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt5665_dai[] = { + { + .name = "rt5665-aif1_1", + .id = RT5665_AIF1_1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 8, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .capture = { + .stream_name = "AIF1_1 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, + { + .name = "rt5665-aif1_2", + .id = RT5665_AIF1_2, + .capture = { + .stream_name = "AIF1_2 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, + { + .name = "rt5665-aif2_1", + .id = RT5665_AIF2_1, + .playback = { + .stream_name = "AIF2_1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .capture = { + .stream_name = "AIF2_1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, + { + .name = "rt5665-aif2_2", + .id = RT5665_AIF2_2, + .playback = { + .stream_name = "AIF2_2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .capture = { + .stream_name = "AIF2_2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, + { + .name = "rt5665-aif3", + .id = RT5665_AIF3, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5665 = { + .probe = rt5665_probe, + .remove = rt5665_remove, + .suspend = rt5665_suspend, + .resume = rt5665_resume, + .set_bias_level = rt5665_set_bias_level, + .idle_bias_off = true, + .component_driver = { + .controls = rt5665_snd_controls, + .num_controls = ARRAY_SIZE(rt5665_snd_controls), + .dapm_widgets = rt5665_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5665_dapm_widgets), + .dapm_routes = rt5665_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5665_dapm_routes), + } +}; + + +static const struct regmap_config rt5665_regmap = { + .reg_bits = 16, + .val_bits = 16, + .max_register = 0x0400, + .volatile_reg = rt5665_volatile_register, + .readable_reg = rt5665_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5665_reg, + .num_reg_defaults = ARRAY_SIZE(rt5665_reg), + .use_single_rw = true, +}; + +static const struct i2c_device_id rt5665_i2c_id[] = { + {"rt5665", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt5665_i2c_id); + +static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev) +{ + rt5665->pdata.in1_diff = of_property_read_bool(dev->of_node, + "realtek,in1-differential"); + rt5665->pdata.in2_diff = of_property_read_bool(dev->of_node, + "realtek,in2-differential"); + rt5665->pdata.in3_diff = of_property_read_bool(dev->of_node, + "realtek,in3-differential"); + rt5665->pdata.in4_diff = of_property_read_bool(dev->of_node, + "realtek,in4-differential"); + + of_property_read_u32(dev->of_node, "realtek,dmic1-data-pin", + &rt5665->pdata.dmic1_data_pin); + of_property_read_u32(dev->of_node, "realtek,dmic2-data-pin", + &rt5665->pdata.dmic2_data_pin); + of_property_read_u32(dev->of_node, "realtek,jd-src", + &rt5665->pdata.jd_src); + + rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node, + "realtek,ldo1-en-gpios", 0); + + return 0; +} + +static void rt5665_calibrate(struct rt5665_priv *rt5665) +{ + int value, count; + + mutex_lock(&rt5665->calibrate_mutex); + + regcache_cache_bypass(rt5665->regmap, true); + + regmap_write(rt5665->regmap, RT5665_RESET, 0); + regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); + regmap_write(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1, 0x0c26); + regmap_write(rt5665->regmap, RT5665_MONOMIX_IN_GAIN, 0x021f); + regmap_write(rt5665->regmap, RT5665_MONO_OUT, 0x480a); + regmap_write(rt5665->regmap, RT5665_PWR_MIXER, 0x083f); + regmap_write(rt5665->regmap, RT5665_PWR_DIG_1, 0x0180); + regmap_write(rt5665->regmap, RT5665_EJD_CTRL_1, 0x4040); + regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0000); + regmap_write(rt5665->regmap, RT5665_DIG_MISC, 0x0001); + regmap_write(rt5665->regmap, RT5665_MICBIAS_2, 0x0380); + regmap_write(rt5665->regmap, RT5665_GLB_CLK, 0x8000); + regmap_write(rt5665->regmap, RT5665_ADDA_CLK_1, 0x1000); + regmap_write(rt5665->regmap, RT5665_CHOP_DAC, 0x3030); + regmap_write(rt5665->regmap, RT5665_CALIB_ADC_CTRL, 0x3c05); + regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xaa3e); + usleep_range(15000, 20000); + regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xfe7e); + regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_2, 0x0321); + + regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_1, 0xfc00); + count = 0; + while (true) { + regmap_read(rt5665->regmap, RT5665_HP_CALIB_STA_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 60) { + pr_err("HP Calibration Failure\n"); + regmap_write(rt5665->regmap, RT5665_RESET, 0); + regcache_cache_bypass(rt5665->regmap, false); + goto out_unlock; + } + + count++; + } + + regmap_write(rt5665->regmap, RT5665_MONO_AMP_CALIB_CTRL_1, 0x9e24); + count = 0; + while (true) { + regmap_read(rt5665->regmap, RT5665_MONO_AMP_CALIB_STA1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 60) { + pr_err("MONO Calibration Failure\n"); + regmap_write(rt5665->regmap, RT5665_RESET, 0); + regcache_cache_bypass(rt5665->regmap, false); + goto out_unlock; + } + + count++; + } + + regmap_write(rt5665->regmap, RT5665_RESET, 0); + regcache_cache_bypass(rt5665->regmap, false); + + regcache_mark_dirty(rt5665->regmap); + regcache_sync(rt5665->regmap); + + regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); + regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); + +out_unlock: + mutex_unlock(&rt5665->calibrate_mutex); +} + +static void rt5665_calibrate_handler(struct work_struct *work) +{ + struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv, + calibrate_work.work); + + while (!rt5665->codec->component.card->instantiated) { + pr_debug("%s\n", __func__); + usleep_range(10000, 15000); + } + + rt5665_calibrate(rt5665); +} + +static int rt5665_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5665_priv *rt5665; + int i, ret; + unsigned int val; + + rt5665 = devm_kzalloc(&i2c->dev, sizeof(struct rt5665_priv), + GFP_KERNEL); + + if (rt5665 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5665); + + if (pdata) + rt5665->pdata = *pdata; + else + rt5665_parse_dt(rt5665, &i2c->dev); + + for (i = 0; i < ARRAY_SIZE(rt5665->supplies); i++) + rt5665->supplies[i].supply = rt5665_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5665->supplies), + rt5665->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(rt5665->supplies), + rt5665->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + if (gpio_is_valid(rt5665->pdata.ldo1_en)) { + if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en, + GPIOF_OUT_INIT_HIGH, "rt5665")) + dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + } + + /* Sleep for 300 ms miniumum */ + usleep_range(300000, 350000); + + rt5665->regmap = devm_regmap_init_i2c(i2c, &rt5665_regmap); + if (IS_ERR(rt5665->regmap)) { + ret = PTR_ERR(rt5665->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5665->regmap, RT5665_DEVICE_ID, &val); + if (val != DEVICE_ID) { + dev_err(&i2c->dev, + "Device with ID register %x is not rt5665\n", val); + return -ENODEV; + } + + regmap_read(rt5665->regmap, RT5665_RESET, &val); + switch (val) { + case 0x0: + rt5665->id = CODEC_5666; + break; + case 0x6: + rt5665->id = CODEC_5668; + break; + case 0x3: + default: + rt5665->id = CODEC_5665; + break; + } + + regmap_write(rt5665->regmap, RT5665_RESET, 0); + + /* line in diff mode*/ + if (rt5665->pdata.in1_diff) + regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2, + RT5665_IN1_DF_MASK, RT5665_IN1_DF_MASK); + if (rt5665->pdata.in2_diff) + regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2, + RT5665_IN2_DF_MASK, RT5665_IN2_DF_MASK); + if (rt5665->pdata.in3_diff) + regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4, + RT5665_IN3_DF_MASK, RT5665_IN3_DF_MASK); + if (rt5665->pdata.in4_diff) + regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4, + RT5665_IN4_DF_MASK, RT5665_IN4_DF_MASK); + + /* DMIC pin*/ + if (rt5665->pdata.dmic1_data_pin != RT5665_DMIC1_NULL || + rt5665->pdata.dmic2_data_pin != RT5665_DMIC2_NULL) { + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2, + RT5665_GP9_PIN_MASK, RT5665_GP9_PIN_DMIC1_SCL); + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, + RT5665_GP8_PIN_MASK, RT5665_GP8_PIN_DMIC2_SCL); + switch (rt5665->pdata.dmic1_data_pin) { + case RT5665_DMIC1_DATA_IN2N: + regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1, + RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_IN2N); + break; + + case RT5665_DMIC1_DATA_GPIO4: + regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1, + RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_GPIO4); + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, + RT5665_GP4_PIN_MASK, RT5665_GP4_PIN_DMIC1_SDA); + break; + + default: + dev_dbg(&i2c->dev, "no DMIC1\n"); + break; + } + + switch (rt5665->pdata.dmic2_data_pin) { + case RT5665_DMIC2_DATA_IN2P: + regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1, + RT5665_DMIC_2_DP_MASK, RT5665_DMIC_2_DP_IN2P); + break; + + case RT5665_DMIC2_DATA_GPIO5: + regmap_update_bits(rt5665->regmap, + RT5665_DMIC_CTRL_1, + RT5665_DMIC_2_DP_MASK, + RT5665_DMIC_2_DP_GPIO5); + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, + RT5665_GP5_PIN_MASK, RT5665_GP5_PIN_DMIC2_SDA); + break; + + default: + dev_dbg(&i2c->dev, "no DMIC2\n"); + break; + + } + } + + regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0002); + regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, + 0xf000 | RT5665_VREF_POW_MASK, 0xd000 | RT5665_VREF_POW_REG); + /* Work around for pow_pump */ + regmap_update_bits(rt5665->regmap, RT5665_STO1_DAC_SIL_DET, + RT5665_DEB_STO_DAC_MASK, RT5665_DEB_80_MS); + + regmap_update_bits(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1, + RT5665_PM_HP_MASK, RT5665_PM_HP_HV); + + /* Set GPIO4,8 as input for combo jack */ + if (rt5665->id == CODEC_5666) { + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2, + RT5665_GP4_PF_MASK, RT5665_GP4_PF_IN); + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_3, + RT5665_GP8_PF_MASK, RT5665_GP8_PF_IN); + } + + /* Enhance performance*/ + regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1, + RT5665_HP_DRIVER_MASK | RT5665_LDO1_DVO_MASK, + RT5665_HP_DRIVER_5X | RT5665_LDO1_DVO_09); + + INIT_DELAYED_WORK(&rt5665->jack_detect_work, + rt5665_jack_detect_handler); + INIT_DELAYED_WORK(&rt5665->calibrate_work, + rt5665_calibrate_handler); + INIT_DELAYED_WORK(&rt5665->jd_check_work, + rt5665_jd_check_handler); + + mutex_init(&rt5665->calibrate_mutex); + + if (i2c->irq) { + ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, + rt5665_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, "rt5665", rt5665); + if (ret) + dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + + } + + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5665, + rt5665_dai, ARRAY_SIZE(rt5665_dai)); +} + +static int rt5665_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static void rt5665_i2c_shutdown(struct i2c_client *client) +{ + struct rt5665_priv *rt5665 = i2c_get_clientdata(client); + + regmap_write(rt5665->regmap, RT5665_RESET, 0); +} + +#ifdef CONFIG_OF +static const struct of_device_id rt5665_of_match[] = { + {.compatible = "realtek,rt5665"}, + {.compatible = "realtek,rt5666"}, + {.compatible = "realtek,rt5668"}, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5665_of_match); +#endif + +#ifdef CONFIG_ACPI +static struct acpi_device_id rt5665_acpi_match[] = { + {"10EC5665", 0,}, + {"10EC5666", 0,}, + {"10EC5668", 0,}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt5665_acpi_match); +#endif + +struct i2c_driver rt5665_i2c_driver = { + .driver = { + .name = "rt5665", + .of_match_table = of_match_ptr(rt5665_of_match), + .acpi_match_table = ACPI_PTR(rt5665_acpi_match), + }, + .probe = rt5665_i2c_probe, + .remove = rt5665_i2c_remove, + .shutdown = rt5665_i2c_shutdown, + .id_table = rt5665_i2c_id, +}; +module_i2c_driver(rt5665_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5665 driver"); +MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h new file mode 100644 index 000000000000..12f7080a0d3c --- /dev/null +++ b/sound/soc/codecs/rt5665.h @@ -0,0 +1,1990 @@ +/* + * rt5665.h -- RT5665/RT5658 ALSA SoC audio driver + * + * Copyright 2016 Realtek Microelectronics + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5665_H__ +#define __RT5665_H__ + +#include <sound/rt5665.h> + +#define DEVICE_ID 0x6451 + +/* Info */ +#define RT5665_RESET 0x0000 +#define RT5665_VENDOR_ID 0x00fd +#define RT5665_VENDOR_ID_1 0x00fe +#define RT5665_DEVICE_ID 0x00ff +/* I/O - Output */ +#define RT5665_LOUT 0x0001 +#define RT5665_HP_CTRL_1 0x0002 +#define RT5665_HP_CTRL_2 0x0003 +#define RT5665_MONO_OUT 0x0004 +#define RT5665_HPL_GAIN 0x0005 +#define RT5665_HPR_GAIN 0x0006 +#define RT5665_MONO_GAIN 0x0007 + +/* I/O - Input */ +#define RT5665_CAL_BST_CTRL 0x000a +#define RT5665_CBJ_BST_CTRL 0x000b +#define RT5665_IN1_IN2 0x000c +#define RT5665_IN3_IN4 0x000d +#define RT5665_INL1_INR1_VOL 0x000f +/* I/O - Speaker */ +#define RT5665_EJD_CTRL_1 0x0010 +#define RT5665_EJD_CTRL_2 0x0011 +#define RT5665_EJD_CTRL_3 0x0012 +#define RT5665_EJD_CTRL_4 0x0013 +#define RT5665_EJD_CTRL_5 0x0014 +#define RT5665_EJD_CTRL_6 0x0015 +#define RT5665_EJD_CTRL_7 0x0016 +/* I/O - ADC/DAC/DMIC */ +#define RT5665_DAC2_CTRL 0x0017 +#define RT5665_DAC2_DIG_VOL 0x0018 +#define RT5665_DAC1_DIG_VOL 0x0019 +#define RT5665_DAC3_DIG_VOL 0x001a +#define RT5665_DAC3_CTRL 0x001b +#define RT5665_STO1_ADC_DIG_VOL 0x001c +#define RT5665_MONO_ADC_DIG_VOL 0x001d +#define RT5665_STO2_ADC_DIG_VOL 0x001e +#define RT5665_STO1_ADC_BOOST 0x001f +#define RT5665_MONO_ADC_BOOST 0x0020 +#define RT5665_STO2_ADC_BOOST 0x0021 +#define RT5665_HP_IMP_GAIN_1 0x0022 +#define RT5665_HP_IMP_GAIN_2 0x0023 +/* Mixer - D-D */ +#define RT5665_STO1_ADC_MIXER 0x0026 +#define RT5665_MONO_ADC_MIXER 0x0027 +#define RT5665_STO2_ADC_MIXER 0x0028 +#define RT5665_AD_DA_MIXER 0x0029 +#define RT5665_STO1_DAC_MIXER 0x002a +#define RT5665_MONO_DAC_MIXER 0x002b +#define RT5665_STO2_DAC_MIXER 0x002c +#define RT5665_A_DAC1_MUX 0x002d +#define RT5665_A_DAC2_MUX 0x002e +#define RT5665_DIG_INF2_DATA 0x002f +#define RT5665_DIG_INF3_DATA 0x0030 +/* Mixer - PDM */ +#define RT5665_PDM_OUT_CTRL 0x0031 +#define RT5665_PDM_DATA_CTRL_1 0x0032 +#define RT5665_PDM_DATA_CTRL_2 0x0033 +#define RT5665_PDM_DATA_CTRL_3 0x0034 +#define RT5665_PDM_DATA_CTRL_4 0x0035 +/* Mixer - ADC */ +#define RT5665_REC1_GAIN 0x003a +#define RT5665_REC1_L1_MIXER 0x003b +#define RT5665_REC1_L2_MIXER 0x003c +#define RT5665_REC1_R1_MIXER 0x003d +#define RT5665_REC1_R2_MIXER 0x003e +#define RT5665_REC2_GAIN 0x003f +#define RT5665_REC2_L1_MIXER 0x0040 +#define RT5665_REC2_L2_MIXER 0x0041 +#define RT5665_REC2_R1_MIXER 0x0042 +#define RT5665_REC2_R2_MIXER 0x0043 +#define RT5665_CAL_REC 0x0044 +/* Mixer - DAC */ +#define RT5665_ALC_BACK_GAIN 0x0049 +#define RT5665_MONOMIX_GAIN 0x004a +#define RT5665_MONOMIX_IN_GAIN 0x004b +#define RT5665_OUT_L_GAIN 0x004d +#define RT5665_OUT_L_MIXER 0x004e +#define RT5665_OUT_R_GAIN 0x004f +#define RT5665_OUT_R_MIXER 0x0050 +#define RT5665_LOUT_MIXER 0x0052 +/* Power */ +#define RT5665_PWR_DIG_1 0x0061 +#define RT5665_PWR_DIG_2 0x0062 +#define RT5665_PWR_ANLG_1 0x0063 +#define RT5665_PWR_ANLG_2 0x0064 +#define RT5665_PWR_ANLG_3 0x0065 +#define RT5665_PWR_MIXER 0x0066 +#define RT5665_PWR_VOL 0x0067 +/* Clock Detect */ +#define RT5665_CLK_DET 0x006b +/* Filter */ +#define RT5665_HPF_CTRL1 0x006d +/* DMIC */ +#define RT5665_DMIC_CTRL_1 0x006e +#define RT5665_DMIC_CTRL_2 0x006f +/* Format - ADC/DAC */ +#define RT5665_I2S1_SDP 0x0070 +#define RT5665_I2S2_SDP 0x0071 +#define RT5665_I2S3_SDP 0x0072 +#define RT5665_ADDA_CLK_1 0x0073 +#define RT5665_ADDA_CLK_2 0x0074 +#define RT5665_I2S1_F_DIV_CTRL_1 0x0075 +#define RT5665_I2S1_F_DIV_CTRL_2 0x0076 +/* Format - TDM Control */ +#define RT5665_TDM_CTRL_1 0x0078 +#define RT5665_TDM_CTRL_2 0x0079 +#define RT5665_TDM_CTRL_3 0x007a +#define RT5665_TDM_CTRL_4 0x007b +#define RT5665_TDM_CTRL_5 0x007c +#define RT5665_TDM_CTRL_6 0x007d +#define RT5665_TDM_CTRL_7 0x007e +#define RT5665_TDM_CTRL_8 0x007f +/* Function - Analog */ +#define RT5665_GLB_CLK 0x0080 +#define RT5665_PLL_CTRL_1 0x0081 +#define RT5665_PLL_CTRL_2 0x0082 +#define RT5665_ASRC_1 0x0083 +#define RT5665_ASRC_2 0x0084 +#define RT5665_ASRC_3 0x0085 +#define RT5665_ASRC_4 0x0086 +#define RT5665_ASRC_5 0x0087 +#define RT5665_ASRC_6 0x0088 +#define RT5665_ASRC_7 0x0089 +#define RT5665_ASRC_8 0x008a +#define RT5665_ASRC_9 0x008b +#define RT5665_ASRC_10 0x008c +#define RT5665_DEPOP_1 0x008e +#define RT5665_DEPOP_2 0x008f +#define RT5665_HP_CHARGE_PUMP_1 0x0091 +#define RT5665_HP_CHARGE_PUMP_2 0x0092 +#define RT5665_MICBIAS_1 0x0093 +#define RT5665_MICBIAS_2 0x0094 +#define RT5665_ASRC_12 0x0098 +#define RT5665_ASRC_13 0x0099 +#define RT5665_ASRC_14 0x009a +#define RT5665_RC_CLK_CTRL 0x009f +#define RT5665_I2S_M_CLK_CTRL_1 0x00a0 +#define RT5665_I2S2_F_DIV_CTRL_1 0x00a1 +#define RT5665_I2S2_F_DIV_CTRL_2 0x00a2 +#define RT5665_I2S3_F_DIV_CTRL_1 0x00a3 +#define RT5665_I2S3_F_DIV_CTRL_2 0x00a4 +/* Function - Digital */ +#define RT5665_EQ_CTRL_1 0x00ae +#define RT5665_EQ_CTRL_2 0x00af +#define RT5665_IRQ_CTRL_1 0x00b6 +#define RT5665_IRQ_CTRL_2 0x00b7 +#define RT5665_IRQ_CTRL_3 0x00b8 +#define RT5665_IRQ_CTRL_4 0x00b9 +#define RT5665_IRQ_CTRL_5 0x00ba +#define RT5665_IRQ_CTRL_6 0x00bb +#define RT5665_INT_ST_1 0x00be +#define RT5665_GPIO_CTRL_1 0x00c0 +#define RT5665_GPIO_CTRL_2 0x00c1 +#define RT5665_GPIO_CTRL_3 0x00c2 +#define RT5665_GPIO_CTRL_4 0x00c3 +#define RT5665_GPIO_STA 0x00c4 +#define RT5665_HP_AMP_DET_CTRL_1 0x00d0 +#define RT5665_HP_AMP_DET_CTRL_2 0x00d1 +#define RT5665_MID_HP_AMP_DET 0x00d3 +#define RT5665_LOW_HP_AMP_DET 0x00d4 +#define RT5665_SV_ZCD_1 0x00d9 +#define RT5665_SV_ZCD_2 0x00da +#define RT5665_IL_CMD_1 0x00db +#define RT5665_IL_CMD_2 0x00dc +#define RT5665_IL_CMD_3 0x00dd +#define RT5665_IL_CMD_4 0x00de +#define RT5665_4BTN_IL_CMD_1 0x00df +#define RT5665_4BTN_IL_CMD_2 0x00e0 +#define RT5665_4BTN_IL_CMD_3 0x00e1 +#define RT5665_PSV_IL_CMD_1 0x00e2 + +#define RT5665_ADC_STO1_HP_CTRL_1 0x00ea +#define RT5665_ADC_STO1_HP_CTRL_2 0x00eb +#define RT5665_ADC_MONO_HP_CTRL_1 0x00ec +#define RT5665_ADC_MONO_HP_CTRL_2 0x00ed +#define RT5665_ADC_STO2_HP_CTRL_1 0x00ee +#define RT5665_ADC_STO2_HP_CTRL_2 0x00ef +#define RT5665_AJD1_CTRL 0x00f0 +#define RT5665_JD1_THD 0x00f1 +#define RT5665_JD2_THD 0x00f2 +#define RT5665_JD_CTRL_1 0x00f6 +#define RT5665_JD_CTRL_2 0x00f7 +#define RT5665_JD_CTRL_3 0x00f8 +/* General Control */ +#define RT5665_DIG_MISC 0x00fa +#define RT5665_DUMMY_2 0x00fb +#define RT5665_DUMMY_3 0x00fc + +#define RT5665_DAC_ADC_DIG_VOL1 0x0100 +#define RT5665_DAC_ADC_DIG_VOL2 0x0101 +#define RT5665_BIAS_CUR_CTRL_1 0x010a +#define RT5665_BIAS_CUR_CTRL_2 0x010b +#define RT5665_BIAS_CUR_CTRL_3 0x010c +#define RT5665_BIAS_CUR_CTRL_4 0x010d +#define RT5665_BIAS_CUR_CTRL_5 0x010e +#define RT5665_BIAS_CUR_CTRL_6 0x010f +#define RT5665_BIAS_CUR_CTRL_7 0x0110 +#define RT5665_BIAS_CUR_CTRL_8 0x0111 +#define RT5665_BIAS_CUR_CTRL_9 0x0112 +#define RT5665_BIAS_CUR_CTRL_10 0x0113 +#define RT5665_VREF_REC_OP_FB_CAP_CTRL 0x0117 +#define RT5665_CHARGE_PUMP_1 0x0125 +#define RT5665_DIG_IN_CTRL_1 0x0132 +#define RT5665_DIG_IN_CTRL_2 0x0133 +#define RT5665_PAD_DRIVING_CTRL 0x0137 +#define RT5665_SOFT_RAMP_DEPOP 0x0138 +#define RT5665_PLL 0x0139 +#define RT5665_CHOP_DAC 0x013a +#define RT5665_CHOP_ADC 0x013b +#define RT5665_CALIB_ADC_CTRL 0x013c +#define RT5665_VOL_TEST 0x013f +#define RT5665_TEST_MODE_CTRL_1 0x0145 +#define RT5665_TEST_MODE_CTRL_2 0x0146 +#define RT5665_TEST_MODE_CTRL_3 0x0147 +#define RT5665_TEST_MODE_CTRL_4 0x0148 +#define RT5665_BASSBACK_CTRL 0x0150 +#define RT5665_STO_NG2_CTRL_1 0x0160 +#define RT5665_STO_NG2_CTRL_2 0x0161 +#define RT5665_STO_NG2_CTRL_3 0x0162 +#define RT5665_STO_NG2_CTRL_4 0x0163 +#define RT5665_STO_NG2_CTRL_5 0x0164 +#define RT5665_STO_NG2_CTRL_6 0x0165 +#define RT5665_STO_NG2_CTRL_7 0x0166 +#define RT5665_STO_NG2_CTRL_8 0x0167 +#define RT5665_MONO_NG2_CTRL_1 0x0170 +#define RT5665_MONO_NG2_CTRL_2 0x0171 +#define RT5665_MONO_NG2_CTRL_3 0x0172 +#define RT5665_MONO_NG2_CTRL_4 0x0173 +#define RT5665_MONO_NG2_CTRL_5 0x0174 +#define RT5665_MONO_NG2_CTRL_6 0x0175 +#define RT5665_STO1_DAC_SIL_DET 0x0190 +#define RT5665_MONOL_DAC_SIL_DET 0x0191 +#define RT5665_MONOR_DAC_SIL_DET 0x0192 +#define RT5665_STO2_DAC_SIL_DET 0x0193 +#define RT5665_SIL_PSV_CTRL1 0x0194 +#define RT5665_SIL_PSV_CTRL2 0x0195 +#define RT5665_SIL_PSV_CTRL3 0x0196 +#define RT5665_SIL_PSV_CTRL4 0x0197 +#define RT5665_SIL_PSV_CTRL5 0x0198 +#define RT5665_SIL_PSV_CTRL6 0x0199 +#define RT5665_MONO_AMP_CALIB_CTRL_1 0x01a0 +#define RT5665_MONO_AMP_CALIB_CTRL_2 0x01a1 +#define RT5665_MONO_AMP_CALIB_CTRL_3 0x01a2 +#define RT5665_MONO_AMP_CALIB_CTRL_4 0x01a3 +#define RT5665_MONO_AMP_CALIB_CTRL_5 0x01a4 +#define RT5665_MONO_AMP_CALIB_CTRL_6 0x01a5 +#define RT5665_MONO_AMP_CALIB_CTRL_7 0x01a6 +#define RT5665_MONO_AMP_CALIB_STA1 0x01a7 +#define RT5665_MONO_AMP_CALIB_STA2 0x01a8 +#define RT5665_MONO_AMP_CALIB_STA3 0x01a9 +#define RT5665_MONO_AMP_CALIB_STA4 0x01aa +#define RT5665_MONO_AMP_CALIB_STA6 0x01ab +#define RT5665_HP_IMP_SENS_CTRL_01 0x01b5 +#define RT5665_HP_IMP_SENS_CTRL_02 0x01b6 +#define RT5665_HP_IMP_SENS_CTRL_03 0x01b7 +#define RT5665_HP_IMP_SENS_CTRL_04 0x01b8 +#define RT5665_HP_IMP_SENS_CTRL_05 0x01b9 +#define RT5665_HP_IMP_SENS_CTRL_06 0x01ba +#define RT5665_HP_IMP_SENS_CTRL_07 0x01bb +#define RT5665_HP_IMP_SENS_CTRL_08 0x01bc +#define RT5665_HP_IMP_SENS_CTRL_09 0x01bd +#define RT5665_HP_IMP_SENS_CTRL_10 0x01be +#define RT5665_HP_IMP_SENS_CTRL_11 0x01bf +#define RT5665_HP_IMP_SENS_CTRL_12 0x01c0 +#define RT5665_HP_IMP_SENS_CTRL_13 0x01c1 +#define RT5665_HP_IMP_SENS_CTRL_14 0x01c2 +#define RT5665_HP_IMP_SENS_CTRL_15 0x01c3 +#define RT5665_HP_IMP_SENS_CTRL_16 0x01c4 +#define RT5665_HP_IMP_SENS_CTRL_17 0x01c5 +#define RT5665_HP_IMP_SENS_CTRL_18 0x01c6 +#define RT5665_HP_IMP_SENS_CTRL_19 0x01c7 +#define RT5665_HP_IMP_SENS_CTRL_20 0x01c8 +#define RT5665_HP_IMP_SENS_CTRL_21 0x01c9 +#define RT5665_HP_IMP_SENS_CTRL_22 0x01ca +#define RT5665_HP_IMP_SENS_CTRL_23 0x01cb +#define RT5665_HP_IMP_SENS_CTRL_24 0x01cc +#define RT5665_HP_IMP_SENS_CTRL_25 0x01cd +#define RT5665_HP_IMP_SENS_CTRL_26 0x01ce +#define RT5665_HP_IMP_SENS_CTRL_27 0x01cf +#define RT5665_HP_IMP_SENS_CTRL_28 0x01d0 +#define RT5665_HP_IMP_SENS_CTRL_29 0x01d1 +#define RT5665_HP_IMP_SENS_CTRL_30 0x01d2 +#define RT5665_HP_IMP_SENS_CTRL_31 0x01d3 +#define RT5665_HP_IMP_SENS_CTRL_32 0x01d4 +#define RT5665_HP_IMP_SENS_CTRL_33 0x01d5 +#define RT5665_HP_IMP_SENS_CTRL_34 0x01d6 +#define RT5665_HP_LOGIC_CTRL_1 0x01da +#define RT5665_HP_LOGIC_CTRL_2 0x01db +#define RT5665_HP_LOGIC_CTRL_3 0x01dc +#define RT5665_HP_CALIB_CTRL_1 0x01de +#define RT5665_HP_CALIB_CTRL_2 0x01df +#define RT5665_HP_CALIB_CTRL_3 0x01e0 +#define RT5665_HP_CALIB_CTRL_4 0x01e1 +#define RT5665_HP_CALIB_CTRL_5 0x01e2 +#define RT5665_HP_CALIB_CTRL_6 0x01e3 +#define RT5665_HP_CALIB_CTRL_7 0x01e4 +#define RT5665_HP_CALIB_CTRL_9 0x01e6 +#define RT5665_HP_CALIB_CTRL_10 0x01e7 +#define RT5665_HP_CALIB_CTRL_11 0x01e8 +#define RT5665_HP_CALIB_STA_1 0x01ea +#define RT5665_HP_CALIB_STA_2 0x01eb +#define RT5665_HP_CALIB_STA_3 0x01ec +#define RT5665_HP_CALIB_STA_4 0x01ed +#define RT5665_HP_CALIB_STA_5 0x01ee +#define RT5665_HP_CALIB_STA_6 0x01ef +#define RT5665_HP_CALIB_STA_7 0x01f0 +#define RT5665_HP_CALIB_STA_8 0x01f1 +#define RT5665_HP_CALIB_STA_9 0x01f2 +#define RT5665_HP_CALIB_STA_10 0x01f3 +#define RT5665_HP_CALIB_STA_11 0x01f4 +#define RT5665_PGM_TAB_CTRL1 0x0200 +#define RT5665_PGM_TAB_CTRL2 0x0201 +#define RT5665_PGM_TAB_CTRL3 0x0202 +#define RT5665_PGM_TAB_CTRL4 0x0203 +#define RT5665_PGM_TAB_CTRL5 0x0204 +#define RT5665_PGM_TAB_CTRL6 0x0205 +#define RT5665_PGM_TAB_CTRL7 0x0206 +#define RT5665_PGM_TAB_CTRL8 0x0207 +#define RT5665_PGM_TAB_CTRL9 0x0208 +#define RT5665_SAR_IL_CMD_1 0x0210 +#define RT5665_SAR_IL_CMD_2 0x0211 +#define RT5665_SAR_IL_CMD_3 0x0212 +#define RT5665_SAR_IL_CMD_4 0x0213 +#define RT5665_SAR_IL_CMD_5 0x0214 +#define RT5665_SAR_IL_CMD_6 0x0215 +#define RT5665_SAR_IL_CMD_7 0x0216 +#define RT5665_SAR_IL_CMD_8 0x0217 +#define RT5665_SAR_IL_CMD_9 0x0218 +#define RT5665_SAR_IL_CMD_10 0x0219 +#define RT5665_SAR_IL_CMD_11 0x021a +#define RT5665_SAR_IL_CMD_12 0x021b +#define RT5665_DRC1_CTRL_0 0x02ff +#define RT5665_DRC1_CTRL_1 0x0300 +#define RT5665_DRC1_CTRL_2 0x0301 +#define RT5665_DRC1_CTRL_3 0x0302 +#define RT5665_DRC1_CTRL_4 0x0303 +#define RT5665_DRC1_CTRL_5 0x0304 +#define RT5665_DRC1_CTRL_6 0x0305 +#define RT5665_DRC1_HARD_LMT_CTRL_1 0x0306 +#define RT5665_DRC1_HARD_LMT_CTRL_2 0x0307 +#define RT5665_DRC1_PRIV_1 0x0310 +#define RT5665_DRC1_PRIV_2 0x0311 +#define RT5665_DRC1_PRIV_3 0x0312 +#define RT5665_DRC1_PRIV_4 0x0313 +#define RT5665_DRC1_PRIV_5 0x0314 +#define RT5665_DRC1_PRIV_6 0x0315 +#define RT5665_DRC1_PRIV_7 0x0316 +#define RT5665_DRC1_PRIV_8 0x0317 +#define RT5665_ALC_PGA_CTRL_1 0x0330 +#define RT5665_ALC_PGA_CTRL_2 0x0331 +#define RT5665_ALC_PGA_CTRL_3 0x0332 +#define RT5665_ALC_PGA_CTRL_4 0x0333 +#define RT5665_ALC_PGA_CTRL_5 0x0334 +#define RT5665_ALC_PGA_CTRL_6 0x0335 +#define RT5665_ALC_PGA_CTRL_7 0x0336 +#define RT5665_ALC_PGA_CTRL_8 0x0337 +#define RT5665_ALC_PGA_STA_1 0x0338 +#define RT5665_ALC_PGA_STA_2 0x0339 +#define RT5665_ALC_PGA_STA_3 0x033a +#define RT5665_EQ_AUTO_RCV_CTRL1 0x03c0 +#define RT5665_EQ_AUTO_RCV_CTRL2 0x03c1 +#define RT5665_EQ_AUTO_RCV_CTRL3 0x03c2 +#define RT5665_EQ_AUTO_RCV_CTRL4 0x03c3 +#define RT5665_EQ_AUTO_RCV_CTRL5 0x03c4 +#define RT5665_EQ_AUTO_RCV_CTRL6 0x03c5 +#define RT5665_EQ_AUTO_RCV_CTRL7 0x03c6 +#define RT5665_EQ_AUTO_RCV_CTRL8 0x03c7 +#define RT5665_EQ_AUTO_RCV_CTRL9 0x03c8 +#define RT5665_EQ_AUTO_RCV_CTRL10 0x03c9 +#define RT5665_EQ_AUTO_RCV_CTRL11 0x03ca +#define RT5665_EQ_AUTO_RCV_CTRL12 0x03cb +#define RT5665_EQ_AUTO_RCV_CTRL13 0x03cc +#define RT5665_ADC_L_EQ_LPF1_A1 0x03d0 +#define RT5665_R_EQ_LPF1_A1 0x03d1 +#define RT5665_L_EQ_LPF1_H0 0x03d2 +#define RT5665_R_EQ_LPF1_H0 0x03d3 +#define RT5665_L_EQ_BPF1_A1 0x03d4 +#define RT5665_R_EQ_BPF1_A1 0x03d5 +#define RT5665_L_EQ_BPF1_A2 0x03d6 +#define RT5665_R_EQ_BPF1_A2 0x03d7 +#define RT5665_L_EQ_BPF1_H0 0x03d8 +#define RT5665_R_EQ_BPF1_H0 0x03d9 +#define RT5665_L_EQ_BPF2_A1 0x03da +#define RT5665_R_EQ_BPF2_A1 0x03db +#define RT5665_L_EQ_BPF2_A2 0x03dc +#define RT5665_R_EQ_BPF2_A2 0x03dd +#define RT5665_L_EQ_BPF2_H0 0x03de +#define RT5665_R_EQ_BPF2_H0 0x03df +#define RT5665_L_EQ_BPF3_A1 0x03e0 +#define RT5665_R_EQ_BPF3_A1 0x03e1 +#define RT5665_L_EQ_BPF3_A2 0x03e2 +#define RT5665_R_EQ_BPF3_A2 0x03e3 +#define RT5665_L_EQ_BPF3_H0 0x03e4 +#define RT5665_R_EQ_BPF3_H0 0x03e5 +#define RT5665_L_EQ_BPF4_A1 0x03e6 +#define RT5665_R_EQ_BPF4_A1 0x03e7 +#define RT5665_L_EQ_BPF4_A2 0x03e8 +#define RT5665_R_EQ_BPF4_A2 0x03e9 +#define RT5665_L_EQ_BPF4_H0 0x03ea +#define RT5665_R_EQ_BPF4_H0 0x03eb +#define RT5665_L_EQ_HPF1_A1 0x03ec +#define RT5665_R_EQ_HPF1_A1 0x03ed +#define RT5665_L_EQ_HPF1_H0 0x03ee +#define RT5665_R_EQ_HPF1_H0 0x03ef +#define RT5665_L_EQ_PRE_VOL 0x03f0 +#define RT5665_R_EQ_PRE_VOL 0x03f1 +#define RT5665_L_EQ_POST_VOL 0x03f2 +#define RT5665_R_EQ_POST_VOL 0x03f3 +#define RT5665_SCAN_MODE_CTRL 0x07f0 +#define RT5665_I2C_MODE 0x07fa + + + +/* global definition */ +#define RT5665_L_MUTE (0x1 << 15) +#define RT5665_L_MUTE_SFT 15 +#define RT5665_VOL_L_MUTE (0x1 << 14) +#define RT5665_VOL_L_SFT 14 +#define RT5665_R_MUTE (0x1 << 7) +#define RT5665_R_MUTE_SFT 7 +#define RT5665_VOL_R_MUTE (0x1 << 6) +#define RT5665_VOL_R_SFT 6 +#define RT5665_L_VOL_MASK (0x3f << 8) +#define RT5665_L_VOL_SFT 8 +#define RT5665_R_VOL_MASK (0x3f) +#define RT5665_R_VOL_SFT 0 + +/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ +#define RT5665_G_HP (0xf << 8) +#define RT5665_G_HP_SFT 8 +#define RT5665_G_STO_DA_DMIX (0xf) +#define RT5665_G_STO_DA_SFT 0 + +/* CBJ Control (0x000b) */ +#define RT5665_BST_CBJ_MASK (0xf << 8) +#define RT5665_BST_CBJ_SFT 8 + +/* IN1/IN2 Control (0x000c) */ +#define RT5665_IN1_DF_MASK (0x1 << 15) +#define RT5665_IN1_DF 15 +#define RT5665_BST1_MASK (0x7f << 8) +#define RT5665_BST1_SFT 8 +#define RT5665_IN2_DF_MASK (0x1 << 7) +#define RT5665_IN2_DF 7 +#define RT5665_BST2_MASK (0x7f) +#define RT5665_BST2_SFT 0 + +/* IN3/IN4 Control (0x000d) */ +#define RT5665_IN3_DF_MASK (0x1 << 15) +#define RT5665_IN3_DF 15 +#define RT5665_BST3_MASK (0x7f << 8) +#define RT5665_BST3_SFT 8 +#define RT5665_IN4_DF_MASK (0x1 << 7) +#define RT5665_IN4_DF 7 +#define RT5665_BST4_MASK (0x7f) +#define RT5665_BST4_SFT 0 + +/* INL and INR Volume Control (0x000f) */ +#define RT5665_INL_VOL_MASK (0x1f << 8) +#define RT5665_INL_VOL_SFT 8 +#define RT5665_INR_VOL_MASK (0x1f) +#define RT5665_INR_VOL_SFT 0 + +/* Embeeded Jack and Type Detection Control 1 (0x0010) */ +#define RT5665_EMB_JD_EN (0x1 << 15) +#define RT5665_EMB_JD_EN_SFT 15 +#define RT5665_JD_MODE (0x1 << 13) +#define RT5665_JD_MODE_SFT 13 +#define RT5665_POLA_EXT_JD_MASK (0x1 << 11) +#define RT5665_POLA_EXT_JD_LOW (0x1 << 11) +#define RT5665_POLA_EXT_JD_HIGH (0x0 << 11) +#define RT5665_EXT_JD_DIG (0x1 << 9) +#define RT5665_POL_FAST_OFF_MASK (0x1 << 8) +#define RT5665_POL_FAST_OFF_HIGH (0x1 << 8) +#define RT5665_POL_FAST_OFF_LOW (0x0 << 8) +#define RT5665_VREF_POW_MASK (0x1 << 6) +#define RT5665_VREF_POW_FSM (0x0 << 6) +#define RT5665_VREF_POW_REG (0x1 << 6) +#define RT5665_MB1_PATH_MASK (0x1 << 5) +#define RT5665_CTRL_MB1_REG (0x1 << 5) +#define RT5665_CTRL_MB1_FSM (0x0 << 5) +#define RT5665_MB2_PATH_MASK (0x1 << 4) +#define RT5665_CTRL_MB2_REG (0x1 << 4) +#define RT5665_CTRL_MB2_FSM (0x0 << 4) +#define RT5665_TRIG_JD_MASK (0x1 << 3) +#define RT5665_TRIG_JD_HIGH (0x1 << 3) +#define RT5665_TRIG_JD_LOW (0x0 << 3) + +/* Embeeded Jack and Type Detection Control 2 (0x0011) */ +#define RT5665_EXT_JD_SRC (0x7 << 4) +#define RT5665_EXT_JD_SRC_SFT 4 +#define RT5665_EXT_JD_SRC_GPIO_JD1 (0x0 << 4) +#define RT5665_EXT_JD_SRC_GPIO_JD2 (0x1 << 4) +#define RT5665_EXT_JD_SRC_JD1_1 (0x2 << 4) +#define RT5665_EXT_JD_SRC_JD1_2 (0x3 << 4) +#define RT5665_EXT_JD_SRC_JD2 (0x4 << 4) +#define RT5665_EXT_JD_SRC_JD3 (0x5 << 4) +#define RT5665_EXT_JD_SRC_MANUAL (0x6 << 4) + +/* Combo Jack and Type Detection Control 4 (0x0013) */ +#define RT5665_SEL_SHT_MID_TON_MASK (0x3 << 12) +#define RT5665_SEL_SHT_MID_TON_2 (0x0 << 12) +#define RT5665_SEL_SHT_MID_TON_3 (0x1 << 12) +#define RT5665_CBJ_JD_TEST_MASK (0x1 << 6) +#define RT5665_CBJ_JD_TEST_NORM (0x0 << 6) +#define RT5665_CBJ_JD_TEST_MODE (0x1 << 6) + +/* Slience Detection Control (0x0015) */ +#define RT5665_SIL_DET_MASK (0x1 << 15) +#define RT5665_SIL_DET_DIS (0x0 << 15) +#define RT5665_SIL_DET_EN (0x1 << 15) + +/* DAC2 Control (0x0017) */ +#define RT5665_M_DAC2_L_VOL (0x1 << 13) +#define RT5665_M_DAC2_L_VOL_SFT 13 +#define RT5665_M_DAC2_R_VOL (0x1 << 12) +#define RT5665_M_DAC2_R_VOL_SFT 12 +#define RT5665_DAC_L2_SEL_MASK (0x7 << 4) +#define RT5665_DAC_L2_SEL_SFT 4 +#define RT5665_DAC_R2_SEL_MASK (0x7 << 0) +#define RT5665_DAC_R2_SEL_SFT 0 + +/* Sidetone Control (0x0018) */ +#define RT5665_ST_SEL_MASK (0x7 << 9) +#define RT5665_ST_SEL_SFT 9 +#define RT5665_ST_EN (0x1 << 6) +#define RT5665_ST_EN_SFT 6 + +/* DAC1 Digital Volume (0x0019) */ +#define RT5665_DAC_L1_VOL_MASK (0xff << 8) +#define RT5665_DAC_L1_VOL_SFT 8 +#define RT5665_DAC_R1_VOL_MASK (0xff) +#define RT5665_DAC_R1_VOL_SFT 0 + +/* DAC2 Digital Volume (0x001a) */ +#define RT5665_DAC_L2_VOL_MASK (0xff << 8) +#define RT5665_DAC_L2_VOL_SFT 8 +#define RT5665_DAC_R2_VOL_MASK (0xff) +#define RT5665_DAC_R2_VOL_SFT 0 + +/* DAC3 Control (0x001b) */ +#define RT5665_M_DAC3_L_VOL (0x1 << 13) +#define RT5665_M_DAC3_L_VOL_SFT 13 +#define RT5665_M_DAC3_R_VOL (0x1 << 12) +#define RT5665_M_DAC3_R_VOL_SFT 12 +#define RT5665_DAC_L3_SEL_MASK (0x7 << 4) +#define RT5665_DAC_L3_SEL_SFT 4 +#define RT5665_DAC_R3_SEL_MASK (0x7 << 0) +#define RT5665_DAC_R3_SEL_SFT 0 + +/* ADC Digital Volume Control (0x001c) */ +#define RT5665_ADC_L_VOL_MASK (0x7f << 8) +#define RT5665_ADC_L_VOL_SFT 8 +#define RT5665_ADC_R_VOL_MASK (0x7f) +#define RT5665_ADC_R_VOL_SFT 0 + +/* Mono ADC Digital Volume Control (0x001d) */ +#define RT5665_MONO_ADC_L_VOL_MASK (0x7f << 8) +#define RT5665_MONO_ADC_L_VOL_SFT 8 +#define RT5665_MONO_ADC_R_VOL_MASK (0x7f) +#define RT5665_MONO_ADC_R_VOL_SFT 0 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5665_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5665_STO1_ADC_L_BST_SFT 14 +#define RT5665_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5665_STO1_ADC_R_BST_SFT 12 + +/* Mono ADC Boost Gain Control (0x0020) */ +#define RT5665_MONO_ADC_L_BST_MASK (0x3 << 14) +#define RT5665_MONO_ADC_L_BST_SFT 14 +#define RT5665_MONO_ADC_R_BST_MASK (0x3 << 12) +#define RT5665_MONO_ADC_R_BST_SFT 12 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5665_STO2_ADC_L_BST_MASK (0x3 << 14) +#define RT5665_STO2_ADC_L_BST_SFT 14 +#define RT5665_STO2_ADC_R_BST_MASK (0x3 << 12) +#define RT5665_STO2_ADC_R_BST_SFT 12 + +/* Stereo1 ADC Mixer Control (0x0026) */ +#define RT5665_M_STO1_ADC_L1 (0x1 << 15) +#define RT5665_M_STO1_ADC_L1_SFT 15 +#define RT5665_M_STO1_ADC_L2 (0x1 << 14) +#define RT5665_M_STO1_ADC_L2_SFT 14 +#define RT5665_STO1_ADC1L_SRC_MASK (0x1 << 13) +#define RT5665_STO1_ADC1L_SRC_SFT 13 +#define RT5665_STO1_ADC1_SRC_ADC (0x1 << 13) +#define RT5665_STO1_ADC1_SRC_DACMIX (0x0 << 13) +#define RT5665_STO1_ADC2L_SRC_MASK (0x1 << 12) +#define RT5665_STO1_ADC2L_SRC_SFT 12 +#define RT5665_STO1_ADCL_SRC_MASK (0x3 << 10) +#define RT5665_STO1_ADCL_SRC_SFT 10 +#define RT5665_STO1_DD_L_SRC_MASK (0x1 << 9) +#define RT5665_STO1_DD_L_SRC_SFT 9 +#define RT5665_STO1_DMIC_SRC_MASK (0x1 << 8) +#define RT5665_STO1_DMIC_SRC_SFT 8 +#define RT5665_STO1_DMIC_SRC_DMIC2 (0x1 << 8) +#define RT5665_STO1_DMIC_SRC_DMIC1 (0x0 << 8) +#define RT5665_M_STO1_ADC_R1 (0x1 << 7) +#define RT5665_M_STO1_ADC_R1_SFT 7 +#define RT5665_M_STO1_ADC_R2 (0x1 << 6) +#define RT5665_M_STO1_ADC_R2_SFT 6 +#define RT5665_STO1_ADC1R_SRC_MASK (0x1 << 5) +#define RT5665_STO1_ADC1R_SRC_SFT 5 +#define RT5665_STO1_ADC2R_SRC_MASK (0x1 << 4) +#define RT5665_STO1_ADC2R_SRC_SFT 4 +#define RT5665_STO1_ADCR_SRC_MASK (0x3 << 2) +#define RT5665_STO1_ADCR_SRC_SFT 2 +#define RT5665_STO1_DD_R_SRC_MASK (0x3) +#define RT5665_STO1_DD_R_SRC_SFT 0 + + +/* Mono1 ADC Mixer control (0x0027) */ +#define RT5665_M_MONO_ADC_L1 (0x1 << 15) +#define RT5665_M_MONO_ADC_L1_SFT 15 +#define RT5665_M_MONO_ADC_L2 (0x1 << 14) +#define RT5665_M_MONO_ADC_L2_SFT 14 +#define RT5665_MONO_ADC_L1_SRC_MASK (0x1 << 13) +#define RT5665_MONO_ADC_L1_SRC_SFT 13 +#define RT5665_MONO_ADC_L2_SRC_MASK (0x1 << 12) +#define RT5665_MONO_ADC_L2_SRC_SFT 12 +#define RT5665_MONO_ADC_L_SRC_MASK (0x3 << 10) +#define RT5665_MONO_ADC_L_SRC_SFT 10 +#define RT5665_MONO_DD_L_SRC_MASK (0x1 << 9) +#define RT5665_MONO_DD_L_SRC_SFT 9 +#define RT5665_MONO_DMIC_L_SRC_MASK (0x1 << 8) +#define RT5665_MONO_DMIC_L_SRC_SFT 8 +#define RT5665_M_MONO_ADC_R1 (0x1 << 7) +#define RT5665_M_MONO_ADC_R1_SFT 7 +#define RT5665_M_MONO_ADC_R2 (0x1 << 6) +#define RT5665_M_MONO_ADC_R2_SFT 6 +#define RT5665_MONO_ADC_R1_SRC_MASK (0x1 << 5) +#define RT5665_MONO_ADC_R1_SRC_SFT 5 +#define RT5665_MONO_ADC_R2_SRC_MASK (0x1 << 4) +#define RT5665_MONO_ADC_R2_SRC_SFT 4 +#define RT5665_MONO_ADC_R_SRC_MASK (0x3 << 2) +#define RT5665_MONO_ADC_R_SRC_SFT 2 +#define RT5665_MONO_DD_R_SRC_MASK (0x1 << 1) +#define RT5665_MONO_DD_R_SRC_SFT 1 +#define RT5665_MONO_DMIC_R_SRC_MASK 0x1 +#define RT5665_MONO_DMIC_R_SRC_SFT 0 + +/* Stereo2 ADC Mixer Control (0x0028) */ +#define RT5665_M_STO2_ADC_L1 (0x1 << 15) +#define RT5665_M_STO2_ADC_L1_UN (0x0 << 15) +#define RT5665_M_STO2_ADC_L1_SFT 15 +#define RT5665_M_STO2_ADC_L2 (0x1 << 14) +#define RT5665_M_STO2_ADC_L2_SFT 14 +#define RT5665_STO2_ADC1L_SRC_MASK (0x1 << 13) +#define RT5665_STO2_ADC1L_SRC_SFT 13 +#define RT5665_STO2_ADC1_SRC_ADC (0x1 << 13) +#define RT5665_STO2_ADC1_SRC_DACMIX (0x0 << 13) +#define RT5665_STO2_ADC2L_SRC_MASK (0x1 << 12) +#define RT5665_STO2_ADC2L_SRC_SFT 12 +#define RT5665_STO2_ADCL_SRC_MASK (0x3 << 10) +#define RT5665_STO2_ADCL_SRC_SFT 10 +#define RT5665_STO2_DD_L_SRC_MASK (0x1 << 9) +#define RT5665_STO2_DD_L_SRC_SFT 9 +#define RT5665_STO2_DMIC_SRC_MASK (0x1 << 8) +#define RT5665_STO2_DMIC_SRC_SFT 8 +#define RT5665_STO2_DMIC_SRC_DMIC2 (0x1 << 8) +#define RT5665_STO2_DMIC_SRC_DMIC1 (0x0 << 8) +#define RT5665_M_STO2_ADC_R1 (0x1 << 7) +#define RT5665_M_STO2_ADC_R1_UN (0x0 << 7) +#define RT5665_M_STO2_ADC_R1_SFT 7 +#define RT5665_M_STO2_ADC_R2 (0x1 << 6) +#define RT5665_M_STO2_ADC_R2_SFT 6 +#define RT5665_STO2_ADC1R_SRC_MASK (0x1 << 5) +#define RT5665_STO2_ADC1R_SRC_SFT 5 +#define RT5665_STO2_ADC2R_SRC_MASK (0x1 << 4) +#define RT5665_STO2_ADC2R_SRC_SFT 4 +#define RT5665_STO2_ADCR_SRC_MASK (0x3 << 2) +#define RT5665_STO2_ADCR_SRC_SFT 2 +#define RT5665_STO2_DD_R_SRC_MASK (0x1 << 1) +#define RT5665_STO2_DD_R_SRC_SFT 1 + +/* ADC Mixer to DAC Mixer Control (0x0029) */ +#define RT5665_M_ADCMIX_L (0x1 << 15) +#define RT5665_M_ADCMIX_L_SFT 15 +#define RT5665_M_DAC1_L (0x1 << 14) +#define RT5665_M_DAC1_L_SFT 14 +#define RT5665_DAC1_R_SEL_MASK (0x3 << 10) +#define RT5665_DAC1_R_SEL_SFT 10 +#define RT5665_DAC1_L_SEL_MASK (0x3 << 8) +#define RT5665_DAC1_L_SEL_SFT 8 +#define RT5665_M_ADCMIX_R (0x1 << 7) +#define RT5665_M_ADCMIX_R_SFT 7 +#define RT5665_M_DAC1_R (0x1 << 6) +#define RT5665_M_DAC1_R_SFT 6 + +/* Stereo1 DAC Mixer Control (0x002a) */ +#define RT5665_M_DAC_L1_STO_L (0x1 << 15) +#define RT5665_M_DAC_L1_STO_L_SFT 15 +#define RT5665_G_DAC_L1_STO_L_MASK (0x1 << 14) +#define RT5665_G_DAC_L1_STO_L_SFT 14 +#define RT5665_M_DAC_R1_STO_L (0x1 << 13) +#define RT5665_M_DAC_R1_STO_L_SFT 13 +#define RT5665_G_DAC_R1_STO_L_MASK (0x1 << 12) +#define RT5665_G_DAC_R1_STO_L_SFT 12 +#define RT5665_M_DAC_L2_STO_L (0x1 << 11) +#define RT5665_M_DAC_L2_STO_L_SFT 11 +#define RT5665_G_DAC_L2_STO_L_MASK (0x1 << 10) +#define RT5665_G_DAC_L2_STO_L_SFT 10 +#define RT5665_M_DAC_R2_STO_L (0x1 << 9) +#define RT5665_M_DAC_R2_STO_L_SFT 9 +#define RT5665_G_DAC_R2_STO_L_MASK (0x1 << 8) +#define RT5665_G_DAC_R2_STO_L_SFT 8 +#define RT5665_M_DAC_L1_STO_R (0x1 << 7) +#define RT5665_M_DAC_L1_STO_R_SFT 7 +#define RT5665_G_DAC_L1_STO_R_MASK (0x1 << 6) +#define RT5665_G_DAC_L1_STO_R_SFT 6 +#define RT5665_M_DAC_R1_STO_R (0x1 << 5) +#define RT5665_M_DAC_R1_STO_R_SFT 5 +#define RT5665_G_DAC_R1_STO_R_MASK (0x1 << 4) +#define RT5665_G_DAC_R1_STO_R_SFT 4 +#define RT5665_M_DAC_L2_STO_R (0x1 << 3) +#define RT5665_M_DAC_L2_STO_R_SFT 3 +#define RT5665_G_DAC_L2_STO_R_MASK (0x1 << 2) +#define RT5665_G_DAC_L2_STO_R_SFT 2 +#define RT5665_M_DAC_R2_STO_R (0x1 << 1) +#define RT5665_M_DAC_R2_STO_R_SFT 1 +#define RT5665_G_DAC_R2_STO_R_MASK (0x1) +#define RT5665_G_DAC_R2_STO_R_SFT 0 + +/* Mono DAC Mixer Control (0x002b) */ +#define RT5665_M_DAC_L1_MONO_L (0x1 << 15) +#define RT5665_M_DAC_L1_MONO_L_SFT 15 +#define RT5665_G_DAC_L1_MONO_L_MASK (0x1 << 14) +#define RT5665_G_DAC_L1_MONO_L_SFT 14 +#define RT5665_M_DAC_R1_MONO_L (0x1 << 13) +#define RT5665_M_DAC_R1_MONO_L_SFT 13 +#define RT5665_G_DAC_R1_MONO_L_MASK (0x1 << 12) +#define RT5665_G_DAC_R1_MONO_L_SFT 12 +#define RT5665_M_DAC_L2_MONO_L (0x1 << 11) +#define RT5665_M_DAC_L2_MONO_L_SFT 11 +#define RT5665_G_DAC_L2_MONO_L_MASK (0x1 << 10) +#define RT5665_G_DAC_L2_MONO_L_SFT 10 +#define RT5665_M_DAC_R2_MONO_L (0x1 << 9) +#define RT5665_M_DAC_R2_MONO_L_SFT 9 +#define RT5665_G_DAC_R2_MONO_L_MASK (0x1 << 8) +#define RT5665_G_DAC_R2_MONO_L_SFT 8 +#define RT5665_M_DAC_L1_MONO_R (0x1 << 7) +#define RT5665_M_DAC_L1_MONO_R_SFT 7 +#define RT5665_G_DAC_L1_MONO_R_MASK (0x1 << 6) +#define RT5665_G_DAC_L1_MONO_R_SFT 6 +#define RT5665_M_DAC_R1_MONO_R (0x1 << 5) +#define RT5665_M_DAC_R1_MONO_R_SFT 5 +#define RT5665_G_DAC_R1_MONO_R_MASK (0x1 << 4) +#define RT5665_G_DAC_R1_MONO_R_SFT 4 +#define RT5665_M_DAC_L2_MONO_R (0x1 << 3) +#define RT5665_M_DAC_L2_MONO_R_SFT 3 +#define RT5665_G_DAC_L2_MONO_R_MASK (0x1 << 2) +#define RT5665_G_DAC_L2_MONO_R_SFT 2 +#define RT5665_M_DAC_R2_MONO_R (0x1 << 1) +#define RT5665_M_DAC_R2_MONO_R_SFT 1 +#define RT5665_G_DAC_R2_MONO_R_MASK (0x1) +#define RT5665_G_DAC_R2_MONO_R_SFT 0 + +/* Stereo2 DAC Mixer Control (0x002c) */ +#define RT5665_M_DAC_L1_STO2_L (0x1 << 15) +#define RT5665_M_DAC_L1_STO2_L_SFT 15 +#define RT5665_G_DAC_L1_STO2_L_MASK (0x1 << 14) +#define RT5665_G_DAC_L1_STO2_L_SFT 14 +#define RT5665_M_DAC_L2_STO2_L (0x1 << 13) +#define RT5665_M_DAC_L2_STO2_L_SFT 13 +#define RT5665_G_DAC_L2_STO2_L_MASK (0x1 << 12) +#define RT5665_G_DAC_L2_STO2_L_SFT 12 +#define RT5665_M_DAC_L3_STO2_L (0x1 << 11) +#define RT5665_M_DAC_L3_STO2_L_SFT 11 +#define RT5665_G_DAC_L3_STO2_L_MASK (0x1 << 10) +#define RT5665_G_DAC_L3_STO2_L_SFT 10 +#define RT5665_M_ST_DAC_L1 (0x1 << 9) +#define RT5665_M_ST_DAC_L1_SFT 9 +#define RT5665_M_ST_DAC_R1 (0x1 << 8) +#define RT5665_M_ST_DAC_R1_SFT 8 +#define RT5665_M_DAC_R1_STO2_R (0x1 << 7) +#define RT5665_M_DAC_R1_STO2_R_SFT 7 +#define RT5665_G_DAC_R1_STO2_R_MASK (0x1 << 6) +#define RT5665_G_DAC_R1_STO2_R_SFT 6 +#define RT5665_M_DAC_R2_STO2_R (0x1 << 5) +#define RT5665_M_DAC_R2_STO2_R_SFT 5 +#define RT5665_G_DAC_R2_STO2_R_MASK (0x1 << 4) +#define RT5665_G_DAC_R2_STO2_R_SFT 4 +#define RT5665_M_DAC_R3_STO2_R (0x1 << 3) +#define RT5665_M_DAC_R3_STO2_R_SFT 3 +#define RT5665_G_DAC_R3_STO2_R_MASK (0x1 << 2) +#define RT5665_G_DAC_R3_STO2_R_SFT 2 + +/* Analog DAC1 Input Source Control (0x002d) */ +#define RT5665_DAC_MIX_L_MASK (0x3 << 12) +#define RT5665_DAC_MIX_L_SFT 12 +#define RT5665_DAC_MIX_R_MASK (0x3 << 8) +#define RT5665_DAC_MIX_R_SFT 8 +#define RT5665_DAC_L1_SRC_MASK (0x3 << 4) +#define RT5665_A_DACL1_SFT 4 +#define RT5665_DAC_R1_SRC_MASK (0x3) +#define RT5665_A_DACR1_SFT 0 + +/* Analog DAC Input Source Control (0x002e) */ +#define RT5665_A_DACL2_SEL (0x1 << 4) +#define RT5665_A_DACL2_SFT 4 +#define RT5665_A_DACR2_SEL (0x1 << 0) +#define RT5665_A_DACR2_SFT 0 + +/* Digital Interface Data Control (0x002f) */ +#define RT5665_IF2_1_ADC_IN_MASK (0x7 << 12) +#define RT5665_IF2_1_ADC_IN_SFT 12 +#define RT5665_IF2_1_DAC_SEL_MASK (0x3 << 10) +#define RT5665_IF2_1_DAC_SEL_SFT 10 +#define RT5665_IF2_1_ADC_SEL_MASK (0x3 << 8) +#define RT5665_IF2_1_ADC_SEL_SFT 8 +#define RT5665_IF2_2_ADC_IN_MASK (0x7 << 4) +#define RT5665_IF2_2_ADC_IN_SFT 4 +#define RT5665_IF2_2_DAC_SEL_MASK (0x3 << 2) +#define RT5665_IF2_2_DAC_SEL_SFT 2 +#define RT5665_IF2_2_ADC_SEL_MASK (0x3 << 0) +#define RT5665_IF2_2_ADC_SEL_SFT 0 + +/* Digital Interface Data Control (0x0030) */ +#define RT5665_IF3_ADC_IN_MASK (0x7 << 4) +#define RT5665_IF3_ADC_IN_SFT 4 +#define RT5665_IF3_DAC_SEL_MASK (0x3 << 2) +#define RT5665_IF3_DAC_SEL_SFT 2 +#define RT5665_IF3_ADC_SEL_MASK (0x3 << 0) +#define RT5665_IF3_ADC_SEL_SFT 0 + +/* PDM Output Control (0x0031) */ +#define RT5665_M_PDM1_L (0x1 << 14) +#define RT5665_M_PDM1_L_SFT 14 +#define RT5665_M_PDM1_R (0x1 << 12) +#define RT5665_M_PDM1_R_SFT 12 +#define RT5665_PDM1_L_MASK (0x3 << 10) +#define RT5665_PDM1_L_SFT 10 +#define RT5665_PDM1_R_MASK (0x3 << 8) +#define RT5665_PDM1_R_SFT 8 +#define RT5665_PDM1_BUSY (0x1 << 6) +#define RT5665_PDM_PATTERN (0x1 << 5) +#define RT5665_PDM_GAIN (0x1 << 4) +#define RT5665_LRCK_PDM_PI2C (0x1 << 3) +#define RT5665_PDM_DIV_MASK (0x3) + +/*S/PDIF Output Control (0x0036) */ +#define RT5665_SPDIF_SEL_MASK (0x3 << 0) +#define RT5665_SPDIF_SEL_SFT 0 + +/* REC Left Mixer Control 2 (0x003c) */ +#define RT5665_M_CBJ_RM1_L (0x1 << 7) +#define RT5665_M_CBJ_RM1_L_SFT 7 +#define RT5665_M_BST1_RM1_L (0x1 << 5) +#define RT5665_M_BST1_RM1_L_SFT 5 +#define RT5665_M_BST2_RM1_L (0x1 << 4) +#define RT5665_M_BST2_RM1_L_SFT 4 +#define RT5665_M_BST3_RM1_L (0x1 << 3) +#define RT5665_M_BST3_RM1_L_SFT 3 +#define RT5665_M_BST4_RM1_L (0x1 << 2) +#define RT5665_M_BST4_RM1_L_SFT 2 +#define RT5665_M_INL_RM1_L (0x1 << 1) +#define RT5665_M_INL_RM1_L_SFT 1 +#define RT5665_M_INR_RM1_L (0x1) +#define RT5665_M_INR_RM1_L_SFT 0 + +/* REC Right Mixer Control 2 (0x003e) */ +#define RT5665_M_AEC_REF_RM1_R (0x1 << 7) +#define RT5665_M_AEC_REF_RM1_R_SFT 7 +#define RT5665_M_BST1_RM1_R (0x1 << 5) +#define RT5665_M_BST1_RM1_R_SFT 5 +#define RT5665_M_BST2_RM1_R (0x1 << 4) +#define RT5665_M_BST2_RM1_R_SFT 4 +#define RT5665_M_BST3_RM1_R (0x1 << 3) +#define RT5665_M_BST3_RM1_R_SFT 3 +#define RT5665_M_BST4_RM1_R (0x1 << 2) +#define RT5665_M_BST4_RM1_R_SFT 2 +#define RT5665_M_INR_RM1_R (0x1 << 1) +#define RT5665_M_INR_RM1_R_SFT 1 +#define RT5665_M_MONOVOL_RM1_R (0x1) +#define RT5665_M_MONOVOL_RM1_R_SFT 0 + +/* REC Mixer 2 Left Control 2 (0x0041) */ +#define RT5665_M_CBJ_RM2_L (0x1 << 7) +#define RT5665_M_CBJ_RM2_L_SFT 7 +#define RT5665_M_BST1_RM2_L (0x1 << 5) +#define RT5665_M_BST1_RM2_L_SFT 5 +#define RT5665_M_BST2_RM2_L (0x1 << 4) +#define RT5665_M_BST2_RM2_L_SFT 4 +#define RT5665_M_BST3_RM2_L (0x1 << 3) +#define RT5665_M_BST3_RM2_L_SFT 3 +#define RT5665_M_BST4_RM2_L (0x1 << 2) +#define RT5665_M_BST4_RM2_L_SFT 2 +#define RT5665_M_INL_RM2_L (0x1 << 1) +#define RT5665_M_INL_RM2_L_SFT 1 +#define RT5665_M_INR_RM2_L (0x1) +#define RT5665_M_INR_RM2_L_SFT 0 + +/* REC Mixer 2 Right Control 2 (0x0043) */ +#define RT5665_M_MONOVOL_RM2_R (0x1 << 7) +#define RT5665_M_MONOVOL_RM2_R_SFT 7 +#define RT5665_M_BST1_RM2_R (0x1 << 5) +#define RT5665_M_BST1_RM2_R_SFT 5 +#define RT5665_M_BST2_RM2_R (0x1 << 4) +#define RT5665_M_BST2_RM2_R_SFT 4 +#define RT5665_M_BST3_RM2_R (0x1 << 3) +#define RT5665_M_BST3_RM2_R_SFT 3 +#define RT5665_M_BST4_RM2_R (0x1 << 2) +#define RT5665_M_BST4_RM2_R_SFT 2 +#define RT5665_M_INL_RM2_R (0x1 << 1) +#define RT5665_M_INL_RM2_R_SFT 1 +#define RT5665_M_INR_RM2_R (0x1) +#define RT5665_M_INR_RM2_R_SFT 0 + +/* SPK Left Mixer Control (0x0046) */ +#define RT5665_M_BST3_SM_L (0x1 << 4) +#define RT5665_M_BST3_SM_L_SFT 4 +#define RT5665_M_IN_R_SM_L (0x1 << 3) +#define RT5665_M_IN_R_SM_L_SFT 3 +#define RT5665_M_IN_L_SM_L (0x1 << 2) +#define RT5665_M_IN_L_SM_L_SFT 2 +#define RT5665_M_BST1_SM_L (0x1 << 1) +#define RT5665_M_BST1_SM_L_SFT 1 +#define RT5665_M_DAC_L2_SM_L (0x1) +#define RT5665_M_DAC_L2_SM_L_SFT 0 + +/* SPK Right Mixer Control (0x0047) */ +#define RT5665_M_BST3_SM_R (0x1 << 4) +#define RT5665_M_BST3_SM_R_SFT 4 +#define RT5665_M_IN_R_SM_R (0x1 << 3) +#define RT5665_M_IN_R_SM_R_SFT 3 +#define RT5665_M_IN_L_SM_R (0x1 << 2) +#define RT5665_M_IN_L_SM_R_SFT 2 +#define RT5665_M_BST4_SM_R (0x1 << 1) +#define RT5665_M_BST4_SM_R_SFT 1 +#define RT5665_M_DAC_R2_SM_R (0x1) +#define RT5665_M_DAC_R2_SM_R_SFT 0 + +/* SPO Amp Input and Gain Control (0x0048) */ +#define RT5665_M_DAC_L2_SPKOMIX (0x1 << 13) +#define RT5665_M_DAC_L2_SPKOMIX_SFT 13 +#define RT5665_M_SPKVOLL_SPKOMIX (0x1 << 12) +#define RT5665_M_SPKVOLL_SPKOMIX_SFT 12 +#define RT5665_M_DAC_R2_SPKOMIX (0x1 << 9) +#define RT5665_M_DAC_R2_SPKOMIX_SFT 9 +#define RT5665_M_SPKVOLR_SPKOMIX (0x1 << 8) +#define RT5665_M_SPKVOLR_SPKOMIX_SFT 8 + +/* MONOMIX Input and Gain Control (0x004b) */ +#define RT5665_G_MONOVOL_MA (0x1 << 10) +#define RT5665_G_MONOVOL_MA_SFT 10 +#define RT5665_M_MONOVOL_MA (0x1 << 9) +#define RT5665_M_MONOVOL_MA_SFT 9 +#define RT5665_M_DAC_L2_MA (0x1 << 8) +#define RT5665_M_DAC_L2_MA_SFT 8 +#define RT5665_M_BST3_MM (0x1 << 4) +#define RT5665_M_BST3_MM_SFT 4 +#define RT5665_M_BST2_MM (0x1 << 3) +#define RT5665_M_BST2_MM_SFT 3 +#define RT5665_M_BST1_MM (0x1 << 2) +#define RT5665_M_BST1_MM_SFT 2 +#define RT5665_M_RECMIC2L_MM (0x1 << 1) +#define RT5665_M_RECMIC2L_MM_SFT 1 +#define RT5665_M_DAC_L2_MM (0x1) +#define RT5665_M_DAC_L2_MM_SFT 0 + +/* Output Left Mixer Control 1 (0x004d) */ +#define RT5665_G_BST3_OM_L_MASK (0x7 << 12) +#define RT5665_G_BST3_OM_L_SFT 12 +#define RT5665_G_BST2_OM_L_MASK (0x7 << 9) +#define RT5665_G_BST2_OM_L_SFT 9 +#define RT5665_G_BST1_OM_L_MASK (0x7 << 6) +#define RT5665_G_BST1_OM_L_SFT 6 +#define RT5665_G_IN_L_OM_L_MASK (0x7 << 3) +#define RT5665_G_IN_L_OM_L_SFT 3 +#define RT5665_G_DAC_L2_OM_L_MASK (0x7 << 0) +#define RT5665_G_DAC_L2_OM_L_SFT 0 + +/* Output Left Mixer Input Control (0x004e) */ +#define RT5665_M_BST3_OM_L (0x1 << 4) +#define RT5665_M_BST3_OM_L_SFT 4 +#define RT5665_M_BST2_OM_L (0x1 << 3) +#define RT5665_M_BST2_OM_L_SFT 3 +#define RT5665_M_BST1_OM_L (0x1 << 2) +#define RT5665_M_BST1_OM_L_SFT 2 +#define RT5665_M_IN_L_OM_L (0x1 << 1) +#define RT5665_M_IN_L_OM_L_SFT 1 +#define RT5665_M_DAC_L2_OM_L (0x1) +#define RT5665_M_DAC_L2_OM_L_SFT 0 + +/* Output Right Mixer Input Control (0x0050) */ +#define RT5665_M_BST4_OM_R (0x1 << 4) +#define RT5665_M_BST4_OM_R_SFT 4 +#define RT5665_M_BST3_OM_R (0x1 << 3) +#define RT5665_M_BST3_OM_R_SFT 3 +#define RT5665_M_BST2_OM_R (0x1 << 2) +#define RT5665_M_BST2_OM_R_SFT 2 +#define RT5665_M_IN_R_OM_R (0x1 << 1) +#define RT5665_M_IN_R_OM_R_SFT 1 +#define RT5665_M_DAC_R2_OM_R (0x1) +#define RT5665_M_DAC_R2_OM_R_SFT 0 + +/* LOUT Mixer Control (0x0052) */ +#define RT5665_M_DAC_L2_LM (0x1 << 15) +#define RT5665_M_DAC_L2_LM_SFT 15 +#define RT5665_M_DAC_R2_LM (0x1 << 14) +#define RT5665_M_DAC_R2_LM_SFT 14 +#define RT5665_M_OV_L_LM (0x1 << 13) +#define RT5665_M_OV_L_LM_SFT 13 +#define RT5665_M_OV_R_LM (0x1 << 12) +#define RT5665_M_OV_R_LM_SFT 12 +#define RT5665_LOUT_BST_SFT 11 +#define RT5665_LOUT_DF (0x1 << 11) +#define RT5665_LOUT_DF_SFT 11 + +/* Power Management for Digital 1 (0x0061) */ +#define RT5665_PWR_I2S1_1 (0x1 << 15) +#define RT5665_PWR_I2S1_1_BIT 15 +#define RT5665_PWR_I2S1_2 (0x1 << 14) +#define RT5665_PWR_I2S1_2_BIT 14 +#define RT5665_PWR_I2S2_1 (0x1 << 13) +#define RT5665_PWR_I2S2_1_BIT 13 +#define RT5665_PWR_I2S2_2 (0x1 << 12) +#define RT5665_PWR_I2S2_2_BIT 12 +#define RT5665_PWR_DAC_L1 (0x1 << 11) +#define RT5665_PWR_DAC_L1_BIT 11 +#define RT5665_PWR_DAC_R1 (0x1 << 10) +#define RT5665_PWR_DAC_R1_BIT 10 +#define RT5665_PWR_I2S3 (0x1 << 9) +#define RT5665_PWR_I2S3_BIT 9 +#define RT5665_PWR_LDO (0x1 << 8) +#define RT5665_PWR_LDO_BIT 8 +#define RT5665_PWR_DAC_L2 (0x1 << 7) +#define RT5665_PWR_DAC_L2_BIT 7 +#define RT5665_PWR_DAC_R2 (0x1 << 6) +#define RT5665_PWR_DAC_R2_BIT 6 +#define RT5665_PWR_ADC_L1 (0x1 << 4) +#define RT5665_PWR_ADC_L1_BIT 4 +#define RT5665_PWR_ADC_R1 (0x1 << 3) +#define RT5665_PWR_ADC_R1_BIT 3 +#define RT5665_PWR_ADC_L2 (0x1 << 2) +#define RT5665_PWR_ADC_L2_BIT 2 +#define RT5665_PWR_ADC_R2 (0x1 << 1) +#define RT5665_PWR_ADC_R2_BIT 1 + +/* Power Management for Digital 2 (0x0062) */ +#define RT5665_PWR_ADC_S1F (0x1 << 15) +#define RT5665_PWR_ADC_S1F_BIT 15 +#define RT5665_PWR_ADC_S2F (0x1 << 14) +#define RT5665_PWR_ADC_S2F_BIT 14 +#define RT5665_PWR_ADC_MF_L (0x1 << 13) +#define RT5665_PWR_ADC_MF_L_BIT 13 +#define RT5665_PWR_ADC_MF_R (0x1 << 12) +#define RT5665_PWR_ADC_MF_R_BIT 12 +#define RT5665_PWR_DAC_S2F (0x1 << 11) +#define RT5665_PWR_DAC_S2F_BIT 11 +#define RT5665_PWR_DAC_S1F (0x1 << 10) +#define RT5665_PWR_DAC_S1F_BIT 10 +#define RT5665_PWR_DAC_MF_L (0x1 << 9) +#define RT5665_PWR_DAC_MF_L_BIT 9 +#define RT5665_PWR_DAC_MF_R (0x1 << 8) +#define RT5665_PWR_DAC_MF_R_BIT 8 +#define RT5665_PWR_PDM1 (0x1 << 7) +#define RT5665_PWR_PDM1_BIT 7 + +/* Power Management for Analog 1 (0x0063) */ +#define RT5665_PWR_VREF1 (0x1 << 15) +#define RT5665_PWR_VREF1_BIT 15 +#define RT5665_PWR_FV1 (0x1 << 14) +#define RT5665_PWR_FV1_BIT 14 +#define RT5665_PWR_VREF2 (0x1 << 13) +#define RT5665_PWR_VREF2_BIT 13 +#define RT5665_PWR_FV2 (0x1 << 12) +#define RT5665_PWR_FV2_BIT 12 +#define RT5665_PWR_VREF3 (0x1 << 11) +#define RT5665_PWR_VREF3_BIT 11 +#define RT5665_PWR_FV3 (0x1 << 10) +#define RT5665_PWR_FV3_BIT 10 +#define RT5665_PWR_MB (0x1 << 9) +#define RT5665_PWR_MB_BIT 9 +#define RT5665_PWR_LM (0x1 << 8) +#define RT5665_PWR_LM_BIT 8 +#define RT5665_PWR_BG (0x1 << 7) +#define RT5665_PWR_BG_BIT 7 +#define RT5665_PWR_MA (0x1 << 6) +#define RT5665_PWR_MA_BIT 6 +#define RT5665_PWR_HA_L (0x1 << 5) +#define RT5665_PWR_HA_L_BIT 5 +#define RT5665_PWR_HA_R (0x1 << 4) +#define RT5665_PWR_HA_R_BIT 4 +#define RT5665_HP_DRIVER_MASK (0x3 << 2) +#define RT5665_HP_DRIVER_1X (0x0 << 2) +#define RT5665_HP_DRIVER_3X (0x1 << 2) +#define RT5665_HP_DRIVER_5X (0x2 << 2) +#define RT5665_LDO1_DVO_MASK (0x3) +#define RT5665_LDO1_DVO_09 (0x0) +#define RT5665_LDO1_DVO_10 (0x1) +#define RT5665_LDO1_DVO_12 (0x2) +#define RT5665_LDO1_DVO_14 (0x3) + +/* Power Management for Analog 2 (0x0064) */ +#define RT5665_PWR_BST1 (0x1 << 15) +#define RT5665_PWR_BST1_BIT 15 +#define RT5665_PWR_BST2 (0x1 << 14) +#define RT5665_PWR_BST2_BIT 14 +#define RT5665_PWR_BST3 (0x1 << 13) +#define RT5665_PWR_BST3_BIT 13 +#define RT5665_PWR_BST4 (0x1 << 12) +#define RT5665_PWR_BST4_BIT 12 +#define RT5665_PWR_MB1 (0x1 << 11) +#define RT5665_PWR_MB1_PWR_DOWN (0x0 << 11) +#define RT5665_PWR_MB1_BIT 11 +#define RT5665_PWR_MB2 (0x1 << 10) +#define RT5665_PWR_MB2_PWR_DOWN (0x0 << 10) +#define RT5665_PWR_MB2_BIT 10 +#define RT5665_PWR_MB3 (0x1 << 9) +#define RT5665_PWR_MB3_BIT 9 +#define RT5665_PWR_BST1_P (0x1 << 7) +#define RT5665_PWR_BST1_P_BIT 7 +#define RT5665_PWR_BST2_P (0x1 << 6) +#define RT5665_PWR_BST2_P_BIT 6 +#define RT5665_PWR_BST3_P (0x1 << 5) +#define RT5665_PWR_BST3_P_BIT 5 +#define RT5665_PWR_BST4_P (0x1 << 4) +#define RT5665_PWR_BST4_P_BIT 4 +#define RT5665_PWR_JD1 (0x1 << 3) +#define RT5665_PWR_JD1_BIT 3 +#define RT5665_PWR_JD2 (0x1 << 2) +#define RT5665_PWR_JD2_BIT 2 +#define RT5665_PWR_RM1_L (0x1 << 1) +#define RT5665_PWR_RM1_L_BIT 1 +#define RT5665_PWR_RM1_R (0x1) +#define RT5665_PWR_RM1_R_BIT 0 + +/* Power Management for Analog 3 (0x0065) */ +#define RT5665_PWR_CBJ (0x1 << 9) +#define RT5665_PWR_CBJ_BIT 9 +#define RT5665_PWR_BST_L (0x1 << 8) +#define RT5665_PWR_BST_L_BIT 8 +#define RT5665_PWR_BST_R (0x1 << 7) +#define RT5665_PWR_BST_R_BIT 7 +#define RT5665_PWR_PLL (0x1 << 6) +#define RT5665_PWR_PLL_BIT 6 +#define RT5665_PWR_LDO2 (0x1 << 2) +#define RT5665_PWR_LDO2_BIT 2 +#define RT5665_PWR_SVD (0x1 << 1) +#define RT5665_PWR_SVD_BIT 1 + +/* Power Management for Mixer (0x0066) */ +#define RT5665_PWR_RM2_L (0x1 << 15) +#define RT5665_PWR_RM2_L_BIT 15 +#define RT5665_PWR_RM2_R (0x1 << 14) +#define RT5665_PWR_RM2_R_BIT 14 +#define RT5665_PWR_OM_L (0x1 << 13) +#define RT5665_PWR_OM_L_BIT 13 +#define RT5665_PWR_OM_R (0x1 << 12) +#define RT5665_PWR_OM_R_BIT 12 +#define RT5665_PWR_MM (0x1 << 11) +#define RT5665_PWR_MM_BIT 11 +#define RT5665_PWR_AEC_REF (0x1 << 6) +#define RT5665_PWR_AEC_REF_BIT 6 +#define RT5665_PWR_STO1_DAC_L (0x1 << 5) +#define RT5665_PWR_STO1_DAC_L_BIT 5 +#define RT5665_PWR_STO1_DAC_R (0x1 << 4) +#define RT5665_PWR_STO1_DAC_R_BIT 4 +#define RT5665_PWR_MONO_DAC_L (0x1 << 3) +#define RT5665_PWR_MONO_DAC_L_BIT 3 +#define RT5665_PWR_MONO_DAC_R (0x1 << 2) +#define RT5665_PWR_MONO_DAC_R_BIT 2 +#define RT5665_PWR_STO2_DAC_L (0x1 << 1) +#define RT5665_PWR_STO2_DAC_L_BIT 1 +#define RT5665_PWR_STO2_DAC_R (0x1) +#define RT5665_PWR_STO2_DAC_R_BIT 0 + +/* Power Management for Volume (0x0067) */ +#define RT5665_PWR_OV_L (0x1 << 13) +#define RT5665_PWR_OV_L_BIT 13 +#define RT5665_PWR_OV_R (0x1 << 12) +#define RT5665_PWR_OV_R_BIT 12 +#define RT5665_PWR_IN_L (0x1 << 9) +#define RT5665_PWR_IN_L_BIT 9 +#define RT5665_PWR_IN_R (0x1 << 8) +#define RT5665_PWR_IN_R_BIT 8 +#define RT5665_PWR_MV (0x1 << 7) +#define RT5665_PWR_MV_BIT 7 +#define RT5665_PWR_MIC_DET (0x1 << 5) +#define RT5665_PWR_MIC_DET_BIT 5 + +/* (0x006b) */ +#define RT5665_SYS_CLK_DET 15 +#define RT5665_HP_CLK_DET 14 +#define RT5665_MONO_CLK_DET 13 +#define RT5665_LOUT_CLK_DET 12 +#define RT5665_POW_CLK_DET 0 + +/* Digital Microphone Control 1 (0x006e) */ +#define RT5665_DMIC_1_EN_MASK (0x1 << 15) +#define RT5665_DMIC_1_EN_SFT 15 +#define RT5665_DMIC_1_DIS (0x0 << 15) +#define RT5665_DMIC_1_EN (0x1 << 15) +#define RT5665_DMIC_2_EN_MASK (0x1 << 14) +#define RT5665_DMIC_2_EN_SFT 14 +#define RT5665_DMIC_2_DIS (0x0 << 14) +#define RT5665_DMIC_2_EN (0x1 << 14) +#define RT5665_DMIC_2_DP_MASK (0x1 << 9) +#define RT5665_DMIC_2_DP_SFT 9 +#define RT5665_DMIC_2_DP_GPIO5 (0x0 << 9) +#define RT5665_DMIC_2_DP_IN2P (0x1 << 9) +#define RT5665_DMIC_CLK_MASK (0x7 << 5) +#define RT5665_DMIC_CLK_SFT 5 +#define RT5665_DMIC_1_DP_MASK (0x1 << 1) +#define RT5665_DMIC_1_DP_SFT 1 +#define RT5665_DMIC_1_DP_GPIO4 (0x0 << 1) +#define RT5665_DMIC_1_DP_IN2N (0x1 << 1) + + +/* Digital Microphone Control 1 (0x006f) */ +#define RT5665_DMIC_2L_LH_MASK (0x1 << 3) +#define RT5665_DMIC_2L_LH_SFT 3 +#define RT5665_DMIC_2L_LH_RISING (0x0 << 3) +#define RT5665_DMIC_2L_LH_FALLING (0x1 << 3) +#define RT5665_DMIC_2R_LH_MASK (0x1 << 2) +#define RT5665_DMIC_2R_LH_SFT 2 +#define RT5665_DMIC_2R_LH_RISING (0x0 << 2) +#define RT5665_DMIC_2R_LH_FALLING (0x1 << 2) +#define RT5665_DMIC_1L_LH_MASK (0x1 << 1) +#define RT5665_DMIC_1L_LH_SFT 1 +#define RT5665_DMIC_1L_LH_RISING (0x0 << 1) +#define RT5665_DMIC_1L_LH_FALLING (0x1 << 1) +#define RT5665_DMIC_1R_LH_MASK (0x1 << 0) +#define RT5665_DMIC_1R_LH_SFT 0 +#define RT5665_DMIC_1R_LH_RISING (0x0) +#define RT5665_DMIC_1R_LH_FALLING (0x1) + +/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */ +#define RT5665_I2S_MS_MASK (0x1 << 15) +#define RT5665_I2S_MS_SFT 15 +#define RT5665_I2S_MS_M (0x0 << 15) +#define RT5665_I2S_MS_S (0x1 << 15) +#define RT5665_I2S_PIN_CFG_MASK (0x1 << 14) +#define RT5665_I2S_PIN_CFG_SFT 14 +#define RT5665_I2S_CLK_SEL_MASK (0x1 << 11) +#define RT5665_I2S_CLK_SEL_SFT 11 +#define RT5665_I2S_BP_MASK (0x1 << 8) +#define RT5665_I2S_BP_SFT 8 +#define RT5665_I2S_BP_NOR (0x0 << 8) +#define RT5665_I2S_BP_INV (0x1 << 8) +#define RT5665_I2S_DL_MASK (0x3 << 4) +#define RT5665_I2S_DL_SFT 4 +#define RT5665_I2S_DL_16 (0x0 << 4) +#define RT5665_I2S_DL_20 (0x1 << 4) +#define RT5665_I2S_DL_24 (0x2 << 4) +#define RT5665_I2S_DL_8 (0x3 << 4) +#define RT5665_I2S_DF_MASK (0x7) +#define RT5665_I2S_DF_SFT 0 +#define RT5665_I2S_DF_I2S (0x0) +#define RT5665_I2S_DF_LEFT (0x1) +#define RT5665_I2S_DF_PCM_A (0x2) +#define RT5665_I2S_DF_PCM_B (0x3) +#define RT5665_I2S_DF_PCM_A_N (0x6) +#define RT5665_I2S_DF_PCM_B_N (0x7) + +/* ADC/DAC Clock Control 1 (0x0073) */ +#define RT5665_I2S_PD1_MASK (0x7 << 12) +#define RT5665_I2S_PD1_SFT 12 +#define RT5665_I2S_PD1_1 (0x0 << 12) +#define RT5665_I2S_PD1_2 (0x1 << 12) +#define RT5665_I2S_PD1_3 (0x2 << 12) +#define RT5665_I2S_PD1_4 (0x3 << 12) +#define RT5665_I2S_PD1_6 (0x4 << 12) +#define RT5665_I2S_PD1_8 (0x5 << 12) +#define RT5665_I2S_PD1_12 (0x6 << 12) +#define RT5665_I2S_PD1_16 (0x7 << 12) +#define RT5665_I2S_M_PD2_MASK (0x7 << 8) +#define RT5665_I2S_M_PD2_SFT 8 +#define RT5665_I2S_M_PD2_1 (0x0 << 8) +#define RT5665_I2S_M_PD2_2 (0x1 << 8) +#define RT5665_I2S_M_PD2_3 (0x2 << 8) +#define RT5665_I2S_M_PD2_4 (0x3 << 8) +#define RT5665_I2S_M_PD2_6 (0x4 << 8) +#define RT5665_I2S_M_PD2_8 (0x5 << 8) +#define RT5665_I2S_M_PD2_12 (0x6 << 8) +#define RT5665_I2S_M_PD2_16 (0x7 << 8) +#define RT5665_I2S_CLK_SRC_MASK (0x3 << 4) +#define RT5665_I2S_CLK_SRC_SFT 4 +#define RT5665_I2S_CLK_SRC_MCLK (0x0 << 4) +#define RT5665_I2S_CLK_SRC_PLL1 (0x1 << 4) +#define RT5665_I2S_CLK_SRC_RCCLK (0x2 << 4) +#define RT5665_DAC_OSR_MASK (0x3 << 2) +#define RT5665_DAC_OSR_SFT 2 +#define RT5665_DAC_OSR_128 (0x0 << 2) +#define RT5665_DAC_OSR_64 (0x1 << 2) +#define RT5665_DAC_OSR_32 (0x2 << 2) +#define RT5665_ADC_OSR_MASK (0x3) +#define RT5665_ADC_OSR_SFT 0 +#define RT5665_ADC_OSR_128 (0x0) +#define RT5665_ADC_OSR_64 (0x1) +#define RT5665_ADC_OSR_32 (0x2) + +/* ADC/DAC Clock Control 2 (0x0074) */ +#define RT5665_I2S_BCLK_MS2_MASK (0x1 << 15) +#define RT5665_I2S_BCLK_MS2_SFT 15 +#define RT5665_I2S_BCLK_MS2_32 (0x0 << 15) +#define RT5665_I2S_BCLK_MS2_64 (0x1 << 15) +#define RT5665_I2S_PD2_MASK (0x7 << 12) +#define RT5665_I2S_PD2_SFT 12 +#define RT5665_I2S_PD2_1 (0x0 << 12) +#define RT5665_I2S_PD2_2 (0x1 << 12) +#define RT5665_I2S_PD2_3 (0x2 << 12) +#define RT5665_I2S_PD2_4 (0x3 << 12) +#define RT5665_I2S_PD2_6 (0x4 << 12) +#define RT5665_I2S_PD2_8 (0x5 << 12) +#define RT5665_I2S_PD2_12 (0x6 << 12) +#define RT5665_I2S_PD2_16 (0x7 << 12) +#define RT5665_I2S_BCLK_MS3_MASK (0x1 << 11) +#define RT5665_I2S_BCLK_MS3_SFT 11 +#define RT5665_I2S_BCLK_MS3_32 (0x0 << 11) +#define RT5665_I2S_BCLK_MS3_64 (0x1 << 11) +#define RT5665_I2S_PD3_MASK (0x7 << 8) +#define RT5665_I2S_PD3_SFT 8 +#define RT5665_I2S_PD3_1 (0x0 << 8) +#define RT5665_I2S_PD3_2 (0x1 << 8) +#define RT5665_I2S_PD3_3 (0x2 << 8) +#define RT5665_I2S_PD3_4 (0x3 << 8) +#define RT5665_I2S_PD3_6 (0x4 << 8) +#define RT5665_I2S_PD3_8 (0x5 << 8) +#define RT5665_I2S_PD3_12 (0x6 << 8) +#define RT5665_I2S_PD3_16 (0x7 << 8) +#define RT5665_I2S_PD4_MASK (0x7 << 4) +#define RT5665_I2S_PD4_SFT 4 +#define RT5665_I2S_PD4_1 (0x0 << 4) +#define RT5665_I2S_PD4_2 (0x1 << 4) +#define RT5665_I2S_PD4_3 (0x2 << 4) +#define RT5665_I2S_PD4_4 (0x3 << 4) +#define RT5665_I2S_PD4_6 (0x4 << 4) +#define RT5665_I2S_PD4_8 (0x5 << 4) +#define RT5665_I2S_PD4_12 (0x6 << 4) +#define RT5665_I2S_PD4_16 (0x7 << 4) + +/* TDM control 1 (0x0078) */ +#define RT5665_I2S1_MODE_MASK (0x1 << 15) +#define RT5665_I2S1_MODE_I2S (0x0 << 15) +#define RT5665_I2S1_MODE_TDM (0x1 << 15) +#define RT5665_TDM_IN_CH_MASK (0x3 << 10) +#define RT5665_TDM_IN_CH_2 (0x0 << 10) +#define RT5665_TDM_IN_CH_4 (0x1 << 10) +#define RT5665_TDM_IN_CH_6 (0x2 << 10) +#define RT5665_TDM_IN_CH_8 (0x3 << 10) +#define RT5665_TDM_OUT_CH_MASK (0x3 << 8) +#define RT5665_TDM_OUT_CH_2 (0x0 << 8) +#define RT5665_TDM_OUT_CH_4 (0x1 << 8) +#define RT5665_TDM_OUT_CH_6 (0x2 << 8) +#define RT5665_TDM_OUT_CH_8 (0x3 << 8) +#define RT5665_TDM_IN_LEN_MASK (0x3 << 6) +#define RT5665_TDM_IN_LEN_16 (0x0 << 6) +#define RT5665_TDM_IN_LEN_20 (0x1 << 6) +#define RT5665_TDM_IN_LEN_24 (0x2 << 6) +#define RT5665_TDM_IN_LEN_32 (0x3 << 6) +#define RT5665_TDM_OUT_LEN_MASK (0x3 << 4) +#define RT5665_TDM_OUT_LEN_16 (0x0 << 4) +#define RT5665_TDM_OUT_LEN_20 (0x1 << 4) +#define RT5665_TDM_OUT_LEN_24 (0x2 << 4) +#define RT5665_TDM_OUT_LEN_32 (0x3 << 4) + + +/* TDM control 2 (0x0079) */ +#define RT5665_I2S1_1_DS_ADC_SLOT01_SFT 14 +#define RT5665_I2S1_1_DS_ADC_SLOT23_SFT 12 +#define RT5665_I2S1_1_DS_ADC_SLOT45_SFT 10 +#define RT5665_I2S1_1_DS_ADC_SLOT67_SFT 8 +#define RT5665_I2S1_2_DS_ADC_SLOT01_SFT 6 +#define RT5665_I2S1_2_DS_ADC_SLOT23_SFT 4 +#define RT5665_I2S1_2_DS_ADC_SLOT45_SFT 2 +#define RT5665_I2S1_2_DS_ADC_SLOT67_SFT 0 + +/* TDM control 3/4 (0x007a) (0x007b) */ +#define RT5665_IF1_ADC1_SEL_SFT 10 +#define RT5665_IF1_ADC2_SEL_SFT 9 +#define RT5665_IF1_ADC3_SEL_SFT 8 +#define RT5665_IF1_ADC4_SEL_SFT 7 +#define RT5665_TDM_ADC_SEL_SFT 0 +#define RT5665_TDM_ADC_CTRL_MASK (0x1f << 0) +#define RT5665_TDM_ADC_DATA_06 (0x6 << 0) + +/* Global Clock Control (0x0080) */ +#define RT5665_SCLK_SRC_MASK (0x3 << 14) +#define RT5665_SCLK_SRC_SFT 14 +#define RT5665_SCLK_SRC_MCLK (0x0 << 14) +#define RT5665_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5665_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5665_PLL1_SRC_MASK (0x7 << 8) +#define RT5665_PLL1_SRC_SFT 8 +#define RT5665_PLL1_SRC_MCLK (0x0 << 8) +#define RT5665_PLL1_SRC_BCLK1 (0x1 << 8) +#define RT5665_PLL1_SRC_BCLK2 (0x2 << 8) +#define RT5665_PLL1_SRC_BCLK3 (0x3 << 8) +#define RT5665_PLL1_PD_MASK (0x7 << 4) +#define RT5665_PLL1_PD_SFT 4 + + +#define RT5665_PLL_INP_MAX 40000000 +#define RT5665_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x0081) */ +#define RT5665_PLL_N_MAX 0x001ff +#define RT5665_PLL_N_MASK (RT5665_PLL_N_MAX << 7) +#define RT5665_PLL_N_SFT 7 +#define RT5665_PLL_K_MAX 0x001f +#define RT5665_PLL_K_MASK (RT5665_PLL_K_MAX) +#define RT5665_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x0082) */ +#define RT5665_PLL_M_MAX 0x00f +#define RT5665_PLL_M_MASK (RT5665_PLL_M_MAX << 12) +#define RT5665_PLL_M_SFT 12 +#define RT5665_PLL_M_BP (0x1 << 11) +#define RT5665_PLL_M_BP_SFT 11 +#define RT5665_PLL_K_BP (0x1 << 10) +#define RT5665_PLL_K_BP_SFT 10 + +/* PLL tracking mode 1 (0x0083) */ +#define RT5665_I2S3_ASRC_MASK (0x1 << 15) +#define RT5665_I2S3_ASRC_SFT 15 +#define RT5665_I2S2_ASRC_MASK (0x1 << 14) +#define RT5665_I2S2_ASRC_SFT 14 +#define RT5665_I2S1_ASRC_MASK (0x1 << 13) +#define RT5665_I2S1_ASRC_SFT 13 +#define RT5665_DAC_STO1_ASRC_MASK (0x1 << 12) +#define RT5665_DAC_STO1_ASRC_SFT 12 +#define RT5665_DAC_STO2_ASRC_MASK (0x1 << 11) +#define RT5665_DAC_STO2_ASRC_SFT 11 +#define RT5665_DAC_MONO_L_ASRC_MASK (0x1 << 10) +#define RT5665_DAC_MONO_L_ASRC_SFT 10 +#define RT5665_DAC_MONO_R_ASRC_MASK (0x1 << 9) +#define RT5665_DAC_MONO_R_ASRC_SFT 9 +#define RT5665_DMIC_STO1_ASRC_MASK (0x1 << 8) +#define RT5665_DMIC_STO1_ASRC_SFT 8 +#define RT5665_DMIC_STO2_ASRC_MASK (0x1 << 7) +#define RT5665_DMIC_STO2_ASRC_SFT 7 +#define RT5665_DMIC_MONO_L_ASRC_MASK (0x1 << 6) +#define RT5665_DMIC_MONO_L_ASRC_SFT 6 +#define RT5665_DMIC_MONO_R_ASRC_MASK (0x1 << 5) +#define RT5665_DMIC_MONO_R_ASRC_SFT 5 +#define RT5665_ADC_STO1_ASRC_MASK (0x1 << 4) +#define RT5665_ADC_STO1_ASRC_SFT 4 +#define RT5665_ADC_STO2_ASRC_MASK (0x1 << 3) +#define RT5665_ADC_STO2_ASRC_SFT 3 +#define RT5665_ADC_MONO_L_ASRC_MASK (0x1 << 2) +#define RT5665_ADC_MONO_L_ASRC_SFT 2 +#define RT5665_ADC_MONO_R_ASRC_MASK (0x1 << 1) +#define RT5665_ADC_MONO_R_ASRC_SFT 1 + +/* PLL tracking mode 2 (0x0084)*/ +#define RT5665_DA_STO1_CLK_SEL_MASK (0x7 << 12) +#define RT5665_DA_STO1_CLK_SEL_SFT 12 +#define RT5665_DA_STO2_CLK_SEL_MASK (0x7 << 8) +#define RT5665_DA_STO2_CLK_SEL_SFT 8 +#define RT5665_DA_MONOL_CLK_SEL_MASK (0x7 << 4) +#define RT5665_DA_MONOL_CLK_SEL_SFT 4 +#define RT5665_DA_MONOR_CLK_SEL_MASK (0x7) +#define RT5665_DA_MONOR_CLK_SEL_SFT 0 + +/* PLL tracking mode 3 (0x0085)*/ +#define RT5665_AD_STO1_CLK_SEL_MASK (0x7 << 12) +#define RT5665_AD_STO1_CLK_SEL_SFT 12 +#define RT5665_AD_STO2_CLK_SEL_MASK (0x7 << 8) +#define RT5665_AD_STO2_CLK_SEL_SFT 8 +#define RT5665_AD_MONOL_CLK_SEL_MASK (0x7 << 4) +#define RT5665_AD_MONOL_CLK_SEL_SFT 4 +#define RT5665_AD_MONOR_CLK_SEL_MASK (0x7) +#define RT5665_AD_MONOR_CLK_SEL_SFT 0 + +/* ASRC Control 4 (0x0086) */ +#define RT5665_I2S1_RATE_MASK (0xf << 12) +#define RT5665_I2S1_RATE_SFT 12 +#define RT5665_I2S2_RATE_MASK (0xf << 8) +#define RT5665_I2S2_RATE_SFT 8 +#define RT5665_I2S3_RATE_MASK (0xf << 4) +#define RT5665_I2S3_RATE_SFT 4 + +/* Depop Mode Control 1 (0x008e) */ +#define RT5665_PUMP_EN (0x1 << 3) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5665_DEPOP_MASK (0x1 << 13) +#define RT5665_DEPOP_SFT 13 +#define RT5665_DEPOP_AUTO (0x0 << 13) +#define RT5665_DEPOP_MAN (0x1 << 13) +#define RT5665_RAMP_MASK (0x1 << 12) +#define RT5665_RAMP_SFT 12 +#define RT5665_RAMP_DIS (0x0 << 12) +#define RT5665_RAMP_EN (0x1 << 12) +#define RT5665_BPS_MASK (0x1 << 11) +#define RT5665_BPS_SFT 11 +#define RT5665_BPS_DIS (0x0 << 11) +#define RT5665_BPS_EN (0x1 << 11) +#define RT5665_FAST_UPDN_MASK (0x1 << 10) +#define RT5665_FAST_UPDN_SFT 10 +#define RT5665_FAST_UPDN_DIS (0x0 << 10) +#define RT5665_FAST_UPDN_EN (0x1 << 10) +#define RT5665_MRES_MASK (0x3 << 8) +#define RT5665_MRES_SFT 8 +#define RT5665_MRES_15MO (0x0 << 8) +#define RT5665_MRES_25MO (0x1 << 8) +#define RT5665_MRES_35MO (0x2 << 8) +#define RT5665_MRES_45MO (0x3 << 8) +#define RT5665_VLO_MASK (0x1 << 7) +#define RT5665_VLO_SFT 7 +#define RT5665_VLO_3V (0x0 << 7) +#define RT5665_VLO_32V (0x1 << 7) +#define RT5665_DIG_DP_MASK (0x1 << 6) +#define RT5665_DIG_DP_SFT 6 +#define RT5665_DIG_DP_DIS (0x0 << 6) +#define RT5665_DIG_DP_EN (0x1 << 6) +#define RT5665_DP_TH_MASK (0x3 << 4) +#define RT5665_DP_TH_SFT 4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5665_CP_SYS_MASK (0x7 << 12) +#define RT5665_CP_SYS_SFT 12 +#define RT5665_CP_FQ1_MASK (0x7 << 8) +#define RT5665_CP_FQ1_SFT 8 +#define RT5665_CP_FQ2_MASK (0x7 << 4) +#define RT5665_CP_FQ2_SFT 4 +#define RT5665_CP_FQ3_MASK (0x7) +#define RT5665_CP_FQ3_SFT 0 +#define RT5665_CP_FQ_1_5_KHZ 0 +#define RT5665_CP_FQ_3_KHZ 1 +#define RT5665_CP_FQ_6_KHZ 2 +#define RT5665_CP_FQ_12_KHZ 3 +#define RT5665_CP_FQ_24_KHZ 4 +#define RT5665_CP_FQ_48_KHZ 5 +#define RT5665_CP_FQ_96_KHZ 6 +#define RT5665_CP_FQ_192_KHZ 7 + +/* HPOUT charge pump 1 (0x0091) */ +#define RT5665_OSW_L_MASK (0x1 << 11) +#define RT5665_OSW_L_SFT 11 +#define RT5665_OSW_L_DIS (0x0 << 11) +#define RT5665_OSW_L_EN (0x1 << 11) +#define RT5665_OSW_R_MASK (0x1 << 10) +#define RT5665_OSW_R_SFT 10 +#define RT5665_OSW_R_DIS (0x0 << 10) +#define RT5665_OSW_R_EN (0x1 << 10) +#define RT5665_PM_HP_MASK (0x3 << 8) +#define RT5665_PM_HP_SFT 8 +#define RT5665_PM_HP_LV (0x0 << 8) +#define RT5665_PM_HP_MV (0x1 << 8) +#define RT5665_PM_HP_HV (0x2 << 8) +#define RT5665_IB_HP_MASK (0x3 << 6) +#define RT5665_IB_HP_SFT 6 +#define RT5665_IB_HP_125IL (0x0 << 6) +#define RT5665_IB_HP_25IL (0x1 << 6) +#define RT5665_IB_HP_5IL (0x2 << 6) +#define RT5665_IB_HP_1IL (0x3 << 6) + +/* PV detection and SPK gain control (0x92) */ +#define RT5665_PVDD_DET_MASK (0x1 << 15) +#define RT5665_PVDD_DET_SFT 15 +#define RT5665_PVDD_DET_DIS (0x0 << 15) +#define RT5665_PVDD_DET_EN (0x1 << 15) +#define RT5665_SPK_AG_MASK (0x1 << 14) +#define RT5665_SPK_AG_SFT 14 +#define RT5665_SPK_AG_DIS (0x0 << 14) +#define RT5665_SPK_AG_EN (0x1 << 14) + +/* Micbias Control1 (0x93) */ +#define RT5665_MIC1_BS_MASK (0x1 << 15) +#define RT5665_MIC1_BS_SFT 15 +#define RT5665_MIC1_BS_9AV (0x0 << 15) +#define RT5665_MIC1_BS_75AV (0x1 << 15) +#define RT5665_MIC2_BS_MASK (0x1 << 14) +#define RT5665_MIC2_BS_SFT 14 +#define RT5665_MIC2_BS_9AV (0x0 << 14) +#define RT5665_MIC2_BS_75AV (0x1 << 14) +#define RT5665_MIC1_CLK_MASK (0x1 << 13) +#define RT5665_MIC1_CLK_SFT 13 +#define RT5665_MIC1_CLK_DIS (0x0 << 13) +#define RT5665_MIC1_CLK_EN (0x1 << 13) +#define RT5665_MIC2_CLK_MASK (0x1 << 12) +#define RT5665_MIC2_CLK_SFT 12 +#define RT5665_MIC2_CLK_DIS (0x0 << 12) +#define RT5665_MIC2_CLK_EN (0x1 << 12) +#define RT5665_MIC1_OVCD_MASK (0x1 << 11) +#define RT5665_MIC1_OVCD_SFT 11 +#define RT5665_MIC1_OVCD_DIS (0x0 << 11) +#define RT5665_MIC1_OVCD_EN (0x1 << 11) +#define RT5665_MIC1_OVTH_MASK (0x3 << 9) +#define RT5665_MIC1_OVTH_SFT 9 +#define RT5665_MIC1_OVTH_600UA (0x0 << 9) +#define RT5665_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5665_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5665_MIC2_OVCD_MASK (0x1 << 8) +#define RT5665_MIC2_OVCD_SFT 8 +#define RT5665_MIC2_OVCD_DIS (0x0 << 8) +#define RT5665_MIC2_OVCD_EN (0x1 << 8) +#define RT5665_MIC2_OVTH_MASK (0x3 << 6) +#define RT5665_MIC2_OVTH_SFT 6 +#define RT5665_MIC2_OVTH_600UA (0x0 << 6) +#define RT5665_MIC2_OVTH_1500UA (0x1 << 6) +#define RT5665_MIC2_OVTH_2000UA (0x2 << 6) +#define RT5665_PWR_MB_MASK (0x1 << 5) +#define RT5665_PWR_MB_SFT 5 +#define RT5665_PWR_MB_PD (0x0 << 5) +#define RT5665_PWR_MB_PU (0x1 << 5) + +/* Micbias Control2 (0x94) */ +#define RT5665_PWR_CLK25M_MASK (0x1 << 9) +#define RT5665_PWR_CLK25M_SFT 9 +#define RT5665_PWR_CLK25M_PD (0x0 << 9) +#define RT5665_PWR_CLK25M_PU (0x1 << 9) +#define RT5665_PWR_CLK1M_MASK (0x1 << 8) +#define RT5665_PWR_CLK1M_SFT 8 +#define RT5665_PWR_CLK1M_PD (0x0 << 8) +#define RT5665_PWR_CLK1M_PU (0x1 << 8) + + +/* EQ Control 1 (0x00b0) */ +#define RT5665_EQ_SRC_DAC (0x0 << 15) +#define RT5665_EQ_SRC_ADC (0x1 << 15) +#define RT5665_EQ_UPD (0x1 << 14) +#define RT5665_EQ_UPD_BIT 14 +#define RT5665_EQ_CD_MASK (0x1 << 13) +#define RT5665_EQ_CD_SFT 13 +#define RT5665_EQ_CD_DIS (0x0 << 13) +#define RT5665_EQ_CD_EN (0x1 << 13) +#define RT5665_EQ_DITH_MASK (0x3 << 8) +#define RT5665_EQ_DITH_SFT 8 +#define RT5665_EQ_DITH_NOR (0x0 << 8) +#define RT5665_EQ_DITH_LSB (0x1 << 8) +#define RT5665_EQ_DITH_LSB_1 (0x2 << 8) +#define RT5665_EQ_DITH_LSB_2 (0x3 << 8) + +/* IRQ Control 1 (0x00b7) */ +#define RT5665_JD1_1_EN_MASK (0x1 << 15) +#define RT5665_JD1_1_EN_SFT 15 +#define RT5665_JD1_1_DIS (0x0 << 15) +#define RT5665_JD1_1_EN (0x1 << 15) +#define RT5665_JD1_2_EN_MASK (0x1 << 12) +#define RT5665_JD1_2_EN_SFT 12 +#define RT5665_JD1_2_DIS (0x0 << 12) +#define RT5665_JD1_2_EN (0x1 << 12) + +/* IRQ Control 2 (0x00b8) */ +#define RT5665_IL_IRQ_MASK (0x1 << 6) +#define RT5665_IL_IRQ_DIS (0x0 << 6) +#define RT5665_IL_IRQ_EN (0x1 << 6) + +/* IRQ Control 5 (0x00ba) */ +#define RT5665_IRQ_JD_EN (0x1 << 3) +#define RT5665_IRQ_JD_EN_SFT 3 + +/* GPIO Control 1 (0x00c0) */ +#define RT5665_GP1_PIN_MASK (0x1 << 15) +#define RT5665_GP1_PIN_SFT 15 +#define RT5665_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5665_GP1_PIN_IRQ (0x1 << 15) +#define RT5665_GP2_PIN_MASK (0x3 << 13) +#define RT5665_GP2_PIN_SFT 13 +#define RT5665_GP2_PIN_GPIO2 (0x0 << 13) +#define RT5665_GP2_PIN_BCLK2 (0x1 << 13) +#define RT5665_GP2_PIN_PDM_SCL (0x2 << 13) +#define RT5665_GP3_PIN_MASK (0x3 << 11) +#define RT5665_GP3_PIN_SFT 11 +#define RT5665_GP3_PIN_GPIO3 (0x0 << 11) +#define RT5665_GP3_PIN_LRCK2 (0x1 << 11) +#define RT5665_GP3_PIN_PDM_SDA (0x2 << 11) +#define RT5665_GP4_PIN_MASK (0x3 << 9) +#define RT5665_GP4_PIN_SFT 9 +#define RT5665_GP4_PIN_GPIO4 (0x0 << 9) +#define RT5665_GP4_PIN_DACDAT2_1 (0x1 << 9) +#define RT5665_GP4_PIN_DMIC1_SDA (0x2 << 9) +#define RT5665_GP5_PIN_MASK (0x3 << 7) +#define RT5665_GP5_PIN_SFT 7 +#define RT5665_GP5_PIN_GPIO5 (0x0 << 7) +#define RT5665_GP5_PIN_ADCDAT2_1 (0x1 << 7) +#define RT5665_GP5_PIN_DMIC2_SDA (0x2 << 7) +#define RT5665_GP6_PIN_MASK (0x3 << 5) +#define RT5665_GP6_PIN_SFT 5 +#define RT5665_GP6_PIN_GPIO6 (0x0 << 5) +#define RT5665_GP6_PIN_BCLK3 (0x0 << 5) +#define RT5665_GP6_PIN_PDM_SCL (0x1 << 5) +#define RT5665_GP7_PIN_MASK (0x3 << 3) +#define RT5665_GP7_PIN_SFT 3 +#define RT5665_GP7_PIN_GPIO7 (0x0 << 3) +#define RT5665_GP7_PIN_LRCK3 (0x1 << 3) +#define RT5665_GP7_PIN_PDM_SDA (0x2 << 3) +#define RT5665_GP8_PIN_MASK (0x3 << 1) +#define RT5665_GP8_PIN_SFT 1 +#define RT5665_GP8_PIN_GPIO8 (0x0 << 1) +#define RT5665_GP8_PIN_DACDAT3 (0x1 << 1) +#define RT5665_GP8_PIN_DMIC2_SCL (0x2 << 1) +#define RT5665_GP8_PIN_DACDAT2_2 (0x3 << 1) + + +/* GPIO Control 2 (0x00c1)*/ +#define RT5665_GP9_PIN_MASK (0x3 << 14) +#define RT5665_GP9_PIN_SFT 14 +#define RT5665_GP9_PIN_GPIO9 (0x0 << 14) +#define RT5665_GP9_PIN_ADCDAT3 (0x1 << 14) +#define RT5665_GP9_PIN_DMIC1_SCL (0x2 << 14) +#define RT5665_GP9_PIN_ADCDAT2_2 (0x3 << 14) +#define RT5665_GP10_PIN_MASK (0x3 << 12) +#define RT5665_GP10_PIN_SFT 12 +#define RT5665_GP10_PIN_GPIO10 (0x0 << 12) +#define RT5665_GP10_PIN_ADCDAT1_2 (0x1 << 12) +#define RT5665_GP10_PIN_LPD (0x2 << 12) +#define RT5665_GP1_PF_MASK (0x1 << 11) +#define RT5665_GP1_PF_IN (0x0 << 11) +#define RT5665_GP1_PF_OUT (0x1 << 11) +#define RT5665_GP1_OUT_MASK (0x1 << 10) +#define RT5665_GP1_OUT_H (0x0 << 10) +#define RT5665_GP1_OUT_L (0x1 << 10) +#define RT5665_GP2_PF_MASK (0x1 << 9) +#define RT5665_GP2_PF_IN (0x0 << 9) +#define RT5665_GP2_PF_OUT (0x1 << 9) +#define RT5665_GP2_OUT_MASK (0x1 << 8) +#define RT5665_GP2_OUT_H (0x0 << 8) +#define RT5665_GP2_OUT_L (0x1 << 8) +#define RT5665_GP3_PF_MASK (0x1 << 7) +#define RT5665_GP3_PF_IN (0x0 << 7) +#define RT5665_GP3_PF_OUT (0x1 << 7) +#define RT5665_GP3_OUT_MASK (0x1 << 6) +#define RT5665_GP3_OUT_H (0x0 << 6) +#define RT5665_GP3_OUT_L (0x1 << 6) +#define RT5665_GP4_PF_MASK (0x1 << 5) +#define RT5665_GP4_PF_IN (0x0 << 5) +#define RT5665_GP4_PF_OUT (0x1 << 5) +#define RT5665_GP4_OUT_MASK (0x1 << 4) +#define RT5665_GP4_OUT_H (0x0 << 4) +#define RT5665_GP4_OUT_L (0x1 << 4) +#define RT5665_GP5_PF_MASK (0x1 << 3) +#define RT5665_GP5_PF_IN (0x0 << 3) +#define RT5665_GP5_PF_OUT (0x1 << 3) +#define RT5665_GP5_OUT_MASK (0x1 << 2) +#define RT5665_GP5_OUT_H (0x0 << 2) +#define RT5665_GP5_OUT_L (0x1 << 2) +#define RT5665_GP6_PF_MASK (0x1 << 1) +#define RT5665_GP6_PF_IN (0x0 << 1) +#define RT5665_GP6_PF_OUT (0x1 << 1) +#define RT5665_GP6_OUT_MASK (0x1) +#define RT5665_GP6_OUT_H (0x0) +#define RT5665_GP6_OUT_L (0x1) + + +/* GPIO Control 3 (0x00c2) */ +#define RT5665_GP7_PF_MASK (0x1 << 15) +#define RT5665_GP7_PF_IN (0x0 << 15) +#define RT5665_GP7_PF_OUT (0x1 << 15) +#define RT5665_GP7_OUT_MASK (0x1 << 14) +#define RT5665_GP7_OUT_H (0x0 << 14) +#define RT5665_GP7_OUT_L (0x1 << 14) +#define RT5665_GP8_PF_MASK (0x1 << 13) +#define RT5665_GP8_PF_IN (0x0 << 13) +#define RT5665_GP8_PF_OUT (0x1 << 13) +#define RT5665_GP8_OUT_MASK (0x1 << 12) +#define RT5665_GP8_OUT_H (0x0 << 12) +#define RT5665_GP8_OUT_L (0x1 << 12) +#define RT5665_GP9_PF_MASK (0x1 << 11) +#define RT5665_GP9_PF_IN (0x0 << 11) +#define RT5665_GP9_PF_OUT (0x1 << 11) +#define RT5665_GP9_OUT_MASK (0x1 << 10) +#define RT5665_GP9_OUT_H (0x0 << 10) +#define RT5665_GP9_OUT_L (0x1 << 10) +#define RT5665_GP10_PF_MASK (0x1 << 9) +#define RT5665_GP10_PF_IN (0x0 << 9) +#define RT5665_GP10_PF_OUT (0x1 << 9) +#define RT5665_GP10_OUT_MASK (0x1 << 8) +#define RT5665_GP10_OUT_H (0x0 << 8) +#define RT5665_GP10_OUT_L (0x1 << 8) +#define RT5665_GP11_PF_MASK (0x1 << 7) +#define RT5665_GP11_PF_IN (0x0 << 7) +#define RT5665_GP11_PF_OUT (0x1 << 7) +#define RT5665_GP11_OUT_MASK (0x1 << 6) +#define RT5665_GP11_OUT_H (0x0 << 6) +#define RT5665_GP11_OUT_L (0x1 << 6) + +/* Soft volume and zero cross control 1 (0x00d9) */ +#define RT5665_SV_MASK (0x1 << 15) +#define RT5665_SV_SFT 15 +#define RT5665_SV_DIS (0x0 << 15) +#define RT5665_SV_EN (0x1 << 15) +#define RT5665_OUT_SV_MASK (0x1 << 13) +#define RT5665_OUT_SV_SFT 13 +#define RT5665_OUT_SV_DIS (0x0 << 13) +#define RT5665_OUT_SV_EN (0x1 << 13) +#define RT5665_HP_SV_MASK (0x1 << 12) +#define RT5665_HP_SV_SFT 12 +#define RT5665_HP_SV_DIS (0x0 << 12) +#define RT5665_HP_SV_EN (0x1 << 12) +#define RT5665_ZCD_DIG_MASK (0x1 << 11) +#define RT5665_ZCD_DIG_SFT 11 +#define RT5665_ZCD_DIG_DIS (0x0 << 11) +#define RT5665_ZCD_DIG_EN (0x1 << 11) +#define RT5665_ZCD_MASK (0x1 << 10) +#define RT5665_ZCD_SFT 10 +#define RT5665_ZCD_PD (0x0 << 10) +#define RT5665_ZCD_PU (0x1 << 10) +#define RT5665_SV_DLY_MASK (0xf) +#define RT5665_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0x00da) */ +#define RT5665_ZCD_HP_MASK (0x1 << 15) +#define RT5665_ZCD_HP_SFT 15 +#define RT5665_ZCD_HP_DIS (0x0 << 15) +#define RT5665_ZCD_HP_EN (0x1 << 15) + +/* 4 Button Inline Command Control 2 (0x00e0) */ +#define RT5665_4BTN_IL_MASK (0x1 << 15) +#define RT5665_4BTN_IL_EN (0x1 << 15) +#define RT5665_4BTN_IL_DIS (0x0 << 15) +#define RT5665_4BTN_IL_RST_MASK (0x1 << 14) +#define RT5665_4BTN_IL_NOR (0x1 << 14) +#define RT5665_4BTN_IL_RST (0x0 << 14) + +/* Analog JD Control 1 (0x00f0) */ +#define RT5665_JD1_MODE_MASK (0x3 << 0) +#define RT5665_JD1_MODE_0 (0x0 << 0) +#define RT5665_JD1_MODE_1 (0x1 << 0) +#define RT5665_JD1_MODE_2 (0x2 << 0) + +/* Jack Detect Control 3 (0x00f8) */ +#define RT5665_JD_TRI_HPO_SEL_MASK (0x7) +#define RT5665_JD_TRI_HPO_SEL_SFT (0) +#define RT5665_JD_HPO_GPIO_JD1 (0x0) +#define RT5665_JD_HPO_JD1_1 (0x1) +#define RT5665_JD_HPO_JD1_2 (0x2) +#define RT5665_JD_HPO_JD2 (0x3) +#define RT5665_JD_HPO_GPIO_JD2 (0x4) +#define RT5665_JD_HPO_JD3 (0x5) +#define RT5665_JD_HPO_JD_D (0x6) + +/* Digital Misc Control (0x00fa) */ +#define RT5665_AM_MASK (0x1 << 7) +#define RT5665_AM_EN (0x1 << 7) +#define RT5665_AM_DIS (0x1 << 7) +#define RT5665_DIG_GATE_CTRL 0x1 +#define RT5665_DIG_GATE_CTRL_SFT (0) + +/* Chopper and Clock control for ADC (0x011c)*/ +#define RT5665_M_RF_DIG_MASK (0x1 << 12) +#define RT5665_M_RF_DIG_SFT 12 +#define RT5665_M_RI_DIG (0x1 << 11) + +/* Chopper and Clock control for DAC (0x013a)*/ +#define RT5665_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5665_CKXEN_DAC1_SFT 13 +#define RT5665_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5665_CKGEN_DAC1_SFT 12 +#define RT5665_CKXEN_DAC2_MASK (0x1 << 5) +#define RT5665_CKXEN_DAC2_SFT 5 +#define RT5665_CKGEN_DAC2_MASK (0x1 << 4) +#define RT5665_CKGEN_DAC2_SFT 4 + +/* Chopper and Clock control for ADC (0x013b)*/ +#define RT5665_CKXEN_ADC1_MASK (0x1 << 13) +#define RT5665_CKXEN_ADC1_SFT 13 +#define RT5665_CKGEN_ADC1_MASK (0x1 << 12) +#define RT5665_CKGEN_ADC1_SFT 12 +#define RT5665_CKXEN_ADC2_MASK (0x1 << 5) +#define RT5665_CKXEN_ADC2_SFT 5 +#define RT5665_CKGEN_ADC2_MASK (0x1 << 4) +#define RT5665_CKGEN_ADC2_SFT 4 + +/* Volume test (0x013f)*/ +#define RT5665_SEL_CLK_VOL_MASK (0x1 << 15) +#define RT5665_SEL_CLK_VOL_EN (0x1 << 15) +#define RT5665_SEL_CLK_VOL_DIS (0x0 << 15) + +/* Test Mode Control 1 (0x0145) */ +#define RT5665_AD2DA_LB_MASK (0x1 << 9) +#define RT5665_AD2DA_LB_SFT 9 + +/* Stereo Noise Gate Control 1 (0x0160) */ +#define RT5665_NG2_EN_MASK (0x1 << 15) +#define RT5665_NG2_EN (0x1 << 15) +#define RT5665_NG2_DIS (0x0 << 15) + +/* Stereo1 DAC Silence Detection Control (0x0190) */ +#define RT5665_DEB_STO_DAC_MASK (0x7 << 4) +#define RT5665_DEB_80_MS (0x0 << 4) + +/* SAR ADC Inline Command Control 1 (0x0210) */ +#define RT5665_SAR_BUTT_DET_MASK (0x1 << 15) +#define RT5665_SAR_BUTT_DET_EN (0x1 << 15) +#define RT5665_SAR_BUTT_DET_DIS (0x0 << 15) +#define RT5665_SAR_BUTDET_MODE_MASK (0x1 << 14) +#define RT5665_SAR_BUTDET_POW_SAV (0x1 << 14) +#define RT5665_SAR_BUTDET_POW_NORM (0x0 << 14) +#define RT5665_SAR_BUTDET_RST_MASK (0x1 << 13) +#define RT5665_SAR_BUTDET_RST_NORMAL (0x1 << 13) +#define RT5665_SAR_BUTDET_RST (0x0 << 13) +#define RT5665_SAR_POW_MASK (0x1 << 12) +#define RT5665_SAR_POW_EN (0x1 << 12) +#define RT5665_SAR_POW_DIS (0x0 << 12) +#define RT5665_SAR_RST_MASK (0x1 << 11) +#define RT5665_SAR_RST_NORMAL (0x1 << 11) +#define RT5665_SAR_RST (0x0 << 11) +#define RT5665_SAR_BYPASS_MASK (0x1 << 10) +#define RT5665_SAR_BYPASS_EN (0x1 << 10) +#define RT5665_SAR_BYPASS_DIS (0x0 << 10) +#define RT5665_SAR_SEL_MB1_MASK (0x1 << 9) +#define RT5665_SAR_SEL_MB1_SEL (0x1 << 9) +#define RT5665_SAR_SEL_MB1_NOSEL (0x0 << 9) +#define RT5665_SAR_SEL_MB2_MASK (0x1 << 8) +#define RT5665_SAR_SEL_MB2_SEL (0x1 << 8) +#define RT5665_SAR_SEL_MB2_NOSEL (0x0 << 8) +#define RT5665_SAR_SEL_MODE_MASK (0x1 << 7) +#define RT5665_SAR_SEL_MODE_CMP (0x1 << 7) +#define RT5665_SAR_SEL_MODE_ADC (0x0 << 7) +#define RT5665_SAR_SEL_MB1_MB2_MASK (0x1 << 5) +#define RT5665_SAR_SEL_MB1_MB2_AUTO (0x1 << 5) +#define RT5665_SAR_SEL_MB1_MB2_MANU (0x0 << 5) +#define RT5665_SAR_SEL_SIGNAL_MASK (0x1 << 4) +#define RT5665_SAR_SEL_SIGNAL_AUTO (0x1 << 4) +#define RT5665_SAR_SEL_SIGNAL_MANU (0x0 << 4) + +/* System Clock Source */ +enum { + RT5665_SCLK_S_MCLK, + RT5665_SCLK_S_PLL1, + RT5665_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { + RT5665_PLL1_S_MCLK, + RT5665_PLL1_S_BCLK1, + RT5665_PLL1_S_BCLK2, + RT5665_PLL1_S_BCLK3, + RT5665_PLL1_S_BCLK4, +}; + +enum { + RT5665_AIF1_1, + RT5665_AIF1_2, + RT5665_AIF2_1, + RT5665_AIF2_2, + RT5665_AIF3, + RT5665_AIFS +}; + +enum { + CODEC_5665, + CODEC_5666, + CODEC_5668, +}; + +/* filter mask */ +enum { + RT5665_DA_STEREO1_FILTER = 0x1, + RT5665_DA_STEREO2_FILTER = (0x1 << 1), + RT5665_DA_MONO_L_FILTER = (0x1 << 2), + RT5665_DA_MONO_R_FILTER = (0x1 << 3), + RT5665_AD_STEREO1_FILTER = (0x1 << 4), + RT5665_AD_STEREO2_FILTER = (0x1 << 5), + RT5665_AD_MONO_L_FILTER = (0x1 << 6), + RT5665_AD_MONO_R_FILTER = (0x1 << 7), +}; + +enum { + RT5665_CLK_SEL_SYS, + RT5665_CLK_SEL_I2S1_ASRC, + RT5665_CLK_SEL_I2S2_ASRC, + RT5665_CLK_SEL_I2S3_ASRC, + RT5665_CLK_SEL_SYS2, + RT5665_CLK_SEL_SYS3, + RT5665_CLK_SEL_SYS4, +}; + +int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); +int rt5665_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack); + +#endif /* __RT5665_H__ */ diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 49caf1393aeb..97bafac3bc15 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2618,7 +2618,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, RT5670_OSW_L_DIS | RT5670_OSW_R_DIS); snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x1); snd_soc_update_bits(codec, RT5670_PWR_ANLG1, - RT5670_LDO_SEL_MASK, 0x3); + RT5670_LDO_SEL_MASK, 0x5); } break; case SND_SOC_BIAS_STANDBY: @@ -2626,7 +2626,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, RT5670_PWR_VREF1 | RT5670_PWR_VREF2 | RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); snd_soc_update_bits(codec, RT5670_PWR_ANLG1, - RT5670_LDO_SEL_MASK, 0x1); + RT5670_LDO_SEL_MASK, 0x3); break; case SND_SOC_BIAS_OFF: if (rt5670->pdata.jd_mode) @@ -2813,6 +2813,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5670_acpi_match[] = { { "10EC5670", 0}, + { "10EC5672", 0}, { }, }; MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); @@ -2826,6 +2827,13 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"), }, }, + { + .ident = "Dell Wyse 3040", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"), + }, + }, {} }; @@ -2889,6 +2897,9 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, + RT5670_MCLK_DET, RT5670_MCLK_DET); + if (rt5670->pdata.in2_diff) regmap_update_bits(rt5670->regmap, RT5670_IN2, RT5670_IN_DF2, RT5670_IN_DF2); @@ -2903,7 +2914,6 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2, RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); - regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, 0x8, 0x8); } if (rt5670->pdata.jd_mode) { diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 3f1b0f1df809..5ba485cae4e6 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1914,6 +1914,7 @@ enum { #define RT5670_IF1_ADC1_IN2_SFT 11 #define RT5670_IF1_ADC2_IN1_SEL (0x1 << 10) #define RT5670_IF1_ADC2_IN1_SFT 10 +#define RT5670_MCLK_DET (0x1 << 3) /* General Control2 (0xfb) */ #define RT5670_RXDC_SRC_MASK (0x1 << 7) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 91879ea95415..ebd0f7c5ad3b 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -20,7 +20,6 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/sched.h> -#include <linux/kthread.h> #include <linux/uaccess.h> #include <linux/miscdevice.h> #include <linux/regulator/consumer.h> diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 27f30d352867..9de7fe8af255 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/device.h> +#include <linux/regmap.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/ac97_codec.h> @@ -26,31 +27,56 @@ #include <sound/soc.h> #include <sound/tlv.h> -#include "stac9766.h" - #define STAC9766_VENDOR_ID 0x83847666 #define STAC9766_VENDOR_ID_MASK 0xffffffff -/* - * STAC9766 register cache - */ -static const u16 stac9766_reg[] = { - 0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */ - 0x0000, 0x0000, 0x8008, 0x8008, /* e */ - 0x8808, 0x8808, 0x8808, 0x8808, /* 16 */ - 0x8808, 0x0000, 0x8000, 0x0000, /* 1e */ - 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ - 0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */ - 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ - 0x0000, 0x2000, 0x0000, 0x0100, /* 3e */ - 0x0000, 0x0000, 0x0080, 0x0000, /* 46 */ - 0x0000, 0x0000, 0x0003, 0xffff, /* 4e */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 56 */ - 0x4000, 0x0000, 0x0000, 0x0000, /* 5e */ - 0x1201, 0xFFFF, 0xFFFF, 0x0000, /* 66 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ - 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 7e */ +#define AC97_STAC_DA_CONTROL 0x6A +#define AC97_STAC_ANALOG_SPECIAL 0x6E +#define AC97_STAC_STEREO_MIC 0x78 + +static const struct reg_default stac9766_reg_defaults[] = { + { 0x02, 0x8000 }, + { 0x04, 0x8000 }, + { 0x06, 0x8000 }, + { 0x0a, 0x0000 }, + { 0x0c, 0x8008 }, + { 0x0e, 0x8008 }, + { 0x10, 0x8808 }, + { 0x12, 0x8808 }, + { 0x14, 0x8808 }, + { 0x16, 0x8808 }, + { 0x18, 0x8808 }, + { 0x1a, 0x0000 }, + { 0x1c, 0x8000 }, + { 0x20, 0x0000 }, + { 0x22, 0x0000 }, + { 0x28, 0x0a05 }, + { 0x2c, 0xbb80 }, + { 0x32, 0xbb80 }, + { 0x3a, 0x2000 }, + { 0x3e, 0x0100 }, + { 0x4c, 0x0300 }, + { 0x4e, 0xffff }, + { 0x50, 0x0000 }, + { 0x52, 0x0000 }, + { 0x54, 0x0000 }, + { 0x6a, 0x0000 }, + { 0x6e, 0x1000 }, + { 0x72, 0x0000 }, + { 0x78, 0x0000 }, +}; + +static const struct regmap_config stac9766_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x78, + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = regmap_ac97_default_volatile, + + .reg_defaults = stac9766_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(stac9766_reg_defaults), }; static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX", @@ -139,71 +165,22 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum), }; -static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - if (reg > AC97_STAC_PAGE0) { - stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - soc_ac97_ops->write(ac97, reg, val); - stac9766_ac97_write(codec, AC97_INT_PAGING, 1); - return 0; - } - if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) - return -EIO; - - soc_ac97_ops->write(ac97, reg, val); - cache[reg / 2] = val; - return 0; -} - -static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 val = 0, *cache = codec->reg_cache; - - if (reg > AC97_STAC_PAGE0) { - stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0); - stac9766_ac97_write(codec, AC97_INT_PAGING, 1); - return val; - } - if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) - return -EIO; - - if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || - reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || - reg == AC97_VENDOR_ID2) { - - val = soc_ac97_ops->read(ac97, reg); - return val; - } - return cache[reg / 2]; -} - static int ac97_analog_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - unsigned short reg, vra; - - vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); + unsigned short reg; - vra |= 0x1; /* enable variable rate audio */ - vra &= ~0x4; /* disable SPDIF output */ - - stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); + /* enable variable rate audio, disable SPDIF output */ + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x1); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) reg = AC97_PCM_FRONT_DAC_RATE; else reg = AC97_PCM_LR_ADC_RATE; - return stac9766_ac97_write(codec, reg, runtime->rate); + return snd_soc_write(codec, reg, runtime->rate); } static int ac97_digital_prepare(struct snd_pcm_substream *substream, @@ -211,18 +188,16 @@ static int ac97_digital_prepare(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - unsigned short reg, vra; - - stac9766_ac97_write(codec, AC97_SPDIF, 0x2002); + unsigned short reg; - vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); - vra |= 0x5; /* Enable VRA and SPDIF out */ + snd_soc_write(codec, AC97_SPDIF, 0x2002); - stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); + /* Enable VRA and SPDIF out */ + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x5); reg = AC97_PCM_FRONT_DAC_RATE; - return stac9766_ac97_write(codec, reg, runtime->rate); + return snd_soc_write(codec, reg, runtime->rate); } static int stac9766_set_bias_level(struct snd_soc_codec *codec, @@ -232,11 +207,11 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_ON: /* full On */ case SND_SOC_BIAS_PREPARE: /* partial On */ case SND_SOC_BIAS_STANDBY: /* Off, with power */ - stac9766_ac97_write(codec, AC97_POWERDOWN, 0x0000); + snd_soc_write(codec, AC97_POWERDOWN, 0x0000); break; case SND_SOC_BIAS_OFF: /* Off, without power */ /* disable everything including AC link */ - stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff); + snd_soc_write(codec, AC97_POWERDOWN, 0xffff); break; } return 0; @@ -300,21 +275,34 @@ static struct snd_soc_dai_driver stac9766_dai[] = { static int stac9766_codec_probe(struct snd_soc_codec *codec) { struct snd_ac97 *ac97; + struct regmap *regmap; + int ret; ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID, STAC9766_VENDOR_ID_MASK); if (IS_ERR(ac97)) return PTR_ERR(ac97); + regmap = regmap_init_ac97(ac97, &stac9766_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_free_ac97; + } + + snd_soc_codec_init_regmap(codec, regmap); snd_soc_codec_set_drvdata(codec, ac97); return 0; +err_free_ac97: + snd_soc_free_ac97_codec(ac97); + return ret; } static int stac9766_codec_remove(struct snd_soc_codec *codec) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + snd_soc_codec_exit_regmap(codec); snd_soc_free_ac97_codec(ac97); return 0; } @@ -324,17 +312,11 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { .controls = stac9766_snd_ac97_controls, .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), }, - .write = stac9766_ac97_write, - .read = stac9766_ac97_read, .set_bias_level = stac9766_set_bias_level, .suspend_bias_off = true, .probe = stac9766_codec_probe, .remove = stac9766_codec_remove, .resume = stac9766_codec_resume, - .reg_cache_size = ARRAY_SIZE(stac9766_reg), - .reg_word_size = sizeof(u16), - .reg_cache_step = 2, - .reg_cache_default = stac9766_reg, }; static int stac9766_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h deleted file mode 100644 index c726f907e2c0..000000000000 --- a/sound/soc/codecs/stac9766.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * stac9766.h -- STAC9766 Soc Audio driver - */ - -#ifndef _STAC9766_H -#define _STAC9766_H - -#define AC97_STAC_PAGE0 0x1000 -#define AC97_STAC_DA_CONTROL (AC97_STAC_PAGE0 | 0x6A) -#define AC97_STAC_ANALOG_SPECIAL (AC97_STAC_PAGE0 | 0x6E) -#define AC97_STAC_STEREO_MIC 0x78 - -/* STAC9766 DAI ID's */ -#define STAC9766_DAI_AC97_ANALOG 0 -#define STAC9766_DAI_AC97_DIGITAL 1 - -#endif diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 7b31ee9b82bc..62c618765224 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -14,28 +14,8 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> -/* chipID supported */ -#define CHIPID_STIH416 0 -#define CHIPID_STIH407 1 - /* DAC definitions */ -/* stih416 DAC registers */ -/* sysconf 2517: Audio-DAC-Control */ -#define STIH416_AUDIO_DAC_CTRL 0x00000814 -/* sysconf 2519: Audio-Gue-Control */ -#define STIH416_AUDIO_GLUE_CTRL 0x0000081C - -#define STIH416_DAC_NOT_STANDBY 0x3 -#define STIH416_DAC_SOFTMUTE 0x4 -#define STIH416_DAC_ANA_NOT_PWR 0x5 -#define STIH416_DAC_NOT_PNDBG 0x6 - -#define STIH416_DAC_NOT_STANDBY_MASK BIT(STIH416_DAC_NOT_STANDBY) -#define STIH416_DAC_SOFTMUTE_MASK BIT(STIH416_DAC_SOFTMUTE) -#define STIH416_DAC_ANA_NOT_PWR_MASK BIT(STIH416_DAC_ANA_NOT_PWR) -#define STIH416_DAC_NOT_PNDBG_MASK BIT(STIH416_DAC_NOT_PNDBG) - /* stih407 DAC registers */ /* sysconf 5041: Audio-Gue-Control */ #define STIH407_AUDIO_GLUE_CTRL 0x000000A4 @@ -63,14 +43,9 @@ enum { STI_SAS_DAI_ANALOG_OUT, }; -static const struct reg_default stih416_sas_reg_defaults[] = { - { STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, - { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, -}; - static const struct reg_default stih407_sas_reg_defaults[] = { - { STIH416_AUDIO_DAC_CTRL, 0x000000000 }, - { STIH416_AUDIO_GLUE_CTRL, 0x00000040 }, + { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, + { STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, }; struct sti_dac_audio { @@ -89,7 +64,6 @@ struct sti_spdif_audio { /* device data structure */ struct sti_sas_dev_data { - const int chipid; /* IC version */ const struct regmap_config *regmap; const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */ const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */ @@ -150,51 +124,27 @@ static int sti_sas_init_sas_registers(struct snd_soc_codec *codec, ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, SPDIF_BIPHASE_IDLE_MASK, 0); if (ret < 0) { - dev_err(codec->dev, "Failed to update SPDIF registers"); + dev_err(codec->dev, "Failed to update SPDIF registers\n"); return ret; } /* Init DAC configuration */ - switch (data->dev_data->chipid) { - case CHIPID_STIH407: - /* init configuration */ - ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, - STIH407_DAC_STANDBY_MASK, - STIH407_DAC_STANDBY_MASK); - - if (!ret) - ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, - STIH407_DAC_STANDBY_ANA_MASK, - STIH407_DAC_STANDBY_ANA_MASK); - if (!ret) - ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, - STIH407_DAC_SOFTMUTE_MASK, - STIH407_DAC_SOFTMUTE_MASK); - break; - case CHIPID_STIH416: - ret = snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_NOT_STANDBY_MASK, 0); - if (!ret) - ret = snd_soc_update_bits(codec, - STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_ANA_NOT_PWR, 0); - if (!ret) - ret = snd_soc_update_bits(codec, - STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_NOT_PNDBG_MASK, - 0); - if (!ret) - ret = snd_soc_update_bits(codec, - STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_SOFTMUTE_MASK, - STIH416_DAC_SOFTMUTE_MASK); - break; - default: - return -EINVAL; - } + /* init configuration */ + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_MASK, + STIH407_DAC_STANDBY_MASK); + + if (!ret) + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_ANA_MASK, + STIH407_DAC_STANDBY_ANA_MASK); + if (!ret) + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_SOFTMUTE_MASK, + STIH407_DAC_SOFTMUTE_MASK); if (ret < 0) { - dev_err(codec->dev, "Failed to update DAC registers"); + dev_err(codec->dev, "Failed to update DAC registers\n"); return ret; } @@ -217,37 +167,6 @@ static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static int stih416_dac_probe(struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); - struct sti_dac_audio *dac = &drvdata->dac; - - /* Get reset control */ - dac->rst = devm_reset_control_get(codec->dev, "dac_rst"); - if (IS_ERR(dac->rst)) { - dev_err(dai->codec->dev, - "%s: ERROR: DAC reset control not defined !\n", - __func__); - dac->rst = NULL; - return -EFAULT; - } - /* Put the DAC into reset */ - reset_control_assert(dac->rst); - - return 0; -} - -static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { - SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0), - SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_NOT_STANDBY, 0), - SND_SOC_DAPM_OUTPUT("DAC Output"), -}; - static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL, STIH407_DAC_STANDBY_ANA, 1, NULL, 0), @@ -256,30 +175,11 @@ static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("DAC Output"), }; -static const struct snd_soc_dapm_route stih416_sas_route[] = { - {"DAC Output", NULL, "DAC bandgap"}, - {"DAC Output", NULL, "DAC standby ana"}, - {"DAC standby ana", NULL, "DAC standby"}, -}; - static const struct snd_soc_dapm_route stih407_sas_route[] = { {"DAC Output", NULL, "DAC standby ana"}, {"DAC standby ana", NULL, "DAC standby"}, }; -static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) -{ - struct snd_soc_codec *codec = dai->codec; - - if (mute) { - return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_SOFTMUTE_MASK, - STIH416_DAC_SOFTMUTE_MASK); - } else { - return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_SOFTMUTE_MASK, 0); - } -} static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) { @@ -392,13 +292,13 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream, switch (dai->id) { case STI_SAS_DAI_SPDIF_OUT: if ((drvdata->spdif.mclk / runtime->rate) != 128) { - dev_err(codec->dev, "unexpected mclk-fs ratio"); + dev_err(codec->dev, "unexpected mclk-fs ratio\n"); return -EINVAL; } break; case STI_SAS_DAI_ANALOG_OUT: if ((drvdata->dac.mclk / runtime->rate) != 256) { - dev_err(codec->dev, "unexpected mclk-fs ratio"); + dev_err(codec->dev, "unexpected mclk-fs ratio\n"); return -EINVAL; } break; @@ -407,13 +307,6 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops stih416_dac_ops = { - .set_fmt = sti_sas_dac_set_fmt, - .mute_stream = stih416_sas_dac_mute, - .prepare = sti_sas_prepare, - .set_sysclk = sti_sas_set_sysclk, -}; - static const struct snd_soc_dai_ops stih407_dac_ops = { .set_fmt = sti_sas_dac_set_fmt, .mute_stream = stih407_sas_dac_mute, @@ -424,7 +317,7 @@ static const struct snd_soc_dai_ops stih407_dac_ops = { static const struct regmap_config stih407_sas_regmap = { .reg_bits = 32, .val_bits = 32, - + .fast_io = true, .max_register = STIH407_AUDIO_DAC_CTRL, .reg_defaults = stih407_sas_reg_defaults, .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults), @@ -434,31 +327,7 @@ static const struct regmap_config stih407_sas_regmap = { .reg_write = sti_sas_write_reg, }; -static const struct regmap_config stih416_sas_regmap = { - .reg_bits = 32, - .val_bits = 32, - - .max_register = STIH416_AUDIO_DAC_CTRL, - .reg_defaults = stih416_sas_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults), - .volatile_reg = sti_sas_volatile_register, - .cache_type = REGCACHE_RBTREE, - .reg_read = sti_sas_read_reg, - .reg_write = sti_sas_write_reg, -}; - -static const struct sti_sas_dev_data stih416_data = { - .chipid = CHIPID_STIH416, - .regmap = &stih416_sas_regmap, - .dac_ops = &stih416_dac_ops, - .dapm_widgets = stih416_sas_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets), - .dapm_routes = stih416_sas_route, - .num_dapm_routes = ARRAY_SIZE(stih416_sas_route), -}; - static const struct sti_sas_dev_data stih407_data = { - .chipid = CHIPID_STIH407, .regmap = &stih407_sas_regmap, .dac_ops = &stih407_dac_ops, .dapm_widgets = stih407_sas_dapm_widgets, @@ -533,10 +402,6 @@ static struct snd_soc_codec_driver sti_sas_driver = { static const struct of_device_id sti_sas_dev_match[] = { { - .compatible = "st,stih416-sas-codec", - .data = &stih416_data, - }, - { .compatible = "st,stih407-sas-codec", .data = &stih407_data, }, @@ -558,7 +423,7 @@ static int sti_sas_driver_probe(struct platform_device *pdev) /* Populate data structure depending on compatibility */ of_id = of_match_node(sti_sas_dev_match, pnode); if (!of_id->data) { - dev_err(&pdev->dev, "data associated to device is missing"); + dev_err(&pdev->dev, "data associated to device is missing\n"); return -EINVAL; } @@ -584,10 +449,6 @@ static int sti_sas_driver_probe(struct platform_device *pdev) } drvdata->spdif.regmap = drvdata->dac.regmap; - /* Set DAC dai probe */ - if (drvdata->dev_data->chipid == CHIPID_STIH416) - sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe; - sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; /* Set dapms*/ diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index df5e5cb33baa..810369f687d7 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -341,20 +341,9 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec, return ret; } } - - gpiod_set_value(priv->pdn_gpio, 0); - usleep_range(5000, 6000); - - regcache_cache_only(priv->regmap, false); - ret = regcache_sync(priv->regmap); - if (ret) - return ret; } break; case SND_SOC_BIAS_OFF: - regcache_cache_only(priv->regmap, true); - gpiod_set_value(priv->pdn_gpio, 1); - if (!IS_ERR(priv->mclk)) clk_disable_unprepare(priv->mclk); break; @@ -401,16 +390,6 @@ static const struct snd_kcontrol_new tas5711_controls[] = { TAS571X_SOFT_MUTE_REG, TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, 1, 1), - - SOC_DOUBLE_R_RANGE("CH1 Mixer Volume", - TAS5717_CH1_LEFT_CH_MIX_REG, - TAS5717_CH1_RIGHT_CH_MIX_REG, - 16, 0, 0x80, 0), - - SOC_DOUBLE_R_RANGE("CH2 Mixer Volume", - TAS5717_CH2_LEFT_CH_MIX_REG, - TAS5717_CH2_RIGHT_CH_MIX_REG, - 16, 0, 0x80, 0), }; static const struct regmap_range tas571x_readonly_regs_range[] = { @@ -488,6 +467,16 @@ static const struct snd_kcontrol_new tas5717_controls[] = { TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, 1, 1), + SOC_DOUBLE_R_RANGE("CH1 Mixer Volume", + TAS5717_CH1_LEFT_CH_MIX_REG, + TAS5717_CH1_RIGHT_CH_MIX_REG, + 16, 0, 0x80, 0), + + SOC_DOUBLE_R_RANGE("CH2 Mixer Volume", + TAS5717_CH2_LEFT_CH_MIX_REG, + TAS5717_CH2_RIGHT_CH_MIX_REG, + 16, 0, 0x80, 0), + /* * The biquads are named according to the register names. * Please note that TI's TAS57xx Graphical Development Environment @@ -747,13 +736,14 @@ static int tas571x_i2c_probe(struct i2c_client *client, /* pulse the active low reset line for ~100us */ usleep_range(100, 200); gpiod_set_value(priv->reset_gpio, 0); - usleep_range(12000, 20000); + usleep_range(13500, 20000); } ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0); if (ret) return ret; + usleep_range(50000, 60000); memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver)); priv->codec_driver.component_driver.controls = priv->chip->controls; @@ -770,9 +760,6 @@ static int tas571x_i2c_probe(struct i2c_client *client, return ret; } - regcache_cache_only(priv->regmap, true); - gpiod_set_value(priv->pdn_gpio, 1); - return snd_soc_register_codec(&client->dev, &priv->codec_driver, &tas571x_dai, 1); } diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index be1a64bfd320..f8a90ba8cd71 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1253,6 +1253,8 @@ static const struct of_device_id tlv320aic31xx_of_match[] = { { .compatible = "ti,tlv320aic3110" }, { .compatible = "ti,tlv320aic3120" }, { .compatible = "ti,tlv320aic3111" }, + { .compatible = "ti,tlv320dac3100" }, + { .compatible = "ti,tlv320dac3101" }, {}, }; MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match); @@ -1379,6 +1381,7 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { { "tlv320aic3120", AIC3120 }, { "tlv320aic3111", AIC3111 }, { "tlv320dac3100", DAC3100 }, + { "tlv320dac3101", DAC3101 }, { } }; MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 5acd5b69fb83..730fb2058869 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -32,6 +32,7 @@ enum aic31xx_type { AIC3120 = AIC31XX_MINIDSP_BIT, AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT), DAC3100 = DAC31XX_BIT, + DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT, }; struct aic31xx_pdata { diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5a8d96ec058c..8877b74b0510 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -157,7 +157,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; unsigned short val; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { 0 }; int connect, change; val = (ucontrol->value.integer.value[0] & mask); diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 533e3bb444e4..2918fdb95e58 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -698,25 +698,10 @@ static int uda1380_probe(struct snd_soc_codec *codec) codec->hw_write = (hw_write_t)i2c_master_send; codec->control_data = uda1380->control_data; - if (!pdata) - return -EINVAL; - - if (gpio_is_valid(pdata->gpio_reset)) { - ret = gpio_request_one(pdata->gpio_reset, GPIOF_OUT_INIT_LOW, - "uda1380 reset"); - if (ret) - goto err_out; - } - - if (gpio_is_valid(pdata->gpio_power)) { - ret = gpio_request_one(pdata->gpio_power, GPIOF_OUT_INIT_LOW, - "uda1380 power"); - if (ret) - goto err_free_gpio; - } else { + if (!gpio_is_valid(pdata->gpio_power)) { ret = uda1380_reset(codec); if (ret) - goto err_free_gpio; + return ret; } INIT_WORK(&uda1380->work, uda1380_flush_work); @@ -733,28 +718,10 @@ static int uda1380_probe(struct snd_soc_codec *codec) } return 0; - -err_free_gpio: - if (gpio_is_valid(pdata->gpio_reset)) - gpio_free(pdata->gpio_reset); -err_out: - return ret; -} - -/* power down chip */ -static int uda1380_remove(struct snd_soc_codec *codec) -{ - struct uda1380_platform_data *pdata =codec->dev->platform_data; - - gpio_free(pdata->gpio_reset); - gpio_free(pdata->gpio_power); - - return 0; } static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { .probe = uda1380_probe, - .remove = uda1380_remove, .read = uda1380_read_reg_cache, .write = uda1380_write, .set_bias_level = uda1380_set_bias_level, @@ -775,18 +742,35 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { }, }; -#if IS_ENABLED(CONFIG_I2C) static int uda1380_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct uda1380_platform_data *pdata = i2c->dev.platform_data; struct uda1380_priv *uda1380; int ret; + if (!pdata) + return -EINVAL; + uda1380 = devm_kzalloc(&i2c->dev, sizeof(struct uda1380_priv), GFP_KERNEL); if (uda1380 == NULL) return -ENOMEM; + if (gpio_is_valid(pdata->gpio_reset)) { + ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_reset, + GPIOF_OUT_INIT_LOW, "uda1380 reset"); + if (ret) + return ret; + } + + if (gpio_is_valid(pdata->gpio_power)) { + ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_power, + GPIOF_OUT_INIT_LOW, "uda1380 power"); + if (ret) + return ret; + } + i2c_set_clientdata(i2c, uda1380); uda1380->control_data = i2c; @@ -815,27 +799,8 @@ static struct i2c_driver uda1380_i2c_driver = { .remove = uda1380_i2c_remove, .id_table = uda1380_i2c_id, }; -#endif -static int __init uda1380_modinit(void) -{ - int ret = 0; -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&uda1380_i2c_driver); - if (ret != 0) - pr_err("Failed to register UDA1380 I2C driver: %d\n", ret); -#endif - return ret; -} -module_init(uda1380_modinit); - -static void __exit uda1380_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&uda1380_i2c_driver); -#endif -} -module_exit(uda1380_exit); +module_i2c_driver(uda1380_i2c_driver); MODULE_AUTHOR("Giorgio Padrin"); MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h index 942e3927c72b..69a326ac3c1a 100644 --- a/sound/soc/codecs/uda1380.h +++ b/sound/soc/codecs/uda1380.h @@ -72,8 +72,4 @@ #define R22_SKIP_DCFIL 0x0002 #define R23_AGC_EN 0x0001 -#define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */ -#define UDA1380_DAI_PLAYBACK 1 /* playback DAI */ -#define UDA1380_DAI_CAPTURE 2 /* capture DAI */ - #endif /* _UDA1380_H */ diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 606bf88abfc4..d83dab57a1d1 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -999,7 +999,7 @@ static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0); static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0); -static const char *wm2200_mixer_texts[] = { +static const char * const wm2200_mixer_texts[] = { "None", "Tone Generator", "AEC Loopback", @@ -1033,7 +1033,7 @@ static const char *wm2200_mixer_texts[] = { "DSP2.6", }; -static int wm2200_mixer_values[] = { +static unsigned int wm2200_mixer_values[] = { 0x00, 0x04, /* Tone */ 0x08, /* AEC */ diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 93876c6d48ee..e7ab37d0dd32 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -607,6 +607,9 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: break; + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMD: + return arizona_clk_ev(w, kcontrol, event); default: return 0; } @@ -1077,9 +1080,11 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux = static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, 0, wm5102_sysclk_ev, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -1903,7 +1908,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { static int wm5102_open(struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct wm5102_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + struct wm5102_priv *priv = snd_soc_platform_get_drvdata(rtd->platform); return wm_adsp_compr_open(&priv->core.adsp[0], stream); } @@ -1926,18 +1931,10 @@ static irqreturn_t wm5102_adsp2_irq(int irq, void *data) static int wm5102_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; int ret; - ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, - "ADSP2 Compressed IRQ", wm5102_adsp2_irq, - priv); - if (ret != 0) { - dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; - } - ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec); if (ret) return ret; @@ -1949,8 +1946,9 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) arizona_init_spk(codec); arizona_init_gpio(codec); + arizona_init_notifiers(codec); - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); priv->core.arizona->dapm = dapm; @@ -1965,16 +1963,11 @@ err_adsp2_codec_probe: static int wm5102_codec_remove(struct snd_soc_codec *codec) { struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; wm_adsp2_codec_remove(&priv->core.adsp[0], codec); priv->core.arizona->dapm = NULL; - arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - - arizona_free_spk(codec); - return 0; } @@ -2092,25 +2085,47 @@ static int wm5102_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", wm5102_adsp2_irq, + wm5102); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + goto err_dsp_irq; + ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform); if (ret < 0) { dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); - return ret; + goto err_spk_irqs; } ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102, wm5102_dai, ARRAY_SIZE(wm5102_dai)); if (ret < 0) { dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); - snd_soc_unregister_platform(&pdev->dev); + goto err_platform; } return ret; + +err_platform: + snd_soc_unregister_platform(&pdev->dev); +err_spk_irqs: + arizona_free_spk_irqs(arizona); +err_dsp_irq: + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); + + return ret; } static int wm5102_remove(struct platform_device *pdev) { struct wm5102_priv *wm5102 = platform_get_drvdata(pdev); + struct arizona *arizona = wm5102->core.arizona; snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_codec(&pdev->dev); @@ -2118,6 +2133,10 @@ static int wm5102_remove(struct platform_device *pdev) wm_adsp2_remove(&wm5102->core.adsp[0]); + arizona_free_spk_irqs(arizona); + + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); + return 0; } diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 06bae3b23fce..585fc706c1b0 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -183,7 +183,9 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, regmap_write_async(regmap, patch[i].reg, patch[i].def); break; - + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMD: + return arizona_clk_ev(w, kcontrol, event); default: break; } @@ -1073,9 +1075,11 @@ static const struct snd_kcontrol_new wm5110_output_anc_src[] = { static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, - 0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU), + 0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -2220,7 +2224,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { static int wm5110_open(struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + struct wm5110_priv *priv = snd_soc_platform_get_drvdata(rtd->platform); struct arizona *arizona = priv->core.arizona; int n_adsp; @@ -2269,8 +2273,8 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data) static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; int i, ret; priv->core.arizona->dapm = dapm; @@ -2280,14 +2284,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) arizona_init_mono(codec); arizona_init_notifiers(codec); - ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, - "ADSP2 Compressed IRQ", wm5110_adsp2_irq, - priv); - if (ret != 0) { - dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; - } - for (i = 0; i < WM5110_NUM_ADSP; ++i) { ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec); if (ret) @@ -2300,7 +2296,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) if (ret) goto err_adsp2_codec_probe; - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); return 0; @@ -2308,15 +2304,12 @@ err_adsp2_codec_probe: for (--i; i >= 0; --i) wm_adsp2_codec_remove(&priv->core.adsp[i], codec); - arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - return ret; } static int wm5110_codec_remove(struct snd_soc_codec *codec) { struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; int i; for (i = 0; i < WM5110_NUM_ADSP; ++i) @@ -2324,10 +2317,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) priv->core.arizona->dapm = NULL; - arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - - arizona_free_spk(codec); - return 0; } @@ -2449,25 +2438,47 @@ static int wm5110_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", wm5110_adsp2_irq, + wm5110); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + goto err_dsp_irq; + ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform); if (ret < 0) { dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); - return ret; + goto err_spk_irqs; } ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110, wm5110_dai, ARRAY_SIZE(wm5110_dai)); if (ret < 0) { dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); - snd_soc_unregister_platform(&pdev->dev); + goto err_platform; } return ret; + +err_platform: + snd_soc_unregister_platform(&pdev->dev); +err_spk_irqs: + arizona_free_spk_irqs(arizona); +err_dsp_irq: + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); + + return ret; } static int wm5110_remove(struct platform_device *pdev) { struct wm5110_priv *wm5110 = platform_get_drvdata(pdev); + struct arizona *arizona = wm5110->core.arizona; int i; snd_soc_unregister_platform(&pdev->dev); @@ -2477,6 +2488,10 @@ static int wm5110_remove(struct platform_device *pdev) for (i = 0; i < WM5110_NUM_ADSP; i++) wm_adsp2_remove(&wm5110->core.adsp[i]); + arizona_free_spk_irqs(arizona); + + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); + return 0; } diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 2f2821b3382f..ee0c8639c743 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -108,6 +108,9 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: break; + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMD: + return arizona_clk_ev(w, kcontrol, event); default: return 0; } @@ -408,9 +411,11 @@ static const struct snd_kcontrol_new wm8997_aec_loopback_mux = static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, 0, wm8997_sysclk_ev, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -1055,11 +1060,13 @@ static struct snd_soc_dai_driver wm8997_dai[] = { static int wm8997_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); arizona_init_spk(codec); + arizona_init_notifiers(codec); - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); priv->core.arizona->dapm = dapm; @@ -1072,8 +1079,6 @@ static int wm8997_codec_remove(struct snd_soc_codec *codec) priv->core.arizona->dapm = NULL; - arizona_free_spk(codec); - return 0; } @@ -1119,7 +1124,7 @@ static int wm8997_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct wm8997_priv *wm8997; - int i; + int i, ret; wm8997 = devm_kzalloc(&pdev->dev, sizeof(struct wm8997_priv), GFP_KERNEL); @@ -1159,15 +1164,33 @@ static int wm8997_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); - return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997, - wm8997_dai, ARRAY_SIZE(wm8997_dai)); + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + return ret; + + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997, + wm8997_dai, ARRAY_SIZE(wm8997_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + goto err_spk_irqs; + } + +err_spk_irqs: + arizona_free_spk_irqs(arizona); + + return ret; } static int wm8997_remove(struct platform_device *pdev) { + struct wm8997_priv *wm8997 = platform_get_drvdata(pdev); + struct arizona *arizona = wm8997->core.arizona; + snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev); + arizona_free_spk_irqs(arizona); + return 0; } diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index bcc2e1060a6c..3694f5958d86 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -541,9 +541,11 @@ static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = { static const struct snd_soc_dapm_widget wm8998_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, - ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -1318,13 +1320,15 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec) { struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); priv->core.arizona->dapm = dapm; arizona_init_spk(codec); arizona_init_gpio(codec); + arizona_init_notifiers(codec); - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); return 0; } @@ -1335,8 +1339,6 @@ static int wm8998_codec_remove(struct snd_soc_codec *codec) priv->core.arizona->dapm = NULL; - arizona_free_spk(codec); - return 0; } @@ -1385,7 +1387,7 @@ static int wm8998_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct wm8998_priv *wm8998; - int i; + int i, ret; wm8998 = devm_kzalloc(&pdev->dev, sizeof(struct wm8998_priv), GFP_KERNEL); @@ -1417,15 +1419,35 @@ static int wm8998_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); - return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998, - wm8998_dai, ARRAY_SIZE(wm8998_dai)); + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + return ret; + + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998, + wm8998_dai, ARRAY_SIZE(wm8998_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + goto err_spk_irqs; + } + + return ret; + +err_spk_irqs: + arizona_free_spk_irqs(arizona); + + return ret; } static int wm8998_remove(struct platform_device *pdev) { + struct wm8998_priv *wm8998 = platform_get_drvdata(pdev); + struct arizona *arizona = wm8998->core.arizona; + snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev); + arizona_free_spk_irqs(arizona); + return 0; } diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 557709eac698..85f7c5bb8b82 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -187,7 +187,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int mixer, mask, shift, old; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { 0 }; bool change; mixer = mc->shift >> 8; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index e4301ddb1b84..7e4822185feb 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -231,7 +231,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int mixer, mask, shift, old; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { 0 }; bool change; mixer = mc->shift >> 8; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b943dde8dbe5..593b7d1aed46 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -162,6 +162,16 @@ #define ADSP_MAX_STD_CTRL_SIZE 512 +#define WM_ADSP_ACKED_CTL_TIMEOUT_MS 100 +#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS 10 +#define WM_ADSP_ACKED_CTL_MIN_VALUE 0 +#define WM_ADSP_ACKED_CTL_MAX_VALUE 0xFFFFFF + +/* + * Event control messages + */ +#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001 + struct wm_adsp_buf { struct list_head list; void *buf; @@ -177,7 +187,7 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, buf->buf = vmalloc(len); if (!buf->buf) { - vfree(buf); + kfree(buf); return NULL; } memcpy(buf->buf, src, len); @@ -441,11 +451,29 @@ struct wm_coeff_ctl { unsigned int offset; size_t len; unsigned int set:1; - struct snd_kcontrol *kcontrol; struct soc_bytes_ext bytes_ext; unsigned int flags; + unsigned int type; }; +static const char *wm_adsp_mem_region_name(unsigned int type) +{ + switch (type) { + case WMFW_ADSP1_PM: + return "PM"; + case WMFW_ADSP1_DM: + return "DM"; + case WMFW_ADSP2_XM: + return "XM"; + case WMFW_ADSP2_YM: + return "YM"; + case WMFW_ADSP1_ZM: + return "ZM"; + default: + return NULL; + } +} + #ifdef CONFIG_DEBUG_FS static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) { @@ -727,6 +755,24 @@ static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) return container_of(ext, struct wm_coeff_ctl, bytes_ext); } +static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg) +{ + const struct wm_adsp_alg_region *alg_region = &ctl->alg_region; + struct wm_adsp *dsp = ctl->dsp; + const struct wm_adsp_region *mem; + + mem = wm_adsp_find_region(dsp, alg_region->type); + if (!mem) { + adsp_err(dsp, "No base for region %x\n", + alg_region->type); + return -EINVAL; + } + + *reg = wm_adsp_region_to_reg(mem, ctl->alg_region.base + ctl->offset); + + return 0; +} + static int wm_coeff_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -734,30 +780,94 @@ static int wm_coeff_info(struct snd_kcontrol *kctl, (struct soc_bytes_ext *)kctl->private_value; struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = ctl->len; + switch (ctl->type) { + case WMFW_CTL_TYPE_ACKED: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE; + uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE; + uinfo->value.integer.step = 1; + uinfo->count = 1; + break; + default: + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = ctl->len; + break; + } + return 0; } +static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl, + unsigned int event_id) +{ + struct wm_adsp *dsp = ctl->dsp; + u32 val = cpu_to_be32(event_id); + unsigned int reg; + int i, ret; + + ret = wm_coeff_base_reg(ctl, ®); + if (ret) + return ret; + + adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n", + event_id, ctl->alg_region.alg, + wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset); + + ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); + if (ret) { + adsp_err(dsp, "Failed to write %x: %d\n", reg, ret); + return ret; + } + + /* + * Poll for ack, we initially poll at ~1ms intervals for firmwares + * that respond quickly, then go to ~10ms polls. A firmware is unlikely + * to ack instantly so we do the first 1ms delay before reading the + * control to avoid a pointless bus transaction + */ + for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) { + switch (i) { + case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1: + usleep_range(1000, 2000); + i++; + break; + default: + usleep_range(10000, 20000); + i += 10; + break; + } + + ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); + if (ret) { + adsp_err(dsp, "Failed to read %x: %d\n", reg, ret); + return ret; + } + + if (val == 0) { + adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i); + return 0; + } + } + + adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n", + reg, ctl->alg_region.alg, + wm_adsp_mem_region_name(ctl->alg_region.type), + ctl->offset); + + return -ETIMEDOUT; +} + static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, const void *buf, size_t len) { - struct wm_adsp_alg_region *alg_region = &ctl->alg_region; - const struct wm_adsp_region *mem; struct wm_adsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - mem = wm_adsp_find_region(dsp, alg_region->type); - if (!mem) { - adsp_err(dsp, "No base for region %x\n", - alg_region->type); - return -EINVAL; - } - - reg = ctl->alg_region.base + ctl->offset; - reg = wm_adsp_region_to_reg(mem, reg); + ret = wm_coeff_base_reg(ctl, ®); + if (ret) + return ret; scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA); if (!scratch) @@ -823,25 +933,41 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, return ret; } +static int wm_coeff_put_acked(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + unsigned int val = ucontrol->value.integer.value[0]; + int ret; + + if (val == 0) + return 0; /* 0 means no event */ + + mutex_lock(&ctl->dsp->pwr_lock); + + if (ctl->enabled) + ret = wm_coeff_write_acked_control(ctl, val); + else + ret = -EPERM; + + mutex_unlock(&ctl->dsp->pwr_lock); + + return ret; +} + static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, void *buf, size_t len) { - struct wm_adsp_alg_region *alg_region = &ctl->alg_region; - const struct wm_adsp_region *mem; struct wm_adsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - mem = wm_adsp_find_region(dsp, alg_region->type); - if (!mem) { - adsp_err(dsp, "No base for region %x\n", - alg_region->type); - return -EINVAL; - } - - reg = ctl->alg_region.base + ctl->offset; - reg = wm_adsp_region_to_reg(mem, reg); + ret = wm_coeff_base_reg(ctl, ®); + if (ret) + return ret; scratch = kmalloc(len, GFP_KERNEL | GFP_DMA); if (!scratch) @@ -918,6 +1044,21 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, return ret; } +static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* + * Although it's not useful to read an acked control, we must satisfy + * user-side assumptions that all controls are readable and that a + * write of the same value should be filtered out (it's valid to send + * the same event number again to the firmware). We therefore return 0, + * meaning "no event" so valid event numbers will always be a change + */ + ucontrol->value.integer.value[0] = 0; + + return 0; +} + struct wmfw_ctl_work { struct wm_adsp *dsp; struct wm_coeff_ctl *ctl; @@ -967,30 +1108,35 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); if (!kcontrol) return -ENOMEM; - kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kcontrol->name = ctl->name; kcontrol->info = wm_coeff_info; - kcontrol->get = wm_coeff_get; - kcontrol->put = wm_coeff_put; kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kcontrol->tlv.c = snd_soc_bytes_tlv_callback; kcontrol->private_value = (unsigned long)&ctl->bytes_ext; + kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); - ctl->bytes_ext.max = ctl->len; - ctl->bytes_ext.get = wm_coeff_tlv_get; - ctl->bytes_ext.put = wm_coeff_tlv_put; + switch (ctl->type) { + case WMFW_CTL_TYPE_ACKED: + kcontrol->get = wm_coeff_get_acked; + kcontrol->put = wm_coeff_put_acked; + break; + default: + kcontrol->get = wm_coeff_get; + kcontrol->put = wm_coeff_put; - kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); + ctl->bytes_ext.max = ctl->len; + ctl->bytes_ext.get = wm_coeff_tlv_get; + ctl->bytes_ext.put = wm_coeff_tlv_put; + break; + } - ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); + ret = snd_soc_add_codec_controls(dsp->codec, kcontrol, 1); if (ret < 0) goto err_kcontrol; kfree(kcontrol); - ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, ctl->name); - return 0; err_kcontrol: @@ -1035,6 +1181,27 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp) return 0; } +static void wm_adsp_signal_event_controls(struct wm_adsp *dsp, + unsigned int event) +{ + struct wm_coeff_ctl *ctl; + int ret; + + list_for_each_entry(ctl, &dsp->ctl_list, list) { + if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT) + continue; + + if (!ctl->enabled) + continue; + + ret = wm_coeff_write_acked_control(ctl, event); + if (ret) + adsp_warn(dsp, + "Failed to send 0x%x event to alg 0x%x (%d)\n", + event, ctl->alg_region.alg, ret); + } +} + static void wm_adsp_ctl_work(struct work_struct *work) { struct wmfw_ctl_work *ctl_work = container_of(work, @@ -1056,34 +1223,16 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, const struct wm_adsp_alg_region *alg_region, unsigned int offset, unsigned int len, const char *subname, unsigned int subname_len, - unsigned int flags) + unsigned int flags, unsigned int type) { struct wm_coeff_ctl *ctl; struct wmfw_ctl_work *ctl_work; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - char *region_name; + const char *region_name; int ret; - if (flags & WMFW_CTL_FLAG_SYS) - return 0; - - switch (alg_region->type) { - case WMFW_ADSP1_PM: - region_name = "PM"; - break; - case WMFW_ADSP1_DM: - region_name = "DM"; - break; - case WMFW_ADSP2_XM: - region_name = "XM"; - break; - case WMFW_ADSP2_YM: - region_name = "YM"; - break; - case WMFW_ADSP1_ZM: - region_name = "ZM"; - break; - default: + region_name = wm_adsp_mem_region_name(alg_region->type); + if (!region_name) { adsp_err(dsp, "Unknown region type: %d\n", alg_region->type); return -EINVAL; } @@ -1139,6 +1288,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, ctl->dsp = dsp; ctl->flags = flags; + ctl->type = type; ctl->offset = offset; ctl->len = len; ctl->cache = kzalloc(ctl->len, GFP_KERNEL); @@ -1149,6 +1299,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, list_add(&ctl->list, &dsp->ctl_list); + if (flags & WMFW_CTL_FLAG_SYS) + return 0; + ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); if (!ctl_work) { ret = -ENOMEM; @@ -1308,6 +1461,21 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data, adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); } +static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp, + const struct wm_coeff_parsed_coeff *coeff_blk, + unsigned int f_required, + unsigned int f_illegal) +{ + if ((coeff_blk->flags & f_illegal) || + ((coeff_blk->flags & f_required) != f_required)) { + adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", + coeff_blk->flags, coeff_blk->ctl_type); + return -EINVAL; + } + + return 0; +} + static int wm_adsp_parse_coeff(struct wm_adsp *dsp, const struct wmfw_region *region) { @@ -1324,6 +1492,28 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp, switch (coeff_blk.ctl_type) { case SNDRV_CTL_ELEM_TYPE_BYTES: break; + case WMFW_CTL_TYPE_ACKED: + if (coeff_blk.flags & WMFW_CTL_FLAG_SYS) + continue; /* ignore */ + + ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, + WMFW_CTL_FLAG_VOLATILE | + WMFW_CTL_FLAG_WRITEABLE | + WMFW_CTL_FLAG_READABLE, + 0); + if (ret) + return -EINVAL; + break; + case WMFW_CTL_TYPE_HOSTEVENT: + ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, + WMFW_CTL_FLAG_SYS | + WMFW_CTL_FLAG_VOLATILE | + WMFW_CTL_FLAG_WRITEABLE | + WMFW_CTL_FLAG_READABLE, + 0); + if (ret) + return -EINVAL; + break; default: adsp_err(dsp, "Unknown control type: %d\n", coeff_blk.ctl_type); @@ -1338,7 +1528,8 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp, coeff_blk.len, coeff_blk.name, coeff_blk.name_len, - coeff_blk.flags); + coeff_blk.flags, + coeff_blk.ctl_type); if (ret < 0) adsp_err(dsp, "Failed to create control: %.*s, %d\n", coeff_blk.name_len, coeff_blk.name, ret); @@ -1491,23 +1682,11 @@ static int wm_adsp_load(struct wm_adsp *dsp) reg = offset; break; case WMFW_ADSP1_PM: - region_name = "PM"; - reg = wm_adsp_region_to_reg(mem, offset); - break; case WMFW_ADSP1_DM: - region_name = "DM"; - reg = wm_adsp_region_to_reg(mem, offset); - break; case WMFW_ADSP2_XM: - region_name = "XM"; - reg = wm_adsp_region_to_reg(mem, offset); - break; case WMFW_ADSP2_YM: - region_name = "YM"; - reg = wm_adsp_region_to_reg(mem, offset); - break; case WMFW_ADSP1_ZM: - region_name = "ZM"; + region_name = wm_adsp_mem_region_name(type); reg = wm_adsp_region_to_reg(mem, offset); break; default: @@ -1750,7 +1929,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp1_alg[i].dm); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region DM with ID %x\n", be32_to_cpu(adsp1_alg[i].alg.id)); @@ -1770,7 +1950,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp1_alg[i].zm); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", be32_to_cpu(adsp1_alg[i].alg.id)); @@ -1861,7 +2042,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp2_alg[i].xm); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region XM with ID %x\n", be32_to_cpu(adsp2_alg[i].alg.id)); @@ -1881,7 +2063,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp2_alg[i].ym); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region YM with ID %x\n", be32_to_cpu(adsp2_alg[i].alg.id)); @@ -1901,7 +2084,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp2_alg[i].zm); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", be32_to_cpu(adsp2_alg[i].alg.id)); @@ -2114,7 +2298,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, int ret; unsigned int val; - dsp->card = codec->component.card; + dsp->codec = codec; mutex_lock(&dsp->pwr_lock); @@ -2325,8 +2509,6 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, struct wm_adsp *dsp = &dsps[w->shift]; struct wm_coeff_ctl *ctl; - dsp->card = codec->component.card; - switch (event) { case SND_SOC_DAPM_PRE_PMU: wm_adsp2_set_dspclk(dsp, freq); @@ -2393,14 +2575,22 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, mutex_lock(&dsp->pwr_lock); - if (wm_adsp_fw[dsp->fw].num_caps != 0) + if (wm_adsp_fw[dsp->fw].num_caps != 0) { ret = wm_adsp_buffer_init(dsp); + if (ret < 0) { + mutex_unlock(&dsp->pwr_lock); + goto err; + } + } mutex_unlock(&dsp->pwr_lock); break; case SND_SOC_DAPM_PRE_PMD: + /* Tell the firmware to cleanup */ + wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); + /* Log firmware state, it can be useful for analysis */ wm_adsp2_show_fw_status(dsp); @@ -2441,6 +2631,8 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event); int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec) { + dsp->codec = codec; + wm_adsp2_init_debugfs(dsp, codec); return snd_soc_add_codec_controls(codec, diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 362dd7ce60d8..411d062c13f2 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -44,7 +44,7 @@ struct wm_adsp { int type; struct device *dev; struct regmap *regmap; - struct snd_soc_card *card; + struct snd_soc_codec *codec; int base; int sysclk_reg; @@ -110,18 +110,17 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -extern int wm_adsp_compr_open(struct wm_adsp *dsp, - struct snd_compr_stream *stream); -extern int wm_adsp_compr_free(struct snd_compr_stream *stream); -extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream, - struct snd_compr_params *params); -extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, - struct snd_compr_caps *caps); -extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); -extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); -extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp); -extern int wm_adsp_compr_copy(struct snd_compr_stream *stream, - char __user *buf, size_t count); +int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream); +int wm_adsp_compr_free(struct snd_compr_stream *stream); +int wm_adsp_compr_set_params(struct snd_compr_stream *stream, + struct snd_compr_params *params); +int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, + struct snd_compr_caps *caps); +int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); +int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); +int wm_adsp_compr_pointer(struct snd_compr_stream *stream, + struct snd_compr_tstamp *tstamp); +int wm_adsp_compr_copy(struct snd_compr_stream *stream, + char __user *buf, size_t count); #endif diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h index 7613d60d62ea..ec78b9da020f 100644 --- a/sound/soc/codecs/wmfw.h +++ b/sound/soc/codecs/wmfw.h @@ -26,6 +26,10 @@ #define WMFW_CTL_FLAG_WRITEABLE 0x0002 #define WMFW_CTL_FLAG_READABLE 0x0001 +/* Non-ALSA coefficient types start at 0x1000 */ +#define WMFW_CTL_TYPE_ACKED 0x1000 /* acked control */ +#define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */ + struct wmfw_header { char magic[4]; __le32 len; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 19bdcac71775..37f9b6201918 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -40,6 +40,7 @@ config SND_SOC_FSL_SPDIF select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC) + select BITREVERSE help Say Y if you want to add Sony/Philips Digital Interface (SPDIF) support for the Freescale CPUs. diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c index b2acd3293ea8..f200d1cfc4bd 100644 --- a/sound/soc/fsl/efika-audio-fabric.c +++ b/sound/soc/fsl/efika-audio-fabric.c @@ -27,7 +27,6 @@ #include "mpc5200_dma.h" #include "mpc5200_psc_ac97.h" -#include "../codecs/stac9766.h" #define DRV_NAME "efika-audio-fabric" diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index dffd549a0e2a..9998aea23597 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -183,7 +183,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops fsl_asoc_card_ops = { +static const struct snd_soc_ops fsl_asoc_card_ops = { .hw_params = fsl_asoc_card_hw_params, }; diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 201a70d1027a..1b60958e2080 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -61,7 +61,7 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops imx_hifi_ops = { +static const struct snd_soc_ops imx_hifi_ops = { .hw_params = imx_hifi_hw_params, }; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 1cb39309f5d5..cf026252cd4a 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -1,5 +1,5 @@ /* - * simple-card-core.c + * simple-card-utils.c * * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> * @@ -195,9 +195,6 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { - if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) - return -EINVAL; - /* Assumes platform == cpu */ if (!dai_link->platform_of_node) dai_link->platform_of_node = dai_link->cpu_of_node; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index f608f8d23f3d..a385ff6bfa4b 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -174,7 +174,7 @@ err: return ret; } -static struct snd_soc_ops asoc_simple_card_ops = { +static const struct snd_soc_ops asoc_simple_card_ops = { .startup = asoc_simple_card_startup, .shutdown = asoc_simple_card_shutdown, .hw_params = asoc_simple_card_hw_params, diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index b9973a56bcb0..bb86ee042490 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -22,7 +22,7 @@ #include <sound/soc-dai.h> #include <sound/simple_card_utils.h> -struct asoc_simple_card_priv { +struct simple_card_data { struct snd_soc_card snd_card; struct snd_soc_codec_conf codec_conf; struct asoc_simple_dai *dai_props; @@ -42,7 +42,7 @@ struct asoc_simple_card_priv { static int asoc_simple_card_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, rtd->num); @@ -52,21 +52,21 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, rtd->num); clk_disable_unprepare(dai_props->clk); } -static struct snd_soc_ops asoc_simple_card_ops = { +static const struct snd_soc_ops asoc_simple_card_ops = { .startup = asoc_simple_card_startup, .shutdown = asoc_simple_card_shutdown, }; static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai; struct snd_soc_dai_link *dai_link; struct asoc_simple_dai *dai_props; @@ -84,7 +84,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, @@ -101,8 +101,8 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static int asoc_simple_card_parse_links(struct device_node *np, - struct asoc_simple_card_priv *priv, +static int asoc_simple_card_dai_link_of(struct device_node *np, + struct simple_card_data *priv, unsigned int daifmt, int idx, bool is_fe) { @@ -195,22 +195,35 @@ static int asoc_simple_card_parse_links(struct device_node *np, return 0; } -static int asoc_simple_card_dai_link_of(struct device_node *node, - struct asoc_simple_card_priv *priv) +static int asoc_simple_card_parse_of(struct device_node *node, + struct simple_card_data *priv) + { struct device *dev = simple_priv_to_dev(priv); struct device_node *np; unsigned int daifmt = 0; - int ret, i; bool is_fe; + int ret, i; + + if (!node) + return -EINVAL; + + ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); + if (ret < 0) + return ret; + + /* sampling rate convert */ + of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate); + + /* channels transfer */ + of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels); /* find 1st codec */ np = of_get_child_by_name(node, PREFIX "codec"); if (!np) return -ENODEV; - ret = asoc_simple_card_parse_daifmt(dev, node, np, - PREFIX, &daifmt); + ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt); if (ret < 0) return ret; @@ -220,58 +233,12 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, if (strcmp(np->name, PREFIX "cpu") == 0) is_fe = true; - ret = asoc_simple_card_parse_links(np, priv, daifmt, i, is_fe); + ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe); if (ret < 0) return ret; i++; } - return 0; -} - -static int asoc_simple_card_parse_of(struct device_node *node, - struct asoc_simple_card_priv *priv, - struct device *dev) -{ - struct asoc_simple_dai *props; - struct snd_soc_dai_link *links; - int ret; - int num; - - if (!node) - return -EINVAL; - - num = of_get_child_count(node); - props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL); - links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL); - if (!props || !links) - return -ENOMEM; - - priv->dai_props = props; - priv->dai_link = links; - - /* Init snd_soc_card */ - priv->snd_card.owner = THIS_MODULE; - priv->snd_card.dev = dev; - priv->snd_card.dai_link = priv->dai_link; - priv->snd_card.num_links = num; - priv->snd_card.codec_conf = &priv->codec_conf; - priv->snd_card.num_configs = 1; - - ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); - if (ret < 0) - return ret; - - /* sampling rate convert */ - of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate); - - /* channels transfer */ - of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels); - - ret = asoc_simple_card_dai_link_of(node, priv); - if (ret < 0) - return ret; - ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); if (ret < 0) return ret; @@ -286,17 +253,37 @@ static int asoc_simple_card_parse_of(struct device_node *node, static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_priv *priv; - struct device_node *np = pdev->dev.of_node; + struct simple_card_data *priv; + struct snd_soc_dai_link *dai_link; + struct asoc_simple_dai *dai_props; struct device *dev = &pdev->dev; - int ret; + struct device_node *np = pdev->dev.of_node; + int num, ret; /* Allocate the private data */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - ret = asoc_simple_card_parse_of(np, priv, dev); + num = of_get_child_count(np); + + dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); + dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); + if (!dai_props || !dai_link) + return -ENOMEM; + + priv->dai_props = dai_props; + priv->dai_link = dai_link; + + /* Init snd_soc_card */ + priv->snd_card.owner = THIS_MODULE; + priv->snd_card.dev = dev; + priv->snd_card.dai_link = priv->dai_link; + priv->snd_card.num_links = num; + priv->snd_card.codec_conf = &priv->codec_conf; + priv->snd_card.num_configs = 1; + + ret = asoc_simple_card_parse_of(np, priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 26eb5a0a5575..fd5d1e091038 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -47,6 +47,7 @@ config SND_SOC_INTEL_SST_MATCH config SND_SOC_INTEL_HASWELL tristate + select SND_SOC_INTEL_SST_FIRMWARE config SND_SOC_INTEL_BAYTRAIL tristate @@ -56,7 +57,6 @@ config SND_SOC_INTEL_HASWELL_MACH depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM depends on DW_DMAC_CORE select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 help @@ -138,7 +138,6 @@ config SND_SOC_INTEL_BROADWELL_MACH I2C_DESIGNWARE_PLATFORM depends on DW_DMAC_CORE select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 help diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 0838478c4c3f..c7b3cbf92faf 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -937,7 +937,7 @@ int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) struct sst_data *drv = snd_soc_dai_get_drvdata(dai); int ssp_id; - dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); + dev_dbg(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); if (strcmp(id, "ssp0-port") == 0) ssp_id = SSP_MODEM; diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 25c6d87c818e..f5a8050351b5 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -771,6 +771,9 @@ static int sst_soc_prepare(struct device *dev) struct sst_data *drv = dev_get_drvdata(dev); struct snd_soc_pcm_runtime *rtd; + if (!drv->soc_card) + return 0; + /* suspend all pcms first */ snd_soc_suspend(drv->soc_card->dev); snd_soc_poweroff(drv->soc_card->dev); @@ -793,6 +796,9 @@ static void sst_soc_complete(struct device *dev) struct sst_data *drv = dev_get_drvdata(dev); struct snd_soc_pcm_runtime *rtd; + if (!drv->soc_card) + return; + /* restart SSPs */ list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { struct snd_soc_dai *dai = rtd->cpu_dai; diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 9b6e27385dc9..f9ba71315e33 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -27,6 +27,7 @@ #include <linux/pm_qos.h> #include <linux/async.h> #include <linux/acpi.h> +#include <linux/sysfs.h> #include <sound/core.h> #include <sound/soc.h> #include <asm/platform_sst_audio.h> @@ -242,6 +243,32 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx, } EXPORT_SYMBOL_GPL(sst_alloc_drv_context); +static ssize_t firmware_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + + if (ctx->fw_version.type == 0 && ctx->fw_version.major == 0 && + ctx->fw_version.minor == 0 && ctx->fw_version.build == 0) + return sprintf(buf, "FW not yet loaded\n"); + else + return sprintf(buf, "v%02x.%02x.%02x.%02x\n", + ctx->fw_version.type, ctx->fw_version.major, + ctx->fw_version.minor, ctx->fw_version.build); + +} + +DEVICE_ATTR_RO(firmware_version); + +static const struct attribute *sst_fw_version_attrs[] = { + &dev_attr_firmware_version.attr, + NULL, +}; + +static const struct attribute_group sst_fw_version_attr_group = { + .attrs = (struct attribute **)sst_fw_version_attrs, +}; + int sst_context_init(struct intel_sst_drv *ctx) { int ret = 0, i; @@ -315,8 +342,19 @@ int sst_context_init(struct intel_sst_drv *ctx) dev_err(ctx->dev, "Firmware download failed:%d\n", ret); goto do_free_mem; } + + ret = sysfs_create_group(&ctx->dev->kobj, + &sst_fw_version_attr_group); + if (ret) { + dev_err(ctx->dev, + "Unable to create sysfs\n"); + goto err_sysfs; + } + sst_register(ctx->dev); return 0; +err_sysfs: + sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group); do_free_mem: destroy_workqueue(ctx->post_msg_wq); @@ -330,6 +368,7 @@ void sst_context_cleanup(struct intel_sst_drv *ctx) pm_runtime_disable(ctx->dev); sst_unregister(ctx->dev); sst_set_fw_state_locked(ctx, SST_SHUTDOWN); + sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group); flush_scheduled_work(); destroy_workqueue(ctx->post_msg_wq); pm_qos_remove_request(ctx->qos); diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 3f493862e98d..5c9a51cc77aa 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -436,6 +436,7 @@ struct intel_sst_drv { */ char firmware_name[FW_NAME_SIZE]; + struct snd_sst_fw_version fw_version; struct sst_fw_save *fw_save; }; diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index ba5c0d71720a..f4d92bbc5373 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -416,6 +416,7 @@ static const struct dmi_system_id cht_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), }, }, + { } }; @@ -451,6 +452,8 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = { static struct sst_acpi_mach sst_acpi_chv[] = { {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, + {"10EC5672", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, + &chv_platform_data }, {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index bfc889950bb2..374bb61c596d 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -236,6 +236,17 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx, retval = init->result; goto ret; } + dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n", + init->fw_version.type, init->fw_version.major, + init->fw_version.minor, init->fw_version.build); + dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", + init->build_info.date, init->build_info.time); + + /* Save FW version */ + sst_drv_ctx->fw_version.type = init->fw_version.type; + sst_drv_ctx->fw_version.major = init->fw_version.major; + sst_drv_ctx->fw_version.minor = init->fw_version.minor; + sst_drv_ctx->fw_version.build = init->fw_version.build; ret: sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 4ccc80e5e8cc..51bdeeecb7c8 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -104,7 +104,7 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type, str_id, alloc_param.operation, 0); - dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", + dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", str_id, pipe_id); ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD, IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), @@ -415,7 +415,7 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) str_info->status = STREAM_UN_INIT; mutex_unlock(&str_info->lock); - dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", + dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", str_id, str_info->pipe_id); retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 7ab14ce65a73..260447da32b8 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -23,7 +23,6 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/kthread.h> #include <linux/firmware.h> #include <linux/io.h> #include <asm/div64.h> @@ -338,7 +337,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sst->spinlock, flags); /* continue to send any remaining messages... */ - kthread_queue_work(&ipc->kworker, &ipc->kwork); + schedule_work(&ipc->kwork); return IRQ_HANDLED; } diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 547e6705bf6d..53c6b4cbb1e1 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -156,7 +156,7 @@ static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops bdw_rt5677_ops = { +static const struct snd_soc_ops bdw_rt5677_ops = { .hw_params = bdw_rt5677_hw_params, }; diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 7486a0022fde..4d7e9decfa92 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -126,7 +126,7 @@ static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops broadwell_rt286_ops = { +static const struct snd_soc_ops broadwell_rt286_ops = { .hw_params = broadwell_rt286_hw_params, }; @@ -220,10 +220,12 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { }; static int broadwell_suspend(struct snd_soc_card *card){ - struct snd_soc_codec *codec; + struct snd_soc_component *component; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, "i2c-INT343A:00")) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-INT343A:00")) { dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); rt286_mic_detect(codec, NULL); break; @@ -233,10 +235,12 @@ static int broadwell_suspend(struct snd_soc_card *card){ } static int broadwell_resume(struct snd_soc_card *card){ - struct snd_soc_codec *codec; + struct snd_soc_component *component; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, "i2c-INT343A:00")) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-INT343A:00")) { dev_dbg(codec->dev, "enabling jack detect for resume.\n"); rt286_mic_detect(codec, &broadwell_headset); break; diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6532b8f0ab2f..1b4330cd2739 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -30,6 +30,7 @@ #define BXT_DIALOG_CODEC_DAI "da7219-hifi" #define BXT_MAXIM_CODEC_DAI "HiFi" #define DUAL_CHANNEL 2 +#define QUAD_CHANNEL 4 static struct snd_soc_jack broxton_headset; @@ -130,8 +131,8 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) */ ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &broxton_headset, - NULL, 0); + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &broxton_headset, NULL, 0); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -182,6 +183,16 @@ static struct snd_pcm_hw_constraint_list constraints_channels = { .mask = 0, }; +static unsigned int channels_quad[] = { + QUAD_CHANNEL, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels_quad = { + .count = ARRAY_SIZE(channels_quad), + .list = channels_quad, + .mask = 0, +}; + static int bxt_fe_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -248,7 +259,7 @@ static int broxton_da7219_hw_free(struct snd_pcm_substream *substream) return ret; } -static struct snd_soc_ops broxton_da7219_ops = { +static const struct snd_soc_ops broxton_da7219_ops = { .hw_params = broxton_da7219_hw_params, .hw_free = broxton_da7219_hw_free, }; @@ -258,7 +269,10 @@ static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - channels->min = channels->max = DUAL_CHANNEL; + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; return 0; } @@ -267,9 +281,9 @@ static int broxton_dmic_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - runtime->hw.channels_max = DUAL_CHANNEL; + runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); + &constraints_channels_quad); return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); @@ -295,7 +309,7 @@ static int broxton_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); }; -static struct snd_soc_ops broxton_refcap_ops = { +static const struct snd_soc_ops broxton_refcap_ops = { .startup = broxton_refcap_startup, }; @@ -348,7 +362,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .dynamic = 1, .ops = &broxton_refcap_ops, }, - [BXT_DPCM_AUDIO_DMIC_CP] + [BXT_DPCM_AUDIO_DMIC_CP] = { .name = "Bxt Audio DMIC cap", .stream_name = "dmiccap", diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index d610bdca1608..1309405b3808 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -181,7 +181,7 @@ static int broxton_rt298_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops broxton_rt298_ops = { +static const struct snd_soc_ops broxton_rt298_ops = { .hw_params = broxton_rt298_hw_params, }; @@ -230,7 +230,7 @@ static int broxton_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops broxton_dmic_ops = { +static const struct snd_soc_ops broxton_dmic_ops = { .startup = broxton_dmic_startup, }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index bff77a1f27fc..507a86a5eafe 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -57,9 +57,7 @@ struct byt_rt5640_private { struct clk *mclk; }; -static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | - BYT_RT5640_DMIC_EN | - BYT_RT5640_MCLK_EN; +static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN; static void log_quirks(struct device *dev) { @@ -597,11 +595,11 @@ static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops byt_rt5640_aif1_ops = { +static const struct snd_soc_ops byt_rt5640_aif1_ops = { .startup = byt_rt5640_aif1_startup, }; -static struct snd_soc_ops byt_rt5640_be_ssp2_ops = { +static const struct snd_soc_ops byt_rt5640_be_ssp2_ops = { .hw_params = byt_rt5640_aif1_hw_params, }; @@ -689,6 +687,10 @@ static bool is_valleyview(void) return true; } +struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ + u64 aif_value; /* 1: AIF1, 2: AIF2 */ + u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ +}; static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { @@ -698,6 +700,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) int i; int dai_index; struct byt_rt5640_private *priv; + bool is_bytcr = false; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); if (!priv) @@ -734,10 +737,61 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) struct sst_platform_info *p_info = mach->pdata; const struct sst_res_info *res_info = p_info->res_info; - /* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */ - if (res_info->acpi_ipc_irq_index == 0) { + if (res_info->acpi_ipc_irq_index == 0) + is_bytcr = true; + } + + if (is_bytcr) { + /* + * Baytrail CR platforms may have CHAN package in BIOS, try + * to find relevant routing quirk based as done on Windows + * platforms. We have to read the information directly from the + * BIOS, at this stage the card is not created and the links + * with the codec driver/pdata are non-existent + */ + + struct acpi_chan_package chan_package; + + /* format specified: 2 64-bit integers */ + struct acpi_buffer format = {sizeof("NN"), "NN"}; + struct acpi_buffer state = {0, NULL}; + struct sst_acpi_package_context pkg_ctx; + bool pkg_found = false; + + state.length = sizeof(chan_package); + state.pointer = &chan_package; + + pkg_ctx.name = "CHAN"; + pkg_ctx.length = 2; + pkg_ctx.format = &format; + pkg_ctx.state = &state; + pkg_ctx.data_valid = false; + + pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx); + if (pkg_found) { + if (chan_package.aif_value == 1) { + dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n"); + byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF1; + } else if (chan_package.aif_value == 2) { + dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); + byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; + } else { + dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n"); + pkg_found = false; + } + } + + if (!pkg_found) { + /* no BIOS indications, assume SSP0-AIF2 connection */ byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; } + + /* change defaults for Baytrail-CR capture */ + byt_rt5640_quirk |= BYT_RT5640_IN1_MAP; + byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; + } else { + byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP | + BYT_RT5640_DMIC_EN); } /* check quirks before creating card */ diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 35f591eab3c9..2d24dc04b597 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -219,11 +219,11 @@ static int byt_rt5651_aif1_startup(struct snd_pcm_substream *substream) &constraints_48000); } -static struct snd_soc_ops byt_rt5651_aif1_ops = { +static const struct snd_soc_ops byt_rt5651_aif1_ops = { .startup = byt_rt5651_aif1_startup, }; -static struct snd_soc_ops byt_rt5651_be_ssp2_ops = { +static const struct snd_soc_ops byt_rt5651_be_ssp2_ops = { .hw_params = byt_rt5651_aif1_hw_params, }; diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index cdcced9f32b6..742bc0d4e681 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -204,11 +204,11 @@ static int cht_max98090_headset_init(struct snd_soc_component *component) return ts3a227e_enable_jack_detect(component, &ctx->jack); } -static struct snd_soc_ops cht_aif1_ops = { +static const struct snd_soc_ops cht_aif1_ops = { .startup = cht_aif1_startup, }; -static struct snd_soc_ops cht_be_ssp2_ops = { +static const struct snd_soc_ops cht_be_ssp2_ops = { .hw_params = cht_aif1_hw_params, }; diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 56056ed7fcfd..f504a0e18f91 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -44,6 +44,7 @@ struct cht_acpi_card { struct cht_mc_private { struct snd_soc_jack jack; struct cht_acpi_card *acpi_card; + char codec_name[16]; }; static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) @@ -250,11 +251,11 @@ static int cht_aif1_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops cht_aif1_ops = { +static const struct snd_soc_ops cht_aif1_ops = { .startup = cht_aif1_startup, }; -static struct snd_soc_ops cht_be_ssp2_ops = { +static const struct snd_soc_ops cht_be_ssp2_ops = { .hw_params = cht_aif1_hw_params, }; @@ -354,7 +355,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int i; struct cht_mc_private *drv; struct snd_soc_card *card = snd_soc_cards[0].soc_card; - char codec_name[16]; struct sst_acpi_mach *mach; const char *i2c_name = NULL; int dai_index = 0; @@ -374,12 +374,12 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } card->dev = &pdev->dev; mach = card->dev->platform_data; - sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id); + sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id); /* set correct codec name */ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) { - card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL); + card->dai_link[i].codec_name = drv->codec_name; dai_index = i; } diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index df9d254baa18..e4d46d4360d7 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -25,12 +25,14 @@ #include <sound/jack.h> #include "../../codecs/rt5670.h" #include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h" /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ #define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_CODEC_DAI "rt5670-aif1" static struct snd_soc_jack cht_bsw_headset; +static char cht_bsw_codec_name[16]; /* Headset jack detection DAPM pins */ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { @@ -225,11 +227,11 @@ static int cht_aif1_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops cht_aif1_ops = { +static const struct snd_soc_ops cht_aif1_ops = { .startup = cht_aif1_startup, }; -static struct snd_soc_ops cht_be_ssp2_ops = { +static const struct snd_soc_ops cht_be_ssp2_ops = { .hw_params = cht_aif1_hw_params, }; @@ -292,10 +294,12 @@ static struct snd_soc_dai_link cht_dailink[] = { static int cht_suspend_pre(struct snd_soc_card *card) { - struct snd_soc_codec *codec; + struct snd_soc_component *component; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, "i2c-10EC5670:00")) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); rt5670_jack_suspend(codec); break; @@ -306,10 +310,12 @@ static int cht_suspend_pre(struct snd_soc_card *card) static int cht_resume_post(struct snd_soc_card *card) { - struct snd_soc_codec *codec; + struct snd_soc_component *component; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, "i2c-10EC5670:00")) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { dev_dbg(codec->dev, "enabling jack detect for resume.\n"); rt5670_jack_resume(codec); break; @@ -335,9 +341,33 @@ static struct snd_soc_card snd_soc_card_cht = { .resume_post = cht_resume_post, }; +#define RT5672_I2C_DEFAULT "i2c-10EC5670:00" + static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; + struct sst_acpi_mach *mach = pdev->dev.platform_data; + const char *i2c_name; + int i; + + strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT); + + /* fixup codec name based on HID */ + if (mach) { + i2c_name = sst_acpi_find_name_from_hid(mach->id); + if (i2c_name) { + snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name), + "i2c-%s", i2c_name); + for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { + if (!strcmp(cht_dailink[i].codec_name, + RT5672_I2C_DEFAULT)) { + cht_dailink[i].codec_name = + cht_bsw_codec_name; + break; + } + } + } + } /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 863f1d5e2a2c..5e1ea0371c90 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -81,7 +81,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops haswell_rt5640_ops = { +static const struct snd_soc_ops haswell_rt5640_ops = { .hw_params = haswell_rt5640_hw_params, }; diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c index 34f46c72a0e2..4e08885f37aa 100644 --- a/sound/soc/intel/boards/mfld_machine.c +++ b/sound/soc/intel/boards/mfld_machine.c @@ -81,9 +81,9 @@ static struct snd_soc_jack_zone mfld_zones[] = { }; /* sound card controls */ -static const char *headset_switch_text[] = {"Earpiece", "Headset"}; +static const char * const headset_switch_text[] = {"Earpiece", "Headset"}; -static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"}; +static const char * const lo_text[] = {"Vibra", "Headset", "IHF", "None"}; static const struct soc_enum headset_enum = SOC_ENUM_SINGLE_EXT(2, headset_switch_text); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 25db5be7fdfa..fddd1cd12f13 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -332,7 +332,7 @@ static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops skylake_nau8825_ops = { +static const struct snd_soc_ops skylake_nau8825_ops = { .hw_params = skylake_nau8825_hw_params, }; @@ -382,7 +382,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops skylake_dmic_ops = { +static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; @@ -416,7 +416,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylaye_refcap_ops = { .startup = skylake_refcap_startup, }; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 69c5d5da4e86..8ab865ee0cad 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -394,7 +394,7 @@ static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops skylake_nau8825_ops = { +static const struct snd_soc_ops skylake_nau8825_ops = { .hw_params = skylake_nau8825_hw_params, }; @@ -430,7 +430,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops skylake_dmic_ops = { +static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; @@ -464,7 +464,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylaye_refcap_ops = { .startup = skylake_refcap_startup, }; diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 88c61e8cb87f..dc5c3611a6ff 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -250,7 +250,7 @@ static int skylake_rt286_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops skylake_rt286_ops = { +static const struct snd_soc_ops skylake_rt286_ops = { .hw_params = skylake_rt286_hw_params, }; @@ -289,7 +289,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops skylake_dmic_ops = { +static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 012742299dd5..214e000667ae 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h @@ -15,14 +15,29 @@ #include <linux/stddef.h> #include <linux/acpi.h> -/* translation fron HID to I2C name, needed for DAI codec_name */ +struct sst_acpi_package_context { + char *name; /* package name */ + int length; /* number of elements */ + struct acpi_buffer *format; + struct acpi_buffer *state; + bool data_valid; +}; + #if IS_ENABLED(CONFIG_ACPI) +/* translation fron HID to I2C name, needed for DAI codec_name */ const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); +bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], + struct sst_acpi_package_context *ctx); #else static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) { return NULL; } +static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], + struct sst_acpi_package_context *ctx) +{ + return false; +} #endif /* acpi match */ diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 6c672ac79cce..62f3a8e0ec87 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -26,7 +26,6 @@ #include <linux/sched.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/kthread.h> #include <sound/asound.h> #include "sst-dsp.h" @@ -109,10 +108,9 @@ static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header, ipc->ops.tx_data_copy(msg, tx_data, tx_bytes); list_add_tail(&msg->list, &ipc->tx_list); + schedule_work(&ipc->kwork); spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - kthread_queue_work(&ipc->kworker, &ipc->kwork); - if (wait) return tx_wait_done(ipc, msg, rx_data); else @@ -156,42 +154,56 @@ free_mem: return -ENOMEM; } -static void ipc_tx_msgs(struct kthread_work *work) +static void ipc_tx_msgs(struct work_struct *work) { struct sst_generic_ipc *ipc = container_of(work, struct sst_generic_ipc, kwork); struct ipc_message *msg; - unsigned long flags; - spin_lock_irqsave(&ipc->dsp->spinlock, flags); + spin_lock_irq(&ipc->dsp->spinlock); - if (list_empty(&ipc->tx_list) || ipc->pending) { - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return; - } - - /* if the DSP is busy, we will TX messages after IRQ. - * also postpone if we are in the middle of procesing completion irq*/ - if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { - dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return; - } + while (!list_empty(&ipc->tx_list) && !ipc->pending) { + /* if the DSP is busy, we will TX messages after IRQ. + * also postpone if we are in the middle of processing + * completion irq + */ + if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { + dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); + break; + } - msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); - list_move(&msg->list, &ipc->rx_list); + msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); + list_move(&msg->list, &ipc->rx_list); - if (ipc->ops.tx_msg != NULL) - ipc->ops.tx_msg(ipc, msg); + if (ipc->ops.tx_msg != NULL) + ipc->ops.tx_msg(ipc, msg); + } - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); + spin_unlock_irq(&ipc->dsp->spinlock); } int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) { - return ipc_tx_message(ipc, header, tx_data, tx_bytes, + int ret; + + /* + * DSP maybe in lower power active state, so + * check if the DSP supports DSP lp On method + * if so invoke that before sending IPC + */ + if (ipc->ops.check_dsp_lp_on) + if (ipc->ops.check_dsp_lp_on(ipc->dsp, true)) + return -EIO; + + ret = ipc_tx_message(ipc, header, tx_data, tx_bytes, rx_data, rx_bytes, 1); + + if (ipc->ops.check_dsp_lp_on) + if (ipc->ops.check_dsp_lp_on(ipc->dsp, false)) + return -EIO; + + return ret; } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); @@ -203,6 +215,14 @@ int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, + void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) +{ + return ipc_tx_message(ipc, header, tx_data, tx_bytes, + rx_data, rx_bytes, 1); +} +EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm); + struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, u64 header) { @@ -280,19 +300,7 @@ int sst_ipc_init(struct sst_generic_ipc *ipc) if (ret < 0) return -ENOMEM; - /* start the IPC message thread */ - kthread_init_worker(&ipc->kworker); - ipc->tx_thread = kthread_run(kthread_worker_fn, - &ipc->kworker, "%s", - dev_name(ipc->dev)); - if (IS_ERR(ipc->tx_thread)) { - dev_err(ipc->dev, "error: failed to create message TX task\n"); - ret = PTR_ERR(ipc->tx_thread); - kfree(ipc->msg); - return ret; - } - - kthread_init_work(&ipc->kwork, ipc_tx_msgs); + INIT_WORK(&ipc->kwork, ipc_tx_msgs); return 0; } EXPORT_SYMBOL_GPL(sst_ipc_init); @@ -301,8 +309,7 @@ void sst_ipc_fini(struct sst_generic_ipc *ipc) { int i; - if (ipc->tx_thread) - kthread_stop(ipc->tx_thread); + cancel_work_sync(&ipc->kwork); if (ipc->msg) { for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index ceb7e468a3fa..7ed42a640ad6 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -23,7 +23,6 @@ #include <linux/list.h> #include <linux/workqueue.h> #include <linux/sched.h> -#include <linux/kthread.h> #define IPC_MAX_MAILBOX_BYTES 256 @@ -52,6 +51,7 @@ struct sst_plat_ipc_ops { void (*tx_data_copy)(struct ipc_message *, char *, size_t); u64 (*reply_msg_match)(u64 header, u64 *mask); bool (*is_dsp_busy)(struct sst_dsp *dsp); + int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state); }; /* SST generic IPC data */ @@ -65,8 +65,7 @@ struct sst_generic_ipc { struct list_head empty_list; wait_queue_head_t wait_txq; struct task_struct *tx_thread; - struct kthread_worker kworker; - struct kthread_work kwork; + struct work_struct kwork; bool pending; struct ipc_message *msg; int tx_data_max_size; @@ -81,6 +80,9 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, void *tx_data, size_t tx_bytes); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, + void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); + struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, u64 header); diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index 789843307a49..1070f3ad23e5 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -77,5 +77,62 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) } EXPORT_SYMBOL_GPL(sst_acpi_find_machine); +static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level, + void *context, void **ret) +{ + struct acpi_device *adev; + acpi_status status = AE_OK; + struct sst_acpi_package_context *pkg_ctx = context; + + pkg_ctx->data_valid = false; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (adev->status.present && adev->status.functional) { + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *myobj = NULL; + + status = acpi_evaluate_object_typed(handle, pkg_ctx->name, + NULL, &buffer, + ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) + return AE_OK; + + myobj = buffer.pointer; + if (!myobj || myobj->package.count != pkg_ctx->length) { + kfree(buffer.pointer); + return AE_OK; + } + + status = acpi_extract_package(myobj, + pkg_ctx->format, pkg_ctx->state); + if (ACPI_FAILURE(status)) { + kfree(buffer.pointer); + return AE_OK; + } + + kfree(buffer.pointer); + pkg_ctx->data_valid = true; + return AE_CTRL_TERMINATE; + } + + return AE_OK; +} + +bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], + struct sst_acpi_package_context *ctx) +{ + acpi_status status; + + status = acpi_get_devices(hid, sst_acpi_find_package, ctx, NULL); + + if (ACPI_FAILURE(status) || !ctx->data_valid) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index e432a31fd9f2..a3459d1682a6 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -26,7 +26,6 @@ #include <linux/delay.h> #include <linux/sched.h> #include <linux/platform_device.h> -#include <linux/kthread.h> #include <linux/firmware.h> #include <linux/dma-mapping.h> #include <linux/debugfs.h> @@ -818,7 +817,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sst->spinlock, flags); /* continue to send any remaining messages... */ - kthread_queue_work(&ipc->kworker, &ipc->kwork); + schedule_work(&ipc->kwork); return IRQ_HANDLED; } diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 1d251d59bcb9..1f9f33d34000 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -43,6 +43,9 @@ #define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 +/* Delay before scheduling D0i3 entry */ +#define BXT_D0I3_DELAY 5000 + static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) { return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); @@ -288,6 +291,141 @@ sst_load_base_firmware_failed: return ret; } +/* + * Decide the D0i3 state that can be targeted based on the usecase + * ref counts and DSP state + * + * Decision Matrix: (X= dont care; state = target state) + * + * DSP state != SKL_DSP_RUNNING ; state = no d0i3 + * + * DSP state == SKL_DSP_RUNNING , the following matrix applies + * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3 + * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3 + * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3 + * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3 + */ +static int bxt_d0i3_target_state(struct sst_dsp *ctx) +{ + struct skl_sst *skl = ctx->thread_context; + struct skl_d0i3_data *d0i3 = &skl->d0i3; + + if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING) + return SKL_DSP_D0I3_NONE; + + if (d0i3->non_d0i3) + return SKL_DSP_D0I3_NONE; + else if (d0i3->streaming) + return SKL_DSP_D0I3_STREAMING; + else if (d0i3->non_streaming) + return SKL_DSP_D0I3_NON_STREAMING; + else + return SKL_DSP_D0I3_NONE; +} + +static void bxt_set_dsp_D0i3(struct work_struct *work) +{ + int ret; + struct skl_ipc_d0ix_msg msg; + struct skl_sst *skl = container_of(work, + struct skl_sst, d0i3.work.work); + struct sst_dsp *ctx = skl->dsp; + struct skl_d0i3_data *d0i3 = &skl->d0i3; + int target_state; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + + /* D0i3 entry allowed only if core 0 alone is running */ + if (skl_dsp_get_enabled_cores(ctx) != SKL_DSP_CORE0_MASK) { + dev_warn(ctx->dev, + "D0i3 allowed when only core0 running:Exit\n"); + return; + } + + target_state = bxt_d0i3_target_state(ctx); + if (target_state == SKL_DSP_D0I3_NONE) + return; + + msg.instance_id = 0; + msg.module_id = 0; + msg.wake = 1; + msg.streaming = 0; + if (target_state == SKL_DSP_D0I3_STREAMING) + msg.streaming = 1; + + ret = skl_ipc_set_d0ix(&skl->ipc, &msg); + + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n"); + return; + } + + /* Set Vendor specific register D0I3C.I3 to enable D0i3*/ + if (skl->update_d0i3c) + skl->update_d0i3c(skl->dev, true); + + d0i3->state = target_state; + skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3; +} + +static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx) +{ + struct skl_sst *skl = ctx->thread_context; + struct skl_d0i3_data *d0i3 = &skl->d0i3; + + /* Schedule D0i3 only if the usecase ref counts are appropriate */ + if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) { + + dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__); + + schedule_delayed_work(&d0i3->work, + msecs_to_jiffies(BXT_D0I3_DELAY)); + } + + return 0; +} + +static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) +{ + int ret; + struct skl_ipc_d0ix_msg msg; + struct skl_sst *skl = ctx->thread_context; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + + /* First Cancel any pending attempt to put DSP to D0i3 */ + cancel_delayed_work_sync(&skl->d0i3.work); + + /* If DSP is currently in D0i3, bring it to D0i0 */ + if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3) + return 0; + + dev_dbg(ctx->dev, "Set DSP to D0i0\n"); + + msg.instance_id = 0; + msg.module_id = 0; + msg.streaming = 0; + msg.wake = 0; + + if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING) + msg.streaming = 1; + + /* Clear Vendor specific register D0I3C.I3 to disable D0i3*/ + if (skl->update_d0i3c) + skl->update_d0i3c(skl->dev, false); + + ret = skl_ipc_set_d0ix(&skl->ipc, &msg); + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D0i0\n"); + return ret; + } + + skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; + skl->d0i3.state = SKL_DSP_D0I3_NONE; + + return 0; +} + static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) { struct skl_sst *skl = ctx->thread_context; @@ -414,6 +552,8 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) static struct skl_dsp_fw_ops bxt_fw_ops = { .set_state_D0 = bxt_set_dsp_D0, .set_state_D3 = bxt_set_dsp_D3, + .set_state_D0i3 = bxt_schedule_dsp_D0i3, + .set_state_D0i0 = bxt_set_dsp_D0i0, .load_fw = bxt_load_base_firmware, .get_fw_errcode = bxt_get_errorcode, .load_library = bxt_load_library, @@ -470,10 +610,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, if (ret) return ret; + /* set the D0i3 check */ + skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0; + skl->cores.count = 2; skl->boot_complete = false; init_waitqueue_head(&skl->boot_wait); skl->is_first_boot = true; + INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); + skl->d0i3.state = SKL_DSP_D0I3_NONE; if (dsp) *dsp = skl; diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 805b7f2173f3..e79cbcf6e462 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -294,6 +294,33 @@ int skl_free_dsp(struct skl *skl) return 0; } +/* + * In the case of "suspend_active" i.e, the Audio IP being active + * during system suspend, immediately excecute any pending D0i3 work + * before suspending. This is needed for the IP to work in low power + * mode during system suspend. In the case of normal suspend, cancel + * any pending D0i3 work. + */ +int skl_suspend_late_dsp(struct skl *skl) +{ + struct skl_sst *ctx = skl->skl_sst; + struct delayed_work *dwork; + + if (!ctx) + return 0; + + dwork = &ctx->d0i3.work; + + if (dwork->work.func) { + if (skl->supend_active) + flush_delayed_work(dwork); + else + cancel_delayed_work_sync(dwork); + } + + return 0; +} + int skl_suspend_dsp(struct skl *skl) { struct skl_sst *ctx = skl->skl_sst; @@ -500,16 +527,14 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) { struct skl_dma_control *dma_ctrl; - struct skl_i2s_config_blob config_blob; struct skl_ipc_large_config_msg msg = {0}; int err = 0; /* - * if blob size is same as capablity size, then no dma control - * present so return + * if blob size zero, then return */ - if (mconfig->formats_config.caps_size == sizeof(config_blob)) + if (mconfig->formats_config.caps_size == 0) return 0; msg.large_param_id = DMA_CONTROL_ID; @@ -523,7 +548,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) dma_ctrl->node_id = skl_get_node_id(ctx, mconfig); /* size in dwords */ - dma_ctrl->config_length = sizeof(config_blob) / 4; + dma_ctrl->config_length = mconfig->formats_config.caps_size / 4; memcpy(dma_ctrl->config_data, mconfig->formats_config.caps, mconfig->formats_config.caps_size); @@ -531,7 +556,6 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl); kfree(dma_ctrl); - return err; } @@ -1042,7 +1066,8 @@ int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe) dev_dbg(ctx->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); ret = skl_ipc_create_pipeline(&ctx->ipc, pipe->memory_pages, - pipe->pipe_priority, pipe->ppl_id); + pipe->pipe_priority, pipe->ppl_id, + pipe->lp_mode); if (ret < 0) { dev_err(ctx->dev, "Failed to create pipeline\n"); return ret; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 58c728662600..84b5101e6ca6 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -144,6 +144,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream; struct snd_pcm_runtime *runtime = substream->runtime; struct skl_dma_params *dma_params; + struct skl *skl = get_skl_ctx(dai->dev); + struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -177,6 +179,9 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, skl_set_suspend_active(substream, dai, true); snd_pcm_set_sync(substream); + mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); + skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); + return 0; } @@ -302,6 +307,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; struct skl *skl = ebus_to_skl(ebus); + struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -325,6 +331,9 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, skl->skl_sst->miscbdcg_disabled = false; } + mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); + skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); + kfree(dma_params); } @@ -1031,10 +1040,24 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer (struct snd_pcm_substream *substream) { struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); + struct hdac_ext_bus *ebus = get_bus_ctx(substream); unsigned int pos; - /* use the position buffer as default */ - pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); + /* + * Use DPIB for Playback stream as the periodic DMA Position-in- + * Buffer Writes may be scheduled at the same time or later than + * the MSI and does not guarantee to reflect the Position of the + * last buffer that was transferred. Whereas DPIB register in + * HAD space reflects the actual data that is transferred. + * Use the position buffer for capture, as DPIB write gets + * completed earlier than the actual data written to the DDR. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(hstream)->index)); + else + pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); if (pos >= hdac_stream(hstream)->bufsize) pos = 0; @@ -1197,6 +1220,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) return ret; } skl_populate_modules(skl); + skl->skl_sst->update_d0i3c = skl_update_d0i3c; } pm_runtime_mark_last_busy(platform->dev); pm_runtime_put_autosuspend(platform->dev); diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index efa2532114ba..c9f6d87381db 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -17,7 +17,6 @@ #include <linux/device.h> #include <linux/mm.h> -#include <linux/kthread.h> #include <linux/delay.h> #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index b9e71d051fb1..7c272ba0f4b5 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -126,11 +126,21 @@ struct sst_dsp_device; #define SKL_ADSPCS_CPA_SHIFT 24 #define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT) +/* DSP Core state */ enum skl_dsp_states { SKL_DSP_RUNNING = 1, + /* Running in D0i3 state; can be in streaming or non-streaming D0i3 */ + SKL_DSP_RUNNING_D0I3, /* Running in D0i3 state*/ SKL_DSP_RESET, }; +/* D0i3 substates */ +enum skl_dsp_d0i3_states { + SKL_DSP_D0I3_NONE = -1, /* No D0i3 */ + SKL_DSP_D0I3_NON_STREAMING = 0, + SKL_DSP_D0I3_STREAMING = 1, +}; + struct skl_dsp_fw_ops { int (*load_fw)(struct sst_dsp *ctx); /* FW module parser/loader */ @@ -139,6 +149,8 @@ struct skl_dsp_fw_ops { int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); + int (*set_state_D0i3)(struct sst_dsp *ctx); + int (*set_state_D0i0)(struct sst_dsp *ctx); unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name); int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 797cf4053235..e1391dfbc9e9 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -81,6 +81,11 @@ #define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ << IPC_INSTANCE_ID_SHIFT) +#define IPC_PPL_LP_MODE_SHIFT 0 +#define IPC_PPL_LP_MODE_MASK 0x1 +#define IPC_PPL_LP_MODE(x) (((x) & IPC_PPL_LP_MODE_MASK) \ + << IPC_PPL_LP_MODE_SHIFT) + /* Set pipeline state message */ #define IPC_PPL_STATE_SHIFT 0 #define IPC_PPL_STATE_MASK 0x1F @@ -172,6 +177,17 @@ << IPC_INITIAL_BLOCK_SHIFT) #define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ << IPC_INITIAL_BLOCK_SHIFT) +/* Set D0ix IPC extension register */ +#define IPC_D0IX_WAKE_SHIFT 0 +#define IPC_D0IX_WAKE_MASK 0x1 +#define IPC_D0IX_WAKE(x) (((x) & IPC_D0IX_WAKE_MASK) \ + << IPC_D0IX_WAKE_SHIFT) + +#define IPC_D0IX_STREAMING_SHIFT 1 +#define IPC_D0IX_STREAMING_MASK 0x1 +#define IPC_D0IX_STREAMING(x) (((x) & IPC_D0IX_STREAMING_MASK) \ + << IPC_D0IX_STREAMING_SHIFT) + enum skl_ipc_msg_target { IPC_FW_GEN_MSG = 0, @@ -258,7 +274,8 @@ enum skl_ipc_module_msg { IPC_MOD_LARGE_CONFIG_SET = 4, IPC_MOD_BIND = 5, IPC_MOD_UNBIND = 6, - IPC_MOD_SET_DX = 7 + IPC_MOD_SET_DX = 7, + IPC_MOD_SET_D0IX = 8 }; static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, @@ -289,6 +306,23 @@ static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) header->primary | SKL_ADSP_REG_HIPCI_BUSY); } +int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state) +{ + int ret; + + /* check D0i3 support */ + if (!dsp->fw_ops.set_state_D0i0) + return 0; + + /* Attempt D0i0 or D0i3 based on state */ + if (state) + ret = dsp->fw_ops.set_state_D0i0(dsp); + else + ret = dsp->fw_ops.set_state_D0i3(dsp); + + return ret; +} + static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, u64 ipc_header) { @@ -464,7 +498,7 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) skl_ipc_int_enable(dsp); /* continue to send any remaining messages... */ - kthread_queue_work(&ipc->kworker, &ipc->kwork); + schedule_work(&ipc->kwork); return IRQ_HANDLED; } @@ -547,7 +581,7 @@ void skl_ipc_free(struct sst_generic_ipc *ipc) } int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id) + u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode) { struct skl_ipc_header header = {0}; u64 *ipc_header = (u64 *)(&header); @@ -560,6 +594,8 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, header.primary |= IPC_PPL_TYPE(ppl_type); header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); + header.extension = IPC_PPL_LP_MODE(lp_mode); + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); if (ret < 0) { @@ -931,3 +967,32 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, return ret; } EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); + +int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_D0IX_WAKE(msg->wake); + header.extension |= IPC_D0IX_STREAMING(msg->streaming); + + dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__, + header.primary, header.extension); + + /* + * Use the nopm IPC here as we dont want it checking for D0iX + */ + ret = sst_ipc_tx_message_nopm(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) + dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 0334ed4af031..cc40341233fa 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -16,7 +16,6 @@ #ifndef __SKL_IPC_H #define __SKL_IPC_H -#include <linux/kthread.h> #include <linux/irqreturn.h> #include "../common/sst-ipc.h" @@ -53,6 +52,23 @@ struct skl_dsp_cores { int usage_count[SKL_DSP_CORES_MAX]; }; +/** + * skl_d0i3_data: skl D0i3 counters data struct + * + * @streaming: Count of usecases that can attempt streaming D0i3 + * @non_streaming: Count of usecases that can attempt non-streaming D0i3 + * @non_d0i3: Count of usecases that cannot attempt D0i3 + * @state: current state + * @work: D0i3 worker thread + */ +struct skl_d0i3_data { + int streaming; + int non_streaming; + int non_d0i3; + enum skl_dsp_d0i3_states state; + struct delayed_work work; +}; + struct skl_sst { struct device *dev; struct sst_dsp *dsp; @@ -83,6 +99,11 @@ struct skl_sst { /* tplg manifest */ struct skl_dfw_manifest manifest; + + /* Callback to update D0i3C register */ + void (*update_d0i3c)(struct device *dev, bool enable); + + struct skl_d0i3_data d0i3; }; struct skl_ipc_init_instance_msg { @@ -111,6 +132,13 @@ struct skl_ipc_large_config_msg { u32 param_data_size; }; +struct skl_ipc_d0ix_msg { + u32 module_id; + u32 instance_id; + u8 streaming; + u8 wake; +}; + #define SKL_IPC_BOOT_MSECS 3000 #define SKL_IPC_D3_MASK 0 @@ -119,7 +147,7 @@ struct skl_ipc_large_config_msg { irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context); int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id); + u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode); int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id); @@ -155,6 +183,11 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, u8 dma_id, u8 table_id); +int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, + struct skl_ipc_d0ix_msg *msg); + +int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state); + void skl_ipc_int_enable(struct sst_dsp *dsp); void skl_ipc_op_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_disable(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index 8dc03039b311..ea162fbf68e5 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -179,7 +179,7 @@ static inline int skl_getid_32(struct uuid_module *module, u64 *val, index = ffz(mask_val); pvt_id = index + word1_mask + word2_mask; if (pvt_id <= (max_inst - 1)) { - *val |= 1 << (index + word1_mask); + *val |= 1ULL << (index + word1_mask); return pvt_id; } } diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b5b1934d8550..bd313c907b20 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -36,6 +36,44 @@ #define SKL_IN_DIR_BIT_MASK BIT(0) #define SKL_PIN_COUNT_MASK GENMASK(7, 4) +void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) +{ + struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + + switch (caps) { + case SKL_D0I3_NONE: + d0i3->non_d0i3++; + break; + + case SKL_D0I3_STREAMING: + d0i3->streaming++; + break; + + case SKL_D0I3_NON_STREAMING: + d0i3->non_streaming++; + break; + } +} + +void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps) +{ + struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + + switch (caps) { + case SKL_D0I3_NONE: + d0i3->non_d0i3--; + break; + + case SKL_D0I3_STREAMING: + d0i3->streaming--; + break; + + case SKL_D0I3_NON_STREAMING: + d0i3->non_streaming--; + break; + } +} + /* * SKL DSP driver modelling uses only few DAPM widgets so for rest we will * ignore. This helpers checks if the SKL driver handles this widget type @@ -1519,6 +1557,10 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev, pipe->memory_pages = tkn_val; break; + case SKL_TKN_U32_PMODE: + pipe->lp_mode = tkn_val; + break; + default: dev_err(dev, "Token not handled %d\n", tkn); return -EINVAL; @@ -1826,6 +1868,10 @@ static int skl_tplg_get_token(struct device *dev, mconfig->converter = tkn_elem->value; break; + case SKL_TKL_U32_D0I3_CAPS: + mconfig->d0i3_caps = tkn_elem->value; + break; + case SKL_TKN_U32_PIPE_ID: ret = skl_tplg_add_pipe(dev, mconfig, skl, tkn_elem); @@ -1841,6 +1887,7 @@ static int skl_tplg_get_token(struct device *dev, case SKL_TKN_U32_PIPE_CONN_TYPE: case SKL_TKN_U32_PIPE_PRIORITY: case SKL_TKN_U32_PIPE_MEM_PGS: + case SKL_TKN_U32_PMODE: if (is_pipe_exists) { ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, tkn_elem->token, tkn_elem->value); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index a519360f42a6..08d39280b07b 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -113,23 +113,6 @@ struct skl_cpr_gtw_cfg { u32 config_data[1]; } __packed; -struct skl_i2s_config_blob { - u32 gateway_attrib; - u32 tdm_ts_group[8]; - u32 ssc0; - u32 ssc1; - u32 sscto; - u32 sspsp; - u32 sstsa; - u32 ssrsa; - u32 ssc2; - u32 sspsp2; - u32 ssc3; - u32 ssioc; - u32 mdivc; - u32 mdivr; -} __packed; - struct skl_dma_control { u32 node_id; u32 config_length; @@ -279,6 +262,7 @@ struct skl_pipe { u8 pipe_priority; u16 conn_type; u32 memory_pages; + u8 lp_mode; struct skl_pipe_params *p_params; enum skl_pipe_state state; struct list_head w_list; @@ -293,6 +277,12 @@ enum skl_module_state { SKL_MODULE_UNLOADED = 4, }; +enum d0i3_capability { + SKL_D0I3_NONE = 0, + SKL_D0I3_STREAMING = 1, + SKL_D0I3_NON_STREAMING = 2, +}; + struct skl_module_cfg { u8 guid[16]; struct skl_module_inst_id id; @@ -319,6 +309,7 @@ struct skl_module_cfg { u32 converter; u32 vbus_id; u32 mem_pages; + enum d0i3_capability d0i3_caps; struct skl_module_pin *m_in_pin; struct skl_module_pin *m_out_pin; enum skl_module_type m_type; @@ -361,6 +352,9 @@ struct skl_module_cfg *skl_tplg_fe_get_cpr_module( int skl_tplg_update_pipe_params(struct device *dev, struct skl_module_cfg *mconfig, struct skl_pipe_params *params); +void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps); +void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps); + int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe); int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 2989c164dafe..da5db5098274 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -26,6 +26,7 @@ #include <linux/pm_runtime.h> #include <linux/platform_device.h> #include <linux/firmware.h> +#include <linux/delay.h> #include <sound/pcm.h> #include "../common/sst-acpi.h" #include <sound/hda_register.h> @@ -109,6 +110,52 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset) return ret; } +void skl_update_d0i3c(struct device *dev, bool enable) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + u8 reg; + int timeout = 50; + + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + /* Do not write to D0I3C until command in progress bit is cleared */ + while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { + udelay(10); + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + } + + /* Highly unlikely. But if it happens, flag error explicitly */ + if (!timeout) { + dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n"); + return; + } + + if (enable) + reg = reg | AZX_REG_VS_D0I3C_I3; + else + reg = reg & (~AZX_REG_VS_D0I3C_I3); + + snd_hdac_chip_writeb(bus, VS_D0I3C, reg); + + timeout = 50; + /* Wait for cmd in progress to be cleared before exiting the function */ + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { + udelay(10); + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + } + + /* Highly unlikely. But if it happens, flag error explicitly */ + if (!timeout) { + dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n"); + return; + } + + dev_dbg(bus->dev, "D0I3C register = 0x%x\n", + snd_hdac_chip_readb(bus, VS_D0I3C)); +} + /* called from IRQ */ static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) { @@ -181,6 +228,15 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect) return 0; } +static int skl_suspend_late(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); + + return skl_suspend_late_dsp(skl); +} + #ifdef CONFIG_PM static int _skl_suspend(struct hdac_ext_bus *ebus) { @@ -243,7 +299,6 @@ static int skl_suspend(struct device *dev) enable_irq_wake(bus->irq); pci_save_state(pci); - pci_disable_device(pci); } else { ret = _skl_suspend(ebus); if (ret < 0) @@ -286,7 +341,6 @@ static int skl_resume(struct device *dev) */ if (skl->supend_active) { pci_restore_state(pci); - ret = pci_enable_device(pci); snd_hdac_ext_bus_link_power_up_all(ebus); disable_irq_wake(bus->irq); /* @@ -345,6 +399,7 @@ static int skl_runtime_resume(struct device *dev) static const struct dev_pm_ops skl_pm = { SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume) SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL) + .suspend_late = skl_suspend_late, }; /* @@ -674,7 +729,7 @@ static int skl_probe(struct pci_dev *pci, if (skl->nhlt == NULL) { err = -ENODEV; - goto out_free; + goto out_display_power_off; } skl_nhlt_update_topology_bin(skl); @@ -746,6 +801,9 @@ out_mach_free: skl_machine_device_unregister(skl); out_nhlt_free: skl_nhlt_free(skl->nhlt); +out_display_power_off: + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, false); out_free: skl->init_failed = 1; skl_free(ebus); @@ -785,8 +843,7 @@ static void skl_remove(struct pci_dev *pci) release_firmware(skl->tplg); - if (pci_dev_run_wake(pci)) - pm_runtime_get_noresume(&pci->dev); + pm_runtime_get_noresume(&pci->dev); /* codec removal, invoke bus_device_remove */ snd_hdac_ext_bus_device_remove(ebus); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 5d4fbb094c48..4986e3929dd3 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -52,6 +52,9 @@ #define AZX_PGCTL_LSRMD_MASK (1 << 4) #define AZX_PCIREG_CGCTL 0x48 #define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) +/* D0I3C Register fields */ +#define AZX_REG_VS_D0I3C_CIP 0x1 /* Command in progress */ +#define AZX_REG_VS_D0I3C_I3 0x4 /* D0i3 enable */ struct skl_dsp_resource { u32 max_mcps; @@ -121,8 +124,11 @@ int skl_get_dmic_geo(struct skl *skl); int skl_nhlt_update_topology_bin(struct skl *skl); int skl_init_dsp(struct skl *skl); int skl_free_dsp(struct skl *skl); +int skl_suspend_late_dsp(struct skl *skl); int skl_suspend_dsp(struct skl *skl); int skl_resume_dsp(struct skl *skl); void skl_cleanup_resources(struct skl *skl); const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); +void skl_update_d0i3c(struct device *dev, bool enable); + #endif /* __SOUND_SOC_SKL_H */ diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c index e0304d544f26..677a48d7b891 100644 --- a/sound/soc/kirkwood/armada-370-db.c +++ b/sound/soc/kirkwood/armada-370-db.c @@ -42,7 +42,7 @@ static int a370db_hw_params(struct snd_pcm_substream *substream, return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); } -static struct snd_soc_ops a370db_ops = { +static const struct snd_soc_ops a370db_ops = { .hw_params = a370db_hw_params, }; diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 13631003cb7c..a002ab892772 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -735,6 +735,11 @@ static int mxs_saif_probe(struct platform_device *pdev) else saif->id = ret; + if (saif->id >= ARRAY_SIZE(mxs_saif)) { + dev_err(&pdev->dev, "get wrong saif id\n"); + return -EINVAL; + } + /* * If there is no "fsl,saif-master" phandle, it's a saif * master. Otherwise, it's a slave and its phandle points @@ -749,11 +754,11 @@ static int mxs_saif_probe(struct platform_device *pdev) return ret; else saif->master_id = ret; - } - if (saif->master_id >= ARRAY_SIZE(mxs_saif)) { - dev_err(&pdev->dev, "get wrong master id\n"); - return -EINVAL; + if (saif->master_id >= ARRAY_SIZE(mxs_saif)) { + dev_err(&pdev->dev, "get wrong master id\n"); + return -EINVAL; + } } mxs_saif[saif->id] = saif; diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 2b23ffbac6b1..a96276e77332 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -68,7 +68,7 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops mxs_sgtl5000_hifi_ops = { +static const struct snd_soc_ops mxs_sgtl5000_hifi_ops = { .hw_params = mxs_sgtl5000_hw_params, }; diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index f2bf8661dd21..823b5a236d8d 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -208,7 +208,7 @@ config SND_PXA2XX_SOC_IMOTE2 config SND_MMP_SOC_BROWNSTONE tristate "SoC Audio support for Marvell Brownstone" - depends on SND_MMP_SOC && MACH_BROWNSTONE + depends on SND_MMP_SOC && MACH_BROWNSTONE && I2C select SND_MMP_SOC_SSPA select MFD_WM8994 select SND_SOC_WM8994 diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index dcbb7aa9830c..311774e9ca46 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -244,9 +244,9 @@ static const struct snd_soc_dapm_route corgi_audio_map[] = { {"MICIN", NULL, "Line Jack"}, }; -static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", - "Off"}; -static const char *spk_function[] = {"On", "Off"}; +static const char * const jack_function[] = {"Headphone", "Mic", "Line", + "Headset", "Off"}; +static const char * const spk_function[] = {"On", "Off"}; static const struct soc_enum corgi_enum[] = { SOC_ENUM_SINGLE_EXT(5, jack_function), SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c index ecbf2873b7ff..85483049b916 100644 --- a/sound/soc/pxa/hx4700.c +++ b/sound/soc/pxa/hx4700.c @@ -27,8 +27,6 @@ #include <asm/mach-types.h> #include "pxa2xx-i2s.h" -#include "../codecs/ak4641.h" - static struct snd_soc_jack hs_jack; /* Headphones jack detection DAPM pin */ diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 62b8377a9d2b..2d4d4455fe87 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -376,7 +376,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"VINM", NULL, "Call Mic"}, }; -static const char *input_select[] = {"Call Mic", "Headset Mic"}; +static const char * const input_select[] = {"Call Mic", "Headset Mic"}; static const struct soc_enum magician_in_sel_enum = SOC_ENUM_SINGLE_EXT(2, input_select); diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index d1661fa6ee08..0fe0abec8fc4 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c @@ -187,7 +187,7 @@ static int mioa701_wm9713_probe(struct platform_device *pdev) mioa701.dev = &pdev->dev; rc = devm_snd_soc_register_card(&pdev->dev, &mioa701); if (!rc) - dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will" + dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will " "lead to overheating and possible destruction of your device." " Do not use without a good knowledge of mio's board design!\n"); return rc; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 4b3b714f5ee7..a879aba0691f 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -209,8 +209,8 @@ static const struct snd_soc_dapm_route poodle_audio_map[] = { {"MICIN", NULL, "Microphone"}, }; -static const char *jack_function[] = {"Off", "Headphone"}; -static const char *spk_function[] = {"Off", "On"}; +static const char * const jack_function[] = {"Off", "Headphone"}; +static const char * const spk_function[] = {"Off", "On"}; static const struct soc_enum poodle_enum[] = { SOC_ENUM_SINGLE_EXT(2, jack_function), SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h index bc79da221c0d..abf6ec080258 100644 --- a/sound/soc/pxa/pxa-ssp.h +++ b/sound/soc/pxa/pxa-ssp.h @@ -9,12 +9,6 @@ #ifndef _PXA_SSP_H #define _PXA_SSP_H -/* pxa DAI SSP IDs */ -#define PXA_DAI_SSP1 0 -#define PXA_DAI_SSP2 1 -#define PXA_DAI_SSP3 2 -#define PXA_DAI_SSP4 3 - /* SSP clock sources */ #define PXA_SSP_CLK_PLL 0 #define PXA_SSP_CLK_EXT 1 diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h index 070f3c6059fe..7e218e2105a9 100644 --- a/sound/soc/pxa/pxa2xx-i2s.h +++ b/sound/soc/pxa/pxa2xx-i2s.h @@ -9,9 +9,6 @@ #ifndef _PXA2XX_I2S_H #define _PXA2XX_I2S_H -/* pxa2xx DAI ID's */ -#define PXA2XX_DAI_I2S 0 - /* I2S clock */ #define PXA2XX_I2S_SYSCLK 0 diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 0e02634c8b7f..07d77cddac60 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -241,9 +241,9 @@ static const struct snd_soc_dapm_route spitz_audio_map[] = { {"LINPUT1", NULL, "Line Jack"}, }; -static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", - "Off"}; -static const char *spk_function[] = {"On", "Off"}; +static const char * const jack_function[] = {"Headphone", "Mic", "Line", + "Headset", "Off"}; +static const char * const spk_function[] = {"On", "Off"}; static const struct soc_enum spitz_enum[] = { SOC_ENUM_SINGLE_EXT(5, jack_function), SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index c508f024ecfb..08b0cf50e91a 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -170,9 +170,9 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Mic Bias", NULL, "Headset Jack"}, }; -static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", - "Off"}; -static const char *spk_function[] = {"On", "Off"}; +static const char * const jack_function[] = {"Headphone", "Mic", "Line", + "Headset", "Off"}; +static const char * const spk_function[] = {"On", "Off"}; static const struct soc_enum tosa_enum[] = { SOC_ENUM_SINGLE_EXT(5, jack_function), SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 07f91e918b23..d084d7468299 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -123,20 +123,15 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) return ERR_PTR(-EINVAL); } - link->codec_of_node = of_parse_phandle(codec, "sound-dai", 0); - if (!link->codec_of_node) { - dev_err(card->dev, "error getting codec phandle\n"); - return ERR_PTR(-EINVAL); - } - ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name); if (ret) { dev_err(card->dev, "error getting cpu dai name\n"); return ERR_PTR(ret); } - ret = snd_soc_of_get_dai_name(codec, &link->codec_dai_name); - if (ret) { + ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + + if (ret < 0) { dev_err(card->dev, "error getting codec dai name\n"); return ERR_PTR(ret); } diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 3cde9fb977fa..eff3f9a8b685 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -586,3 +586,6 @@ int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) return 0; } EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); + +MODULE_DESCRIPTION("QTi LPASS CPU Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index e2ff538a8aa5..dd5bdd0da730 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -25,8 +25,7 @@ #include "lpass.h" struct lpass_pcm_data { - int rdma_ch; - int wrdma_ch; + int dma_ch; int i2s_port; }; @@ -61,7 +60,41 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - int ret; + struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + struct lpass_variant *v = drvdata->variant; + int ret, dma_ch, dir = substream->stream; + struct lpass_pcm_data *data; + + data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->i2s_port = cpu_dai->driver->id; + runtime->private_data = data; + + dma_ch = 0; + if (v->alloc_dma_channel) + dma_ch = v->alloc_dma_channel(drvdata, dir); + else + dma_ch = 0; + + if (dma_ch < 0) + return dma_ch; + + drvdata->substream[dma_ch] = substream; + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_DMACTL_REG(v, dma_ch, dir), 0); + if (ret) { + dev_err(soc_runtime->dev, + "%s() error writing to rdmactl reg: %d\n", + __func__, ret); + return ret; + } + + data->dma_ch = dma_ch; snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware); @@ -80,13 +113,32 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) return 0; } +static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + struct lpass_variant *v = drvdata->variant; + struct lpass_pcm_data *data; + + data = runtime->private_data; + v = drvdata->variant; + drvdata->substream[data->dma_ch] = NULL; + if (v->free_dma_channel) + v->free_dma_channel(drvdata, data->dma_ch); + + return 0; +} + static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); @@ -95,10 +147,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, int bitwidth; int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ch = pcm_data->rdma_ch; - else - ch = pcm_data->wrdma_ch; + ch = pcm_data->dma_ch; bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { @@ -179,16 +228,13 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; unsigned int reg; int ret; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - reg = LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch); - else - reg = LPAIF_WRDMACTL_REG(v, pcm_data->wrdma_ch); - + reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream); ret = regmap_write(drvdata->lpaif_map, reg, 0); if (ret) dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", @@ -203,14 +249,12 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; int ret, ch, dir = substream->stream; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ch = pcm_data->rdma_ch; - else - ch = pcm_data->wrdma_ch; + ch = pcm_data->dma_ch; ret = regmap_write(drvdata->lpaif_map, LPAIF_DMABASE_REG(v, ch, dir), @@ -257,14 +301,12 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; int ret, ch, dir = substream->stream; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ch = pcm_data->rdma_ch; - else - ch = pcm_data->wrdma_ch; + ch = pcm_data->dma_ch; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -333,15 +375,13 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *pcm_data = drvdata->private_data; + struct snd_pcm_runtime *rt = substream->runtime; + struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; unsigned int base_addr, curr_addr; int ret, ch, dir = substream->stream; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ch = pcm_data->rdma_ch; - else - ch = pcm_data->wrdma_ch; + ch = pcm_data->dma_ch; ret = regmap_read(drvdata->lpaif_map, LPAIF_DMABASE_REG(v, ch, dir), &base_addr); @@ -374,6 +414,7 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream, static const struct snd_pcm_ops lpass_platform_pcm_ops = { .open = lpass_platform_pcmops_open, + .close = lpass_platform_pcmops_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = lpass_platform_pcmops_hw_params, .hw_free = lpass_platform_pcmops_hw_free, @@ -470,117 +511,45 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) { struct snd_pcm *pcm = soc_runtime->pcm; struct snd_pcm_substream *psubstream, *csubstream; - struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; - struct lpass_data *drvdata = - snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_variant *v = drvdata->variant; int ret = -EINVAL; - struct lpass_pcm_data *data; size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; - data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->i2s_port = cpu_dai->driver->id; - drvdata->private_data = data; - psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (psubstream) { - if (v->alloc_dma_channel) - data->rdma_ch = v->alloc_dma_channel(drvdata, - SNDRV_PCM_STREAM_PLAYBACK); - - if (data->rdma_ch < 0) - return data->rdma_ch; - - drvdata->substream[data->rdma_ch] = psubstream; - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, soc_runtime->platform->dev, size, &psubstream->dma_buffer); - if (ret) - goto playback_alloc_err; - - ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, data->rdma_ch), 0); if (ret) { - dev_err(soc_runtime->dev, - "%s() error writing to rdmactl reg: %d\n", - __func__, ret); - goto capture_alloc_err; + dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); + return ret; } } csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; if (csubstream) { - if (v->alloc_dma_channel) - data->wrdma_ch = v->alloc_dma_channel(drvdata, - SNDRV_PCM_STREAM_CAPTURE); - - if (data->wrdma_ch < 0) { - ret = data->wrdma_ch; - goto capture_alloc_err; - } - - drvdata->substream[data->wrdma_ch] = csubstream; - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, soc_runtime->platform->dev, size, &csubstream->dma_buffer); - if (ret) - goto capture_alloc_err; - - ret = regmap_write(drvdata->lpaif_map, - LPAIF_WRDMACTL_REG(v, data->wrdma_ch), 0); if (ret) { - dev_err(soc_runtime->dev, - "%s() error writing to wrdmactl reg: %d\n", - __func__, ret); - goto capture_reg_err; + dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); + if (psubstream) + snd_dma_free_pages(&psubstream->dma_buffer); + return ret; } + } return 0; - -capture_reg_err: - if (csubstream) - snd_dma_free_pages(&csubstream->dma_buffer); - -capture_alloc_err: - if (psubstream) - snd_dma_free_pages(&psubstream->dma_buffer); - - playback_alloc_err: - dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); - - return ret; } static void lpass_platform_pcm_free(struct snd_pcm *pcm) { - struct snd_soc_pcm_runtime *rt; - struct lpass_data *drvdata; - struct lpass_pcm_data *data; - struct lpass_variant *v; struct snd_pcm_substream *substream; - int ch, i; + int i; for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { substream = pcm->streams[i].substream; if (substream) { - rt = substream->private_data; - drvdata = snd_soc_platform_get_drvdata(rt->platform); - data = drvdata->private_data; - - ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ? data->rdma_ch - : data->wrdma_ch; - v = drvdata->variant; - drvdata->substream[ch] = NULL; - if (v->free_dma_channel) - v->free_dma_channel(drvdata, ch); - snd_dma_free_pages(&substream->dma_buffer); substream->dma_buffer.area = NULL; substream->dma_buffer.addr = 0; diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 35b3cea8207d..924971b6ded5 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -59,7 +59,6 @@ struct lpass_data { struct clk *pcnoc_mport_clk; struct clk *pcnoc_sway_clk; - void *private_data; }; /* Vairant data per each SOC */ diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c index 2d833bffdba0..8fcac2ac3aa6 100644 --- a/sound/soc/qcom/storm.c +++ b/sound/soc/qcom/storm.c @@ -58,7 +58,7 @@ static int storm_ops_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops storm_soc_ops = { +static const struct snd_soc_ops storm_soc_ops = { .hw_params = storm_ops_hw_params, }; diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 9ed735a6cf49..3475c61a5fa0 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -38,7 +38,7 @@ #define SOUND_FS 256 -unsigned int rt5514_dmic_delay; +static unsigned int rt5514_dmic_delay; static struct snd_soc_jack rockchip_sound_jack; @@ -228,15 +228,15 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static struct snd_soc_ops rockchip_sound_max98357a_ops = { +static const struct snd_soc_ops rockchip_sound_max98357a_ops = { .hw_params = rockchip_sound_max98357a_hw_params, }; -static struct snd_soc_ops rockchip_sound_rt5514_ops = { +static const struct snd_soc_ops rockchip_sound_rt5514_ops = { .hw_params = rockchip_sound_rt5514_hw_params, }; -static struct snd_soc_ops rockchip_sound_da7219_ops = { +static const struct snd_soc_ops rockchip_sound_da7219_ops = { .hw_params = rockchip_sound_da7219_hw_params, }; diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index e70ffad07184..789d6f1e2b5f 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -119,7 +119,7 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops rk_aif1_ops = { +static const struct snd_soc_ops rk_aif1_ops = { .hw_params = rk_aif1_hw_params, }; diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 440a8026346a..9e0c17805807 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -135,7 +135,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime) &headset_jack); } -static struct snd_soc_ops rk_aif1_ops = { +static const struct snd_soc_ops rk_aif1_ops = { .hw_params = rk_aif1_hw_params, }; diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index f6023b46c107..7c423151ef7d 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,6 +1,7 @@ menuconfig SND_SOC_SAMSUNG tristate "ASoC support for Samsung" - depends on (PLAT_SAMSUNG || ARCH_EXYNOS) + depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST + depends on COMMON_CLK select SND_SOC_GENERIC_DMAENGINE_PCM ---help--- Say Y or M if you want to add support for codecs attached to @@ -22,10 +23,6 @@ config SND_S3C2412_SOC_I2S config SND_SAMSUNG_PCM tristate "Samsung PCM interface support" -config SND_SAMSUNG_AC97 - tristate - select SND_SOC_AC97_BUS - config SND_SAMSUNG_SPDIF tristate "Samsung SPDIF transmitter support" select SND_SOC_SPDIF @@ -53,7 +50,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" - depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 + depends on MACH_SMDK6410 || COMPILE_TEST depends on I2C select SND_SOC_WM8580 select SND_SAMSUNG_I2S @@ -69,26 +66,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8994 help Say Y if you want to add support for SoC audio on the SMDKs. -config SND_SOC_SAMSUNG_SMDK2443_WM9710 - tristate "SoC AC97 Audio support for SMDK2443 - WM9710" - depends on MACH_SMDK2443 - select AC97_BUS - select SND_SOC_AC97_CODEC - select SND_SAMSUNG_AC97 - help - Say Y if you want to add support for SoC audio on smdk2443 - with the WM9710. - -config SND_SOC_SAMSUNG_LN2440SBC_ALC650 - tristate "SoC AC97 Audio support for LN2440SBC - ALC650" - depends on ARCH_S3C24XX - select AC97_BUS - select SND_SOC_AC97_CODEC - select SND_SAMSUNG_AC97 - help - Say Y if you want to add support for SoC audio on ln2440sbc - with the ALC650. - config SND_SOC_SAMSUNG_S3C24XX_UDA134X tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" depends on ARCH_S3C24XX @@ -131,17 +108,10 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 help This driver provides audio support for HP iPAQ RX1950 PDA. -config SND_SOC_SAMSUNG_SMDK_WM9713 - tristate "SoC AC97 Audio support for SMDK with WM9713" - depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 - select SND_SOC_WM9713 - select SND_SAMSUNG_AC97 - help - Say Y if you want to add support for SoC audio on the SMDK. - config SND_SOC_SMARTQ tristate "SoC I2S Audio support for SmartQ board" - depends on MACH_SMARTQ && I2C + depends on MACH_SMARTQ || COMPILE_TEST + depends on I2C select SND_SAMSUNG_I2S select SND_SOC_WM8750 @@ -151,15 +121,6 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF help Say Y if you want to add support for SoC S/PDIF audio on the SMDK. -config SND_SOC_SMDK_WM8580_PCM - tristate "SoC PCM Audio support for WM8580 on SMDK" - depends on MACH_SMDKV210 || MACH_SMDKC110 - depends on I2C - select SND_SOC_WM8580 - select SND_SAMSUNG_PCM - help - Say Y if you want to add support for SoC audio on the SMDK. - config SND_SOC_SMDK_WM8994_PCM tristate "SoC PCM Audio support for WM8994 on SMDK" depends on I2C=y @@ -229,4 +190,13 @@ config SND_SOC_ARNDALE_RT5631_ALC5631 select SND_SAMSUNG_I2S select SND_SOC_RT5631 +config SND_SOC_SAMSUNG_TM2_WM5110 + tristate "SoC I2S Audio support for WM5110 on TM2 board" + depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER + select SND_SOC_MAX98504 + select SND_SOC_WM5110 + select SND_SAMSUNG_I2S + help + Say Y if you want to add support for SoC audio on the TM2 board. + endif #SND_SOC_SAMSUNG diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 5d03f5ce6916..b5df5e2e3d94 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -3,7 +3,6 @@ snd-soc-s3c-dma-objs := dmaengine.o snd-soc-idma-objs := idma.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o -snd-soc-ac97-objs := ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o snd-soc-samsung-spdif-objs := spdif.o snd-soc-pcm-objs := pcm.o @@ -11,7 +10,6 @@ snd-soc-i2s-objs := i2s.o obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c-dma.o obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o -obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o @@ -36,7 +34,6 @@ snd-soc-snow-objs := snow.o snd-soc-smdk-wm9713-objs := smdk_wm9713.o snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o snd-soc-smdk-spdif-objs := smdk_spdif.o -snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o snd-soc-speyside-objs := speyside.o snd-soc-tobermory-objs := tobermory.o @@ -44,11 +41,10 @@ snd-soc-lowland-objs := lowland.o snd-soc-littlemill-objs := littlemill.o snd-soc-bells-objs := bells.o snd-soc-arndale-rt5631-objs := arndale_rt5631.o +snd-soc-tm2-wm5110-objs := tm2_wm5110.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o -obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o -obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o @@ -58,10 +54,8 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o -obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o -obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o @@ -69,3 +63,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o +obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c deleted file mode 100644 index 97d6700b1009..000000000000 --- a/sound/soc/samsung/ac97.c +++ /dev/null @@ -1,437 +0,0 @@ -/* sound/soc/samsung/ac97.c - * - * ALSA SoC Audio Layer - S3C AC97 Controller driver - * Evolved from s3c2443-ac97.c - * - * Copyright (c) 2010 Samsung Electronics Co. Ltd - * Author: Jaswinder Singh <jassisinghbrar@gmail.com> - * Credits: Graeme Gregory, Sean Choi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/module.h> - -#include <sound/soc.h> - -#include "regs-ac97.h" -#include <linux/platform_data/asoc-s3c.h> - -#include "dma.h" - -#define AC_CMD_ADDR(x) (x << 16) -#define AC_CMD_DATA(x) (x & 0xffff) - -#define S3C_AC97_DAI_PCM 0 -#define S3C_AC97_DAI_MIC 1 - -struct s3c_ac97_info { - struct clk *ac97_clk; - void __iomem *regs; - struct mutex lock; - struct completion done; -}; -static struct s3c_ac97_info s3c_ac97; - -static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_out = { - .addr_width = 4, -}; - -static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_in = { - .addr_width = 4, -}; - -static struct snd_dmaengine_dai_dma_data s3c_ac97_mic_in = { - .addr_width = 4, -}; - -static void s3c_ac97_activate(struct snd_ac97 *ac97) -{ - u32 ac_glbctrl, stat; - - stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; - if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) - return; /* Return if already active */ - - reinit_completion(&s3c_ac97.done); - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) - pr_err("AC97: Unable to activate!\n"); -} - -static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) -{ - u32 ac_glbctrl, ac_codec_cmd; - u32 stat, addr, data; - - mutex_lock(&s3c_ac97.lock); - - s3c_ac97_activate(ac97); - - reinit_completion(&s3c_ac97.done); - - ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); - ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); - writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); - - udelay(50); - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) - pr_err("AC97: Unable to read!\n"); - - stat = readl(s3c_ac97.regs + S3C_AC97_STAT); - addr = (stat >> 16) & 0x7f; - data = (stat & 0xffff); - - if (addr != reg) - pr_err("ac97: req addr = %02x, rep addr = %02x\n", - reg, addr); - - mutex_unlock(&s3c_ac97.lock); - - return (unsigned short)data; -} - -static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) -{ - u32 ac_glbctrl, ac_codec_cmd; - - mutex_lock(&s3c_ac97.lock); - - s3c_ac97_activate(ac97); - - reinit_completion(&s3c_ac97.done); - - ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); - ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); - writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); - - udelay(50); - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) - pr_err("AC97: Unable to write!\n"); - - ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); - ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; - writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); - - mutex_unlock(&s3c_ac97.lock); -} - -static void s3c_ac97_cold_reset(struct snd_ac97 *ac97) -{ - pr_debug("AC97: Cold reset\n"); - writel(S3C_AC97_GLBCTRL_COLDRESET, - s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); -} - -static void s3c_ac97_warm_reset(struct snd_ac97 *ac97) -{ - u32 stat; - - stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; - if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) - return; /* Return if already active */ - - pr_debug("AC97: Warm reset\n"); - - writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - s3c_ac97_activate(ac97); -} - -static irqreturn_t s3c_ac97_irq(int irq, void *dev_id) -{ - u32 ac_glbctrl, ac_glbstat; - - ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT); - - if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) { - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - complete(&s3c_ac97.done); - } - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= (1<<30); /* Clear interrupt */ - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - return IRQ_HANDLED; -} - -static struct snd_ac97_bus_ops s3c_ac97_ops = { - .read = s3c_ac97_read, - .write = s3c_ac97_write, - .warm_reset = s3c_ac97_warm_reset, - .reset = s3c_ac97_cold_reset, -}; - -static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - u32 ac_glbctrl; - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; - else - ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; - else - ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA; - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - break; - } - - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - return 0; -} - -static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - u32 ac_glbctrl; - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA; - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - break; - } - - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - return 0; -} - -static const struct snd_soc_dai_ops s3c_ac97_dai_ops = { - .trigger = s3c_ac97_trigger, -}; - -static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { - .trigger = s3c_ac97_mic_trigger, -}; - -static int s3c_ac97_dai_probe(struct snd_soc_dai *dai) -{ - snd_soc_dai_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in); - - return 0; -} - -static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai) -{ - snd_soc_dai_init_dma_data(dai, NULL, &s3c_ac97_mic_in); - - return 0; -} - -static struct snd_soc_dai_driver s3c_ac97_dai[] = { - [S3C_AC97_DAI_PCM] = { - .name = "samsung-ac97", - .bus_control = true, - .playback = { - .stream_name = "AC97 Playback", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .stream_name = "AC97 Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .probe = s3c_ac97_dai_probe, - .ops = &s3c_ac97_dai_ops, - }, - [S3C_AC97_DAI_MIC] = { - .name = "samsung-ac97-mic", - .bus_control = true, - .capture = { - .stream_name = "AC97 Mic Capture", - .channels_min = 1, - .channels_max = 1, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .probe = s3c_ac97_mic_dai_probe, - .ops = &s3c_ac97_mic_dai_ops, - }, -}; - -static const struct snd_soc_component_driver s3c_ac97_component = { - .name = "s3c-ac97", -}; - -static int s3c_ac97_probe(struct platform_device *pdev) -{ - struct resource *mem_res, *irq_res; - struct s3c_audio_pdata *ac97_pdata; - int ret; - - ac97_pdata = pdev->dev.platform_data; - if (!ac97_pdata || !ac97_pdata->cfg_gpio) { - dev_err(&pdev->dev, "cfg_gpio callback not provided!\n"); - return -EINVAL; - } - - /* Check for availability of necessary resource */ - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq_res) { - dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); - return -ENXIO; - } - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res); - if (IS_ERR(s3c_ac97.regs)) - return PTR_ERR(s3c_ac97.regs); - - s3c_ac97_pcm_out.filter_data = ac97_pdata->dma_playback; - s3c_ac97_pcm_out.addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_pcm_in.filter_data = ac97_pdata->dma_capture; - s3c_ac97_pcm_in.addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_mic_in.filter_data = ac97_pdata->dma_capture_mic; - s3c_ac97_mic_in.addr = mem_res->start + S3C_AC97_MIC_DATA; - - init_completion(&s3c_ac97.done); - mutex_init(&s3c_ac97.lock); - - s3c_ac97.ac97_clk = devm_clk_get(&pdev->dev, "ac97"); - if (IS_ERR(s3c_ac97.ac97_clk)) { - dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n"); - ret = -ENODEV; - goto err2; - } - clk_prepare_enable(s3c_ac97.ac97_clk); - - if (ac97_pdata->cfg_gpio(pdev)) { - dev_err(&pdev->dev, "Unable to configure gpio\n"); - ret = -EINVAL; - goto err3; - } - - ret = request_irq(irq_res->start, s3c_ac97_irq, - 0, "AC97", NULL); - if (ret < 0) { - dev_err(&pdev->dev, "ac97: interrupt request failed.\n"); - goto err4; - } - - ret = snd_soc_set_ac97_ops(&s3c_ac97_ops); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret); - goto err4; - } - - ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component, - s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); - if (ret) - goto err5; - - ret = samsung_asoc_dma_platform_register(&pdev->dev, - ac97_pdata->dma_filter, - NULL, NULL); - if (ret) { - dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); - goto err5; - } - - return 0; -err5: - free_irq(irq_res->start, NULL); -err4: -err3: - clk_disable_unprepare(s3c_ac97.ac97_clk); -err2: - snd_soc_set_ac97_ops(NULL); - return ret; -} - -static int s3c_ac97_remove(struct platform_device *pdev) -{ - struct resource *irq_res; - - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (irq_res) - free_irq(irq_res->start, NULL); - - clk_disable_unprepare(s3c_ac97.ac97_clk); - snd_soc_set_ac97_ops(NULL); - - return 0; -} - -static struct platform_driver s3c_ac97_driver = { - .probe = s3c_ac97_probe, - .remove = s3c_ac97_remove, - .driver = { - .name = "samsung-ac97", - }, -}; - -module_platform_driver(s3c_ac97_driver); - -MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>"); -MODULE_DESCRIPTION("AC97 driver for the Samsung SoC"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:samsung-ac97"); diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 9104c98deeb7..cda656e4afc6 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -37,12 +37,8 @@ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, pcm_conf->prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; pcm_conf->compat_filter_fn = filter; - if (dev->of_node) { - pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; - pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx; - } else { - flags |= SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME; - } + pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; + pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx; return devm_snd_dmaengine_pcm_register(dev, pcm_conf, flags); } diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 7e32cf4581f8..e00974bc5616 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1029,12 +1029,13 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) { struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); + unsigned long flags; if (!is_secondary(i2s)) { if (i2s->quirks & QUIRK_NEED_RSTCLR) { - spin_lock(i2s->lock); + spin_lock_irqsave(i2s->lock, flags); writel(0, i2s->addr + I2SCON); - spin_unlock(i2s->lock); + spin_unlock_irqrestore(i2s->lock, flags); } } @@ -1237,14 +1238,14 @@ static int samsung_i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to get drvdata\n"); return -EFAULT; } - ret = devm_snd_soc_register_component(&sec_dai->pdev->dev, - &samsung_i2s_component, - &sec_dai->i2s_dai_drv, 1); + ret = samsung_asoc_dma_platform_register(&pdev->dev, + sec_dai->filter, "tx-sec", NULL); if (ret != 0) return ret; - return samsung_asoc_dma_platform_register(&pdev->dev, - sec_dai->filter, "tx-sec", NULL); + return devm_snd_soc_register_component(&sec_dai->pdev->dev, + &samsung_i2s_component, + &sec_dai->i2s_dai_drv, 1); } pri_dai = i2s_alloc_dai(pdev, false); @@ -1304,8 +1305,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) } pri_dai->dma_playback.addr = regs_base + I2STXD; pri_dai->dma_capture.addr = regs_base + I2SRXD; - pri_dai->dma_playback.chan_name = "tx"; - pri_dai->dma_capture.chan_name = "rx"; pri_dai->dma_playback.addr_width = 4; pri_dai->dma_capture.addr_width = 4; pri_dai->quirks = quirks; @@ -1314,6 +1313,11 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (quirks & QUIRK_PRI_6CHAN) pri_dai->i2s_dai_drv.playback.channels_max = 6; + ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, + NULL, NULL); + if (ret < 0) + goto err_disable_clk; + if (quirks & QUIRK_SEC_DAI) { sec_dai = i2s_alloc_dai(pdev, true); if (!sec_dai) { @@ -1325,7 +1329,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->lock = &pri_dai->spinlock; sec_dai->variant_regs = pri_dai->variant_regs; sec_dai->dma_playback.addr = regs_base + I2STXDS; - sec_dai->dma_playback.chan_name = "tx-sec"; if (!np) { sec_dai->dma_playback.filter_data = i2s_pdata->dma_play_sec; @@ -1353,10 +1356,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (ret < 0) goto err_free_dai; - ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, - NULL, NULL); - if (ret < 0) - goto err_free_dai; pm_runtime_enable(&pdev->dev); diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c deleted file mode 100644 index 9342fc270c2b..000000000000 --- a/sound/soc/samsung/ln2440sbc_alc650.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SoC audio for ln2440sbc - * - * Copyright 2007 KonekTel, a.s. - * Author: Ivan Kuten - * ivan.kuten@promwad.com - * - * Heavily based on smdk2443_wm9710.c - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/module.h> -#include <sound/soc.h> - -static struct snd_soc_card ln2440sbc; - -static struct snd_soc_dai_link ln2440sbc_dai[] = { -{ - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai_name = "samsung-ac97", - .codec_dai_name = "ac97-hifi", - .codec_name = "ac97-codec", - .platform_name = "samsung-ac97", -}, -}; - -static struct snd_soc_card ln2440sbc = { - .name = "LN2440SBC", - .owner = THIS_MODULE, - .dai_link = ln2440sbc_dai, - .num_links = ARRAY_SIZE(ln2440sbc_dai), -}; - -static struct platform_device *ln2440sbc_snd_ac97_device; - -static int __init ln2440sbc_init(void) -{ - int ret; - - ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1); - if (!ln2440sbc_snd_ac97_device) - return -ENOMEM; - - platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc); - ret = platform_device_add(ln2440sbc_snd_ac97_device); - - if (ret) - platform_device_put(ln2440sbc_snd_ac97_device); - - return ret; -} - -static void __exit ln2440sbc_exit(void) -{ - platform_device_unregister(ln2440sbc_snd_ac97_device); -} - -module_init(ln2440sbc_init); -module_exit(ln2440sbc_exit); - -/* Module information */ -MODULE_AUTHOR("Ivan Kuten"); -MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 43e367a9acc3..d50a6377c23d 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -499,13 +499,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pcm_pdata = pdev->dev.platform_data; - /* Check for availability of necessary resource */ - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem_res) { - dev_err(&pdev->dev, "Unable to get register resource\n"); - return -ENXIO; - } - if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) { dev_err(&pdev->dev, "Unable to configure gpio\n"); return -EINVAL; @@ -519,36 +512,26 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) /* Default is 128fs */ pcm->sclk_per_fs = 128; + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pcm->regs = devm_ioremap_resource(&pdev->dev, mem_res); + if (IS_ERR(pcm->regs)) + return PTR_ERR(pcm->regs); + pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus"); if (IS_ERR(pcm->cclk)) { - dev_err(&pdev->dev, "failed to get audio-bus\n"); - ret = PTR_ERR(pcm->cclk); - goto err1; + dev_err(&pdev->dev, "failed to get audio-bus clock\n"); + return PTR_ERR(pcm->cclk); } clk_prepare_enable(pcm->cclk); /* record our pcm structure for later use in the callbacks */ dev_set_drvdata(&pdev->dev, pcm); - if (!request_mem_region(mem_res->start, - resource_size(mem_res), "samsung-pcm")) { - dev_err(&pdev->dev, "Unable to request register region\n"); - ret = -EBUSY; - goto err2; - } - - pcm->regs = ioremap(mem_res->start, 0x100); - if (pcm->regs == NULL) { - dev_err(&pdev->dev, "cannot ioremap registers\n"); - ret = -ENXIO; - goto err3; - } - pcm->pclk = devm_clk_get(&pdev->dev, "pcm"); if (IS_ERR(pcm->pclk)) { - dev_err(&pdev->dev, "failed to get pcm_clock\n"); - ret = -ENOENT; - goto err4; + dev_err(&pdev->dev, "failed to get pcm clock\n"); + ret = PTR_ERR(pcm->pclk); + goto err_dis_cclk; } clk_prepare_enable(pcm->pclk); @@ -565,48 +548,38 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id]; pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id]; + ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); + goto err_dis_pclk; + } + pm_runtime_enable(&pdev->dev); ret = devm_snd_soc_register_component(&pdev->dev, &s3c_pcm_component, &s3c_pcm_dai[pdev->id], 1); if (ret != 0) { dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret); - goto err5; - } - - ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, - NULL, NULL); - if (ret) { - dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); - goto err5; + goto err_dis_pm; } return 0; -err5: +err_dis_pm: + pm_runtime_disable(&pdev->dev); +err_dis_pclk: clk_disable_unprepare(pcm->pclk); -err4: - iounmap(pcm->regs); -err3: - release_mem_region(mem_res->start, resource_size(mem_res)); -err2: +err_dis_cclk: clk_disable_unprepare(pcm->cclk); -err1: return ret; } static int s3c_pcm_dev_remove(struct platform_device *pdev) { struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; - struct resource *mem_res; pm_runtime_disable(&pdev->dev); - - iounmap(pcm->regs); - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem_res->start, resource_size(mem_res)); - clk_disable_unprepare(pcm->cclk); clk_disable_unprepare(pcm->pclk); diff --git a/sound/soc/samsung/regs-ac97.h b/sound/soc/samsung/regs-ac97.h deleted file mode 100644 index a71be45bbffc..000000000000 --- a/sound/soc/samsung/regs-ac97.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk> - * http://www.simtec.co.uk/products/SWLINUX/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * S3C2440 AC97 Controller -*/ - -#ifndef __SAMSUNG_REGS_AC97_H__ -#define __SAMSUNG_REGS_AC97_H__ - -#define S3C_AC97_GLBCTRL (0x00) - -#define S3C_AC97_GLBCTRL_CODECREADYIE (1<<22) -#define S3C_AC97_GLBCTRL_PCMOUTURIE (1<<21) -#define S3C_AC97_GLBCTRL_PCMINORIE (1<<20) -#define S3C_AC97_GLBCTRL_MICINORIE (1<<19) -#define S3C_AC97_GLBCTRL_PCMOUTTIE (1<<18) -#define S3C_AC97_GLBCTRL_PCMINTIE (1<<17) -#define S3C_AC97_GLBCTRL_MICINTIE (1<<16) -#define S3C_AC97_GLBCTRL_PCMOUTTM_OFF (0<<12) -#define S3C_AC97_GLBCTRL_PCMOUTTM_PIO (1<<12) -#define S3C_AC97_GLBCTRL_PCMOUTTM_DMA (2<<12) -#define S3C_AC97_GLBCTRL_PCMOUTTM_MASK (3<<12) -#define S3C_AC97_GLBCTRL_PCMINTM_OFF (0<<10) -#define S3C_AC97_GLBCTRL_PCMINTM_PIO (1<<10) -#define S3C_AC97_GLBCTRL_PCMINTM_DMA (2<<10) -#define S3C_AC97_GLBCTRL_PCMINTM_MASK (3<<10) -#define S3C_AC97_GLBCTRL_MICINTM_OFF (0<<8) -#define S3C_AC97_GLBCTRL_MICINTM_PIO (1<<8) -#define S3C_AC97_GLBCTRL_MICINTM_DMA (2<<8) -#define S3C_AC97_GLBCTRL_MICINTM_MASK (3<<8) -#define S3C_AC97_GLBCTRL_TRANSFERDATAENABLE (1<<3) -#define S3C_AC97_GLBCTRL_ACLINKON (1<<2) -#define S3C_AC97_GLBCTRL_WARMRESET (1<<1) -#define S3C_AC97_GLBCTRL_COLDRESET (1<<0) - -#define S3C_AC97_GLBSTAT (0x04) - -#define S3C_AC97_GLBSTAT_CODECREADY (1<<22) -#define S3C_AC97_GLBSTAT_PCMOUTUR (1<<21) -#define S3C_AC97_GLBSTAT_PCMINORI (1<<20) -#define S3C_AC97_GLBSTAT_MICINORI (1<<19) -#define S3C_AC97_GLBSTAT_PCMOUTTI (1<<18) -#define S3C_AC97_GLBSTAT_PCMINTI (1<<17) -#define S3C_AC97_GLBSTAT_MICINTI (1<<16) -#define S3C_AC97_GLBSTAT_MAINSTATE_IDLE (0<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_INIT (1<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_READY (2<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE (3<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_LP (4<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_WARM (5<<0) - -#define S3C_AC97_CODEC_CMD (0x08) - -#define S3C_AC97_CODEC_CMD_READ (1<<23) - -#define S3C_AC97_STAT (0x0c) -#define S3C_AC97_PCM_ADDR (0x10) -#define S3C_AC97_PCM_DATA (0x18) -#define S3C_AC97_MIC_DATA (0x1C) - -#endif /* __SAMSUNG_REGS_AC97_H__ */ diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 3e89fbc0c51d..6d0b8897fa6c 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -35,12 +35,10 @@ #include <linux/platform_data/asoc-s3c.h> static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_out = { - .chan_name = "tx", .addr_width = 4, }; static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_in = { - .chan_name = "rx", .addr_width = 4, }; @@ -168,19 +166,19 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) s3c2412_i2s_pcm_stereo_in.addr = res->start + S3C2412_IISRXD; s3c2412_i2s_pcm_stereo_in.filter_data = pdata->dma_capture; - ret = s3c_i2sv2_register_component(&pdev->dev, -1, - &s3c2412_i2s_component, - &s3c2412_i2s_dai); + ret = samsung_asoc_dma_platform_register(&pdev->dev, + pdata->dma_filter, + NULL, NULL); if (ret) { - pr_err("failed to register the dai\n"); + pr_err("failed to register the DMA: %d\n", ret); return ret; } - ret = samsung_asoc_dma_platform_register(&pdev->dev, - pdata->dma_filter, - NULL, NULL); + ret = s3c_i2sv2_register_component(&pdev->dev, -1, + &s3c2412_i2s_component, + &s3c2412_i2s_dai); if (ret) - pr_err("failed to register the DMA: %d\n", ret); + pr_err("failed to register the dai\n"); return ret; } diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index c78a936a3099..07f5091b33e8 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -30,15 +30,11 @@ #include "dma.h" #include "s3c24xx-i2s.h" -#include <linux/platform_data/asoc-s3c.h> - static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = { - .chan_name = "tx", .addr_width = 2, }; static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_in = { - .chan_name = "rx", .addr_width = 2, }; @@ -58,8 +54,6 @@ static void s3c24xx_snd_txctrl(int on) u32 iiscon; u32 iismod; - pr_debug("Entered %s\n", __func__); - iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); @@ -103,8 +97,6 @@ static void s3c24xx_snd_rxctrl(int on) u32 iiscon; u32 iismod; - pr_debug("Entered %s\n", __func__); - iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); @@ -151,8 +143,6 @@ static int s3c24xx_snd_lrsync(void) u32 iiscon; int timeout = 50; /* 5ms */ - pr_debug("Entered %s\n", __func__); - while (1) { iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); if (iiscon & S3C2410_IISCON_LRINDEX) @@ -171,8 +161,6 @@ static int s3c24xx_snd_lrsync(void) */ static inline int s3c24xx_snd_is_clkmaster(void) { - pr_debug("Entered %s\n", __func__); - return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; } @@ -184,8 +172,6 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, { u32 iismod; - pr_debug("Entered %s\n", __func__); - iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); pr_debug("hw_params r: IISMOD: %x \n", iismod); @@ -213,6 +199,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); pr_debug("hw_params w: IISMOD: %x \n", iismod); + return 0; } @@ -223,8 +210,6 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_dmaengine_dai_dma_data *dma_data; u32 iismod; - pr_debug("Entered %s\n", __func__); - dma_data = snd_soc_dai_get_dma_data(dai, substream); /* Working copies of register */ @@ -246,6 +231,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); pr_debug("hw_params w: IISMOD: %x\n", iismod); + return 0; } @@ -254,8 +240,6 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, { int ret = 0; - pr_debug("Entered %s\n", __func__); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -297,8 +281,6 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, { u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); - pr_debug("Entered %s\n", __func__); - iismod &= ~S3C2440_IISMOD_MPLL; switch (clk_id) { @@ -323,8 +305,6 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, { u32 reg; - pr_debug("Entered %s\n", __func__); - switch (div_id) { case S3C24XX_DIV_BCLK: reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK; @@ -358,8 +338,6 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) { - pr_debug("Entered %s\n", __func__); - snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out, &s3c24xx_i2s_pcm_stereo_in); @@ -385,8 +363,6 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) #ifdef CONFIG_PM static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) { - pr_debug("Entered %s\n", __func__); - s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); @@ -399,7 +375,6 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) { - pr_debug("Entered %s\n", __func__); clk_prepare_enable(s3c24xx_i2s.iis_clk); writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); @@ -414,7 +389,6 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) #define s3c24xx_i2s_resume NULL #endif - #define S3C24XX_I2S_RATES \ (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ @@ -451,41 +425,28 @@ static const struct snd_soc_component_driver s3c24xx_i2s_component = { static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { - int ret = 0; struct resource *res; - struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev); - - if (!pdata) { - dev_err(&pdev->dev, "missing platform data"); - return -ENXIO; - } + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Can't get IO resource.\n"); - return -ENOENT; - } s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(s3c24xx_i2s.regs)) return PTR_ERR(s3c24xx_i2s.regs); s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO; - s3c24xx_i2s_pcm_stereo_out.filter_data = pdata->dma_playback; s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; - s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture; - ret = devm_snd_soc_register_component(&pdev->dev, - &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); + ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL, + NULL, NULL); if (ret) { - pr_err("failed to register the dai\n"); + dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret); return ret; } - ret = samsung_asoc_dma_platform_register(&pdev->dev, - pdata->dma_filter, - NULL, NULL); + ret = devm_snd_soc_register_component(&pdev->dev, + &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); if (ret) - pr_err("failed to register the dma: %d\n", ret); + dev_err(&pdev->dev, "Failed to register the DAI\n"); return ret; } diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index 7853fbe6ccc9..81a78940967c 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c @@ -19,9 +19,15 @@ #include <sound/s3c24xx_uda134x.h> #include "regs-iis.h" - #include "s3c24xx-i2s.h" +struct s3c24xx_uda134x { + struct clk *xtal; + struct clk *pclk; + struct mutex clk_lock; + int clk_users; +}; + /* #define ENFORCE_RATES 1 */ /* Unfortunately the S3C24XX in master mode has a limited capacity of @@ -36,15 +42,6 @@ possible an error will be returned. */ -static struct clk *xtal; -static struct clk *pclk; -/* this is need because we don't have a place where to keep the - * pointers to the clocks in each substream. We get the clocks only - * when we are actually using them so we don't block stuff like - * frequency change or oscillator power-off */ -static int clk_users; -static DEFINE_MUTEX(clk_lock); - static unsigned int rates[33 * 2]; #ifdef ENFORCE_RATES static struct snd_pcm_hw_constraint_list hw_constraints_rates = { @@ -57,26 +54,24 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = { static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -#ifdef ENFORCE_RATES - struct snd_pcm_runtime *runtime = substream->runtime; -#endif int ret = 0; - mutex_lock(&clk_lock); + mutex_lock(&priv->clk_lock); - if (clk_users == 0) { - xtal = clk_get(rtd->dev, "xtal"); - if (IS_ERR(xtal)) { + if (priv->clk_users == 0) { + priv->xtal = clk_get(rtd->dev, "xtal"); + if (IS_ERR(priv->xtal)) { dev_err(rtd->dev, "%s cannot get xtal\n", __func__); - ret = PTR_ERR(xtal); + ret = PTR_ERR(priv->xtal); } else { - pclk = clk_get(cpu_dai->dev, "iis"); - if (IS_ERR(pclk)) { + priv->pclk = clk_get(cpu_dai->dev, "iis"); + if (IS_ERR(priv->pclk)) { dev_err(rtd->dev, "%s cannot get pclk\n", __func__); - clk_put(xtal); - ret = PTR_ERR(pclk); + clk_put(priv->xtal); + ret = PTR_ERR(priv->pclk); } } if (!ret) { @@ -85,18 +80,19 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) for (i = 0; i < 2; i++) { int fs = i ? 256 : 384; - rates[i*33] = clk_get_rate(xtal) / fs; + rates[i*33] = clk_get_rate(priv->xtal) / fs; for (j = 1; j < 33; j++) - rates[i*33 + j] = clk_get_rate(pclk) / + rates[i*33 + j] = clk_get_rate(priv->pclk) / (j * fs); } } } - clk_users += 1; - mutex_unlock(&clk_lock); + priv->clk_users += 1; + mutex_unlock(&priv->clk_lock); + if (!ret) { #ifdef ENFORCE_RATES - ret = snd_pcm_hw_constraint_list(runtime, 0, + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); if (ret < 0) @@ -109,15 +105,18 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) { - mutex_lock(&clk_lock); - clk_users -= 1; - if (clk_users == 0) { - clk_put(xtal); - xtal = NULL; - clk_put(pclk); - pclk = NULL; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card); + + mutex_lock(&priv->clk_lock); + priv->clk_users -= 1; + if (priv->clk_users == 0) { + clk_put(priv->xtal); + priv->xtal = NULL; + clk_put(priv->pclk); + priv->pclk = NULL; } - mutex_unlock(&clk_lock); + mutex_unlock(&priv->clk_lock); } static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, @@ -228,10 +227,18 @@ static struct snd_soc_card snd_soc_s3c24xx_uda134x = { static int s3c24xx_uda134x_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x; + struct s3c24xx_uda134x *priv; int ret; - platform_set_drvdata(pdev, card); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->clk_lock); + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c deleted file mode 100644 index c390aad68cfb..000000000000 --- a/sound/soc/samsung/smdk2443_wm9710.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * smdk2443_wm9710.c -- SoC audio for smdk2443 - * - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <linux/module.h> -#include <sound/soc.h> - -static struct snd_soc_card smdk2443; - -static struct snd_soc_dai_link smdk2443_dai[] = { -{ - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai_name = "samsung-ac97", - .codec_dai_name = "ac97-hifi", - .codec_name = "ac97-codec", - .platform_name = "samsung-ac97", -}, -}; - -static struct snd_soc_card smdk2443 = { - .name = "SMDK2443", - .owner = THIS_MODULE, - .dai_link = smdk2443_dai, - .num_links = ARRAY_SIZE(smdk2443_dai), -}; - -static struct platform_device *smdk2443_snd_ac97_device; - -static int __init smdk2443_init(void) -{ - int ret; - - smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1); - if (!smdk2443_snd_ac97_device) - return -ENOMEM; - - platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443); - ret = platform_device_add(smdk2443_snd_ac97_device); - - if (ret) - platform_device_put(smdk2443_snd_ac97_device); - - return ret; -} - -static void __exit smdk2443_exit(void) -{ - platform_device_unregister(smdk2443_snd_ac97_device); -} - -module_init(smdk2443_init); -module_exit(smdk2443_exit); - -/* Module information */ -MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com"); -MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index 548bfd993788..de724ce7b955 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -14,8 +14,6 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <asm/mach-types.h> - #include "../codecs/wm8580.h" #include "i2s.h" @@ -147,7 +145,6 @@ static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) enum { PRI_PLAYBACK = 0, PRI_CAPTURE, - SEC_PLAYBACK, }; #define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ @@ -157,7 +154,7 @@ static struct snd_soc_dai_link smdk_dai[] = { [PRI_PLAYBACK] = { /* Primary Playback i/f */ .name = "WM8580 PAIF RX", .stream_name = "Playback", - .cpu_dai_name = "samsung-i2s.0", + .cpu_dai_name = "samsung-i2s.2", .codec_dai_name = "wm8580-hifi-playback", .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", @@ -167,7 +164,7 @@ static struct snd_soc_dai_link smdk_dai[] = { [PRI_CAPTURE] = { /* Primary Capture i/f */ .name = "WM8580 PAIF TX", .stream_name = "Capture", - .cpu_dai_name = "samsung-i2s.0", + .cpu_dai_name = "samsung-i2s.2", .codec_dai_name = "wm8580-hifi-capture", .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", @@ -175,23 +172,13 @@ static struct snd_soc_dai_link smdk_dai[] = { .init = smdk_wm8580_init_paiftx, .ops = &smdk_ops, }, - [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ - .name = "Sec_FIFO TX", - .stream_name = "Playback", - .cpu_dai_name = "samsung-i2s-sec", - .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-i2s-sec", - .codec_name = "wm8580.0-001b", - .dai_fmt = SMDK_DAI_FMT, - .ops = &smdk_ops, - }, }; static struct snd_soc_card smdk = { .name = "SMDK-I2S", .owner = THIS_MODULE, .dai_link = smdk_dai, - .num_links = 2, + .num_links = ARRAY_SIZE(smdk_dai), .dapm_widgets = smdk_wm8580_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets), @@ -204,17 +191,6 @@ static struct platform_device *smdk_snd_device; static int __init smdk_audio_init(void) { int ret; - char *str; - - if (machine_is_smdkc100() - || machine_is_smdkv210() || machine_is_smdkc110()) { - smdk.num_links = 3; - } else if (machine_is_smdk6410()) { - str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; - str[strlen(str) - 1] = '2'; - str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name; - str[strlen(str) - 1] = '2'; - } smdk_snd_device = platform_device_alloc("soc-audio", -1); if (!smdk_snd_device) diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c deleted file mode 100644 index a6d223310c67..000000000000 --- a/sound/soc/samsung/smdk_wm8580pcm.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * sound/soc/samsung/smdk_wm8580pcm.c - * - * Copyright (c) 2011 Samsung Electronics Co. Ltd - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#include <linux/module.h> -#include <sound/soc.h> -#include <sound/pcm_params.h> -#include <sound/pcm.h> - -#include <asm/mach-types.h> - -#include "../codecs/wm8580.h" -#include "pcm.h" - -/* - * Board Settings: - * o '1' means 'ON' - * o '0' means 'OFF' - * o 'X' means 'Don't care' - * - * SMDK6410 Base B/D: CFG1-0000, CFG2-1111 - * SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000 - */ - -#define SMDK_WM8580_EXT_OSC 12000000 -#define SMDK_WM8580_EXT_MCLK 4096000 -#define SMDK_WM8580_EXT_VOICE 2048000 - -static unsigned long mclk_freq; -static unsigned long xtal_freq; - -/* - * If MCLK clock directly gets from XTAL, we don't have to use PLL - * to make MCLK, but if XTAL clock source connects with other codec - * pin (like XTI), we should have to set codec's PLL to make MCLK. - * Because Samsung SoC does not support pcmcdclk output like I2S. - */ - -static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int rfs, ret; - - switch (params_rate(params)) { - case 8000: - break; - default: - printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n", - __func__, __LINE__, params_rate(params)); - return -EINVAL; - } - - rfs = mclk_freq / params_rate(params) / 2; - - if (mclk_freq == xtal_freq) { - ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK, - mclk_freq, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, - WM8580_CLKSRC_MCLK); - if (ret < 0) - return ret; - } else { - ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, - mclk_freq, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, - WM8580_CLKSRC_PLLA); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, - xtal_freq, mclk_freq); - if (ret < 0) - return ret; - } - - /* Set PCM source clock on CPU */ - ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX, - mclk_freq, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - /* Set SCLK_DIV for making bclk */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops smdk_wm8580_pcm_ops = { - .hw_params = smdk_wm8580_pcm_hw_params, -}; - -#define SMDK_DAI_FMT (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | \ - SND_SOC_DAIFMT_CBS_CFS) - -static struct snd_soc_dai_link smdk_dai[] = { - { - .name = "WM8580 PAIF PCM RX", - .stream_name = "Playback", - .cpu_dai_name = "samsung-pcm.0", - .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-audio", - .codec_name = "wm8580.0-001b", - .dai_fmt = SMDK_DAI_FMT, - .ops = &smdk_wm8580_pcm_ops, - }, { - .name = "WM8580 PAIF PCM TX", - .stream_name = "Capture", - .cpu_dai_name = "samsung-pcm.0", - .codec_dai_name = "wm8580-hifi-capture", - .platform_name = "samsung-pcm.0", - .codec_name = "wm8580.0-001b", - .dai_fmt = SMDK_DAI_FMT, - .ops = &smdk_wm8580_pcm_ops, - }, -}; - -static struct snd_soc_card smdk_pcm = { - .name = "SMDK-PCM", - .owner = THIS_MODULE, - .dai_link = smdk_dai, - .num_links = 2, -}; - -/* - * After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1) - * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4), - * 2.0484Mhz, directly with MCLK both Codec and SoC. - */ -static int snd_smdk_probe(struct platform_device *pdev) -{ - int ret = 0; - - xtal_freq = SMDK_WM8580_EXT_OSC; - mclk_freq = SMDK_WM8580_EXT_MCLK; - - if (machine_is_smdkc110() || machine_is_smdkv210()) - xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE; - - smdk_pcm.dev = &pdev->dev; - ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm); - if (ret) - dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); - - return ret; -} - -static struct platform_driver snd_smdk_driver = { - .driver = { - .name = "samsung-smdk-pcm", - }, - .probe = snd_smdk_probe, -}; - -module_platform_driver(snd_smdk_driver); - -MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>"); -MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c deleted file mode 100644 index 0d20e4ed27aa..000000000000 --- a/sound/soc/samsung/smdk_wm9713.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * smdk_wm9713.c -- SoC audio for SMDK - * - * Copyright 2010 Samsung Electronics Co. Ltd. - * Author: Jaswinder Singh Brar <jassisinghbrar@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - */ - -#include <linux/module.h> -#include <sound/soc.h> - -static struct snd_soc_card smdk; - -/* - * Default CFG switch settings to use this driver: - * - * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off - * SMDKC100: Set CFG6 1-3 On, CFG7 1 On - * SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On - * SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On - * SMDKV310: Set CFG2 1-2 Off, CFG4 All On, CFG7 All Off, CFG8 1-On - */ - -/* - Playback (HeadPhone):- - $ amixer sset 'Headphone' unmute - $ amixer sset 'Right Headphone Out Mux' 'Headphone' - $ amixer sset 'Left Headphone Out Mux' 'Headphone' - $ amixer sset 'Right HP Mixer PCM' unmute - $ amixer sset 'Left HP Mixer PCM' unmute - - Capture (LineIn):- - $ amixer sset 'Right Capture Source' 'Line' - $ amixer sset 'Left Capture Source' 'Line' -*/ - -static struct snd_soc_dai_link smdk_dai = { - .name = "AC97", - .stream_name = "AC97 PCM", - .platform_name = "samsung-ac97", - .cpu_dai_name = "samsung-ac97", - .codec_dai_name = "wm9713-hifi", - .codec_name = "wm9713-codec", -}; - -static struct snd_soc_card smdk = { - .name = "SMDK WM9713", - .owner = THIS_MODULE, - .dai_link = &smdk_dai, - .num_links = 1, -}; - -static struct platform_device *smdk_snd_wm9713_device; -static struct platform_device *smdk_snd_ac97_device; - -static int __init smdk_init(void) -{ - int ret; - - smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1); - if (!smdk_snd_wm9713_device) - return -ENOMEM; - - ret = platform_device_add(smdk_snd_wm9713_device); - if (ret) - goto err1; - - smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1); - if (!smdk_snd_ac97_device) { - ret = -ENOMEM; - goto err2; - } - - platform_set_drvdata(smdk_snd_ac97_device, &smdk); - - ret = platform_device_add(smdk_snd_ac97_device); - if (ret) - goto err3; - - return 0; - -err3: - platform_device_put(smdk_snd_ac97_device); -err2: - platform_device_del(smdk_snd_wm9713_device); -err1: - platform_device_put(smdk_snd_wm9713_device); - return ret; -} - -static void __exit smdk_exit(void) -{ - platform_device_unregister(smdk_snd_ac97_device); - platform_device_unregister(smdk_snd_wm9713_device); -} - -module_init(smdk_init); -module_exit(smdk_exit); - -/* Module information */ -MODULE_AUTHOR("Jaswinder Singh Brar, jassisinghbrar@gmail.com"); -MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 26c1fbed4d35..779504f54bc0 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -416,15 +416,6 @@ static int spdif_probe(struct platform_device *pdev) goto err3; } - dev_set_drvdata(&pdev->dev, spdif); - - ret = devm_snd_soc_register_component(&pdev->dev, - &samsung_spdif_component, &samsung_spdif_dai, 1); - if (ret != 0) { - dev_err(&pdev->dev, "fail to register dai\n"); - goto err4; - } - spdif_stereo_out.addr_width = 2; spdif_stereo_out.addr = mem_res->start + DATA_OUTBUF; filter = NULL; @@ -432,7 +423,6 @@ static int spdif_probe(struct platform_device *pdev) spdif_stereo_out.filter_data = spdif_pdata->dma_playback; filter = spdif_pdata->dma_filter; } - spdif->dma_playback = &spdif_stereo_out; ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, @@ -442,6 +432,15 @@ static int spdif_probe(struct platform_device *pdev) goto err4; } + dev_set_drvdata(&pdev->dev, spdif); + + ret = devm_snd_soc_register_component(&pdev->dev, + &samsung_spdif_component, &samsung_spdif_dai, 1); + if (ret != 0) { + dev_err(&pdev->dev, "fail to register dai\n"); + goto err4; + } + return 0; err4: iounmap(spdif->regs); diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c new file mode 100644 index 000000000000..5cdf7d19b87f --- /dev/null +++ b/sound/soc/samsung/tm2_wm5110.c @@ -0,0 +1,552 @@ +/* + * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd. + * + * Authors: Inha Song <ideal.song@samsung.com> + * Sylwester Nawrocki <s.nawrocki@samsung.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "i2s.h" +#include "../codecs/wm5110.h" + +/* + * The source clock is XCLKOUT with its mux set to the external fixed rate + * oscillator (XXTI). + */ +#define MCLK_RATE 24000000U + +#define TM2_DAI_AIF1 0 +#define TM2_DAI_AIF2 1 + +struct tm2_machine_priv { + struct snd_soc_codec *codec; + unsigned int sysclk_rate; + struct gpio_desc *gpio_mic_bias; +}; + +static int tm2_start_sysclk(struct snd_soc_card *card) +{ + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_codec *codec = priv->codec; + int ret; + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL1_REFCLK, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + priv->sysclk_rate); + if (ret < 0) { + dev_err(codec->dev, "Failed to set FLL1 source: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + priv->sysclk_rate); + if (ret < 0) { + dev_err(codec->dev, "Failed to start FLL1: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, + ARIZONA_CLK_SRC_FLL1, + priv->sysclk_rate, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec->dev, "Failed to set SYSCLK source: %d\n", ret); + return ret; + } + + return 0; +} + +static int tm2_stop_sysclk(struct snd_soc_card *card) +{ + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_codec *codec = priv->codec; + int ret; + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, 0, 0, 0); + if (ret < 0) { + dev_err(codec->dev, "Failed to stop FLL1: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, + ARIZONA_CLK_SRC_FLL1, 0, 0); + if (ret < 0) { + dev_err(codec->dev, "Failed to stop SYSCLK: %d\n", ret); + return ret; + } + + return 0; +} + +static int tm2_aif1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card); + + switch (params_rate(params)) { + case 4000: + case 8000: + case 12000: + case 16000: + case 24000: + case 32000: + case 48000: + case 96000: + case 192000: + /* Highest possible SYSCLK frequency: 147.456MHz */ + priv->sysclk_rate = 147456000U; + break; + case 11025: + case 22050: + case 44100: + case 88200: + case 176400: + /* Highest possible SYSCLK frequency: 135.4752 MHz */ + priv->sysclk_rate = 135475200U; + break; + default: + dev_err(codec->dev, "Not supported sample rate: %d\n", + params_rate(params)); + return -EINVAL; + } + + return tm2_start_sysclk(rtd->card); +} + +static struct snd_soc_ops tm2_aif1_ops = { + .hw_params = tm2_aif1_hw_params, +}; + +static int tm2_aif2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + unsigned int asyncclk_rate; + int ret; + + switch (params_rate(params)) { + case 8000: + case 12000: + case 16000: + /* Highest possible ASYNCCLK frequency: 49.152MHz */ + asyncclk_rate = 49152000U; + break; + case 11025: + /* Highest possible ASYNCCLK frequency: 45.1584 MHz */ + asyncclk_rate = 45158400U; + break; + default: + dev_err(codec->dev, "Not supported sample rate: %d\n", + params_rate(params)); + return -EINVAL; + } + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL2_REFCLK, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + asyncclk_rate); + if (ret < 0) { + dev_err(codec->dev, "Failed to set FLL2 source: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + asyncclk_rate); + if (ret < 0) { + dev_err(codec->dev, "Failed to start FLL2: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, + ARIZONA_CLK_SRC_FLL2, + asyncclk_rate, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec->dev, "Failed to set ASYNCCLK source: %d\n", ret); + return ret; + } + + return 0; +} + +static int tm2_aif2_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + int ret; + + /* disable FLL2 */ + ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1, + 0, 0); + if (ret < 0) + dev_err(codec->dev, "Failed to stop FLL2: %d\n", ret); + + return ret; +} + +static struct snd_soc_ops tm2_aif2_ops = { + .hw_params = tm2_aif2_hw_params, + .hw_free = tm2_aif2_hw_free, +}; + +static int tm2_mic_bias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + gpiod_set_value_cansleep(priv->gpio_mic_bias, 1); + break; + case SND_SOC_DAPM_POST_PMD: + gpiod_set_value_cansleep(priv->gpio_mic_bias, 0); + break; + } + + return 0; +} + +static int tm2_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct snd_soc_pcm_runtime *rtd; + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + + if (dapm->dev != rtd->codec_dai->dev) + return 0; + + switch (level) { + case SND_SOC_BIAS_STANDBY: + if (card->dapm.bias_level == SND_SOC_BIAS_OFF) + tm2_start_sysclk(card); + break; + case SND_SOC_BIAS_OFF: + tm2_stop_sysclk(card); + break; + default: + break; + } + + return 0; +} + +static struct snd_soc_aux_dev tm2_speaker_amp_dev; + +static int tm2_late_probe(struct snd_soc_card *card) +{ + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_dai_link_component dlc = { 0 }; + unsigned int ch_map[] = { 0, 1 }; + struct snd_soc_dai *amp_pdm_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *aif1_dai; + struct snd_soc_dai *aif2_dai; + int ret; + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name); + aif1_dai = rtd->codec_dai; + priv->codec = rtd->codec; + + ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); + if (ret < 0) { + dev_err(aif1_dai->dev, "Failed to set SYSCLK: %d\n", ret); + return ret; + } + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF2].name); + aif2_dai = rtd->codec_dai; + + ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); + if (ret < 0) { + dev_err(aif2_dai->dev, "Failed to set ASYNCCLK: %d\n", ret); + return ret; + } + + dlc.of_node = tm2_speaker_amp_dev.codec_of_node; + amp_pdm_dai = snd_soc_find_dai(&dlc); + if (!amp_pdm_dai) + return -ENODEV; + + /* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */ + ret = snd_soc_dai_set_channel_map(amp_pdm_dai, ARRAY_SIZE(ch_map), + ch_map, 0, NULL); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_tdm_slot(amp_pdm_dai, 0x3, 0x0, 2, 16); + if (ret < 0) + return ret; + + return 0; +} + +static const struct snd_kcontrol_new tm2_controls[] = { + SOC_DAPM_PIN_SWITCH("HP"), + SOC_DAPM_PIN_SWITCH("SPK"), + SOC_DAPM_PIN_SWITCH("RCV"), + SOC_DAPM_PIN_SWITCH("VPS"), + SOC_DAPM_PIN_SWITCH("HDMI"), + + SOC_DAPM_PIN_SWITCH("Main Mic"), + SOC_DAPM_PIN_SWITCH("Sub Mic"), + SOC_DAPM_PIN_SWITCH("Third Mic"), + + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +const struct snd_soc_dapm_widget tm2_dapm_widgets[] = { + SND_SOC_DAPM_HP("HP", NULL), + SND_SOC_DAPM_SPK("SPK", NULL), + SND_SOC_DAPM_SPK("RCV", NULL), + SND_SOC_DAPM_LINE("VPS", NULL), + SND_SOC_DAPM_LINE("HDMI", NULL), + + SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias), + SND_SOC_DAPM_MIC("Sub Mic", NULL), + SND_SOC_DAPM_MIC("Third Mic", NULL), + + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_component_driver tm2_component = { + .name = "tm2-audio", +}; + +static struct snd_soc_dai_driver tm2_ext_dai[] = { + { + .name = "Voice call", + .playback = { + .channels_min = 1, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 1, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, + { + .name = "Bluetooth", + .playback = { + .channels_min = 1, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 16000, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 16000, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, +}; + +static struct snd_soc_dai_link tm2_dai_links[] = { + { + .name = "WM5110 AIF1", + .stream_name = "HiFi Primary", + .codec_dai_name = "wm5110-aif1", + .ops = &tm2_aif1_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + }, { + .name = "WM5110 Voice", + .stream_name = "Voice call", + .codec_dai_name = "wm5110-aif2", + .ops = &tm2_aif2_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + .ignore_suspend = 1, + }, { + .name = "WM5110 BT", + .stream_name = "Bluetooth", + .codec_dai_name = "wm5110-aif3", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + .ignore_suspend = 1, + } +}; + +static struct snd_soc_card tm2_card = { + .owner = THIS_MODULE, + + .dai_link = tm2_dai_links, + .num_links = ARRAY_SIZE(tm2_dai_links), + .controls = tm2_controls, + .num_controls = ARRAY_SIZE(tm2_controls), + .dapm_widgets = tm2_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tm2_dapm_widgets), + .aux_dev = &tm2_speaker_amp_dev, + .num_aux_devs = 1, + + .late_probe = tm2_late_probe, + .set_bias_level = tm2_set_bias_level, +}; + +static int tm2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct snd_soc_card *card = &tm2_card; + struct tm2_machine_priv *priv; + struct device_node *cpu_dai_node, *codec_dai_node; + int ret, i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + snd_soc_card_set_drvdata(card, priv); + card->dev = dev; + + priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias", + GPIOF_OUT_INIT_LOW); + if (IS_ERR(priv->gpio_mic_bias)) { + dev_err(dev, "Failed to get mic bias gpio\n"); + return PTR_ERR(priv->gpio_mic_bias); + } + + ret = snd_soc_of_parse_card_name(card, "model"); + if (ret < 0) { + dev_err(dev, "Card name is not specified\n"); + return ret; + } + + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing is not specified or invalid\n"); + return ret; + } + + card->aux_dev[0].codec_of_node = of_parse_phandle(dev->of_node, + "audio-amplifier", 0); + if (!card->aux_dev[0].codec_of_node) { + dev_err(dev, "audio-amplifier property invalid or missing\n"); + return -EINVAL; + } + + cpu_dai_node = of_parse_phandle(dev->of_node, "i2s-controller", 0); + if (!cpu_dai_node) { + dev_err(dev, "i2s-controllers property invalid or missing\n"); + ret = -EINVAL; + goto amp_node_put; + } + + codec_dai_node = of_parse_phandle(dev->of_node, "audio-codec", 0); + if (!codec_dai_node) { + dev_err(dev, "audio-codec property invalid or missing\n"); + ret = -EINVAL; + goto cpu_dai_node_put; + } + + for (i = 0; i < card->num_links; i++) { + card->dai_link[i].cpu_dai_name = NULL; + card->dai_link[i].cpu_name = NULL; + card->dai_link[i].platform_name = NULL; + card->dai_link[i].codec_of_node = codec_dai_node; + card->dai_link[i].cpu_of_node = cpu_dai_node; + card->dai_link[i].platform_of_node = cpu_dai_node; + } + + ret = devm_snd_soc_register_component(dev, &tm2_component, + tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai)); + if (ret < 0) { + dev_err(dev, "Failed to register component: %d\n", ret); + goto codec_dai_node_put; + } + + ret = devm_snd_soc_register_card(dev, card); + if (ret < 0) { + dev_err(dev, "Failed to register card: %d\n", ret); + goto codec_dai_node_put; + } + +codec_dai_node_put: + of_node_put(codec_dai_node); +cpu_dai_node_put: + of_node_put(cpu_dai_node); +amp_node_put: + of_node_put(card->aux_dev[0].codec_of_node); + return ret; +} + +static int tm2_pm_prepare(struct device *dev) +{ + struct snd_soc_card *card = dev_get_drvdata(dev); + + return tm2_stop_sysclk(card); +} + +static void tm2_pm_complete(struct device *dev) +{ + struct snd_soc_card *card = dev_get_drvdata(dev); + + tm2_start_sysclk(card); +} + +const struct dev_pm_ops tm2_pm_ops = { + .prepare = tm2_pm_prepare, + .suspend = snd_soc_suspend, + .resume = snd_soc_resume, + .complete = tm2_pm_complete, + .freeze = snd_soc_suspend, + .thaw = snd_soc_resume, + .poweroff = snd_soc_poweroff, + .restore = snd_soc_resume, +}; + +static const struct of_device_id tm2_of_match[] = { + { .compatible = "samsung,tm2-audio" }, + { }, +}; +MODULE_DEVICE_TABLE(of, tm2_of_match); + +static struct platform_driver tm2_driver = { + .driver = { + .name = "tm2-audio", + .pm = &tm2_pm_ops, + .of_match_table = tm2_of_match, + }, + .probe = tm2_probe, +}; +module_platform_driver(tm2_driver); + +MODULE_AUTHOR("Inha Song <ideal.song@samsung.com>"); +MODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 6db6405d952f..147ebecfed94 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -1,5 +1,5 @@ menu "SoC Audio support for SuperH" - depends on SUPERH || ARCH_SHMOBILE + depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST config SND_SOC_PCM_SH7760 tristate "SoC Audio support for Renesas SH7760" @@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK + depends on OF || COMPILE_TEST select SND_SIMPLE_CARD select REGMAP_MMIO help diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 2145957d0229..85a33ac0a5c4 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -34,6 +34,9 @@ struct rsnd_adg { struct clk_onecell_data onecell; struct rsnd_mod mod; u32 flags; + u32 ckr; + u32 rbga; + u32 rbgb; int rbga_rate_for_441khz; /* RBGA */ int rbgb_rate_for_48khz; /* RBGB */ @@ -316,9 +319,11 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct clk *clk; int i; u32 data; + u32 ckr = 0; int sel_table[] = { [CLKA] = 0x1, [CLKB] = 0x2, @@ -360,15 +365,14 @@ found_clock: rsnd_adg_set_ssi_clk(ssi_mod, data); if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) { - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - u32 ckr = 0; - if (0 == (rate % 8000)) ckr = 0x80000000; - - rsnd_mod_bset(adg_mod, SSICKR, 0x80000000, ckr); } + rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr); + rsnd_mod_write(adg_mod, BRRA, adg->rbga); + rsnd_mod_write(adg_mod, BRRB, adg->rbgb); + dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), data, rate); @@ -376,6 +380,25 @@ found_clock: return 0; } +void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct clk *clk; + int i, ret; + + for_each_rsnd_clk(clk, adg, i) { + ret = 0; + if (enable) + ret = clk_prepare_enable(clk); + else + clk_disable_unprepare(clk); + + if (ret < 0) + dev_warn(dev, "can't use clk %d\n", i); + } +} + static void rsnd_adg_get_clkin(struct rsnd_priv *priv, struct rsnd_adg *adg) { @@ -387,27 +410,21 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, [CLKC] = "clk_c", [CLKI] = "clk_i", }; - int i, ret; + int i; for (i = 0; i < CLKMAX; i++) { clk = devm_clk_get(dev, clk_name[i]); adg->clk[i] = IS_ERR(clk) ? NULL : clk; } - for_each_rsnd_clk(clk, adg, i) { - ret = clk_prepare_enable(clk); - if (ret < 0) - dev_warn(dev, "can't use clk %d\n", i); - + for_each_rsnd_clk(clk, adg, i) dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); - } } static void rsnd_adg_get_clkout(struct rsnd_priv *priv, struct rsnd_adg *adg) { struct clk *clk; - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; u32 ckr, rbgx, rbga, rbgb; @@ -532,13 +549,13 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, } } - rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr); - rsnd_mod_write(adg_mod, BRRA, rbga); - rsnd_mod_write(adg_mod, BRRB, rbgb); + adg->ckr = ckr; + adg->rbga = rbga; + adg->rbgb = rbgb; for_each_rsnd_clkout(clk, adg, i) dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk)); - dev_dbg(dev, "SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", + dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", ckr, rbga, rbgb); } @@ -565,16 +582,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv) priv->adg = adg; + rsnd_adg_clk_enable(priv); + return 0; } void rsnd_adg_remove(struct rsnd_priv *priv) { - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct clk *clk; - int i; - - for_each_rsnd_clk(clk, adg, i) { - clk_disable_unprepare(clk); - } + rsnd_adg_clk_disable(priv); } diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f18141098b50..4bd68de76130 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -306,7 +306,7 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) */ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 val = 0x76543210; @@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) if (rsnd_io_is_play(io)) { struct rsnd_mod *src = rsnd_io_to_mod_src(io); - target = src ? src : ssi; + target = src ? src : ssiu; } else { struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); - target = cmd ? cmd : ssi; + target = cmd ? cmd : ssiu; } mask <<= runtime->channels * 4; @@ -348,32 +348,28 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) /* * rsnd_dai functions */ -#define rsnd_mod_call(idx, io, func, param...) \ -({ \ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ - struct rsnd_mod *mod = (io)->mod[idx]; \ - struct device *dev = rsnd_priv_to_dev(priv); \ - u32 *status = mod->get_status(io, mod, idx); \ - u32 mask = 0xF << __rsnd_mod_shift_##func; \ - u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ - u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ - int ret = 0; \ - int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ - if (add == 0xF) \ - call = 0; \ - else \ - *status = (*status & ~mask) + \ - (add << __rsnd_mod_shift_##func); \ - dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ - rsnd_mod_name(mod), rsnd_mod_id(mod), \ - *status, call ? #func : ""); \ - if (call) \ - ret = (mod)->ops->func(mod, io, param); \ - if (ret) \ - dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \ - rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \ - ret; \ -}) +struct rsnd_mod *rsnd_mod_next(int *iterator, + struct rsnd_dai_stream *io, + enum rsnd_mod_type *array, + int array_size) +{ + struct rsnd_mod *mod; + enum rsnd_mod_type type; + int max = array ? array_size : RSND_MOD_MAX; + + for (; *iterator < max; (*iterator)++) { + type = (array) ? array[*iterator] : *iterator; + mod = io->mod[type]; + if (!mod) + continue; + + (*iterator)++; + + return mod; + } + + return NULL; +} static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { { @@ -409,19 +405,49 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { }, }; -#define rsnd_dai_call(fn, io, param...) \ -({ \ - struct rsnd_mod *mod; \ - int type, is_play = rsnd_io_is_play(io); \ - int ret = 0, i; \ - for (i = 0; i < RSND_MOD_MAX; i++) { \ - type = rsnd_mod_sequence[is_play][i]; \ - mod = (io)->mod[type]; \ - if (!mod) \ - continue; \ - ret |= rsnd_mod_call(type, io, fn, param); \ - } \ - ret; \ +static int rsnd_status_update(u32 *status, + int shift, int add, int timing) +{ + u32 mask = 0xF << shift; + u8 val = (*status >> shift) & 0xF; + u8 next_val = (val + add) & 0xF; + int func_call = (val == timing); + + if (next_val == 0xF) /* underflow case */ + func_call = 0; + else + *status = (*status & ~mask) + (next_val << shift); + + return func_call; +} + +#define rsnd_dai_call(fn, io, param...) \ +({ \ + struct rsnd_priv *priv = rsnd_io_to_priv(io); \ + struct device *dev = rsnd_priv_to_dev(priv); \ + struct rsnd_mod *mod; \ + int is_play = rsnd_io_is_play(io); \ + int ret = 0, i; \ + enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ + for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ + int tmp = 0; \ + u32 *status = mod->get_status(io, mod, types[i]); \ + int func_call = rsnd_status_update(status, \ + __rsnd_mod_shift_##fn, \ + __rsnd_mod_add_##fn, \ + __rsnd_mod_call_##fn); \ + dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ + rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \ + (func_call && (mod)->ops->fn) ? #fn : ""); \ + if (func_call && (mod)->ops->fn) \ + tmp = (mod)->ops->fn(mod, io, param); \ + if (tmp) \ + dev_err(dev, "%s[%d] : %s error %d\n", \ + rsnd_mod_name(mod), rsnd_mod_id(mod), \ + #fn, tmp); \ + ret |= tmp; \ + } \ + ret; \ }) int rsnd_dai_connect(struct rsnd_mod *mod, @@ -690,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } +static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + return rsnd_dai_call(nolock_start, io, priv); +} + +static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + rsnd_dai_call(nolock_stop, io, priv); +} + static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, .trigger = rsnd_soc_dai_trigger, .set_fmt = rsnd_soc_dai_set_fmt, .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, @@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg) { - snd_ctl_remove(cfg->card, cfg->kctrl); + if (cfg->card && cfg->kctrl) + snd_ctl_remove(cfg->card, cfg->kctrl); + + cfg->card = NULL; + cfg->kctrl = NULL; } int rsnd_kctrl_new_m(struct rsnd_mod *mod, @@ -1070,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, - SNDRV_DMA_TYPE_DEV, - rtd->card->snd_card->dev, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); } @@ -1092,6 +1148,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, ret = rsnd_dai_call(probe, io, priv); if (ret == -EAGAIN) { struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *mod; int i; /* @@ -1111,8 +1168,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, * remove all mod from io * and, re connect ssi */ - for (i = 0; i < RSND_MOD_MAX; i++) - rsnd_dai_disconnect((io)->mod[i], io, i); + for_each_rsnd_mod(i, mod, io) + rsnd_dai_disconnect(mod, io, i); rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); /* @@ -1251,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev) return ret; } +static int rsnd_suspend(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_disable(priv); + + return 0; +} + +static int rsnd_resume(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_enable(priv); + + return 0; +} + +static struct dev_pm_ops rsnd_pm_ops = { + .suspend = rsnd_suspend, + .resume = rsnd_resume, +}; + static struct platform_driver rsnd_driver = { .driver = { .name = "rcar_sound", + .pm = &rsnd_pm_ops, .of_match_table = rsnd_of_match, }, .probe = rsnd_probe, diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 6bc93cbb3049..1f405c833867 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -25,6 +25,10 @@ struct rsnd_dmaen { struct dma_chan *chan; + dma_addr_t dma_buf; + unsigned int dma_len; + unsigned int dma_period; + unsigned int dma_cnt; }; struct rsnd_dmapp { @@ -34,6 +38,8 @@ struct rsnd_dmapp { struct rsnd_dma { struct rsnd_mod mod; + struct rsnd_mod *mod_from; + struct rsnd_mod *mod_to; dma_addr_t src_addr; dma_addr_t dst_addr; union { @@ -56,10 +62,38 @@ struct rsnd_dma_ctrl { /* * Audio DMAC */ +#define rsnd_dmaen_sync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 1) +#define rsnd_dmaen_unsync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 0) +static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io, + int i, int sync) +{ + struct device *dev = dmaen->chan->device->dev; + enum dma_data_direction dir; + int is_play = rsnd_io_is_play(io); + dma_addr_t buf; + int len, max; + size_t period; + + len = dmaen->dma_len; + period = dmaen->dma_period; + max = len / period; + i = i % max; + buf = dmaen->dma_buf + (period * i); + + dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + + if (sync) + dma_sync_single_for_device(dev, buf, period, dir); + else + dma_sync_single_for_cpu(dev, buf, period, dir); +} + static void __rsnd_dmaen_complete(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); bool elapsed = false; unsigned long flags; @@ -76,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, */ spin_lock_irqsave(&priv->lock, flags); - if (rsnd_io_is_working(io)) + if (rsnd_io_is_working(io)) { + rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt); + + /* + * Next period is already started. + * Let's sync Next Next period + * see + * rsnd_dmaen_start() + */ + rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); + elapsed = rsnd_dai_pointer_update(io, io->byte_per_period); + dmaen->dma_cnt++; + } + spin_unlock_irqrestore(&priv->lock, flags); if (elapsed) @@ -92,6 +139,20 @@ static void rsnd_dmaen_complete(void *data) rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); } +static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, + struct rsnd_mod *mod_from, + struct rsnd_mod *mod_to) +{ + if ((!mod_from && !mod_to) || + (mod_from && mod_to)) + return NULL; + + if (mod_from) + return rsnd_mod_dma_req(io, mod_from); + else + return rsnd_mod_dma_req(io, mod_to); +} + static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -99,7 +160,66 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - dmaengine_terminate_all(dmaen->chan); + if (dmaen->chan) { + int is_play = rsnd_io_is_play(io); + + dmaengine_terminate_all(dmaen->chan); + dma_unmap_single(dmaen->chan->device->dev, + dmaen->dma_buf, dmaen->dma_len, + is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + } + + return 0; +} + +static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + + /* + * DMAEngine release uses mutex lock. + * Thus, it shouldn't be called under spinlock. + * Let's call it under nolock_start + */ + if (dmaen->chan) + dma_release_channel(dmaen->chan); + + dmaen->chan = NULL; + + return 0; +} + +static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + struct device *dev = rsnd_priv_to_dev(priv); + + if (dmaen->chan) { + dev_err(dev, "it already has dma channel\n"); + return -EIO; + } + + /* + * DMAEngine request uses mutex lock. + * Thus, it shouldn't be called under spinlock. + * Let's call it under nolock_start + */ + dmaen->chan = rsnd_dmaen_request_channel(io, + dma->mod_from, + dma->mod_to); + if (IS_ERR_OR_NULL(dmaen->chan)) { + int ret = PTR_ERR(dmaen->chan); + + dmaen->chan = NULL; + dev_err(dev, "can't get dma channel\n"); + return ret; + } return 0; } @@ -113,12 +233,41 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; + struct dma_slave_config cfg = {}; + dma_addr_t buf; + size_t len; + size_t period; int is_play = rsnd_io_is_play(io); + int i; + int ret; + + cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + cfg.src_addr = dma->src_addr; + cfg.dst_addr = dma->dst_addr; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + dev_dbg(dev, "%s[%d] %pad -> %pad\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + &cfg.src_addr, &cfg.dst_addr); + + ret = dmaengine_slave_config(dmaen->chan, &cfg); + if (ret < 0) + return ret; + + len = snd_pcm_lib_buffer_bytes(substream); + period = snd_pcm_lib_period_bytes(substream); + buf = dma_map_single(dmaen->chan->device->dev, + substream->runtime->dma_area, + len, + is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (dma_mapping_error(dmaen->chan->device->dev, buf)) { + dev_err(dev, "dma map failed\n"); + return -EIO; + } desc = dmaengine_prep_dma_cyclic(dmaen->chan, - substream->runtime->dma_addr, - snd_pcm_lib_buffer_bytes(substream), - snd_pcm_lib_period_bytes(substream), + buf, len, period, is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -130,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, desc->callback = rsnd_dmaen_complete; desc->callback_param = rsnd_mod_get(dma); + dmaen->dma_buf = buf; + dmaen->dma_len = len; + dmaen->dma_period = period; + dmaen->dma_cnt = 0; + + /* + * synchronize this and next period + * see + * __rsnd_dmaen_complete() + */ + for (i = 0; i < 2; i++) + rsnd_dmaen_sync(dmaen, io, i); + if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return -EIO; @@ -143,124 +305,55 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name) { - struct dma_chan *chan; + struct dma_chan *chan = NULL; struct device_node *np; int i = 0; for_each_child_of_node(of_node, np) { - if (i == rsnd_mod_id(mod)) - break; + if (i == rsnd_mod_id(mod) && (!chan)) + chan = of_dma_request_slave_channel(np, name); i++; } - chan = of_dma_request_slave_channel(np, name); - - of_node_put(np); + /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ of_node_put(of_node); return chan; } -static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, - struct rsnd_mod *mod_from, - struct rsnd_mod *mod_to) -{ - if ((!mod_from && !mod_to) || - (mod_from && mod_to)) - return NULL; - - if (mod_from) - return rsnd_mod_dma_req(io, mod_from); - else - return rsnd_mod_dma_req(io, mod_to); -} - -static int rsnd_dmaen_remove(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - if (dmaen->chan) - dma_release_channel(dmaen->chan); - - dmaen->chan = NULL; - - return 0; -} - static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, + struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { - struct rsnd_mod *mod = rsnd_mod_get(dma); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_slave_config cfg = {}; - int is_play = rsnd_io_is_play(io); - int ret; - - if (dmaen->chan) { - dev_err(dev, "it already has dma channel\n"); - return -EIO; - } - - if (dev->of_node) { - dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); - } else { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + struct dma_chan *chan; - dmaen->chan = dma_request_channel(mask, shdma_chan_filter, - (void *)(uintptr_t)id); - } - if (IS_ERR_OR_NULL(dmaen->chan)) { - dmaen->chan = NULL; - dev_err(dev, "can't get dma channel\n"); - goto rsnd_dma_channel_err; + /* try to get DMAEngine channel */ + chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); + if (IS_ERR_OR_NULL(chan)) { + /* + * DMA failed. try to PIO mode + * see + * rsnd_ssi_fallback() + * rsnd_rdai_continuance_probe() + */ + return -EAGAIN; } - cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - cfg.src_addr = dma->src_addr; - cfg.dst_addr = dma->dst_addr; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - - dev_dbg(dev, "%s[%d] %pad -> %pad\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), - &cfg.src_addr, &cfg.dst_addr); - - ret = dmaengine_slave_config(dmaen->chan, &cfg); - if (ret < 0) - goto rsnd_dma_attach_err; + dma_release_channel(chan); dmac->dmaen_num++; return 0; - -rsnd_dma_attach_err: - rsnd_dmaen_remove(mod, io, priv); -rsnd_dma_channel_err: - - /* - * DMA failed. try to PIO mode - * see - * rsnd_ssi_fallback() - * rsnd_rdai_continuance_probe() - */ - return -EAGAIN; } static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", + .nolock_start = rsnd_dmaen_nolock_start, + .nolock_stop = rsnd_dmaen_nolock_stop, .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, - .remove = rsnd_dmaen_remove, }; /* @@ -394,7 +487,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod, } static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, + struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); @@ -627,7 +720,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, } int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - struct rsnd_mod **dma_mod, int id) + struct rsnd_mod **dma_mod) { struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; @@ -636,7 +729,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; enum rsnd_mod_type type; - int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, + int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); int ret, dma_id; @@ -682,9 +775,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, *dma_mod = rsnd_mod_get(dma); - dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); - dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); - ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, rsnd_mod_get_status, type, dma_id); if (ret < 0) @@ -695,9 +785,14 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); - ret = attach(io, dma, id, mod_from, mod_to); + ret = attach(io, dma, mod_from, mod_to); if (ret < 0) return ret; + + dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); + dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); + dma->mod_from = mod_from; + dma->mod_to = mod_to; } ret = rsnd_dai_connect(*dma_mod, io, type); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 02d971f69eff..cf8f59cdd8d7 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -48,8 +48,6 @@ struct rsnd_dvc { #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) -#define rsnd_dvc_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") #define rsnd_mod_to_dvc(_mod) \ container_of((_mod), struct rsnd_dvc, mod) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 7d2fdf8dd188..63b6d3c28021 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -211,6 +211,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_S_REG(SSI_MODE1, 0x804), RSND_GEN_S_REG(SSI_MODE2, 0x808), RSND_GEN_S_REG(SSI_CONTROL, 0x810), + RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840), + RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844), + RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848), + RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c), + RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880), + RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884), + RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), + RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c), /* FIXME: it needs SSI_MODE2/3 in the future */ RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), @@ -311,7 +319,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) static const struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRB, 0x04), - RSND_GEN_S_REG(SSICKR, 0x08), + RSND_GEN_S_REG(BRGCKR, 0x08), RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14), @@ -362,7 +370,7 @@ static int rsnd_gen1_probe(struct rsnd_priv *priv) static const struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRB, 0x04), - RSND_GEN_S_REG(SSICKR, 0x08), + RSND_GEN_S_REG(BRGCKR, 0x08), RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), }; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index a8f61d79333b..b90df77662df 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -43,17 +43,7 @@ * see gen1/gen2 for detail */ enum rsnd_reg { - /* SCU (SRC/SSIU/MIX/CTU/DVC) */ - RSND_REG_SSI_MODE, /* Gen2 only */ - RSND_REG_SSI_MODE0, - RSND_REG_SSI_MODE1, - RSND_REG_SSI_MODE2, - RSND_REG_SSI_CONTROL, - RSND_REG_SSI_CTRL, /* Gen2 only */ - RSND_REG_SSI_BUSIF_MODE, /* Gen2 only */ - RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */ - RSND_REG_SSI_BUSIF_DALIGN, /* Gen2 only */ - RSND_REG_SSI_INT_ENABLE, /* Gen2 only */ + /* SCU (MIX/CTU/DVC) */ RSND_REG_SRC_I_BUSIF_MODE, RSND_REG_SRC_O_BUSIF_MODE, RSND_REG_SRC_ROUTE_MODE0, @@ -63,29 +53,29 @@ enum rsnd_reg { RSND_REG_SRC_IFSCR, RSND_REG_SRC_IFSVR, RSND_REG_SRC_SRCCR, - RSND_REG_SRC_CTRL, /* Gen2 only */ - RSND_REG_SRC_BSDSR, /* Gen2 only */ - RSND_REG_SRC_BSISR, /* Gen2 only */ - RSND_REG_SRC_INT_ENABLE0, /* Gen2 only */ - RSND_REG_SRC_BUSIF_DALIGN, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL0, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL1, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL2, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL3, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL4, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL0, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL1, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL2, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL3, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL4, /* Gen2 only */ + RSND_REG_SRC_CTRL, + RSND_REG_SRC_BSDSR, + RSND_REG_SRC_BSISR, + RSND_REG_SRC_INT_ENABLE0, + RSND_REG_SRC_BUSIF_DALIGN, + RSND_REG_SRCIN_TIMSEL0, + RSND_REG_SRCIN_TIMSEL1, + RSND_REG_SRCIN_TIMSEL2, + RSND_REG_SRCIN_TIMSEL3, + RSND_REG_SRCIN_TIMSEL4, + RSND_REG_SRCOUT_TIMSEL0, + RSND_REG_SRCOUT_TIMSEL1, + RSND_REG_SRCOUT_TIMSEL2, + RSND_REG_SRCOUT_TIMSEL3, + RSND_REG_SRCOUT_TIMSEL4, RSND_REG_SCU_SYS_STATUS0, - RSND_REG_SCU_SYS_STATUS1, /* Gen2 only */ + RSND_REG_SCU_SYS_STATUS1, RSND_REG_SCU_SYS_INT_EN0, - RSND_REG_SCU_SYS_INT_EN1, /* Gen2 only */ - RSND_REG_CMD_CTRL, /* Gen2 only */ - RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */ + RSND_REG_SCU_SYS_INT_EN1, + RSND_REG_CMD_CTRL, + RSND_REG_CMD_BUSIF_DALIGN, RSND_REG_CMD_ROUTE_SLCT, - RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */ + RSND_REG_CMDOUT_TIMSEL, RSND_REG_CTU_SWRSR, RSND_REG_CTU_CTUIR, RSND_REG_CTU_ADINR, @@ -147,18 +137,38 @@ enum rsnd_reg { RSND_REG_DVC_VOL6R, RSND_REG_DVC_VOL7R, RSND_REG_DVC_DVUER, - RSND_REG_DVC_VRCTR, /* Gen2 only */ - RSND_REG_DVC_VRPDR, /* Gen2 only */ - RSND_REG_DVC_VRDBR, /* Gen2 only */ + RSND_REG_DVC_VRCTR, + RSND_REG_DVC_VRPDR, + RSND_REG_DVC_VRDBR, /* ADG */ RSND_REG_BRRA, RSND_REG_BRRB, - RSND_REG_SSICKR, - RSND_REG_DIV_EN, /* Gen2 only */ + RSND_REG_BRGCKR, + RSND_REG_DIV_EN, RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL1, - RSND_REG_AUDIO_CLK_SEL2, /* Gen2 only */ + RSND_REG_AUDIO_CLK_SEL2, + + /* SSIU */ + RSND_REG_SSI_MODE, + RSND_REG_SSI_MODE0, + RSND_REG_SSI_MODE1, + RSND_REG_SSI_MODE2, + RSND_REG_SSI_CONTROL, + RSND_REG_SSI_CTRL, + RSND_REG_SSI_BUSIF_MODE, + RSND_REG_SSI_BUSIF_ADINR, + RSND_REG_SSI_BUSIF_DALIGN, + RSND_REG_SSI_INT_ENABLE, + RSND_REG_SSI_SYS_STATUS0, + RSND_REG_SSI_SYS_STATUS1, + RSND_REG_SSI_SYS_STATUS2, + RSND_REG_SSI_SYS_STATUS3, + RSND_REG_SSI_SYS_STATUS4, + RSND_REG_SSI_SYS_STATUS5, + RSND_REG_SSI_SYS_STATUS6, + RSND_REG_SSI_SYS_STATUS7, /* SSI */ RSND_REG_SSICR, @@ -199,7 +209,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); * R-Car DMA */ int rsnd_dma_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id); + struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); @@ -259,6 +269,12 @@ struct rsnd_mod_ops { int (*fallback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + int (*nolock_start)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*nolock_stop)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); }; struct rsnd_dai_stream; @@ -278,7 +294,7 @@ struct rsnd_mod { * * 0xH0000CBA * - * A 0: probe 1: remove + * A 0: nolock_start 1: nolock_stop * B 0: init 1: quit * C 0: start 1: stop * @@ -288,19 +304,23 @@ struct rsnd_mod { * H 0: fallback * H 0: hw_params */ -#define __rsnd_mod_shift_probe 0 -#define __rsnd_mod_shift_remove 0 +#define __rsnd_mod_shift_nolock_start 0 +#define __rsnd_mod_shift_nolock_stop 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 #define __rsnd_mod_shift_stop 8 +#define __rsnd_mod_shift_probe 28 /* always called */ +#define __rsnd_mod_shift_remove 28 /* always called */ #define __rsnd_mod_shift_irq 28 /* always called */ #define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */ -#define __rsnd_mod_add_probe 1 -#define __rsnd_mod_add_remove -1 +#define __rsnd_mod_add_probe 0 +#define __rsnd_mod_add_remove 0 +#define __rsnd_mod_add_nolock_start 1 +#define __rsnd_mod_add_nolock_stop -1 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -311,7 +331,7 @@ struct rsnd_mod { #define __rsnd_mod_add_hw_params 0 #define __rsnd_mod_call_probe 0 -#define __rsnd_mod_call_remove 1 +#define __rsnd_mod_call_remove 0 #define __rsnd_mod_call_init 0 #define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_start 0 @@ -320,6 +340,8 @@ struct rsnd_mod { #define __rsnd_mod_call_pcm_new 0 #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 +#define __rsnd_mod_call_nolock_start 0 +#define __rsnd_mod_call_nolock_stop 1 #define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) @@ -346,6 +368,18 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, struct rsnd_mod *mod, enum rsnd_mod_type type); +struct rsnd_mod *rsnd_mod_next(int *iterator, + struct rsnd_dai_stream *io, + enum rsnd_mod_type *array, + int array_size); +#define for_each_rsnd_mod(iterator, pos, io) \ + for (iterator = 0; \ + (pos = rsnd_mod_next(&iterator, io, NULL, 0));) +#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size) \ + for (iterator = 0; \ + (pos = rsnd_mod_next(&iterator, io, array, size));) +#define for_each_rsnd_mod_array(iterator, pos, io, array) \ + for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array)) void rsnd_parse_connect_common(struct rsnd_dai *rdai, struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), @@ -365,6 +399,18 @@ int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); /* + * DT + */ +#define rsnd_parse_of_node(priv, node) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) +#define RSND_NODE_DAI "rcar_sound,dai" +#define RSND_NODE_SSI "rcar_sound,ssi" +#define RSND_NODE_SRC "rcar_sound,src" +#define RSND_NODE_CTU "rcar_sound,ctu" +#define RSND_NODE_MIX "rcar_sound,mix" +#define RSND_NODE_DVC "rcar_sound,dvc" + +/* * R-Car sound DAI */ #define RSND_DAI_NAME_SIZE 16 @@ -382,6 +428,7 @@ struct rsnd_dai_stream { }; #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU) #define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) @@ -428,8 +475,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type); -#define rsnd_dai_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai") +#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI) /* * R-Car Gen1/Gen2 @@ -453,6 +499,9 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, unsigned int out_rate); int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1) +#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0) +void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable); /* * R-Car sound priv @@ -606,8 +655,7 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); -#define rsnd_ssi_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") +#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI) void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); @@ -633,8 +681,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, int is_in); -#define rsnd_src_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") +#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC) #define rsnd_parse_connect_src(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \ rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -647,8 +694,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv); void rsnd_ctu_remove(struct rsnd_priv *priv); int rsnd_ctu_converted_channel(struct rsnd_mod *mod); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_ctu_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") +#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) #define rsnd_parse_connect_ctu(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \ rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -660,8 +706,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); int rsnd_mix_probe(struct rsnd_priv *priv); void rsnd_mix_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_mix_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix") +#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX) #define rsnd_parse_connect_mix(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \ rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -673,8 +718,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); int rsnd_dvc_probe(struct rsnd_priv *priv); void rsnd_dvc_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_dvc_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") +#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC) #define rsnd_parse_connect_dvc(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \ rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 969a5169de25..3a8f65bd1bf9 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -189,6 +189,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int use_src = 0; u32 fin, fout; u32 ifscr, fsrate, adinr; u32 cr, route; @@ -214,6 +215,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, return; } + use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod); + /* * SRC_ADINR */ @@ -225,7 +228,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, */ ifscr = 0; fsrate = 0; - if (fin != fout) { + if (use_src) { u64 n; ifscr = 1; @@ -239,7 +242,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, */ cr = 0x00011110; route = 0x0; - if (fin != fout) { + if (use_src) { route = 0x1; if (rsnd_src_sync_is_enabled(mod)) { @@ -327,8 +330,8 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod) { u32 val = OUF_SRC(rsnd_mod_id(mod)); - rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val); - rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); + rsnd_mod_write(mod, SCU_SYS_STATUS0, val); + rsnd_mod_write(mod, SCU_SYS_STATUS1, val); } static bool rsnd_src_error_occurred(struct rsnd_mod *mod) @@ -475,7 +478,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod, return ret; } - ret = rsnd_dma_attach(io, mod, &src->dma, 0); + ret = rsnd_dma_attach(io, mod, &src->dma); return ret; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 6cb6db005fc4..411bda2387ad 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -417,11 +417,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, int chan = params_channels(params); /* - * Already working. - * It will happen if SSI has parent/child connection. + * snd_pcm_ops::hw_params will be called *before* + * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0 + * in 1st call. */ - if (ssi->usrcnt > 1) { + if (ssi->usrcnt) { /* + * Already working. + * It will happen if SSI has parent/child connection. * it is error if child <-> parent SSI uses * different channels. */ @@ -644,10 +647,14 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, if (ret < 0) return ret; - ret = devm_request_irq(dev, ssi->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); + /* + * SSI might be called again as PIO fallback + * It is easy to manual handling for IRQ request/free + */ + ret = request_irq(ssi->irq, + rsnd_ssi_interrupt, + IRQF_SHARED, + dev_name(dev), mod); return ret; } @@ -669,7 +676,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int dma_id = 0; /* not needed */ int ret; /* @@ -684,7 +690,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, return ret; /* SSI probe might be called many times in MUX multi path */ - ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id); + ret = rsnd_dma_attach(io, mod, &ssi->dma); return ret; } @@ -694,11 +700,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct device *dev = rsnd_priv_to_dev(priv); - int irq = ssi->irq; /* PIO will request IRQ again */ - devm_free_irq(dev, irq, mod); + free_irq(ssi->irq, mod); return 0; } diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 6f9b388ec5a8..4e817c8a18c0 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -33,6 +33,26 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, u32 mask1, val1; u32 mask2, val2; + /* clear status */ + switch (id) { + case 0: + case 1: + case 2: + case 3: + case 4: + rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4)); + rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4)); + rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4)); + rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4)); + break; + case 9: + rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4); + rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4); + rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4); + rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4); + break; + } + /* * SSI_MODE0 */ diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index bf7b52fce597..bfd71b873ca2 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -30,16 +30,26 @@ static int soc_compr_open(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { + ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n", + cpu_dai->name, ret); + goto out; + } + } + if (platform->driver->compr_ops && platform->driver->compr_ops->open) { ret = platform->driver->compr_ops->open(cstream); if (ret < 0) { pr_err("compress asoc: can't open platform %s\n", platform->component.name); - goto out; + goto plat_err; } } @@ -60,6 +70,9 @@ static int soc_compr_open(struct snd_compr_stream *cstream) machine_err: if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); +plat_err: + if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) + cpu_dai->driver->cops->shutdown(cstream, cpu_dai); out: mutex_unlock(&rtd->pcm_mutex); return ret; @@ -70,6 +83,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; struct snd_soc_dpcm *dpcm; struct snd_soc_dapm_widget_list *list; int stream; @@ -82,12 +96,22 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { + ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n", + cpu_dai->name, ret); + goto out; + } + } + + if (platform->driver->compr_ops && platform->driver->compr_ops->open) { ret = platform->driver->compr_ops->open(cstream); if (ret < 0) { pr_err("compress asoc: can't open platform %s\n", platform->component.name); - goto out; + goto plat_err; } } @@ -144,6 +168,9 @@ fe_err: machine_err: if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); +plat_err: + if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) + cpu_dai->driver->cops->shutdown(cstream, cpu_dai); out: fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; mutex_unlock(&fe->card->mutex); @@ -210,6 +237,9 @@ static int soc_compr_free(struct snd_compr_stream *cstream) if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) + cpu_dai->driver->cops->shutdown(cstream, cpu_dai); + if (cstream->direction == SND_COMPRESS_PLAYBACK) { if (snd_soc_runtime_ignore_pmdown_time(rtd)) { snd_soc_dapm_stream_event(rtd, @@ -236,6 +266,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; struct snd_soc_dpcm *dpcm; int stream, ret; @@ -275,6 +306,9 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) + cpu_dai->driver->cops->shutdown(cstream, cpu_dai); + mutex_unlock(&fe->card->mutex); return 0; } @@ -285,6 +319,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -295,6 +330,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) goto out; } + if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) + cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); + + switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction); @@ -313,6 +352,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) { struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret = 0, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || @@ -332,6 +372,12 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) { + ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); + if (ret < 0) + goto out; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { ret = platform->driver->compr_ops->trigger(cstream, cmd); if (ret < 0) @@ -368,6 +414,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -378,6 +425,12 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, * expectation is that platform and machine will configure everything * for this compress path, like configuring pcm port for codec */ + if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) { + ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai); + if (ret < 0) + goto err; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) @@ -416,6 +469,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret = 0, stream; if (cstream->direction == SND_COMPRESS_PLAYBACK) @@ -425,6 +479,12 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) { + ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai); + if (ret < 0) + goto out; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) @@ -469,13 +529,21 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) { + ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai); + if (ret < 0) + goto err; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->get_params) ret = platform->driver->compr_ops->get_params(cstream, params); +err: mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -516,13 +584,21 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) { + ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai); + if (ret < 0) + goto err; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->ack) ret = platform->driver->compr_ops->ack(cstream, bytes); +err: mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -533,9 +609,13 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; int ret = 0; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer) + cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai); + if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) ret = platform->driver->compr_ops->pointer(cstream, tstamp); @@ -564,8 +644,15 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; + if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) { + ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai); + if (ret < 0) + return ret; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata) ret = platform->driver->compr_ops->set_metadata(cstream, metadata); @@ -577,8 +664,15 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; + if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) { + ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai); + if (ret < 0) + return ret; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata) ret = platform->driver->compr_ops->get_metadata(cstream, metadata); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0bbcd903261..f1901bb1466e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -626,7 +626,7 @@ static void codec2codec_close_delayed_work(struct work_struct *work) int snd_soc_suspend(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); - struct snd_soc_codec *codec; + struct snd_soc_component *component; struct snd_soc_pcm_runtime *rtd; int i; @@ -702,39 +702,39 @@ int snd_soc_suspend(struct device *dev) dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); - /* suspend all CODECs */ - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + /* suspend all COMPONENTs */ + list_for_each_entry(component, &card->component_dev_list, card_list) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - /* If there are paths active then the CODEC will be held with + /* If there are paths active then the COMPONENT will be held with * bias _ON and should not be suspended. */ - if (!codec->suspended) { + if (!component->suspended) { switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_STANDBY: /* - * If the CODEC is capable of idle + * If the COMPONENT is capable of idle * bias off then being in STANDBY * means it's doing something, * otherwise fall through. */ if (dapm->idle_bias_off) { - dev_dbg(codec->dev, + dev_dbg(component->dev, "ASoC: idle_bias_off CODEC on over suspend\n"); break; } case SND_SOC_BIAS_OFF: - if (codec->driver->suspend) - codec->driver->suspend(codec); - codec->suspended = 1; - if (codec->component.regmap) - regcache_mark_dirty(codec->component.regmap); + if (component->suspend) + component->suspend(component); + component->suspended = 1; + if (component->regmap) + regcache_mark_dirty(component->regmap); /* deactivate pins to sleep state */ - pinctrl_pm_select_sleep_state(codec->dev); + pinctrl_pm_select_sleep_state(component->dev); break; default: - dev_dbg(codec->dev, - "ASoC: CODEC is on over suspend\n"); + dev_dbg(component->dev, + "ASoC: COMPONENT is on over suspend\n"); break; } } @@ -768,7 +768,7 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_card *card = container_of(work, struct snd_soc_card, deferred_resume_work); struct snd_soc_pcm_runtime *rtd; - struct snd_soc_codec *codec; + struct snd_soc_component *component; int i; /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, @@ -794,11 +794,11 @@ static void soc_resume_deferred(struct work_struct *work) cpu_dai->driver->resume(cpu_dai); } - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (codec->suspended) { - if (codec->driver->resume) - codec->driver->resume(codec); - codec->suspended = 0; + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (component->suspended) { + if (component->resume) + component->resume(component); + component->suspended = 0; } } @@ -972,6 +972,48 @@ struct snd_soc_dai *snd_soc_find_dai( } EXPORT_SYMBOL_GPL(snd_soc_find_dai); + +/** + * snd_soc_find_dai_link - Find a DAI link + * + * @card: soc card + * @id: DAI link ID to match + * @name: DAI link name to match, optional + * @stream name: DAI link stream name to match, optional + * + * This function will search all existing DAI links of the soc card to + * find the link of the same ID. Since DAI links may not have their + * unique ID, so name and stream name should also match if being + * specified. + * + * Return: pointer of DAI link, or NULL if not found. + */ +struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, + int id, const char *name, + const char *stream_name) +{ + struct snd_soc_dai_link *link, *_link; + + lockdep_assert_held(&client_mutex); + + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + if (link->id != id) + continue; + + if (name && (!link->name || strcmp(name, link->name))) + continue; + + if (stream_name && (!link->stream_name + || strcmp(stream_name, link->stream_name))) + continue; + + return link; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_find_dai_link); + static bool soc_is_dai_link_bound(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -993,6 +1035,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_dai **codec_dais; struct snd_soc_platform *platform; + struct device_node *platform_of_node; const char *platform_name; int i; @@ -1042,9 +1085,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* find one from the set of registered platforms */ list_for_each_entry(platform, &platform_list, list) { + platform_of_node = platform->dev->of_node; + if (!platform_of_node && platform->dev->parent->of_node) + platform_of_node = platform->dev->parent->of_node; + if (dai_link->platform_of_node) { - if (platform->dev->of_node != - dai_link->platform_of_node) + if (platform_of_node != dai_link->platform_of_node) continue; } else { if (strcmp(platform->component.name, platform_name)) @@ -1072,9 +1118,7 @@ static void soc_remove_component(struct snd_soc_component *component) if (!component->card) return; - /* This is a HACK and will be removed soon */ - if (component->codec) - list_del(&component->codec->card_list); + list_del(&component->card_list); if (component->remove) component->remove(component); @@ -1443,10 +1487,7 @@ static int soc_probe_component(struct snd_soc_card *card, component->num_dapm_routes); list_add(&dapm->list, &card->dapm_list); - - /* This is a HACK and will be removed soon */ - if (component->codec) - list_add(&component->codec->card_list, &card->codec_dev_list); + list_add(&component->card_list, &card->component_dev_list); return 0; @@ -1706,7 +1747,8 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) } component->init = aux_dev->init; - list_add(&component->list_aux, &card->aux_comp_list); + component->auxiliary = 1; + return 0; err_defer: @@ -1722,7 +1764,10 @@ static int soc_probe_aux_devices(struct snd_soc_card *card) for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(comp, &card->aux_comp_list, list_aux) { + list_for_each_entry(comp, &card->component_dev_list, card_list) { + if (!comp->auxiliary) + continue; + if (comp->driver->probe_order == order) { ret = soc_probe_component(card, comp); if (ret < 0) { @@ -1746,11 +1791,14 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { list_for_each_entry_safe(comp, _comp, - &card->aux_comp_list, list_aux) { + &card->component_dev_list, card_list) { + + if (!comp->auxiliary) + continue; + if (comp->driver->remove_order == order) { soc_remove_component(comp); - /* remove it from the card's aux_comp_list */ - list_del(&comp->list_aux); + comp->auxiliary = 0; } } } @@ -2926,6 +2974,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->driver = driver; component->probe = component->driver->probe; component->remove = component->driver->remove; + component->suspend = component->driver->suspend; + component->resume = component->driver->resume; dapm = &component->dapm; dapm->dev = dev; @@ -3275,6 +3325,20 @@ static void snd_soc_codec_drv_remove(struct snd_soc_component *component) codec->driver->remove(codec); } +static int snd_soc_codec_drv_suspend(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->suspend(codec); +} + +static int snd_soc_codec_drv_resume(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->resume(codec); +} + static int snd_soc_codec_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { @@ -3336,6 +3400,10 @@ int snd_soc_register_codec(struct device *dev, codec->component.probe = snd_soc_codec_drv_probe; if (codec_drv->remove) codec->component.remove = snd_soc_codec_drv_remove; + if (codec_drv->suspend) + codec->component.suspend = snd_soc_codec_drv_suspend; + if (codec_drv->resume) + codec->component.resume = snd_soc_codec_drv_resume; if (codec_drv->write) codec->component.write = snd_soc_codec_drv_write; if (codec_drv->read) @@ -3424,10 +3492,10 @@ found: EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); /* Retrieve a card's name from device tree */ -int snd_soc_of_parse_card_name(struct snd_soc_card *card, - const char *propname) +int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, + struct device_node *np, + const char *propname) { - struct device_node *np; int ret; if (!card->dev) { @@ -3435,7 +3503,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, return -EINVAL; } - np = card->dev->of_node; + if (!np) + np = card->dev->of_node; ret = of_property_read_string_index(np, propname, 0, &card->name); /* @@ -3452,7 +3521,7 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name_from_node); static const struct snd_soc_dapm_widget simple_widgets[] = { SND_SOC_DAPM_MIC("Microphone", NULL), @@ -3461,14 +3530,17 @@ static const struct snd_soc_dapm_widget simple_widgets[] = { SND_SOC_DAPM_SPK("Speaker", NULL), }; -int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, +int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card, + struct device_node *np, const char *propname) { - struct device_node *np = card->dev->of_node; struct snd_soc_dapm_widget *widgets; const char *template, *wname; int i, j, num_widgets, ret; + if (!np) + np = card->dev->of_node; + num_widgets = of_property_count_strings(np, propname); if (num_widgets < 0) { dev_err(card->dev, @@ -3539,7 +3611,7 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets_from_node); static int snd_soc_of_get_slot_mask(struct device_node *np, const char *prop_name, @@ -3595,15 +3667,18 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); -void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, +void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card, + struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname) { - struct device_node *np = card->dev->of_node; const char *str; int ret; + if (!np) + np = card->dev->of_node; + ret = of_property_read_string(np, propname, &str); if (ret < 0) { /* no prefix is not error */ @@ -3613,16 +3688,19 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, codec_conf->of_node = of_node; codec_conf->name_prefix = str; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix_from_node); -int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, +int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card, + struct device_node *np, const char *propname) { - struct device_node *np = card->dev->of_node; int num_routes; struct snd_soc_dapm_route *routes; int i, ret; + if (!np) + np = card->dev->of_node; + num_routes = of_property_count_strings(np, propname); if (num_routes < 0 || num_routes & 1) { dev_err(card->dev, @@ -3669,7 +3747,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing_from_node); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix, @@ -3784,7 +3862,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); -static int snd_soc_get_dai_name(struct of_phandle_args *args, +int snd_soc_get_dai_name(struct of_phandle_args *args, const char **dai_name) { struct snd_soc_component *pos; @@ -3836,6 +3914,7 @@ static int snd_soc_get_dai_name(struct of_phandle_args *args, mutex_unlock(&client_mutex); return ret; } +EXPORT_SYMBOL_GPL(snd_soc_get_dai_name); int snd_soc_of_get_dai_name(struct device_node *of_node, const char **dai_name) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3bbe32ee4630..27dd02e57b31 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -330,6 +330,11 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, case snd_soc_dapm_mixer_named_ctl: mc = (struct soc_mixer_control *)kcontrol->private_value; + if (mc->autodisable && snd_soc_volsw_is_stereo(mc)) + dev_warn(widget->dapm->dev, + "ASoC: Unsupported stereo autodisable control '%s'\n", + ctrl_name); + if (mc->autodisable) { struct snd_soc_dapm_widget template; @@ -723,7 +728,8 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, } /* set up initial codec paths */ -static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) +static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i, + int nth_path) { struct soc_mixer_control *mc = (struct soc_mixer_control *) p->sink->kcontrol_news[i].private_value; @@ -736,7 +742,25 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) if (reg != SND_SOC_NOPM) { soc_dapm_read(p->sink->dapm, reg, &val); - val = (val >> shift) & mask; + /* + * The nth_path argument allows this function to know + * which path of a kcontrol it is setting the initial + * status for. Ideally this would support any number + * of paths and channels. But since kcontrols only come + * in mono and stereo variants, we are limited to 2 + * channels. + * + * The following code assumes for stereo controls the + * first path is the left channel, and all remaining + * paths are the right channel. + */ + if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) { + if (reg != mc->rreg) + soc_dapm_read(p->sink->dapm, mc->rreg, &val); + val = (val >> mc->rshift) & mask; + } else { + val = (val >> shift) & mask; + } if (invert) val = max - val; p->connect = !!val; @@ -749,13 +773,13 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_path *path, const char *control_name) { - int i; + int i, nth_path = 0; /* search for mixer kcontrol */ for (i = 0; i < path->sink->num_kcontrols; i++) { if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) { path->name = path->sink->kcontrol_news[i].name; - dapm_set_mixer_path_status(path, i); + dapm_set_mixer_path_status(path, i, nth_path++); return 0; } } @@ -1626,6 +1650,15 @@ static void dapm_widget_update(struct snd_soc_card *card) dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", w->name, ret); + if (update->has_second_set) { + ret = soc_dapm_update_bits(w->dapm, update->reg2, + update->mask2, update->val2); + if (ret < 0) + dev_err(w->dapm->dev, + "ASoC: %s DAPM update failed: %d\n", + w->name, ret); + } + for (wi = 0; wi < wlist->num_widgets; wi++) { w = wlist->widgets[wi]; @@ -2177,7 +2210,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); /* test and update the power status of a mixer or switch widget */ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, - struct snd_kcontrol *kcontrol, int connect) + struct snd_kcontrol *kcontrol, + int connect, int rconnect) { struct snd_soc_dapm_path *path; int found = 0; @@ -2186,8 +2220,33 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, /* find dapm widget path assoc with kcontrol */ dapm_kcontrol_for_each_path(path, kcontrol) { + /* + * Ideally this function should support any number of + * paths and channels. But since kcontrols only come + * in mono and stereo variants, we are limited to 2 + * channels. + * + * The following code assumes for stereo controls the + * first path (when 'found == 0') is the left channel, + * and all remaining paths (when 'found == 1') are the + * right channel. + * + * A stereo control is signified by a valid 'rconnect' + * value, either 0 for unconnected, or >= 0 for connected. + * This is chosen instead of using snd_soc_volsw_is_stereo, + * so that the behavior of snd_soc_dapm_mixer_update_power + * doesn't change even when the kcontrol passed in is + * stereo. + * + * It passes 'connect' as the path connect status for + * the left channel, and 'rconnect' for the right + * channel. + */ + if (found && rconnect >= 0) + soc_dapm_connect_path(path, rconnect, "mixer update"); + else + soc_dapm_connect_path(path, connect, "mixer update"); found = 1; - soc_dapm_connect_path(path, connect, "mixer update"); } if (found) @@ -2205,7 +2264,7 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); card->update = update; - ret = soc_dapm_mixer_update_power(card, kcontrol, connect); + ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1); card->update = NULL; mutex_unlock(&card->dapm_mutex); if (ret > 0) @@ -3030,22 +3089,28 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; + unsigned int width = fls(max); unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; - unsigned int val; + unsigned int reg_val, val, rval = 0; int ret = 0; - if (snd_soc_volsw_is_stereo(mc)) - dev_warn(dapm->dev, - "ASoC: Control '%s' is stereo, which is not supported\n", - kcontrol->id.name); - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) { - ret = soc_dapm_read(dapm, reg, &val); - val = (val >> shift) & mask; + ret = soc_dapm_read(dapm, reg, ®_val); + val = (reg_val >> shift) & mask; + + if (ret == 0 && reg != mc->rreg) + ret = soc_dapm_read(dapm, mc->rreg, ®_val); + + if (snd_soc_volsw_is_stereo(mc)) + rval = (reg_val >> mc->rshift) & mask; } else { - val = dapm_kcontrol_get_value(kcontrol); + reg_val = dapm_kcontrol_get_value(kcontrol); + val = reg_val & mask; + + if (snd_soc_volsw_is_stereo(mc)) + rval = (reg_val >> width) & mask; } mutex_unlock(&card->dapm_mutex); @@ -3057,6 +3122,13 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, else ucontrol->value.integer.value[0] = val; + if (snd_soc_volsw_is_stereo(mc)) { + if (invert) + ucontrol->value.integer.value[1] = max - rval; + else + ucontrol->value.integer.value[1] = rval; + } + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); @@ -3080,46 +3152,66 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; - unsigned int mask = (1 << fls(max)) - 1; + unsigned int width = fls(max); + unsigned int mask = (1 << width) - 1; unsigned int invert = mc->invert; - unsigned int val; - int connect, change, reg_change = 0; - struct snd_soc_dapm_update update; + unsigned int val, rval = 0; + int connect, rconnect = -1, change, reg_change = 0; + struct snd_soc_dapm_update update = { NULL }; int ret = 0; - if (snd_soc_volsw_is_stereo(mc)) - dev_warn(dapm->dev, - "ASoC: Control '%s' is stereo, which is not supported\n", - kcontrol->id.name); - val = (ucontrol->value.integer.value[0] & mask); connect = !!val; if (invert) val = max - val; + if (snd_soc_volsw_is_stereo(mc)) { + rval = (ucontrol->value.integer.value[1] & mask); + rconnect = !!rval; + if (invert) + rval = max - rval; + } + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - change = dapm_kcontrol_set_value(kcontrol, val); + /* This assumes field width < (bits in unsigned int / 2) */ + if (width > sizeof(unsigned int) * 8 / 2) + dev_warn(dapm->dev, + "ASoC: control %s field width limit exceeded\n", + kcontrol->id.name); + change = dapm_kcontrol_set_value(kcontrol, val | (rval << width)); if (reg != SND_SOC_NOPM) { - mask = mask << shift; val = val << shift; + rval = rval << mc->rshift; + + reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val); - reg_change = soc_dapm_test_bits(dapm, reg, mask, val); + if (snd_soc_volsw_is_stereo(mc)) + reg_change |= soc_dapm_test_bits(dapm, mc->rreg, + mask << mc->rshift, + rval); } if (change || reg_change) { if (reg_change) { + if (snd_soc_volsw_is_stereo(mc)) { + update.has_second_set = true; + update.reg2 = mc->rreg; + update.mask2 = mask << mc->rshift; + update.val2 = rval; + } update.kcontrol = kcontrol; update.reg = reg; - update.mask = mask; + update.mask = mask << shift; update.val = val; card->update = &update; } change |= reg_change; - ret = soc_dapm_mixer_update_power(card, kcontrol, connect); + ret = soc_dapm_mixer_update_power(card, kcontrol, connect, + rconnect); card->update = NULL; } @@ -3192,7 +3284,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, unsigned int *item = ucontrol->value.enumerated.item; unsigned int val, change, reg_change = 0; unsigned int mask; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { NULL }; int ret = 0; if (item[0] >= e->items) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6cef3977507a..17eb14935577 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -263,7 +263,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); const struct snd_dmaengine_pcm_config *config = pcm->config; struct device *dev = rtd->platform->dev; - struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; size_t prealloc_buffer_size; size_t max_buffer_size; @@ -278,19 +277,11 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) max_buffer_size = SIZE_MAX; } - for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { substream = rtd->pcm->streams[i].substream; if (!substream) continue; - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - if (!pcm->chan[i] && - (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) - pcm->chan[i] = dma_request_slave_channel(dev, - dma_data->chan_name); - if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, substream); @@ -359,9 +350,7 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, const char *name; struct dma_chan *chan; - if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | - SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - !dev->of_node) + if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !dev->of_node) return 0; if (config && config->dma_dev) { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d56a16a0f6fa..e7a1eaa2772f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2882,7 +2882,7 @@ int snd_soc_platform_trigger(struct snd_pcm_substream *substream, EXPORT_SYMBOL_GPL(snd_soc_platform_trigger); #ifdef CONFIG_DEBUG_FS -static char *dpcm_state_string(enum snd_soc_dpcm_state state) +static const char *dpcm_state_string(enum snd_soc_dpcm_state state) { switch (state) { case SND_SOC_DPCM_STATE_NEW: diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 6b05047a4134..65670b2b408c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -49,10 +49,68 @@ #define SOC_TPLG_PASS_GRAPH 5 #define SOC_TPLG_PASS_PINS 6 #define SOC_TPLG_PASS_BE_DAI 7 +#define SOC_TPLG_PASS_LINK 8 #define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST -#define SOC_TPLG_PASS_END SOC_TPLG_PASS_BE_DAI +#define SOC_TPLG_PASS_END SOC_TPLG_PASS_LINK +/* + * Old version of ABI structs, supported for backward compatibility. + */ + +/* Manifest v4 */ +struct snd_soc_tplg_manifest_v4 { + __le32 size; /* in bytes of this structure */ + __le32 control_elems; /* number of control elements */ + __le32 widget_elems; /* number of widget elements */ + __le32 graph_elems; /* number of graph elements */ + __le32 pcm_elems; /* number of PCM elements */ + __le32 dai_link_elems; /* number of DAI link elements */ + struct snd_soc_tplg_private priv; +} __packed; + +/* Stream Capabilities v4 */ +struct snd_soc_tplg_stream_caps_v4 { + __le32 size; /* in bytes of this structure */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le64 formats; /* supported formats SNDRV_PCM_FMTBIT_* */ + __le32 rates; /* supported rates SNDRV_PCM_RATE_* */ + __le32 rate_min; /* min rate */ + __le32 rate_max; /* max rate */ + __le32 channels_min; /* min channels */ + __le32 channels_max; /* max channels */ + __le32 periods_min; /* min number of periods */ + __le32 periods_max; /* max number of periods */ + __le32 period_size_min; /* min period size bytes */ + __le32 period_size_max; /* max period size bytes */ + __le32 buffer_size_min; /* min buffer size bytes */ + __le32 buffer_size_max; /* max buffer size bytes */ +} __packed; + +/* PCM v4 */ +struct snd_soc_tplg_pcm_v4 { + __le32 size; /* in bytes of this structure */ + char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le32 pcm_id; /* unique ID - used to match with DAI link */ + __le32 dai_id; /* unique ID - used to match */ + __le32 playback; /* supports playback mode */ + __le32 capture; /* supports capture mode */ + __le32 compress; /* 1 = compressed; 0 = PCM */ + struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */ + __le32 num_streams; /* number of streams */ + struct snd_soc_tplg_stream_caps_v4 caps[2]; /* playback and capture for DAI */ +} __packed; + +/* Physical link config v4 */ +struct snd_soc_tplg_link_config_v4 { + __le32 size; /* in bytes of this structure */ + __le32 id; /* unique ID - used to match */ + struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */ + __le32 num_streams; /* number of streams */ +} __packed; + +/* topology context */ struct soc_tplg { const struct firmware *fw; @@ -428,33 +486,41 @@ static void remove_widget(struct snd_soc_component *comp, dobj->ops->widget_unload(comp, dobj); /* - * Dynamic Widgets either have 1 enum kcontrol or 1..N mixers. + * Dynamic Widgets either have 1..N enum kcontrols or mixers. * The enum may either have an array of values or strings. */ - if (dobj->widget.kcontrol_enum) { + if (dobj->widget.kcontrol_type == SND_SOC_TPLG_TYPE_ENUM) { /* enumerated widget mixer */ - struct soc_enum *se = - (struct soc_enum *)w->kcontrols[0]->private_value; + for (i = 0; i < w->num_kcontrols; i++) { + struct snd_kcontrol *kcontrol = w->kcontrols[i]; + struct soc_enum *se = + (struct soc_enum *)kcontrol->private_value; - snd_ctl_remove(card, w->kcontrols[0]); + snd_ctl_remove(card, kcontrol); - kfree(se->dobj.control.dvalues); - for (i = 0; i < se->items; i++) - kfree(se->dobj.control.dtexts[i]); + kfree(se->dobj.control.dvalues); + for (i = 0; i < se->items; i++) + kfree(se->dobj.control.dtexts[i]); - kfree(se); + kfree(se); + } kfree(w->kcontrol_news); } else { - /* non enumerated widget mixer */ + /* volume mixer or bytes controls */ for (i = 0; i < w->num_kcontrols; i++) { struct snd_kcontrol *kcontrol = w->kcontrols[i]; - struct soc_mixer_control *sm = - (struct soc_mixer_control *) kcontrol->private_value; - kfree(w->kcontrols[i]->tlv.p); + if (dobj->widget.kcontrol_type + == SND_SOC_TPLG_TYPE_MIXER) + kfree(kcontrol->tlv.p); - snd_ctl_remove(card, w->kcontrols[i]); - kfree(sm); + snd_ctl_remove(card, kcontrol); + + /* Private value is used as struct soc_mixer_control + * for volume mixers or soc_bytes_ext for bytes + * controls. + */ + kfree((void *)kcontrol->private_value); } kfree(w->kcontrol_news); } @@ -474,6 +540,7 @@ static void remove_dai(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->dai_unload) dobj->ops->dai_unload(comp, dobj); + kfree(dai_drv->name); list_del(&dobj->list); kfree(dai_drv); } @@ -491,6 +558,10 @@ static void remove_link(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->link_unload) dobj->ops->link_unload(comp, dobj); + kfree(link->name); + kfree(link->stream_name); + kfree(link->cpu_dai_name); + list_del(&dobj->list); snd_soc_remove_dai_link(comp->card, link); kfree(link); @@ -1193,98 +1264,105 @@ err: } static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( - struct soc_tplg *tplg) + struct soc_tplg *tplg, int num_kcontrols) { struct snd_kcontrol_new *kc; struct snd_soc_tplg_enum_control *ec; struct soc_enum *se; - int i, err; - - ec = (struct snd_soc_tplg_enum_control *)tplg->pos; - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - ec->priv.size); + int i, j, err; - /* validate kcontrol */ - if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return NULL; - - kc = kzalloc(sizeof(*kc), GFP_KERNEL); + kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL); if (kc == NULL) return NULL; - se = kzalloc(sizeof(*se), GFP_KERNEL); - if (se == NULL) - goto err; + for (i = 0; i < num_kcontrols; i++) { + ec = (struct snd_soc_tplg_enum_control *)tplg->pos; + /* validate kcontrol */ + if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return NULL; - dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", - ec->hdr.name); + se = kzalloc(sizeof(*se), GFP_KERNEL); + if (se == NULL) + goto err; - kc->name = ec->hdr.name; - kc->private_value = (long)se; - kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc->access = ec->hdr.access; + dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", + ec->hdr.name); + + kc[i].name = ec->hdr.name; + kc[i].private_value = (long)se; + kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc[i].access = ec->hdr.access; - /* we only support FL/FR channel mapping atm */ - se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_l = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR); + /* we only support FL/FR channel mapping atm */ + se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); + se->shift_l = tplc_chan_get_shift(tplg, ec->channel, + SNDRV_CHMAP_FL); + se->shift_r = tplc_chan_get_shift(tplg, ec->channel, + SNDRV_CHMAP_FR); - se->items = ec->items; - se->mask = ec->mask; - se->dobj.index = tplg->index; + se->items = ec->items; + se->mask = ec->mask; + se->dobj.index = tplg->index; - switch (ec->hdr.ops.info) { - case SND_SOC_TPLG_CTL_ENUM_VALUE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - err = soc_tplg_denum_create_values(se, ec); - if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create values for %s\n", - ec->hdr.name); + switch (ec->hdr.ops.info) { + case SND_SOC_TPLG_CTL_ENUM_VALUE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + err = soc_tplg_denum_create_values(se, ec); + if (err < 0) { + dev_err(tplg->dev, "ASoC: could not create values for %s\n", + ec->hdr.name); + goto err_se; + } + /* fall through to create texts */ + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: + err = soc_tplg_denum_create_texts(se, ec); + if (err < 0) { + dev_err(tplg->dev, "ASoC: could not create texts for %s\n", + ec->hdr.name); + goto err_se; + } + break; + default: + dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", + ec->hdr.ops.info, ec->hdr.name); goto err_se; } - /* fall through to create texts */ - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - err = soc_tplg_denum_create_texts(se, ec); + + /* map io handlers */ + err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc[i], tplg); + if (err) { + soc_control_err(tplg, &ec->hdr, ec->hdr.name); + goto err_se; + } + + /* pass control to driver for optional further init */ + err = soc_tplg_init_kcontrol(tplg, &kc[i], + (struct snd_soc_tplg_ctl_hdr *)ec); if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create texts for %s\n", + dev_err(tplg->dev, "ASoC: failed to init %s\n", ec->hdr.name); goto err_se; } - break; - default: - dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", - ec->hdr.ops.info, ec->hdr.name); - goto err_se; - } - /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg); - if (err) { - soc_control_err(tplg, &ec->hdr, ec->hdr.name); - goto err_se; - } - - /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, kc, - (struct snd_soc_tplg_ctl_hdr *)ec); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", - ec->hdr.name); - goto err_se; + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + + ec->priv.size); } return kc; err_se: - /* free values and texts */ - kfree(se->dobj.control.dvalues); - for (i = 0; i < ec->items; i++) - kfree(se->dobj.control.dtexts[i]); + for (; i >= 0; i--) { + /* free values and texts */ + se = (struct soc_enum *)kc[i].private_value; + kfree(se->dobj.control.dvalues); + for (j = 0; j < ec->items; j++) + kfree(se->dobj.control.dtexts[j]); - kfree(se); + kfree(se); + } err: kfree(kc); @@ -1366,6 +1444,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, struct snd_soc_dapm_widget template, *widget; struct snd_soc_tplg_ctl_hdr *control_hdr; struct snd_soc_card *card = tplg->comp->card; + unsigned int kcontrol_type; int ret = 0; if (strnlen(w->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == @@ -1406,6 +1485,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, tplg->pos += (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size); if (w->num_kcontrols == 0) { + kcontrol_type = 0; template.num_kcontrols = 0; goto widget; } @@ -1421,6 +1501,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, case SND_SOC_TPLG_CTL_VOLSW_XR_SX: case SND_SOC_TPLG_CTL_RANGE: case SND_SOC_TPLG_DAPM_CTL_VOLSW: + kcontrol_type = SND_SOC_TPLG_TYPE_MIXER; /* volume mixer */ template.num_kcontrols = w->num_kcontrols; template.kcontrol_news = soc_tplg_dapm_widget_dmixer_create(tplg, @@ -1435,16 +1516,18 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - template.dobj.widget.kcontrol_enum = 1; - template.num_kcontrols = 1; + kcontrol_type = SND_SOC_TPLG_TYPE_ENUM; /* enumerated mixer */ + template.num_kcontrols = w->num_kcontrols; template.kcontrol_news = - soc_tplg_dapm_widget_denum_create(tplg); + soc_tplg_dapm_widget_denum_create(tplg, + template.num_kcontrols); if (!template.kcontrol_news) { ret = -ENOMEM; goto hdr_err; } break; case SND_SOC_TPLG_CTL_BYTES: + kcontrol_type = SND_SOC_TPLG_TYPE_BYTES; /* bytes control */ template.num_kcontrols = w->num_kcontrols; template.kcontrol_news = soc_tplg_dapm_widget_dbytes_create(tplg, @@ -1481,6 +1564,7 @@ widget: } widget->dobj.type = SND_SOC_DOBJ_WIDGET; + widget->dobj.widget.kcontrol_type = kcontrol_type; widget->dobj.ops = tplg->ops; widget->dobj.index = tplg->index; kfree(template.sname); @@ -1589,7 +1673,8 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, if (dai_drv == NULL) return -ENOMEM; - dai_drv->name = pcm->dai_name; + if (strlen(pcm->dai_name)) + dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL); dai_drv->id = pcm->dai_id; if (pcm->playback) { @@ -1621,8 +1706,31 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, return snd_soc_register_dai(tplg->comp, dai_drv); } +static void set_link_flags(struct snd_soc_dai_link *link, + unsigned int flag_mask, unsigned int flags) +{ + if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES) + link->symmetric_rates = + flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES ? 1 : 0; + + if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS) + link->symmetric_channels = + flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS ? + 1 : 0; + + if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS) + link->symmetric_samplebits = + flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS ? + 1 : 0; + + if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP) + link->ignore_suspend = + flags & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP ? + 1 : 0; +} + /* create the FE DAI link */ -static int soc_tplg_link_create(struct soc_tplg *tplg, +static int soc_tplg_fe_link_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) { struct snd_soc_dai_link *link; @@ -1632,11 +1740,15 @@ static int soc_tplg_link_create(struct soc_tplg *tplg, if (link == NULL) return -ENOMEM; - link->name = pcm->pcm_name; - link->stream_name = pcm->pcm_name; + if (strlen(pcm->pcm_name)) { + link->name = kstrdup(pcm->pcm_name, GFP_KERNEL); + link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL); + } link->id = pcm->pcm_id; - link->cpu_dai_name = pcm->dai_name; + if (strlen(pcm->dai_name)) + link->cpu_dai_name = kstrdup(pcm->dai_name, GFP_KERNEL); + link->codec_name = "snd-soc-dummy"; link->codec_dai_name = "snd-soc-dummy-dai"; @@ -1644,6 +1756,8 @@ static int soc_tplg_link_create(struct soc_tplg *tplg, link->dynamic = 1; link->dpcm_playback = pcm->playback; link->dpcm_capture = pcm->capture; + if (pcm->flag_mask) + set_link_flags(link, pcm->flag_mask, pcm->flags); /* pass control to component driver for optional further init */ ret = soc_tplg_dai_link_load(tplg, link); @@ -1672,55 +1786,351 @@ static int soc_tplg_pcm_create(struct soc_tplg *tplg, if (ret < 0) return ret; - return soc_tplg_link_create(tplg, pcm); + return soc_tplg_fe_link_create(tplg, pcm); +} + +/* copy stream caps from the old version 4 of source */ +static void stream_caps_new_ver(struct snd_soc_tplg_stream_caps *dest, + struct snd_soc_tplg_stream_caps_v4 *src) +{ + dest->size = sizeof(*dest); + memcpy(dest->name, src->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + dest->formats = src->formats; + dest->rates = src->rates; + dest->rate_min = src->rate_min; + dest->rate_max = src->rate_max; + dest->channels_min = src->channels_min; + dest->channels_max = src->channels_max; + dest->periods_min = src->periods_min; + dest->periods_max = src->periods_max; + dest->period_size_min = src->period_size_min; + dest->period_size_max = src->period_size_max; + dest->buffer_size_min = src->buffer_size_min; + dest->buffer_size_max = src->buffer_size_max; +} + +/** + * pcm_new_ver - Create the new version of PCM from the old version. + * @tplg: topology context + * @src: older version of pcm as a source + * @pcm: latest version of pcm created from the source + * + * Support from vesion 4. User should free the returned pcm manually. + */ +static int pcm_new_ver(struct soc_tplg *tplg, + struct snd_soc_tplg_pcm *src, + struct snd_soc_tplg_pcm **pcm) +{ + struct snd_soc_tplg_pcm *dest; + struct snd_soc_tplg_pcm_v4 *src_v4; + int i; + + *pcm = NULL; + + if (src->size != sizeof(*src_v4)) { + dev_err(tplg->dev, "ASoC: invalid PCM size\n"); + return -EINVAL; + } + + dev_warn(tplg->dev, "ASoC: old version of PCM\n"); + src_v4 = (struct snd_soc_tplg_pcm_v4 *)src; + dest = kzalloc(sizeof(*dest), GFP_KERNEL); + if (!dest) + return -ENOMEM; + + dest->size = sizeof(*dest); /* size of latest abi version */ + memcpy(dest->pcm_name, src_v4->pcm_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + memcpy(dest->dai_name, src_v4->dai_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + dest->pcm_id = src_v4->pcm_id; + dest->dai_id = src_v4->dai_id; + dest->playback = src_v4->playback; + dest->capture = src_v4->capture; + dest->compress = src_v4->compress; + dest->num_streams = src_v4->num_streams; + for (i = 0; i < dest->num_streams; i++) + memcpy(&dest->stream[i], &src_v4->stream[i], + sizeof(struct snd_soc_tplg_stream)); + + for (i = 0; i < 2; i++) + stream_caps_new_ver(&dest->caps[i], &src_v4->caps[i]); + + *pcm = dest; + return 0; } static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { - struct snd_soc_tplg_pcm *pcm; + struct snd_soc_tplg_pcm *pcm, *_pcm; int count = hdr->count; - int i; + int i, err; + bool abi_match; if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) return 0; + /* check the element size and count */ + pcm = (struct snd_soc_tplg_pcm *)tplg->pos; + if (pcm->size > sizeof(struct snd_soc_tplg_pcm) + || pcm->size < sizeof(struct snd_soc_tplg_pcm_v4)) { + dev_err(tplg->dev, "ASoC: invalid size %d for PCM elems\n", + pcm->size); + return -EINVAL; + } + if (soc_tplg_check_elem_count(tplg, - sizeof(struct snd_soc_tplg_pcm), count, + pcm->size, count, hdr->payload_size, "PCM DAI")) { dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n", count); return -EINVAL; } - /* create the FE DAIs and DAI links */ - pcm = (struct snd_soc_tplg_pcm *)tplg->pos; for (i = 0; i < count; i++) { - if (pcm->size != sizeof(*pcm)) { - dev_err(tplg->dev, "ASoC: invalid pcm size\n"); - return -EINVAL; + pcm = (struct snd_soc_tplg_pcm *)tplg->pos; + + /* check ABI version by size, create a new version of pcm + * if abi not match. + */ + if (pcm->size == sizeof(*pcm)) { + abi_match = true; + _pcm = pcm; + } else { + abi_match = false; + err = pcm_new_ver(tplg, pcm, &_pcm); } - soc_tplg_pcm_create(tplg, pcm); - pcm++; + /* create the FE DAIs and DAI links */ + soc_tplg_pcm_create(tplg, _pcm); + + /* offset by version-specific struct size and + * real priv data size + */ + tplg->pos += pcm->size + _pcm->priv.size; + + if (!abi_match) + kfree(_pcm); /* free the duplicated one */ } dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count); - tplg->pos += sizeof(struct snd_soc_tplg_pcm) * count; return 0; } -/* * - * soc_tplg_be_dai_config - Find and configure an existing BE DAI. +/** + * set_link_hw_format - Set the HW audio format of the physical DAI link. + * @tplg: topology context + * @cfg: physical link configs. + * + * Topology context contains a list of supported HW formats (configs) and + * a default format ID for the physical link. This function will use this + * default ID to choose the HW format to set the link's DAI format for init. + */ +static void set_link_hw_format(struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg) +{ + struct snd_soc_tplg_hw_config *hw_config; + unsigned char bclk_master, fsync_master; + unsigned char invert_bclk, invert_fsync; + int i; + + for (i = 0; i < cfg->num_hw_configs; i++) { + hw_config = &cfg->hw_config[i]; + if (hw_config->id != cfg->default_hw_config_id) + continue; + + link->dai_fmt = hw_config->fmt & SND_SOC_DAIFMT_FORMAT_MASK; + + /* clock signal polarity */ + invert_bclk = hw_config->invert_bclk; + invert_fsync = hw_config->invert_fsync; + if (!invert_bclk && !invert_fsync) + link->dai_fmt |= SND_SOC_DAIFMT_NB_NF; + else if (!invert_bclk && invert_fsync) + link->dai_fmt |= SND_SOC_DAIFMT_NB_IF; + else if (invert_bclk && !invert_fsync) + link->dai_fmt |= SND_SOC_DAIFMT_IB_NF; + else + link->dai_fmt |= SND_SOC_DAIFMT_IB_IF; + + /* clock masters */ + bclk_master = hw_config->bclk_master; + fsync_master = hw_config->fsync_master; + if (!bclk_master && !fsync_master) + link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + else if (bclk_master && !fsync_master) + link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; + else if (!bclk_master && fsync_master) + link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; + else + link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } +} + +/** + * link_new_ver - Create a new physical link config from the old + * version of source. + * @toplogy: topology context + * @src: old version of phyical link config as a source + * @link: latest version of physical link config created from the source + * + * Support from vesion 4. User need free the returned link config manually. + */ +static int link_new_ver(struct soc_tplg *tplg, + struct snd_soc_tplg_link_config *src, + struct snd_soc_tplg_link_config **link) +{ + struct snd_soc_tplg_link_config *dest; + struct snd_soc_tplg_link_config_v4 *src_v4; + int i; + + *link = NULL; + + if (src->size != sizeof(struct snd_soc_tplg_link_config_v4)) { + dev_err(tplg->dev, "ASoC: invalid physical link config size\n"); + return -EINVAL; + } + + dev_warn(tplg->dev, "ASoC: old version of physical link config\n"); + + src_v4 = (struct snd_soc_tplg_link_config_v4 *)src; + dest = kzalloc(sizeof(*dest), GFP_KERNEL); + if (!dest) + return -ENOMEM; + + dest->size = sizeof(*dest); + dest->id = src_v4->id; + dest->num_streams = src_v4->num_streams; + for (i = 0; i < dest->num_streams; i++) + memcpy(&dest->stream[i], &src_v4->stream[i], + sizeof(struct snd_soc_tplg_stream)); + + *link = dest; + return 0; +} + +/* Find and configure an existing physical DAI link */ +static int soc_tplg_link_config(struct soc_tplg *tplg, + struct snd_soc_tplg_link_config *cfg) +{ + struct snd_soc_dai_link *link; + const char *name, *stream_name; + size_t len; + int ret; + + len = strnlen(cfg->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + if (len == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; + else if (len) + name = cfg->name; + else + name = NULL; + + len = strnlen(cfg->stream_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + if (len == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; + else if (len) + stream_name = cfg->stream_name; + else + stream_name = NULL; + + link = snd_soc_find_dai_link(tplg->comp->card, cfg->id, + name, stream_name); + if (!link) { + dev_err(tplg->dev, "ASoC: physical link %s (id %d) not exist\n", + name, cfg->id); + return -EINVAL; + } + + /* hw format */ + if (cfg->num_hw_configs) + set_link_hw_format(link, cfg); + + /* flags */ + if (cfg->flag_mask) + set_link_flags(link, cfg->flag_mask, cfg->flags); + + /* pass control to component driver for optional further init */ + ret = soc_tplg_dai_link_load(tplg, link); + if (ret < 0) { + dev_err(tplg->dev, "ASoC: physical link loading failed\n"); + return ret; + } + + return 0; +} + + +/* Load physical link config elements from the topology context */ +static int soc_tplg_link_elems_load(struct soc_tplg *tplg, + struct snd_soc_tplg_hdr *hdr) +{ + struct snd_soc_tplg_link_config *link, *_link; + int count = hdr->count; + int i, ret; + bool abi_match; + + if (tplg->pass != SOC_TPLG_PASS_LINK) { + tplg->pos += hdr->size + hdr->payload_size; + return 0; + }; + + /* check the element size and count */ + link = (struct snd_soc_tplg_link_config *)tplg->pos; + if (link->size > sizeof(struct snd_soc_tplg_link_config) + || link->size < sizeof(struct snd_soc_tplg_link_config_v4)) { + dev_err(tplg->dev, "ASoC: invalid size %d for physical link elems\n", + link->size); + return -EINVAL; + } + + if (soc_tplg_check_elem_count(tplg, + link->size, count, + hdr->payload_size, "physical link config")) { + dev_err(tplg->dev, "ASoC: invalid count %d for physical link elems\n", + count); + return -EINVAL; + } + + /* config physical DAI links */ + for (i = 0; i < count; i++) { + link = (struct snd_soc_tplg_link_config *)tplg->pos; + if (link->size == sizeof(*link)) { + abi_match = true; + _link = link; + } else { + abi_match = false; + ret = link_new_ver(tplg, link, &_link); + if (ret < 0) + return ret; + } + + ret = soc_tplg_link_config(tplg, _link); + if (ret < 0) + return ret; + + /* offset by version-specific struct size and + * real priv data size + */ + tplg->pos += link->size + _link->priv.size; + + if (!abi_match) + kfree(_link); /* free the duplicated one */ + } + + return 0; +} + +/** + * soc_tplg_dai_config - Find and configure an existing physical DAI. * @tplg: topology context - * @be: topology BE DAI configs. + * @d: physical DAI configs. * - * The BE dai should already be registered by the platform driver. The - * platform driver should specify the BE DAI name and ID for matching. + * The physical dai should already be registered by the platform driver. + * The platform driver should specify the DAI name and ID for matching. */ -static int soc_tplg_be_dai_config(struct soc_tplg *tplg, - struct snd_soc_tplg_be_dai *be) +static int soc_tplg_dai_config(struct soc_tplg *tplg, + struct snd_soc_tplg_dai *d) { struct snd_soc_dai_link_component dai_component = {0}; struct snd_soc_dai *dai; @@ -1729,17 +2139,17 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg, struct snd_soc_tplg_stream_caps *caps; int ret; - dai_component.dai_name = be->dai_name; + dai_component.dai_name = d->dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { - dev_err(tplg->dev, "ASoC: BE DAI %s not registered\n", - be->dai_name); + dev_err(tplg->dev, "ASoC: physical DAI %s not registered\n", + d->dai_name); return -EINVAL; } - if (be->dai_id != dai->id) { - dev_err(tplg->dev, "ASoC: BE DAI %s id mismatch\n", - be->dai_name); + if (d->dai_id != dai->id) { + dev_err(tplg->dev, "ASoC: physical DAI %s id mismatch\n", + d->dai_name); return -EINVAL; } @@ -1747,20 +2157,20 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg, if (!dai_drv) return -EINVAL; - if (be->playback) { + if (d->playback) { stream = &dai_drv->playback; - caps = &be->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; + caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; set_stream_info(stream, caps); } - if (be->capture) { + if (d->capture) { stream = &dai_drv->capture; - caps = &be->caps[SND_SOC_TPLG_STREAM_CAPTURE]; + caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE]; set_stream_info(stream, caps); } - if (be->flag_mask) - set_dai_flags(dai_drv, be->flag_mask, be->flags); + if (d->flag_mask) + set_dai_flags(dai_drv, d->flag_mask, d->flags); /* pass control to component driver for optional further init */ ret = soc_tplg_dai_load(tplg, dai_drv); @@ -1772,10 +2182,11 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg, return 0; } -static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, - struct snd_soc_tplg_hdr *hdr) +/* load physical DAI elements */ +static int soc_tplg_dai_elems_load(struct soc_tplg *tplg, + struct snd_soc_tplg_hdr *hdr) { - struct snd_soc_tplg_be_dai *be; + struct snd_soc_tplg_dai *dai; int count = hdr->count; int i; @@ -1784,41 +2195,95 @@ static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, /* config the existing BE DAIs */ for (i = 0; i < count; i++) { - be = (struct snd_soc_tplg_be_dai *)tplg->pos; - if (be->size != sizeof(*be)) { - dev_err(tplg->dev, "ASoC: invalid BE DAI size\n"); + dai = (struct snd_soc_tplg_dai *)tplg->pos; + if (dai->size != sizeof(*dai)) { + dev_err(tplg->dev, "ASoC: invalid physical DAI size\n"); return -EINVAL; } - soc_tplg_be_dai_config(tplg, be); - tplg->pos += (sizeof(*be) + be->priv.size); + soc_tplg_dai_config(tplg, dai); + tplg->pos += (sizeof(*dai) + dai->priv.size); } dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count); return 0; } +/** + * manifest_new_ver - Create a new version of manifest from the old version + * of source. + * @toplogy: topology context + * @src: old version of manifest as a source + * @manifest: latest version of manifest created from the source + * + * Support from vesion 4. Users need free the returned manifest manually. + */ +static int manifest_new_ver(struct soc_tplg *tplg, + struct snd_soc_tplg_manifest *src, + struct snd_soc_tplg_manifest **manifest) +{ + struct snd_soc_tplg_manifest *dest; + struct snd_soc_tplg_manifest_v4 *src_v4; + + *manifest = NULL; + + if (src->size != sizeof(*src_v4)) { + dev_err(tplg->dev, "ASoC: invalid manifest size\n"); + return -EINVAL; + } + + dev_warn(tplg->dev, "ASoC: old version of manifest\n"); + + src_v4 = (struct snd_soc_tplg_manifest_v4 *)src; + dest = kzalloc(sizeof(*dest) + src_v4->priv.size, GFP_KERNEL); + if (!dest) + return -ENOMEM; + + dest->size = sizeof(*dest); /* size of latest abi version */ + dest->control_elems = src_v4->control_elems; + dest->widget_elems = src_v4->widget_elems; + dest->graph_elems = src_v4->graph_elems; + dest->pcm_elems = src_v4->pcm_elems; + dest->dai_link_elems = src_v4->dai_link_elems; + dest->priv.size = src_v4->priv.size; + if (dest->priv.size) + memcpy(dest->priv.data, src_v4->priv.data, + src_v4->priv.size); + + *manifest = dest; + return 0; +} static int soc_tplg_manifest_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { - struct snd_soc_tplg_manifest *manifest; + struct snd_soc_tplg_manifest *manifest, *_manifest; + bool abi_match; + int err; if (tplg->pass != SOC_TPLG_PASS_MANIFEST) return 0; manifest = (struct snd_soc_tplg_manifest *)tplg->pos; - if (manifest->size != sizeof(*manifest)) { - dev_err(tplg->dev, "ASoC: invalid manifest size\n"); - return -EINVAL; - } - tplg->pos += sizeof(struct snd_soc_tplg_manifest); + /* check ABI version by size, create a new manifest if abi not match */ + if (manifest->size == sizeof(*manifest)) { + abi_match = true; + _manifest = manifest; + } else { + abi_match = false; + err = manifest_new_ver(tplg, manifest, &_manifest); + if (err < 0) + return err; + } + /* pass control to component driver for optional further init */ if (tplg->comp && tplg->ops && tplg->ops->manifest) - return tplg->ops->manifest(tplg->comp, manifest); + return tplg->ops->manifest(tplg->comp, _manifest); + + if (!abi_match) /* free the duplicated one */ + kfree(_manifest); - dev_err(tplg->dev, "ASoC: Firmware manifest not supported\n"); return 0; } @@ -1854,7 +2319,9 @@ static int soc_valid_header(struct soc_tplg *tplg, return -EINVAL; } - if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) { + /* Support ABI from version 4 */ + if (hdr->abi > SND_SOC_TPLG_ABI_VERSION + || hdr->abi < SND_SOC_TPLG_ABI_VERSION_MIN) { dev_err(tplg->dev, "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n", tplg->pass, hdr->abi, @@ -1902,8 +2369,12 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, return soc_tplg_dapm_widget_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_PCM: return soc_tplg_pcm_elems_load(tplg, hdr); - case SND_SOC_TPLG_TYPE_BE_DAI: - return soc_tplg_be_dai_elems_load(tplg, hdr); + case SND_SOC_TPLG_TYPE_DAI: + return soc_tplg_dai_elems_load(tplg, hdr); + case SND_SOC_TPLG_TYPE_DAI_LINK: + case SND_SOC_TPLG_TYPE_BACKEND_LINK: + /* physical link configurations */ + return soc_tplg_link_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_MANIFEST: return soc_tplg_manifest_load(tplg, hdr); default: diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 393e8f0fe2cc..644d9a9ebfbc 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -58,6 +58,205 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) } EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); +int snd_soc_component_enable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_enable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_enable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); + +int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_enable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); + +int snd_soc_component_disable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_disable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_disable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); + +int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_disable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); + +int snd_soc_component_nc_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_nc_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_nc_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); + +int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_nc_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); + +int snd_soc_component_get_pin_status(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_get_pin_status(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_get_pin_status(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); + +int snd_soc_component_force_enable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_force_enable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_force_enable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); + +int snd_soc_component_force_enable_pin_unlocked( + struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); + static const struct snd_pcm_hardware dummy_dma_hardware = { /* Random values to keep userspace happy when checking constraints */ .info = SNDRV_PCM_INFO_INTERLEAVED | diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 549fac349fa0..98eb205a0b62 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/pinctrl/consumer.h> +#include <linux/delay.h> #include "uniperif.h" @@ -97,6 +98,28 @@ static const struct of_device_id snd_soc_sti_match[] = { {}, }; +int sti_uniperiph_reset(struct uniperif *uni) +{ + int count = 10; + + /* Reset uniperipheral uni */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(uni); + + if (uni->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { + while (GET_UNIPERIF_SOFT_RST_SOFT_RST(uni) && count) { + udelay(5); + count--; + } + } + + if (!count) { + dev_err(uni->dev, "Failed to reset uniperif\n"); + return -EIO; + } + + return 0; +} + int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) @@ -293,7 +316,7 @@ static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai) /* The uniperipheral should be in stopped state */ if (uni->state != UNIPERIF_STATE_STOPPED) { - dev_err(uni->dev, "%s: invalid uni state( %d)", + dev_err(uni->dev, "%s: invalid uni state( %d)\n", __func__, (int)uni->state); return -EBUSY; } @@ -301,7 +324,7 @@ static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai) /* Pinctrl: switch pinstate to sleep */ ret = pinctrl_pm_select_sleep_state(uni->dev); if (ret) - dev_err(uni->dev, "%s: failed to select pinctrl state", + dev_err(uni->dev, "%s: failed to select pinctrl state\n", __func__); return ret; @@ -322,7 +345,7 @@ static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai) /* pinctrl: switch pinstate to default */ ret = pinctrl_pm_select_default_state(uni->dev); if (ret) - dev_err(uni->dev, "%s: failed to select pinctrl state", + dev_err(uni->dev, "%s: failed to select pinctrl state\n", __func__); return ret; @@ -366,11 +389,12 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, const struct of_device_id *of_id; const struct sti_uniperiph_dev_data *dev_data; const char *mode; + int ret; /* Populate data structure depending on compatibility */ of_id = of_match_node(snd_soc_sti_match, node); if (!of_id->data) { - dev_err(dev, "data associated to device is missing"); + dev_err(dev, "data associated to device is missing\n"); return -EINVAL; } dev_data = (struct sti_uniperiph_dev_data *)of_id->data; @@ -389,7 +413,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); if (!uni->mem_region) { - dev_err(dev, "Failed to get memory resource"); + dev_err(dev, "Failed to get memory resource\n"); return -ENODEV; } @@ -403,7 +427,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, uni->irq = platform_get_irq(priv->pdev, 0); if (uni->irq < 0) { - dev_err(dev, "Failed to get IRQ resource"); + dev_err(dev, "Failed to get IRQ resource\n"); return -ENXIO; } @@ -421,12 +445,15 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, dai_data->stream = dev_data->stream; if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) { - uni_player_init(priv->pdev, uni); + ret = uni_player_init(priv->pdev, uni); stream = &dai->playback; } else { - uni_reader_init(priv->pdev, uni); + ret = uni_reader_init(priv->pdev, uni); stream = &dai->capture; } + if (ret < 0) + return ret; + dai->ops = uni->dai_ops; stream->stream_name = dai->name; diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index 1993c655fb79..d487dd2ef016 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1397,6 +1397,8 @@ static inline int sti_uniperiph_get_unip_tdm_frame_size(struct uniperif *uni) return (uni->tdm_slot.slots * uni->tdm_slot.slot_width / 8); } +int sti_uniperiph_reset(struct uniperif *uni); + int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 1bc8ebc2528e..60ae31a303ab 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -6,8 +6,6 @@ */ #include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> #include <linux/mfd/syscon.h> #include <sound/asoundef.h> @@ -55,25 +53,6 @@ static const struct snd_pcm_hardware uni_player_pcm_hw = { .buffer_bytes_max = 256 * PAGE_SIZE }; -static inline int reset_player(struct uniperif *player) -{ - int count = 10; - - if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { - while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) { - udelay(5); - count--; - } - } - - if (!count) { - dev_err(player->dev, "Failed to reset uniperif"); - return -EIO; - } - - return 0; -} - /* * uni_player_irq_handler * In case of error audio stream is stopped; stop action is protected via PCM @@ -97,7 +76,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check for fifo error (underrun) */ if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) { - dev_err(player->dev, "FIFO underflow error detected"); + dev_err(player->dev, "FIFO underflow error detected\n"); /* Interrupt is just for information when underflow recovery */ if (player->underflow_enabled) { @@ -119,7 +98,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check for dma error (overrun) */ if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) { - dev_err(player->dev, "DMA error detected"); + dev_err(player->dev, "DMA error detected\n"); /* Disable interrupt so doesn't continually fire */ SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); @@ -135,11 +114,14 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check for underflow recovery done */ if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { if (!player->underflow_enabled) { - dev_err(player->dev, "unexpected Underflow recovering"); + dev_err(player->dev, + "unexpected Underflow recovering\n"); return -EPERM; } /* Read the underflow recovery duration */ tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); + dev_dbg(player->dev, "Underflow recovered (%d LR clocks max)\n", + tmp); /* Clear the underflow recovery duration */ SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player); @@ -153,7 +135,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check if underflow recovery failed */ if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) { - dev_err(player->dev, "Underflow recovery failed"); + dev_err(player->dev, "Underflow recovery failed\n"); /* Stop the player */ snd_pcm_stream_lock(player->substream); @@ -336,7 +318,7 @@ static int uni_player_prepare_iec958(struct uniperif *player, /* Oversampling must be multiple of 128 as iec958 frame is 32-bits */ if ((clk_div % 128) || (clk_div <= 0)) { - dev_err(player->dev, "%s: invalid clk_div %d", + dev_err(player->dev, "%s: invalid clk_div %d\n", __func__, clk_div); return -EINVAL; } @@ -359,7 +341,7 @@ static int uni_player_prepare_iec958(struct uniperif *player, SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player); break; default: - dev_err(player->dev, "format not supported"); + dev_err(player->dev, "format not supported\n"); return -EINVAL; } @@ -448,12 +430,12 @@ static int uni_player_prepare_pcm(struct uniperif *player, * for 16 bits must be a multiple of 64 */ if ((slot_width == 32) && (clk_div % 128)) { - dev_err(player->dev, "%s: invalid clk_div", __func__); + dev_err(player->dev, "%s: invalid clk_div\n", __func__); return -EINVAL; } if ((slot_width == 16) && (clk_div % 64)) { - dev_err(player->dev, "%s: invalid clk_div", __func__); + dev_err(player->dev, "%s: invalid clk_div\n", __func__); return -EINVAL; } @@ -471,7 +453,7 @@ static int uni_player_prepare_pcm(struct uniperif *player, SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); break; default: - dev_err(player->dev, "subframe format not supported"); + dev_err(player->dev, "subframe format not supported\n"); return -EINVAL; } @@ -491,7 +473,7 @@ static int uni_player_prepare_pcm(struct uniperif *player, break; default: - dev_err(player->dev, "format not supported"); + dev_err(player->dev, "format not supported\n"); return -EINVAL; } @@ -504,7 +486,7 @@ static int uni_player_prepare_pcm(struct uniperif *player, /* Number of channelsmust be even*/ if ((runtime->channels % 2) || (runtime->channels < 2) || (runtime->channels > 10)) { - dev_err(player->dev, "%s: invalid nb of channels", __func__); + dev_err(player->dev, "%s: invalid nb of channels\n", __func__); return -EINVAL; } @@ -614,7 +596,11 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, iec958->status[3] = ucontrol->value.iec958.status[3]; mutex_unlock(&player->ctrl_lock); - uni_player_set_channel_status(player, NULL); + if (player->substream && player->substream->runtime) + uni_player_set_channel_status(player, + player->substream->runtime); + else + uni_player_set_channel_status(player, NULL); return 0; } @@ -758,7 +744,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, /* The player should be stopped */ if (player->state != UNIPERIF_STATE_STOPPED) { - dev_err(player->dev, "%s: invalid player state %d", __func__, + dev_err(player->dev, "%s: invalid player state %d\n", __func__, player->state); return -EINVAL; } @@ -787,7 +773,8 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, /* Trigger limit must be an even number */ if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) || (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) { - dev_err(player->dev, "invalid trigger limit %d", trigger_limit); + dev_err(player->dev, "invalid trigger limit %d\n", + trigger_limit); return -EINVAL; } @@ -808,7 +795,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, ret = uni_player_prepare_tdm(player, runtime); break; default: - dev_err(player->dev, "invalid player type"); + dev_err(player->dev, "invalid player type\n"); return -EINVAL; } @@ -848,16 +835,14 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); break; default: - dev_err(player->dev, "format not supported"); + dev_err(player->dev, "format not supported\n"); return -EINVAL; } SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0); - /* Reset uniperipheral player */ - SET_UNIPERIF_SOFT_RST_SOFT_RST(player); - return reset_player(player); + return sti_uniperiph_reset(player); } static int uni_player_start(struct uniperif *player) @@ -866,13 +851,13 @@ static int uni_player_start(struct uniperif *player) /* The player should be stopped */ if (player->state != UNIPERIF_STATE_STOPPED) { - dev_err(player->dev, "%s: invalid player state", __func__); + dev_err(player->dev, "%s: invalid player state\n", __func__); return -EINVAL; } ret = clk_prepare_enable(player->clk); if (ret) { - dev_err(player->dev, "%s: Failed to enable clock", __func__); + dev_err(player->dev, "%s: Failed to enable clock\n", __func__); return ret; } @@ -889,10 +874,7 @@ static int uni_player_start(struct uniperif *player) SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player); } - /* Reset uniperipheral player */ - SET_UNIPERIF_SOFT_RST_SOFT_RST(player); - - ret = reset_player(player); + ret = sti_uniperiph_reset(player); if (ret < 0) { clk_disable_unprepare(player->clk); return ret; @@ -934,17 +916,14 @@ static int uni_player_stop(struct uniperif *player) /* The player should not be in stopped state */ if (player->state == UNIPERIF_STATE_STOPPED) { - dev_err(player->dev, "%s: invalid player state", __func__); + dev_err(player->dev, "%s: invalid player state\n", __func__); return -EINVAL; } /* Turn the player off */ SET_UNIPERIF_CTRL_OPERATION_OFF(player); - /* Soft reset the player */ - SET_UNIPERIF_SOFT_RST_SOFT_RST(player); - - ret = reset_player(player); + ret = sti_uniperiph_reset(player); if (ret < 0) return ret; @@ -969,7 +948,7 @@ int uni_player_resume(struct uniperif *player) ret = regmap_field_write(player->clk_sel, 1); if (ret) { dev_err(player->dev, - "%s: Failed to select freq synth clock", + "%s: Failed to select freq synth clock\n", __func__); return ret; } @@ -1066,7 +1045,7 @@ int uni_player_init(struct platform_device *pdev, ret = uni_player_parse_dt_audio_glue(pdev, player); if (ret < 0) { - dev_err(player->dev, "Failed to parse DeviceTree"); + dev_err(player->dev, "Failed to parse DeviceTree\n"); return ret; } @@ -1081,15 +1060,17 @@ int uni_player_init(struct platform_device *pdev, /* Get uniperif resource */ player->clk = of_clk_get(pdev->dev.of_node, 0); - if (IS_ERR(player->clk)) + if (IS_ERR(player->clk)) { + dev_err(player->dev, "Failed to get clock\n"); ret = PTR_ERR(player->clk); + } /* Select the frequency synthesizer clock */ if (player->clk_sel) { ret = regmap_field_write(player->clk_sel, 1); if (ret) { dev_err(player->dev, - "%s: Failed to select freq synth clock", + "%s: Failed to select freq synth clock\n", __func__); return ret; } @@ -1101,7 +1082,7 @@ int uni_player_init(struct platform_device *pdev, ret = regmap_field_write(player->valid_sel, player->id); if (ret) { dev_err(player->dev, - "%s: unable to connect to tdm bus", __func__); + "%s: unable to connect to tdm bus\n", __func__); return ret; } } @@ -1109,8 +1090,10 @@ int uni_player_init(struct platform_device *pdev, ret = devm_request_irq(&pdev->dev, player->irq, uni_player_irq_handler, IRQF_SHARED, dev_name(&pdev->dev), player); - if (ret < 0) + if (ret < 0) { + dev_err(player->dev, "unable to request IRQ %d\n", player->irq); return ret; + } mutex_init(&player->ctrl_lock); diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 0e1c3ee56675..5992c6ab3833 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -5,10 +5,6 @@ * License terms: GNU General Public License (GPL), version 2 */ -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> - #include <sound/soc.h> #include "uniperif.h" @@ -52,7 +48,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) if (reader->state == UNIPERIF_STATE_STOPPED) { /* Unexpected IRQ: do nothing */ - dev_warn(reader->dev, "unexpected IRQ "); + dev_warn(reader->dev, "unexpected IRQ\n"); return IRQ_HANDLED; } @@ -62,7 +58,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) /* Check for fifo overflow error */ if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { - dev_err(reader->dev, "FIFO error detected"); + dev_err(reader->dev, "FIFO error detected\n"); snd_pcm_stream_lock(reader->substream); snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); @@ -105,7 +101,7 @@ static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime, SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader); break; default: - dev_err(reader->dev, "subframe format not supported"); + dev_err(reader->dev, "subframe format not supported\n"); return -EINVAL; } @@ -125,14 +121,14 @@ static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime, break; default: - dev_err(reader->dev, "format not supported"); + dev_err(reader->dev, "format not supported\n"); return -EINVAL; } /* Number of channels must be even */ if ((runtime->channels % 2) || (runtime->channels < 2) || (runtime->channels > 10)) { - dev_err(reader->dev, "%s: invalid nb of channels", __func__); + dev_err(reader->dev, "%s: invalid nb of channels\n", __func__); return -EINVAL; } @@ -186,11 +182,10 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, struct uniperif *reader = priv->dai_data.uni; struct snd_pcm_runtime *runtime = substream->runtime; int transfer_size, trigger_limit, ret; - int count = 10; /* The reader should be stopped */ if (reader->state != UNIPERIF_STATE_STOPPED) { - dev_err(reader->dev, "%s: invalid reader state %d", __func__, + dev_err(reader->dev, "%s: invalid reader state %d\n", __func__, reader->state); return -EINVAL; } @@ -219,7 +214,8 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) || (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { - dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); + dev_err(reader->dev, "invalid trigger limit %d\n", + trigger_limit); return -EINVAL; } @@ -246,7 +242,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader); break; default: - dev_err(reader->dev, "format not supported"); + dev_err(reader->dev, "format not supported\n"); return -EINVAL; } @@ -287,25 +283,14 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, } /* Reset uniperipheral reader */ - SET_UNIPERIF_SOFT_RST_SOFT_RST(reader); - - while (GET_UNIPERIF_SOFT_RST_SOFT_RST(reader)) { - udelay(5); - count--; - } - if (!count) { - dev_err(reader->dev, "Failed to reset uniperif"); - return -EIO; - } - - return 0; + return sti_uniperiph_reset(reader); } static int uni_reader_start(struct uniperif *reader) { /* The reader should be stopped */ if (reader->state != UNIPERIF_STATE_STOPPED) { - dev_err(reader->dev, "%s: invalid reader state", __func__); + dev_err(reader->dev, "%s: invalid reader state\n", __func__); return -EINVAL; } @@ -325,7 +310,7 @@ static int uni_reader_stop(struct uniperif *reader) { /* The reader should not be in stopped state */ if (reader->state == UNIPERIF_STATE_STOPPED) { - dev_err(reader->dev, "%s: invalid reader state", __func__); + dev_err(reader->dev, "%s: invalid reader state\n", __func__); return -EINVAL; } @@ -423,7 +408,7 @@ int uni_reader_init(struct platform_device *pdev, uni_reader_irq_handler, IRQF_SHARED, dev_name(&pdev->dev), reader); if (ret < 0) { - dev_err(&pdev->dev, "Failed to request IRQ"); + dev_err(&pdev->dev, "Failed to request IRQ\n"); return -EBUSY; } diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index dd2368297fd3..6c344e16aca4 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -9,6 +9,14 @@ config SND_SUN4I_CODEC Select Y or M to add support for the Codec embedded in the Allwinner A10 and affiliated SoCs. +config SND_SUN8I_CODEC_ANALOG + tristate "Allwinner sun8i Codec Analog Controls Support" + depends on MACH_SUN8I || COMPILE_TEST + select REGMAP + help + Say Y or M if you want to add support for the analog controls for + the codec embedded in newer Allwinner SoCs. + config SND_SUN4I_I2S tristate "Allwinner A10 I2S Support" select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index 604c7b842837..241c0df9ca0c 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o +obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index e047ec06d538..848af01692a0 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -3,6 +3,7 @@ * Copyright 2014 Jon Smirl <jonsmirl@gmail.com> * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com> * Copyright 2015 Adam Sampson <ats@offog.org> + * Copyright 2016 Chen-Yu Tsai <wens@csie.org> * * Based on the Allwinner SDK driver, released under the GPL. * @@ -24,10 +25,12 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_platform.h> #include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> #include <linux/clk.h> #include <linux/regmap.h> +#include <linux/reset.h> #include <linux/gpio/consumer.h> #include <sound/core.h> @@ -38,7 +41,7 @@ #include <sound/initval.h> #include <sound/dmaengine_pcm.h> -/* Codec DAC register offsets and bit fields */ +/* Codec DAC digital controls and FIFO registers */ #define SUN4I_CODEC_DAC_DPC (0x00) #define SUN4I_CODEC_DAC_DPC_EN_DA (31) #define SUN4I_CODEC_DAC_DPC_DVOL (12) @@ -55,6 +58,8 @@ #define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH (0) #define SUN4I_CODEC_DAC_FIFOS (0x08) #define SUN4I_CODEC_DAC_TXDATA (0x0c) + +/* Codec DAC side analog signal controls */ #define SUN4I_CODEC_DAC_ACTL (0x10) #define SUN4I_CODEC_DAC_ACTL_DACAENR (31) #define SUN4I_CODEC_DAC_ACTL_DACAENL (30) @@ -69,7 +74,7 @@ #define SUN4I_CODEC_DAC_TUNE (0x14) #define SUN4I_CODEC_DAC_DEBUG (0x18) -/* Codec ADC register offsets and bit fields */ +/* Codec ADC digital controls and FIFO registers */ #define SUN4I_CODEC_ADC_FIFOC (0x1c) #define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29) #define SUN4I_CODEC_ADC_FIFOC_EN_AD (28) @@ -81,6 +86,8 @@ #define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH (0) #define SUN4I_CODEC_ADC_FIFOS (0x20) #define SUN4I_CODEC_ADC_RXDATA (0x24) + +/* Codec ADC side analog signal controls */ #define SUN4I_CODEC_ADC_ACTL (0x28) #define SUN4I_CODEC_ADC_ACTL_ADC_R_EN (31) #define SUN4I_CODEC_ADC_ACTL_ADC_L_EN (30) @@ -93,19 +100,141 @@ #define SUN4I_CODEC_ADC_ACTL_DDE (3) #define SUN4I_CODEC_ADC_DEBUG (0x2c) -/* Other various ADC registers */ +/* FIFO counters */ #define SUN4I_CODEC_DAC_TXCNT (0x30) #define SUN4I_CODEC_ADC_RXCNT (0x34) + +/* Calibration register (sun7i only) */ #define SUN7I_CODEC_AC_DAC_CAL (0x38) + +/* Microphone controls (sun7i only) */ #define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c) +/* + * sun6i specific registers + * + * sun6i shares the same digital control and FIFO registers as sun4i, + * but only the DAC digital controls are at the same offset. The others + * have been moved around to accommodate extra analog controls. + */ + +/* Codec DAC digital controls and FIFO registers */ +#define SUN6I_CODEC_ADC_FIFOC (0x10) +#define SUN6I_CODEC_ADC_FIFOC_EN_AD (28) +#define SUN6I_CODEC_ADC_FIFOS (0x14) +#define SUN6I_CODEC_ADC_RXDATA (0x18) + +/* Output mixer and gain controls */ +#define SUN6I_CODEC_OM_DACA_CTRL (0x20) +#define SUN6I_CODEC_OM_DACA_CTRL_DACAREN (31) +#define SUN6I_CODEC_OM_DACA_CTRL_DACALEN (30) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN (29) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN (28) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1 (23) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2 (22) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE (21) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP (20) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR (19) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR (18) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL (17) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1 (16) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2 (15) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE (14) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN (13) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL (12) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL (11) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR (10) +#define SUN6I_CODEC_OM_DACA_CTRL_RHPIS (9) +#define SUN6I_CODEC_OM_DACA_CTRL_LHPIS (8) +#define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE (7) +#define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE (6) +#define SUN6I_CODEC_OM_DACA_CTRL_HPVOL (0) +#define SUN6I_CODEC_OM_PA_CTRL (0x24) +#define SUN6I_CODEC_OM_PA_CTRL_HPPAEN (31) +#define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL (29) +#define SUN6I_CODEC_OM_PA_CTRL_COMPTEN (28) +#define SUN6I_CODEC_OM_PA_CTRL_MIC1G (15) +#define SUN6I_CODEC_OM_PA_CTRL_MIC2G (12) +#define SUN6I_CODEC_OM_PA_CTRL_LINEING (9) +#define SUN6I_CODEC_OM_PA_CTRL_PHONEG (6) +#define SUN6I_CODEC_OM_PA_CTRL_PHONEPG (3) +#define SUN6I_CODEC_OM_PA_CTRL_PHONENG (0) + +/* Microphone, line out and phone out controls */ +#define SUN6I_CODEC_MIC_CTRL (0x28) +#define SUN6I_CODEC_MIC_CTRL_HBIASEN (31) +#define SUN6I_CODEC_MIC_CTRL_MBIASEN (30) +#define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN (28) +#define SUN6I_CODEC_MIC_CTRL_MIC1BOOST (25) +#define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN (24) +#define SUN6I_CODEC_MIC_CTRL_MIC2BOOST (21) +#define SUN6I_CODEC_MIC_CTRL_MIC2SLT (20) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN (19) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTREN (18) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC (17) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC (16) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTVC (11) +#define SUN6I_CODEC_MIC_CTRL_PHONEPREG (8) + +/* ADC mixer controls */ +#define SUN6I_CODEC_ADC_ACTL (0x2c) +#define SUN6I_CODEC_ADC_ACTL_ADCREN (31) +#define SUN6I_CODEC_ADC_ACTL_ADCLEN (30) +#define SUN6I_CODEC_ADC_ACTL_ADCRG (27) +#define SUN6I_CODEC_ADC_ACTL_ADCLG (24) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1 (13) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2 (12) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE (11) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP (10) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR (9) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR (8) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL (7) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1 (6) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2 (5) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE (4) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN (3) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL (2) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL (1) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR (0) + +/* Analog performance tuning controls */ +#define SUN6I_CODEC_ADDA_TUNE (0x30) + +/* Calibration controls */ +#define SUN6I_CODEC_CALIBRATION (0x34) + +/* FIFO counters */ +#define SUN6I_CODEC_DAC_TXCNT (0x40) +#define SUN6I_CODEC_ADC_RXCNT (0x44) + +/* headset jack detection and button support registers */ +#define SUN6I_CODEC_HMIC_CTL (0x50) +#define SUN6I_CODEC_HMIC_DATA (0x54) + +/* TODO sun6i DAP (Digital Audio Processing) bits */ + +/* FIFO counters moved on A23 */ +#define SUN8I_A23_CODEC_DAC_TXCNT (0x1c) +#define SUN8I_A23_CODEC_ADC_RXCNT (0x20) + +/* TX FIFO moved on H3 */ +#define SUN8I_H3_CODEC_DAC_TXDATA (0x20) +#define SUN8I_H3_CODEC_DAC_DBG (0x48) +#define SUN8I_H3_CODEC_ADC_DBG (0x4c) + +/* TODO H3 DAP (Digital Audio Processing) bits */ + struct sun4i_codec { struct device *dev; struct regmap *regmap; struct clk *clk_apb; struct clk *clk_module; + struct reset_control *rst; struct gpio_desc *gpio_pa; + /* ADC_FIFOC register is at different offset on different SoCs */ + struct regmap_field *reg_adc_fifoc; + struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; }; @@ -134,16 +263,16 @@ static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) static void sun4i_codec_start_capture(struct sun4i_codec *scodec) { /* Enable ADC DRQ */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), - BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); } static void sun4i_codec_stop_capture(struct sun4i_codec *scodec) { /* Disable ADC DRQ */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); } static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, @@ -186,24 +315,29 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, /* Flush RX FIFO */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), - BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), + BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); /* Set RX FIFO trigger level */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, - 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL); + regmap_field_update_bits(scodec->reg_adc_fifoc, + 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, + 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL); /* * FIXME: Undocumented in the datasheet, but * Allwinner's code mentions that it is related * related to microphone gain */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, - 0x3 << 25, - 0x1 << 25); + if (of_device_is_compatible(scodec->dev->of_node, + "allwinner,sun4i-a10-codec") || + of_device_is_compatible(scodec->dev->of_node, + "allwinner,sun7i-a20-codec")) { + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, + 0x3 << 25, + 0x1 << 25); + } if (of_device_is_compatible(scodec->dev->of_node, "allwinner,sun7i-a20-codec")) @@ -213,9 +347,9 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, 0x1 << 8); /* Fill most significant bits with valid data MSB */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), - BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), + BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); return 0; } @@ -342,18 +476,19 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec, unsigned int hwrate) { /* Set ADC sample rate */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, - hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS); + regmap_field_update_bits(scodec->reg_adc_fifoc, + 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, + hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS); /* Set the number of channels we want to use */ if (params_channels(params) == 1) - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), - BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); else - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), + 0); return 0; } @@ -502,7 +637,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = { }, }; -/*** Codec ***/ +/*** sun4i Codec ***/ static const struct snd_kcontrol_new sun4i_codec_pa_mute = SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); @@ -638,6 +773,337 @@ static struct snd_soc_codec_driver sun4i_codec_codec = { }, }; +/*** sun6i Codec ***/ + +/* mixer controls */ +static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = { + SOC_DAPM_DOUBLE("DAC Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0), + SOC_DAPM_DOUBLE("DAC Reversed Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0), + SOC_DAPM_DOUBLE("Line In Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0), + SOC_DAPM_DOUBLE("Mic1 Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0), + SOC_DAPM_DOUBLE("Mic2 Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0), +}; + +/* ADC mixer controls */ +static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = { + SOC_DAPM_DOUBLE("Mixer Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL, + SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0), + SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR, + SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0), + SOC_DAPM_DOUBLE("Line In Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL, + SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0), + SOC_DAPM_DOUBLE("Mic1 Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1, + SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0), + SOC_DAPM_DOUBLE("Mic2 Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2, + SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0), +}; + +/* headphone controls */ +static const char * const sun6i_codec_hp_src_enum_text[] = { + "DAC", "Mixer", +}; + +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum, + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LHPIS, + SUN6I_CODEC_OM_DACA_CTRL_RHPIS, + sun6i_codec_hp_src_enum_text); + +static const struct snd_kcontrol_new sun6i_codec_hp_src[] = { + SOC_DAPM_ENUM("Headphone Source Playback Route", + sun6i_codec_hp_src_enum), +}; + +/* microphone controls */ +static const char * const sun6i_codec_mic2_src_enum_text[] = { + "Mic2", "Mic3", +}; + +static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum, + SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC2SLT, + sun6i_codec_mic2_src_enum_text); + +static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = { + SOC_DAPM_ENUM("Mic2 Amplifier Source Route", + sun6i_codec_mic2_src_enum), +}; + +/* line out controls */ +static const char * const sun6i_codec_lineout_src_enum_text[] = { + "Stereo", "Mono Differential", +}; + +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum, + SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC, + SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC, + sun6i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun6i_codec_lineout_src_enum), +}; + +/* volume / mute controls */ +static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0); +static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1); +static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale, + -450, 150, 0); +static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale, + 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), +); +static const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), +); + +static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { + SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, + sun6i_codec_dvol_scale), + SOC_SINGLE_TLV("Headphone Playback Volume", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0, + sun6i_codec_hp_vol_scale), + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0, + sun6i_codec_lineout_vol_scale), + SOC_DOUBLE("Headphone Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE, + SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0), + SOC_DOUBLE("Line Out Playback Switch", + SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_LINEOUTLEN, + SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0), + /* Mixer pre-gains */ + SOC_SINGLE_TLV("Line In Playback Volume", + SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING, + 0x7, 0, sun6i_codec_out_mixer_pregain_scale), + SOC_SINGLE_TLV("Mic1 Playback Volume", + SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G, + 0x7, 0, sun6i_codec_out_mixer_pregain_scale), + SOC_SINGLE_TLV("Mic2 Playback Volume", + SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G, + 0x7, 0, sun6i_codec_out_mixer_pregain_scale), + + /* Microphone Amp boost gains */ + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0, + sun6i_codec_mic_gain_scale), + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0, + sun6i_codec_mic_gain_scale), + SOC_DOUBLE_TLV("ADC Capture Volume", + SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG, + SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0, + sun6i_codec_out_mixer_pregain_scale), +}; + +static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = { + /* Microphone inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("MIC3"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route", + SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src), + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0), + + /* Line In */ + SND_SOC_DAPM_INPUT("LINEIN"), + + /* Digital parts of the ADCs */ + SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC, + SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, + NULL, 0), + + /* Analog parts of the ADCs */ + SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_ADCLEN, 0), + SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_ADCREN, 0), + + /* ADC Mixers */ + SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0, + sun6i_codec_adc_mixer_controls), + SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0, + sun6i_codec_adc_mixer_controls), + + /* Digital parts of the DACs */ + SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_EN_DA, 0, + NULL, 0), + + /* Analog parts of the DACs */ + SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0), + SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0), + + /* Mixers */ + SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0, + sun6i_codec_mixer_controls), + SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0, + sun6i_codec_mixer_controls), + + /* Headphone output path */ + SND_SOC_DAPM_MUX("Headphone Source Playback Route", + SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src), + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL, + SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL, + SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL, + SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0), + SND_SOC_DAPM_OUTPUT("HP"), + + /* Line Out path */ + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src), + SND_SOC_DAPM_OUTPUT("LINEOUT"), +}; + +static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { + /* DAC Routes */ + { "Left DAC", NULL, "DAC Enable" }, + { "Right DAC", NULL, "DAC Enable" }, + + /* Microphone Routes */ + { "Mic1 Amplifier", NULL, "MIC1"}, + { "Mic2 Amplifier Source Route", "Mic2", "MIC2" }, + { "Mic2 Amplifier Source Route", "Mic3", "MIC3" }, + { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"}, + + /* Left Mixer Routes */ + { "Left Mixer", "DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, + { "Left Mixer", "Line In Playback Switch", "LINEIN" }, + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + + /* Right Mixer Routes */ + { "Right Mixer", "DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, + { "Right Mixer", "Line In Playback Switch", "LINEIN" }, + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + + /* Left ADC Mixer Routes */ + { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, + { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + /* Right ADC Mixer Routes */ + { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, + { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + /* Headphone Routes */ + { "Headphone Source Playback Route", "DAC", "Left DAC" }, + { "Headphone Source Playback Route", "DAC", "Right DAC" }, + { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, + { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, + { "Headphone Amp", NULL, "Headphone Source Playback Route" }, + { "HP", NULL, "Headphone Amp" }, + { "HPCOM", NULL, "HPCOM Protection" }, + + /* Line Out Routes */ + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "LINEOUT", NULL, "Line Out Source Playback Route" }, + + /* ADC Routes */ + { "Left ADC", NULL, "ADC Enable" }, + { "Right ADC", NULL, "ADC Enable" }, + { "Left ADC", NULL, "Left ADC Mixer" }, + { "Right ADC", NULL, "Right ADC Mixer" }, +}; + +static struct snd_soc_codec_driver sun6i_codec_codec = { + .component_driver = { + .controls = sun6i_codec_codec_widgets, + .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets), + .dapm_widgets = sun6i_codec_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets), + .dapm_routes = sun6i_codec_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes), + }, +}; + +/* sun8i A23 codec */ +static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, + sun6i_codec_dvol_scale), +}; + +static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = { + /* Digital parts of the ADCs */ + SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC, + SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0), + /* Digital parts of the DACs */ + SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0), + +}; + +static struct snd_soc_codec_driver sun8i_a23_codec_codec = { + .component_driver = { + .controls = sun8i_a23_codec_codec_controls, + .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls), + .dapm_widgets = sun8i_a23_codec_codec_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets), + }, +}; + static const struct snd_soc_component_driver sun4i_codec_component = { .name = "sun4i-codec", }; @@ -678,45 +1144,6 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { }, }; -static const struct regmap_config sun4i_codec_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = SUN4I_CODEC_ADC_RXCNT, -}; - -static const struct regmap_config sun7i_codec_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL, -}; - -struct sun4i_codec_quirks { - const struct regmap_config *regmap_config; -}; - -static const struct sun4i_codec_quirks sun4i_codec_quirks = { - .regmap_config = &sun4i_codec_regmap_config, -}; - -static const struct sun4i_codec_quirks sun7i_codec_quirks = { - .regmap_config = &sun7i_codec_regmap_config, -}; - -static const struct of_device_id sun4i_codec_of_match[] = { - { - .compatible = "allwinner,sun4i-a10-codec", - .data = &sun4i_codec_quirks, - }, - { - .compatible = "allwinner,sun7i-a20-codec", - .data = &sun7i_codec_quirks, - }, - {} -}; -MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); - static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, int *num_links) { @@ -765,11 +1192,11 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) - return NULL; + return ERR_PTR(-ENOMEM); card->dai_link = sun4i_codec_create_link(dev, &card->num_links); if (!card->dai_link) - return NULL; + return ERR_PTR(-ENOMEM); card->dev = dev; card->name = "sun4i-codec"; @@ -781,6 +1208,259 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) return card; }; +static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), +}; + +static struct snd_soc_card *sun6i_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dev = dev; + card->name = "A31 Audio Codec"; + card->dapm_widgets = sun6i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + +/* Connect digital side enables to analog side widgets */ +static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = { + /* ADC Routes */ + { "Left ADC", NULL, "ADC Enable" }, + { "Right ADC", NULL, "ADC Enable" }, + { "Codec Capture", NULL, "Left ADC" }, + { "Codec Capture", NULL, "Right ADC" }, + + /* DAC Routes */ + { "Left DAC", NULL, "DAC Enable" }, + { "Right DAC", NULL, "DAC Enable" }, + { "Left DAC", NULL, "Codec Playback" }, + { "Right DAC", NULL, "Codec Playback" }, +}; + +static struct snd_soc_aux_dev aux_dev = { + .name = "Codec Analog Controls", +}; + +static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + "allwinner,codec-analog-controls", + 0); + if (!aux_dev.codec_of_node) { + dev_err(dev, "Can't find analog controls for codec.\n"); + return ERR_PTR(-EINVAL); + }; + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dev = dev; + card->name = "A23 Audio Codec"; + card->dapm_widgets = sun6i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); + card->dapm_routes = sun8i_codec_card_routes; + card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); + card->aux_dev = &aux_dev; + card->num_aux_devs = 1; + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + +static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + "allwinner,codec-analog-controls", + 0); + if (!aux_dev.codec_of_node) { + dev_err(dev, "Can't find analog controls for codec.\n"); + return ERR_PTR(-EINVAL); + }; + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dev = dev; + card->name = "H3 Audio Codec"; + card->dapm_widgets = sun6i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); + card->dapm_routes = sun8i_codec_card_routes; + card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); + card->aux_dev = &aux_dev; + card->num_aux_devs = 1; + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + +static const struct regmap_config sun4i_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN4I_CODEC_ADC_RXCNT, +}; + +static const struct regmap_config sun6i_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN6I_CODEC_HMIC_DATA, +}; + +static const struct regmap_config sun7i_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL, +}; + +static const struct regmap_config sun8i_a23_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN8I_A23_CODEC_ADC_RXCNT, +}; + +static const struct regmap_config sun8i_h3_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN8I_H3_CODEC_ADC_DBG, +}; + +struct sun4i_codec_quirks { + const struct regmap_config *regmap_config; + const struct snd_soc_codec_driver *codec; + struct snd_soc_card * (*create_card)(struct device *dev); + struct reg_field reg_adc_fifoc; /* used for regmap_field */ + unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ + unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ + bool has_reset; +}; + +static const struct sun4i_codec_quirks sun4i_codec_quirks = { + .regmap_config = &sun4i_codec_regmap_config, + .codec = &sun4i_codec_codec, + .create_card = sun4i_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, +}; + +static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = { + .regmap_config = &sun6i_codec_regmap_config, + .codec = &sun6i_codec_codec, + .create_card = sun6i_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, + .has_reset = true, +}; + +static const struct sun4i_codec_quirks sun7i_codec_quirks = { + .regmap_config = &sun7i_codec_regmap_config, + .codec = &sun4i_codec_codec, + .create_card = sun4i_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, +}; + +static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { + .regmap_config = &sun8i_a23_codec_regmap_config, + .codec = &sun8i_a23_codec_codec, + .create_card = sun8i_a23_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, + .has_reset = true, +}; + +static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { + .regmap_config = &sun8i_h3_codec_regmap_config, + /* + * TODO Share the codec structure with A23 for now. + * This should be split out when adding digital audio + * processing support for the H3. + */ + .codec = &sun8i_a23_codec_codec, + .create_card = sun8i_h3_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, + .has_reset = true, +}; + +static const struct of_device_id sun4i_codec_of_match[] = { + { + .compatible = "allwinner,sun4i-a10-codec", + .data = &sun4i_codec_quirks, + }, + { + .compatible = "allwinner,sun6i-a31-codec", + .data = &sun6i_a31_codec_quirks, + }, + { + .compatible = "allwinner,sun7i-a20-codec", + .data = &sun7i_codec_quirks, + }, + { + .compatible = "allwinner,sun8i-a23-codec", + .data = &sun8i_a23_codec_quirks, + }, + { + .compatible = "allwinner,sun8i-h3-codec", + .data = &sun8i_h3_codec_quirks, + }, + {} +}; +MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); + static int sun4i_codec_probe(struct platform_device *pdev) { struct snd_soc_card *card; @@ -829,10 +1509,12 @@ static int sun4i_codec_probe(struct platform_device *pdev) return PTR_ERR(scodec->clk_module); } - /* Enable the bus clock */ - if (clk_prepare_enable(scodec->clk_apb)) { - dev_err(&pdev->dev, "Failed to enable the APB clock\n"); - return -EINVAL; + if (quirks->has_reset) { + scodec->rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(scodec->rst)) { + dev_err(&pdev->dev, "Failed to get reset control\n"); + return PTR_ERR(scodec->rst); + } } scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", @@ -844,21 +1526,48 @@ static int sun4i_codec_probe(struct platform_device *pdev) return ret; } + /* reg_field setup */ + scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, + scodec->regmap, + quirks->reg_adc_fifoc); + if (IS_ERR(scodec->reg_adc_fifoc)) { + ret = PTR_ERR(scodec->reg_adc_fifoc); + dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", + ret); + return ret; + } + + /* Enable the bus clock */ + if (clk_prepare_enable(scodec->clk_apb)) { + dev_err(&pdev->dev, "Failed to enable the APB clock\n"); + return -EINVAL; + } + + /* Deassert the reset control */ + if (scodec->rst) { + ret = reset_control_deassert(scodec->rst); + if (ret) { + dev_err(&pdev->dev, + "Failed to deassert the reset control\n"); + goto err_clk_disable; + } + } + /* DMA configuration for TX FIFO */ - scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA; - scodec->playback_dma_data.maxburst = 4; + scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; + scodec->playback_dma_data.maxburst = 8; scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; /* DMA configuration for RX FIFO */ - scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA; - scodec->capture_dma_data.maxburst = 4; + scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata; + scodec->capture_dma_data.maxburst = 8; scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec, + ret = snd_soc_register_codec(&pdev->dev, quirks->codec, &sun4i_codec_dai, 1); if (ret) { dev_err(&pdev->dev, "Failed to register our codec\n"); - goto err_clk_disable; + goto err_assert_reset; } ret = devm_snd_soc_register_component(&pdev->dev, @@ -875,8 +1584,9 @@ static int sun4i_codec_probe(struct platform_device *pdev) goto err_unregister_codec; } - card = sun4i_codec_create_card(&pdev->dev); - if (!card) { + card = quirks->create_card(&pdev->dev); + if (IS_ERR(card)) { + ret = PTR_ERR(card); dev_err(&pdev->dev, "Failed to create our card\n"); goto err_unregister_codec; } @@ -894,6 +1604,9 @@ static int sun4i_codec_probe(struct platform_device *pdev) err_unregister_codec: snd_soc_unregister_codec(&pdev->dev); +err_assert_reset: + if (scodec->rst) + reset_control_assert(scodec->rst); err_clk_disable: clk_disable_unprepare(scodec->clk_apb); return ret; @@ -906,6 +1619,8 @@ static int sun4i_codec_remove(struct platform_device *pdev) snd_soc_unregister_card(card); snd_soc_unregister_codec(&pdev->dev); + if (scodec->rst) + reset_control_assert(scodec->rst); clk_disable_unprepare(scodec->clk_apb); return 0; @@ -925,4 +1640,5 @@ MODULE_DESCRIPTION("Allwinner A10 codec driver"); MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>"); MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>"); MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 687a8f83dbe5..f24d19526603 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -93,6 +93,9 @@ struct sun4i_i2s { struct clk *mod_clk; struct regmap *regmap; + unsigned int mclk_freq; + + struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; }; @@ -157,14 +160,24 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, } static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 }; +static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++) + if (sun4i_i2s_oversample_rates[i] == oversample) + return true; + + return false; +} static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, unsigned int rate, unsigned int word_size) { - unsigned int clk_rate; + unsigned int oversample_rate, clk_rate; int bclk_div, mclk_div; - int ret, i; + int ret; switch (rate) { case 176400: @@ -196,21 +209,18 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, if (ret) return ret; - /* Always favor the highest oversampling rate */ - for (i = (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >= 0; i--) { - unsigned int oversample_rate = sun4i_i2s_oversample_rates[i]; - - bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, - word_size); - mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, - clk_rate, - rate); + oversample_rate = i2s->mclk_freq / rate; + if (!sun4i_i2s_oversample_is_valid(oversample_rate)) + return -EINVAL; - if ((bclk_div >= 0) && (mclk_div >= 0)) - break; - } + bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, + word_size); + if (bclk_div < 0) + return -EINVAL; - if ((bclk_div < 0) || (mclk_div < 0)) + mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, + clk_rate, rate); + if (mclk_div < 0) return -EINVAL; regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, @@ -341,6 +351,27 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s) +{ + /* Flush RX FIFO */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, + SUN4I_I2S_FIFO_CTRL_FLUSH_RX, + SUN4I_I2S_FIFO_CTRL_FLUSH_RX); + + /* Clear RX counter */ + regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0); + + /* Enable RX Block */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_RX_EN, + SUN4I_I2S_CTRL_RX_EN); + + /* Enable RX DRQ */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, + SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, + SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN); +} + static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s) { /* Flush TX FIFO */ @@ -362,6 +393,18 @@ static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s) SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN); } +static void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s) +{ + /* Disable RX Block */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_RX_EN, + 0); + + /* Disable RX DRQ */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, + SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, + 0); +} static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s) { @@ -388,7 +431,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) sun4i_i2s_start_playback(i2s); else - return -EINVAL; + sun4i_i2s_start_capture(i2s); break; case SNDRV_PCM_TRIGGER_STOP: @@ -397,7 +440,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) sun4i_i2s_stop_playback(i2s); else - return -EINVAL; + sun4i_i2s_stop_capture(i2s); break; default: @@ -447,9 +490,23 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream, regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0); } +static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + + if (clk_id != 0) + return -EINVAL; + + i2s->mclk_freq = freq; + + return 0; +} + static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, + .set_sysclk = sun4i_i2s_set_sysclk, .shutdown = sun4i_i2s_shutdown, .startup = sun4i_i2s_startup, .trigger = sun4i_i2s_trigger, @@ -459,7 +516,9 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, NULL); + snd_soc_dai_init_dma_data(dai, + &i2s->playback_dma_data, + &i2s->capture_dma_data); snd_soc_dai_set_drvdata(dai, i2s); @@ -468,6 +527,13 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver sun4i_i2s_dai = { .probe = sun4i_i2s_dai_probe, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, .playback = { .stream_name = "Playback", .channels_min = 2, @@ -630,6 +696,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev) i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; i2s->playback_dma_data.maxburst = 4; + i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG; + i2s->capture_dma_data.maxburst = 4; + pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { ret = sun4i_i2s_runtime_resume(&pdev->dev); diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c new file mode 100644 index 000000000000..af02290ebe49 --- /dev/null +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -0,0 +1,665 @@ +/* + * This driver supports the analog controls for the internal codec + * found in Allwinner's A31s, A23, A33 and H3 SoCs. + * + * Copyright 2016 Chen-Yu Tsai <wens@csie.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +/* Codec analog control register offsets and bit fields */ +#define SUN8I_ADDA_HP_VOLC 0x00 +#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7 +#define SUN8I_ADDA_HP_VOLC_HP_VOL 0 +#define SUN8I_ADDA_LOMIXSC 0x01 +#define SUN8I_ADDA_LOMIXSC_MIC1 6 +#define SUN8I_ADDA_LOMIXSC_MIC2 5 +#define SUN8I_ADDA_LOMIXSC_PHONE 4 +#define SUN8I_ADDA_LOMIXSC_PHONEN 3 +#define SUN8I_ADDA_LOMIXSC_LINEINL 2 +#define SUN8I_ADDA_LOMIXSC_DACL 1 +#define SUN8I_ADDA_LOMIXSC_DACR 0 +#define SUN8I_ADDA_ROMIXSC 0x02 +#define SUN8I_ADDA_ROMIXSC_MIC1 6 +#define SUN8I_ADDA_ROMIXSC_MIC2 5 +#define SUN8I_ADDA_ROMIXSC_PHONE 4 +#define SUN8I_ADDA_ROMIXSC_PHONEP 3 +#define SUN8I_ADDA_ROMIXSC_LINEINR 2 +#define SUN8I_ADDA_ROMIXSC_DACR 1 +#define SUN8I_ADDA_ROMIXSC_DACL 0 +#define SUN8I_ADDA_DAC_PA_SRC 0x03 +#define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7 +#define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6 +#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5 +#define SUN8I_ADDA_DAC_PA_SRC_LMIXEN 4 +#define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE 3 +#define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE 2 +#define SUN8I_ADDA_DAC_PA_SRC_RHPIS 1 +#define SUN8I_ADDA_DAC_PA_SRC_LHPIS 0 +#define SUN8I_ADDA_PHONEIN_GCTRL 0x04 +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG 4 +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG 0 +#define SUN8I_ADDA_LINEIN_GCTRL 0x05 +#define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4 +#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0 +#define SUN8I_ADDA_MICIN_GCTRL 0x06 +#define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4 +#define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0 +#define SUN8I_ADDA_PAEN_HP_CTRL 0x07 +#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7 +#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */ +#define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC 5 +#define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN 4 +#define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL 2 +#define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE 1 +#define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE 0 +#define SUN8I_ADDA_PHONEOUT_CTRL 0x08 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG 5 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN 4 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1 3 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2 2 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX 1 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX 0 +#define SUN8I_ADDA_PHONE_GAIN_CTRL 0x09 +#define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL 3 +#define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG 0 +#define SUN8I_ADDA_MIC2G_CTRL 0x0a +#define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN 7 +#define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST 4 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN 3 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN 2 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC 1 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC 0 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL 0x0b +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN 7 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN 6 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE 5 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN 3 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST 0 +#define SUN8I_ADDA_LADCMIXSC 0x0c +#define SUN8I_ADDA_LADCMIXSC_MIC1 6 +#define SUN8I_ADDA_LADCMIXSC_MIC2 5 +#define SUN8I_ADDA_LADCMIXSC_PHONE 4 +#define SUN8I_ADDA_LADCMIXSC_PHONEN 3 +#define SUN8I_ADDA_LADCMIXSC_LINEINL 2 +#define SUN8I_ADDA_LADCMIXSC_OMIXRL 1 +#define SUN8I_ADDA_LADCMIXSC_OMIXRR 0 +#define SUN8I_ADDA_RADCMIXSC 0x0d +#define SUN8I_ADDA_RADCMIXSC_MIC1 6 +#define SUN8I_ADDA_RADCMIXSC_MIC2 5 +#define SUN8I_ADDA_RADCMIXSC_PHONE 4 +#define SUN8I_ADDA_RADCMIXSC_PHONEP 3 +#define SUN8I_ADDA_RADCMIXSC_LINEINR 2 +#define SUN8I_ADDA_RADCMIXSC_OMIXR 1 +#define SUN8I_ADDA_RADCMIXSC_OMIXL 0 +#define SUN8I_ADDA_RES 0x0e +#define SUN8I_ADDA_RES_MMICBIAS_SEL 4 +#define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL 0 +#define SUN8I_ADDA_ADC_AP_EN 0x0f +#define SUN8I_ADDA_ADC_AP_EN_ADCREN 7 +#define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6 +#define SUN8I_ADDA_ADC_AP_EN_ADCG 0 + +/* Analog control register access bits */ +#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */ +#define ADDA_PR_RESET BIT(28) +#define ADDA_PR_WRITE BIT(24) +#define ADDA_PR_ADDR_SHIFT 16 +#define ADDA_PR_ADDR_MASK GENMASK(4, 0) +#define ADDA_PR_DATA_IN_SHIFT 8 +#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0) +#define ADDA_PR_DATA_OUT_SHIFT 0 +#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0) + +/* regmap access bits */ +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + void __iomem *base = (void __iomem *)context; + u32 tmp; + + /* De-assert reset */ + writel(readl(base) | ADDA_PR_RESET, base); + + /* Clear write bit */ + writel(readl(base) & ~ADDA_PR_WRITE, base); + + /* Set register address */ + tmp = readl(base); + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; + writel(tmp, base); + + /* Read back value */ + *val = readl(base) & ADDA_PR_DATA_OUT_MASK; + + return 0; +} + +static int adda_reg_write(void *context, unsigned int reg, unsigned int val) +{ + void __iomem *base = (void __iomem *)context; + u32 tmp; + + /* De-assert reset */ + writel(readl(base) | ADDA_PR_RESET, base); + + /* Set register address */ + tmp = readl(base); + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; + writel(tmp, base); + + /* Set data to write */ + tmp = readl(base); + tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT); + tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT; + writel(tmp, base); + + /* Set write bit to signal a write */ + writel(readl(base) | ADDA_PR_WRITE, base); + + /* Clear write bit */ + writel(readl(base) & ~ADDA_PR_WRITE, base); + + return 0; +} + +static const struct regmap_config adda_pr_regmap_cfg = { + .name = "adda-pr", + .reg_bits = 5, + .reg_stride = 1, + .val_bits = 8, + .reg_read = adda_reg_read, + .reg_write = adda_reg_write, + .fast_io = true, + .max_register = 24, +}; + +/* mixer controls */ +static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("DAC Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_DACL, 1, 0), + SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_DACR, 1, 0), + SOC_DAPM_DOUBLE_R("Line In Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_MIC2, 1, 0), +}; + +/* ADC mixer controls */ +static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("Mixer Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0), + SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0), + SOC_DAPM_DOUBLE_R("Line In Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0), +}; + +/* volume / mute controls */ +static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale, + -450, 150, 0); +static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), +); + +static const struct snd_kcontrol_new sun8i_codec_common_controls[] = { + /* Mixer pre-gains */ + SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL, + SUN8I_ADDA_LINEIN_GCTRL_LINEING, + 0x7, 0, sun8i_codec_out_mixer_pregain_scale), + SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL, + SUN8I_ADDA_MICIN_GCTRL_MIC1G, + 0x7, 0, sun8i_codec_out_mixer_pregain_scale), + SOC_SINGLE_TLV("Mic2 Playback Volume", + SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G, + 0x7, 0, sun8i_codec_out_mixer_pregain_scale), + + /* Microphone Amp boost gains */ + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0, + sun8i_codec_mic_gain_scale), + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0, + sun8i_codec_mic_gain_scale), + + /* ADC */ + SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0, + sun8i_codec_out_mixer_pregain_scale), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { + /* ADC */ + SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0), + SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0), + + /* DAC */ + SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0), + SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0), + /* + * Due to this component and the codec belonging to separate DAPM + * contexts, we need to manually link the above widgets to their + * stream widgets at the card level. + */ + + /* Line In */ + SND_SOC_DAPM_INPUT("LINEIN"), + + /* Microphone inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN, + 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0), + + /* Mixers */ + SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, + sun8i_codec_mixer_controls, + ARRAY_SIZE(sun8i_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0, + sun8i_codec_mixer_controls, + ARRAY_SIZE(sun8i_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0, + sun8i_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0, + sun8i_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), +}; + +static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { + /* Microphone Routes */ + { "Mic1 Amplifier", NULL, "MIC1"}, + { "Mic2 Amplifier", NULL, "MIC2"}, + + /* Left Mixer Routes */ + { "Left Mixer", "DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, + { "Left Mixer", "Line In Playback Switch", "LINEIN" }, + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + + /* Right Mixer Routes */ + { "Right Mixer", "DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, + { "Right Mixer", "Line In Playback Switch", "LINEIN" }, + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + + /* Left ADC Mixer Routes */ + { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, + { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + /* Right ADC Mixer Routes */ + { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, + { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + /* ADC Routes */ + { "Left ADC", NULL, "Left ADC Mixer" }, + { "Right ADC", NULL, "Right ADC Mixer" }, +}; + +/* headphone specific controls, widgets, and routes */ +static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1); +static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = { + SOC_SINGLE_TLV("Headphone Playback Volume", + SUN8I_ADDA_HP_VOLC, + SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0, + sun8i_codec_hp_vol_scale), + SOC_DOUBLE("Headphone Playback Switch", + SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE, + SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0), +}; + +static const char * const sun8i_codec_hp_src_enum_text[] = { + "DAC", "Mixer", +}; + +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum, + SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LHPIS, + SUN8I_ADDA_DAC_PA_SRC_RHPIS, + sun8i_codec_hp_src_enum_text); + +static const struct snd_kcontrol_new sun8i_codec_hp_src[] = { + SOC_DAPM_ENUM("Headphone Source Playback Route", + sun8i_codec_hp_src_enum), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = { + SND_SOC_DAPM_MUX("Headphone Source Playback Route", + SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src), + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL, + SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL, + SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL, + SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0), + SND_SOC_DAPM_OUTPUT("HP"), +}; + +static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = { + { "Headphone Source Playback Route", "DAC", "Left DAC" }, + { "Headphone Source Playback Route", "DAC", "Right DAC" }, + { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, + { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, + { "Headphone Amp", NULL, "Headphone Source Playback Route" }, + { "HPCOM", NULL, "HPCOM Protection" }, + { "HP", NULL, "Headphone Amp" }, +}; + +static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun8i_codec_headphone_controls, + ARRAY_SIZE(sun8i_codec_headphone_controls)); + if (ret) { + dev_err(dev, "Failed to add Headphone controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets, + ARRAY_SIZE(sun8i_codec_headphone_widgets)); + if (ret) { + dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes, + ARRAY_SIZE(sun8i_codec_headphone_routes)); + if (ret) { + dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + +/* hmic specific widget */ +static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = { + SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN, + 0, NULL, 0), +}; + +static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets, + ARRAY_SIZE(sun8i_codec_hmic_widgets)); + if (ret) + dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret); + + return ret; +} + +/* line out specific controls, widgets and routes */ +static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale, + 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), +); +static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = { + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN8I_ADDA_PHONE_GAIN_CTRL, + SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0, + sun8i_codec_lineout_vol_scale), + SOC_DOUBLE("Line Out Playback Switch", + SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN, + SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0), +}; + +static const char * const sun8i_codec_lineout_src_enum_text[] = { + "Stereo", "Mono Differential", +}; + +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum, + SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC, + SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC, + sun8i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun8i_codec_lineout_src_enum), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = { + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src), + /* It is unclear if this is a buffer or gate, model it as a supply */ + SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL, + SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("LINEOUT"), +}; + +static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = { + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" }, + { "LINEOUT", NULL, "Line Out Source Playback Route" }, + { "LINEOUT", NULL, "Line Out Enable", }, +}; + +static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun8i_codec_lineout_controls, + ARRAY_SIZE(sun8i_codec_lineout_controls)); + if (ret) { + dev_err(dev, "Failed to add Line Out controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets, + ARRAY_SIZE(sun8i_codec_lineout_widgets)); + if (ret) { + dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes, + ARRAY_SIZE(sun8i_codec_lineout_routes)); + if (ret) { + dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + +struct sun8i_codec_analog_quirks { + bool has_headphone; + bool has_hmic; + bool has_lineout; +}; + +static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { + .has_headphone = true, + .has_hmic = true, +}; + +static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { + .has_lineout = true, +}; + +static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) +{ + struct device *dev = cmpnt->dev; + const struct sun8i_codec_analog_quirks *quirks; + int ret; + + /* + * This would never return NULL unless someone directly registers a + * platform device matching this driver's name, without specifying a + * device tree node. + */ + quirks = of_device_get_match_data(dev); + + /* Add controls, widgets, and routes for individual features */ + + if (quirks->has_headphone) { + ret = sun8i_codec_add_headphone(cmpnt); + if (ret) + return ret; + } + + if (quirks->has_hmic) { + ret = sun8i_codec_add_hmic(cmpnt); + if (ret) + return ret; + } + + if (quirks->has_lineout) { + ret = sun8i_codec_add_lineout(cmpnt); + if (ret) + return ret; + } + + return 0; +} + +static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = { + .controls = sun8i_codec_common_controls, + .num_controls = ARRAY_SIZE(sun8i_codec_common_controls), + .dapm_widgets = sun8i_codec_common_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_common_widgets), + .dapm_routes = sun8i_codec_common_routes, + .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes), + .probe = sun8i_codec_analog_cmpnt_probe, +}; + +static const struct of_device_id sun8i_codec_analog_of_match[] = { + { + .compatible = "allwinner,sun8i-a23-codec-analog", + .data = &sun8i_a23_quirks, + }, + { + .compatible = "allwinner,sun8i-h3-codec-analog", + .data = &sun8i_h3_quirks, + }, + {} +}; +MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match); + +static int sun8i_codec_analog_probe(struct platform_device *pdev) +{ + struct resource *res; + struct regmap *regmap; + void __iomem *base; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed to map the registers\n"); + return PTR_ERR(base); + } + + regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg); + if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "Failed to create regmap\n"); + return PTR_ERR(regmap); + } + + return devm_snd_soc_register_component(&pdev->dev, + &sun8i_codec_analog_cmpnt_drv, + NULL, 0); +} + +static struct platform_driver sun8i_codec_analog_driver = { + .driver = { + .name = "sun8i-codec-analog", + .of_match_table = sun8i_codec_analog_of_match, + }, + .probe = sun8i_codec_analog_probe, +}; +module_platform_driver(sun8i_codec_analog_driver); + +MODULE_DESCRIPTION("Allwinner internal codec analog controls driver"); +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sun8i-codec-analog"); diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index deb597f7c302..eead6e7f205b 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -65,7 +65,7 @@ static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_alc5632_asoc_ops = { +static const struct snd_soc_ops tegra_alc5632_asoc_ops = { .hw_params = tegra_alc5632_asoc_hw_params, }; diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index 902da36581d1..a403db6d563e 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -93,7 +93,7 @@ static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_max98090_ops = { +static const struct snd_soc_ops tegra_max98090_ops = { .hw_params = tegra_max98090_asoc_hw_params, }; diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index e5ef4e9c4ac5..25b9fc03ba62 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -76,7 +76,7 @@ static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_rt5640_ops = { +static const struct snd_soc_ops tegra_rt5640_ops = { .hw_params = tegra_rt5640_asoc_hw_params, }; diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c index 1470873ecde6..ebf58d0e0f10 100644 --- a/sound/soc/tegra/tegra_rt5677.c +++ b/sound/soc/tegra/tegra_rt5677.c @@ -93,7 +93,7 @@ static int tegra_rt5677_event_hp(struct snd_soc_dapm_widget *w, return 0; } -static struct snd_soc_ops tegra_rt5677_ops = { +static const struct snd_soc_ops tegra_rt5677_ops = { .hw_params = tegra_rt5677_asoc_hw_params, }; diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c index 1e76869dd488..4bbab098f50b 100644 --- a/sound/soc/tegra/tegra_sgtl5000.c +++ b/sound/soc/tegra/tegra_sgtl5000.c @@ -82,7 +82,7 @@ static int tegra_sgtl5000_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_sgtl5000_ops = { +static const struct snd_soc_ops tegra_sgtl5000_ops = { .hw_params = tegra_sgtl5000_hw_params, }; diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index f0cd01dbfc38..bdedd1028569 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -89,7 +89,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_wm8753_ops = { +static const struct snd_soc_ops tegra_wm8753_ops = { .hw_params = tegra_wm8753_hw_params, }; diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index e485278e027a..2013e9c4bba0 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -96,7 +96,7 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_wm8903_ops = { +static const struct snd_soc_ops tegra_wm8903_ops = { .hw_params = tegra_wm8903_hw_params, }; diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 2cea203c4f5f..870f84ab5005 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -74,7 +74,7 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops trimslice_asoc_ops = { +static const struct snd_soc_ops trimslice_asoc_ops = { .hw_params = trimslice_asoc_hw_params, }; diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 0190cb6332f2..52063b262667 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -304,7 +304,7 @@ struct snd_dbri { spinlock_t lock; struct dbri_dma *dma; /* Pointer to our DMA block */ - u32 dma_dvma; /* DBRI visible DMA address */ + dma_addr_t dma_dvma; /* DBRI visible DMA address */ void __iomem *regs; /* dbri HW regs */ int dbri_irqp; /* intr queue pointer */ @@ -657,12 +657,14 @@ static void dbri_cmdwait(struct snd_dbri *dbri) */ static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len) { + u32 dvma_addr = (u32)dbri->dma_dvma; + /* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */ len += 2; spin_lock(&dbri->cmdlock); if (dbri->cmdptr - dbri->dma->cmd + len < DBRI_NO_CMDS - 2) return dbri->cmdptr + 2; - else if (len < sbus_readl(dbri->regs + REG8) - dbri->dma_dvma) + else if (len < sbus_readl(dbri->regs + REG8) - dvma_addr) return dbri->dma->cmd; else printk(KERN_ERR "DBRI: no space for commands."); @@ -680,6 +682,7 @@ static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len) */ static void dbri_cmdsend(struct snd_dbri *dbri, s32 *cmd, int len) { + u32 dvma_addr = (u32)dbri->dma_dvma; s32 tmp, addr; static int wait_id = 0; @@ -689,7 +692,7 @@ static void dbri_cmdsend(struct snd_dbri *dbri, s32 *cmd, int len) *(cmd+1) = DBRI_CMD(D_WAIT, 1, wait_id); /* Replace the last command with JUMP */ - addr = dbri->dma_dvma + (cmd - len - dbri->dma->cmd) * sizeof(s32); + addr = dvma_addr + (cmd - len - dbri->dma->cmd) * sizeof(s32); *(dbri->cmdptr+1) = addr; *(dbri->cmdptr) = DBRI_CMD(D_JUMP, 0, 0); @@ -747,6 +750,7 @@ static void dbri_reset(struct snd_dbri *dbri) /* Lock must not be held before calling this */ static void dbri_initialize(struct snd_dbri *dbri) { + u32 dvma_addr = (u32)dbri->dma_dvma; s32 *cmd; u32 dma_addr; unsigned long flags; @@ -764,7 +768,7 @@ static void dbri_initialize(struct snd_dbri *dbri) /* * Initialize the interrupt ring buffer. */ - dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0); + dma_addr = dvma_addr + dbri_dma_off(intr, 0); dbri->dma->intr[0] = dma_addr; dbri->dbri_irqp = 1; /* @@ -778,7 +782,7 @@ static void dbri_initialize(struct snd_dbri *dbri) dbri->cmdptr = cmd; *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); - dma_addr = dbri->dma_dvma + dbri_dma_off(cmd, 0); + dma_addr = dvma_addr + dbri_dma_off(cmd, 0); sbus_writel(dma_addr, dbri->regs + REG8); spin_unlock(&dbri->cmdlock); @@ -1077,6 +1081,7 @@ static void recv_fixed(struct snd_dbri *dbri, int pipe, volatile __u32 *ptr) static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period) { struct dbri_streaminfo *info = &dbri->stream_info[streamno]; + u32 dvma_addr = (u32)dbri->dma_dvma; __u32 dvma_buffer; int desc; int len; @@ -1177,7 +1182,7 @@ static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period) else { dbri->next_desc[last_desc] = desc; dbri->dma->desc[last_desc].nda = - dbri->dma_dvma + dbri_dma_off(desc, desc); + dvma_addr + dbri_dma_off(desc, desc); } last_desc = desc; @@ -1192,7 +1197,7 @@ static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period) } dbri->dma->desc[last_desc].nda = - dbri->dma_dvma + dbri_dma_off(desc, first_desc); + dvma_addr + dbri_dma_off(desc, first_desc); dbri->next_desc[last_desc] = first_desc; dbri->pipes[info->pipe].first_desc = first_desc; dbri->pipes[info->pipe].desc = first_desc; @@ -1697,6 +1702,7 @@ interrupts are disabled. static void xmit_descs(struct snd_dbri *dbri) { struct dbri_streaminfo *info; + u32 dvma_addr; s32 *cmd; unsigned long flags; int first_td; @@ -1704,6 +1710,7 @@ static void xmit_descs(struct snd_dbri *dbri) if (dbri == NULL) return; /* Disabled */ + dvma_addr = (u32)dbri->dma_dvma; info = &dbri->stream_info[DBRI_REC]; spin_lock_irqsave(&dbri->lock, flags); @@ -1718,7 +1725,7 @@ static void xmit_descs(struct snd_dbri *dbri) *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[info->pipe].sdp | D_SDP_P | D_SDP_EVERY | D_SDP_C); - *(cmd++) = dbri->dma_dvma + + *(cmd++) = dvma_addr + dbri_dma_off(desc, first_td); dbri_cmdsend(dbri, cmd, 2); @@ -1740,7 +1747,7 @@ static void xmit_descs(struct snd_dbri *dbri) *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[info->pipe].sdp | D_SDP_P | D_SDP_EVERY | D_SDP_C); - *(cmd++) = dbri->dma_dvma + + *(cmd++) = dvma_addr + dbri_dma_off(desc, first_td); dbri_cmdsend(dbri, cmd, 2); @@ -2539,7 +2546,7 @@ static int snd_dbri_create(struct snd_card *card, if (!dbri->dma) return -ENOMEM; - dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n", + dprintk(D_GEN, "DMA Cmd Block 0x%p (%pad)\n", dbri->dma, dbri->dma_dvma); /* Map the registers into memory. */ diff --git a/sound/usb/card.c b/sound/usb/card.c index 9e5276d6dda0..2ddc034673a8 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -315,7 +315,8 @@ static int snd_usb_audio_free(struct snd_usb_audio *chip) snd_usb_endpoint_free(ep); mutex_destroy(&chip->mutex); - dev_set_drvdata(&chip->dev->dev, NULL); + if (!atomic_read(&chip->shutdown)) + dev_set_drvdata(&chip->dev->dev, NULL); kfree(chip); return 0; } diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index c60a776e815d..8a59d4782a0f 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2907,6 +2907,23 @@ AU0828_DEVICE(0x2040, 0x7260, "Hauppauge", "HVR-950Q"), AU0828_DEVICE(0x2040, 0x7213, "Hauppauge", "HVR-950Q"), AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), +/* Syntek STK1160 */ +{ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .idVendor = 0x05e1, + .idProduct = 0x0408, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Syntek", + .product_name = "STK1160", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER + } +}, + /* Digidesign Mbox */ { /* Thanks to Clemens Ladisch <clemens@ladisch.de> */ |