diff options
Diffstat (limited to '')
260 files changed, 16850 insertions, 7568 deletions
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 467836057ee5..a80d5ea87ccd 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -47,15 +47,11 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, /* We use the PCI APIs for now until the generic one gets fixed * enough or until we get some macio-specific versions */ - r->space = dma_alloc_coherent( - &macio_get_pci_dev(i2sdev->macio)->dev, - r->size, - &r->bus_addr, - GFP_KERNEL); + r->space = dma_zalloc_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, + r->size, &r->bus_addr, GFP_KERNEL); + if (!r->space) + return -ENOMEM; - if (!r->space) return -ENOMEM; - - memset(r->space, 0, r->size); r->cmds = (void*)DBDMA_ALIGN(r->space); r->bus_cmd_start = r->bus_addr + (dma_addr_t)((char*)r->cmds - (char*)r->space); diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 66de90ed30ca..39c3969ac1c7 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -152,9 +152,9 @@ static inline void pxa_ac97_cold_pxa27x(void) gsr_bits = 0; /* PXA27x Developers Manual section 13.5.2.2.1 */ - clk_enable(ac97conf_clk); + clk_prepare_enable(ac97conf_clk); udelay(5); - clk_disable(ac97conf_clk); + clk_disable_unprepare(ac97conf_clk); GCR = GCR_COLD_RST | GCR_WARM_RST; } #endif @@ -299,14 +299,14 @@ static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) int pxa2xx_ac97_hw_suspend(void) { GCR |= GCR_ACLINK_OFF; - clk_disable(ac97_clk); + clk_disable_unprepare(ac97_clk); return 0; } EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend); int pxa2xx_ac97_hw_resume(void) { - clk_enable(ac97_clk); + clk_prepare_enable(ac97_clk); return 0; } EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); @@ -368,7 +368,7 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev) goto err_clk; } - ret = clk_enable(ac97_clk); + ret = clk_prepare_enable(ac97_clk); if (ret) goto err_clk2; @@ -403,7 +403,7 @@ void pxa2xx_ac97_hw_remove(struct platform_device *dev) clk_put(ac97conf_clk); ac97conf_clk = NULL; } - clk_disable(ac97_clk); + clk_disable_unprepare(ac97_clk); clk_put(ac97_clk); ac97_clk = NULL; } diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 7403f348ed14..89028fab64fd 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -491,7 +491,7 @@ static int snd_compress_check_input(struct snd_compr_params *params) { /* first let's check the buffer parameter's */ if (params->buffer.fragment_size == 0 || - params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size) + params->buffer.fragments > INT_MAX / params->buffer.fragment_size) return -EINVAL; /* now codec parameters */ diff --git a/sound/core/control.c b/sound/core/control.c index f0b0e14497a5..b9611344ff9e 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1406,11 +1406,11 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: return snd_ctl_subscribe_events(ctl, ip); case SNDRV_CTL_IOCTL_TLV_READ: - return snd_ctl_tlv_ioctl(ctl, argp, 0); + return snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ); case SNDRV_CTL_IOCTL_TLV_WRITE: - return snd_ctl_tlv_ioctl(ctl, argp, 1); + return snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE); case SNDRV_CTL_IOCTL_TLV_COMMAND: - return snd_ctl_tlv_ioctl(ctl, argp, -1); + return snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD); case SNDRV_CTL_IOCTL_POWER: return -ENOPROTOOPT; case SNDRV_CTL_IOCTL_POWER_STATE: diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index af49721ba0e3..102e8fd1d450 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -101,7 +101,9 @@ struct snd_pcm_sw_params32 { u32 silence_threshold; u32 silence_size; u32 boundary; - unsigned char reserved[64]; + u32 proto; + u32 tstamp_type; + unsigned char reserved[56]; }; /* recalcuate the boundary within 32bit */ @@ -133,7 +135,9 @@ static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream, get_user(params.start_threshold, &src->start_threshold) || get_user(params.stop_threshold, &src->stop_threshold) || get_user(params.silence_threshold, &src->silence_threshold) || - get_user(params.silence_size, &src->silence_size)) + get_user(params.silence_size, &src->silence_size) || + get_user(params.tstamp_type, &src->tstamp_type) || + get_user(params.proto, &src->proto)) return -EFAULT; /* * Check silent_size parameter. Since we have 64bit boundary, diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 76cbb9ec953a..6542c4083594 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -65,13 +65,15 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, enum dma_slave_buswidth buswidth; int bits; - bits = snd_pcm_format_physical_width(params_format(params)); + bits = params_physical_width(params); if (bits < 8 || bits > 64) return -EINVAL; else if (bits == 8) buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; else if (bits == 16) buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + else if (bits == 24) + buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES; else if (bits <= 32) buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; else diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b653ab001fba..8cd2f930ad0b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -543,6 +543,9 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST) return -EINVAL; + if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12) && + params->tstamp_type > SNDRV_PCM_TSTAMP_TYPE_LAST) + return -EINVAL; if (params->avail_min == 0) return -EINVAL; if (params->silence_size >= runtime->boundary) { @@ -557,6 +560,8 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, err = 0; snd_pcm_stream_lock_irq(substream); runtime->tstamp_mode = params->tstamp_mode; + if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12)) + runtime->tstamp_type = params->tstamp_type; runtime->period_step = params->period_step; runtime->control->avail_min = params->avail_min; runtime->start_threshold = params->start_threshold; @@ -2540,9 +2545,7 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg) return -EFAULT; if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST) return -EINVAL; - runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY; - if (arg == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC) - runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; + runtime->tstamp_type = arg; return 0; } diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 1e206de0c2dd..ba8e4a64e13e 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -101,9 +101,9 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, len -= size; } return 0; - } if (! (event->data.ext.len & SNDRV_SEQ_EXT_CHAINED)) { - return func(private_data, event->data.ext.ptr, len); } + if (!(event->data.ext.len & SNDRV_SEQ_EXT_CHAINED)) + return func(private_data, event->data.ext.ptr, len); cell = (struct snd_seq_event_cell *)event->data.ext.ptr; for (; len > 0 && cell; cell = cell->next) { diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 775ef2efc296..46dff64908c8 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -83,8 +83,8 @@ config SND_BEBOB * Edirol FA-66/FA-101 * PreSonus FIREBOX/FIREPOD/FP10/Inspire1394 * BridgeCo RDAudio1/Audio5 - * Mackie Onyx 1220/1620/1640 (Firewire I/O Card) - * Mackie d.2 (Firewire Option) + * Mackie Onyx 1220/1620/1640 (FireWire I/O Card) + * Mackie d.2 (FireWire Option) * Stanton FinalScratch 2 (ScratchAmp) * Tascam IF-FW/DM * Behringer XENIX UFX 1204/1604 @@ -92,7 +92,7 @@ config SND_BEBOB * Apogee Rosetta 200/400 (X-FireWire card) * Apogee DA/AD/DD-16X (X-FireWire card) * Apogee Ensemble - * ESI Quotafire610 + * ESI QuataFire 610 * AcousticReality eARMasterOne * CME MatrixKFW * Phonic Helix Board 12 MkII/18 MkII/24 MkII @@ -101,13 +101,13 @@ config SND_BEBOB * ICON FireXon * PrismSound Orpheus/ADA-8XR * TerraTec PHASE 24 FW/PHASE X24 FW/PHASE 88 Rack FW - * Terratec EWS MIC2/EWS MIC4 - * Terratec Aureon 7.1 Firewire + * TerraTec EWS MIC2/EWS MIC8 + * TerraTec Aureon 7.1 FireWire * Yamaha GO44/GO46 * Focusrite Saffire/Saffire LE/SaffirePro10 IO/SaffirePro26 IO - * M-Audio Firewire410/AudioPhile/Solo + * M-Audio FireWire410/AudioPhile/Solo * M-Audio Ozonic/NRV10/ProfireLightBridge - * M-Audio Firewire 1814/ProjectMix IO + * M-Audio FireWire 1814/ProjectMix IO To compile this driver as a module, choose M here: the module will be called snd-bebob. diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c index 6af50eb80ea7..70faa3a32526 100644 --- a/sound/firewire/bebob/bebob_maudio.c +++ b/sound/firewire/bebob/bebob_maudio.c @@ -379,11 +379,11 @@ static int special_clk_ctl_put(struct snd_kcontrol *kctl, struct special_params *params = bebob->maudio_special_quirk; int err, id; - mutex_lock(&bebob->mutex); - id = uval->value.enumerated.item[0]; if (id >= ARRAY_SIZE(special_clk_labels)) - return 0; + return -EINVAL; + + mutex_lock(&bebob->mutex); err = avc_maudio_set_special_clk(bebob, id, params->dig_in_fmt, @@ -391,7 +391,10 @@ static int special_clk_ctl_put(struct snd_kcontrol *kctl, params->clk_lock); mutex_unlock(&bebob->mutex); - return err >= 0; + if (err >= 0) + err = 1; + + return err; } static struct snd_kcontrol_new special_clk_ctl = { .name = "Clock Source", @@ -434,8 +437,8 @@ static struct snd_kcontrol_new special_sync_ctl = { .get = special_sync_ctl_get, }; -/* Digital interface control for special firmware */ -static char *const special_dig_iface_labels[] = { +/* Digital input interface control for special firmware */ +static char *const special_dig_in_iface_labels[] = { "S/PDIF Optical", "S/PDIF Coaxial", "ADAT Optical" }; static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl, @@ -443,13 +446,13 @@ static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl, { einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; einf->count = 1; - einf->value.enumerated.items = ARRAY_SIZE(special_dig_iface_labels); + einf->value.enumerated.items = ARRAY_SIZE(special_dig_in_iface_labels); if (einf->value.enumerated.item >= einf->value.enumerated.items) einf->value.enumerated.item = einf->value.enumerated.items - 1; strcpy(einf->value.enumerated.name, - special_dig_iface_labels[einf->value.enumerated.item]); + special_dig_in_iface_labels[einf->value.enumerated.item]); return 0; } @@ -491,26 +494,36 @@ static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl, unsigned int id, dig_in_fmt, dig_in_iface; int err; - mutex_lock(&bebob->mutex); - id = uval->value.enumerated.item[0]; + if (id >= ARRAY_SIZE(special_dig_in_iface_labels)) + return -EINVAL; /* decode user value */ dig_in_fmt = (id >> 1) & 0x01; dig_in_iface = id & 0x01; + mutex_lock(&bebob->mutex); + err = avc_maudio_set_special_clk(bebob, params->clk_src, dig_in_fmt, params->dig_out_fmt, params->clk_lock); - if ((err < 0) || (params->dig_in_fmt > 0)) /* ADAT */ + if (err < 0) + goto end; + + /* For ADAT, optical interface is only available. */ + if (params->dig_in_fmt > 0) { + err = 1; goto end; + } + /* For S/PDIF, optical/coaxial interfaces are selectable. */ err = avc_audio_set_selector(bebob->unit, 0x00, 0x04, dig_in_iface); if (err < 0) dev_err(&bebob->unit->device, "fail to set digital input interface: %d\n", err); + err = 1; end: special_stream_formation_set(bebob); mutex_unlock(&bebob->mutex); @@ -525,18 +538,22 @@ static struct snd_kcontrol_new special_dig_in_iface_ctl = { .put = special_dig_in_iface_ctl_set }; +/* Digital output interface control for special firmware */ +static char *const special_dig_out_iface_labels[] = { + "S/PDIF Optical and Coaxial", "ADAT Optical" +}; static int special_dig_out_iface_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *einf) { einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; einf->count = 1; - einf->value.enumerated.items = ARRAY_SIZE(special_dig_iface_labels) - 1; + einf->value.enumerated.items = ARRAY_SIZE(special_dig_out_iface_labels); if (einf->value.enumerated.item >= einf->value.enumerated.items) einf->value.enumerated.item = einf->value.enumerated.items - 1; strcpy(einf->value.enumerated.name, - special_dig_iface_labels[einf->value.enumerated.item + 1]); + special_dig_out_iface_labels[einf->value.enumerated.item]); return 0; } @@ -558,16 +575,20 @@ static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl, unsigned int id; int err; - mutex_lock(&bebob->mutex); - id = uval->value.enumerated.item[0]; + if (id >= ARRAY_SIZE(special_dig_out_iface_labels)) + return -EINVAL; + + mutex_lock(&bebob->mutex); err = avc_maudio_set_special_clk(bebob, params->clk_src, params->dig_in_fmt, id, params->clk_lock); - if (err >= 0) + if (err >= 0) { special_stream_formation_set(bebob); + err = 1; + } mutex_unlock(&bebob->mutex); return err; diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c index f29d4aaf56a1..0639dcb13f7d 100644 --- a/sound/firewire/fireworks/fireworks_proc.c +++ b/sound/firewire/fireworks/fireworks_proc.c @@ -64,7 +64,7 @@ proc_read_hwinfo(struct snd_info_entry *entry, struct snd_info_buffer *buffer) hwinfo->phys_in_grp_count); for (i = 0; i < hwinfo->phys_in_grp_count; i++) { snd_iprintf(buffer, - "phys in grp[0x%d]: type 0x%d, count 0x%d\n", + "phys in grp[%d]: type 0x%X, count 0x%X\n", i, hwinfo->phys_out_grps[i].type, hwinfo->phys_out_grps[i].count); } @@ -73,7 +73,7 @@ proc_read_hwinfo(struct snd_info_entry *entry, struct snd_info_buffer *buffer) hwinfo->phys_out_grp_count); for (i = 0; i < hwinfo->phys_out_grp_count; i++) { snd_iprintf(buffer, - "phys out grps[0x%d]: type 0x%d, count 0x%d\n", + "phys out grps[%d]: type 0x%X, count 0x%X\n", i, hwinfo->phys_out_grps[i].type, hwinfo->phys_out_grps[i].count); } diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 3bbc3ec5be82..862735005b43 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -316,6 +316,7 @@ static int mpu_input_scanner(struct mpu_config *devc, unsigned char midic) case 0xf6: /* printk( "tune_request\n"); */ devc->m_state = ST_INIT; + break; /* * Real time messages @@ -972,7 +973,6 @@ int attach_mpu401(struct address_info *hw_config, struct module *owner) devc->m_busy = 0; devc->m_state = ST_INIT; devc->shared_irq = hw_config->always_detect; - devc->irq = hw_config->irq; spin_lock_init(&devc->lock); if (devc->irq < 0) diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c index 4709e592e2cc..607cee4d545e 100644 --- a/sound/oss/opl3.c +++ b/sound/oss/opl3.c @@ -52,7 +52,7 @@ struct voice_info int panning; /* 0xffff means not set */ }; -typedef struct opl_devinfo +struct opl_devinfo { int base; int left_io, right_io; @@ -73,7 +73,7 @@ typedef struct opl_devinfo unsigned char cmask; int is_opl4; -} opl_devinfo; +}; static struct opl_devinfo *devc = NULL; diff --git a/sound/oss/pss.c b/sound/oss/pss.c index 145e36b2cfd0..ca0d6e9f49f5 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -123,25 +123,25 @@ static bool pss_mixer; #endif -typedef struct pss_mixerdata { +struct pss_mixerdata { unsigned int volume_l; unsigned int volume_r; unsigned int bass; unsigned int treble; unsigned int synth; -} pss_mixerdata; +}; -typedef struct pss_confdata { +struct pss_confdata { int base; int irq; int dma; int *osp; - pss_mixerdata mixer; + struct pss_mixerdata mixer; int ad_mixer_dev; -} pss_confdata; +}; -static pss_confdata pss_data; -static pss_confdata *devc = &pss_data; +static struct pss_confdata pss_data; +static struct pss_confdata *devc = &pss_data; static DEFINE_SPINLOCK(lock); static int pss_initialized; @@ -150,7 +150,7 @@ static int pss_cdrom_port = -1; /* Parameter for the PSS cdrom port */ static bool pss_enable_joystick; /* Parameter for enabling the joystick */ static coproc_operations pss_coproc_operations; -static void pss_write(pss_confdata *devc, int data) +static void pss_write(struct pss_confdata *devc, int data) { unsigned long i, limit; @@ -206,7 +206,7 @@ static int __init probe_pss(struct address_info *hw_config) return 1; } -static int set_irq(pss_confdata * devc, int dev, int irq) +static int set_irq(struct pss_confdata *devc, int dev, int irq) { static unsigned short irq_bits[16] = { @@ -232,7 +232,7 @@ static int set_irq(pss_confdata * devc, int dev, int irq) return 1; } -static void set_io_base(pss_confdata * devc, int dev, int base) +static void set_io_base(struct pss_confdata *devc, int dev, int base) { unsigned short tmp = inw(REG(dev)) & 0x003f; unsigned short bits = (base & 0x0ffc) << 4; @@ -240,7 +240,7 @@ static void set_io_base(pss_confdata * devc, int dev, int base) outw(bits | tmp, REG(dev)); } -static int set_dma(pss_confdata * devc, int dev, int dma) +static int set_dma(struct pss_confdata *devc, int dev, int dma) { static unsigned short dma_bits[8] = { @@ -264,7 +264,7 @@ static int set_dma(pss_confdata * devc, int dev, int dma) return 1; } -static int pss_reset_dsp(pss_confdata * devc) +static int pss_reset_dsp(struct pss_confdata *devc) { unsigned long i, limit = jiffies + HZ/10; @@ -275,7 +275,7 @@ static int pss_reset_dsp(pss_confdata * devc) return 1; } -static int pss_put_dspword(pss_confdata * devc, unsigned short word) +static int pss_put_dspword(struct pss_confdata *devc, unsigned short word) { int i, val; @@ -291,7 +291,7 @@ static int pss_put_dspword(pss_confdata * devc, unsigned short word) return 0; } -static int pss_get_dspword(pss_confdata * devc, unsigned short *word) +static int pss_get_dspword(struct pss_confdata *devc, unsigned short *word) { int i, val; @@ -307,7 +307,8 @@ static int pss_get_dspword(pss_confdata * devc, unsigned short *word) return 0; } -static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags) +static int pss_download_boot(struct pss_confdata *devc, unsigned char *block, + int size, int flags) { int i, val, count; unsigned long limit; @@ -397,7 +398,7 @@ static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size } /* Mixer */ -static void set_master_volume(pss_confdata *devc, int left, int right) +static void set_master_volume(struct pss_confdata *devc, int left, int right) { static unsigned char log_scale[101] = { 0xdb, 0xe0, 0xe3, 0xe5, 0xe7, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee, @@ -416,7 +417,7 @@ static void set_master_volume(pss_confdata *devc, int left, int right) pss_write(devc, log_scale[right] | 0x0100); } -static void set_synth_volume(pss_confdata *devc, int volume) +static void set_synth_volume(struct pss_confdata *devc, int volume) { int vol = ((0x8000*volume)/100L); pss_write(devc, 0x0080); @@ -425,21 +426,21 @@ static void set_synth_volume(pss_confdata *devc, int volume) pss_write(devc, vol); } -static void set_bass(pss_confdata *devc, int level) +static void set_bass(struct pss_confdata *devc, int level) { int vol = (int)(((0xfd - 0xf0) * level)/100L) + 0xf0; pss_write(devc, 0x0010); pss_write(devc, vol | 0x0200); }; -static void set_treble(pss_confdata *devc, int level) +static void set_treble(struct pss_confdata *devc, int level) { int vol = (((0xfd - 0xf0) * level)/100L) + 0xf0; pss_write(devc, 0x0010); pss_write(devc, vol | 0x0300); }; -static void pss_mixer_reset(pss_confdata *devc) +static void pss_mixer_reset(struct pss_confdata *devc) { set_master_volume(devc, 33, 33); set_bass(devc, 50); @@ -499,7 +500,8 @@ static int ret_vol_stereo(int left, int right) return ((right << 8) | left); } -static int call_ad_mixer(pss_confdata *devc,unsigned int cmd, void __user *arg) +static int call_ad_mixer(struct pss_confdata *devc, unsigned int cmd, + void __user *arg) { if (devc->ad_mixer_dev != NO_WSS_MIXER) return mixer_devs[devc->ad_mixer_dev]->ioctl(devc->ad_mixer_dev, cmd, arg); @@ -509,7 +511,7 @@ static int call_ad_mixer(pss_confdata *devc,unsigned int cmd, void __user *arg) static int pss_mixer_ioctl (int dev, unsigned int cmd, void __user *arg) { - pss_confdata *devc = mixer_devs[dev]->devc; + struct pss_confdata *devc = mixer_devs[dev]->devc; int cmdf = cmd & 0xff; if ((cmdf != SOUND_MIXER_VOLUME) && (cmdf != SOUND_MIXER_BASS) && diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 3a3a3a71088b..50dd0086cfb1 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -858,8 +858,8 @@ config SND_VIRTUOSO select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for sound cards based on the - Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, - Essence ST (Deluxe), and Essence STX. + Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, DSX, + Essence ST (Deluxe), and Essence STX (II). Support for the HDAV1.3 (Deluxe) and HDAV1.3 Slim is experimental; for the Xense, missing. diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 9f10c9e0df5e..631aaa4046ad 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1754,9 +1754,6 @@ static struct snd_kcontrol_new snd_echo_vumeters_switch = { static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct echoaudio *chip; - - chip = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 96; uinfo->value.integer.min = ECHOGAIN_MINOUT; @@ -1798,9 +1795,6 @@ static struct snd_kcontrol_new snd_echo_vumeters = { static int snd_echo_channels_info_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct echoaudio *chip; - - chip = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 6; uinfo->value.integer.min = 0; diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c new file mode 100644 index 000000000000..9c22f95838ef --- /dev/null +++ b/sound/pci/hda/dell_wmi_helper.c @@ -0,0 +1,76 @@ +/* Helper functions for Dell Mic Mute LED control; + * to be included from codec driver + */ + +#if IS_ENABLED(CONFIG_LEDS_DELL_NETBOOKS) +#include <linux/dell-led.h> + +static int dell_led_value; +static int (*dell_led_set_func)(int, int); +static void (*dell_old_cap_hook)(struct hda_codec *, + struct snd_kcontrol *, + struct snd_ctl_elem_value *); + +static void update_dell_wmi_micmute_led(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + if (dell_old_cap_hook) + dell_old_cap_hook(codec, kcontrol, ucontrol); + + if (!ucontrol || !dell_led_set_func) + return; + if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) { + /* TODO: How do I verify if it's a mono or stereo here? */ + int val = (ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1]) ? 0 : 1; + if (val == dell_led_value) + return; + dell_led_value = val; + if (dell_led_set_func) + dell_led_set_func(DELL_LED_MICMUTE, dell_led_value); + } +} + + +static void alc_fixup_dell_wmi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + bool removefunc = false; + + if (action == HDA_FIXUP_ACT_PROBE) { + if (!dell_led_set_func) + dell_led_set_func = symbol_request(dell_app_wmi_led_set); + if (!dell_led_set_func) { + codec_warn(codec, "Failed to find dell wmi symbol dell_app_wmi_led_set\n"); + return; + } + + removefunc = true; + if (dell_led_set_func(DELL_LED_MICMUTE, false) >= 0) { + dell_led_value = 0; + if (spec->gen.num_adc_nids > 1) + codec_dbg(codec, "Skipping micmute LED control due to several ADCs"); + else { + dell_old_cap_hook = spec->gen.cap_sync_hook; + spec->gen.cap_sync_hook = update_dell_wmi_micmute_led; + removefunc = false; + } + } + + } + + if (dell_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) { + symbol_put(dell_app_wmi_led_set); + dell_led_set_func = NULL; + dell_old_cap_hook = NULL; + } +} + +#else /* CONFIG_LEDS_DELL_NETBOOKS */ +static void alc_fixup_dell_wmi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ +} + +#endif /* CONFIG_LEDS_DELL_NETBOOKS */ diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index dabe41975a9d..51dea49aadd4 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -17,8 +17,6 @@ #include "hda_local.h" #include "hda_auto_parser.h" -#define SFX "hda_codec: " - /* * Helper for automatic pin configuration */ @@ -856,7 +854,7 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, { const struct snd_hda_pin_quirk *pq; - if (codec->fixup_forced) + if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) return; for (pq = pin_quirk; pq->subvendor; pq++) { @@ -882,14 +880,17 @@ void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_fixup *fixlist) { const struct snd_pci_quirk *q; - int id = -1; + int id = HDA_FIXUP_ID_NOT_SET; const char *name = NULL; + if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) + return; + /* when model=nofixup is given, don't pick up any fixups */ if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { codec->fixup_list = NULL; - codec->fixup_id = -1; - codec->fixup_forced = 1; + codec->fixup_name = NULL; + codec->fixup_id = HDA_FIXUP_ID_NO_FIXUP; return; } @@ -899,13 +900,12 @@ void snd_hda_pick_fixup(struct hda_codec *codec, codec->fixup_id = models->id; codec->fixup_name = models->name; codec->fixup_list = fixlist; - codec->fixup_forced = 1; return; } models++; } } - if (id < 0 && quirk) { + if (quirk) { q = snd_pci_quirk_lookup(codec->bus->pci, quirk); if (q) { id = q->value; @@ -929,7 +929,6 @@ void snd_hda_pick_fixup(struct hda_codec *codec, } } - codec->fixup_forced = 0; codec->fixup_id = id; if (id >= 0) { codec->fixup_list = fixlist; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4c20277a6835..ec6a7d0d1886 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1476,6 +1476,7 @@ int snd_hda_codec_new(struct hda_bus *bus, INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); codec->depop_delay = -1; + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; #ifdef CONFIG_PM spin_lock_init(&codec->power_lock); @@ -2727,7 +2728,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) return 0; } -typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *); +typedef int (*map_slave_func_t)(struct hda_codec *, void *, struct snd_kcontrol *); /* apply the function to all matching slave ctls in the mixer list */ static int map_slaves(struct hda_codec *codec, const char * const *slaves, @@ -2751,7 +2752,7 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves, name = tmpname; } if (!strcmp(sctl->id.name, name)) { - err = func(data, sctl); + err = func(codec, data, sctl); if (err) return err; break; @@ -2761,13 +2762,15 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves, return 0; } -static int check_slave_present(void *data, struct snd_kcontrol *sctl) +static int check_slave_present(struct hda_codec *codec, + void *data, struct snd_kcontrol *sctl) { return 1; } /* guess the value corresponding to 0dB */ -static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check) +static int get_kctl_0dB_offset(struct hda_codec *codec, + struct snd_kcontrol *kctl, int *step_to_check) { int _tlv[4]; const int *tlv = NULL; @@ -2788,7 +2791,7 @@ static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check) if (!step) return -1; if (*step_to_check && *step_to_check != step) { - snd_printk(KERN_ERR "hda_codec: Mismatching dB step for vmaster slave (%d!=%d)\n", + codec_err(codec, "Mismatching dB step for vmaster slave (%d!=%d)\n", - *step_to_check, step); return -1; } @@ -2813,20 +2816,28 @@ static int put_kctl_with_value(struct snd_kcontrol *kctl, int val) } /* initialize the slave volume with 0dB */ -static int init_slave_0dB(void *data, struct snd_kcontrol *slave) +static int init_slave_0dB(struct hda_codec *codec, + void *data, struct snd_kcontrol *slave) { - int offset = get_kctl_0dB_offset(slave, data); + int offset = get_kctl_0dB_offset(codec, slave, data); if (offset > 0) put_kctl_with_value(slave, offset); return 0; } /* unmute the slave */ -static int init_slave_unmute(void *data, struct snd_kcontrol *slave) +static int init_slave_unmute(struct hda_codec *codec, + void *data, struct snd_kcontrol *slave) { return put_kctl_with_value(slave, 1); } +static int add_slave(struct hda_codec *codec, + void *data, struct snd_kcontrol *slave) +{ + return snd_ctl_add_slave(data, slave); +} + /** * snd_hda_add_vmaster - create a virtual master control and add slaves * @codec: HD-audio codec @@ -2869,8 +2880,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, if (err < 0) return err; - err = map_slaves(codec, slaves, suffix, - (map_slave_func_t)snd_ctl_add_slave, kctl); + err = map_slaves(codec, slaves, suffix, add_slave, kctl); if (err < 0) return err; @@ -4280,6 +4290,7 @@ static struct hda_rate_tbl rate_bits[] = { /** * snd_hda_calc_stream_format - calculate format bitset + * @codec: HD-audio codec * @rate: the sample rate * @channels: the number of channels * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) @@ -4289,7 +4300,8 @@ static struct hda_rate_tbl rate_bits[] = { * * Return zero if invalid. */ -unsigned int snd_hda_calc_stream_format(unsigned int rate, +unsigned int snd_hda_calc_stream_format(struct hda_codec *codec, + unsigned int rate, unsigned int channels, unsigned int format, unsigned int maxbps, @@ -4304,12 +4316,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, break; } if (!rate_bits[i].hz) { - snd_printdd("invalid rate %d\n", rate); + codec_dbg(codec, "invalid rate %d\n", rate); return 0; } if (channels == 0 || channels > 8) { - snd_printdd("invalid channels %d\n", channels); + codec_dbg(codec, "invalid channels %d\n", channels); return 0; } val |= channels - 1; @@ -4332,7 +4344,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, val |= AC_FMT_BITS_20; break; default: - snd_printdd("invalid format width %d\n", + codec_dbg(codec, "invalid format width %d\n", snd_pcm_format_width(format)); return 0; } @@ -5670,12 +5682,13 @@ EXPORT_SYMBOL_GPL(_snd_hda_set_pin_ctl); * suffix is appended to the label. This label index number is stored * to type_idx when non-NULL pointer is given. */ -int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, +int snd_hda_add_imux_item(struct hda_codec *codec, + struct hda_input_mux *imux, const char *label, int index, int *type_idx) { int i, label_idx = 0; if (imux->num_items >= HDA_MAX_NUM_INPUTS) { - snd_printd(KERN_ERR "hda_codec: Too many imux items!\n"); + codec_err(codec, "hda_codec: Too many imux items!\n"); return -EINVAL; } for (i = 0; i < imux->num_items; i++) { diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5825aa17d8e3..bbc5a1392c75 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -402,7 +402,6 @@ struct hda_codec { /* fix-up list */ int fixup_id; - unsigned int fixup_forced:1; /* fixup explicitly set by user */ const struct hda_fixup *fixup_list; const char *fixup_name; @@ -538,7 +537,8 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, int do_now); #define snd_hda_codec_cleanup_stream(codec, nid) \ __snd_hda_codec_cleanup_stream(codec, nid, 0) -unsigned int snd_hda_calc_stream_format(unsigned int rate, +unsigned int snd_hda_calc_stream_format(struct hda_codec *codec, + unsigned int rate, unsigned int channels, unsigned int format, unsigned int maxbps, diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 6df04d91c93c..8337645aa7a5 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/slab.h> +#include <linux/reboot.h> #include <sound/core.h> #include <sound/initval.h> #include "hda_priv.h" @@ -152,11 +153,11 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) upper_32_bits(azx_dev->bdl.addr)); /* enable the position buffer */ - if (chip->position_fix[0] != POS_FIX_LPIB || - chip->position_fix[1] != POS_FIX_LPIB) { - if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + if (chip->get_position[0] != azx_get_pos_lpib || + chip->get_position[1] != azx_get_pos_lpib) { + if (!(azx_readl(chip, DPLBASE) & AZX_DPLBASE_ENABLE)) azx_writel(chip, DPLBASE, - (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); + (u32)chip->posbuf.addr | AZX_DPLBASE_ENABLE); } /* set the interrupt enable bits in the descriptor control register */ @@ -482,7 +483,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) } azx_stream_reset(chip, azx_dev); - format_val = snd_hda_calc_stream_format(runtime->rate, + format_val = snd_hda_calc_stream_format(apcm->codec, + runtime->rate, runtime->channels, runtime->format, hinfo->maxbps, @@ -673,125 +675,40 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -/* get the current DMA position with correction on VIA chips */ -static unsigned int azx_via_get_position(struct azx *chip, - struct azx_dev *azx_dev) +unsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev) { - unsigned int link_pos, mini_pos, bound_pos; - unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; - unsigned int fifo_size; - - link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* Playback, no problem using link position */ - return link_pos; - } - - /* Capture */ - /* For new chipset, - * use mod to get the DMA position just like old chipset - */ - mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); - mod_dma_pos %= azx_dev->period_bytes; - - /* azx_dev->fifo_size can't get FIFO size of in stream. - * Get from base address + offset. - */ - fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); - - if (azx_dev->insufficient) { - /* Link position never gather than FIFO size */ - if (link_pos <= fifo_size) - return 0; - - azx_dev->insufficient = 0; - } - - if (link_pos <= fifo_size) - mini_pos = azx_dev->bufsize + link_pos - fifo_size; - else - mini_pos = link_pos - fifo_size; - - /* Find nearest previous boudary */ - mod_mini_pos = mini_pos % azx_dev->period_bytes; - mod_link_pos = link_pos % azx_dev->period_bytes; - if (mod_link_pos >= fifo_size) - bound_pos = link_pos - mod_link_pos; - else if (mod_dma_pos >= mod_mini_pos) - bound_pos = mini_pos - mod_mini_pos; - else { - bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; - if (bound_pos >= azx_dev->bufsize) - bound_pos = 0; - } + return azx_sd_readl(chip, azx_dev, SD_LPIB); +} +EXPORT_SYMBOL_GPL(azx_get_pos_lpib); - /* Calculate real DMA position we want */ - return bound_pos + mod_dma_pos; +unsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev) +{ + return le32_to_cpu(*azx_dev->posbuf); } +EXPORT_SYMBOL_GPL(azx_get_pos_posbuf); unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev, - bool with_check) + struct azx_dev *azx_dev) { struct snd_pcm_substream *substream = azx_dev->substream; - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); unsigned int pos; int stream = substream->stream; - struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; int delay = 0; - switch (chip->position_fix[stream]) { - case POS_FIX_LPIB: - /* read LPIB */ - pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - break; - case POS_FIX_VIACOMBO: - pos = azx_via_get_position(chip, azx_dev); - break; - default: - /* use the position buffer */ - pos = le32_to_cpu(*azx_dev->posbuf); - if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) { - if (!pos || pos == (u32)-1) { - dev_info(chip->card->dev, - "Invalid position buffer, using LPIB read method instead.\n"); - chip->position_fix[stream] = POS_FIX_LPIB; - pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - } else - chip->position_fix[stream] = POS_FIX_POSBUF; - } - break; - } + if (chip->get_position[stream]) + pos = chip->get_position[stream](chip, azx_dev); + else /* use the position buffer as default */ + pos = azx_get_pos_posbuf(chip, azx_dev); if (pos >= azx_dev->bufsize) pos = 0; - /* calculate runtime delay from LPIB */ - if (substream->runtime && - chip->position_fix[stream] == POS_FIX_POSBUF && - (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { - unsigned int lpib_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - delay = pos - lpib_pos; - else - delay = lpib_pos - pos; - if (delay < 0) { - if (delay >= azx_dev->delay_negative_threshold) - delay = 0; - else - delay += azx_dev->bufsize; - } - if (delay >= azx_dev->period_bytes) { - dev_info(chip->card->dev, - "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", - delay, azx_dev->period_bytes); - delay = 0; - chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; - } - delay = bytes_to_frames(substream->runtime, delay); - } - if (substream->runtime) { + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; + + if (chip->get_delay[stream]) + delay += chip->get_delay[stream](chip, azx_dev, pos); if (hinfo->ops.get_delay) delay += hinfo->ops.get_delay(hinfo, apcm->codec, substream); @@ -809,7 +726,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); return bytes_to_frames(substream->runtime, - azx_get_position(chip, azx_dev, false)); + azx_get_position(chip, azx_dev)); } static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, @@ -1059,10 +976,10 @@ static void azx_init_cmd_io(struct azx *chip) azx_writew(chip, CORBWP, 0); /* reset the corb hw read pointer */ - azx_writew(chip, CORBRP, ICH6_CORBRP_RST); + azx_writew(chip, CORBRP, AZX_CORBRP_RST); if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) { for (timeout = 1000; timeout > 0; timeout--) { - if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST) + if ((azx_readw(chip, CORBRP) & AZX_CORBRP_RST) == AZX_CORBRP_RST) break; udelay(1); } @@ -1082,7 +999,7 @@ static void azx_init_cmd_io(struct azx *chip) } /* enable corb dma */ - azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN); + azx_writeb(chip, CORBCTL, AZX_CORBCTL_RUN); /* RIRB set up */ chip->rirb.addr = chip->rb.addr + 2048; @@ -1095,14 +1012,14 @@ static void azx_init_cmd_io(struct azx *chip) /* set the rirb size to 256 entries (ULI requires explicitly) */ azx_writeb(chip, RIRBSIZE, 0x02); /* reset the rirb hw write pointer */ - azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); + azx_writew(chip, RIRBWP, AZX_RIRBWP_RST); /* set N=1, get RIRB response interrupt for new entry */ if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) azx_writew(chip, RINTCNT, 0xc0); else azx_writew(chip, RINTCNT, 1); /* enable rirb dma and response irq */ - azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); + azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN); spin_unlock_irq(&chip->reg_lock); } EXPORT_SYMBOL_GPL(azx_init_cmd_io); @@ -1146,7 +1063,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) return -EIO; } wp++; - wp %= ICH6_MAX_CORB_ENTRIES; + wp %= AZX_MAX_CORB_ENTRIES; rp = azx_readw(chip, CORBRP); if (wp == rp) { @@ -1164,7 +1081,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) return 0; } -#define ICH6_RIRB_EX_UNSOL_EV (1<<4) +#define AZX_RIRB_EX_UNSOL_EV (1<<4) /* retrieve RIRB entry - called from interrupt handler */ static void azx_update_rirb(struct azx *chip) @@ -1185,7 +1102,7 @@ static void azx_update_rirb(struct azx *chip) while (chip->rirb.rp != wp) { chip->rirb.rp++; - chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES; + chip->rirb.rp %= AZX_MAX_RIRB_ENTRIES; rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); @@ -1196,8 +1113,7 @@ static void azx_update_rirb(struct azx *chip) res, res_ex, chip->rirb.rp, wp); snd_BUG(); - } - else if (res_ex & ICH6_RIRB_EX_UNSOL_EV) + } else if (res_ex & AZX_RIRB_EX_UNSOL_EV) snd_hda_queue_unsol_event(chip->bus, res, res_ex); else if (chip->rirb.cmds[addr]) { chip->rirb.res[addr] = res; @@ -1305,7 +1221,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, /* release CORB/RIRB */ azx_free_cmd_io(chip); /* disable unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL); + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_UNSOL); return -1; } @@ -1326,7 +1242,7 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) while (timeout--) { /* check IRV busy bit */ - if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { + if (azx_readw(chip, IRS) & AZX_IRS_VALID) { /* reuse rirb.res as the response return value */ chip->rirb.res[addr] = azx_readl(chip, IR); return 0; @@ -1350,13 +1266,13 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) bus->rirb_error = 0; while (timeout--) { /* check ICB busy bit */ - if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { + if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) { /* Clear IRV valid bit */ azx_writew(chip, IRS, azx_readw(chip, IRS) | - ICH6_IRS_VALID); + AZX_IRS_VALID); azx_writel(chip, IC, val); azx_writew(chip, IRS, azx_readw(chip, IRS) | - ICH6_IRS_BUSY); + AZX_IRS_BUSY); return azx_single_wait_for_response(chip, addr); } udelay(1); @@ -1585,10 +1501,10 @@ void azx_enter_link_reset(struct azx *chip) unsigned long timeout; /* reset controller */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); - while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) && + while ((azx_readb(chip, GCTL) & AZX_GCTL_RESET) && time_before(jiffies, timeout)) usleep_range(500, 1000); } @@ -1599,7 +1515,7 @@ static void azx_exit_link_reset(struct azx *chip) { unsigned long timeout; - azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); + azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | AZX_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); while (!azx_readb(chip, GCTL) && @@ -1640,7 +1556,7 @@ static int azx_reset(struct azx *chip, bool full_reset) /* Accept unsolicited responses */ if (!chip->single_cmd) azx_writel(chip, GCTL, azx_readl(chip, GCTL) | - ICH6_GCTL_UNSOL); + AZX_GCTL_UNSOL); /* detect codecs */ if (!chip->codec_mask) { @@ -1657,7 +1573,7 @@ static void azx_int_enable(struct azx *chip) { /* enable controller CIE and GIE */ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) | - ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN); + AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); } /* disable interrupts */ @@ -1678,7 +1594,7 @@ static void azx_int_disable(struct azx *chip) /* disable controller CIE and GIE */ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) & - ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN)); + ~(AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN)); } /* clear interrupts */ @@ -1699,7 +1615,7 @@ static void azx_int_clear(struct azx *chip) azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); /* clear int status */ - azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM); + azx_writel(chip, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM); } /* @@ -2031,5 +1947,30 @@ int azx_init_stream(struct azx *chip) } EXPORT_SYMBOL_GPL(azx_init_stream); +/* + * reboot notifier for hang-up problem at power-down + */ +static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) +{ + struct azx *chip = container_of(nb, struct azx, reboot_notifier); + snd_hda_bus_reboot_notify(chip->bus); + azx_stop_chip(chip); + return NOTIFY_OK; +} + +void azx_notifier_register(struct azx *chip) +{ + chip->reboot_notifier.notifier_call = azx_halt; + register_reboot_notifier(&chip->reboot_notifier); +} +EXPORT_SYMBOL_GPL(azx_notifier_register); + +void azx_notifier_unregister(struct azx *chip) +{ + if (chip->reboot_notifier.notifier_call) + unregister_reboot_notifier(&chip->reboot_notifier); +} +EXPORT_SYMBOL_GPL(azx_notifier_unregister); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Common HDA driver funcitons"); diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index baf0e77330af..c90d10fd4d8f 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -25,9 +25,9 @@ static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream) { return substream->runtime->private_data; } -unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev, - bool with_check); +unsigned int azx_get_position(struct azx *chip, struct azx_dev *azx_dev); +unsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev); +unsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev); /* Stream control. */ void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev); @@ -50,4 +50,7 @@ int azx_codec_configure(struct azx *chip); int azx_mixer_create(struct azx *chip); int azx_init_stream(struct azx *chip); +void azx_notifier_register(struct azx *chip); +void azx_notifier_unregister(struct azx *chip); + #endif /* __SOUND_HDA_CONTROLLER_H */ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 46690a7f48f6..e1cd34d9011d 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -167,7 +167,8 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ }) -static void hdmi_update_short_audio_desc(struct cea_sad *a, +static void hdmi_update_short_audio_desc(struct hda_codec *codec, + struct cea_sad *a, const unsigned char *buf) { int i; @@ -188,8 +189,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, a->format = GRAB_BITS(buf, 0, 3, 4); switch (a->format) { case AUDIO_CODING_TYPE_REF_STREAM_HEADER: - snd_printd(KERN_INFO - "HDMI: audio coding type 0 not expected\n"); + codec_info(codec, "HDMI: audio coding type 0 not expected\n"); break; case AUDIO_CODING_TYPE_LPCM: @@ -233,9 +233,9 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, a->format = GRAB_BITS(buf, 2, 3, 5); if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { - snd_printd(KERN_INFO - "HDMI: audio coding xtype %d not expected\n", - a->format); + codec_info(codec, + "HDMI: audio coding xtype %d not expected\n", + a->format); a->format = 0; } else a->format += AUDIO_CODING_TYPE_HE_AAC - @@ -247,7 +247,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, /* * Be careful, ELD buf could be totally rubbish! */ -int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, +int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, const unsigned char *buf, int size) { int mnl; @@ -256,8 +256,7 @@ int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, e->eld_ver = GRAB_BITS(buf, 0, 3, 5); if (e->eld_ver != ELD_VER_CEA_861D && e->eld_ver != ELD_VER_PARTIAL) { - snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", - e->eld_ver); + codec_info(codec, "HDMI: Unknown ELD version %d\n", e->eld_ver); goto out_fail; } @@ -280,20 +279,20 @@ int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, e->product_id = get_unaligned_le16(buf + 18); if (mnl > ELD_MAX_MNL) { - snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl); + codec_info(codec, "HDMI: MNL is reserved value %d\n", mnl); goto out_fail; } else if (ELD_FIXED_BYTES + mnl > size) { - snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl); + codec_info(codec, "HDMI: out of range MNL %d\n", mnl); goto out_fail; } else strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); for (i = 0; i < e->sad_count; i++) { if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); + codec_info(codec, "HDMI: out of range SAD %d\n", i); goto out_fail; } - hdmi_update_short_audio_desc(e->sad + i, + hdmi_update_short_audio_desc(codec, e->sad + i, buf + ELD_FIXED_BYTES + mnl + 3 * i); } @@ -394,7 +393,8 @@ static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) #define SND_PRINT_RATES_ADVISED_BUFSIZE 80 -static void hdmi_show_short_audio_desc(struct cea_sad *a) +static void hdmi_show_short_audio_desc(struct hda_codec *codec, + struct cea_sad *a) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; @@ -412,12 +412,10 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) else buf2[0] = '\0'; - _snd_printd(SND_PR_VERBOSE, "HDMI: supports coding type %s:" - " channels = %d, rates =%s%s\n", - cea_audio_coding_type_names[a->format], - a->channels, - buf, - buf2); + codec_dbg(codec, + "HDMI: supports coding type %s: channels = %d, rates =%s%s\n", + cea_audio_coding_type_names[a->format], + a->channels, buf, buf2); } void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) @@ -432,22 +430,22 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -void snd_hdmi_show_eld(struct parsed_hdmi_eld *e) +void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e) { int i; - _snd_printd(SND_PR_VERBOSE, "HDMI: detected monitor %s at connection type %s\n", + codec_dbg(codec, "HDMI: detected monitor %s at connection type %s\n", e->monitor_name, eld_connection_type_names[e->conn_type]); if (e->spk_alloc) { char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - _snd_printd(SND_PR_VERBOSE, "HDMI: available speakers:%s\n", buf); + codec_dbg(codec, "HDMI: available speakers:%s\n", buf); } for (i = 0; i < e->sad_count; i++) - hdmi_show_short_audio_desc(e->sad + i); + hdmi_show_short_audio_desc(codec, e->sad + i); } #ifdef CONFIG_PROC_FS diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 589e47c5aeb3..b956449ddada 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -350,16 +350,16 @@ static void print_nid_path(struct hda_codec *codec, const char *pfx, struct nid_path *path) { char buf[40]; + char *pos = buf; int i; + *pos = 0; + for (i = 0; i < path->depth; i++) + pos += scnprintf(pos, sizeof(buf) - (pos - buf), "%s%02x", + pos != buf ? ":" : "", + path->path[i]); - buf[0] = 0; - for (i = 0; i < path->depth; i++) { - char tmp[4]; - sprintf(tmp, ":%02x", path->path[i]); - strlcat(buf, tmp, sizeof(buf)); - } - codec_dbg(codec, "%s path: depth=%d %s\n", pfx, path->depth, buf); + codec_dbg(codec, "%s path: depth=%d '%s'\n", pfx, path->depth, buf); } /* called recursively */ @@ -1700,9 +1700,11 @@ static int fill_and_eval_dacs(struct hda_codec *codec, #define DEBUG_BADNESS #ifdef DEBUG_BADNESS -#define debug_badness(fmt, args...) codec_dbg(codec, fmt, ##args) +#define debug_badness(fmt, ...) \ + codec_dbg(codec, fmt, ##__VA_ARGS__) #else -#define debug_badness(...) +#define debug_badness(fmt, ...) \ + do { if (0) codec_dbg(codec, fmt, ##__VA_ARGS__); } while (0) #endif #ifdef DEBUG_BADNESS @@ -3054,7 +3056,7 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, if (spec->hp_mic_pin == pin) spec->hp_mic_mux_idx = imux->num_items; spec->imux_pins[imux->num_items] = pin; - snd_hda_add_imux_item(imux, label, cfg_idx, NULL); + snd_hda_add_imux_item(codec, imux, label, cfg_idx, NULL); imux_added = true; if (spec->dyn_adc_switch) spec->dyn_adc_idx[imux_idx] = c; diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 8b4940ba33d6..d4d0375ac181 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -28,8 +28,8 @@ * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N * The values will be lost when the display power well is disabled. */ -#define ICH6_REG_EM4 0x100c -#define ICH6_REG_EM5 0x1010 +#define AZX_REG_EM4 0x100c +#define AZX_REG_EM5 0x1010 static int (*get_power)(void); static int (*put_power)(void); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 83cd19017cf3..5db1948699d8 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -44,7 +44,6 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/mutex.h> -#include <linux/reboot.h> #include <linux/io.h> #include <linux/pm_runtime.h> #include <linux/clocksource.h> @@ -66,6 +65,52 @@ #include "hda_priv.h" #include "hda_i915.h" +/* position fix mode */ +enum { + POS_FIX_AUTO, + POS_FIX_LPIB, + POS_FIX_POSBUF, + POS_FIX_VIACOMBO, + POS_FIX_COMBO, +}; + +/* Defines for ATI HD Audio support in SB450 south bridge */ +#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 +#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 + +/* Defines for Nvidia HDA support */ +#define NVIDIA_HDA_TRANSREG_ADDR 0x4e +#define NVIDIA_HDA_ENABLE_COHBITS 0x0f +#define NVIDIA_HDA_ISTRM_COH 0x4d +#define NVIDIA_HDA_OSTRM_COH 0x4c +#define NVIDIA_HDA_ENABLE_COHBIT 0x01 + +/* Defines for Intel SCH HDA snoop control */ +#define INTEL_SCH_HDA_DEVC 0x78 +#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) + +/* Define IN stream 0 FIFO size offset in VIA controller */ +#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 +/* Define VIA HD Audio Device ID*/ +#define VIA_HDAC_DEVICE_ID 0x3288 + +/* max number of SDs */ +/* ICH, ATI and VIA have 4 playback and 4 capture */ +#define ICH6_NUM_CAPTURE 4 +#define ICH6_NUM_PLAYBACK 4 + +/* ULI has 6 playback and 5 capture */ +#define ULI_NUM_CAPTURE 5 +#define ULI_NUM_PLAYBACK 6 + +/* ATI HDMI may have up to 8 playbacks and 0 capture */ +#define ATIHDMI_NUM_CAPTURE 0 +#define ATIHDMI_NUM_PLAYBACK 8 + +/* TERA has 4 playback and 3 capture */ +#define TERA_NUM_CAPTURE 3 +#define TERA_NUM_PLAYBACK 4 + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; @@ -290,8 +335,28 @@ static char *driver_short_names[] = { struct hda_intel { struct azx chip; -}; + /* for pending irqs */ + struct work_struct irq_pending_work; + + /* sync probing */ + struct completion probe_wait; + struct work_struct probe_work; + + /* card list (for power_save trigger) */ + struct list_head list; + + /* extra flags */ + unsigned int irq_pending_warned:1; + + /* VGA-switcheroo setup */ + unsigned int use_vga_switcheroo:1; + unsigned int vga_switcheroo_registered:1; + unsigned int init_failed:1; /* delayed init failed */ + + /* secondary power domain for hdmi audio under vga device */ + struct dev_pm_domain hdmi_pm_domain; +}; #ifdef CONFIG_X86 static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) @@ -373,7 +438,7 @@ static void azx_init_pci(struct azx *chip) */ if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) { dev_dbg(chip->card->dev, "Clearing TCSEL\n"); - update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + update_pci_byte(chip->pci, AZX_PCIREG_TCSEL, 0x07, 0); } /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio, @@ -421,11 +486,44 @@ static void azx_init_pci(struct azx *chip) } } +/* calculate runtime delay from LPIB */ +static int azx_get_delay_from_lpib(struct azx *chip, struct azx_dev *azx_dev, + unsigned int pos) +{ + struct snd_pcm_substream *substream = azx_dev->substream; + int stream = substream->stream; + unsigned int lpib_pos = azx_get_pos_lpib(chip, azx_dev); + int delay; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + delay = pos - lpib_pos; + else + delay = lpib_pos - pos; + if (delay < 0) { + if (delay >= azx_dev->delay_negative_threshold) + delay = 0; + else + delay += azx_dev->bufsize; + } + + if (delay >= azx_dev->period_bytes) { + dev_info(chip->card->dev, + "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", + delay, azx_dev->period_bytes); + delay = 0; + chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; + chip->get_delay[stream] = NULL; + } + + return bytes_to_frames(substream->runtime, delay); +} + static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); /* called from IRQ */ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); int ok; ok = azx_position_ok(chip, azx_dev); @@ -435,7 +533,7 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) } else if (ok == 0 && chip->bus && chip->bus->workq) { /* bogus IRQ, process it later */ azx_dev->irq_pending = 1; - queue_work(chip->bus->workq, &chip->irq_pending_work); + queue_work(chip->bus->workq, &hda->irq_pending_work); } return 0; } @@ -451,6 +549,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) */ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) { + struct snd_pcm_substream *substream = azx_dev->substream; + int stream = substream->stream; u32 wallclk; unsigned int pos; @@ -458,7 +558,25 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) if (wallclk < (azx_dev->period_wallclk * 2) / 3) return -1; /* bogus (too early) interrupt */ - pos = azx_get_position(chip, azx_dev, true); + if (chip->get_position[stream]) + pos = chip->get_position[stream](chip, azx_dev); + else { /* use the position buffer as default */ + pos = azx_get_pos_posbuf(chip, azx_dev); + if (!pos || pos == (u32)-1) { + dev_info(chip->card->dev, + "Invalid position buffer, using LPIB read method instead.\n"); + chip->get_position[stream] = azx_get_pos_lpib; + pos = azx_get_pos_lpib(chip, azx_dev); + chip->get_delay[stream] = NULL; + } else { + chip->get_position[stream] = azx_get_pos_posbuf; + if (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY) + chip->get_delay[stream] = azx_get_delay_from_lpib; + } + } + + if (pos >= azx_dev->bufsize) + pos = 0; if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) @@ -476,14 +594,15 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) */ static void azx_irq_pending_work(struct work_struct *work) { - struct azx *chip = container_of(work, struct azx, irq_pending_work); + struct hda_intel *hda = container_of(work, struct hda_intel, irq_pending_work); + struct azx *chip = &hda->chip; int i, pending, ok; - if (!chip->irq_pending_warned) { + if (!hda->irq_pending_warned) { dev_info(chip->card->dev, "IRQ timing workaround is activated for card #%d. Suggest a bigger bdl_pos_adj.\n", chip->card->number); - chip->irq_pending_warned = 1; + hda->irq_pending_warned = 1; } for (;;) { @@ -541,27 +660,86 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) return 0; } +/* get the current DMA position with correction on VIA chips */ +static unsigned int azx_via_get_position(struct azx *chip, + struct azx_dev *azx_dev) +{ + unsigned int link_pos, mini_pos, bound_pos; + unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; + unsigned int fifo_size; + + link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); + if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Playback, no problem using link position */ + return link_pos; + } + + /* Capture */ + /* For new chipset, + * use mod to get the DMA position just like old chipset + */ + mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); + mod_dma_pos %= azx_dev->period_bytes; + + /* azx_dev->fifo_size can't get FIFO size of in stream. + * Get from base address + offset. + */ + fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); + + if (azx_dev->insufficient) { + /* Link position never gather than FIFO size */ + if (link_pos <= fifo_size) + return 0; + + azx_dev->insufficient = 0; + } + + if (link_pos <= fifo_size) + mini_pos = azx_dev->bufsize + link_pos - fifo_size; + else + mini_pos = link_pos - fifo_size; + + /* Find nearest previous boudary */ + mod_mini_pos = mini_pos % azx_dev->period_bytes; + mod_link_pos = link_pos % azx_dev->period_bytes; + if (mod_link_pos >= fifo_size) + bound_pos = link_pos - mod_link_pos; + else if (mod_dma_pos >= mod_mini_pos) + bound_pos = mini_pos - mod_mini_pos; + else { + bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; + if (bound_pos >= azx_dev->bufsize) + bound_pos = 0; + } + + /* Calculate real DMA position we want */ + return bound_pos + mod_dma_pos; +} + #ifdef CONFIG_PM static DEFINE_MUTEX(card_list_lock); static LIST_HEAD(card_list); static void azx_add_card_list(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); mutex_lock(&card_list_lock); - list_add(&chip->list, &card_list); + list_add(&hda->list, &card_list); mutex_unlock(&card_list_lock); } static void azx_del_card_list(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); mutex_lock(&card_list_lock); - list_del_init(&chip->list); + list_del_init(&hda->list); mutex_unlock(&card_list_lock); } /* trigger power-save check at writing parameter */ static int param_set_xint(const char *val, const struct kernel_param *kp) { + struct hda_intel *hda; struct azx *chip; struct hda_codec *c; int prev = power_save; @@ -571,7 +749,8 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) return ret; mutex_lock(&card_list_lock); - list_for_each_entry(chip, &card_list, list) { + list_for_each_entry(hda, &card_list, list) { + chip = &hda->chip; if (!chip->bus || chip->disabled) continue; list_for_each_entry(c, &chip->bus->codec_list, list) @@ -593,10 +772,16 @@ static int azx_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; struct azx_pcm *p; - if (chip->disabled || chip->init_failed) + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); @@ -626,9 +811,15 @@ static int azx_resume(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; - if (chip->disabled || chip->init_failed) + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { @@ -663,9 +854,15 @@ static int azx_resume(struct device *dev) static int azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; + + if (!card) + return 0; - if (chip->disabled || chip->init_failed) + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) @@ -687,12 +884,18 @@ static int azx_runtime_suspend(struct device *dev) static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; struct hda_bus *bus; struct hda_codec *codec; int status; - if (chip->disabled || chip->init_failed) + if (!card) + return 0; + + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) @@ -727,9 +930,15 @@ static int azx_runtime_resume(struct device *dev) static int azx_runtime_idle(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; + struct azx *chip; + struct hda_intel *hda; + + if (!card) + return 0; - if (chip->disabled || chip->init_failed) + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + if (chip->disabled || hda->init_failed) return 0; if (!power_save_controller || @@ -753,29 +962,6 @@ static const struct dev_pm_ops azx_pm = { #endif /* CONFIG_PM */ -/* - * reboot notifier for hang-up problem at power-down - */ -static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) -{ - struct azx *chip = container_of(nb, struct azx, reboot_notifier); - snd_hda_bus_reboot_notify(chip->bus); - azx_stop_chip(chip); - return NOTIFY_OK; -} - -static void azx_notifier_register(struct azx *chip) -{ - chip->reboot_notifier.notifier_call = azx_halt; - register_reboot_notifier(&chip->reboot_notifier); -} - -static void azx_notifier_unregister(struct azx *chip) -{ - if (chip->reboot_notifier.notifier_call) - unregister_reboot_notifier(&chip->reboot_notifier); -} - static int azx_probe_continue(struct azx *chip); #ifdef SUPPORT_VGA_SWITCHEROO @@ -786,10 +972,11 @@ static void azx_vs_set_state(struct pci_dev *pci, { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); bool disabled; - wait_for_completion(&chip->probe_wait); - if (chip->init_failed) + wait_for_completion(&hda->probe_wait); + if (hda->init_failed) return; disabled = (state == VGA_SWITCHEROO_OFF); @@ -803,7 +990,7 @@ static void azx_vs_set_state(struct pci_dev *pci, "Start delayed initialization\n"); if (azx_probe_continue(chip) < 0) { dev_err(chip->card->dev, "initialization error\n"); - chip->init_failed = true; + hda->init_failed = true; } } } else { @@ -833,9 +1020,10 @@ static bool azx_vs_can_switch(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - wait_for_completion(&chip->probe_wait); - if (chip->init_failed) + wait_for_completion(&hda->probe_wait); + if (hda->init_failed) return false; if (chip->disabled || !chip->bus) return true; @@ -847,11 +1035,12 @@ static bool azx_vs_can_switch(struct pci_dev *pci) static void init_vga_switcheroo(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); struct pci_dev *p = get_bound_vga(chip->pci); if (p) { dev_info(chip->card->dev, "Handle VGA-switcheroo audio client\n"); - chip->use_vga_switcheroo = 1; + hda->use_vga_switcheroo = 1; pci_dev_put(p); } } @@ -863,9 +1052,10 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = { static int register_vga_switcheroo(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); int err; - if (!chip->use_vga_switcheroo) + if (!hda->use_vga_switcheroo) return 0; /* FIXME: currently only handling DIS controller * is there any machine with two switchable HDMI audio controllers? @@ -875,11 +1065,11 @@ static int register_vga_switcheroo(struct azx *chip) chip->bus != NULL); if (err < 0) return err; - chip->vga_switcheroo_registered = 1; + hda->vga_switcheroo_registered = 1; /* register as an optimus hdmi audio power domain */ vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev, - &chip->hdmi_pm_domain); + &hda->hdmi_pm_domain); return 0; } #else @@ -895,7 +1085,6 @@ static int azx_free(struct azx *chip) { struct pci_dev *pci = chip->pci; struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - int i; if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) @@ -906,13 +1095,13 @@ static int azx_free(struct azx *chip) azx_notifier_unregister(chip); - chip->init_failed = 1; /* to be sure */ - complete_all(&chip->probe_wait); + hda->init_failed = 1; /* to be sure */ + complete_all(&hda->probe_wait); - if (use_vga_switcheroo(chip)) { + if (use_vga_switcheroo(hda)) { if (chip->disabled && chip->bus) snd_hda_unlock_devices(chip->bus); - if (chip->vga_switcheroo_registered) + if (hda->vga_switcheroo_registered) vga_switcheroo_unregister_client(chip->pci); } @@ -1048,6 +1237,30 @@ static int check_position_fix(struct azx *chip, int fix) return POS_FIX_AUTO; } +static void assign_position_fix(struct azx *chip, int fix) +{ + static azx_get_pos_callback_t callbacks[] = { + [POS_FIX_AUTO] = NULL, + [POS_FIX_LPIB] = azx_get_pos_lpib, + [POS_FIX_POSBUF] = azx_get_pos_posbuf, + [POS_FIX_VIACOMBO] = azx_via_get_position, + [POS_FIX_COMBO] = azx_get_pos_lpib, + }; + + chip->get_position[0] = chip->get_position[1] = callbacks[fix]; + + /* combo mode uses LPIB only for playback */ + if (fix == POS_FIX_COMBO) + chip->get_position[1] = NULL; + + if (fix == POS_FIX_POSBUF && + (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { + chip->get_delay[0] = chip->get_delay[1] = + azx_get_delay_from_lpib; + } + +} + /* * black-lists for probe_mask */ @@ -1173,7 +1386,8 @@ static void azx_check_snoop_available(struct azx *chip) static void azx_probe_work(struct work_struct *work) { - azx_probe_continue(container_of(work, struct azx, probe_work)); + struct hda_intel *hda = container_of(work, struct hda_intel, probe_work); + azx_probe_continue(&hda->chip); } /* @@ -1216,19 +1430,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, check_msi(chip); chip->dev_index = dev; chip->jackpoll_ms = jackpoll_ms; - INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); INIT_LIST_HEAD(&chip->pcm_list); - INIT_LIST_HEAD(&chip->list); + INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work); + INIT_LIST_HEAD(&hda->list); init_vga_switcheroo(chip); - init_completion(&chip->probe_wait); - - chip->position_fix[0] = chip->position_fix[1] = - check_position_fix(chip, position_fix[dev]); - /* combo mode uses LPIB for playback */ - if (chip->position_fix[0] == POS_FIX_COMBO) { - chip->position_fix[0] = POS_FIX_LPIB; - chip->position_fix[1] = POS_FIX_AUTO; - } + init_completion(&hda->probe_wait); + + assign_position_fix(chip, check_position_fix(chip, position_fix[dev])); check_probe_mask(chip, dev); @@ -1257,7 +1465,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, } /* continue probing in work context as may trigger request module */ - INIT_WORK(&chip->probe_work, azx_probe_work); + INIT_WORK(&hda->probe_work, azx_probe_work); *rchip = chip; @@ -1315,7 +1523,7 @@ static int azx_first_init(struct azx *chip) NULL); if (p_smbus) { if (p_smbus->revision < 0x30) - gcap &= ~ICH6_GCAP_64OK; + gcap &= ~AZX_GCAP_64OK; pci_dev_put(p_smbus); } } @@ -1323,7 +1531,7 @@ static int azx_first_init(struct azx *chip) /* disable 64bit DMA address on some devices */ if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { dev_dbg(card->dev, "Disabling 64bit DMA\n"); - gcap &= ~ICH6_GCAP_64OK; + gcap &= ~AZX_GCAP_64OK; } /* disable buffer size rounding to 128-byte multiples if supported */ @@ -1339,7 +1547,7 @@ static int azx_first_init(struct azx *chip) } /* allow 64bit DMA address if supported by H/W */ - if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) + if ((gcap & AZX_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); else { pci_set_dma_mask(pci, DMA_BIT_MASK(32)); @@ -1583,6 +1791,7 @@ static int azx_probe(struct pci_dev *pci, { static int dev; struct snd_card *card; + struct hda_intel *hda; struct azx *chip; bool schedule_probe; int err; @@ -1606,6 +1815,7 @@ static int azx_probe(struct pci_dev *pci, if (err < 0) goto out_free; card->private_data = chip; + hda = container_of(chip, struct hda_intel, chip); pci_set_drvdata(pci, card); @@ -1642,11 +1852,11 @@ static int azx_probe(struct pci_dev *pci, #endif if (schedule_probe) - schedule_work(&chip->probe_work); + schedule_work(&hda->probe_work); dev++; if (chip->disabled) - complete_all(&chip->probe_wait); + complete_all(&hda->probe_wait); return 0; out_free: @@ -1662,6 +1872,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { static int azx_probe_continue(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); struct pci_dev *pci = chip->pci; int dev = chip->dev_index; int err; @@ -1735,13 +1946,13 @@ static int azx_probe_continue(struct azx *chip) power_down_all_codecs(chip); azx_notifier_register(chip); azx_add_card_list(chip); - if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || chip->use_vga_switcheroo) + if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || hda->use_vga_switcheroo) pm_runtime_put_noidle(&pci->dev); out_free: if (err < 0) - chip->init_failed = 1; - complete_all(&chip->probe_wait); + hda->init_failed = 1; + complete_all(&hda->probe_wait); return err; } @@ -1806,6 +2017,9 @@ static const struct pci_device_id azx_ids[] = { /* BayTrail */ { PCI_DEVICE(0x8086, 0x0f04), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, + /* Braswell */ + { PCI_DEVICE(0x8086, 0x2284), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* ICH */ { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 4e2d4863daa1..364bb413e02a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -268,7 +268,8 @@ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, unsigned int *cur_val); -int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, +int snd_hda_add_imux_item(struct hda_codec *codec, + struct hda_input_mux *imux, const char *label, int index, int *type_index_ret); /* @@ -437,6 +438,8 @@ struct snd_hda_pin_quirk { #endif +#define HDA_FIXUP_ID_NOT_SET -1 +#define HDA_FIXUP_ID_NO_FIXUP -2 /* fixup types */ enum { @@ -773,9 +776,9 @@ struct hdmi_eld { int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, unsigned char *buf, int *eld_size); -int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, +int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, const unsigned char *buf, int size); -void snd_hdmi_show_eld(struct parsed_hdmi_eld *e); +void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e); void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo); diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index e9d1a5762a55..949cd437eeb2 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -22,107 +22,87 @@ /* * registers */ -#define ICH6_REG_GCAP 0x00 -#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ -#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ -#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ -#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ -#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ -#define ICH6_REG_VMIN 0x02 -#define ICH6_REG_VMAJ 0x03 -#define ICH6_REG_OUTPAY 0x04 -#define ICH6_REG_INPAY 0x06 -#define ICH6_REG_GCTL 0x08 -#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ -#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ -#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ -#define ICH6_REG_WAKEEN 0x0c -#define ICH6_REG_STATESTS 0x0e -#define ICH6_REG_GSTS 0x10 -#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ -#define ICH6_REG_INTCTL 0x20 -#define ICH6_REG_INTSTS 0x24 -#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ -#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ -#define ICH6_REG_SSYNC 0x38 -#define ICH6_REG_CORBLBASE 0x40 -#define ICH6_REG_CORBUBASE 0x44 -#define ICH6_REG_CORBWP 0x48 -#define ICH6_REG_CORBRP 0x4a -#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ -#define ICH6_REG_CORBCTL 0x4c -#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ -#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ -#define ICH6_REG_CORBSTS 0x4d -#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ -#define ICH6_REG_CORBSIZE 0x4e - -#define ICH6_REG_RIRBLBASE 0x50 -#define ICH6_REG_RIRBUBASE 0x54 -#define ICH6_REG_RIRBWP 0x58 -#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ -#define ICH6_REG_RINTCNT 0x5a -#define ICH6_REG_RIRBCTL 0x5c -#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ -#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ -#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ -#define ICH6_REG_RIRBSTS 0x5d -#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ -#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ -#define ICH6_REG_RIRBSIZE 0x5e - -#define ICH6_REG_IC 0x60 -#define ICH6_REG_IR 0x64 -#define ICH6_REG_IRS 0x68 -#define ICH6_IRS_VALID (1<<1) -#define ICH6_IRS_BUSY (1<<0) - -#define ICH6_REG_DPLBASE 0x70 -#define ICH6_REG_DPUBASE 0x74 -#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ +#define AZX_REG_GCAP 0x00 +#define AZX_GCAP_64OK (1 << 0) /* 64bit address support */ +#define AZX_GCAP_NSDO (3 << 1) /* # of serial data out signals */ +#define AZX_GCAP_BSS (31 << 3) /* # of bidirectional streams */ +#define AZX_GCAP_ISS (15 << 8) /* # of input streams */ +#define AZX_GCAP_OSS (15 << 12) /* # of output streams */ +#define AZX_REG_VMIN 0x02 +#define AZX_REG_VMAJ 0x03 +#define AZX_REG_OUTPAY 0x04 +#define AZX_REG_INPAY 0x06 +#define AZX_REG_GCTL 0x08 +#define AZX_GCTL_RESET (1 << 0) /* controller reset */ +#define AZX_GCTL_FCNTRL (1 << 1) /* flush control */ +#define AZX_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ +#define AZX_REG_WAKEEN 0x0c +#define AZX_REG_STATESTS 0x0e +#define AZX_REG_GSTS 0x10 +#define AZX_GSTS_FSTS (1 << 1) /* flush status */ +#define AZX_REG_INTCTL 0x20 +#define AZX_REG_INTSTS 0x24 +#define AZX_REG_WALLCLK 0x30 /* 24Mhz source */ +#define AZX_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ +#define AZX_REG_SSYNC 0x38 +#define AZX_REG_CORBLBASE 0x40 +#define AZX_REG_CORBUBASE 0x44 +#define AZX_REG_CORBWP 0x48 +#define AZX_REG_CORBRP 0x4a +#define AZX_CORBRP_RST (1 << 15) /* read pointer reset */ +#define AZX_REG_CORBCTL 0x4c +#define AZX_CORBCTL_RUN (1 << 1) /* enable DMA */ +#define AZX_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ +#define AZX_REG_CORBSTS 0x4d +#define AZX_CORBSTS_CMEI (1 << 0) /* memory error indication */ +#define AZX_REG_CORBSIZE 0x4e + +#define AZX_REG_RIRBLBASE 0x50 +#define AZX_REG_RIRBUBASE 0x54 +#define AZX_REG_RIRBWP 0x58 +#define AZX_RIRBWP_RST (1 << 15) /* write pointer reset */ +#define AZX_REG_RINTCNT 0x5a +#define AZX_REG_RIRBCTL 0x5c +#define AZX_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ +#define AZX_RBCTL_DMA_EN (1 << 1) /* enable DMA */ +#define AZX_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ +#define AZX_REG_RIRBSTS 0x5d +#define AZX_RBSTS_IRQ (1 << 0) /* response irq */ +#define AZX_RBSTS_OVERRUN (1 << 2) /* overrun irq */ +#define AZX_REG_RIRBSIZE 0x5e + +#define AZX_REG_IC 0x60 +#define AZX_REG_IR 0x64 +#define AZX_REG_IRS 0x68 +#define AZX_IRS_VALID (1<<1) +#define AZX_IRS_BUSY (1<<0) + +#define AZX_REG_DPLBASE 0x70 +#define AZX_REG_DPUBASE 0x74 +#define AZX_DPLBASE_ENABLE 0x1 /* Enable position buffer */ /* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* stream register offsets from stream base */ -#define ICH6_REG_SD_CTL 0x00 -#define ICH6_REG_SD_STS 0x03 -#define ICH6_REG_SD_LPIB 0x04 -#define ICH6_REG_SD_CBL 0x08 -#define ICH6_REG_SD_LVI 0x0c -#define ICH6_REG_SD_FIFOW 0x0e -#define ICH6_REG_SD_FIFOSIZE 0x10 -#define ICH6_REG_SD_FORMAT 0x12 -#define ICH6_REG_SD_BDLPL 0x18 -#define ICH6_REG_SD_BDLPU 0x1c +#define AZX_REG_SD_CTL 0x00 +#define AZX_REG_SD_STS 0x03 +#define AZX_REG_SD_LPIB 0x04 +#define AZX_REG_SD_CBL 0x08 +#define AZX_REG_SD_LVI 0x0c +#define AZX_REG_SD_FIFOW 0x0e +#define AZX_REG_SD_FIFOSIZE 0x10 +#define AZX_REG_SD_FORMAT 0x12 +#define AZX_REG_SD_BDLPL 0x18 +#define AZX_REG_SD_BDLPU 0x1c /* PCI space */ -#define ICH6_PCIREG_TCSEL 0x44 +#define AZX_PCIREG_TCSEL 0x44 /* * other constants */ -/* max number of SDs */ -/* ICH, ATI and VIA have 4 playback and 4 capture */ -#define ICH6_NUM_CAPTURE 4 -#define ICH6_NUM_PLAYBACK 4 - -/* ULI has 6 playback and 5 capture */ -#define ULI_NUM_CAPTURE 5 -#define ULI_NUM_PLAYBACK 6 - -/* ATI HDMI may have up to 8 playbacks and 0 capture */ -#define ATIHDMI_NUM_CAPTURE 0 -#define ATIHDMI_NUM_PLAYBACK 8 - -/* TERA has 4 playback and 3 capture */ -#define TERA_NUM_CAPTURE 3 -#define TERA_NUM_PLAYBACK 4 - -/* this number is statically defined for simplicity */ -#define MAX_AZX_DEV 16 - /* max number of fragments - we may use more if allocating more pages for BDL */ #define BDL_SIZE 4096 #define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) @@ -160,13 +140,13 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ /* INTCTL and INTSTS */ -#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ +#define AZX_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define AZX_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define AZX_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ /* below are so far hardcoded - should read registers in future */ -#define ICH6_MAX_CORB_ENTRIES 256 -#define ICH6_MAX_RIRB_ENTRIES 256 +#define AZX_MAX_CORB_ENTRIES 256 +#define AZX_MAX_RIRB_ENTRIES 256 /* driver quirks (capabilities) */ /* bits 0-7 are used for indicating driver type */ @@ -192,35 +172,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ -/* position fix mode */ -enum { - POS_FIX_AUTO, - POS_FIX_LPIB, - POS_FIX_POSBUF, - POS_FIX_VIACOMBO, - POS_FIX_COMBO, -}; - -/* Defines for ATI HD Audio support in SB450 south bridge */ -#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 -#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 - -/* Defines for Nvidia HDA support */ -#define NVIDIA_HDA_TRANSREG_ADDR 0x4e -#define NVIDIA_HDA_ENABLE_COHBITS 0x0f -#define NVIDIA_HDA_ISTRM_COH 0x4d -#define NVIDIA_HDA_OSTRM_COH 0x4c -#define NVIDIA_HDA_ENABLE_COHBIT 0x01 - -/* Defines for Intel SCH HDA snoop control */ -#define INTEL_SCH_HDA_DEVC 0x78 -#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) - -/* Define IN stream 0 FIFO size offset in VIA controller */ -#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 -/* Define VIA HD Audio Device ID*/ -#define VIA_HDAC_DEVICE_ID 0x3288 - /* HD Audio class code */ #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 @@ -325,6 +276,9 @@ struct azx_pcm { struct list_head list; }; +typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *); +typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos); + struct azx { struct snd_card *card; struct pci_dev *pci; @@ -343,6 +297,10 @@ struct azx { /* Register interaction. */ const struct hda_controller_ops *ops; + /* position adjustment callbacks */ + azx_get_pos_callback_t get_position[2]; + azx_get_delay_callback_t get_delay[2]; + /* pci resources */ unsigned long addr; void __iomem *remap_addr; @@ -351,7 +309,6 @@ struct azx { /* locks */ spinlock_t reg_lock; struct mutex open_mutex; /* Prevents concurrent open/close operations */ - struct completion probe_wait; /* streams (x num_streams) */ struct azx_dev *azx_dev; @@ -378,7 +335,6 @@ struct azx { #endif /* flags */ - int position_fix[2]; /* for both playback/capture streams */ const int *bdl_pos_adj; int poll_count; unsigned int running:1; @@ -386,46 +342,23 @@ struct azx { unsigned int single_cmd:1; unsigned int polling_mode:1; unsigned int msi:1; - unsigned int irq_pending_warned:1; unsigned int probing:1; /* codec probing phase */ unsigned int snoop:1; unsigned int align_buffer_size:1; unsigned int region_requested:1; - - /* VGA-switcheroo setup */ - unsigned int use_vga_switcheroo:1; - unsigned int vga_switcheroo_registered:1; - unsigned int init_failed:1; /* delayed init failed */ unsigned int disabled:1; /* disabled by VGA-switcher */ /* for debugging */ unsigned int last_cmd[AZX_MAX_CODECS]; - /* for pending irqs */ - struct work_struct irq_pending_work; - - struct work_struct probe_work; - /* reboot notifier (for mysterious hangup problem at power-down) */ struct notifier_block reboot_notifier; - /* card list (for power_save trigger) */ - struct list_head list; - #ifdef CONFIG_SND_HDA_DSP_LOADER struct azx_dev saved_azx_dev; #endif - - /* secondary power domain for hdmi audio under vga device */ - struct dev_pm_domain hdmi_pm_domain; }; -#ifdef CONFIG_SND_VERBOSE_PRINTK -#define SFX /* nop */ -#else -#define SFX "hda-intel " -#endif - #ifdef CONFIG_X86 #define azx_snoop(chip) ((chip)->snoop) #else @@ -437,29 +370,29 @@ struct azx { */ #define azx_writel(chip, reg, value) \ - ((chip)->ops->reg_writel(value, (chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg)) #define azx_readl(chip, reg) \ - ((chip)->ops->reg_readl((chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg)) #define azx_writew(chip, reg, value) \ - ((chip)->ops->reg_writew(value, (chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg)) #define azx_readw(chip, reg) \ - ((chip)->ops->reg_readw((chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg)) #define azx_writeb(chip, reg, value) \ - ((chip)->ops->reg_writeb(value, (chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg)) #define azx_readb(chip, reg) \ - ((chip)->ops->reg_readb((chip)->remap_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg)) #define azx_sd_writel(chip, dev, reg, value) \ - ((chip)->ops->reg_writel(value, (dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_readl(chip, dev, reg) \ - ((chip)->ops->reg_readl((dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_writew(chip, dev, reg, value) \ - ((chip)->ops->reg_writew(value, (dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_readw(chip, dev, reg) \ - ((chip)->ops->reg_readw((dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_writeb(chip, dev, reg, value) \ - ((chip)->ops->reg_writeb(value, (dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg)) #define azx_sd_readb(chip, dev, reg) \ - ((chip)->ops->reg_readb((dev)->sd_addr + ICH6_REG_##reg)) + ((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg)) #endif /* __SOUND_HDA_PRIV_H */ diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 358414da6418..227990bc02e3 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -29,7 +29,6 @@ #include <linux/moduleparam.h> #include <linux/mutex.h> #include <linux/of_device.h> -#include <linux/reboot.h> #include <linux/slab.h> #include <linux/time.h> @@ -272,13 +271,9 @@ static int hda_tegra_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); - int status; hda_tegra_enable_clocks(hda); - /* Read STATESTS before controller reset */ - status = azx_readw(chip, STATESTS); - hda_tegra_init(hda); azx_init_chip(chip, 1); @@ -295,30 +290,6 @@ static const struct dev_pm_ops hda_tegra_pm = { }; /* - * reboot notifier for hang-up problem at power-down - */ -static int hda_tegra_halt(struct notifier_block *nb, unsigned long event, - void *buf) -{ - struct azx *chip = container_of(nb, struct azx, reboot_notifier); - snd_hda_bus_reboot_notify(chip->bus); - azx_stop_chip(chip); - return NOTIFY_OK; -} - -static void hda_tegra_notifier_register(struct azx *chip) -{ - chip->reboot_notifier.notifier_call = hda_tegra_halt; - register_reboot_notifier(&chip->reboot_notifier); -} - -static void hda_tegra_notifier_unregister(struct azx *chip) -{ - if (chip->reboot_notifier.notifier_call) - unregister_reboot_notifier(&chip->reboot_notifier); -} - -/* * destructor */ static int hda_tegra_dev_free(struct snd_device *device) @@ -326,7 +297,7 @@ static int hda_tegra_dev_free(struct snd_device *device) int i; struct azx *chip = device->device_data; - hda_tegra_notifier_unregister(chip); + azx_notifier_unregister(chip); if (chip->initialized) { for (i = 0; i < chip->num_streams; i++) @@ -478,10 +449,7 @@ static int hda_tegra_create(struct snd_card *card, chip->driver_type = driver_caps & 0xff; chip->dev_index = 0; INIT_LIST_HEAD(&chip->pcm_list); - INIT_LIST_HEAD(&chip->list); - chip->position_fix[0] = POS_FIX_AUTO; - chip->position_fix[1] = POS_FIX_AUTO; chip->codec_probe_mask = -1; chip->single_cmd = false; @@ -559,7 +527,7 @@ static int hda_tegra_probe(struct platform_device *pdev) chip->running = 1; power_down_all_codecs(chip); - hda_tegra_notifier_register(chip); + azx_notifier_register(chip); return 0; diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 092f2bd030bd..4f3aba78f720 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2046,14 +2046,14 @@ enum dma_state { DMA_STATE_RUN = 1 }; -static int dma_convert_to_hda_format( +static int dma_convert_to_hda_format(struct hda_codec *codec, unsigned int sample_rate, unsigned short channels, unsigned short *hda_format) { unsigned int format_val; - format_val = snd_hda_calc_stream_format( + format_val = snd_hda_calc_stream_format(codec, sample_rate, channels, SNDRV_PCM_FORMAT_S32_LE, @@ -2452,7 +2452,7 @@ static int dspxfr_image(struct hda_codec *codec, } dma_engine->codec = codec; - dma_convert_to_hda_format(sample_rate, channels, &hda_format); + dma_convert_to_hda_format(codec, sample_rate, channels, &hda_format); dma_engine->m_converter_format = hda_format; dma_engine->buf_size = (ovly ? DSP_DMA_WRITE_BUFLEN_OVLY : DSP_DMA_WRITE_BUFLEN_INIT) * 2; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 387f0b551889..3db724eaa53c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -657,8 +657,10 @@ static void cs4208_fixup_mac(struct hda_codec *codec, { if (action != HDA_FIXUP_ACT_PRE_PROBE) return; + + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups); - if (codec->fixup_id < 0 || codec->fixup_id == CS4208_MAC_AUTO) + if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET) codec->fixup_id = CS4208_GPIO0; /* default fixup */ snd_hda_apply_fixup(codec, action); } diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 061ea5965dd5..ed3d133ffbb6 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -31,550 +31,11 @@ #include "hda_jack.h" #include "hda_generic.h" -#undef ENABLE_CMI_STATIC_QUIRKS - -#ifdef ENABLE_CMI_STATIC_QUIRKS -#define NUM_PINS 11 - - -/* board config type */ -enum { - CMI_MINIMAL, /* back 3-jack */ - CMI_MIN_FP, /* back 3-jack + front-panel 2-jack */ - CMI_FULL, /* back 6-jack + front-panel 2-jack */ - CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ - CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ - CMI_AUTO, /* let driver guess it */ - CMI_MODELS -}; -#endif /* ENABLE_CMI_STATIC_QUIRKS */ - struct cmi_spec { struct hda_gen_spec gen; - -#ifdef ENABLE_CMI_STATIC_QUIRKS - /* below are only for static models */ - - int board_config; - unsigned int no_line_in: 1; /* no line-in (5-jack) */ - unsigned int front_panel: 1; /* has front-panel 2-jack */ - - /* playback */ - struct hda_multi_out multiout; - hda_nid_t dac_nids[AUTO_CFG_MAX_OUTS]; /* NID for each DAC */ - int num_dacs; - - /* capture */ - const hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; - - /* capture source */ - const struct hda_input_mux *input_mux; - unsigned int cur_mux[2]; - - /* channel mode */ - int num_channel_modes; - const struct hda_channel_mode *channel_modes; - - struct hda_pcm pcm_rec[2]; /* PCM information */ - - /* pin default configuration */ - hda_nid_t pin_nid[NUM_PINS]; - unsigned int def_conf[NUM_PINS]; - unsigned int pin_def_confs; - - /* multichannel pins */ - struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ -#endif /* ENABLE_CMI_STATIC_QUIRKS */ -}; - -#ifdef ENABLE_CMI_STATIC_QUIRKS -/* - * input MUX - */ -static int cmi_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int cmi_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); -} - -/* - * shared line-in, mic for surrounds - */ - -/* 3-stack / 2 channel */ -static const struct hda_verb cmi9880_ch2_init[] = { - /* set line-in PIN for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* set mic PIN for input, also enable vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* route front PCM (DAC1) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - {} -}; - -/* 3-stack / 6 channel */ -static const struct hda_verb cmi9880_ch6_init[] = { - /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* route front PCM (DAC1) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - {} -}; - -/* 3-stack+front / 8 channel */ -static const struct hda_verb cmi9880_ch8_init[] = { - /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - /* route rear-surround PCM (DAC4) to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, - {} -}; - -static const struct hda_channel_mode cmi9880_channel_modes[3] = { - { 2, cmi9880_ch2_init }, - { 6, cmi9880_ch6_init }, - { 8, cmi9880_ch8_init }, -}; - -static int cmi_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_modes, - spec->num_channel_modes); -} - -static int cmi_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_modes, - spec->num_channel_modes, spec->multiout.max_channels); -} - -static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cmi_spec *spec = codec->spec; - return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_modes, - spec->num_channel_modes, &spec->multiout.max_channels); -} - -/* - */ -static const struct snd_kcontrol_new cmi9880_basic_mixer[] = { - /* CMI9880 has no playback volumes! */ - HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */ - HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = cmi_mux_enum_info, - .get = cmi_mux_enum_get, - .put = cmi_mux_enum_put, - }, - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x23, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x23, 0, HDA_OUTPUT), - { } /* end */ }; /* - * shared I/O pins - */ -static const struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = cmi_ch_mode_info, - .get = cmi_ch_mode_get, - .put = cmi_ch_mode_put, - }, - { } /* end */ -}; - -/* AUD-in selections: - * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20 - */ -static const struct hda_input_mux cmi9880_basic_mux = { - .num_items = 4, - .items = { - { "Front Mic", 0x5 }, - { "Rear Mic", 0x2 }, - { "Line", 0x1 }, - { "CD", 0x7 }, - } -}; - -static const struct hda_input_mux cmi9880_no_line_mux = { - .num_items = 3, - .items = { - { "Front Mic", 0x5 }, - { "Rear Mic", 0x2 }, - { "CD", 0x7 }, - } -}; - -/* front, rear, clfe, rear_surr */ -static const hda_nid_t cmi9880_dac_nids[4] = { - 0x03, 0x04, 0x05, 0x06 -}; -/* ADC0, ADC1 */ -static const hda_nid_t cmi9880_adc_nids[2] = { - 0x08, 0x09 -}; - -#define CMI_DIG_OUT_NID 0x07 -#define CMI_DIG_IN_NID 0x0a - -/* - */ -static const struct hda_verb cmi9880_basic_init[] = { - /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* route front mic to ADC1/2 */ - { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, - { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, - {} /* terminator */ -}; - -static const struct hda_verb cmi9880_allout_init[] = { - /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* route front PCM to HP */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - /* port-A for side (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, - /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, - /* port-C for surround (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* route front mic to ADC1/2 */ - { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, - { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, - {} /* terminator */ -}; - -/* - */ -static int cmi9880_build_controls(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - struct snd_kcontrol *kctl; - int i, err; - - err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); - if (err < 0) - return err; - if (spec->channel_modes) { - err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - - /* assign Capture Source enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]); - if (err < 0) - return err; - } - return 0; -} - -static int cmi9880_init(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - if (spec->board_config == CMI_ALLOUT) - snd_hda_sequence_write(codec, cmi9880_allout_init); - else - snd_hda_sequence_write(codec, cmi9880_basic_init); - if (spec->board_config == CMI_AUTO) - snd_hda_sequence_write(codec, spec->multi_init); - return 0; -} - -/* - * Analog playback callbacks - */ -static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int cmi9880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cmi_spec *spec = codec->spec; - - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - - -/* - */ -static const struct hda_pcm_stream cmi9880_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = 0x03, /* NID to query formats and rates */ - .ops = { - .open = cmi9880_playback_pcm_open, - .prepare = cmi9880_playback_pcm_prepare, - .cleanup = cmi9880_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cmi9880_pcm_analog_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = 0x08, /* NID to query formats and rates */ - .ops = { - .prepare = cmi9880_capture_pcm_prepare, - .cleanup = cmi9880_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cmi9880_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in cmi9880_build_pcms */ - .ops = { - .open = cmi9880_dig_playback_pcm_open, - .close = cmi9880_dig_playback_pcm_close, - .prepare = cmi9880_dig_playback_pcm_prepare - }, -}; - -static const struct hda_pcm_stream cmi9880_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in cmi9880_build_pcms */ -}; - -static int cmi9880_build_pcms(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "CMI9880"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture; - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - codec->num_pcms++; - info++; - info->name = "CMI9880 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - return 0; -} - -static void cmi9880_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -/* - */ - -static const char * const cmi9880_models[CMI_MODELS] = { - [CMI_MINIMAL] = "minimal", - [CMI_MIN_FP] = "min_fp", - [CMI_FULL] = "full", - [CMI_FULL_DIG] = "full_dig", - [CMI_ALLOUT] = "allout", - [CMI_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cmi9880_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG), - SND_PCI_QUIRK(0x1854, 0x002b, "LG LS75", CMI_MINIMAL), - SND_PCI_QUIRK(0x1854, 0x0032, "LG", CMI_FULL_DIG), - {} /* terminator */ -}; - -static const struct hda_codec_ops cmi9880_patch_ops = { - .build_controls = cmi9880_build_controls, - .build_pcms = cmi9880_build_pcms, - .init = cmi9880_init, - .free = cmi9880_free, -}; -#endif /* ENABLE_CMI_STATIC_QUIRKS */ - -/* * stuff for auto-parser */ static const struct hda_codec_ops cmi_auto_patch_ops = { @@ -585,12 +46,18 @@ static const struct hda_codec_ops cmi_auto_patch_ops = { .unsol_event = snd_hda_jack_unsol_event, }; -static int cmi_parse_auto_config(struct hda_codec *codec) +static int patch_cmi9880(struct hda_codec *codec) { - struct cmi_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->gen.autocfg; + struct cmi_spec *spec; + struct auto_pin_cfg *cfg; int err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + cfg = &spec->gen.autocfg; snd_hda_gen_spec_init(&spec->gen); err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); @@ -608,79 +75,6 @@ static int cmi_parse_auto_config(struct hda_codec *codec) return err; } - -static int patch_cmi9880(struct hda_codec *codec) -{ - struct cmi_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; -#ifdef ENABLE_CMI_STATIC_QUIRKS - spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS, - cmi9880_models, - cmi9880_cfg_tbl); - if (spec->board_config < 0) { - codec_dbg(codec, "%s: BIOS auto-probing.\n", - codec->chip_name); - spec->board_config = CMI_AUTO; /* try everything */ - } - - if (spec->board_config == CMI_AUTO) - return cmi_parse_auto_config(codec); - - /* copy default DAC NIDs */ - memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); - spec->num_dacs = 4; - - switch (spec->board_config) { - case CMI_MINIMAL: - case CMI_MIN_FP: - spec->channel_modes = cmi9880_channel_modes; - if (spec->board_config == CMI_MINIMAL) - spec->num_channel_modes = 2; - else { - spec->front_panel = 1; - spec->num_channel_modes = 3; - } - spec->multiout.max_channels = cmi9880_channel_modes[0].channels; - spec->input_mux = &cmi9880_basic_mux; - break; - case CMI_FULL: - case CMI_FULL_DIG: - spec->front_panel = 1; - spec->multiout.max_channels = 8; - spec->input_mux = &cmi9880_basic_mux; - if (spec->board_config == CMI_FULL_DIG) { - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - spec->dig_in_nid = CMI_DIG_IN_NID; - } - break; - case CMI_ALLOUT: - default: - spec->front_panel = 1; - spec->multiout.max_channels = 8; - spec->no_line_in = 1; - spec->input_mux = &cmi9880_no_line_mux; - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - break; - } - - spec->multiout.num_dacs = spec->num_dacs; - spec->multiout.dac_nids = spec->dac_nids; - - spec->adc_nids = cmi9880_adc_nids; - - codec->patch_ops = cmi9880_patch_ops; - - return 0; -#else - return cmi_parse_auto_config(codec); -#endif -} - /* * patch entries */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 1dc7e974f3b1..7627a69ca6d7 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -34,27 +34,6 @@ #include "hda_jack.h" #include "hda_generic.h" -#undef ENABLE_CXT_STATIC_QUIRKS - -#define CXT_PIN_DIR_IN 0x00 -#define CXT_PIN_DIR_OUT 0x01 -#define CXT_PIN_DIR_INOUT 0x02 -#define CXT_PIN_DIR_IN_NOMICBIAS 0x03 -#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04 - -#define CONEXANT_HP_EVENT 0x37 -#define CONEXANT_MIC_EVENT 0x38 -#define CONEXANT_LINE_EVENT 0x39 - -/* Conexant 5051 specific */ - -#define CXT5051_SPDIF_OUT 0x12 -#define CXT5051_PORTB_EVENT 0x38 -#define CXT5051_PORTC_EVENT 0x39 - -#define AUTO_MIC_PORTB (1 << 1) -#define AUTO_MIC_PORTC (1 << 2) - struct conexant_spec { struct hda_gen_spec gen; @@ -72,64 +51,6 @@ struct conexant_spec { bool dc_enable; unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ struct nid_path *dc_mode_path; - -#ifdef ENABLE_CXT_STATIC_QUIRKS - const struct snd_kcontrol_new *mixers[5]; - int num_mixers; - hda_nid_t vmaster_nid; - - const struct hda_verb *init_verbs[5]; /* initialization verbs - * don't forget NULL - * termination! - */ - unsigned int num_init_verbs; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - unsigned int cur_eapd; - unsigned int hp_present; - unsigned int line_present; - unsigned int auto_mic; - - /* capture */ - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; /* digital-in NID; optional */ - - unsigned int cur_adc_idx; - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - - const struct hda_pcm_stream *capture_stream; - - /* capture source */ - const struct hda_input_mux *input_mux; - const hda_nid_t *capsrc_nids; - unsigned int cur_mux[3]; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - - /* PCM information */ - struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ - - unsigned int spdif_route; - - unsigned int port_d_mode; - unsigned int dell_automute:1; - unsigned int dell_vostro:1; - unsigned int ideapad:1; - unsigned int thinkpad:1; - unsigned int hp_laptop:1; - unsigned int asus:1; - - unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ -#endif /* ENABLE_CXT_STATIC_QUIRKS */ }; @@ -173,2533 +94,6 @@ static int add_beep_ctls(struct hda_codec *codec) #define add_beep_ctls(codec) 0 #endif - -#ifdef ENABLE_CXT_STATIC_QUIRKS -static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int conexant_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - - - -static const struct hda_pcm_stream conexant_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_playback_pcm_open, - .prepare = conexant_playback_pcm_prepare, - .cleanup = conexant_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream conexant_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = conexant_capture_pcm_prepare, - .cleanup = conexant_capture_pcm_cleanup - }, -}; - - -static const struct hda_pcm_stream conexant_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = conexant_dig_playback_pcm_open, - .close = conexant_dig_playback_pcm_close, - .prepare = conexant_dig_playback_pcm_prepare - }, -}; - -static const struct hda_pcm_stream conexant_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; -} - -static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -static const struct hda_pcm_stream cx5051_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = cx5051_capture_pcm_prepare, - .cleanup = cx5051_capture_pcm_cleanup - }, -}; - -static int conexant_build_pcms(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "CONEXANT Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dac_nids[0]; - if (spec->capture_stream) - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; - else { - if (codec->vendor_id == 0x14f15051) - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - cx5051_pcm_analog_capture; - else { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids; - } - } - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - - if (spec->multiout.dig_out_nid) { - info++; - codec->num_pcms++; - info->name = "Conexant Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - conexant_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - conexant_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->dig_in_nid; - } - } - - return 0; -} - -static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->capsrc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - -static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) -{ - if (power_state == AC_PWRST_D3) - msleep(100); - snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, - power_state); - /* partial workaround for "azx_get_response timeout" */ - if (power_state == AC_PWRST_D0) - msleep(10); - snd_hda_codec_set_power_to_all(codec, fg, power_state); -} - -static int conexant_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - return 0; -} - -static void conexant_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -static const struct snd_kcontrol_new cxt_capture_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put - }, - {} -}; - -static const char * const slave_pfxs[] = { - "Headphone", "Speaker", "Bass Speaker", "Front", "Surround", "CLFE", - NULL -}; - -static int conexant_build_controls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int i; - int err; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); - if (err < 0) - return err; - } - - /* if we have no master control, let's create it */ - if (spec->vmaster_nid && - !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - } - if (spec->vmaster_nid && - !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, - "Playback Switch"); - if (err < 0) - return err; - } - - if (spec->input_mux) { - err = snd_hda_add_new_ctls(codec, cxt_capture_mixers); - if (err < 0) - return err; - } - - err = add_beep_ctls(codec); - if (err < 0) - return err; - - return 0; -} - -static const struct hda_codec_ops conexant_patch_ops = { - .build_controls = conexant_build_controls, - .build_pcms = conexant_build_pcms, - .init = conexant_init, - .free = conexant_free, - .set_power_state = conexant_set_power, -}; - -static int patch_conexant_auto(struct hda_codec *codec); -/* - * EAPD control - * the private value = nid | (invert << 8) - */ - -#define cxt_eapd_info snd_ctl_boolean_mono_info - -static int cxt_eapd_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - if (invert) - ucontrol->value.integer.value[0] = !spec->cur_eapd; - else - ucontrol->value.integer.value[0] = spec->cur_eapd; - return 0; - -} - -static int cxt_eapd_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int eapd; - - eapd = !!ucontrol->value.integer.value[0]; - if (invert) - eapd = !eapd; - if (eapd == spec->cur_eapd) - return 0; - - spec->cur_eapd = eapd; - snd_hda_codec_write_cache(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); - return 1; -} - -/* controls for test mode */ -#ifdef CONFIG_SND_DEBUG - -#define CXT_EAPD_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = cxt_eapd_info, \ - .get = cxt_eapd_get, \ - .put = cxt_eapd_put, \ - .private_value = nid | (mask<<16) } - - - -static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - spec->multiout.max_channels); -} - -static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->multiout.max_channels); - return err; -} - -#define CXT_PIN_MODE(xname, nid, dir) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = conexant_ch_mode_info, \ - .get = conexant_ch_mode_get, \ - .put = conexant_ch_mode_put, \ - .private_value = nid | (dir<<16) } - -#endif /* CONFIG_SND_DEBUG */ - -/* Conexant 5045 specific */ - -static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; -static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; -static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; -#define CXT5045_SPDIF_OUT 0x18 - -static const struct hda_channel_mode cxt5045_modes[1] = { - { 2, NULL }, -}; - -static const struct hda_input_mux cxt5045_capture_source = { - .num_items = 2, - .items = { - { "Internal Mic", 0x1 }, - { "Mic", 0x2 }, - } -}; - -static const struct hda_input_mux cxt5045_capture_source_benq = { - .num_items = 4, - .items = { - { "Internal Mic", 0x1 }, - { "Mic", 0x2 }, - { "Line", 0x3 }, - { "Mixer", 0x0 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - - bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - return 1; -} - -/* bind volumes of both NID 0x10 and 0x11 */ -static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5045_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x12); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - - -/* mute internal speaker if HP is plugged */ -static void cxt5045_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_jack_detect(codec, 0x11); - - bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5045_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - res >>= 26; - switch (res) { - case CONEXANT_HP_EVENT: - cxt5045_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5045_hp_automic(codec); - break; - - } -} - -static const struct snd_kcontrol_new cxt5045_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, HDA_INPUT), - HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5045_hp_master_sw_put, - .private_value = 0x10, - }, - - {} -}; - -static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x3, HDA_INPUT), - - {} -}; - -static const struct hda_verb cxt5045_init_verbs[] = { - /* Line in, Mic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - /* HP, Amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Record selector: Internal mic */ - {0x1a, AC_VERB_SET_CONNECT_SEL,0x1}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - /* SPDIF route: PCM */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* EAPD */ - {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2 }, /* default on */ - { } /* end */ -}; - -static const struct hda_verb cxt5045_benq_init_verbs[] = { - /* Internal Mic, Mic */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, - /* Line In,HP, Amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Record selector: Internal mic */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - /* SPDIF route: PCM */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - { } /* end */ -}; - -static const struct hda_verb cxt5045_hp_sense_init_verbs[] = { - /* pin sensing on HP jack */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5045_mic_sense_init_verbs[] = { - /* pin sensing on HP jack */ - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -#ifdef CONFIG_SND_DEBUG -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -static const struct hda_input_mux cxt5045_test_capture_source = { - .num_items = 5, - .items = { - { "MIXER", 0x0 }, - { "MIC1 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "HP-OUT pin", 0x3 }, - { "CD pin", 0x4 }, - }, -}; - -static const struct snd_kcontrol_new cxt5045_test_mixer[] = { - - /* Output controls */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HP-OUT Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("HP-OUT Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("LINE1 Playback Switch", 0x12, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x10, 0x0), - - /* Loopback mixer controls */ - - HDA_CODEC_VOLUME("PCM Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("MIC1 pin Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 pin Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 pin Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("LINE1 pin Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("HP-OUT pin Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("HP-OUT pin Switch", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("CD pin Volume", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD pin Switch", 0x17, 0x4, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - /* Audio input controls */ - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_verb cxt5045_test_init_verbs[] = { - /* Set connections */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable retasking pins as output, initially without power amp */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5045_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5045_hp_automute(codec); - return 0; -} - - -enum { - CXT5045_LAPTOP_HPSENSE, - CXT5045_LAPTOP_MICSENSE, - CXT5045_LAPTOP_HPMICSENSE, - CXT5045_BENQ, -#ifdef CONFIG_SND_DEBUG - CXT5045_TEST, -#endif - CXT5045_AUTO, - CXT5045_MODELS -}; - -static const char * const cxt5045_models[CXT5045_MODELS] = { - [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", - [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", - [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", - [CXT5045_BENQ] = "benq", -#ifdef CONFIG_SND_DEBUG - [CXT5045_TEST] = "test", -#endif - [CXT5045_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { - SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), - SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), - SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", - CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK_MASK(0x1631, 0xff00, 0xc100, "Packard Bell", - CXT5045_LAPTOP_HPMICSENSE), - SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), - {} -}; - -static int patch_cxt5045(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, - cxt5045_models, - cxt5045_cfg_tbl); - if (board_config < 0) - board_config = CXT5045_AUTO; /* model=auto as default */ - if (board_config == CXT5045_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->single_adc_amp = 1; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); - spec->multiout.dac_nids = cxt5045_dac_nids; - spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5045_adc_nids; - spec->capsrc_nids = cxt5045_capsrc_nids; - spec->input_mux = &cxt5045_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = cxt5045_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5045_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes); - spec->channel_mode = cxt5045_modes; - - set_beep_amp(spec, 0x16, 0, 1); - - codec->patch_ops = conexant_patch_ops; - - switch (board_config) { - case CXT5045_LAPTOP_HPSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - case CXT5045_LAPTOP_MICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - default: - case CXT5045_LAPTOP_HPMICSENSE: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source; - spec->num_init_verbs = 3; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->init_verbs[2] = cxt5045_mic_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers; - codec->patch_ops.init = cxt5045_init; - break; - case CXT5045_BENQ: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source_benq; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5045_benq_init_verbs; - spec->mixers[0] = cxt5045_mixers; - spec->mixers[1] = cxt5045_benq_mixers; - spec->num_mixers = 2; - codec->patch_ops.init = cxt5045_init; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5045_TEST: - spec->input_mux = &cxt5045_test_capture_source; - spec->mixers[0] = cxt5045_test_mixer; - spec->init_verbs[0] = cxt5045_test_init_verbs; - break; - -#endif - } - - switch (codec->subsystem_id >> 16) { - case 0x103c: - case 0x1631: - case 0x1734: - case 0x17aa: - /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have - * really bad sound over 0dB on NID 0x17. Fix max PCM level to - * 0 dB (originally it has 0x2b steps with 0dB offset 0x14) - */ - snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, - (0x14 << AC_AMPCAP_OFFSET_SHIFT) | - (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - - -/* Conexant 5047 specific */ -#define CXT5047_SPDIF_OUT 0x11 - -static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ -static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; -static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; - -static const struct hda_channel_mode cxt5047_modes[1] = { - { 2, NULL }, -}; - -static const struct hda_input_mux cxt5047_toshiba_capture_source = { - .num_items = 2, - .items = { - { "ExtMic", 0x2 }, - { "Line-In", 0x1 }, - } -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - /* toggle internal speakers mute depending of presence of - * the headphone jack - */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; - /* NOTE: Conexat codec needs the index for *OUTPUT* amp of - * pin widgets unlike other codecs. In this case, we need to - * set index 0x01 for the volume from the mixer amp 0x19. - */ - snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, - HDA_AMP_MUTE, bits); - bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - return 1; -} - -/* mute internal speaker if HP is plugged */ -static void cxt5047_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int bits; - - spec->hp_present = snd_hda_jack_detect(codec, 0x13); - - bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; - /* See the note in cxt5047_hp_master_sw_put */ - snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, - HDA_AMP_MUTE, bits); -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5047_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x15); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5047_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5047_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5047_hp_automic(codec); - break; - } -} - -static const struct snd_kcontrol_new cxt5047_base_mixers[] = { - HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5047_hp_master_sw_put, - .private_value = 0x13, - }, - - {} -}; - -static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { - /* See the note in cxt5047_hp_master_sw_put */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb cxt5047_init_verbs[] = { - /* Line in, Mic, Built-in Mic */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, - /* HP, Speaker */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* mixer(0x19) */ - {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mixer(0x19) */ - /* Record selector: Mic */ - {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, - {0x1A, AC_VERB_SET_CONNECT_SEL,0x02}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, - {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, - /* SPDIF route: PCM */ - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* Enable unsolicited events */ - {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -/* configuration for Toshiba Laptops */ -static const struct hda_verb cxt5047_toshiba_init_verbs[] = { - {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ - {} -}; - -/* Test configuration for debugging, modelled after the ALC260 test - * configuration. - */ -#ifdef CONFIG_SND_DEBUG -static const struct hda_input_mux cxt5047_test_capture_source = { - .num_items = 4, - .items = { - { "LINE1 pin", 0x0 }, - { "MIC1 pin", 0x1 }, - { "MIC2 pin", 0x2 }, - { "CD pin", 0x3 }, - }, -}; - -static const struct snd_kcontrol_new cxt5047_test_mixer[] = { - - /* Output only controls */ - HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line1-Out Playback Volume", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line1-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line2-Out Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line2-Out Playback Switch", 0x15, 0x0, HDA_OUTPUT), - - /* Modes for retasking pin widgets */ - CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), - CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), - - /* EAPD Switch Control */ - CXT_EAPD_SWITCH("External Amplifier", 0x13, 0x0), - - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x12, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x12, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LINE Playback Volume", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("LINE Playback Switch", 0x12, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x12, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x12, 0x04, HDA_INPUT), - - HDA_CODEC_VOLUME("Capture-1 Volume", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture-1 Switch", 0x19, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-2 Volume", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Capture-2 Switch", 0x19, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-3 Volume", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Capture-3 Switch", 0x19, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Capture-4 Volume", 0x19, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Capture-4 Switch", 0x19, 0x3, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = conexant_mux_enum_info, - .get = conexant_mux_enum_get, - .put = conexant_mux_enum_put, - }, - HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), - - { } /* end */ -}; - -static const struct hda_verb cxt5047_test_init_verbs[] = { - /* Enable retasking pins as output, initially without power amp */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure mic1, mic2, line1 pin widgets take input from the - * OUT1 sum bus when acting as an output. - */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; -#endif - - -/* initialize jack-sensing, too */ -static int cxt5047_hp_init(struct hda_codec *codec) -{ - conexant_init(codec); - cxt5047_hp_automute(codec); - return 0; -} - - -enum { - CXT5047_LAPTOP, /* Laptops w/o EAPD support */ - CXT5047_LAPTOP_HP, /* Some HP laptops */ - CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */ -#ifdef CONFIG_SND_DEBUG - CXT5047_TEST, -#endif - CXT5047_AUTO, - CXT5047_MODELS -}; - -static const char * const cxt5047_models[CXT5047_MODELS] = { - [CXT5047_LAPTOP] = "laptop", - [CXT5047_LAPTOP_HP] = "laptop-hp", - [CXT5047_LAPTOP_EAPD] = "laptop-eapd", -#ifdef CONFIG_SND_DEBUG - [CXT5047_TEST] = "test", -#endif - [CXT5047_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5047_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", - CXT5047_LAPTOP), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), - {} -}; - -static int patch_cxt5047(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, - cxt5047_models, - cxt5047_cfg_tbl); - if (board_config < 0) - board_config = CXT5047_AUTO; /* model=auto as default */ - if (board_config == CXT5047_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->pin_amp_workaround = 1; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); - spec->multiout.dac_nids = cxt5047_dac_nids; - spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = cxt5047_adc_nids; - spec->capsrc_nids = cxt5047_capsrc_nids; - spec->num_mixers = 1; - spec->mixers[0] = cxt5047_base_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5047_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes), - spec->channel_mode = cxt5047_modes, - - codec->patch_ops = conexant_patch_ops; - - switch (board_config) { - case CXT5047_LAPTOP: - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_spk_mixers; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - break; - case CXT5047_LAPTOP_HP: - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_only_mixers; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - codec->patch_ops.init = cxt5047_hp_init; - break; - case CXT5047_LAPTOP_EAPD: - spec->input_mux = &cxt5047_toshiba_capture_source; - spec->num_mixers = 2; - spec->mixers[1] = cxt5047_hp_spk_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5047_toshiba_init_verbs; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; - break; -#ifdef CONFIG_SND_DEBUG - case CXT5047_TEST: - spec->input_mux = &cxt5047_test_capture_source; - spec->mixers[0] = cxt5047_test_mixer; - spec->init_verbs[0] = cxt5047_test_init_verbs; - codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; -#endif - } - spec->vmaster_nid = 0x13; - - switch (codec->subsystem_id >> 16) { - case 0x103c: - /* HP laptops have really bad sound over 0 dB on NID 0x10. - * Fix max PCM level to 0 dB (originally it has 0x1e steps - * with 0 dB offset 0x17) - */ - snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } - - return 0; -} - -/* Conexant 5051 specific */ -static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; -static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; - -static const struct hda_channel_mode cxt5051_modes[1] = { - { 2, NULL }, -}; - -static void cxt5051_update_speaker(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int pinctl; - /* headphone pin */ - pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x16, pinctl); - /* speaker pin */ - pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1a, pinctl); - /* on ideapad there is an additional speaker (subwoofer) to mute */ - if (spec->ideapad) - snd_hda_set_pin_ctl(codec, 0x1b, pinctl); -} - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - cxt5051_update_speaker(codec); - return 1; -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5051_portb_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - - if (!(spec->auto_mic & AUTO_MIC_PORTB)) - return; - present = snd_hda_jack_detect(codec, 0x17); - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_CONNECT_SEL, - present ? 0x01 : 0x00); -} - -/* switch the current ADC according to the jack state */ -static void cxt5051_portc_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - hda_nid_t new_adc; - - if (!(spec->auto_mic & AUTO_MIC_PORTC)) - return; - present = snd_hda_jack_detect(codec, 0x18); - if (present) - spec->cur_adc_idx = 1; - else - spec->cur_adc_idx = 0; - new_adc = spec->adc_nids[spec->cur_adc_idx]; - if (spec->cur_adc && spec->cur_adc != new_adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = new_adc; - snd_hda_codec_setup_stream(codec, new_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } -} - -/* mute internal speaker if HP is plugged */ -static void cxt5051_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - spec->hp_present = snd_hda_jack_detect(codec, 0x16); - cxt5051_update_speaker(codec); -} - -/* unsolicited event for HP jack sensing */ -static void cxt5051_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5051_hp_automute(codec); - break; - case CXT5051_PORTB_EVENT: - cxt5051_portb_automic(codec); - break; - case CXT5051_PORTC_EVENT: - cxt5051_portc_automic(codec); - break; - } -} - -static const struct snd_kcontrol_new cxt5051_playback_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5051_hp_master_sw_put, - .private_value = 0x1a, - }, - {} -}; - -static const struct snd_kcontrol_new cxt5051_capture_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Switch", 0x15, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_hp_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_f700_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), - {} -}; - -static const struct hda_verb cxt5051_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5051_f700_init_verbs[] = { - /* Line in, Mic */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, - /* SPK */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP, Amp */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Internal mic */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* SPDIF route: PCM */ - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* EAPD */ - {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, - { } /* end */ -}; - -static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, - unsigned int event) -{ - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | event); -} - -static const struct hda_verb cxt5051_ideapad_init_verbs[] = { - /* Subwoofer */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* initialize jack-sensing, too */ -static int cxt5051_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - conexant_init(codec); - - if (spec->auto_mic & AUTO_MIC_PORTB) - cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); - if (spec->auto_mic & AUTO_MIC_PORTC) - cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT); - - if (codec->patch_ops.unsol_event) { - cxt5051_hp_automute(codec); - cxt5051_portb_automic(codec); - cxt5051_portc_automic(codec); - } - return 0; -} - - -enum { - CXT5051_LAPTOP, /* Laptops w/ EAPD support */ - CXT5051_HP, /* no docking */ - CXT5051_HP_DV6736, /* HP without mic switch */ - CXT5051_F700, /* HP Compaq Presario F700 */ - CXT5051_TOSHIBA, /* Toshiba M300 & co */ - CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ - CXT5051_AUTO, /* auto-parser */ - CXT5051_MODELS -}; - -static const char *const cxt5051_models[CXT5051_MODELS] = { - [CXT5051_LAPTOP] = "laptop", - [CXT5051_HP] = "hp", - [CXT5051_HP_DV6736] = "hp-dv6736", - [CXT5051_F700] = "hp-700", - [CXT5051_TOSHIBA] = "toshiba", - [CXT5051_IDEAPAD] = "ideapad", - [CXT5051_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), - SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), - SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), - SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA), - SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", - CXT5051_LAPTOP), - SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), - {} -}; - -static int patch_cxt5051(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, - cxt5051_models, - cxt5051_cfg_tbl); - if (board_config < 0) - board_config = CXT5051_AUTO; /* model=auto as default */ - if (board_config == CXT5051_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - codec->pin_amp_workaround = 1; - - codec->patch_ops = conexant_patch_ops; - codec->patch_ops.init = cxt5051_init; - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids); - spec->multiout.dac_nids = cxt5051_dac_nids; - spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; - spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ - spec->adc_nids = cxt5051_adc_nids; - spec->num_mixers = 2; - spec->mixers[0] = cxt5051_capture_mixers; - spec->mixers[1] = cxt5051_playback_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5051_init_verbs; - spec->spdif_route = 0; - spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes); - spec->channel_mode = cxt5051_modes; - spec->cur_adc = 0; - spec->cur_adc_idx = 0; - - set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - - codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; - - spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; - switch (board_config) { - case CXT5051_HP: - spec->mixers[0] = cxt5051_hp_mixers; - break; - case CXT5051_HP_DV6736: - spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; - spec->mixers[0] = cxt5051_hp_dv6736_mixers; - spec->auto_mic = 0; - break; - case CXT5051_F700: - spec->init_verbs[0] = cxt5051_f700_init_verbs; - spec->mixers[0] = cxt5051_f700_mixers; - spec->auto_mic = 0; - break; - case CXT5051_TOSHIBA: - spec->mixers[0] = cxt5051_toshiba_mixers; - spec->auto_mic = AUTO_MIC_PORTB; - break; - case CXT5051_IDEAPAD: - spec->init_verbs[spec->num_init_verbs++] = - cxt5051_ideapad_init_verbs; - spec->ideapad = 1; - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - -/* Conexant 5066 specific */ - -static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; -static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; -static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; -static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; - -static const struct hda_channel_mode cxt5066_modes[1] = { - { 2, NULL }, -}; - -#define HP_PRESENT_PORT_A (1 << 0) -#define HP_PRESENT_PORT_D (1 << 1) -#define hp_port_a_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_A) -#define hp_port_d_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_D) - -static void cxt5066_update_speaker(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int pinctl; - - codec_dbg(codec, - "CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n", - spec->hp_present, spec->cur_eapd); - - /* Port A (HP) */ - pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x19, pinctl); - - /* Port D (HP/LO) */ - pinctl = spec->cur_eapd ? spec->port_d_mode : 0; - if (spec->dell_automute || spec->thinkpad) { - /* Mute if Port A is connected */ - if (hp_port_a_present(spec)) - pinctl = 0; - } else { - /* Thinkpad/Dell doesn't give pin-D status */ - if (!hp_port_d_present(spec)) - pinctl = 0; - } - snd_hda_set_pin_ctl(codec, 0x1c, pinctl); - - /* CLASS_D AMP */ - pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1f, pinctl); -} - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - if (!cxt_eapd_put(kcontrol, ucontrol)) - return 0; - - cxt5066_update_speaker(codec); - return 1; -} - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_vostro_automic(struct hda_codec *codec) -{ - unsigned int present; - - struct hda_verb ext_mic_present[] = { - /* enable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - - /* switch to external mic input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - - /* disable internal digital mic */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - /* enable internal mic, port C */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* switch to internal mic input */ - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - - /* disable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - present = snd_hda_jack_detect(codec, 0x1a); - if (present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_ideapad_automic(struct hda_codec *codec) -{ - unsigned int present; - - struct hda_verb ext_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - present = snd_hda_jack_detect(codec, 0x1b); - if (present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_asus_automic(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x1b); - codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 1 : 0); -} - - -/* toggle input of built-in digital mic and mic jack appropriately */ -static void cxt5066_hp_laptop_automic(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x1b); - codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 1 : 3); -} - - -/* toggle input of built-in digital mic and mic jack appropriately - order is: external mic -> dock mic -> interal mic */ -static void cxt5066_thinkpad_automic(struct hda_codec *codec) -{ - unsigned int ext_present, dock_present; - - static const struct hda_verb ext_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb dock_mic_present[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - static const struct hda_verb ext_mic_absent[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {} - }; - - ext_present = snd_hda_jack_detect(codec, 0x1b); - dock_present = snd_hda_jack_detect(codec, 0x1a); - if (ext_present) { - codec_dbg(codec, "CXT5066: external microphone detected\n"); - snd_hda_sequence_write(codec, ext_mic_present); - } else if (dock_present) { - codec_dbg(codec, "CXT5066: dock microphone detected\n"); - snd_hda_sequence_write(codec, dock_mic_present); - } else { - codec_dbg(codec, "CXT5066: external microphone absent\n"); - snd_hda_sequence_write(codec, ext_mic_absent); - } -} - -/* mute internal speaker if HP is plugged */ -static void cxt5066_hp_automute(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int portA, portD; - - /* Port A */ - portA = snd_hda_jack_detect(codec, 0x19); - - /* Port D */ - portD = snd_hda_jack_detect(codec, 0x1c); - - spec->hp_present = portA ? HP_PRESENT_PORT_A : 0; - spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0; - codec_dbg(codec, "CXT5066: hp automute portA=%x portD=%x present=%d\n", - portA, portD, spec->hp_present); - cxt5066_update_speaker(codec); -} - -/* Dispatch the right mic autoswitch function */ -static void cxt5066_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - - if (spec->dell_vostro) - cxt5066_vostro_automic(codec); - else if (spec->ideapad) - cxt5066_ideapad_automic(codec); - else if (spec->thinkpad) - cxt5066_thinkpad_automic(codec); - else if (spec->hp_laptop) - cxt5066_hp_laptop_automic(codec); - else if (spec->asus) - cxt5066_asus_automic(codec); -} - -/* unsolicited event for jack sensing */ -static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) -{ - codec_dbg(codec, "CXT5066: unsol event %x (%x)\n", res, res >> 26); - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5066_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - cxt5066_automic(codec); - break; - } -} - - -static const struct hda_input_mux cxt5066_analog_mic_boost = { - .num_items = 5, - .items = { - { "0dB", 0 }, - { "10dB", 1 }, - { "20dB", 2 }, - { "30dB", 3 }, - { "40dB", 4 }, - }, -}; - -static void cxt5066_set_mic_boost(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | - cxt5066_analog_mic_boost.items[spec->mic_boost].index); - if (spec->ideapad || spec->thinkpad) { - /* adjust the internal mic as well...it is not through 0x17 */ - snd_hda_codec_write_cache(codec, 0x23, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT | - cxt5066_analog_mic_boost. - items[spec->mic_boost].index); - } -} - -static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo); -} - -static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->mic_boost; - return 0; -} - -static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; - unsigned int idx; - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - - spec->mic_boost = idx; - cxt5066_set_mic_boost(codec); - return 1; -} - -static void conexant_check_dig_outs(struct hda_codec *codec, - const hda_nid_t *dig_pins, - int num_pins) -{ - struct conexant_spec *spec = codec->spec; - hda_nid_t *nid_loc = &spec->multiout.dig_out_nid; - int i; - - for (i = 0; i < num_pins; i++, dig_pins++) { - unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins); - if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE) - continue; - if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1) - continue; - } -} - -static const struct hda_input_mux cxt5066_capture_source = { - .num_items = 4, - .items = { - { "Mic B", 0 }, - { "Mic C", 1 }, - { "Mic E", 2 }, - { "Mic F", 3 }, - }, -}; - -static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), - 0 - }, -}; - -static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), - 0 - }, -}; - -static const struct snd_kcontrol_new cxt5066_mixer_master[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), - {} -}; - -static const struct snd_kcontrol_new cxt5066_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5066_hp_master_sw_put, - .private_value = 0x1d, - }, - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Mic Boost Capture Enum", - .info = cxt5066_mic_boost_mux_enum_info, - .get = cxt5066_mic_boost_mux_enum_get, - .put = cxt5066_mic_boost_mux_enum_put, - }, - - HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), - HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others), - {} -}; - -static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Internal Mic Boost Capture Enum", - .info = cxt5066_mic_boost_mux_enum_info, - .get = cxt5066_mic_boost_mux_enum_get, - .put = cxt5066_mic_boost_mux_enum_put, - .private_value = 0x23 | 0x100, - }, - {} -}; - -static const struct hda_verb cxt5066_init_verbs[] = { - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* no digital microphone support yet */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - - /* SPDIF route: PCM */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* not handling these yet */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_vostro[] = { - /* Port A: headphones */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: external microphone */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: unused */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: unused */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port E: unused, but has primary EAPD */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* Port F: unused */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* DAC2: unused */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - - /* Digital microphone port */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* Audio input selectors */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - - /* Disable SPDIF */ - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* enable unsolicited events for Port A and B */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_ideapad[] = { - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ - - /* SPDIF route: PCM */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* internal microphone */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_thinkpad[] = { - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port A: HP, Amp */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: Mic Dock */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: Mic */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: HP Dock, Amp */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ - - /* Audio input selector */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, - {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ - - /* SPDIF route: PCM */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* internal microphone */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ - - /* EAPD */ - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* enable unsolicited events for Port A, B, C and D */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -static const struct hda_verb cxt5066_init_verbs_portd_lo[] = { - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { } /* end */ -}; - - -static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = { - {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - -/* initialize jack-sensing, too */ -static int cxt5066_init(struct hda_codec *codec) -{ - codec_dbg(codec, "CXT5066: init\n"); - conexant_init(codec); - if (codec->patch_ops.unsol_event) { - cxt5066_hp_automute(codec); - cxt5066_automic(codec); - } - cxt5066_set_mic_boost(codec); - return 0; -} - -enum { - CXT5066_LAPTOP, /* Laptops w/ EAPD support */ - CXT5066_DELL_LAPTOP, /* Dell Laptop */ - CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ - CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ - CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ - CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ - CXT5066_HP_LAPTOP, /* HP Laptop */ - CXT5066_AUTO, /* BIOS auto-parser */ - CXT5066_MODELS -}; - -static const char * const cxt5066_models[CXT5066_MODELS] = { - [CXT5066_LAPTOP] = "laptop", - [CXT5066_DELL_LAPTOP] = "dell-laptop", - [CXT5066_DELL_VOSTRO] = "dell-vostro", - [CXT5066_IDEAPAD] = "ideapad", - [CXT5066_THINKPAD] = "thinkpad", - [CXT5066_ASUS] = "asus", - [CXT5066_HP_LAPTOP] = "hp-laptop", - [CXT5066_AUTO] = "auto", -}; - -static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { - SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS), - SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS), - SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), - SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", - CXT5066_LAPTOP), - SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), - {} -}; - -static int patch_cxt5066(struct hda_codec *codec) -{ - struct conexant_spec *spec; - int board_config; - - board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, - cxt5066_models, cxt5066_cfg_tbl); - if (board_config < 0) - board_config = CXT5066_AUTO; /* model=auto as default */ - if (board_config == CXT5066_AUTO) - return patch_conexant_auto(codec); - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - codec->patch_ops = conexant_patch_ops; - codec->patch_ops.init = conexant_init; - - spec->dell_automute = 0; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); - spec->multiout.dac_nids = cxt5066_dac_nids; - conexant_check_dig_outs(codec, cxt5066_digout_pin_nids, - ARRAY_SIZE(cxt5066_digout_pin_nids)); - spec->num_adc_nids = 1; - spec->adc_nids = cxt5066_adc_nids; - spec->capsrc_nids = cxt5066_capsrc_nids; - spec->input_mux = &cxt5066_capture_source; - - spec->port_d_mode = PIN_HP; - - spec->num_init_verbs = 1; - spec->init_verbs[0] = cxt5066_init_verbs; - spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes); - spec->channel_mode = cxt5066_modes; - spec->cur_adc = 0; - spec->cur_adc_idx = 0; - - set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - - switch (board_config) { - default: - case CXT5066_LAPTOP: - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - break; - case CXT5066_DELL_LAPTOP: - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - - spec->port_d_mode = PIN_OUT; - spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo; - spec->num_init_verbs++; - spec->dell_automute = 1; - break; - case CXT5066_ASUS: - case CXT5066_HP_LAPTOP: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->init_verbs[spec->num_init_verbs] = - cxt5066_init_verbs_hp_laptop; - spec->num_init_verbs++; - spec->hp_laptop = board_config == CXT5066_HP_LAPTOP; - spec->asus = board_config == CXT5066_ASUS; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - /* no S/PDIF out */ - if (board_config == CXT5066_HP_LAPTOP) - spec->multiout.dig_out_nid = 0; - /* input source automatically selected */ - spec->input_mux = NULL; - spec->port_d_mode = 0; - spec->mic_boost = 3; /* default 30dB gain */ - break; - - case CXT5066_DELL_VOSTRO: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->init_verbs[0] = cxt5066_init_verbs_vostro; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; - spec->port_d_mode = 0; - spec->dell_vostro = 1; - spec->mic_boost = 3; /* default 30dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - case CXT5066_IDEAPAD: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->init_verbs[0] = cxt5066_init_verbs_ideapad; - spec->port_d_mode = 0; - spec->ideapad = 1; - spec->mic_boost = 2; /* default 20dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - case CXT5066_THINKPAD: - codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_unsol_event; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; - spec->thinkpad = 1; - spec->port_d_mode = PIN_OUT; - spec->mic_boost = 2; /* default 20dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - break; - } - - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); - - return 0; -} - -#endif /* ENABLE_CXT_STATIC_QUIRKS */ - - /* * Automatic parser for CX20641 & co */ @@ -3487,35 +881,28 @@ static int patch_conexant_auto(struct hda_codec *codec) return err; } -#ifndef ENABLE_CXT_STATIC_QUIRKS -#define patch_cxt5045 patch_conexant_auto -#define patch_cxt5047 patch_conexant_auto -#define patch_cxt5051 patch_conexant_auto -#define patch_cxt5066 patch_conexant_auto -#endif - /* */ static const struct hda_codec_preset snd_hda_preset_conexant[] = { { .id = 0x14f15045, .name = "CX20549 (Venice)", - .patch = patch_cxt5045 }, + .patch = patch_conexant_auto }, { .id = 0x14f15047, .name = "CX20551 (Waikiki)", - .patch = patch_cxt5047 }, + .patch = patch_conexant_auto }, { .id = 0x14f15051, .name = "CX20561 (Hermosa)", - .patch = patch_cxt5051 }, + .patch = patch_conexant_auto }, { .id = 0x14f15066, .name = "CX20582 (Pebble)", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15068, .name = "CX20584", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15069, .name = "CX20585", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f1506c, .name = "CX20588", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f1506e, .name = "CX20590", - .patch = patch_cxt5066 }, + .patch = patch_conexant_auto }, { .id = 0x14f15097, .name = "CX20631", .patch = patch_conexant_auto }, { .id = 0x14f15098, .name = "CX20632", diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index ba4ca52072ff..36badba2dcec 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -648,7 +648,8 @@ static int get_channel_allocation_order(int ca) * * TODO: it could select the wrong CA from multiple candidates. */ -static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) +static int hdmi_channel_allocation(struct hda_codec *codec, + struct hdmi_eld *eld, int channels) { int i; int ca = 0; @@ -694,7 +695,7 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) } snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf)); - snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", + codec_dbg(codec, "HDMI: select CA 0x%x for %d-channel allocation: %s\n", ca, channels, buf); return ca; @@ -1131,7 +1132,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, if (!non_pcm && per_pin->chmap_set) ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); else - ca = hdmi_channel_allocation(eld, channels); + ca = hdmi_channel_allocation(codec, eld, channels); if (ca < 0) ca = 0; @@ -1557,13 +1558,13 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) eld->eld_valid = false; else { memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld)); - if (snd_hdmi_parse_eld(&eld->info, eld->eld_buffer, + if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, eld->eld_size) < 0) eld->eld_valid = false; } if (eld->eld_valid) { - snd_hdmi_show_eld(&eld->info); + snd_hdmi_show_eld(codec, &eld->info); update_eld = true; } else if (repoll) { @@ -3355,6 +3356,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x80862808, .name = "Broadwell HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862882, .name = "Valleyview2 HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862883, .name = "Braswell HDMI", .patch = patch_generic_hdmi }, { .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, {} /* terminator */ }; @@ -3414,6 +3416,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862807"); MODULE_ALIAS("snd-hda-codec-id:80862808"); MODULE_ALIAS("snd-hda-codec-id:80862880"); MODULE_ALIAS("snd-hda-codec-id:80862882"); +MODULE_ALIAS("snd-hda-codec-id:80862883"); MODULE_ALIAS("snd-hda-codec-id:808629fb"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b60824e90408..654c8f16d150 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -101,6 +101,7 @@ struct alc_spec { /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */ int mute_led_polarity; hda_nid_t mute_led_nid; + hda_nid_t cap_mute_led_nid; unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */ @@ -3402,7 +3403,8 @@ static unsigned int led_power_filter(struct hda_codec *codec, { struct alc_spec *spec = codec->spec; - if (power_state != AC_PWRST_D3 || nid != spec->mute_led_nid) + if (power_state != AC_PWRST_D3 || nid == 0 || + (nid != spec->mute_led_nid && nid != spec->cap_mute_led_nid)) return power_state; /* Set pin ctl again, it might have just been set to 0 */ @@ -3520,6 +3522,68 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, } } +/* turn on/off mic-mute LED per capture hook */ +static void alc269_fixup_hp_cap_mic_mute_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct alc_spec *spec = codec->spec; + unsigned int pinval, enable, disable; + + pinval = snd_hda_codec_get_pin_target(codec, spec->cap_mute_led_nid); + pinval &= ~AC_PINCTL_VREFEN; + enable = pinval | AC_PINCTL_VREF_80; + disable = pinval | AC_PINCTL_VREF_HIZ; + + if (!ucontrol) + return; + + if (ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]) + pinval = disable; + else + pinval = enable; + + if (spec->cap_mute_led_nid) + snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval); +} + +static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x08 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x08 }, + {} + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook; + spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; + spec->gpio_led = 0; + spec->cap_mute_led_nid = 0x18; + snd_hda_add_verbs(codec, gpio_init); + codec->power_filter = led_power_filter; + } +} + +static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; + spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; + spec->mute_led_polarity = 0; + spec->mute_led_nid = 0x1a; + spec->cap_mute_led_nid = 0x18; + spec->gen.vmaster_mute_enum = 1; + codec->power_filter = led_power_filter; + } +} + static void alc_headset_mode_unplugged(struct hda_codec *codec) { int val; @@ -4231,6 +4295,9 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec, /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" +/* for dell wmi mic mute led */ +#include "dell_wmi_helper.c" + enum { ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, @@ -4255,6 +4322,8 @@ enum { ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC269_FIXUP_HP_MUTE_LED_MIC2, ALC269_FIXUP_HP_GPIO_LED, + ALC269_FIXUP_HP_GPIO_MIC1_LED, + ALC269_FIXUP_HP_LINE1_MIC1_LED, ALC269_FIXUP_INV_DMIC, ALC269_FIXUP_LENOVO_DOCK, ALC269_FIXUP_NO_SHUTUP, @@ -4292,6 +4361,8 @@ enum { ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC, ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_FIXUP_TPT440_DOCK, + ALC283_FIXUP_BXBT2807_MIC, + ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, }; static const struct hda_fixup alc269_fixups[] = { @@ -4447,6 +4518,14 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_hp_gpio_led, }, + [ALC269_FIXUP_HP_GPIO_MIC1_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_gpio_mic1_led, + }, + [ALC269_FIXUP_HP_LINE1_MIC1_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_line1_mic1_led, + }, [ALC269_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, @@ -4718,6 +4797,20 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST }, + [ALC283_FIXUP_BXBT2807_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x04a110f0 }, + { }, + }, + }, + [ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_dell_wmi, + .chained_before = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, + }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -4727,7 +4820,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), - SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), @@ -4761,10 +4853,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), + SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), @@ -4782,6 +4876,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), /* ALC282 */ + SND_PCI_QUIRK(0x103c, 0x21f8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4790,6 +4886,20 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2212, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2234, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2235, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224a, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x224d, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4814,13 +4924,43 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22da, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x8004, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), /* ALC290 */ + SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x221c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x221d, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2220, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2222, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2223, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2224, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2256, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2258, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2277, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4843,7 +4983,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -4864,9 +5003,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), - SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), + SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), @@ -4891,7 +5030,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), - SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI), SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ #if 0 @@ -4945,6 +5083,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { {} }; +static const struct snd_pci_quirk alc269_fixup_vendor_tbl[] = { + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), + SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI), + {} +}; + static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"}, {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"}, @@ -5040,6 +5186,17 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40700001}, {0x1e, 0x411111f0}, {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x03a11020}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40f41905}, + {0x1e, 0x411111f0}, + {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60130}, {0x14, 0x90170110}, @@ -5162,6 +5319,8 @@ static int patch_alc269(struct hda_codec *codec) snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); + snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl, + alc269_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); @@ -5858,6 +6017,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13), SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13), SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3744ea4e843d..ea823e1100da 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -84,6 +84,7 @@ enum { STAC_DELL_EQ, STAC_ALIENWARE_M17X, STAC_92HD89XX_HP_FRONT_JACK, + STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK, STAC_92HD73XX_MODELS }; @@ -103,6 +104,7 @@ enum { STAC_92HD83XXX_HP, STAC_HP_ENVY_BASS, STAC_HP_BNB13_EQ, + STAC_HP_ENVY_TS_BASS, STAC_92HD83XXX_MODELS }; @@ -1017,7 +1019,7 @@ static int stac_create_spdif_mux_ctls(struct hda_codec *codec) for (i = 0; i < num_cons; i++) { if (snd_BUG_ON(!labels[i])) return -EINVAL; - snd_hda_add_imux_item(&spec->spdif_mux, labels[i], i, NULL); + snd_hda_add_imux_item(codec, &spec->spdif_mux, labels[i], i, NULL); } kctl = snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_smux_mixer); @@ -1809,6 +1811,11 @@ static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = { {} }; +static const struct hda_pintbl stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs[] = { + { 0x0e, 0x400000f0 }, + {} +}; + static void stac92hd73xx_fixup_ref(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -1931,6 +1938,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = { [STAC_92HD89XX_HP_FRONT_JACK] = { .type = HDA_FIXUP_PINS, .v.pins = stac92hd89xx_hp_front_jack_pin_configs, + }, + [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs, } }; @@ -1991,6 +2002,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, "Alienware M17x R3", STAC_DELL_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927, + "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, "unknown HP", STAC_92HD89XX_HP_FRONT_JACK), {} /* terminator */ @@ -2668,6 +2681,13 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = { .chained = true, .chain_id = STAC_92HD83XXX_HP_MIC_LED, }, + [STAC_HP_ENVY_TS_BASS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x10, 0x92170111 }, + {} + }, + }, }; static const struct hda_model_fixup stac92hd83xxx_models[] = { @@ -2684,6 +2704,7 @@ static const struct hda_model_fixup stac92hd83xxx_models[] = { { .id = STAC_92HD83XXX_HEADSET_JACK, .name = "headset-jack" }, { .id = STAC_HP_ENVY_BASS, .name = "hp-envy-bass" }, { .id = STAC_HP_BNB13_EQ, .name = "hp-bnb13-eq" }, + { .id = STAC_HP_ENVY_TS_BASS, .name = "hp-envy-ts-bass" }, {} }; @@ -2739,6 +2760,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { "HP bNB13", STAC_HP_BNB13_EQ), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190A, "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190e, + "HP ENVY TS", STAC_HP_ENVY_TS_BASS), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1940, "HP bNB13", STAC_HP_BNB13_EQ), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1941, @@ -3438,9 +3461,11 @@ static void stac922x_fixup_intel_mac_auto(struct hda_codec *codec, { if (action != HDA_FIXUP_ACT_PRE_PROBE) return; + + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; snd_hda_pick_fixup(codec, NULL, stac922x_intel_mac_fixup_tbl, stac922x_fixups); - if (codec->fixup_id != STAC_INTEL_MAC_AUTO) + if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) snd_hda_apply_fixup(codec, action); } diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index b209fc30b334..58f8f2ae758d 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -41,14 +41,17 @@ #define ICEREG(ice, x) ((ice)->port + ICE1712_REG_##x) #define ICE1712_REG_CONTROL 0x00 /* byte */ -#define ICE1712_RESET 0x80 /* reset whole chip */ -#define ICE1712_SERR_LEVEL 0x04 /* SERR# level otherwise edge */ +#define ICE1712_RESET 0x80 /* soft reset whole chip */ +#define ICE1712_SERR_ASSERT_DS_DMA 0x40 /* disabled SERR# assertion for the DS DMA Ch-C irq otherwise enabled */ +#define ICE1712_DOS_VOL 0x10 /* DOS WT/FM volume control */ +#define ICE1712_SERR_LEVEL 0x08 /* SERR# level otherwise edge */ +#define ICE1712_SERR_ASSERT_SB 0x02 /* disabled SERR# assertion for SB irq otherwise enabled */ #define ICE1712_NATIVE 0x01 /* native mode otherwise SB */ #define ICE1712_REG_IRQMASK 0x01 /* byte */ -#define ICE1712_IRQ_MPU1 0x80 -#define ICE1712_IRQ_TIMER 0x40 -#define ICE1712_IRQ_MPU2 0x20 -#define ICE1712_IRQ_PROPCM 0x10 +#define ICE1712_IRQ_MPU1 0x80 /* MIDI irq mask */ +#define ICE1712_IRQ_TIMER 0x40 /* Timer mask */ +#define ICE1712_IRQ_MPU2 0x20 /* Secondary MIDI irq mask */ +#define ICE1712_IRQ_PROPCM 0x10 /* professional multi-track */ #define ICE1712_IRQ_FM 0x08 /* FM/MIDI - legacy */ #define ICE1712_IRQ_PBKDS 0x04 /* playback DS channels */ #define ICE1712_IRQ_CONCAP 0x02 /* consumer capture */ diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index 71f4bdcc4055..84f67450924e 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -151,13 +151,11 @@ static int send_msg( struct mixart_mgr *mgr, { u32 headptr, tailptr; u32 msg_frame_address; - int err, i; + int i; if (snd_BUG_ON(msg->size % 4)) return -EINVAL; - err = 0; - /* get message frame address */ tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL)); headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD)); diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 64b9fda5f04a..dbbbacfd535e 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -53,6 +53,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, { OXYGEN_PCI_SUBID(0x1043, 0x8522) }, + { OXYGEN_PCI_SUBID(0x1043, 0x85f4) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index c8c7f2c9b355..e02605931669 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -100,8 +100,8 @@ */ /* - * Xonar Essence ST (Deluxe)/STX - * ----------------------------- + * Xonar Essence ST (Deluxe)/STX (II) + * ---------------------------------- * * CMI8788: * @@ -1138,6 +1138,14 @@ int get_xonar_pcm179x_model(struct oxygen *chip, chip->model.resume = xonar_stx_resume; chip->model.set_dac_params = set_pcm1796_params; break; + case 0x85f4: + chip->model = model_xonar_st; + /* TODO: daughterboard support */ + chip->model.shortname = "Xonar STX II"; + chip->model.init = xonar_stx_init; + chip->model.resume = xonar_stx_resume; + chip->model.set_dac_params = set_pcm1796_params; + break; default: return -EINVAL; } diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index b4a8278241b1..f0315c3f7de4 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -941,7 +941,7 @@ setmixer(struct cmdif *cif, short num, unsigned short rval, unsigned short lval) union cmdret rptr = CMDRET_ZERO; int i = 0; - snd_printdd("sent mixer %d: 0x%d 0x%d\n", num, rval, lval); + snd_printdd("sent mixer %d: 0x%x 0x%x\n", num, rval, lval); do { SEND_SDGV(cif, num, num, rval, lval); SEND_RDGV(cif, num, num, &rptr); @@ -1080,7 +1080,7 @@ getmixer(struct cmdif *cif, short num, unsigned short *rval, return -EIO; *rval = rptr.retwords[0]; *lval = rptr.retwords[1]; - snd_printdd("got mixer %d: 0x%d 0x%d\n", num, *rval, *lval); + snd_printdd("got mixer %d: 0x%x 0x%x\n", num, *rval, *lval); return 0; } diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 1272c18a2544..da875dced2ef 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3880,14 +3880,12 @@ void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voi { unsigned long flags; void (*private_free)(struct snd_trident_voice *); - void *private_data; if (voice == NULL || !voice->use) return; snd_trident_clear_voices(trident, voice->number, voice->number); spin_lock_irqsave(&trident->voice_alloc, flags); private_free = voice->private_free; - private_data = voice->private_data; voice->private_free = NULL; voice->private_data = NULL; if (voice->pcm) diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 3102a579660b..04c474658e3c 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -139,12 +139,11 @@ static inline void *offset_ptr(struct snd_trident *trident, int offset) static struct snd_util_memblk * search_empty(struct snd_util_memhdr *hdr, int size) { - struct snd_util_memblk *blk, *prev; + struct snd_util_memblk *blk; int page, psize; struct list_head *p; psize = get_aligned_page(size + ALIGN_PAGE_SIZE -1); - prev = NULL; page = 0; list_for_each(p, &hdr->block) { blk = list_entry(p, struct snd_util_memblk, list); diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 0060b31cc3f3..0e9623368ab0 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -47,6 +47,7 @@ source "sound/soc/kirkwood/Kconfig" source "sound/soc/intel/Kconfig" source "sound/soc/mxs/Kconfig" source "sound/soc/pxa/Kconfig" +source "sound/soc/rockchip/Kconfig" source "sound/soc/samsung/Kconfig" source "sound/soc/s6000/Kconfig" source "sound/soc/sh/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 5f1df02984f8..534714a1ca44 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_SND_SOC) += nuc900/ obj-$(CONFIG_SND_SOC) += omap/ obj-$(CONFIG_SND_SOC) += kirkwood/ obj-$(CONFIG_SND_SOC) += pxa/ +obj-$(CONFIG_SND_SOC) += rockchip/ obj-$(CONFIG_SND_SOC) += samsung/ obj-$(CONFIG_SND_SOC) += s6000/ obj-$(CONFIG_SND_SOC) += sh/ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index de433cfd044c..f403f399808a 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -347,6 +347,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, u32 tfmr, rfmr, tcmr, rcmr; int start_event; int ret; + int fslen, fslen_ext; /* * Currently, there is only one set of dma params for @@ -388,18 +389,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, } /* - * The SSC only supports up to 16-bit samples in I2S format, due - * to the size of the Frame Mode Register FSLEN field. - */ - if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S - && bits > 16) { - printk(KERN_WARNING - "atmel_ssc_dai: sample size %d " - "is too large for I2S\n", bits); - return -EINVAL; - } - - /* * Compute SSC register settings. */ switch (ssc_p->daifmt @@ -413,6 +402,17 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, * from the MCK divider, and the BCLK signal * is output on the SSC TK line. */ + + if (bits > 16 && !ssc->pdata->has_fslen_ext) { + dev_err(dai->dev, + "sample size %d is too large for SSC device\n", + bits); + return -EINVAL; + } + + fslen_ext = (bits - 1) / 16; + fslen = (bits - 1) % 16; + rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, SSC_START_FALLING_RF) @@ -420,9 +420,10 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) + | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(RFMR_FSLEN, (bits - 1)) + | SSC_BF(RFMR_FSLEN, fslen) | SSC_BF(RFMR_DATNB, (channels - 1)) | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_LOOP, 0) @@ -435,10 +436,11 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) + | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSDEN, 0) | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(TFMR_FSLEN, (bits - 1)) + | SSC_BF(TFMR_FSLEN, fslen) | SSC_BF(TFMR_DATNB, (channels - 1)) | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATDEF, 0) diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index b4e36901a40b..4052268ce462 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -18,10 +18,6 @@ #include "../codecs/wm8904.h" #include "atmel_ssc_dai.h" -#define MCLK_RATE 32768 - -static struct clk *mclk; - static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Mic", NULL), @@ -61,26 +57,6 @@ static struct snd_soc_ops atmel_asoc_wm8904_ops = { .hw_params = atmel_asoc_wm8904_hw_params, }; -static int atmel_set_bias_level(struct snd_soc_card *card, - struct snd_soc_dapm_context *dapm, - enum snd_soc_bias_level level) -{ - if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { - switch (level) { - case SND_SOC_BIAS_PREPARE: - clk_prepare_enable(mclk); - break; - case SND_SOC_BIAS_OFF: - clk_disable_unprepare(mclk); - break; - default: - break; - } - } - - return 0; -}; - static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = { .name = "WM8904", .stream_name = "WM8904 PCM", @@ -94,7 +70,6 @@ static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = { static struct snd_soc_card atmel_asoc_wm8904_card = { .name = "atmel_asoc_wm8904", .owner = THIS_MODULE, - .set_bias_level = atmel_set_bias_level, .dai_link = &atmel_asoc_wm8904_dailink, .num_links = 1, .dapm_widgets = atmel_asoc_wm8904_dapm_widgets, @@ -153,7 +128,6 @@ static int atmel_asoc_wm8904_probe(struct platform_device *pdev) { struct snd_soc_card *card = &atmel_asoc_wm8904_card; struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; - struct clk *clk_src; int id, ret; card->dev = &pdev->dev; @@ -170,30 +144,6 @@ static int atmel_asoc_wm8904_probe(struct platform_device *pdev) return ret; } - mclk = clk_get(NULL, "pck0"); - if (IS_ERR(mclk)) { - dev_err(&pdev->dev, "failed to get pck0\n"); - ret = PTR_ERR(mclk); - goto err_set_audio; - } - - clk_src = clk_get(NULL, "clk32k"); - if (IS_ERR(clk_src)) { - dev_err(&pdev->dev, "failed to get clk32k\n"); - ret = PTR_ERR(clk_src); - goto err_set_audio; - } - - ret = clk_set_parent(mclk, clk_src); - clk_put(clk_src); - if (ret != 0) { - dev_err(&pdev->dev, "failed to set MCLK parent\n"); - goto err_set_audio; - } - - dev_info(&pdev->dev, "setting pck0 to %dHz\n", MCLK_RATE); - clk_set_rate(mclk, MCLK_RATE); - ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed\n"); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 986dcec79fa0..84f31e1f9d24 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -79,28 +79,28 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, unsigned short retry, tmo; unsigned long data; - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + wmb(); /* drain writebuffer */ retry = AC97_RW_RETRIES; do { mutex_lock(&pscdata->lock); - au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), + __raw_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), AC97_CDC(pscdata)); - au_sync(); + wmb(); /* drain writebuffer */ tmo = 20; do { udelay(21); - if (au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) + if (__raw_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) break; } while (--tmo); - data = au_readl(AC97_CDC(pscdata)); + data = __raw_readl(AC97_CDC(pscdata)); - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + wmb(); /* drain writebuffer */ mutex_unlock(&pscdata->lock); @@ -119,26 +119,26 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97); unsigned int tmo, retry; - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + wmb(); /* drain writebuffer */ retry = AC97_RW_RETRIES; do { mutex_lock(&pscdata->lock); - au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), + __raw_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), AC97_CDC(pscdata)); - au_sync(); + wmb(); /* drain writebuffer */ tmo = 20; do { udelay(21); - if (au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) + if (__raw_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) break; } while (--tmo); - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + __raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + wmb(); /* drain writebuffer */ mutex_unlock(&pscdata->lock); } while (--retry && !tmo); @@ -149,11 +149,11 @@ static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97) { struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97); - au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata)); - au_sync(); + __raw_writel(PSC_AC97RST_SNC, AC97_RST(pscdata)); + wmb(); /* drain writebuffer */ msleep(10); - au_writel(0, AC97_RST(pscdata)); - au_sync(); + __raw_writel(0, AC97_RST(pscdata)); + wmb(); /* drain writebuffer */ } static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) @@ -162,25 +162,25 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) int i; /* disable PSC during cold reset */ - au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ /* issue cold reset */ - au_writel(PSC_AC97RST_RST, AC97_RST(pscdata)); - au_sync(); + __raw_writel(PSC_AC97RST_RST, AC97_RST(pscdata)); + wmb(); /* drain writebuffer */ msleep(500); - au_writel(0, AC97_RST(pscdata)); - au_sync(); + __raw_writel(0, AC97_RST(pscdata)); + wmb(); /* drain writebuffer */ /* enable PSC */ - au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ /* wait for PSC to indicate it's ready */ i = 1000; - while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) + while (!((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) msleep(1); if (i == 0) { @@ -189,12 +189,12 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) } /* enable the ac97 function */ - au_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); + __raw_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* wait for AC97 core to become ready */ i = 1000; - while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) + while (!((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) msleep(1); if (i == 0) printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n"); @@ -218,8 +218,8 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, chans = params_channels(params); - r = ro = au_readl(AC97_CFG(pscdata)); - stat = au_readl(AC97_STAT(pscdata)); + r = ro = __raw_readl(AC97_CFG(pscdata)); + stat = __raw_readl(AC97_STAT(pscdata)); /* already active? */ if (stat & (PSC_AC97STAT_TB | PSC_AC97STAT_RB)) { @@ -252,28 +252,28 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, mutex_lock(&pscdata->lock); /* disable AC97 device controller first... */ - au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); + __raw_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* ...wait for it... */ t = 100; - while ((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) && --t) + while ((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) && --t) msleep(1); if (!t) printk(KERN_ERR "PSC-AC97: can't disable!\n"); /* ...write config... */ - au_writel(r, AC97_CFG(pscdata)); - au_sync(); + __raw_writel(r, AC97_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* ...enable the AC97 controller again... */ - au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); + __raw_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* ...and wait for ready bit */ t = 100; - while ((!(au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && --t) + while ((!(__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && --t) msleep(1); if (!t) @@ -300,21 +300,21 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - au_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); - au_sync(); - au_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); - au_sync(); + __raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); + wmb(); /* drain writebuffer */ + __raw_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); + wmb(); /* drain writebuffer */ break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); - au_sync(); + __raw_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); + wmb(); /* drain writebuffer */ - while (au_readl(AC97_STAT(pscdata)) & AC97STAT_BUSY(stype)) + while (__raw_readl(AC97_STAT(pscdata)) & AC97STAT_BUSY(stype)) asm volatile ("nop"); - au_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); - au_sync(); + __raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); + wmb(); /* drain writebuffer */ break; default: @@ -398,13 +398,13 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) PSC_AC97CFG_DE_ENABLE; /* preserve PSC clock source set up by platform */ - sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); - au_writel(0, PSC_SEL(wd)); - au_sync(); - au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd)); - au_sync(); + sel = __raw_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(0, PSC_SEL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd)); + wmb(); /* drain writebuffer */ /* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */ memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template, @@ -433,10 +433,10 @@ static int au1xpsc_ac97_drvremove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); /* disable PSC completely */ - au_writel(0, AC97_CFG(wd)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); + __raw_writel(0, AC97_CFG(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ au1xpsc_ac97_workdata = NULL; /* MDEV */ @@ -449,12 +449,12 @@ static int au1xpsc_ac97_drvsuspend(struct device *dev) struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); /* save interesting registers and disable PSC */ - wd->pm[0] = au_readl(PSC_SEL(wd)); + wd->pm[0] = __raw_readl(PSC_SEL(wd)); - au_writel(0, AC97_CFG(wd)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); + __raw_writel(0, AC97_CFG(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ return 0; } @@ -464,8 +464,8 @@ static int au1xpsc_ac97_drvresume(struct device *dev) struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); /* restore PSC clock config */ - au_writel(wd->pm[0] | PSC_SEL_PS_AC97MODE, PSC_SEL(wd)); - au_sync(); + __raw_writel(wd->pm[0] | PSC_SEL_PS_AC97MODE, PSC_SEL(wd)); + wmb(); /* drain writebuffer */ /* after this point the ac97 core will cold-reset the codec. * During cold-reset the PSC is reinitialized and the last diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index fe923a7bdc39..814beffc56f2 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -120,10 +120,10 @@ static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream, unsigned long stat; /* check if the PSC is already streaming data */ - stat = au_readl(I2S_STAT(pscdata)); + stat = __raw_readl(I2S_STAT(pscdata)); if (stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB)) { /* reject parameters not currently set up in hardware */ - cfgbits = au_readl(I2S_CFG(pscdata)); + cfgbits = __raw_readl(I2S_CFG(pscdata)); if ((PSC_I2SCFG_GET_LEN(cfgbits) != params->msbits) || (params_rate(params) != pscdata->rate)) return -EINVAL; @@ -149,33 +149,33 @@ static int au1xpsc_i2s_configure(struct au1xpsc_audio_data *pscdata) unsigned long tmo; /* bring PSC out of sleep, and configure I2S unit */ - au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ tmo = 1000000; - while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_SR) && tmo) + while (!(__raw_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_SR) && tmo) tmo--; if (!tmo) goto psc_err; - au_writel(0, I2S_CFG(pscdata)); - au_sync(); - au_writel(pscdata->cfg | PSC_I2SCFG_DE_ENABLE, I2S_CFG(pscdata)); - au_sync(); + __raw_writel(0, I2S_CFG(pscdata)); + wmb(); /* drain writebuffer */ + __raw_writel(pscdata->cfg | PSC_I2SCFG_DE_ENABLE, I2S_CFG(pscdata)); + wmb(); /* drain writebuffer */ /* wait for I2S controller to become ready */ tmo = 1000000; - while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_DR) && tmo) + while (!(__raw_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_DR) && tmo) tmo--; if (tmo) return 0; psc_err: - au_writel(0, I2S_CFG(pscdata)); - au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(0, I2S_CFG(pscdata)); + __raw_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ return -ETIMEDOUT; } @@ -187,26 +187,26 @@ static int au1xpsc_i2s_start(struct au1xpsc_audio_data *pscdata, int stype) ret = 0; /* if both TX and RX are idle, configure the PSC */ - stat = au_readl(I2S_STAT(pscdata)); + stat = __raw_readl(I2S_STAT(pscdata)); if (!(stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB))) { ret = au1xpsc_i2s_configure(pscdata); if (ret) goto out; } - au_writel(I2SPCR_CLRFIFO(stype), I2S_PCR(pscdata)); - au_sync(); - au_writel(I2SPCR_START(stype), I2S_PCR(pscdata)); - au_sync(); + __raw_writel(I2SPCR_CLRFIFO(stype), I2S_PCR(pscdata)); + wmb(); /* drain writebuffer */ + __raw_writel(I2SPCR_START(stype), I2S_PCR(pscdata)); + wmb(); /* drain writebuffer */ /* wait for start confirmation */ tmo = 1000000; - while (!(au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) + while (!(__raw_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) tmo--; if (!tmo) { - au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); - au_sync(); + __raw_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); + wmb(); /* drain writebuffer */ ret = -ETIMEDOUT; } out: @@ -217,21 +217,21 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype) { unsigned long tmo, stat; - au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); - au_sync(); + __raw_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); + wmb(); /* drain writebuffer */ /* wait for stop confirmation */ tmo = 1000000; - while ((au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) + while ((__raw_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) tmo--; /* if both TX and RX are idle, disable PSC */ - stat = au_readl(I2S_STAT(pscdata)); + stat = __raw_readl(I2S_STAT(pscdata)); if (!(stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB))) { - au_writel(0, I2S_CFG(pscdata)); - au_sync(); - au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); - au_sync(); + __raw_writel(0, I2S_CFG(pscdata)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); + wmb(); /* drain writebuffer */ } return 0; } @@ -332,12 +332,12 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) /* preserve PSC clock source set up by platform (dev.platform_data * is already occupied by soc layer) */ - sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); - au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(wd)); - au_writel(0, I2S_CFG(wd)); - au_sync(); + sel = __raw_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(wd)); + __raw_writel(0, I2S_CFG(wd)); + wmb(); /* drain writebuffer */ /* preconfigure: set max rx/tx fifo depths */ wd->cfg |= PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8; @@ -364,10 +364,10 @@ static int au1xpsc_i2s_drvremove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); - au_writel(0, I2S_CFG(wd)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); + __raw_writel(0, I2S_CFG(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ return 0; } @@ -378,12 +378,12 @@ static int au1xpsc_i2s_drvsuspend(struct device *dev) struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); /* save interesting register and disable PSC */ - wd->pm[0] = au_readl(PSC_SEL(wd)); + wd->pm[0] = __raw_readl(PSC_SEL(wd)); - au_writel(0, I2S_CFG(wd)); - au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); + __raw_writel(0, I2S_CFG(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ return 0; } @@ -393,12 +393,12 @@ static int au1xpsc_i2s_drvresume(struct device *dev) struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); /* select I2S mode and PSC clock */ - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); - au_sync(); - au_writel(0, PSC_SEL(wd)); - au_sync(); - au_writel(wd->pm[0], PSC_SEL(wd)); - au_sync(); + __raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(0, PSC_SEL(wd)); + wmb(); /* drain writebuffer */ + __raw_writel(wd->pm[0], PSC_SEL(wd)); + wmb(); /* drain writebuffer */ return 0; } diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h index b16b2e02e0c9..74dffeb641fa 100644 --- a/sound/soc/au1x/psc.h +++ b/sound/soc/au1x/psc.h @@ -27,16 +27,16 @@ struct au1xpsc_audio_data { }; /* easy access macros */ -#define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET) -#define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET) -#define I2S_STAT(x) ((unsigned long)((x)->mmio) + PSC_I2SSTAT_OFFSET) -#define I2S_CFG(x) ((unsigned long)((x)->mmio) + PSC_I2SCFG_OFFSET) -#define I2S_PCR(x) ((unsigned long)((x)->mmio) + PSC_I2SPCR_OFFSET) -#define AC97_CFG(x) ((unsigned long)((x)->mmio) + PSC_AC97CFG_OFFSET) -#define AC97_CDC(x) ((unsigned long)((x)->mmio) + PSC_AC97CDC_OFFSET) -#define AC97_EVNT(x) ((unsigned long)((x)->mmio) + PSC_AC97EVNT_OFFSET) -#define AC97_PCR(x) ((unsigned long)((x)->mmio) + PSC_AC97PCR_OFFSET) -#define AC97_RST(x) ((unsigned long)((x)->mmio) + PSC_AC97RST_OFFSET) -#define AC97_STAT(x) ((unsigned long)((x)->mmio) + PSC_AC97STAT_OFFSET) +#define PSC_CTRL(x) ((x)->mmio + PSC_CTRL_OFFSET) +#define PSC_SEL(x) ((x)->mmio + PSC_SEL_OFFSET) +#define I2S_STAT(x) ((x)->mmio + PSC_I2SSTAT_OFFSET) +#define I2S_CFG(x) ((x)->mmio + PSC_I2SCFG_OFFSET) +#define I2S_PCR(x) ((x)->mmio + PSC_I2SPCR_OFFSET) +#define AC97_CFG(x) ((x)->mmio + PSC_AC97CFG_OFFSET) +#define AC97_CDC(x) ((x)->mmio + PSC_AC97CDC_OFFSET) +#define AC97_EVNT(x) ((x)->mmio + PSC_AC97EVNT_OFFSET) +#define AC97_PCR(x) ((x)->mmio + PSC_AC97PCR_OFFSET) +#define AC97_RST(x) ((x)->mmio + PSC_AC97RST_OFFSET) +#define AC97_STAT(x) ((x)->mmio + PSC_AC97STAT_OFFSET) #endif diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index a3881c4381c9..bcf591373a7a 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -290,19 +290,19 @@ static int bf5xx_pcm_silence(struct snd_pcm_substream *substream, unsigned int sample_size = runtime->sample_bits / 8; void *buf = runtime->dma_area; struct bf5xx_i2s_pcm_data *dma_data; - unsigned int offset, size; + unsigned int offset, samples; dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (dma_data->tdm_mode) { offset = pos * 8 * sample_size; - size = count * 8 * sample_size; + samples = count * 8; } else { offset = frames_to_bytes(runtime, pos); - size = frames_to_bytes(runtime, count); + samples = count * runtime->channels; } - snd_pcm_format_set_silence(runtime->format, buf + offset, size); + snd_pcm_format_set_silence(runtime->format, buf + offset, samples); return 0; } diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 3c4b10ff48c1..922006dd0583 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -945,11 +945,11 @@ static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream, unsigned char inf = 0, mask = 0; /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: inf &= ~PCM_INF2_18WL; break; - case SNDRV_PCM_FORMAT_S18_3LE: + case 18: inf |= PCM_INF2_18WL; break; default: @@ -1044,11 +1044,11 @@ static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream, unsigned char inf; /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: inf = 0; break; - case SNDRV_PCM_FORMAT_S18_3LE: + case 18: inf = PCM_INF2_18WL; break; default: diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0b9571c858f8..8838838e25ed 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -47,6 +47,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS42L52 if I2C && INPUT select SND_SOC_CS42L56 if I2C && INPUT select SND_SOC_CS42L73 if I2C + select SND_SOC_CS4265 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI select SND_SOC_CS42XX8_I2C if I2C @@ -74,10 +75,12 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM3008 select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER + select SND_SOC_RT286 if I2C select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C select SND_SOC_RT5645 if I2C select SND_SOC_RT5651 if I2C + select SND_SOC_RT5670 if I2C select SND_SOC_RT5677 if I2C select SND_SOC_SGTL5000 if I2C select SND_SOC_SI476X if MFD_SI476X_CORE @@ -91,6 +94,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STA350 if I2C select SND_SOC_STA529 if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS + select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -338,6 +342,11 @@ config SND_SOC_CS42L73 tristate "Cirrus Logic CS42L73 CODEC" depends on I2C +config SND_SOC_CS4265 + tristate "Cirrus Logic CS4265 CODEC" + depends on I2C + select REGMAP_I2C + # Cirrus Logic CS4270 Codec config SND_SOC_CS4270 tristate "Cirrus Logic CS4270 CODEC" @@ -445,9 +454,16 @@ config SND_SOC_RL6231 default y if SND_SOC_RT5640=y default y if SND_SOC_RT5645=y default y if SND_SOC_RT5651=y + default y if SND_SOC_RT5670=y + default y if SND_SOC_RT5677=y default m if SND_SOC_RT5640=m default m if SND_SOC_RT5645=m default m if SND_SOC_RT5651=m + default m if SND_SOC_RT5670=m + default m if SND_SOC_RT5677=m + +config SND_SOC_RT286 + tristate config SND_SOC_RT5631 tristate @@ -461,6 +477,9 @@ config SND_SOC_RT5645 config SND_SOC_RT5651 tristate +config SND_SOC_RT5670 + tristate + config SND_SOC_RT5677 tristate @@ -521,6 +540,10 @@ config SND_SOC_STA529 config SND_SOC_STAC9766 tristate +config SND_SOC_TAS2552 + tristate "Texas Instruments TAS2552 Mono Audio amplifier" + depends on I2C + config SND_SOC_TAS5086 tristate "Texas Instruments TAS5086 speaker amplifier" depends on I2C @@ -541,7 +564,9 @@ config SND_SOC_TLV320AIC26 depends on SPI config SND_SOC_TLV320AIC31XX - tristate + tristate "Texas Instruments TLV320AIC31xx CODECs" + depends on I2C + select REGMAP_I2C config SND_SOC_TLV320AIC32X4 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1bd6e1cf6f82..20afe0f0c5be 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -37,6 +37,7 @@ snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o snd-soc-cs42l56-objs := cs42l56.o snd-soc-cs42l73-objs := cs42l73.o +snd-soc-cs4265-objs := cs4265.o snd-soc-cs4270-objs := cs4270.o snd-soc-cs4271-objs := cs4271.o snd-soc-cs42xx8-objs := cs42xx8.o @@ -68,10 +69,12 @@ snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o snd-soc-rl6231-objs := rl6231.o +snd-soc-rt286-objs := rt286.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o +snd-soc-rt5670-objs := rt5670.o snd-soc-rt5677-objs := rt5677.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o @@ -162,6 +165,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o # Amp snd-soc-max9877-objs := max9877.o snd-soc-tpa6130a2-objs := tpa6130a2.o +snd-soc-tas2552-objs := tas2552.o obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o @@ -204,6 +208,7 @@ obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o +obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o @@ -235,10 +240,12 @@ obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o +obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o +obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o @@ -255,6 +262,7 @@ obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o +obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 8d9ba4ba4bfe..e889e1b84192 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -89,8 +89,8 @@ static int ac97_soc_probe(struct snd_soc_codec *codec) int ret; /* add codec as bus device for standard ac97 */ - ret = snd_ac97_bus(codec->card->snd_card, 0, soc_ac97_ops, NULL, - &ac97_bus); + ret = snd_ac97_bus(codec->component.card->snd_card, 0, soc_ac97_ops, + NULL, &ac97_bus); if (ret < 0) return ret; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index d71c59cf7bdd..370b742117ef 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -230,8 +230,10 @@ static int adau1701_reg_read(void *context, unsigned int reg, *value = 0; - for (i = 0; i < size; i++) - *value |= recv_buf[i] << (i * 8); + for (i = 0; i < size; i++) { + *value <<= 8; + *value |= recv_buf[i]; + } return 0; } diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 2961fae9670a..0b659704e60c 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -359,14 +359,14 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) return 0; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: val = ADAU17X1_SERIAL_PORT1_DELAY16; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: val = ADAU17X1_SERIAL_PORT1_DELAY8; break; - case SNDRV_PCM_FORMAT_S32_LE: + case 32: val = ADAU17X1_SERIAL_PORT1_DELAY0; break; default: diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index fd55da7cb9d4..70ab35744aba 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -968,7 +968,7 @@ int adau1977_probe(struct device *dev, struct regmap *regmap, if (adau1977->dvdd_reg) power_off_mask = ~0; else - power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN; + power_off_mask = (unsigned int)~ADAU1977_BLOCK_POWER_SAI_LDO_EN; ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, power_off_mask, 0x00); diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 3ba4c0f11418..041712592e29 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -547,7 +547,7 @@ static const struct ak4642_drvdata ak4648_drvdata = { .extended_frequencies = 1, }; -static struct of_device_id ak4642_of_match[]; +static const struct of_device_id ak4642_of_match[]; static int ak4642_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -593,7 +593,7 @@ static int ak4642_i2c_remove(struct i2c_client *client) return 0; } -static struct of_device_id ak4642_of_match[] = { +static const struct of_device_id ak4642_of_match[] = { { .compatible = "asahi-kasei,ak4642", .data = &ak4642_drvdata}, { .compatible = "asahi-kasei,ak4643", .data = &ak4643_drvdata}, { .compatible = "asahi-kasei,ak4648", .data = &ak4648_drvdata}, diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c index 72e953b2cb41..8107a1cac876 100644 --- a/sound/soc/codecs/ak5386.c +++ b/sound/soc/codecs/ak5386.c @@ -14,12 +14,18 @@ #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_device.h> +#include <linux/regulator/consumer.h> #include <sound/soc.h> #include <sound/pcm.h> #include <sound/initval.h> +static const char * const supply_names[] = { + "va", "vd" +}; + struct ak5386_priv { int reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; }; static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = { @@ -32,7 +38,42 @@ static const struct snd_soc_dapm_route ak5386_dapm_routes[] = { { "Capture", NULL, "AINR" }, }; +static int ak5386_soc_probe(struct snd_soc_codec *codec) +{ + struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); + return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); +} + +static int ak5386_soc_remove(struct snd_soc_codec *codec) +{ + struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); + return 0; +} + +#ifdef CONFIG_PM +static int ak5386_soc_suspend(struct snd_soc_codec *codec) +{ + struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); + return 0; +} + +static int ak5386_soc_resume(struct snd_soc_codec *codec) +{ + struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec); + return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); +} +#else +#define ak5386_soc_suspend NULL +#define ak5386_soc_resume NULL +#endif /* CONFIG_PM */ + static struct snd_soc_codec_driver soc_codec_ak5386 = { + .probe = ak5386_soc_probe, + .remove = ak5386_soc_remove, + .suspend = ak5386_soc_suspend, + .resume = ak5386_soc_resume, .dapm_widgets = ak5386_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets), .dapm_routes = ak5386_dapm_routes, @@ -122,6 +163,7 @@ static int ak5386_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ak5386_priv *priv; + int ret, i; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -130,6 +172,14 @@ static int ak5386_probe(struct platform_device *pdev) priv->reset_gpio = -EINVAL; dev_set_drvdata(dev, priv); + 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 < 0) + return ret; + if (of_match_device(of_match_ptr(ak5386_dt_ids), dev)) priv->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpio", 0); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 29e198f57d4c..bd41ee4da078 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -107,7 +107,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMU: val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3); - if (val & ARIZONA_SPK_SHUTDOWN_STS) { + if (val & ARIZONA_SPK_OVERHEAT_STS) { dev_crit(arizona->dev, "Speaker not enabled due to temperature\n"); return -EBUSY; @@ -159,7 +159,7 @@ static irqreturn_t arizona_thermal_warn(int irq, void *data) if (ret != 0) { dev_err(arizona->dev, "Failed to read thermal status: %d\n", ret); - } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) { + } else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) { dev_crit(arizona->dev, "Thermal warning\n"); } @@ -177,7 +177,7 @@ static irqreturn_t arizona_thermal_shutdown(int irq, void *data) if (ret != 0) { dev_err(arizona->dev, "Failed to read thermal status: %d\n", ret); - } else if (val & ARIZONA_SPK_SHUTDOWN_STS) { + } else if (val & ARIZONA_SPK_OVERHEAT_STS) { dev_crit(arizona->dev, "Thermal shutdown\n"); ret = regmap_update_bits(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, @@ -223,7 +223,7 @@ int arizona_init_spk(struct snd_soc_codec *codec) break; } - ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN, + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, "Thermal warning", arizona_thermal_warn, arizona); if (ret != 0) @@ -231,7 +231,7 @@ int arizona_init_spk(struct snd_soc_codec *codec) "Failed to get thermal warning IRQ: %d\n", ret); - ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN, + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, "Thermal shutdown", arizona_thermal_shutdown, arizona); if (ret != 0) @@ -243,6 +243,31 @@ int arizona_init_spk(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(arizona_init_spk); +static const struct snd_soc_dapm_route arizona_mono_routes[] = { + { "OUT1R", NULL, "OUT1L" }, + { "OUT2R", NULL, "OUT2L" }, + { "OUT3R", NULL, "OUT3L" }, + { "OUT4R", NULL, "OUT4L" }, + { "OUT5R", NULL, "OUT5L" }, + { "OUT6R", NULL, "OUT6L" }, +}; + +int arizona_init_mono(struct snd_soc_codec *codec) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + int i; + + for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) { + if (arizona->pdata.out_mono[i]) + snd_soc_dapm_add_routes(&codec->dapm, + &arizona_mono_routes[i], 1); + } + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_mono); + int arizona_init_gpio(struct snd_soc_codec *codec) { struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); @@ -1127,6 +1152,31 @@ static int arizona_startup(struct snd_pcm_substream *substream, constraint); } +static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, + unsigned int rate) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + struct reg_default dac_comp[] = { + { 0x80, 0x3 }, + { ARIZONA_DAC_COMP_1, 0 }, + { ARIZONA_DAC_COMP_2, 0 }, + { 0x80, 0x0 }, + }; + + mutex_lock(&codec->mutex); + + dac_comp[1].def = arizona->dac_comp_coeff; + if (rate >= 176400) + dac_comp[2].def = arizona->dac_comp_enabled; + + mutex_unlock(&codec->mutex); + + regmap_multi_reg_write(arizona->regmap, + dac_comp, + ARRAY_SIZE(dac_comp)); +} + static int arizona_hw_params_rate(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -1153,6 +1203,15 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream, switch (dai_priv->clk) { case ARIZONA_CLK_SYSCLK: + switch (priv->arizona->type) { + case WM5102: + arizona_wm5102_set_dac_comp(codec, + params_rate(params)); + break; + default: + break; + } + snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, ARIZONA_SAMPLE_RATE_1_MASK, sr_val); if (base) @@ -1175,6 +1234,27 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream, return 0; } +static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec, + int base, int bclk, int lrclk, int frame) +{ + int val; + + val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL); + if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK)) + return true; + + val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE); + if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK)) + return true; + + val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1); + if (frame != (val & (ARIZONA_AIF1TX_WL_MASK | + ARIZONA_AIF1TX_SLOT_LEN_MASK))) + return true; + + return false; +} + static int arizona_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -1185,26 +1265,40 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, int base = dai->driver->base; const int *rates; int i, ret, val; + int channels = params_channels(params); int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1]; + int tdm_width = arizona->tdm_width[dai->id - 1]; + int tdm_slots = arizona->tdm_slots[dai->id - 1]; int bclk, lrclk, wl, frame, bclk_target; + bool reconfig; + unsigned int aif_tx_state, aif_rx_state; if (params_rate(params) % 8000) rates = &arizona_44k1_bclk_rates[0]; else rates = &arizona_48k_bclk_rates[0]; - bclk_target = snd_soc_params_to_bclk(params); - if (chan_limit && chan_limit < params_channels(params)) { + if (tdm_slots) { + arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", + tdm_slots, tdm_width); + bclk_target = tdm_slots * tdm_width * params_rate(params); + channels = tdm_slots; + } else { + bclk_target = snd_soc_params_to_bclk(params); + } + + if (chan_limit && chan_limit < channels) { arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit); - bclk_target /= params_channels(params); + bclk_target /= channels; bclk_target *= chan_limit; } - /* Force stereo for I2S mode */ + /* Force multiple of 2 channels for I2S mode */ val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); - if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) { + if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) { arizona_aif_dbg(dai, "Forcing stereo mode\n"); - bclk_target *= 2; + bclk_target /= channels; + bclk_target *= channels + 1; } for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { @@ -1228,28 +1322,56 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, wl = snd_pcm_format_width(params_format(params)); frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; + reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame); + + if (reconfig) { + /* Save AIF TX/RX state */ + aif_tx_state = snd_soc_read(codec, + base + ARIZONA_AIF_TX_ENABLES); + aif_rx_state = snd_soc_read(codec, + base + ARIZONA_AIF_RX_ENABLES); + /* Disable AIF TX/RX before reconfiguring it */ + regmap_update_bits_async(arizona->regmap, + base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0); + regmap_update_bits(arizona->regmap, + base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0); + } + ret = arizona_hw_params_rate(substream, params, dai); if (ret != 0) - return ret; + goto restore_aif; - regmap_update_bits_async(arizona->regmap, - base + ARIZONA_AIF_BCLK_CTRL, - ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); - regmap_update_bits_async(arizona->regmap, - base + ARIZONA_AIF_TX_BCLK_RATE, - ARIZONA_AIF1TX_BCPF_MASK, lrclk); - regmap_update_bits_async(arizona->regmap, - base + ARIZONA_AIF_RX_BCLK_RATE, - ARIZONA_AIF1RX_BCPF_MASK, lrclk); - regmap_update_bits_async(arizona->regmap, - base + ARIZONA_AIF_FRAME_CTRL_1, - ARIZONA_AIF1TX_WL_MASK | - ARIZONA_AIF1TX_SLOT_LEN_MASK, frame); - regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2, - ARIZONA_AIF1RX_WL_MASK | - ARIZONA_AIF1RX_SLOT_LEN_MASK, frame); + if (reconfig) { + regmap_update_bits_async(arizona->regmap, + base + ARIZONA_AIF_BCLK_CTRL, + ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); + regmap_update_bits_async(arizona->regmap, + base + ARIZONA_AIF_TX_BCLK_RATE, + ARIZONA_AIF1TX_BCPF_MASK, lrclk); + regmap_update_bits_async(arizona->regmap, + base + ARIZONA_AIF_RX_BCLK_RATE, + ARIZONA_AIF1RX_BCPF_MASK, lrclk); + regmap_update_bits_async(arizona->regmap, + base + ARIZONA_AIF_FRAME_CTRL_1, + ARIZONA_AIF1TX_WL_MASK | + ARIZONA_AIF1TX_SLOT_LEN_MASK, frame); + regmap_update_bits(arizona->regmap, + base + ARIZONA_AIF_FRAME_CTRL_2, + ARIZONA_AIF1RX_WL_MASK | + ARIZONA_AIF1RX_SLOT_LEN_MASK, frame); + } - return 0; +restore_aif: + if (reconfig) { + /* Restore AIF TX/RX state */ + regmap_update_bits_async(arizona->regmap, + base + ARIZONA_AIF_TX_ENABLES, + 0xff, aif_tx_state); + regmap_update_bits(arizona->regmap, + base + ARIZONA_AIF_RX_ENABLES, + 0xff, aif_rx_state); + } + return ret; } static const char *arizona_dai_clk_str(int clk_id) @@ -1324,9 +1446,63 @@ static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate) ARIZONA_AIF1_TRI, reg); } +static void arizona_set_channels_to_mask(struct snd_soc_dai *dai, + unsigned int base, + int channels, unsigned int mask) +{ + struct snd_soc_codec *codec = dai->codec; + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + int slot, i; + + for (i = 0; i < channels; ++i) { + slot = ffs(mask) - 1; + if (slot < 0) + return; + + regmap_write(arizona->regmap, base + i, slot); + + mask &= ~(1 << slot); + } + + if (mask) + arizona_aif_warn(dai, "Too many channels in TDM mask\n"); +} + +static int arizona_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 arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + int base = dai->driver->base; + int rx_max_chan = dai->driver->playback.channels_max; + int tx_max_chan = dai->driver->capture.channels_max; + + /* Only support TDM for the physical AIFs */ + if (dai->id > ARIZONA_MAX_AIF) + return -ENOTSUPP; + + if (slots == 0) { + tx_mask = (1 << tx_max_chan) - 1; + rx_mask = (1 << rx_max_chan) - 1; + } + + arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3, + tx_max_chan, tx_mask); + arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11, + rx_max_chan, rx_mask); + + arizona->tdm_width[dai->id - 1] = slot_width; + arizona->tdm_slots[dai->id - 1] = slots; + + return 0; +} + const struct snd_soc_dai_ops arizona_dai_ops = { .startup = arizona_startup, .set_fmt = arizona_set_fmt, + .set_tdm_slot = arizona_set_tdm_slot, .hw_params = arizona_hw_params, .set_sysclk = arizona_dai_set_sysclk, .set_tristate = arizona_set_tristate, @@ -1400,6 +1576,12 @@ static int arizona_validate_fll(struct arizona_fll *fll, { unsigned int Fvco_min; + if (fll->fout && Fout != fll->fout) { + arizona_fll_err(fll, + "Can't change output on active FLL\n"); + return -EINVAL; + } + if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) { arizona_fll_err(fll, "Can't scale %dMHz in to <=13.5MHz\n", @@ -1478,6 +1660,10 @@ static int arizona_calc_fratio(struct arizona_fll *fll, while (div <= ARIZONA_FLL_MAX_REFDIV) { for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; ratio++) { + if ((ARIZONA_FLL_VCO_CORNER / 2) / + (fll->vco_mult * ratio) < Fref) + break; + if (target % (ratio * Fref)) { cfg->refdiv = refdiv; cfg->fratio = ratio - 1; @@ -1485,11 +1671,7 @@ static int arizona_calc_fratio(struct arizona_fll *fll, } } - for (ratio = init_ratio - 1; ratio >= 0; ratio--) { - if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < - Fref) - break; - + for (ratio = init_ratio - 1; ratio > 0; ratio--) { if (target % (ratio * Fref)) { cfg->refdiv = refdiv; cfg->fratio = ratio - 1; @@ -1616,7 +1798,7 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, ARIZONA_FLL1_CTRL_UPD | cfg->n); } -static bool arizona_is_enabled_fll(struct arizona_fll *fll) +static int arizona_is_enabled_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; unsigned int reg; @@ -1632,13 +1814,26 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) return reg & ARIZONA_FLL1_ENA; } -static void arizona_enable_fll(struct arizona_fll *fll) +static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; int ret; bool use_sync = false; + int already_enabled = arizona_is_enabled_fll(fll); struct arizona_fll_cfg cfg; + if (already_enabled < 0) + return already_enabled; + + if (already_enabled) { + /* Facilitate smooth refclk across the transition */ + regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7, + ARIZONA_FLL1_GAIN_MASK, 0); + regmap_update_bits_async(fll->arizona->regmap, fll->base + 1, + ARIZONA_FLL1_FREERUN, + ARIZONA_FLL1_FREERUN); + } + /* * If we have both REFCLK and SYNCCLK then enable both, * otherwise apply the SYNCCLK settings to REFCLK. @@ -1666,7 +1861,7 @@ static void arizona_enable_fll(struct arizona_fll *fll) ARIZONA_FLL1_SYNC_ENA, 0); } else { arizona_fll_err(fll, "No clocks provided\n"); - return; + return -EINVAL; } /* @@ -1681,25 +1876,29 @@ static void arizona_enable_fll(struct arizona_fll *fll) ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW); - if (!arizona_is_enabled_fll(fll)) + if (!already_enabled) pm_runtime_get(arizona->dev); /* Clear any pending completions */ try_wait_for_completion(&fll->ok); regmap_update_bits_async(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_FREERUN, 0); - regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (use_sync) regmap_update_bits_async(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); + if (already_enabled) + regmap_update_bits_async(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_FREERUN, 0); + ret = wait_for_completion_timeout(&fll->ok, msecs_to_jiffies(250)); if (ret == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); + + return 0; } static void arizona_disable_fll(struct arizona_fll *fll) @@ -1713,6 +1912,8 @@ static void arizona_disable_fll(struct arizona_fll *fll) ARIZONA_FLL1_ENA, 0, &change); regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, 0); + regmap_update_bits_async(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_FREERUN, 0); if (change) pm_runtime_put_autosuspend(arizona->dev); @@ -1721,7 +1922,7 @@ static void arizona_disable_fll(struct arizona_fll *fll) int arizona_set_fll_refclk(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { - int ret; + int ret = 0; if (fll->ref_src == source && fll->ref_freq == Fref) return 0; @@ -1736,17 +1937,17 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, fll->ref_freq = Fref; if (fll->fout && Fref > 0) { - arizona_enable_fll(fll); + ret = arizona_enable_fll(fll); } - return 0; + return ret; } EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { - int ret; + int ret = 0; if (fll->sync_src == source && fll->sync_freq == Fref && fll->fout == Fout) @@ -1768,13 +1969,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->sync_freq = Fref; fll->fout = Fout; - if (Fout) { - arizona_enable_fll(fll); - } else { + if (Fout) + ret = arizona_enable_fll(fll); + else arizona_disable_fll(fll); - } - return 0; + return ret; } EXPORT_SYMBOL_GPL(arizona_set_fll); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 05ae17f5bca3..942cfb197b6d 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -249,6 +249,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source, 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_dai(struct arizona_priv *priv, int dai); diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c new file mode 100644 index 000000000000..a20b30ca52c0 --- /dev/null +++ b/sound/soc/codecs/cs4265.c @@ -0,0 +1,682 @@ +/* + * cs4265.c -- CS4265 ALSA SoC audio driver + * + * Copyright 2014 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/gpio/consumer.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/platform_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 "cs4265.h" + +struct cs4265_private { + struct device *dev; + struct regmap *regmap; + struct gpio_desc *reset_gpio; + u8 format; + u32 sysclk; +}; + +static const struct reg_default cs4265_reg_defaults[] = { + { CS4265_PWRCTL, 0x0F }, + { CS4265_DAC_CTL, 0x08 }, + { CS4265_ADC_CTL, 0x00 }, + { CS4265_MCLK_FREQ, 0x00 }, + { CS4265_SIG_SEL, 0x40 }, + { CS4265_CHB_PGA_CTL, 0x00 }, + { CS4265_CHA_PGA_CTL, 0x00 }, + { CS4265_ADC_CTL2, 0x19 }, + { CS4265_DAC_CHA_VOL, 0x00 }, + { CS4265_DAC_CHB_VOL, 0x00 }, + { CS4265_DAC_CTL2, 0xC0 }, + { CS4265_SPDIF_CTL1, 0x00 }, + { CS4265_SPDIF_CTL2, 0x00 }, + { CS4265_INT_MASK, 0x00 }, + { CS4265_STATUS_MODE_MSB, 0x00 }, + { CS4265_STATUS_MODE_LSB, 0x00 }, +}; + +static bool cs4265_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS4265_PWRCTL: + case CS4265_DAC_CTL: + case CS4265_ADC_CTL: + case CS4265_MCLK_FREQ: + case CS4265_SIG_SEL: + case CS4265_CHB_PGA_CTL: + case CS4265_CHA_PGA_CTL: + case CS4265_ADC_CTL2: + case CS4265_DAC_CHA_VOL: + case CS4265_DAC_CHB_VOL: + case CS4265_DAC_CTL2: + case CS4265_SPDIF_CTL1: + case CS4265_SPDIF_CTL2: + case CS4265_INT_MASK: + case CS4265_STATUS_MODE_MSB: + case CS4265_STATUS_MODE_LSB: + return true; + default: + return false; + } +} + +static bool cs4265_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS4265_INT_STATUS: + return true; + default: + return false; + } +} + +static DECLARE_TLV_DB_SCALE(pga_tlv, -1200, 50, 0); + +static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 0); + +static const char * const digital_input_mux_text[] = { + "SDIN1", "SDIN2" +}; + +static SOC_ENUM_SINGLE_DECL(digital_input_mux_enum, CS4265_SIG_SEL, 7, + digital_input_mux_text); + +static const struct snd_kcontrol_new digital_input_mux = + SOC_DAPM_ENUM("Digital Input Mux", digital_input_mux_enum); + +static const char * const mic_linein_text[] = { + "MIC", "LINEIN" +}; + +static SOC_ENUM_SINGLE_DECL(mic_linein_enum, CS4265_ADC_CTL2, 0, + mic_linein_text); + +static const char * const cam_mode_text[] = { + "One Byte", "Two Byte" +}; + +static SOC_ENUM_SINGLE_DECL(cam_mode_enum, CS4265_SPDIF_CTL1, 5, + cam_mode_text); + +static const char * const cam_mono_stereo_text[] = { + "Stereo", "Mono" +}; + +static SOC_ENUM_SINGLE_DECL(spdif_mono_stereo_enum, CS4265_SPDIF_CTL2, 2, + cam_mono_stereo_text); + +static const char * const mono_select_text[] = { + "Channel A", "Channel B" +}; + +static SOC_ENUM_SINGLE_DECL(spdif_mono_select_enum, CS4265_SPDIF_CTL2, 0, + mono_select_text); + +static const struct snd_kcontrol_new mic_linein_mux = + SOC_DAPM_ENUM("ADC Input Capture Mux", mic_linein_enum); + +static const struct snd_kcontrol_new loopback_ctl = + SOC_DAPM_SINGLE("Switch", CS4265_SIG_SEL, 1, 1, 0); + +static const struct snd_kcontrol_new spdif_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 0, 0); + +static const struct snd_kcontrol_new dac_switch = + SOC_DAPM_SINGLE("Switch", CS4265_PWRCTL, 1, 1, 0); + +static const struct snd_kcontrol_new cs4265_snd_controls[] = { + + SOC_DOUBLE_R_SX_TLV("PGA Volume", CS4265_CHA_PGA_CTL, + CS4265_CHB_PGA_CTL, 0, 0x28, 0x30, pga_tlv), + SOC_DOUBLE_R_TLV("DAC Volume", CS4265_DAC_CHA_VOL, + CS4265_DAC_CHB_VOL, 0, 0xFF, 1, dac_tlv), + SOC_SINGLE("De-emp 44.1kHz Switch", CS4265_DAC_CTL, 1, + 1, 0), + SOC_SINGLE("DAC INV Switch", CS4265_DAC_CTL2, 5, + 1, 0), + SOC_SINGLE("DAC Zero Cross Switch", CS4265_DAC_CTL2, 6, + 1, 0), + SOC_SINGLE("DAC Soft Ramp Switch", CS4265_DAC_CTL2, 7, + 1, 0), + SOC_SINGLE("ADC HPF Switch", CS4265_ADC_CTL, 1, + 1, 0), + SOC_SINGLE("ADC Zero Cross Switch", CS4265_ADC_CTL2, 3, + 1, 1), + SOC_SINGLE("ADC Soft Ramp Switch", CS4265_ADC_CTL2, 7, + 1, 0), + SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1, + 6, 1, 0), + SOC_ENUM("C Data Access", cam_mode_enum), + SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2, + 3, 1, 0), + SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum), + SOC_SINGLE("MMTLR Data Switch", 0, + 1, 1, 0), + SOC_ENUM("Mono Channel Select", spdif_mono_select_enum), + SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24), +}; + +static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = { + + SND_SOC_DAPM_INPUT("LINEINL"), + SND_SOC_DAPM_INPUT("LINEINR"), + SND_SOC_DAPM_INPUT("MICL"), + SND_SOC_DAPM_INPUT("MICR"), + + SND_SOC_DAPM_AIF_OUT("DOUT", NULL, 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("SPDIFOUT", NULL, 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MUX("ADC Mux", SND_SOC_NOPM, 0, 0, &mic_linein_mux), + + SND_SOC_DAPM_ADC("ADC", NULL, CS4265_PWRCTL, 2, 1), + SND_SOC_DAPM_PGA("Pre-amp MIC", CS4265_PWRCTL, 3, + 1, NULL, 0), + + SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, + 0, 0, &digital_input_mux), + + SND_SOC_DAPM_MIXER("SDIN1 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SDIN2 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SPDIF Transmitter", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0, + &loopback_ctl), + SND_SOC_DAPM_SWITCH("SPDIF", SND_SOC_NOPM, 0, 0, + &spdif_switch), + SND_SOC_DAPM_SWITCH("DAC", CS4265_PWRCTL, 1, 1, + &dac_switch), + + SND_SOC_DAPM_AIF_IN("DIN1", NULL, 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DIN2", NULL, 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("TXIN", NULL, 0, + CS4265_SPDIF_CTL2, 5, 1), + + SND_SOC_DAPM_OUTPUT("LINEOUTL"), + SND_SOC_DAPM_OUTPUT("LINEOUTR"), + +}; + +static const struct snd_soc_dapm_route cs4265_audio_map[] = { + + {"DIN1", NULL, "DAI1 Playback"}, + {"DIN2", NULL, "DAI2 Playback"}, + {"SDIN1 Input Mixer", NULL, "DIN1"}, + {"SDIN2 Input Mixer", NULL, "DIN2"}, + {"Input Mux", "SDIN1", "SDIN1 Input Mixer"}, + {"Input Mux", "SDIN2", "SDIN2 Input Mixer"}, + {"DAC", "Switch", "Input Mux"}, + {"SPDIF", "Switch", "Input Mux"}, + {"LINEOUTL", NULL, "DAC"}, + {"LINEOUTR", NULL, "DAC"}, + {"SPDIFOUT", NULL, "SPDIF"}, + + {"ADC Mux", "LINEIN", "LINEINL"}, + {"ADC Mux", "LINEIN", "LINEINR"}, + {"ADC Mux", "MIC", "MICL"}, + {"ADC Mux", "MIC", "MICR"}, + {"ADC", NULL, "ADC Mux"}, + {"DOUT", NULL, "ADC"}, + {"DAI1 Capture", NULL, "DOUT"}, + {"DAI2 Capture", NULL, "DOUT"}, + + /* Loopback */ + {"Loopback", "Switch", "ADC"}, + {"DAC", NULL, "Loopback"}, +}; + +struct cs4265_clk_para { + u32 mclk; + u32 rate; + u8 fm_mode; /* values 1, 2, or 4 */ + u8 mclkdiv; +}; + +static const struct cs4265_clk_para clk_map_table[] = { + /*32k*/ + {8192000, 32000, 0, 0}, + {12288000, 32000, 0, 1}, + {16384000, 32000, 0, 2}, + {24576000, 32000, 0, 3}, + {32768000, 32000, 0, 4}, + + /*44.1k*/ + {11289600, 44100, 0, 0}, + {16934400, 44100, 0, 1}, + {22579200, 44100, 0, 2}, + {33868000, 44100, 0, 3}, + {45158400, 44100, 0, 4}, + + /*48k*/ + {12288000, 48000, 0, 0}, + {18432000, 48000, 0, 1}, + {24576000, 48000, 0, 2}, + {36864000, 48000, 0, 3}, + {49152000, 48000, 0, 4}, + + /*64k*/ + {8192000, 64000, 1, 0}, + {1228800, 64000, 1, 1}, + {1693440, 64000, 1, 2}, + {2457600, 64000, 1, 3}, + {3276800, 64000, 1, 4}, + + /* 88.2k */ + {11289600, 88200, 1, 0}, + {16934400, 88200, 1, 1}, + {22579200, 88200, 1, 2}, + {33868000, 88200, 1, 3}, + {45158400, 88200, 1, 4}, + + /* 96k */ + {12288000, 96000, 1, 0}, + {18432000, 96000, 1, 1}, + {24576000, 96000, 1, 2}, + {36864000, 96000, 1, 3}, + {49152000, 96000, 1, 4}, + + /* 128k */ + {8192000, 128000, 2, 0}, + {12288000, 128000, 2, 1}, + {16934400, 128000, 2, 2}, + {24576000, 128000, 2, 3}, + {32768000, 128000, 2, 4}, + + /* 176.4k */ + {11289600, 176400, 2, 0}, + {16934400, 176400, 2, 1}, + {22579200, 176400, 2, 2}, + {33868000, 176400, 2, 3}, + {49152000, 176400, 2, 4}, + + /* 192k */ + {12288000, 192000, 2, 0}, + {18432000, 192000, 2, 1}, + {24576000, 192000, 2, 2}, + {36864000, 192000, 2, 3}, + {49152000, 192000, 2, 4}, +}; + +static int cs4265_get_clk_index(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) { + if (clk_map_table[i].rate == rate && + clk_map_table[i].mclk == mclk) + return i; + } + return -EINVAL; +} + +static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec); + int i; + + if (clk_id != 0) { + dev_err(codec->dev, "Invalid clk_id %d\n", clk_id); + return -EINVAL; + } + for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) { + if (clk_map_table[i].mclk == freq) { + cs4265->sysclk = freq; + return 0; + } + } + cs4265->sysclk = 0; + dev_err(codec->dev, "Invalid freq parameter %d\n", freq); + return -EINVAL; +} + +static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec); + u8 iface = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + snd_soc_update_bits(codec, CS4265_ADC_CTL, + CS4265_ADC_MASTER, + CS4265_ADC_MASTER); + break; + case SND_SOC_DAIFMT_CBS_CFS: + snd_soc_update_bits(codec, CS4265_ADC_CTL, + CS4265_ADC_MASTER, + 0); + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= SND_SOC_DAIFMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + iface |= SND_SOC_DAIFMT_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= SND_SOC_DAIFMT_LEFT_J; + break; + default: + return -EINVAL; + } + + cs4265->format = iface; + return 0; +} + +static int cs4265_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + + if (mute) { + snd_soc_update_bits(codec, CS4265_DAC_CTL, + CS4265_DAC_CTL_MUTE, + CS4265_DAC_CTL_MUTE); + snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, + CS4265_SPDIF_CTL2_MUTE, + CS4265_SPDIF_CTL2_MUTE); + } else { + snd_soc_update_bits(codec, CS4265_DAC_CTL, + CS4265_DAC_CTL_MUTE, + 0); + snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, + CS4265_SPDIF_CTL2_MUTE, + 0); + } + return 0; +} + +static int cs4265_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 cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec); + int index; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + ((cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) + == SND_SOC_DAIFMT_RIGHT_J)) + return -EINVAL; + + index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params)); + if (index >= 0) { + snd_soc_update_bits(codec, CS4265_ADC_CTL, + CS4265_ADC_FM, clk_map_table[index].fm_mode); + snd_soc_update_bits(codec, CS4265_MCLK_FREQ, + CS4265_MCLK_FREQ_MASK, + clk_map_table[index].mclkdiv); + + } else { + dev_err(codec->dev, "can't get correct mclk\n"); + return -EINVAL; + } + + switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + snd_soc_update_bits(codec, CS4265_DAC_CTL, + CS4265_DAC_CTL_DIF, (1 << 4)); + snd_soc_update_bits(codec, CS4265_ADC_CTL, + CS4265_ADC_DIF, (1 << 4)); + snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, + CS4265_SPDIF_CTL2_DIF, (1 << 6)); + break; + case SND_SOC_DAIFMT_RIGHT_J: + if (params_width(params) == 16) { + snd_soc_update_bits(codec, CS4265_DAC_CTL, + CS4265_DAC_CTL_DIF, (1 << 5)); + snd_soc_update_bits(codec, CS4265_ADC_CTL, + CS4265_SPDIF_CTL2_DIF, (1 << 7)); + } else { + snd_soc_update_bits(codec, CS4265_DAC_CTL, + CS4265_DAC_CTL_DIF, (3 << 5)); + snd_soc_update_bits(codec, CS4265_ADC_CTL, + CS4265_SPDIF_CTL2_DIF, (1 << 7)); + } + break; + case SND_SOC_DAIFMT_LEFT_J: + snd_soc_update_bits(codec, CS4265_DAC_CTL, + CS4265_DAC_CTL_DIF, 0); + snd_soc_update_bits(codec, CS4265_ADC_CTL, + CS4265_ADC_DIF, 0); + snd_soc_update_bits(codec, CS4265_ADC_CTL, + CS4265_SPDIF_CTL2_DIF, (1 << 6)); + + break; + default: + return -EINVAL; + } + return 0; +} + +static int cs4265_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + snd_soc_update_bits(codec, CS4265_PWRCTL, + CS4265_PWRCTL_PDN, 0); + break; + case SND_SOC_BIAS_STANDBY: + snd_soc_update_bits(codec, CS4265_PWRCTL, + CS4265_PWRCTL_PDN, + CS4265_PWRCTL_PDN); + break; + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, CS4265_PWRCTL, + CS4265_PWRCTL_PDN, + CS4265_PWRCTL_PDN); + break; + } + codec->dapm.bias_level = level; + return 0; +} + +#define CS4265_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +#define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE) + +static const struct snd_soc_dai_ops cs4265_ops = { + .hw_params = cs4265_pcm_hw_params, + .digital_mute = cs4265_digital_mute, + .set_fmt = cs4265_set_fmt, + .set_sysclk = cs4265_set_sysclk, +}; + +static struct snd_soc_dai_driver cs4265_dai[] = { + { + .name = "cs4265-dai1", + .playback = { + .stream_name = "DAI1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CS4265_RATES, + .formats = CS4265_FORMATS, + }, + .capture = { + .stream_name = "DAI1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = CS4265_RATES, + .formats = CS4265_FORMATS, + }, + .ops = &cs4265_ops, + }, + { + .name = "cs4265-dai2", + .playback = { + .stream_name = "DAI2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CS4265_RATES, + .formats = CS4265_FORMATS, + }, + .capture = { + .stream_name = "DAI2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = CS4265_RATES, + .formats = CS4265_FORMATS, + }, + .ops = &cs4265_ops, + }, +}; + +static const struct snd_soc_codec_driver soc_codec_cs4265 = { + .set_bias_level = cs4265_set_bias_level, + + .dapm_widgets = cs4265_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets), + .dapm_routes = cs4265_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs4265_audio_map), + + .controls = cs4265_snd_controls, + .num_controls = ARRAY_SIZE(cs4265_snd_controls), +}; + +static const struct regmap_config cs4265_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS4265_MAX_REGISTER, + .reg_defaults = cs4265_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults), + .readable_reg = cs4265_readable_register, + .volatile_reg = cs4265_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int cs4265_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs4265_private *cs4265; + int ret = 0; + unsigned int devid = 0; + unsigned int reg; + + cs4265 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4265_private), + GFP_KERNEL); + if (cs4265 == NULL) + return -ENOMEM; + cs4265->dev = &i2c_client->dev; + + cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap); + if (IS_ERR(cs4265->regmap)) { + ret = PTR_ERR(cs4265->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev, + "reset-gpios"); + if (IS_ERR(cs4265->reset_gpio)) { + ret = PTR_ERR(cs4265->reset_gpio); + if (ret != -ENOENT && ret != -ENOSYS) + return ret; + + cs4265->reset_gpio = NULL; + } else { + ret = gpiod_direction_output(cs4265->reset_gpio, 0); + if (ret) + return ret; + mdelay(1); + gpiod_set_value_cansleep(cs4265->reset_gpio, 1); + + } + + i2c_set_clientdata(i2c_client, cs4265); + + ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, ®); + devid = reg & CS4265_CHIP_ID_MASK; + if (devid != CS4265_CHIP_ID_VAL) { + ret = -ENODEV; + dev_err(&i2c_client->dev, + "CS4265 Device ID (%X). Expected %X\n", + devid, CS4265_CHIP_ID); + return ret; + } + dev_info(&i2c_client->dev, + "CS4265 Version %x\n", + reg & CS4265_REV_ID_MASK); + + regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F); + + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_cs4265, cs4265_dai, + ARRAY_SIZE(cs4265_dai)); + return ret; +} + +static int cs4265_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct of_device_id cs4265_of_match[] = { + { .compatible = "cirrus,cs4265", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs4265_of_match); + +static const struct i2c_device_id cs4265_id[] = { + { "cs4265", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs4265_id); + +static struct i2c_driver cs4265_i2c_driver = { + .driver = { + .name = "cs4265", + .owner = THIS_MODULE, + .of_match_table = cs4265_of_match, + }, + .id_table = cs4265_id, + .probe = cs4265_i2c_probe, + .remove = cs4265_i2c_remove, +}; + +module_i2c_driver(cs4265_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS4265 driver"); +MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4265.h b/sound/soc/codecs/cs4265.h new file mode 100644 index 000000000000..0a80a8dcec67 --- /dev/null +++ b/sound/soc/codecs/cs4265.h @@ -0,0 +1,64 @@ +/* + * cs4265.h -- CS4265 ALSA SoC audio driver + * + * Copyright 2014 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 __CS4265_H__ +#define __CS4265_H__ + +#define CS4265_CHIP_ID 0x1 +#define CS4265_CHIP_ID_VAL 0xD0 +#define CS4265_CHIP_ID_MASK 0xF0 +#define CS4265_REV_ID_MASK 0x0F + +#define CS4265_PWRCTL 0x02 +#define CS4265_PWRCTL_PDN 1 + +#define CS4265_DAC_CTL 0x3 +#define CS4265_DAC_CTL_MUTE (1 << 2) +#define CS4265_DAC_CTL_DIF (3 << 4) + +#define CS4265_ADC_CTL 0x4 +#define CS4265_ADC_MASTER 1 +#define CS4265_ADC_DIF (1 << 4) +#define CS4265_ADC_FM (3 << 6) + +#define CS4265_MCLK_FREQ 0x5 +#define CS4265_MCLK_FREQ_MASK (7 << 4) + +#define CS4265_SIG_SEL 0x6 +#define CS4265_SIG_SEL_LOOP (1 << 1) + +#define CS4265_CHB_PGA_CTL 0x7 +#define CS4265_CHA_PGA_CTL 0x8 + +#define CS4265_ADC_CTL2 0x9 + +#define CS4265_DAC_CHA_VOL 0xA +#define CS4265_DAC_CHB_VOL 0xB + +#define CS4265_DAC_CTL2 0xC + +#define CS4265_INT_STATUS 0xD +#define CS4265_INT_MASK 0xE +#define CS4265_STATUS_MODE_MSB 0xF +#define CS4265_STATUS_MODE_LSB 0x10 + +#define CS4265_SPDIF_CTL1 0x11 + +#define CS4265_SPDIF_CTL2 0x12 +#define CS4265_SPDIF_CTL2_MUTE (1 << 4) +#define CS4265_SPDIF_CTL2_DIF (3 << 6) + +#define CS4265_C_DATA_BUFF 0x13 +#define CS4265_MAX_REGISTER 0x2A + +#endif diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 9947a9583679..e6d4ff9fd992 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -664,10 +664,8 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private), GFP_KERNEL); - if (!cs4270) { - dev_err(&i2c_client->dev, "could not allocate codec\n"); + if (!cs4270) return -ENOMEM; - } /* get the power supply regulators */ for (i = 0; i < ARRAY_SIZE(supply_names); i++) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 071fc77f2f06..969167d8b71e 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -399,15 +399,15 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { CS42L52_MASTERB_VOL, 0, 0x34, 0xE4, hl_tlv), SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L52_HPA_VOL, - CS42L52_HPB_VOL, 0, 0x34, 0xCC, hpd_tlv), + CS42L52_HPB_VOL, 0, 0x34, 0xC0, hpd_tlv), SOC_ENUM("Headphone Analog Gain", hp_gain_enum), SOC_DOUBLE_R_SX_TLV("Speaker Volume", CS42L52_SPKA_VOL, - CS42L52_SPKB_VOL, 0, 0x1, 0xff, hl_tlv), + CS42L52_SPKB_VOL, 0, 0x40, 0xC0, hl_tlv), SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL, - CS42L52_PASSTHRUB_VOL, 6, 0x18, 0x90, pga_tlv), + CS42L52_PASSTHRUB_VOL, 0, 0x88, 0x90, pga_tlv), SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0), @@ -417,10 +417,10 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { SOC_ENUM("MIC Bias Level", mic_bias_level_enum), SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L52_ADCA_VOL, - CS42L52_ADCB_VOL, 7, 0x80, 0xA0, ipd_tlv), + CS42L52_ADCB_VOL, 0, 0xA0, 0x78, ipd_tlv), SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL, - 6, 0x7f, 0x19, ipd_tlv), + 0, 0x19, 0x7F, ipd_tlv), SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0), @@ -428,11 +428,11 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { CS42L52_ADCB_MIXER_VOL, 7, 1, 1), SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L52_PGAA_CTL, - CS42L52_PGAB_CTL, 0, 0x28, 0x30, pga_tlv), + CS42L52_PGAB_CTL, 0, 0x28, 0x24, pga_tlv), SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, - 0, 0x7f, 0x19, mix_tlv), + 0, 0x19, 0x7f, mix_tlv), SOC_DOUBLE_R("PCM Mixer Switch", CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, 7, 1, 1), diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index fdc4bd27b0df..c766a5a9ce80 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -318,24 +318,32 @@ static const struct soc_enum adca_swap_enum = ARRAY_SIZE(left_swap_text), left_swap_text, swap_values); +static const struct snd_kcontrol_new adca_swap_mux = + SOC_DAPM_ENUM("Route", adca_swap_enum); static const struct soc_enum pcma_swap_enum = SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3, ARRAY_SIZE(left_swap_text), left_swap_text, swap_values); +static const struct snd_kcontrol_new pcma_swap_mux = + SOC_DAPM_ENUM("Route", pcma_swap_enum); static const struct soc_enum adcb_swap_enum = SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3, ARRAY_SIZE(right_swap_text), right_swap_text, swap_values); +static const struct snd_kcontrol_new adcb_swap_mux = + SOC_DAPM_ENUM("Route", adcb_swap_enum); static const struct soc_enum pcmb_swap_enum = SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3, ARRAY_SIZE(right_swap_text), right_swap_text, swap_values); +static const struct snd_kcontrol_new pcmb_swap_mux = + SOC_DAPM_ENUM("Route", pcmb_swap_enum); static const struct snd_kcontrol_new hpa_switch = SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1); @@ -421,15 +429,15 @@ static const struct soc_enum ng_delay_enum = static const struct snd_kcontrol_new cs42l56_snd_controls[] = { SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME, - CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xfd, adv_tlv), + CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xE4, adv_tlv), SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1), SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME, - CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), + CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv), SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1), SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME, - CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv), + CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv), SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1), SOC_SINGLE_TLV("Analog Advisory Volume", @@ -438,16 +446,16 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = { CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv), SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME, - CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0xfd, pga_tlv), + CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0x24, pga_tlv), SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR, CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv), SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1), SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1), SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME, - CS42L56_HPA_VOLUME, 0, 0x44, 0x55, hl_tlv), + CS42L56_HPB_VOLUME, 0, 0x84, 0x48, hl_tlv), SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME, - CS42L56_LOA_VOLUME, 0, 0x44, 0x55, hl_tlv), + CS42L56_LOB_VOLUME, 0, 0x84, 0x48, hl_tlv), SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL, 0, 0x00, 1, tone_tlv), @@ -467,11 +475,6 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = { SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1), SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1), - SOC_ENUM("PCMA Swap", pcma_swap_enum), - SOC_ENUM("PCMB Swap", pcmb_swap_enum), - SOC_ENUM("ADCA Swap", adca_swap_enum), - SOC_ENUM("ADCB Swap", adcb_swap_enum), - SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1), SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1), SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum), @@ -570,6 +573,16 @@ static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1), SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1), + SND_SOC_DAPM_MUX("ADCA Swap Mux", SND_SOC_NOPM, 0, 0, + &adca_swap_mux), + SND_SOC_DAPM_MUX("ADCB Swap Mux", SND_SOC_NOPM, 0, 0, + &adcb_swap_mux), + + SND_SOC_DAPM_MUX("PCMA Swap Mux", SND_SOC_NOPM, 0, 0, + &pcma_swap_mux), + SND_SOC_DAPM_MUX("PCMB Swap Mux", SND_SOC_NOPM, 0, 0, + &pcmb_swap_mux), + SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0), @@ -607,8 +620,19 @@ static const struct snd_soc_dapm_route cs42l56_audio_map[] = { {"Digital Output Mux", NULL, "ADCA"}, {"Digital Output Mux", NULL, "ADCB"}, - {"ADCB", NULL, "ADCB Mux"}, - {"ADCA", NULL, "ADCA Mux"}, + {"ADCB", NULL, "ADCB Swap Mux"}, + {"ADCA", NULL, "ADCA Swap Mux"}, + + {"ADCA Swap Mux", NULL, "ADCA"}, + {"ADCB Swap Mux", NULL, "ADCB"}, + + {"DACA", "Left", "ADCA Swap Mux"}, + {"DACA", "LR 2", "ADCA Swap Mux"}, + {"DACA", "Right", "ADCA Swap Mux"}, + + {"DACB", "Left", "ADCB Swap Mux"}, + {"DACB", "LR 2", "ADCB Swap Mux"}, + {"DACB", "Right", "ADCB Swap Mux"}, {"ADCA Mux", NULL, "AIN3A"}, {"ADCA Mux", NULL, "AIN2A"}, @@ -633,30 +657,32 @@ static const struct snd_soc_dapm_route cs42l56_audio_map[] = { {"PGAB Input Mux", NULL, "AIN2B"}, {"PGAB Input Mux", NULL, "AIN3B"}, - {"LOB", NULL, "Lineout Right"}, - {"LOA", NULL, "Lineout Left"}, - - {"Lineout Right", "Switch", "LINEOUTB Input Mux"}, - {"Lineout Left", "Switch", "LINEOUTA Input Mux"}, + {"LOB", "Switch", "LINEOUTB Input Mux"}, + {"LOA", "Switch", "LINEOUTA Input Mux"}, {"LINEOUTA Input Mux", "PGAA", "PGAA"}, {"LINEOUTB Input Mux", "PGAB", "PGAB"}, {"LINEOUTA Input Mux", "DACA", "DACA"}, {"LINEOUTB Input Mux", "DACB", "DACB"}, - {"HPA", NULL, "Headphone Left"}, - {"HPB", NULL, "Headphone Right"}, - - {"Headphone Right", "Switch", "HPB Input Mux"}, - {"Headphone Left", "Switch", "HPA Input Mux"}, + {"HPA", "Switch", "HPB Input Mux"}, + {"HPB", "Switch", "HPA Input Mux"}, {"HPA Input Mux", "PGAA", "PGAA"}, {"HPB Input Mux", "PGAB", "PGAB"}, {"HPA Input Mux", "DACA", "DACA"}, {"HPB Input Mux", "DACB", "DACB"}, - {"DACB", NULL, "HiFi Playback"}, - {"DACA", NULL, "HiFi Playback"}, + {"DACA", NULL, "PCMA Swap Mux"}, + {"DACB", NULL, "PCMB Swap Mux"}, + + {"PCMB Swap Mux", "Left", "HiFi Playback"}, + {"PCMB Swap Mux", "LR 2", "HiFi Playback"}, + {"PCMB Swap Mux", "Right", "HiFi Playback"}, + + {"PCMA Swap Mux", "Left", "HiFi Playback"}, + {"PCMA Swap Mux", "LR 2", "HiFi Playback"}, + {"PCMA Swap Mux", "Right", "HiFi Playback"}, }; diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index ae3717992d56..0e7b9eb2ba61 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -401,7 +401,7 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { CS42L73_LOBAVOL, 0, 0x41, 0x4B, hpaloa_tlv), SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL, - CS42L73_MICBPREPGABVOL, 5, 0x34, + CS42L73_MICBPREPGABVOL, 0, 0x34, 0x24, micpga_tlv), SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL, @@ -1408,10 +1408,8 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private), GFP_KERNEL); - if (!cs42l73) { - dev_err(&i2c_client->dev, "could not allocate codec\n"); + if (!cs42l73) return -ENOMEM; - } cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap); if (IS_ERR(cs42l73->regmap)) { diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index a25bc6061a30..02b1520ae0bc 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -219,6 +219,9 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_RIGHT_J: val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ; break; + case SND_SOC_DAIFMT_DSP_A: + val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM; + break; default: dev_err(codec->dev, "unsupported dai format\n"); return -EINVAL; @@ -422,7 +425,7 @@ const struct cs42xx8_driver_data cs42888_data = { }; EXPORT_SYMBOL_GPL(cs42888_data); -const struct of_device_id cs42xx8_of_match[] = { +static const struct of_device_id cs42xx8_of_match[] = { { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, { /* sentinel */ } diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h index da0b94aee419..b2c10e537ef6 100644 --- a/sound/soc/codecs/cs42xx8.h +++ b/sound/soc/codecs/cs42xx8.h @@ -128,8 +128,8 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap); #define CS42XX8_INTF_DAC_DIF_RIGHTJ (2 << CS42XX8_INTF_DAC_DIF_SHIFT) #define CS42XX8_INTF_DAC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_DAC_DIF_SHIFT) #define CS42XX8_INTF_DAC_DIF_ONELINE_20 (4 << CS42XX8_INTF_DAC_DIF_SHIFT) -#define CS42XX8_INTF_DAC_DIF_ONELINE_24 (6 << CS42XX8_INTF_DAC_DIF_SHIFT) -#define CS42XX8_INTF_DAC_DIF_TDM (7 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_ONELINE_24 (5 << CS42XX8_INTF_DAC_DIF_SHIFT) +#define CS42XX8_INTF_DAC_DIF_TDM (6 << CS42XX8_INTF_DAC_DIF_SHIFT) #define CS42XX8_INTF_ADC_DIF_SHIFT 0 #define CS42XX8_INTF_ADC_DIF_WIDTH 3 #define CS42XX8_INTF_ADC_DIF_MASK (((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT) @@ -138,8 +138,8 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap); #define CS42XX8_INTF_ADC_DIF_RIGHTJ (2 << CS42XX8_INTF_ADC_DIF_SHIFT) #define CS42XX8_INTF_ADC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_ADC_DIF_SHIFT) #define CS42XX8_INTF_ADC_DIF_ONELINE_20 (4 << CS42XX8_INTF_ADC_DIF_SHIFT) -#define CS42XX8_INTF_ADC_DIF_ONELINE_24 (6 << CS42XX8_INTF_ADC_DIF_SHIFT) -#define CS42XX8_INTF_ADC_DIF_TDM (7 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_ONELINE_24 (5 << CS42XX8_INTF_ADC_DIF_SHIFT) +#define CS42XX8_INTF_ADC_DIF_TDM (6 << CS42XX8_INTF_ADC_DIF_SHIFT) /* ADC Control & DAC De-Emphasis (Address 05h) */ #define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT 7 diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index d5fd00a64748..8f95b0300f1a 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -253,7 +253,7 @@ static void v253_close(struct tty_struct *tty) /* Prevent the codec driver from further accessing the modem */ codec->hw_write = NULL; cx20442->control_data = NULL; - codec->card->pop_time = 0; + codec->component.card->pop_time = 0; } /* Line discipline .hangup() */ @@ -281,7 +281,7 @@ static void v253_receive(struct tty_struct *tty, /* Set up codec driver access to modem controls */ cx20442->control_data = tty; codec->hw_write = (hw_write_t)tty->ops->write; - codec->card->pop_time = 1; + codec->component.card->pop_time = 1; } } @@ -372,7 +372,7 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec) snd_soc_codec_set_drvdata(codec, cx20442); codec->hw_write = NULL; - codec->card->pop_time = 0; + codec->component.card->pop_time = 0; return 0; } @@ -383,8 +383,8 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec) struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec); if (cx20442->control_data) { - struct tty_struct *tty = cx20442->control_data; - tty_hangup(tty); + struct tty_struct *tty = cx20442->control_data; + tty_hangup(tty); } if (!IS_ERR(cx20442->por)) { diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 9134982807b5..2cd3e5427441 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1299,12 +1299,12 @@ static int max98088_dai2_hw_params(struct snd_pcm_substream *substream, rate = params_rate(params); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT, M98088_DAI_WS, 0); break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT, M98088_DAI_WS, M98088_DAI_WS); break; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index f5fccc7a8e89..4a063fa88526 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -26,10 +26,6 @@ #include <sound/max98090.h> #include "max98090.h" -#define DEBUG -#define EXTMIC_METHOD -#define EXTMIC_METHOD_TEST - /* Allows for sparsely populated register maps */ static struct reg_default max98090_reg[] = { { 0x00, 0x00 }, /* 00 Software Reset */ @@ -820,7 +816,6 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w, else val = (val & M98090_MIC_PA2EN_MASK) >> M98090_MIC_PA2EN_SHIFT; - if (val >= 1) { if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) { max98090->pa1en = val - 1; /* Update for volatile */ @@ -1140,7 +1135,6 @@ static const struct snd_kcontrol_new max98090_mixhprsel_mux = SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("MIC1"), SND_SOC_DAPM_INPUT("MIC2"), SND_SOC_DAPM_INPUT("DMICL"), @@ -1304,7 +1298,6 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { }; static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("DMIC3"), SND_SOC_DAPM_INPUT("DMIC4"), @@ -1315,7 +1308,6 @@ static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { }; static const struct snd_soc_dapm_route max98090_dapm_routes[] = { - {"MIC1 Input", NULL, "MIC1"}, {"MIC2 Input", NULL, "MIC2"}, @@ -1493,17 +1485,14 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"SPKR", NULL, "SPK Right Out"}, {"RCVL", NULL, "RCV Left Out"}, {"RCVR", NULL, "RCV Right Out"}, - }; static const struct snd_soc_dapm_route max98091_dapm_routes[] = { - /* DMIC inputs */ {"DMIC3", NULL, "DMIC3_ENA"}, {"DMIC4", NULL, "DMIC4_ENA"}, {"DMIC3", NULL, "AHPF"}, {"DMIC4", NULL, "AHPF"}, - }; static int max98090_add_widgets(struct snd_soc_codec *codec) @@ -1531,7 +1520,6 @@ static int max98090_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(dapm, max98091_dapm_routes, ARRAY_SIZE(max98091_dapm_routes)); - } return 0; @@ -2212,22 +2200,11 @@ static struct snd_soc_dai_driver max98090_dai[] = { } }; -static void max98090_handle_pdata(struct snd_soc_codec *codec) -{ - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); - struct max98090_pdata *pdata = max98090->pdata; - - if (!pdata) { - dev_err(codec->dev, "No platform data\n"); - return; - } - -} - static int max98090_probe(struct snd_soc_codec *codec) { struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); struct max98090_cdata *cdata; + enum max98090_type devtype; int ret = 0; dev_dbg(codec->dev, "max98090_probe\n"); @@ -2263,16 +2240,21 @@ static int max98090_probe(struct snd_soc_codec *codec) } if ((ret >= M98090_REVA) && (ret <= M98090_REVA + 0x0f)) { - max98090->devtype = MAX98090; + devtype = MAX98090; dev_info(codec->dev, "MAX98090 REVID=0x%02x\n", ret); } else if ((ret >= M98091_REVA) && (ret <= M98091_REVA + 0x0f)) { - max98090->devtype = MAX98091; + devtype = MAX98091; dev_info(codec->dev, "MAX98091 REVID=0x%02x\n", ret); } else { - max98090->devtype = MAX98090; + devtype = MAX98090; dev_err(codec->dev, "Unrecognized revision 0x%02x\n", ret); } + if (max98090->devtype != devtype) { + dev_warn(codec->dev, "Mismatch in DT specified CODEC type.\n"); + max98090->devtype = devtype; + } + max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); @@ -2284,7 +2266,7 @@ static int max98090_probe(struct snd_soc_codec *codec) /* Register for interrupts */ dev_dbg(codec->dev, "irq = %d\n", max98090->irq); - ret = request_threaded_irq(max98090->irq, NULL, + ret = devm_request_threaded_irq(codec->dev, max98090->irq, NULL, max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "max98090_interrupt", codec); if (ret < 0) { @@ -2317,8 +2299,6 @@ static int max98090_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, M98090_MBVSEL_MASK, M98090_MBVSEL_2V8); - max98090_handle_pdata(codec); - max98090_add_widgets(codec); err_access: @@ -2428,7 +2408,7 @@ static int max98090_runtime_suspend(struct device *dev) } #endif -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int max98090_resume(struct device *dev) { struct max98090_priv *max98090 = dev_get_drvdata(dev); @@ -2460,12 +2440,14 @@ static const struct dev_pm_ops max98090_pm = { static const struct i2c_device_id max98090_i2c_id[] = { { "max98090", MAX98090 }, + { "max98091", MAX98091 }, { } }; MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); static const struct of_device_id max98090_of_match[] = { { .compatible = "maxim,max98090", }, + { .compatible = "maxim,max98091", }, { } }; MODULE_DEVICE_TABLE(of, max98090_of_match); diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 89ec00424880..0ee6797d5083 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -1280,12 +1280,12 @@ static int max98095_dai2_hw_params(struct snd_pcm_substream *substream, rate = params_rate(params); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT, M98095_DAI_WS, 0); break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT, M98095_DAI_WS, M98095_DAI_WS); break; @@ -1341,12 +1341,12 @@ static int max98095_dai3_hw_params(struct snd_pcm_substream *substream, rate = params_rate(params); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT, M98095_DAI_WS, 0); break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT, M98095_DAI_WS, M98095_DAI_WS); break; diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 9965277b595a..388f90a597fa 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -766,11 +766,11 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port); if (ret) - return ret; + goto out; ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port); if (ret) - return ret; + goto out; } dev_set_drvdata(&pdev->dev, priv); @@ -783,6 +783,8 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783, mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async)); +out: + of_node_put(np); return ret; } diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 3a80ba4452df..57b0c94a710b 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c @@ -36,6 +36,7 @@ #define PCM1792A_DAC_VOL_LEFT 0x10 #define PCM1792A_DAC_VOL_RIGHT 0x11 #define PCM1792A_FMT_CONTROL 0x12 +#define PCM1792A_MODE_CONTROL 0x13 #define PCM1792A_SOFT_MUTE PCM1792A_FMT_CONTROL #define PCM1792A_FMT_MASK 0x70 @@ -164,6 +165,8 @@ static const struct snd_kcontrol_new pcm1792a_controls[] = { SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT, PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, pcm1792a_dac_tlv), + SOC_SINGLE("DAC Invert Output Switch", PCM1792A_MODE_CONTROL, 7, 1, 0), + SOC_SINGLE("DAC Rolloff Filter Switch", PCM1792A_MODE_CONTROL, 1, 1, 0), }; static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = { diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm1792a.h index 7a83d1fc102a..51d5470fee16 100644 --- a/sound/soc/codecs/pcm1792a.h +++ b/sound/soc/codecs/pcm1792a.h @@ -18,7 +18,8 @@ #define __PCM1792A_H__ #define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_192000) #define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S16_LE) diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 7b82fbe0d14c..56650d6c2f53 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -11,25 +11,6 @@ */ #include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/gpio.h> -#include <linux/i2c.h> -#include <linux/regmap.h> -#include <linux/of.h> -#include <linux/of_gpio.h> -#include <linux/platform_device.h> -#include <linux/spi/spi.h> -#include <linux/acpi.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 "rl6231.h" diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c new file mode 100644 index 000000000000..e4f6102efc1a --- /dev/null +++ b/sound/soc/codecs/rt286.c @@ -0,0 +1,1222 @@ +/* + * rt286.c -- RT286 ALSA SoC audio codec driver + * + * Copyright 2013 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 <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 <sound/jack.h> +#include <linux/workqueue.h> +#include <sound/rt286.h> +#include <sound/hda_verbs.h> + +#include "rt286.h" + +#define RT286_VENDOR_ID 0x10ec0286 + +struct rt286_priv { + struct regmap *regmap; + struct rt286_platform_data pdata; + struct i2c_client *i2c; + struct snd_soc_jack *jack; + struct delayed_work jack_detect_work; + int sys_clk; + struct reg_default *index_cache; +}; + +static struct reg_default rt286_index_def[] = { + { 0x01, 0xaaaa }, + { 0x02, 0x8aaa }, + { 0x03, 0x0002 }, + { 0x04, 0xaf01 }, + { 0x08, 0x000d }, + { 0x09, 0xd810 }, + { 0x0a, 0x0060 }, + { 0x0b, 0x0000 }, + { 0x0d, 0x2800 }, + { 0x0f, 0x0000 }, + { 0x19, 0x0a17 }, + { 0x20, 0x0020 }, + { 0x33, 0x0208 }, + { 0x49, 0x0004 }, + { 0x4f, 0x50e9 }, + { 0x50, 0x2c00 }, + { 0x63, 0x2902 }, + { 0x67, 0x1111 }, + { 0x68, 0x1016 }, + { 0x69, 0x273f }, +}; +#define INDEX_CACHE_SIZE ARRAY_SIZE(rt286_index_def) + +static const struct reg_default rt286_reg[] = { + { 0x00170500, 0x00000400 }, + { 0x00220000, 0x00000031 }, + { 0x00239000, 0x0000007f }, + { 0x0023a000, 0x0000007f }, + { 0x00270500, 0x00000400 }, + { 0x00370500, 0x00000400 }, + { 0x00870500, 0x00000400 }, + { 0x00920000, 0x00000031 }, + { 0x00935000, 0x000000c3 }, + { 0x00936000, 0x000000c3 }, + { 0x00970500, 0x00000400 }, + { 0x00b37000, 0x00000097 }, + { 0x00b37200, 0x00000097 }, + { 0x00b37300, 0x00000097 }, + { 0x00c37000, 0x00000000 }, + { 0x00c37100, 0x00000080 }, + { 0x01270500, 0x00000400 }, + { 0x01370500, 0x00000400 }, + { 0x01371f00, 0x411111f0 }, + { 0x01439000, 0x00000080 }, + { 0x0143a000, 0x00000080 }, + { 0x01470700, 0x00000000 }, + { 0x01470500, 0x00000400 }, + { 0x01470c00, 0x00000000 }, + { 0x01470100, 0x00000000 }, + { 0x01837000, 0x00000000 }, + { 0x01870500, 0x00000400 }, + { 0x02050000, 0x00000000 }, + { 0x02139000, 0x00000080 }, + { 0x0213a000, 0x00000080 }, + { 0x02170100, 0x00000000 }, + { 0x02170500, 0x00000400 }, + { 0x02170700, 0x00000000 }, + { 0x02270100, 0x00000000 }, + { 0x02370100, 0x00000000 }, + { 0x02040000, 0x00004002 }, + { 0x01870700, 0x00000020 }, + { 0x00830000, 0x000000c3 }, + { 0x00930000, 0x000000c3 }, + { 0x01270700, 0x00000000 }, +}; + +static bool rt286_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... 0xff: + case RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): + case RT286_GET_HP_SENSE: + case RT286_GET_MIC1_SENSE: + case RT286_PROC_COEF: + return true; + default: + return false; + } + + +} + +static bool rt286_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... 0xff: + case RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): + case RT286_GET_HP_SENSE: + case RT286_GET_MIC1_SENSE: + case RT286_SET_AUDIO_POWER: + case RT286_SET_HPO_POWER: + case RT286_SET_SPK_POWER: + case RT286_SET_DMIC1_POWER: + case RT286_SPK_MUX: + case RT286_HPO_MUX: + case RT286_ADC0_MUX: + case RT286_ADC1_MUX: + case RT286_SET_MIC1: + case RT286_SET_PIN_HPO: + case RT286_SET_PIN_SPK: + case RT286_SET_PIN_DMIC1: + case RT286_SPK_EAPD: + case RT286_SET_AMP_GAIN_HPO: + case RT286_SET_DMIC2_DEFAULT: + case RT286_DACL_GAIN: + case RT286_DACR_GAIN: + case RT286_ADCL_GAIN: + case RT286_ADCR_GAIN: + case RT286_MIC_GAIN: + case RT286_SPOL_GAIN: + case RT286_SPOR_GAIN: + case RT286_HPOL_GAIN: + case RT286_HPOR_GAIN: + case RT286_F_DAC_SWITCH: + case RT286_F_RECMIX_SWITCH: + case RT286_REC_MIC_SWITCH: + case RT286_REC_I2S_SWITCH: + case RT286_REC_LINE_SWITCH: + case RT286_REC_BEEP_SWITCH: + case RT286_DAC_FORMAT: + case RT286_ADC_FORMAT: + case RT286_COEF_INDEX: + case RT286_PROC_COEF: + case RT286_SET_AMP_GAIN_ADC_IN1: + case RT286_SET_AMP_GAIN_ADC_IN2: + case RT286_SET_POWER(RT286_DAC_OUT1): + case RT286_SET_POWER(RT286_DAC_OUT2): + case RT286_SET_POWER(RT286_ADC_IN1): + case RT286_SET_POWER(RT286_ADC_IN2): + case RT286_SET_POWER(RT286_DMIC2): + case RT286_SET_POWER(RT286_MIC1): + return true; + default: + return false; + } +} + +static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) +{ + struct i2c_client *client = context; + struct rt286_priv *rt286 = i2c_get_clientdata(client); + u8 data[4]; + int ret, i; + + /*handle index registers*/ + if (reg <= 0xff) { + rt286_hw_write(client, RT286_COEF_INDEX, reg); + reg = RT286_PROC_COEF; + for (i = 0; i < INDEX_CACHE_SIZE; i++) { + if (reg == rt286->index_cache[i].reg) { + rt286->index_cache[i].def = value; + break; + } + + } + } + + data[0] = (reg >> 24) & 0xff; + data[1] = (reg >> 16) & 0xff; + /* + * 4 bit VID: reg should be 0 + * 12 bit VID: value should be 0 + * So we use an OR operator to handle it rather than use if condition. + */ + data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff); + data[3] = value & 0xff; + + ret = i2c_master_send(client, data, 4); + + if (ret == 4) + return 0; + else + pr_err("ret=%d\n", ret); + if (ret < 0) + return ret; + else + return -EIO; +} + +static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value) +{ + struct i2c_client *client = context; + struct i2c_msg xfer[2]; + int ret; + __be32 be_reg; + unsigned int index, vid, buf = 0x0; + + /*handle index registers*/ + if (reg <= 0xff) { + rt286_hw_write(client, RT286_COEF_INDEX, reg); + reg = RT286_PROC_COEF; + } + + reg = reg | 0x80000; + vid = (reg >> 8) & 0xfff; + + if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) { + index = (reg >> 8) & 0xf; + reg = (reg & ~0xf0f) | index; + } + be_reg = cpu_to_be32(reg); + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 4; + xfer[0].buf = (u8 *)&be_reg; + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 4; + xfer[1].buf = (u8 *)&buf; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + + *value = be32_to_cpu(buf); + + return 0; +} + +static void rt286_index_sync(struct snd_soc_codec *codec) +{ + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); + int i; + + for (i = 0; i < INDEX_CACHE_SIZE; i++) { + snd_soc_write(codec, rt286->index_cache[i].reg, + rt286->index_cache[i].def); + } +} + +static int rt286_support_power_controls[] = { + RT286_DAC_OUT1, + RT286_DAC_OUT2, + RT286_ADC_IN1, + RT286_ADC_IN2, + RT286_MIC1, + RT286_DMIC1, + RT286_DMIC2, + RT286_SPK_OUT, + RT286_HP_OUT, +}; +#define RT286_POWER_REG_LEN ARRAY_SIZE(rt286_support_power_controls) + +static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) +{ + unsigned int val, buf; + int i; + + *hp = false; + *mic = false; + + if (rt286->pdata.cbj_en) { + regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); + *hp = buf & 0x80000000; + if (*hp) { + /* power on HV,VERF */ + regmap_update_bits(rt286->regmap, + RT286_POWER_CTRL1, 0x1001, 0x0); + /* power LDO1 */ + regmap_update_bits(rt286->regmap, + RT286_POWER_CTRL2, 0x4, 0x4); + regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); + regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val); + + msleep(200); + i = 40; + while (((val & 0x0800) == 0) && (i > 0)) { + regmap_read(rt286->regmap, + RT286_CBJ_CTRL2, &val); + i--; + msleep(20); + } + + if (0x0400 == (val & 0x0700)) { + *mic = false; + + regmap_write(rt286->regmap, + RT286_SET_MIC1, 0x20); + /* power off HV,VERF */ + regmap_update_bits(rt286->regmap, + RT286_POWER_CTRL1, 0x1001, 0x1001); + regmap_update_bits(rt286->regmap, + RT286_A_BIAS_CTRL3, 0xc000, 0x0000); + regmap_update_bits(rt286->regmap, + RT286_CBJ_CTRL1, 0x0030, 0x0000); + regmap_update_bits(rt286->regmap, + RT286_A_BIAS_CTRL2, 0xc000, 0x0000); + } else if ((0x0200 == (val & 0x0700)) || + (0x0100 == (val & 0x0700))) { + *mic = true; + regmap_update_bits(rt286->regmap, + RT286_A_BIAS_CTRL3, 0xc000, 0x8000); + regmap_update_bits(rt286->regmap, + RT286_CBJ_CTRL1, 0x0030, 0x0020); + regmap_update_bits(rt286->regmap, + RT286_A_BIAS_CTRL2, 0xc000, 0x8000); + } else { + *mic = false; + } + + regmap_update_bits(rt286->regmap, + RT286_MISC_CTRL1, + 0x0060, 0x0000); + } else { + regmap_update_bits(rt286->regmap, + RT286_MISC_CTRL1, + 0x0060, 0x0020); + regmap_update_bits(rt286->regmap, + RT286_A_BIAS_CTRL3, + 0xc000, 0x8000); + regmap_update_bits(rt286->regmap, + RT286_CBJ_CTRL1, + 0x0030, 0x0020); + regmap_update_bits(rt286->regmap, + RT286_A_BIAS_CTRL2, + 0xc000, 0x8000); + + *mic = false; + } + } else { + regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); + *hp = buf & 0x80000000; + regmap_read(rt286->regmap, RT286_GET_MIC1_SENSE, &buf); + *mic = buf & 0x80000000; + } + + return 0; +} + +static void rt286_jack_detect_work(struct work_struct *work) +{ + struct rt286_priv *rt286 = + container_of(work, struct rt286_priv, jack_detect_work.work); + int status = 0; + bool hp = false; + bool mic = false; + + rt286_jack_detect(rt286, &hp, &mic); + + if (hp == true) + status |= SND_JACK_HEADPHONE; + + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt286->jack, status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); +} + +int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) +{ + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); + + rt286->jack = jack; + + /* Send an initial empty report */ + snd_soc_jack_report(rt286->jack, 0, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + + return 0; +} +EXPORT_SYMBOL_GPL(rt286_mic_detect); + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt286_snd_controls[] = { + SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT286_DACL_GAIN, + RT286_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT286_ADCL_GAIN, + RT286_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_SINGLE_TLV("AMIC Volume", RT286_MIC_GAIN, + 0, 0x3, 0, mic_vol_tlv), + SOC_DOUBLE_R("Speaker Playback Switch", RT286_SPOL_GAIN, + RT286_SPOR_GAIN, RT286_MUTE_SFT, 1, 1), +}; + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt286_front_mix[] = { + SOC_DAPM_SINGLE("DAC Switch", RT286_F_DAC_SWITCH, + RT286_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("RECMIX Switch", RT286_F_RECMIX_SWITCH, + RT286_MUTE_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt286_rec_mix[] = { + SOC_DAPM_SINGLE("Mic1 Switch", RT286_REC_MIC_SWITCH, + RT286_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("I2S Switch", RT286_REC_I2S_SWITCH, + RT286_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("Line1 Switch", RT286_REC_LINE_SWITCH, + RT286_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("Beep Switch", RT286_REC_BEEP_SWITCH, + RT286_MUTE_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new spo_enable_control = + SOC_DAPM_SINGLE("Switch", RT286_SET_PIN_SPK, + RT286_SET_PIN_SFT, 1, 0); + +static const struct snd_kcontrol_new hpol_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT286_HPOL_GAIN, + RT286_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpor_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT286_HPOR_GAIN, + RT286_MUTE_SFT, 1, 1); + +/* ADC0 source */ +static const char * const rt286_adc_src[] = { + "Mic", "RECMIX", "Dmic" +}; + +static const int rt286_adc_values[] = { + 0, 4, 5, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL( + rt286_adc0_enum, RT286_ADC0_MUX, RT286_ADC_SEL_SFT, + RT286_ADC_SEL_MASK, rt286_adc_src, rt286_adc_values); + +static const struct snd_kcontrol_new rt286_adc0_mux = + SOC_DAPM_ENUM("ADC 0 source", rt286_adc0_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL( + rt286_adc1_enum, RT286_ADC1_MUX, RT286_ADC_SEL_SFT, + RT286_ADC_SEL_MASK, rt286_adc_src, rt286_adc_values); + +static const struct snd_kcontrol_new rt286_adc1_mux = + SOC_DAPM_ENUM("ADC 1 source", rt286_adc1_enum); + +static const char * const rt286_dac_src[] = { + "Front", "Surround" +}; +/* HP-OUT source */ +static SOC_ENUM_SINGLE_DECL(rt286_hpo_enum, RT286_HPO_MUX, + 0, rt286_dac_src); + +static const struct snd_kcontrol_new rt286_hpo_mux = +SOC_DAPM_ENUM("HPO source", rt286_hpo_enum); + +/* SPK-OUT source */ +static SOC_ENUM_SINGLE_DECL(rt286_spo_enum, RT286_SPK_MUX, + 0, rt286_dac_src); + +static const struct snd_kcontrol_new rt286_spo_mux = +SOC_DAPM_ENUM("SPO source", rt286_spo_enum); + +static int rt286_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, + RT286_SPK_EAPD, RT286_SET_EAPD_HIGH); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, + RT286_SPK_EAPD, RT286_SET_EAPD_LOW); + break; + + default: + return 0; + } + + return 0; +} + +static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, RT286_SET_PIN_DMIC1, 0x20); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, RT286_SET_PIN_DMIC1, 0); + break; + default: + return 0; + } + + return 0; +} + +static int rt286_adc_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + unsigned int nid; + + nid = (w->reg >> 20) & 0xff; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), + 0x7080, 0x7000); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), + 0x7080, 0x7080); + break; + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC1 Pin"), + SND_SOC_DAPM_INPUT("DMIC2 Pin"), + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("Beep"), + + /* DMIC */ + SND_SOC_DAPM_PGA_E("DMIC1", RT286_SET_POWER(RT286_DMIC1), 0, 1, + NULL, 0, rt286_set_dmic1_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA("DMIC2", RT286_SET_POWER(RT286_DMIC2), 0, 1, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC Receiver", SND_SOC_NOPM, + 0, 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX", SND_SOC_NOPM, 0, 0, + rt286_rec_mix, ARRAY_SIZE(rt286_rec_mix)), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC 0", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1, + &rt286_adc0_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1, + &rt286_adc1_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DACs */ + SND_SOC_DAPM_DAC("DAC 0", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC 1", NULL, SND_SOC_NOPM, 0, 0), + + /* Output Mux */ + SND_SOC_DAPM_MUX("SPK Mux", SND_SOC_NOPM, 0, 0, &rt286_spo_mux), + SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt286_hpo_mux), + + SND_SOC_DAPM_SUPPLY("HP Power", RT286_SET_PIN_HPO, + RT286_SET_PIN_SFT, 0, NULL, 0), + + /* Output Mixer */ + SND_SOC_DAPM_MIXER("Front", RT286_SET_POWER(RT286_DAC_OUT1), 0, 1, + rt286_front_mix, ARRAY_SIZE(rt286_front_mix)), + SND_SOC_DAPM_PGA("Surround", RT286_SET_POWER(RT286_DAC_OUT2), 0, 1, + NULL, 0), + + /* Output Pga */ + SND_SOC_DAPM_SWITCH_E("SPO", SND_SOC_NOPM, 0, 0, + &spo_enable_control, rt286_spk_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0, + &hpol_enable_control), + SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0, + &hpor_enable_control), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), + SND_SOC_DAPM_OUTPUT("HPO Pin"), + SND_SOC_DAPM_OUTPUT("SPDIF"), +}; + +static const struct snd_soc_dapm_route rt286_dapm_routes[] = { + {"DMIC1", NULL, "DMIC1 Pin"}, + {"DMIC2", NULL, "DMIC2 Pin"}, + {"DMIC1", NULL, "DMIC Receiver"}, + {"DMIC2", NULL, "DMIC Receiver"}, + + {"RECMIX", "Beep Switch", "Beep"}, + {"RECMIX", "Line1 Switch", "LINE1"}, + {"RECMIX", "Mic1 Switch", "MIC1"}, + + {"ADC 0 Mux", "Dmic", "DMIC1"}, + {"ADC 0 Mux", "RECMIX", "RECMIX"}, + {"ADC 0 Mux", "Mic", "MIC1"}, + {"ADC 1 Mux", "Dmic", "DMIC2"}, + {"ADC 1 Mux", "RECMIX", "RECMIX"}, + {"ADC 1 Mux", "Mic", "MIC1"}, + + {"ADC 0", NULL, "ADC 0 Mux"}, + {"ADC 1", NULL, "ADC 1 Mux"}, + + {"AIF1TX", NULL, "ADC 0"}, + {"AIF2TX", NULL, "ADC 1"}, + + {"DAC 0", NULL, "AIF1RX"}, + {"DAC 1", NULL, "AIF2RX"}, + + {"Front", "DAC Switch", "DAC 0"}, + {"Front", "RECMIX Switch", "RECMIX"}, + + {"Surround", NULL, "DAC 1"}, + + {"SPK Mux", "Front", "Front"}, + {"SPK Mux", "Surround", "Surround"}, + + {"HPO Mux", "Front", "Front"}, + {"HPO Mux", "Surround", "Surround"}, + + {"SPO", "Switch", "SPK Mux"}, + {"HPO L", "Switch", "HPO Mux"}, + {"HPO R", "Switch", "HPO Mux"}, + {"HPO L", NULL, "HP Power"}, + {"HPO R", NULL, "HP Power"}, + + {"SPOL", NULL, "SPO"}, + {"SPOR", NULL, "SPO"}, + {"HPO Pin", NULL, "HPO L"}, + {"HPO Pin", NULL, "HPO R"}, +}; + +static int rt286_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 rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0; + int d_len_code; + + switch (params_rate(params)) { + /* bit 14 0:48K 1:44.1K */ + case 44100: + val |= 0x4000; + break; + case 48000: + break; + default: + dev_err(codec->dev, "Unsupported sample rate %d\n", + params_rate(params)); + return -EINVAL; + } + switch (rt286->sys_clk) { + case 12288000: + case 24576000: + if (params_rate(params) != 48000) { + dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", + params_rate(params), rt286->sys_clk); + return -EINVAL; + } + break; + case 11289600: + case 22579200: + if (params_rate(params) != 44100) { + dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", + params_rate(params), rt286->sys_clk); + return -EINVAL; + } + break; + } + + if (params_channels(params) <= 16) { + /* bit 3:0 Number of Channel */ + val |= (params_channels(params) - 1); + } else { + dev_err(codec->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + d_len_code = 0; + switch (params_width(params)) { + /* bit 6:4 Bits per Sample */ + case 16: + d_len_code = 0; + val |= (0x1 << 4); + break; + case 32: + d_len_code = 2; + val |= (0x4 << 4); + break; + case 20: + d_len_code = 1; + val |= (0x2 << 4); + break; + case 24: + d_len_code = 2; + val |= (0x3 << 4); + break; + case 8: + d_len_code = 3; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, + RT286_I2S_CTRL1, 0x0018, d_len_code << 3); + dev_dbg(codec->dev, "format val = 0x%x\n", val); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x407f, val); + else + snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x407f, val); + + return 0; +} + +static int rt286_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + snd_soc_update_bits(codec, + RT286_I2S_CTRL1, 0x800, 0x800); + break; + case SND_SOC_DAIFMT_CBS_CFS: + snd_soc_update_bits(codec, + RT286_I2S_CTRL1, 0x800, 0x0); + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + snd_soc_update_bits(codec, + RT286_I2S_CTRL1, 0x300, 0x0); + break; + case SND_SOC_DAIFMT_LEFT_J: + snd_soc_update_bits(codec, + RT286_I2S_CTRL1, 0x300, 0x1 << 8); + break; + case SND_SOC_DAIFMT_DSP_A: + snd_soc_update_bits(codec, + RT286_I2S_CTRL1, 0x300, 0x2 << 8); + break; + case SND_SOC_DAIFMT_DSP_B: + snd_soc_update_bits(codec, + RT286_I2S_CTRL1, 0x300, 0x3 << 8); + break; + default: + return -EINVAL; + } + /* bit 15 Stream Type 0:PCM 1:Non-PCM */ + snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x8000, 0); + snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x8000, 0); + + return 0; +} + +static int rt286_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq); + + if (RT286_SCLK_S_MCLK == clk_id) { + snd_soc_update_bits(codec, + RT286_I2S_CTRL2, 0x0100, 0x0); + snd_soc_update_bits(codec, + RT286_PLL_CTRL1, 0x20, 0x20); + } else { + snd_soc_update_bits(codec, + RT286_I2S_CTRL2, 0x0100, 0x0100); + snd_soc_update_bits(codec, + RT286_PLL_CTRL, 0x4, 0x4); + snd_soc_update_bits(codec, + RT286_PLL_CTRL1, 0x20, 0x0); + } + + switch (freq) { + case 19200000: + if (RT286_SCLK_S_MCLK == clk_id) { + dev_err(codec->dev, "Should not use MCLK\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, + RT286_I2S_CTRL2, 0x40, 0x40); + break; + case 24000000: + if (RT286_SCLK_S_MCLK == clk_id) { + dev_err(codec->dev, "Should not use MCLK\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, + RT286_I2S_CTRL2, 0x40, 0x0); + break; + case 12288000: + case 11289600: + snd_soc_update_bits(codec, + RT286_I2S_CTRL2, 0x8, 0x0); + snd_soc_update_bits(codec, + RT286_CLK_DIV, 0xfc1e, 0x0004); + break; + case 24576000: + case 22579200: + snd_soc_update_bits(codec, + RT286_I2S_CTRL2, 0x8, 0x8); + snd_soc_update_bits(codec, + RT286_CLK_DIV, 0xfc1e, 0x5406); + break; + default: + dev_err(codec->dev, "Unsupported system clock\n"); + return -EINVAL; + } + + rt286->sys_clk = freq; + + return 0; +} + +static int rt286_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + + dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); + if (50 == ratio) + snd_soc_update_bits(codec, + RT286_I2S_CTRL1, 0x1000, 0x1000); + else + snd_soc_update_bits(codec, + RT286_I2S_CTRL1, 0x1000, 0x0); + + + return 0; +} + +static int rt286_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { + snd_soc_write(codec, + RT286_SET_AUDIO_POWER, AC_PWRST_D0); + snd_soc_update_bits(codec, + RT286_DC_GAIN, 0x200, 0x200); + } + break; + + case SND_SOC_BIAS_ON: + mdelay(10); + break; + + case SND_SOC_BIAS_STANDBY: + snd_soc_write(codec, + RT286_SET_AUDIO_POWER, AC_PWRST_D3); + snd_soc_update_bits(codec, + RT286_DC_GAIN, 0x200, 0x0); + break; + + default: + break; + } + codec->dapm.bias_level = level; + + return 0; +} + +static irqreturn_t rt286_irq(int irq, void *data) +{ + struct rt286_priv *rt286 = data; + bool hp = false; + bool mic = false; + int status = 0; + + rt286_jack_detect(rt286, &hp, &mic); + + /* Clear IRQ */ + regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x1, 0x1); + + if (hp == true) + status |= SND_JACK_HEADPHONE; + + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt286->jack, status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + + pm_wakeup_event(&rt286->i2c->dev, 300); + + return IRQ_HANDLED; +} + +static int rt286_probe(struct snd_soc_codec *codec) +{ + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); + + codec->dapm.bias_level = SND_SOC_BIAS_OFF; + + if (rt286->i2c->irq) { + regmap_update_bits(rt286->regmap, + RT286_IRQ_CTRL, 0x2, 0x2); + + INIT_DELAYED_WORK(&rt286->jack_detect_work, + rt286_jack_detect_work); + schedule_delayed_work(&rt286->jack_detect_work, + msecs_to_jiffies(1250)); + } + + return 0; +} + +static int rt286_remove(struct snd_soc_codec *codec) +{ + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); + + cancel_delayed_work_sync(&rt286->jack_detect_work); + + return 0; +} + +#ifdef CONFIG_PM +static int rt286_suspend(struct snd_soc_codec *codec) +{ + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt286->regmap, true); + regcache_mark_dirty(rt286->regmap); + + return 0; +} + +static int rt286_resume(struct snd_soc_codec *codec) +{ + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt286->regmap, false); + rt286_index_sync(codec); + regcache_sync(rt286->regmap); + + return 0; +} +#else +#define rt286_suspend NULL +#define rt286_resume NULL +#endif + +#define RT286_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define RT286_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 rt286_aif_dai_ops = { + .hw_params = rt286_hw_params, + .set_fmt = rt286_set_dai_fmt, + .set_sysclk = rt286_set_dai_sysclk, + .set_bclk_ratio = rt286_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt286_dai[] = { + { + .name = "rt286-aif1", + .id = RT286_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT286_STEREO_RATES, + .formats = RT286_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT286_STEREO_RATES, + .formats = RT286_FORMATS, + }, + .ops = &rt286_aif_dai_ops, + .symmetric_rates = 1, + }, + { + .name = "rt286-aif2", + .id = RT286_AIF2, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT286_STEREO_RATES, + .formats = RT286_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT286_STEREO_RATES, + .formats = RT286_FORMATS, + }, + .ops = &rt286_aif_dai_ops, + .symmetric_rates = 1, + }, + +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt286 = { + .probe = rt286_probe, + .remove = rt286_remove, + .suspend = rt286_suspend, + .resume = rt286_resume, + .set_bias_level = rt286_set_bias_level, + .idle_bias_off = true, + .controls = rt286_snd_controls, + .num_controls = ARRAY_SIZE(rt286_snd_controls), + .dapm_widgets = rt286_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt286_dapm_widgets), + .dapm_routes = rt286_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt286_dapm_routes), +}; + +static const struct regmap_config rt286_regmap = { + .reg_bits = 32, + .val_bits = 32, + .max_register = 0x02370100, + .volatile_reg = rt286_volatile_register, + .readable_reg = rt286_readable_register, + .reg_write = rt286_hw_write, + .reg_read = rt286_hw_read, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt286_reg, + .num_reg_defaults = ARRAY_SIZE(rt286_reg), +}; + +static const struct i2c_device_id rt286_i2c_id[] = { + {"rt286", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt286_i2c_id); + +static const struct acpi_device_id rt286_acpi_match[] = { + { "INT343A", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); + +static int rt286_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt286_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt286_priv *rt286; + int i, ret; + + rt286 = devm_kzalloc(&i2c->dev, sizeof(*rt286), + GFP_KERNEL); + if (NULL == rt286) + return -ENOMEM; + + rt286->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt286_regmap); + if (IS_ERR(rt286->regmap)) { + ret = PTR_ERR(rt286->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt286->regmap, + RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret); + if (ret != RT286_VENDOR_ID) { + dev_err(&i2c->dev, + "Device with ID register %x is not rt286\n", ret); + return -ENODEV; + } + + rt286->index_cache = rt286_index_def; + rt286->i2c = i2c; + i2c_set_clientdata(i2c, rt286); + + if (pdata) + rt286->pdata = *pdata; + + regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); + + for (i = 0; i < RT286_POWER_REG_LEN; i++) + regmap_write(rt286->regmap, + RT286_SET_POWER(rt286_support_power_controls[i]), + AC_PWRST_D1); + + if (!rt286->pdata.cbj_en) { + regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000); + regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816); + regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); + regmap_update_bits(rt286->regmap, + RT286_CBJ_CTRL1, 0xf000, 0xb000); + } else { + regmap_update_bits(rt286->regmap, + RT286_CBJ_CTRL1, 0xf000, 0x5000); + } + + mdelay(10); + + if (!rt286->pdata.gpio2_en) + regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0x4000); + else + regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0); + + mdelay(10); + + /*Power down LDO2*/ + regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0); + + /*Set depop parameter*/ + regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a); + regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); + regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); + + if (rt286->i2c->irq) { + ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286); + if (ret != 0) { + dev_err(&i2c->dev, + "Failed to reguest IRQ: %d\n", ret); + return ret; + } + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt286, + rt286_dai, ARRAY_SIZE(rt286_dai)); + + return ret; +} + +static int rt286_i2c_remove(struct i2c_client *i2c) +{ + struct rt286_priv *rt286 = i2c_get_clientdata(i2c); + + if (i2c->irq) + free_irq(i2c->irq, rt286); + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + + +static struct i2c_driver rt286_i2c_driver = { + .driver = { + .name = "rt286", + .owner = THIS_MODULE, + .acpi_match_table = ACPI_PTR(rt286_acpi_match), + }, + .probe = rt286_i2c_probe, + .remove = rt286_i2c_remove, + .id_table = rt286_i2c_id, +}; + +module_i2c_driver(rt286_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT286 driver"); +MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h new file mode 100644 index 000000000000..b539b7320a79 --- /dev/null +++ b/sound/soc/codecs/rt286.h @@ -0,0 +1,198 @@ +/* + * rt286.h -- RT286 ALSA SoC audio driver + * + * Copyright 2011 Realtek Microelectronics + * Author: Johnny Hsu <johnnyhsu@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 __RT286_H__ +#define __RT286_H__ + +#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D) + +#define RT286_AUDIO_FUNCTION_GROUP 0x01 +#define RT286_DAC_OUT1 0x02 +#define RT286_DAC_OUT2 0x03 +#define RT286_ADC_IN1 0x09 +#define RT286_ADC_IN2 0x08 +#define RT286_MIXER_IN 0x0b +#define RT286_MIXER_OUT1 0x0c +#define RT286_MIXER_OUT2 0x0d +#define RT286_DMIC1 0x12 +#define RT286_DMIC2 0x13 +#define RT286_SPK_OUT 0x14 +#define RT286_MIC1 0x18 +#define RT286_LINE1 0x1a +#define RT286_BEEP 0x1d +#define RT286_SPDIF 0x1e +#define RT286_VENDOR_REGISTERS 0x20 +#define RT286_HP_OUT 0x21 +#define RT286_MIXER_IN1 0x22 +#define RT286_MIXER_IN2 0x23 + +#define RT286_SET_PIN_SFT 6 +#define RT286_SET_PIN_ENABLE 0x40 +#define RT286_SET_PIN_DISABLE 0 +#define RT286_SET_EAPD_HIGH 0x2 +#define RT286_SET_EAPD_LOW 0 + +#define RT286_MUTE_SFT 7 + +/* Verb commands */ +#define RT286_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM) +#define RT286_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0) +#define RT286_SET_AUDIO_POWER RT286_SET_POWER(RT286_AUDIO_FUNCTION_GROUP) +#define RT286_SET_HPO_POWER RT286_SET_POWER(RT286_HP_OUT) +#define RT286_SET_SPK_POWER RT286_SET_POWER(RT286_SPK_OUT) +#define RT286_SET_DMIC1_POWER RT286_SET_POWER(RT286_DMIC1) +#define RT286_SPK_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_SPK_OUT, 0) +#define RT286_HPO_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_HP_OUT, 0) +#define RT286_ADC0_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_MIXER_IN1, 0) +#define RT286_ADC1_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_MIXER_IN2, 0) +#define RT286_SET_MIC1\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_MIC1, 0) +#define RT286_SET_PIN_HPO\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_HP_OUT, 0) +#define RT286_SET_PIN_SPK\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_SPK_OUT, 0) +#define RT286_SET_PIN_DMIC1\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_DMIC1, 0) +#define RT286_SPK_EAPD\ + VERB_CMD(AC_VERB_SET_EAPD_BTLENABLE, RT286_SPK_OUT, 0) +#define RT286_SET_AMP_GAIN_HPO\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0) +#define RT286_SET_AMP_GAIN_ADC_IN1\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0) +#define RT286_SET_AMP_GAIN_ADC_IN2\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN2, 0) +#define RT286_GET_HP_SENSE\ + VERB_CMD(AC_VERB_GET_PIN_SENSE, RT286_HP_OUT, 0) +#define RT286_GET_MIC1_SENSE\ + VERB_CMD(AC_VERB_GET_PIN_SENSE, RT286_MIC1, 0) +#define RT286_SET_DMIC2_DEFAULT\ + VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT286_DMIC2, 0) +#define RT286_DACL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_DAC_OUT1, 0xa000) +#define RT286_DACR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_DAC_OUT1, 0x9000) +#define RT286_ADCL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0x6000) +#define RT286_ADCR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0x5000) +#define RT286_MIC_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIC1, 0x7000) +#define RT286_SPOL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_SPK_OUT, 0xa000) +#define RT286_SPOR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_SPK_OUT, 0x9000) +#define RT286_HPOL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0xa000) +#define RT286_HPOR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0x9000) +#define RT286_F_DAC_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_OUT1, 0x7000) +#define RT286_F_RECMIX_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_OUT1, 0x7100) +#define RT286_REC_MIC_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7000) +#define RT286_REC_I2S_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7100) +#define RT286_REC_LINE_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7200) +#define RT286_REC_BEEP_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7300) +#define RT286_DAC_FORMAT\ + VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT286_DAC_OUT1, 0) +#define RT286_ADC_FORMAT\ + VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT286_ADC_IN1, 0) +#define RT286_COEF_INDEX\ + VERB_CMD(AC_VERB_SET_COEF_INDEX, RT286_VENDOR_REGISTERS, 0) +#define RT286_PROC_COEF\ + VERB_CMD(AC_VERB_SET_PROC_COEF, RT286_VENDOR_REGISTERS, 0) + +/* Index registers */ +#define RT286_A_BIAS_CTRL1 0x01 +#define RT286_A_BIAS_CTRL2 0x02 +#define RT286_POWER_CTRL1 0x03 +#define RT286_A_BIAS_CTRL3 0x04 +#define RT286_POWER_CTRL2 0x08 +#define RT286_I2S_CTRL1 0x09 +#define RT286_I2S_CTRL2 0x0a +#define RT286_CLK_DIV 0x0b +#define RT286_DC_GAIN 0x0d +#define RT286_POWER_CTRL3 0x0f +#define RT286_MIC1_DET_CTRL 0x19 +#define RT286_MISC_CTRL1 0x20 +#define RT286_IRQ_CTRL 0x33 +#define RT286_PLL_CTRL1 0x49 +#define RT286_CBJ_CTRL1 0x4f +#define RT286_CBJ_CTRL2 0x50 +#define RT286_PLL_CTRL 0x63 +#define RT286_DEPOP_CTRL1 0x66 +#define RT286_DEPOP_CTRL2 0x67 +#define RT286_DEPOP_CTRL3 0x68 +#define RT286_DEPOP_CTRL4 0x69 + +/* SPDIF (0x06) */ +#define RT286_SPDIF_SEL_SFT 0 +#define RT286_SPDIF_SEL_PCM0 0 +#define RT286_SPDIF_SEL_PCM1 1 +#define RT286_SPDIF_SEL_SPOUT 2 +#define RT286_SPDIF_SEL_PP 3 + +/* RECMIX (0x0b) */ +#define RT286_M_REC_BEEP_SFT 0 +#define RT286_M_REC_LINE1_SFT 1 +#define RT286_M_REC_MIC1_SFT 2 +#define RT286_M_REC_I2S_SFT 3 + +/* Front (0x0c) */ +#define RT286_M_FRONT_DAC_SFT 0 +#define RT286_M_FRONT_REC_SFT 1 + +/* SPK-OUT (0x14) */ +#define RT286_M_SPK_MUX_SFT 14 +#define RT286_SPK_SEL_MASK 0x1 +#define RT286_SPK_SEL_SFT 0 +#define RT286_SPK_SEL_F 0 +#define RT286_SPK_SEL_S 1 + +/* HP-OUT (0x21) */ +#define RT286_M_HP_MUX_SFT 14 +#define RT286_HP_SEL_MASK 0x1 +#define RT286_HP_SEL_SFT 0 +#define RT286_HP_SEL_F 0 +#define RT286_HP_SEL_S 1 + +/* ADC (0x22) (0x23) */ +#define RT286_ADC_SEL_MASK 0x7 +#define RT286_ADC_SEL_SFT 0 +#define RT286_ADC_SEL_SURR 0 +#define RT286_ADC_SEL_FRONT 1 +#define RT286_ADC_SEL_DMIC 2 +#define RT286_ADC_SEL_BEEP 4 +#define RT286_ADC_SEL_LINE1 5 +#define RT286_ADC_SEL_I2S 6 +#define RT286_ADC_SEL_MIC1 7 + +#define RT286_SCLK_S_MCLK 0 +#define RT286_SCLK_S_PLL 1 + +enum { + RT286_AIF1, + RT286_AIF2, + RT286_AIFS, +}; + +int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack); + +#endif /* __RT286_H__ */ + diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 30e234708579..1ba27db660a6 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1370,16 +1370,16 @@ static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream, return coeff; } - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: break; - case SNDRV_PCM_FORMAT_S20_3LE: + case 20: iface |= RT5631_SDP_I2S_DL_20; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: iface |= RT5631_SDP_I2S_DL_24; break; - case SNDRV_PCM_FORMAT_S8: + case 8: iface |= RT5631_SDP_I2S_DL_8; break; default: diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index de80e89b5fd8..6bc6efdec550 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2215,14 +2215,8 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, rt5640->hp_mute = 1; - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, - rt5640_dai, ARRAY_SIZE(rt5640_dai)); - if (ret < 0) - goto err; - - return 0; -err: - return ret; + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, + rt5640_dai, ARRAY_SIZE(rt5640_dai)); } static int rt5640_i2c_remove(struct i2c_client *i2c) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 02147be2b302..a7762d0a623e 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2345,14 +2345,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, } - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, - rt5645_dai, ARRAY_SIZE(rt5645_dai)); - if (ret < 0) - goto err; - - return 0; -err: - return ret; + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, + rt5645_dai, ARRAY_SIZE(rt5645_dai)); } static int rt5645_i2c_remove(struct i2c_client *i2c) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index ea4b1c652a26..bb0a3ab5416c 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1366,16 +1366,16 @@ static int rt5651_hw_params(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", bclk_ms, pre_div, dai->id); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: break; - case SNDRV_PCM_FORMAT_S20_3LE: + case 20: val_len |= RT5651_I2S_DL_20; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: val_len |= RT5651_I2S_DL_24; break; - case SNDRV_PCM_FORMAT_S8: + case 8: val_len |= RT5651_I2S_DL_8; break; default: diff --git a/sound/soc/codecs/rt5670-dsp.h b/sound/soc/codecs/rt5670-dsp.h new file mode 100644 index 000000000000..a34d0cdb8198 --- /dev/null +++ b/sound/soc/codecs/rt5670-dsp.h @@ -0,0 +1,54 @@ +/* + * rt5670-dsp.h -- RT5670 ALSA SoC DSP driver + * + * Copyright 2014 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 __RT5670_DSP_H__ +#define __RT5670_DSP_H__ + +#define RT5670_DSP_CTRL1 0xe0 +#define RT5670_DSP_CTRL2 0xe1 +#define RT5670_DSP_CTRL3 0xe2 +#define RT5670_DSP_CTRL4 0xe3 +#define RT5670_DSP_CTRL5 0xe4 + +/* DSP Control 1 (0xe0) */ +#define RT5670_DSP_CMD_MASK (0xff << 8) +#define RT5670_DSP_CMD_PE (0x0d << 8) /* Patch Entry */ +#define RT5670_DSP_CMD_MW (0x3b << 8) /* Memory Write */ +#define RT5670_DSP_CMD_MR (0x37 << 8) /* Memory Read */ +#define RT5670_DSP_CMD_RR (0x60 << 8) /* Register Read */ +#define RT5670_DSP_CMD_RW (0x68 << 8) /* Register Write */ +#define RT5670_DSP_REG_DATHI (0x26 << 8) /* High Data Addr */ +#define RT5670_DSP_REG_DATLO (0x25 << 8) /* Low Data Addr */ +#define RT5670_DSP_CLK_MASK (0x3 << 6) +#define RT5670_DSP_CLK_SFT 6 +#define RT5670_DSP_CLK_768K (0x0 << 6) +#define RT5670_DSP_CLK_384K (0x1 << 6) +#define RT5670_DSP_CLK_192K (0x2 << 6) +#define RT5670_DSP_CLK_96K (0x3 << 6) +#define RT5670_DSP_BUSY_MASK (0x1 << 5) +#define RT5670_DSP_RW_MASK (0x1 << 4) +#define RT5670_DSP_DL_MASK (0x3 << 2) +#define RT5670_DSP_DL_0 (0x0 << 2) +#define RT5670_DSP_DL_1 (0x1 << 2) +#define RT5670_DSP_DL_2 (0x2 << 2) +#define RT5670_DSP_DL_3 (0x3 << 2) +#define RT5670_DSP_I2C_AL_16 (0x1 << 1) +#define RT5670_DSP_CMD_EN (0x1) + +struct rt5670_dsp_param { + u16 cmd_fmt; + u16 addr; + u16 data; + u8 cmd; +}; + +#endif /* __RT5670_DSP_H__ */ + diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c new file mode 100644 index 000000000000..ba9d9b4d4857 --- /dev/null +++ b/sound/soc/codecs/rt5670.c @@ -0,0 +1,2657 @@ +/* + * rt5670.c -- RT5670 ALSA SoC audio codec driver + * + * Copyright 2014 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 <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/rt5670.h> + +#include "rl6231.h" +#include "rt5670.h" +#include "rt5670-dsp.h" + +#define RT5670_DEVICE_ID 0x6271 + +#define RT5670_PR_RANGE_BASE (0xff + 1) +#define RT5670_PR_SPACING 0x100 + +#define RT5670_PR_BASE (RT5670_PR_RANGE_BASE + (0 * RT5670_PR_SPACING)) + +static const struct regmap_range_cfg rt5670_ranges[] = { + { .name = "PR", .range_min = RT5670_PR_BASE, + .range_max = RT5670_PR_BASE + 0xf8, + .selector_reg = RT5670_PRIV_INDEX, + .selector_mask = 0xff, + .selector_shift = 0x0, + .window_start = RT5670_PRIV_DATA, + .window_len = 0x1, }, +}; + +static struct reg_default init_list[] = { + { RT5670_PR_BASE + 0x14, 0x9a8a }, + { RT5670_PR_BASE + 0x38, 0x3ba1 }, + { RT5670_PR_BASE + 0x3d, 0x3640 }, +}; +#define RT5670_INIT_REG_LEN ARRAY_SIZE(init_list) + +static const struct reg_default rt5670_reg[] = { + { 0x00, 0x0000 }, + { 0x02, 0x8888 }, + { 0x03, 0x8888 }, + { 0x0a, 0x0001 }, + { 0x0b, 0x0827 }, + { 0x0c, 0x0000 }, + { 0x0d, 0x0008 }, + { 0x0e, 0x0000 }, + { 0x0f, 0x0808 }, + { 0x19, 0xafaf }, + { 0x1a, 0xafaf }, + { 0x1b, 0x0011 }, + { 0x1c, 0x2f2f }, + { 0x1d, 0x2f2f }, + { 0x1e, 0x0000 }, + { 0x1f, 0x2f2f }, + { 0x20, 0x0000 }, + { 0x26, 0x7860 }, + { 0x27, 0x7860 }, + { 0x28, 0x7871 }, + { 0x29, 0x8080 }, + { 0x2a, 0x5656 }, + { 0x2b, 0x5454 }, + { 0x2c, 0xaaa0 }, + { 0x2d, 0x0000 }, + { 0x2e, 0x2f2f }, + { 0x2f, 0x1002 }, + { 0x30, 0x0000 }, + { 0x31, 0x5f00 }, + { 0x32, 0x0000 }, + { 0x33, 0x0000 }, + { 0x34, 0x0000 }, + { 0x35, 0x0000 }, + { 0x36, 0x0000 }, + { 0x37, 0x0000 }, + { 0x38, 0x0000 }, + { 0x3b, 0x0000 }, + { 0x3c, 0x007f }, + { 0x3d, 0x0000 }, + { 0x3e, 0x007f }, + { 0x45, 0xe00f }, + { 0x4c, 0x5380 }, + { 0x4f, 0x0073 }, + { 0x52, 0x00d3 }, + { 0x53, 0xf0f0 }, + { 0x61, 0x0000 }, + { 0x62, 0x0001 }, + { 0x63, 0x00c3 }, + { 0x64, 0x0000 }, + { 0x65, 0x0000 }, + { 0x66, 0x0000 }, + { 0x6f, 0x8000 }, + { 0x70, 0x8000 }, + { 0x71, 0x8000 }, + { 0x72, 0x8000 }, + { 0x73, 0x1110 }, + { 0x74, 0x0e00 }, + { 0x75, 0x1505 }, + { 0x76, 0x0015 }, + { 0x77, 0x0c00 }, + { 0x78, 0x4000 }, + { 0x79, 0x0123 }, + { 0x7f, 0x1100 }, + { 0x80, 0x0000 }, + { 0x81, 0x0000 }, + { 0x82, 0x0000 }, + { 0x83, 0x0000 }, + { 0x84, 0x0000 }, + { 0x85, 0x0000 }, + { 0x86, 0x0008 }, + { 0x87, 0x0000 }, + { 0x88, 0x0000 }, + { 0x89, 0x0000 }, + { 0x8a, 0x0000 }, + { 0x8b, 0x0000 }, + { 0x8c, 0x0007 }, + { 0x8d, 0x0000 }, + { 0x8e, 0x0004 }, + { 0x8f, 0x1100 }, + { 0x90, 0x0646 }, + { 0x91, 0x0c06 }, + { 0x93, 0x0000 }, + { 0x94, 0x0000 }, + { 0x95, 0x0000 }, + { 0x97, 0x0000 }, + { 0x98, 0x0000 }, + { 0x99, 0x0000 }, + { 0x9a, 0x2184 }, + { 0x9b, 0x010a }, + { 0x9c, 0x0aea }, + { 0x9d, 0x000c }, + { 0x9e, 0x0400 }, + { 0xae, 0x7000 }, + { 0xaf, 0x0000 }, + { 0xb0, 0x6000 }, + { 0xb1, 0x0000 }, + { 0xb2, 0x0000 }, + { 0xb3, 0x001f }, + { 0xb4, 0x2206 }, + { 0xb5, 0x1f00 }, + { 0xb6, 0x0000 }, + { 0xb7, 0x0000 }, + { 0xbb, 0x0000 }, + { 0xbc, 0x0000 }, + { 0xbd, 0x0000 }, + { 0xbe, 0x0000 }, + { 0xbf, 0x0000 }, + { 0xc0, 0x0000 }, + { 0xc1, 0x0000 }, + { 0xc2, 0x0000 }, + { 0xcd, 0x0000 }, + { 0xce, 0x0000 }, + { 0xcf, 0x1813 }, + { 0xd0, 0x0690 }, + { 0xd1, 0x1c17 }, + { 0xd3, 0xb320 }, + { 0xd4, 0x0000 }, + { 0xd6, 0x0400 }, + { 0xd9, 0x0809 }, + { 0xda, 0x0000 }, + { 0xdb, 0x0001 }, + { 0xdc, 0x0049 }, + { 0xdd, 0x0009 }, + { 0xe6, 0x8000 }, + { 0xe7, 0x0000 }, + { 0xec, 0xb300 }, + { 0xed, 0x0000 }, + { 0xee, 0xb300 }, + { 0xef, 0x0000 }, + { 0xf8, 0x0000 }, + { 0xf9, 0x0000 }, + { 0xfa, 0x8010 }, + { 0xfb, 0x0033 }, + { 0xfc, 0x0080 }, +}; + +static bool rt5670_volatile_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5670_ranges); i++) { + if ((reg >= rt5670_ranges[i].window_start && + reg <= rt5670_ranges[i].window_start + + rt5670_ranges[i].window_len) || + (reg >= rt5670_ranges[i].range_min && + reg <= rt5670_ranges[i].range_max)) { + return true; + } + } + + switch (reg) { + case RT5670_RESET: + case RT5670_PDM_DATA_CTRL1: + case RT5670_PDM1_DATA_CTRL4: + case RT5670_PDM2_DATA_CTRL4: + case RT5670_PRIV_DATA: + case RT5670_ASRC_5: + case RT5670_CJ_CTRL1: + case RT5670_CJ_CTRL2: + case RT5670_CJ_CTRL3: + case RT5670_A_JD_CTRL1: + case RT5670_A_JD_CTRL2: + case RT5670_VAD_CTRL5: + case RT5670_ADC_EQ_CTRL1: + case RT5670_EQ_CTRL1: + case RT5670_ALC_CTRL_1: + case RT5670_IRQ_CTRL1: + case RT5670_IRQ_CTRL2: + case RT5670_INT_IRQ_ST: + case RT5670_IL_CMD: + case RT5670_DSP_CTRL1: + case RT5670_DSP_CTRL2: + case RT5670_DSP_CTRL3: + case RT5670_DSP_CTRL4: + case RT5670_DSP_CTRL5: + case RT5670_VENDOR_ID: + case RT5670_VENDOR_ID1: + case RT5670_VENDOR_ID2: + return true; + default: + return false; + } +} + +static bool rt5670_readable_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5670_ranges); i++) { + if ((reg >= rt5670_ranges[i].window_start && + reg <= rt5670_ranges[i].window_start + + rt5670_ranges[i].window_len) || + (reg >= rt5670_ranges[i].range_min && + reg <= rt5670_ranges[i].range_max)) { + return true; + } + } + + switch (reg) { + case RT5670_RESET: + case RT5670_HP_VOL: + case RT5670_LOUT1: + case RT5670_CJ_CTRL1: + case RT5670_CJ_CTRL2: + case RT5670_CJ_CTRL3: + case RT5670_IN2: + case RT5670_INL1_INR1_VOL: + case RT5670_DAC1_DIG_VOL: + case RT5670_DAC2_DIG_VOL: + case RT5670_DAC_CTRL: + case RT5670_STO1_ADC_DIG_VOL: + case RT5670_MONO_ADC_DIG_VOL: + case RT5670_STO2_ADC_DIG_VOL: + case RT5670_ADC_BST_VOL1: + case RT5670_ADC_BST_VOL2: + case RT5670_STO2_ADC_MIXER: + case RT5670_STO1_ADC_MIXER: + case RT5670_MONO_ADC_MIXER: + case RT5670_AD_DA_MIXER: + case RT5670_STO_DAC_MIXER: + case RT5670_DD_MIXER: + case RT5670_DIG_MIXER: + case RT5670_DSP_PATH1: + case RT5670_DSP_PATH2: + case RT5670_DIG_INF1_DATA: + case RT5670_DIG_INF2_DATA: + case RT5670_PDM_OUT_CTRL: + case RT5670_PDM_DATA_CTRL1: + case RT5670_PDM1_DATA_CTRL2: + case RT5670_PDM1_DATA_CTRL3: + case RT5670_PDM1_DATA_CTRL4: + case RT5670_PDM2_DATA_CTRL2: + case RT5670_PDM2_DATA_CTRL3: + case RT5670_PDM2_DATA_CTRL4: + case RT5670_REC_L1_MIXER: + case RT5670_REC_L2_MIXER: + case RT5670_REC_R1_MIXER: + case RT5670_REC_R2_MIXER: + case RT5670_HPO_MIXER: + case RT5670_MONO_MIXER: + case RT5670_OUT_L1_MIXER: + case RT5670_OUT_R1_MIXER: + case RT5670_LOUT_MIXER: + case RT5670_PWR_DIG1: + case RT5670_PWR_DIG2: + case RT5670_PWR_ANLG1: + case RT5670_PWR_ANLG2: + case RT5670_PWR_MIXER: + case RT5670_PWR_VOL: + case RT5670_PRIV_INDEX: + case RT5670_PRIV_DATA: + case RT5670_I2S4_SDP: + case RT5670_I2S1_SDP: + case RT5670_I2S2_SDP: + case RT5670_I2S3_SDP: + case RT5670_ADDA_CLK1: + case RT5670_ADDA_CLK2: + case RT5670_DMIC_CTRL1: + case RT5670_DMIC_CTRL2: + case RT5670_TDM_CTRL_1: + case RT5670_TDM_CTRL_2: + case RT5670_TDM_CTRL_3: + case RT5670_DSP_CLK: + case RT5670_GLB_CLK: + case RT5670_PLL_CTRL1: + case RT5670_PLL_CTRL2: + case RT5670_ASRC_1: + case RT5670_ASRC_2: + case RT5670_ASRC_3: + case RT5670_ASRC_4: + case RT5670_ASRC_5: + case RT5670_ASRC_7: + case RT5670_ASRC_8: + case RT5670_ASRC_9: + case RT5670_ASRC_10: + case RT5670_ASRC_11: + case RT5670_ASRC_12: + case RT5670_ASRC_13: + case RT5670_ASRC_14: + case RT5670_DEPOP_M1: + case RT5670_DEPOP_M2: + case RT5670_DEPOP_M3: + case RT5670_CHARGE_PUMP: + case RT5670_MICBIAS: + case RT5670_A_JD_CTRL1: + case RT5670_A_JD_CTRL2: + case RT5670_VAD_CTRL1: + case RT5670_VAD_CTRL2: + case RT5670_VAD_CTRL3: + case RT5670_VAD_CTRL4: + case RT5670_VAD_CTRL5: + case RT5670_ADC_EQ_CTRL1: + case RT5670_ADC_EQ_CTRL2: + case RT5670_EQ_CTRL1: + case RT5670_EQ_CTRL2: + case RT5670_ALC_DRC_CTRL1: + case RT5670_ALC_DRC_CTRL2: + case RT5670_ALC_CTRL_1: + case RT5670_ALC_CTRL_2: + case RT5670_ALC_CTRL_3: + case RT5670_JD_CTRL: + case RT5670_IRQ_CTRL1: + case RT5670_IRQ_CTRL2: + case RT5670_INT_IRQ_ST: + case RT5670_GPIO_CTRL1: + case RT5670_GPIO_CTRL2: + case RT5670_GPIO_CTRL3: + case RT5670_SCRABBLE_FUN: + case RT5670_SCRABBLE_CTRL: + case RT5670_BASE_BACK: + case RT5670_MP3_PLUS1: + case RT5670_MP3_PLUS2: + case RT5670_ADJ_HPF1: + case RT5670_ADJ_HPF2: + case RT5670_HP_CALIB_AMP_DET: + case RT5670_SV_ZCD1: + case RT5670_SV_ZCD2: + case RT5670_IL_CMD: + case RT5670_IL_CMD2: + case RT5670_IL_CMD3: + case RT5670_DRC_HL_CTRL1: + case RT5670_DRC_HL_CTRL2: + case RT5670_ADC_MONO_HP_CTRL1: + case RT5670_ADC_MONO_HP_CTRL2: + case RT5670_ADC_STO2_HP_CTRL1: + case RT5670_ADC_STO2_HP_CTRL2: + case RT5670_JD_CTRL3: + case RT5670_JD_CTRL4: + case RT5670_DIG_MISC: + case RT5670_DSP_CTRL1: + case RT5670_DSP_CTRL2: + case RT5670_DSP_CTRL3: + case RT5670_DSP_CTRL4: + case RT5670_DSP_CTRL5: + case RT5670_GEN_CTRL2: + case RT5670_GEN_CTRL3: + case RT5670_VENDOR_ID: + case RT5670_VENDOR_ID1: + case RT5670_VENDOR_ID2: + return true; + default: + return false; + } +} + +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); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static unsigned int bst_tlv[] = { + TLV_DB_RANGE_HEAD(7), + 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 rt5670_data_select[] = { + "Normal", "Swap", "left copy to right", "right copy to left" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_if2_dac_enum, RT5670_DIG_INF1_DATA, + RT5670_IF2_DAC_SEL_SFT, rt5670_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_enum, RT5670_DIG_INF1_DATA, + RT5670_IF2_ADC_SEL_SFT, rt5670_data_select); + +static const struct snd_kcontrol_new rt5670_snd_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE("HP Playback Switch", RT5670_HP_VOL, + RT5670_L_MUTE_SFT, RT5670_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("HP Playback Volume", RT5670_HP_VOL, + RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, + 39, 0, out_vol_tlv), + /* OUTPUT Control */ + SOC_DOUBLE("OUT Channel Switch", RT5670_LOUT1, + RT5670_VOL_L_SFT, RT5670_VOL_R_SFT, 1, 1), + SOC_DOUBLE_TLV("OUT Playback Volume", RT5670_LOUT1, + RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, 39, 1, out_vol_tlv), + /* DAC Digital Volume */ + SOC_DOUBLE("DAC2 Playback Switch", RT5670_DAC_CTRL, + RT5670_M_DAC_L2_VOL_SFT, RT5670_M_DAC_R2_VOL_SFT, 1, 1), + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5670_DAC1_DIG_VOL, + RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, + 175, 0, dac_vol_tlv), + SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5670_DAC2_DIG_VOL, + RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, + 175, 0, dac_vol_tlv), + /* IN1/IN2 Control */ + SOC_SINGLE_TLV("IN1 Boost Volume", RT5670_CJ_CTRL1, + RT5670_BST_SFT1, 8, 0, bst_tlv), + SOC_SINGLE_TLV("IN2 Boost Volume", RT5670_IN2, + RT5670_BST_SFT1, 8, 0, bst_tlv), + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5670_INL1_INR1_VOL, + RT5670_INL_VOL_SFT, RT5670_INR_VOL_SFT, + 31, 1, in_vol_tlv), + /* ADC Digital Volume Control */ + SOC_DOUBLE("ADC Capture Switch", RT5670_STO1_ADC_DIG_VOL, + RT5670_L_MUTE_SFT, RT5670_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("ADC Capture Volume", RT5670_STO1_ADC_DIG_VOL, + RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, + 127, 0, adc_vol_tlv), + + SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5670_MONO_ADC_DIG_VOL, + RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, + 127, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5670_ADC_BST_VOL1, + RT5670_STO1_ADC_L_BST_SFT, RT5670_STO1_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5670_ADC_BST_VOL1, + RT5670_STO2_ADC_L_BST_SFT, RT5670_STO2_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_ENUM("ADC IF2 Data Switch", rt5670_if2_adc_enum), + SOC_ENUM("DAC IF2 Data Switch", rt5670_if2_dac_enum), +}; + +/** + * 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 = w->codec; + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + int idx = -EINVAL; + + idx = rl6231_calc_dmic_clk(rt5670->sysclk); + + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else + snd_soc_update_bits(codec, RT5670_DMIC_CTRL1, + RT5670_DMIC_CLK_MASK, idx << RT5670_DMIC_CLK_SFT); + return idx; +} + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + + val = snd_soc_read(source->codec, RT5670_GLB_CLK); + val &= RT5670_SCLK_SRC_MASK; + if (val == RT5670_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +static int is_using_asrc(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, shift, val; + + switch (source->shift) { + case 0: + reg = RT5670_ASRC_3; + shift = 0; + break; + case 1: + reg = RT5670_ASRC_3; + shift = 4; + break; + case 2: + reg = RT5670_ASRC_5; + shift = 12; + break; + case 3: + reg = RT5670_ASRC_2; + shift = 0; + break; + case 8: + reg = RT5670_ASRC_2; + shift = 4; + break; + case 9: + reg = RT5670_ASRC_2; + shift = 8; + break; + case 10: + reg = RT5670_ASRC_2; + shift = 12; + break; + default: + return 0; + } + + val = (snd_soc_read(source->codec, reg) >> shift) & 0xf; + switch (val) { + case 1: + case 2: + case 3: + case 4: + return 1; + default: + return 0; + } + +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, + RT5670_M_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5670_STO1_ADC_MIXER, + RT5670_M_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, + RT5670_M_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5670_STO1_ADC_MIXER, + RT5670_M_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_sto2_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO2_ADC_MIXER, + RT5670_M_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5670_STO2_ADC_MIXER, + RT5670_M_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_sto2_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO2_ADC_MIXER, + RT5670_M_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5670_STO2_ADC_MIXER, + RT5670_M_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_mono_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5670_MONO_ADC_MIXER, + RT5670_M_MONO_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5670_MONO_ADC_MIXER, + RT5670_M_MONO_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_mono_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5670_MONO_ADC_MIXER, + RT5670_M_MONO_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5670_MONO_ADC_MIXER, + RT5670_M_MONO_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER, + RT5670_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER, + RT5670_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER, + RT5670_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER, + RT5670_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_STO_DAC_MIXER, + RT5670_M_DAC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_STO_DAC_MIXER, + RT5670_M_DAC_L2_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_STO_DAC_MIXER, + RT5670_M_DAC_R1_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_STO_DAC_MIXER, + RT5670_M_DAC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_STO_DAC_MIXER, + RT5670_M_DAC_R2_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_STO_DAC_MIXER, + RT5670_M_DAC_L1_STO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_mono_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_DD_MIXER, + RT5670_M_DAC_L1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_DD_MIXER, + RT5670_M_DAC_L2_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_DD_MIXER, + RT5670_M_DAC_R2_MONO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_mono_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_DD_MIXER, + RT5670_M_DAC_R1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_DD_MIXER, + RT5670_M_DAC_R2_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_DD_MIXER, + RT5670_M_DAC_L2_MONO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_dig_l_mix[] = { + SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5670_DIG_MIXER, + RT5670_M_STO_L_DAC_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_DIG_MIXER, + RT5670_M_DAC_L2_DAC_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_DIG_MIXER, + RT5670_M_DAC_R2_DAC_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_dig_r_mix[] = { + SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5670_DIG_MIXER, + RT5670_M_STO_R_DAC_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_DIG_MIXER, + RT5670_M_DAC_R2_DAC_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_DIG_MIXER, + RT5670_M_DAC_L2_DAC_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5670_rec_l_mix[] = { + SOC_DAPM_SINGLE("INL Switch", RT5670_REC_L2_MIXER, + RT5670_M_IN_L_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5670_REC_L2_MIXER, + RT5670_M_BST2_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5670_REC_L2_MIXER, + RT5670_M_BST1_RM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_rec_r_mix[] = { + SOC_DAPM_SINGLE("INR Switch", RT5670_REC_R2_MIXER, + RT5670_M_IN_R_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5670_REC_R2_MIXER, + RT5670_M_BST2_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5670_REC_R2_MIXER, + RT5670_M_BST1_RM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_out_l_mix[] = { + SOC_DAPM_SINGLE("BST1 Switch", RT5670_OUT_L1_MIXER, + RT5670_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5670_OUT_L1_MIXER, + RT5670_M_IN_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_OUT_L1_MIXER, + RT5670_M_DAC_L2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_OUT_L1_MIXER, + RT5670_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_out_r_mix[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5670_OUT_R1_MIXER, + RT5670_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5670_OUT_R1_MIXER, + RT5670_M_IN_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_OUT_R1_MIXER, + RT5670_M_DAC_R2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_OUT_R1_MIXER, + RT5670_M_DAC_R1_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_hpo_mix[] = { + SOC_DAPM_SINGLE("DAC1 Switch", RT5670_HPO_MIXER, + RT5670_M_DAC1_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("HPVOL Switch", RT5670_HPO_MIXER, + RT5670_M_HPVOL_HM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_hpvoll_mix[] = { + SOC_DAPM_SINGLE("DAC1 Switch", RT5670_HPO_MIXER, + RT5670_M_DACL1_HML_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5670_HPO_MIXER, + RT5670_M_INL1_HML_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_hpvolr_mix[] = { + SOC_DAPM_SINGLE("DAC1 Switch", RT5670_HPO_MIXER, + RT5670_M_DACR1_HMR_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5670_HPO_MIXER, + RT5670_M_INR1_HMR_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_lout_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_LOUT_MIXER, + RT5670_M_DAC_L1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_LOUT_MIXER, + RT5670_M_DAC_R1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTMIX L Switch", RT5670_LOUT_MIXER, + RT5670_M_OV_L_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTMIX R Switch", RT5670_LOUT_MIXER, + RT5670_M_OV_R_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_hpl_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_HPO_MIXER, + RT5670_M_DACL1_HML_SFT, 1, 1), + SOC_DAPM_SINGLE("INL1 Switch", RT5670_HPO_MIXER, + RT5670_M_INL1_HML_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5670_hpr_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_HPO_MIXER, + RT5670_M_DACR1_HMR_SFT, 1, 1), + SOC_DAPM_SINGLE("INR1 Switch", RT5670_HPO_MIXER, + RT5670_M_INR1_HMR_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new lout_l_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5670_LOUT1, + RT5670_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5670_LOUT1, + RT5670_R_MUTE_SFT, 1, 1); + +/* DAC1 L/R source */ /* MX-29 [9:8] [11:10] */ +static const char * const rt5670_dac1_src[] = { + "IF1 DAC", "IF2 DAC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_dac1l_enum, RT5670_AD_DA_MIXER, + RT5670_DAC1_L_SEL_SFT, rt5670_dac1_src); + +static const struct snd_kcontrol_new rt5670_dac1l_mux = + SOC_DAPM_ENUM("DAC1 L source", rt5670_dac1l_enum); + +static SOC_ENUM_SINGLE_DECL(rt5670_dac1r_enum, RT5670_AD_DA_MIXER, + RT5670_DAC1_R_SEL_SFT, rt5670_dac1_src); + +static const struct snd_kcontrol_new rt5670_dac1r_mux = + SOC_DAPM_ENUM("DAC1 R source", rt5670_dac1r_enum); + +/*DAC2 L/R source*/ /* MX-1B [6:4] [2:0] */ +/* TODO Use SOC_VALUE_ENUM_SINGLE_DECL */ +static const char * const rt5670_dac12_src[] = { + "IF1 DAC", "IF2 DAC", "IF3 DAC", "TxDC DAC", + "Bass", "VAD_ADC", "IF4 DAC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_dac2l_enum, RT5670_DAC_CTRL, + RT5670_DAC2_L_SEL_SFT, rt5670_dac12_src); + +static const struct snd_kcontrol_new rt5670_dac_l2_mux = + SOC_DAPM_ENUM("DAC2 L source", rt5670_dac2l_enum); + +static const char * const rt5670_dacr2_src[] = { + "IF1 DAC", "IF2 DAC", "IF3 DAC", "TxDC DAC", "TxDP ADC", "IF4 DAC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_dac2r_enum, RT5670_DAC_CTRL, + RT5670_DAC2_R_SEL_SFT, rt5670_dacr2_src); + +static const struct snd_kcontrol_new rt5670_dac_r2_mux = + SOC_DAPM_ENUM("DAC2 R source", rt5670_dac2r_enum); + +/*RxDP source*/ /* MX-2D [15:13] */ +static const char * const rt5670_rxdp_src[] = { + "IF2 DAC", "IF1 DAC", "STO1 ADC Mixer", "STO2 ADC Mixer", + "Mono ADC Mixer L", "Mono ADC Mixer R", "DAC1" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_rxdp_enum, RT5670_DSP_PATH1, + RT5670_RXDP_SEL_SFT, rt5670_rxdp_src); + +static const struct snd_kcontrol_new rt5670_rxdp_mux = + SOC_DAPM_ENUM("DAC2 L source", rt5670_rxdp_enum); + +/* MX-2D [1] [0] */ +static const char * const rt5670_dsp_bypass_src[] = { + "DSP", "Bypass" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_dsp_ul_enum, RT5670_DSP_PATH1, + RT5670_DSP_UL_SFT, rt5670_dsp_bypass_src); + +static const struct snd_kcontrol_new rt5670_dsp_ul_mux = + SOC_DAPM_ENUM("DSP UL source", rt5670_dsp_ul_enum); + +static SOC_ENUM_SINGLE_DECL(rt5670_dsp_dl_enum, RT5670_DSP_PATH1, + RT5670_DSP_DL_SFT, rt5670_dsp_bypass_src); + +static const struct snd_kcontrol_new rt5670_dsp_dl_mux = + SOC_DAPM_ENUM("DSP DL source", rt5670_dsp_dl_enum); + +/* Stereo2 ADC source */ +/* MX-26 [15] */ +static const char * const rt5670_stereo2_adc_lr_src[] = { + "L", "LR" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc_lr_enum, RT5670_STO2_ADC_MIXER, + RT5670_STO2_ADC_SRC_SFT, rt5670_stereo2_adc_lr_src); + +static const struct snd_kcontrol_new rt5670_sto2_adc_lr_mux = + SOC_DAPM_ENUM("Stereo2 ADC LR source", rt5670_stereo2_adc_lr_enum); + +/* Stereo1 ADC source */ +/* MX-27 MX-26 [12] */ +static const char * const rt5670_stereo_adc1_src[] = { + "DAC MIX", "ADC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc1_enum, RT5670_STO1_ADC_MIXER, + RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src); + +static const struct snd_kcontrol_new rt5670_sto_adc_l1_mux = + SOC_DAPM_ENUM("Stereo1 ADC L1 source", rt5670_stereo1_adc1_enum); + +static const struct snd_kcontrol_new rt5670_sto_adc_r1_mux = + SOC_DAPM_ENUM("Stereo1 ADC R1 source", rt5670_stereo1_adc1_enum); + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc1_enum, RT5670_STO2_ADC_MIXER, + RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src); + +static const struct snd_kcontrol_new rt5670_sto2_adc_l1_mux = + SOC_DAPM_ENUM("Stereo2 ADC L1 source", rt5670_stereo2_adc1_enum); + +static const struct snd_kcontrol_new rt5670_sto2_adc_r1_mux = + SOC_DAPM_ENUM("Stereo2 ADC R1 source", rt5670_stereo2_adc1_enum); + +/* MX-27 MX-26 [11] */ +static const char * const rt5670_stereo_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc2_enum, RT5670_STO1_ADC_MIXER, + RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src); + +static const struct snd_kcontrol_new rt5670_sto_adc_l2_mux = + SOC_DAPM_ENUM("Stereo1 ADC L2 source", rt5670_stereo1_adc2_enum); + +static const struct snd_kcontrol_new rt5670_sto_adc_r2_mux = + SOC_DAPM_ENUM("Stereo1 ADC R2 source", rt5670_stereo1_adc2_enum); + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc2_enum, RT5670_STO2_ADC_MIXER, + RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src); + +static const struct snd_kcontrol_new rt5670_sto2_adc_l2_mux = + SOC_DAPM_ENUM("Stereo2 ADC L2 source", rt5670_stereo2_adc2_enum); + +static const struct snd_kcontrol_new rt5670_sto2_adc_r2_mux = + SOC_DAPM_ENUM("Stereo2 ADC R2 source", rt5670_stereo2_adc2_enum); + +/* MX-27 MX26 [10] */ +static const char * const rt5670_stereo_adc_src[] = { + "ADC1L ADC2R", "ADC3" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc_enum, RT5670_STO1_ADC_MIXER, + RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); + +static const struct snd_kcontrol_new rt5670_sto_adc_mux = + SOC_DAPM_ENUM("Stereo1 ADC source", rt5670_stereo1_adc_enum); + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc_enum, RT5670_STO2_ADC_MIXER, + RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); + +static const struct snd_kcontrol_new rt5670_sto2_adc_mux = + SOC_DAPM_ENUM("Stereo2 ADC source", rt5670_stereo2_adc_enum); + +/* MX-27 MX-26 [9:8] */ +static const char * const rt5670_stereo_dmic_src[] = { + "DMIC1", "DMIC2", "DMIC3" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_dmic_enum, RT5670_STO1_ADC_MIXER, + RT5670_DMIC_SRC_SFT, rt5670_stereo_dmic_src); + +static const struct snd_kcontrol_new rt5670_sto1_dmic_mux = + SOC_DAPM_ENUM("Stereo1 DMIC source", rt5670_stereo1_dmic_enum); + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_dmic_enum, RT5670_STO2_ADC_MIXER, + RT5670_DMIC_SRC_SFT, rt5670_stereo_dmic_src); + +static const struct snd_kcontrol_new rt5670_sto2_dmic_mux = + SOC_DAPM_ENUM("Stereo2 DMIC source", rt5670_stereo2_dmic_enum); + +/* MX-27 [0] */ +static const char * const rt5670_stereo_dmic3_src[] = { + "DMIC3", "PDM ADC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_stereo_dmic3_enum, RT5670_STO1_ADC_MIXER, + RT5670_DMIC3_SRC_SFT, rt5670_stereo_dmic3_src); + +static const struct snd_kcontrol_new rt5670_sto_dmic3_mux = + SOC_DAPM_ENUM("Stereo DMIC3 source", rt5670_stereo_dmic3_enum); + +/* Mono ADC source */ +/* MX-28 [12] */ +static const char * const rt5670_mono_adc_l1_src[] = { + "Mono DAC MIXL", "ADC1" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_mono_adc_l1_enum, RT5670_MONO_ADC_MIXER, + RT5670_MONO_ADC_L1_SRC_SFT, rt5670_mono_adc_l1_src); + +static const struct snd_kcontrol_new rt5670_mono_adc_l1_mux = + SOC_DAPM_ENUM("Mono ADC1 left source", rt5670_mono_adc_l1_enum); +/* MX-28 [11] */ +static const char * const rt5670_mono_adc_l2_src[] = { + "Mono DAC MIXL", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_mono_adc_l2_enum, RT5670_MONO_ADC_MIXER, + RT5670_MONO_ADC_L2_SRC_SFT, rt5670_mono_adc_l2_src); + +static const struct snd_kcontrol_new rt5670_mono_adc_l2_mux = + SOC_DAPM_ENUM("Mono ADC2 left source", rt5670_mono_adc_l2_enum); + +/* MX-28 [9:8] */ +static const char * const rt5670_mono_dmic_src[] = { + "DMIC1", "DMIC2", "DMIC3" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_mono_dmic_l_enum, RT5670_MONO_ADC_MIXER, + RT5670_MONO_DMIC_L_SRC_SFT, rt5670_mono_dmic_src); + +static const struct snd_kcontrol_new rt5670_mono_dmic_l_mux = + SOC_DAPM_ENUM("Mono DMIC left source", rt5670_mono_dmic_l_enum); +/* MX-28 [1:0] */ +static SOC_ENUM_SINGLE_DECL(rt5670_mono_dmic_r_enum, RT5670_MONO_ADC_MIXER, + RT5670_MONO_DMIC_R_SRC_SFT, rt5670_mono_dmic_src); + +static const struct snd_kcontrol_new rt5670_mono_dmic_r_mux = + SOC_DAPM_ENUM("Mono DMIC Right source", rt5670_mono_dmic_r_enum); +/* MX-28 [4] */ +static const char * const rt5670_mono_adc_r1_src[] = { + "Mono DAC MIXR", "ADC2" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_mono_adc_r1_enum, RT5670_MONO_ADC_MIXER, + RT5670_MONO_ADC_R1_SRC_SFT, rt5670_mono_adc_r1_src); + +static const struct snd_kcontrol_new rt5670_mono_adc_r1_mux = + SOC_DAPM_ENUM("Mono ADC1 right source", rt5670_mono_adc_r1_enum); +/* MX-28 [3] */ +static const char * const rt5670_mono_adc_r2_src[] = { + "Mono DAC MIXR", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_mono_adc_r2_enum, RT5670_MONO_ADC_MIXER, + RT5670_MONO_ADC_R2_SRC_SFT, rt5670_mono_adc_r2_src); + +static const struct snd_kcontrol_new rt5670_mono_adc_r2_mux = + SOC_DAPM_ENUM("Mono ADC2 right source", rt5670_mono_adc_r2_enum); + +/* MX-2D [3:2] */ +static const char * const rt5670_txdp_slot_src[] = { + "Slot 0-1", "Slot 2-3", "Slot 4-5", "Slot 6-7" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_txdp_slot_enum, RT5670_DSP_PATH1, + RT5670_TXDP_SLOT_SEL_SFT, rt5670_txdp_slot_src); + +static const struct snd_kcontrol_new rt5670_txdp_slot_mux = + SOC_DAPM_ENUM("TxDP Slot source", rt5670_txdp_slot_enum); + +/* MX-2F [15] */ +static const char * const rt5670_if1_adc2_in_src[] = { + "IF_ADC2", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_if1_adc2_in_enum, RT5670_DIG_INF1_DATA, + RT5670_IF1_ADC2_IN_SFT, rt5670_if1_adc2_in_src); + +static const struct snd_kcontrol_new rt5670_if1_adc2_in_mux = + SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5670_if1_adc2_in_enum); + +/* MX-2F [14:12] */ +static const char * const rt5670_if2_adc_in_src[] = { + "IF_ADC1", "IF_ADC2", "IF_ADC3", "TxDC_DAC", "TxDP_ADC", "VAD_ADC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_in_enum, RT5670_DIG_INF1_DATA, + RT5670_IF2_ADC_IN_SFT, rt5670_if2_adc_in_src); + +static const struct snd_kcontrol_new rt5670_if2_adc_in_mux = + SOC_DAPM_ENUM("IF2 ADC IN source", rt5670_if2_adc_in_enum); + +/* MX-30 [5:4] */ +static const char * const rt5670_if4_adc_in_src[] = { + "IF_ADC1", "IF_ADC2", "IF_ADC3" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_if4_adc_in_enum, RT5670_DIG_INF2_DATA, + RT5670_IF4_ADC_IN_SFT, rt5670_if4_adc_in_src); + +static const struct snd_kcontrol_new rt5670_if4_adc_in_mux = + SOC_DAPM_ENUM("IF4 ADC IN source", rt5670_if4_adc_in_enum); + +/* MX-31 [15] [13] [11] [9] */ +static const char * const rt5670_pdm_src[] = { + "Mono DAC", "Stereo DAC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_pdm1_l_enum, RT5670_PDM_OUT_CTRL, + RT5670_PDM1_L_SFT, rt5670_pdm_src); + +static const struct snd_kcontrol_new rt5670_pdm1_l_mux = + SOC_DAPM_ENUM("PDM1 L source", rt5670_pdm1_l_enum); + +static SOC_ENUM_SINGLE_DECL(rt5670_pdm1_r_enum, RT5670_PDM_OUT_CTRL, + RT5670_PDM1_R_SFT, rt5670_pdm_src); + +static const struct snd_kcontrol_new rt5670_pdm1_r_mux = + SOC_DAPM_ENUM("PDM1 R source", rt5670_pdm1_r_enum); + +static SOC_ENUM_SINGLE_DECL(rt5670_pdm2_l_enum, RT5670_PDM_OUT_CTRL, + RT5670_PDM2_L_SFT, rt5670_pdm_src); + +static const struct snd_kcontrol_new rt5670_pdm2_l_mux = + SOC_DAPM_ENUM("PDM2 L source", rt5670_pdm2_l_enum); + +static SOC_ENUM_SINGLE_DECL(rt5670_pdm2_r_enum, RT5670_PDM_OUT_CTRL, + RT5670_PDM2_R_SFT, rt5670_pdm_src); + +static const struct snd_kcontrol_new rt5670_pdm2_r_mux = + SOC_DAPM_ENUM("PDM2 R source", rt5670_pdm2_r_enum); + +/* MX-FA [12] */ +static const char * const rt5670_if1_adc1_in1_src[] = { + "IF_ADC1", "IF1_ADC3" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_if1_adc1_in1_enum, RT5670_DIG_MISC, + RT5670_IF1_ADC1_IN1_SFT, rt5670_if1_adc1_in1_src); + +static const struct snd_kcontrol_new rt5670_if1_adc1_in1_mux = + SOC_DAPM_ENUM("IF1 ADC1 IN1 source", rt5670_if1_adc1_in1_enum); + +/* MX-FA [11] */ +static const char * const rt5670_if1_adc1_in2_src[] = { + "IF1_ADC1_IN1", "IF1_ADC4" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_if1_adc1_in2_enum, RT5670_DIG_MISC, + RT5670_IF1_ADC1_IN2_SFT, rt5670_if1_adc1_in2_src); + +static const struct snd_kcontrol_new rt5670_if1_adc1_in2_mux = + SOC_DAPM_ENUM("IF1 ADC1 IN2 source", rt5670_if1_adc1_in2_enum); + +/* MX-FA [10] */ +static const char * const rt5670_if1_adc2_in1_src[] = { + "IF1_ADC2_IN", "IF1_ADC4" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_if1_adc2_in1_enum, RT5670_DIG_MISC, + RT5670_IF1_ADC2_IN1_SFT, rt5670_if1_adc2_in1_src); + +static const struct snd_kcontrol_new rt5670_if1_adc2_in1_mux = + SOC_DAPM_ENUM("IF1 ADC2 IN1 source", rt5670_if1_adc2_in1_enum); + +/* MX-9D [9:8] */ +static const char * const rt5670_vad_adc_src[] = { + "Sto1 ADC L", "Mono ADC L", "Mono ADC R", "Sto2 ADC L" +}; + +static SOC_ENUM_SINGLE_DECL(rt5670_vad_adc_enum, RT5670_VAD_CTRL4, + RT5670_VAD_SEL_SFT, rt5670_vad_adc_src); + +static const struct snd_kcontrol_new rt5670_vad_adc_mux = + SOC_DAPM_ENUM("VAD ADC source", rt5670_vad_adc_enum); + +static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(rt5670->regmap, RT5670_CHARGE_PUMP, + RT5670_PM_HP_MASK, RT5670_PM_HP_HV); + regmap_update_bits(rt5670->regmap, RT5670_GEN_CTRL2, + 0x0400, 0x0400); + /* headphone amp power on */ + regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, + RT5670_PWR_HA | RT5670_PWR_FV1 | + RT5670_PWR_FV2, RT5670_PWR_HA | + RT5670_PWR_FV1 | RT5670_PWR_FV2); + /* depop parameters */ + regmap_write(rt5670->regmap, RT5670_DEPOP_M2, 0x3100); + regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x8009); + regmap_write(rt5670->regmap, RT5670_PR_BASE + + RT5670_HP_DCC_INT1, 0x9f00); + mdelay(20); + regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x8019); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x0004); + msleep(30); + break; + default: + return 0; + } + + return 0; +} + +static int rt5670_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* headphone unmute sequence */ + regmap_write(rt5670->regmap, RT5670_PR_BASE + + RT5670_MAMP_INT_REG2, 0xb400); + regmap_write(rt5670->regmap, RT5670_DEPOP_M3, 0x0772); + regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x805d); + regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x831d); + regmap_update_bits(rt5670->regmap, RT5670_GEN_CTRL2, + 0x0300, 0x0300); + regmap_update_bits(rt5670->regmap, RT5670_HP_VOL, + RT5670_L_MUTE | RT5670_R_MUTE, 0); + msleep(80); + regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x8019); + break; + + case SND_SOC_DAPM_PRE_PMD: + /* headphone mute sequence */ + regmap_write(rt5670->regmap, RT5670_PR_BASE + + RT5670_MAMP_INT_REG2, 0xb400); + regmap_write(rt5670->regmap, RT5670_DEPOP_M3, 0x0772); + regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x803d); + mdelay(10); + regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x831d); + mdelay(10); + regmap_update_bits(rt5670->regmap, RT5670_HP_VOL, + RT5670_L_MUTE | RT5670_R_MUTE, + RT5670_L_MUTE | RT5670_R_MUTE); + msleep(20); + regmap_update_bits(rt5670->regmap, + RT5670_GEN_CTRL2, 0x0300, 0x0); + regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x8019); + regmap_write(rt5670->regmap, RT5670_DEPOP_M3, 0x0707); + regmap_write(rt5670->regmap, RT5670_PR_BASE + + RT5670_MAMP_INT_REG2, 0xfc00); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5670_bst1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5670_PWR_ANLG2, + RT5670_PWR_BST1_P, RT5670_PWR_BST1_P); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5670_PWR_ANLG2, + RT5670_PWR_BST1_P, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5670_bst2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5670_PWR_ANLG2, + RT5670_PWR_BST2_P, RT5670_PWR_BST2_P); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5670_PWR_ANLG2, + RT5670_PWR_BST2_P, 0); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("PLL1", RT5670_PWR_ANLG2, + RT5670_PWR_PLL_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S DSP", RT5670_PWR_DIG2, + RT5670_PWR_I2S_DSP_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5670_PWR_VOL, + RT5670_PWR_MIC_DET_BIT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5670_ASRC_1, + 11, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5670_ASRC_1, + 12, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5670_ASRC_1, + 10, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5670_ASRC_1, + 9, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1, + 8, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1, + 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1, + 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5670_ASRC_1, + 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5670_ASRC_1, + 0, 0, NULL, 0), + + /* Input Side */ + /* micbias */ + SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5670_PWR_ANLG2, + RT5670_PWR_MB1_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("DMIC L3"), + SND_SOC_DAPM_INPUT("DMIC R3"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + + 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_PGA("DMIC3", 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", RT5670_DMIC_CTRL1, + RT5670_DMIC_1_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5670_DMIC_CTRL1, + RT5670_DMIC_2_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC3 Power", RT5670_DMIC_CTRL1, + RT5670_DMIC_3_EN_SFT, 0, NULL, 0), + /* Boost */ + SND_SOC_DAPM_PGA_E("BST1", RT5670_PWR_ANLG2, RT5670_PWR_BST1_BIT, + 0, NULL, 0, rt5670_bst1_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("BST2", RT5670_PWR_ANLG2, RT5670_PWR_BST2_BIT, + 0, NULL, 0, rt5670_bst2_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + /* Input Volume */ + SND_SOC_DAPM_PGA("INL VOL", RT5670_PWR_VOL, + RT5670_PWR_IN_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR VOL", RT5670_PWR_VOL, + RT5670_PWR_IN_R_BIT, 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIXL", RT5670_PWR_MIXER, RT5670_PWR_RM_L_BIT, 0, + rt5670_rec_l_mix, ARRAY_SIZE(rt5670_rec_l_mix)), + SND_SOC_DAPM_MIXER("RECMIXR", RT5670_PWR_MIXER, RT5670_PWR_RM_R_BIT, 0, + rt5670_rec_r_mix, ARRAY_SIZE(rt5670_rec_r_mix)), + /* ADCs */ + SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC 2", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_PGA("ADC 1_2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("ADC 1 power", RT5670_PWR_DIG1, + RT5670_PWR_ADC_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC 2 power", RT5670_PWR_DIG1, + RT5670_PWR_ADC_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC clock", RT5670_PR_BASE + + RT5670_CHOP_DAC_ADC, 12, 0, NULL, 0), + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto_adc_l2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto_adc_r2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto_adc_l1_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto_adc_r1_mux), + SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto2_dmic_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto2_adc_l2_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto2_adc_r2_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto2_adc_l1_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto2_adc_r1_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC LR Mux", SND_SOC_NOPM, 0, 0, + &rt5670_sto2_adc_lr_mux), + SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5670_mono_dmic_l_mux), + SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5670_mono_dmic_r_mux), + SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_mono_adc_l2_mux), + SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_mono_adc_l1_mux), + SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_mono_adc_r1_mux), + SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_mono_adc_r2_mux), + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5670_PWR_DIG2, + RT5670_PWR_ADC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5670_PWR_DIG2, + RT5670_PWR_ADC_S2F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", RT5670_STO1_ADC_DIG_VOL, + RT5670_L_MUTE_SFT, 1, rt5670_sto1_adc_l_mix, + ARRAY_SIZE(rt5670_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", RT5670_STO1_ADC_DIG_VOL, + RT5670_R_MUTE_SFT, 1, rt5670_sto1_adc_r_mix, + ARRAY_SIZE(rt5670_sto1_adc_r_mix)), + SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5670_sto2_adc_l_mix, + ARRAY_SIZE(rt5670_sto2_adc_l_mix)), + SND_SOC_DAPM_MIXER("Sto2 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5670_sto2_adc_r_mix, + ARRAY_SIZE(rt5670_sto2_adc_r_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5670_PWR_DIG2, + RT5670_PWR_ADC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5670_MONO_ADC_DIG_VOL, + RT5670_L_MUTE_SFT, 1, rt5670_mono_adc_l_mix, + ARRAY_SIZE(rt5670_mono_adc_l_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5670_PWR_DIG2, + RT5670_PWR_ADC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5670_MONO_ADC_DIG_VOL, + RT5670_R_MUTE_SFT, 1, rt5670_mono_adc_r_mix, + ARRAY_SIZE(rt5670_mono_adc_r_mix)), + + /* ADC PGA */ + SND_SOC_DAPM_PGA("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Stereo2 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Stereo2 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + 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), + SND_SOC_DAPM_PGA("VAD_ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* DSP */ + SND_SOC_DAPM_PGA("TxDP_ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("TxDP_ADC_L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("TxDP_ADC_R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("TxDC_DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("TDM Data Mux", SND_SOC_NOPM, 0, 0, + &rt5670_txdp_slot_mux), + + SND_SOC_DAPM_MUX("DSP UL Mux", SND_SOC_NOPM, 0, 0, + &rt5670_dsp_ul_mux), + SND_SOC_DAPM_MUX("DSP DL Mux", SND_SOC_NOPM, 0, 0, + &rt5670_dsp_dl_mux), + + SND_SOC_DAPM_MUX("RxDP Mux", SND_SOC_NOPM, 0, 0, + &rt5670_rxdp_mux), + + /* IF2 Mux */ + SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5670_if2_adc_in_mux), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5670_PWR_DIG1, + RT5670_PWR_I2S1_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 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 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S2", RT5670_PWR_DIG1, + RT5670_PWR_I2S2_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + SND_SOC_DAPM_MUX("IF1 ADC1 IN1 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_if1_adc1_in1_mux), + SND_SOC_DAPM_MUX("IF1 ADC1 IN2 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_if1_adc1_in2_mux), + SND_SOC_DAPM_MUX("IF1 ADC2 IN Mux", SND_SOC_NOPM, 0, 0, + &rt5670_if1_adc2_in_mux), + SND_SOC_DAPM_MUX("IF1 ADC2 IN1 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_if1_adc2_in1_mux), + SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5670_vad_adc_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, + RT5670_GPIO_CTRL1, RT5670_I2S2_PIN_SFT, 1), + + /* Audio DSP */ + SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, + rt5670_dac_l_mix, ARRAY_SIZE(rt5670_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, + rt5670_dac_r_mix, ARRAY_SIZE(rt5670_dac_r_mix)), + SND_SOC_DAPM_PGA("DAC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* DAC2 channel Mux */ + SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5670_dac_r2_mux), + SND_SOC_DAPM_PGA("DAC L2 Volume", RT5670_PWR_DIG1, + RT5670_PWR_DAC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC R2 Volume", RT5670_PWR_DIG1, + RT5670_PWR_DAC_R2_BIT, 0, NULL, 0), + + SND_SOC_DAPM_MUX("DAC1 L Mux", SND_SOC_NOPM, 0, 0, &rt5670_dac1l_mux), + SND_SOC_DAPM_MUX("DAC1 R Mux", SND_SOC_NOPM, 0, 0, &rt5670_dac1r_mux), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5670_PWR_DIG2, + RT5670_PWR_DAC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5670_PWR_DIG2, + RT5670_PWR_DAC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5670_PWR_DIG2, + RT5670_PWR_DAC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5670_sto_dac_l_mix, + ARRAY_SIZE(rt5670_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5670_sto_dac_r_mix, + ARRAY_SIZE(rt5670_sto_dac_r_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5670_mono_dac_l_mix, + ARRAY_SIZE(rt5670_mono_dac_l_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5670_mono_dac_r_mix, + ARRAY_SIZE(rt5670_mono_dac_r_mix)), + SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5670_dig_l_mix, + ARRAY_SIZE(rt5670_dig_l_mix)), + SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5670_dig_r_mix, + ARRAY_SIZE(rt5670_dig_r_mix)), + + /* DACs */ + SND_SOC_DAPM_SUPPLY("DAC L1 Power", RT5670_PWR_DIG1, + RT5670_PWR_DAC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5670_PWR_DIG1, + RT5670_PWR_DAC_R1_BIT, 0, NULL, 0), + 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_DAC("DAC L2", NULL, RT5670_PWR_DIG1, + RT5670_PWR_DAC_L2_BIT, 0), + + SND_SOC_DAPM_DAC("DAC R2", NULL, RT5670_PWR_DIG1, + RT5670_PWR_DAC_R2_BIT, 0), + /* OUT Mixer */ + + SND_SOC_DAPM_MIXER("OUT MIXL", RT5670_PWR_MIXER, RT5670_PWR_OM_L_BIT, + 0, rt5670_out_l_mix, ARRAY_SIZE(rt5670_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5670_PWR_MIXER, RT5670_PWR_OM_R_BIT, + 0, rt5670_out_r_mix, ARRAY_SIZE(rt5670_out_r_mix)), + /* Ouput Volume */ + SND_SOC_DAPM_MIXER("HPOVOL MIXL", RT5670_PWR_VOL, + RT5670_PWR_HV_L_BIT, 0, + rt5670_hpvoll_mix, ARRAY_SIZE(rt5670_hpvoll_mix)), + SND_SOC_DAPM_MIXER("HPOVOL MIXR", RT5670_PWR_VOL, + RT5670_PWR_HV_R_BIT, 0, + rt5670_hpvolr_mix, ARRAY_SIZE(rt5670_hpvolr_mix)), + SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* HPO/LOUT/Mono Mixer */ + SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, + rt5670_hpo_mix, ARRAY_SIZE(rt5670_hpo_mix)), + SND_SOC_DAPM_MIXER("LOUT MIX", RT5670_PWR_ANLG1, RT5670_PWR_LM_BIT, + 0, rt5670_lout_mix, ARRAY_SIZE(rt5670_lout_mix)), + SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM, 0, 0, + rt5670_hp_power_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("HP L Amp", RT5670_PWR_ANLG1, + RT5670_PWR_HP_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("HP R Amp", RT5670_PWR_ANLG1, + RT5670_PWR_HP_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, + rt5670_hp_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0, + &lout_l_enable_control), + SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0, + &lout_r_enable_control), + SND_SOC_DAPM_PGA("LOUT Amp", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* PDM */ + SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2, + RT5670_PWR_PDM1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2, + RT5670_PWR_PDM2_BIT, 0, NULL, 0), + + SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL, + RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux), + SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL, + RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux), + SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL, + RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux), + SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL, + RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux), + + /* 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("PDM1L"), + SND_SOC_DAPM_OUTPUT("PDM1R"), + SND_SOC_DAPM_OUTPUT("PDM2L"), + SND_SOC_DAPM_OUTPUT("PDM2R"), +}; + +static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { + { "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc }, + { "ADC Stereo2 Filter", NULL, "ADC STO2 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 STO ASRC", is_using_asrc }, + + { "I2S1", NULL, "I2S1 ASRC" }, + { "I2S2", NULL, "I2S2 ASRC" }, + + { "DMIC1", NULL, "DMIC L1" }, + { "DMIC1", NULL, "DMIC R1" }, + { "DMIC2", NULL, "DMIC L2" }, + { "DMIC2", NULL, "DMIC R2" }, + { "DMIC3", NULL, "DMIC L3" }, + { "DMIC3", NULL, "DMIC R3" }, + + { "BST1", NULL, "IN1P" }, + { "BST1", NULL, "IN1N" }, + { "BST1", NULL, "Mic Det Power" }, + { "BST2", NULL, "IN2P" }, + { "BST2", NULL, "IN2N" }, + + { "INL VOL", NULL, "IN2P" }, + { "INR VOL", NULL, "IN2N" }, + + { "RECMIXL", "INL Switch", "INL VOL" }, + { "RECMIXL", "BST2 Switch", "BST2" }, + { "RECMIXL", "BST1 Switch", "BST1" }, + + { "RECMIXR", "INR Switch", "INR VOL" }, + { "RECMIXR", "BST2 Switch", "BST2" }, + { "RECMIXR", "BST1 Switch", "BST1" }, + + { "ADC 1", NULL, "RECMIXL" }, + { "ADC 1", NULL, "ADC 1 power" }, + { "ADC 1", NULL, "ADC clock" }, + { "ADC 2", NULL, "RECMIXR" }, + { "ADC 2", NULL, "ADC 2 power" }, + { "ADC 2", NULL, "ADC 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" }, + { "DMIC L3", NULL, "DMIC CLK" }, + { "DMIC L3", NULL, "DMIC3 Power" }, + { "DMIC R3", NULL, "DMIC CLK" }, + { "DMIC R3", NULL, "DMIC3 Power" }, + + { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, + { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, + { "Stereo1 DMIC Mux", "DMIC3", "DMIC3" }, + + { "Stereo2 DMIC Mux", "DMIC1", "DMIC1" }, + { "Stereo2 DMIC Mux", "DMIC2", "DMIC2" }, + { "Stereo2 DMIC Mux", "DMIC3", "DMIC3" }, + + { "Mono DMIC L Mux", "DMIC1", "DMIC L1" }, + { "Mono DMIC L Mux", "DMIC2", "DMIC L2" }, + { "Mono DMIC L Mux", "DMIC3", "DMIC L3" }, + + { "Mono DMIC R Mux", "DMIC1", "DMIC R1" }, + { "Mono DMIC R Mux", "DMIC2", "DMIC R2" }, + { "Mono DMIC R Mux", "DMIC3", "DMIC R3" }, + + { "ADC 1_2", NULL, "ADC 1" }, + { "ADC 1_2", NULL, "ADC 2" }, + + { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" }, + { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, + { "Stereo1 ADC L1 Mux", "ADC", "ADC 1_2" }, + { "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" }, + + { "Stereo1 ADC R1 Mux", "ADC", "ADC 1_2" }, + { "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" }, + { "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC Mux" }, + { "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" }, + + { "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" }, + { "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, + { "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, + { "Mono ADC L1 Mux", "ADC1", "ADC 1" }, + + { "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, + { "Mono ADC R1 Mux", "ADC2", "ADC 2" }, + { "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" }, + { "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, + + { "Sto1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" }, + { "Sto1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" }, + { "Sto1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" }, + { "Sto1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" }, + + { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, + { "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" }, + { "ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, + { "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" }, + { "ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "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" }, + { "ADC Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "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" }, + { "ADC Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "Stereo2 ADC L2 Mux", "DMIC", "Stereo2 DMIC Mux" }, + { "Stereo2 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, + { "Stereo2 ADC L1 Mux", "ADC", "ADC 1_2" }, + { "Stereo2 ADC L1 Mux", "DAC MIX", "DAC MIXL" }, + + { "Stereo2 ADC R1 Mux", "ADC", "ADC 1_2" }, + { "Stereo2 ADC R1 Mux", "DAC MIX", "DAC MIXR" }, + { "Stereo2 ADC R2 Mux", "DMIC", "Stereo2 DMIC Mux" }, + { "Stereo2 ADC R2 Mux", "DAC MIX", "DAC MIXR" }, + + { "Sto2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux" }, + { "Sto2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux" }, + { "Sto2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux" }, + { "Sto2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux" }, + + { "Sto2 ADC LR MIX", NULL, "Sto2 ADC MIXL" }, + { "Sto2 ADC LR MIX", NULL, "Sto2 ADC MIXR" }, + + { "Stereo2 ADC LR Mux", "L", "Sto2 ADC MIXL" }, + { "Stereo2 ADC LR Mux", "LR", "Sto2 ADC LR MIX" }, + + { "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" }, + { "Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter" }, + { "ADC Stereo2 Filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" }, + { "Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter" }, + { "ADC Stereo2 Filter", NULL, "PLL1", is_sys_clk_from_pll }, + + { "VAD ADC Mux", "Sto1 ADC L", "Stereo1 ADC MIXL" }, + { "VAD ADC Mux", "Mono ADC L", "Mono ADC MIXL" }, + { "VAD ADC Mux", "Mono ADC R", "Mono ADC MIXR" }, + { "VAD ADC Mux", "Sto2 ADC L", "Sto2 ADC MIXL" }, + + { "VAD_ADC", NULL, "VAD ADC Mux" }, + + { "IF_ADC1", NULL, "Stereo1 ADC MIXL" }, + { "IF_ADC1", NULL, "Stereo1 ADC MIXR" }, + { "IF_ADC2", NULL, "Mono ADC MIXL" }, + { "IF_ADC2", NULL, "Mono ADC MIXR" }, + { "IF_ADC3", NULL, "Stereo2 ADC MIXL" }, + { "IF_ADC3", NULL, "Stereo2 ADC MIXR" }, + + { "IF1 ADC1 IN1 Mux", "IF_ADC1", "IF_ADC1" }, + { "IF1 ADC1 IN1 Mux", "IF1_ADC3", "IF1_ADC3" }, + + { "IF1 ADC1 IN2 Mux", "IF1_ADC1_IN1", "IF1 ADC1 IN1 Mux" }, + { "IF1 ADC1 IN2 Mux", "IF1_ADC4", "IF1_ADC4" }, + + { "IF1 ADC2 IN Mux", "IF_ADC2", "IF_ADC2" }, + { "IF1 ADC2 IN Mux", "VAD_ADC", "VAD_ADC" }, + + { "IF1 ADC2 IN1 Mux", "IF1_ADC2_IN", "IF1 ADC2 IN Mux" }, + { "IF1 ADC2 IN1 Mux", "IF1_ADC4", "IF1_ADC4" }, + + { "IF1_ADC1" , NULL, "IF1 ADC1 IN2 Mux" }, + { "IF1_ADC2" , NULL, "IF1 ADC2 IN1 Mux" }, + + { "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL" }, + { "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" }, + { "Stereo2 ADC MIX", NULL, "Sto2 ADC MIXL" }, + { "Stereo2 ADC MIX", NULL, "Sto2 ADC MIXR" }, + { "Mono ADC MIX", NULL, "Mono ADC MIXL" }, + { "Mono ADC MIX", NULL, "Mono ADC MIXR" }, + + { "RxDP Mux", "IF2 DAC", "IF2 DAC" }, + { "RxDP Mux", "IF1 DAC", "IF1 DAC2" }, + { "RxDP Mux", "STO1 ADC Mixer", "Stereo1 ADC MIX" }, + { "RxDP Mux", "STO2 ADC Mixer", "Stereo2 ADC MIX" }, + { "RxDP Mux", "Mono ADC Mixer L", "Mono ADC MIXL" }, + { "RxDP Mux", "Mono ADC Mixer R", "Mono ADC MIXR" }, + { "RxDP Mux", "DAC1", "DAC MIX" }, + + { "TDM Data Mux", "Slot 0-1", "Stereo1 ADC MIX" }, + { "TDM Data Mux", "Slot 2-3", "Mono ADC MIX" }, + { "TDM Data Mux", "Slot 4-5", "Stereo2 ADC MIX" }, + { "TDM Data Mux", "Slot 6-7", "IF2 DAC" }, + + { "DSP UL Mux", "Bypass", "TDM Data Mux" }, + { "DSP UL Mux", NULL, "I2S DSP" }, + { "DSP DL Mux", "Bypass", "RxDP Mux" }, + { "DSP DL Mux", NULL, "I2S DSP" }, + + { "TxDP_ADC_L", NULL, "DSP UL Mux" }, + { "TxDP_ADC_R", NULL, "DSP UL Mux" }, + { "TxDC_DAC", NULL, "DSP DL Mux" }, + + { "TxDP_ADC", NULL, "TxDP_ADC_L" }, + { "TxDP_ADC", NULL, "TxDP_ADC_R" }, + + { "IF1 ADC", NULL, "I2S1" }, + { "IF1 ADC", NULL, "IF1_ADC1" }, + { "IF1 ADC", NULL, "IF1_ADC2" }, + { "IF1 ADC", NULL, "IF_ADC3" }, + { "IF1 ADC", NULL, "TxDP_ADC" }, + + { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" }, + { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" }, + { "IF2 ADC Mux", "IF_ADC3", "IF_ADC3" }, + { "IF2 ADC Mux", "TxDC_DAC", "TxDC_DAC" }, + { "IF2 ADC Mux", "TxDP_ADC", "TxDP_ADC" }, + { "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" }, + + { "IF2 ADC L", NULL, "IF2 ADC Mux" }, + { "IF2 ADC R", NULL, "IF2 ADC Mux" }, + + { "IF2 ADC", NULL, "I2S2" }, + { "IF2 ADC", NULL, "IF2 ADC L" }, + { "IF2 ADC", NULL, "IF2 ADC R" }, + + { "AIF1TX", NULL, "IF1 ADC" }, + { "AIF2TX", NULL, "IF2 ADC" }, + + { "IF1 DAC1", NULL, "AIF1RX" }, + { "IF1 DAC2", NULL, "AIF1RX" }, + { "IF2 DAC", NULL, "AIF2RX" }, + + { "IF1 DAC1", NULL, "I2S1" }, + { "IF1 DAC2", NULL, "I2S1" }, + { "IF2 DAC", NULL, "I2S2" }, + + { "IF1 DAC2 L", NULL, "IF1 DAC2" }, + { "IF1 DAC2 R", NULL, "IF1 DAC2" }, + { "IF1 DAC1 L", NULL, "IF1 DAC1" }, + { "IF1 DAC1 R", NULL, "IF1 DAC1" }, + { "IF2 DAC L", NULL, "IF2 DAC" }, + { "IF2 DAC R", NULL, "IF2 DAC" }, + + { "DAC1 L Mux", "IF1 DAC", "IF1 DAC1 L" }, + { "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" }, + + { "DAC1 R Mux", "IF1 DAC", "IF1 DAC1 R" }, + { "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" }, + + { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" }, + { "DAC1 MIXL", "DAC1 Switch", "DAC1 L Mux" }, + { "DAC1 MIXL", NULL, "DAC Stereo1 Filter" }, + { "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" }, + { "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" }, + { "DAC1 MIXR", NULL, "DAC Stereo1 Filter" }, + + { "DAC MIX", NULL, "DAC1 MIXL" }, + { "DAC MIX", NULL, "DAC1 MIXR" }, + + { "Audio DSP", NULL, "DAC1 MIXL" }, + { "Audio DSP", NULL, "DAC1 MIXR" }, + + { "DAC L2 Mux", "IF1 DAC", "IF1 DAC2 L" }, + { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" }, + { "DAC L2 Mux", "TxDC DAC", "TxDC_DAC" }, + { "DAC L2 Mux", "VAD_ADC", "VAD_ADC" }, + { "DAC L2 Volume", NULL, "DAC L2 Mux" }, + { "DAC L2 Volume", NULL, "DAC Mono Left Filter" }, + + { "DAC R2 Mux", "IF1 DAC", "IF1 DAC2 R" }, + { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" }, + { "DAC R2 Mux", "TxDC DAC", "TxDC_DAC" }, + { "DAC R2 Mux", "TxDP ADC", "TxDP_ADC" }, + { "DAC R2 Volume", NULL, "DAC R2 Mux" }, + { "DAC R2 Volume", NULL, "DAC Mono Right Filter" }, + + { "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" }, + { "Stereo DAC MIXL", NULL, "DAC Stereo1 Filter" }, + { "Stereo DAC MIXL", NULL, "DAC L1 Power" }, + { "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, + { "Stereo DAC MIXR", NULL, "DAC Stereo1 Filter" }, + { "Stereo DAC MIXR", NULL, "DAC R1 Power" }, + + { "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" }, + { "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" }, + { "Mono DAC MIXL", NULL, "DAC Mono Left Filter" }, + { "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, + { "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" }, + { "Mono DAC MIXR", NULL, "DAC Mono Right Filter" }, + + { "DAC MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" }, + { "DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" }, + { "DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" }, + { "DAC MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" }, + { "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, + { "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" }, + + { "DAC L1", NULL, "DAC L1 Power" }, + { "DAC L1", NULL, "Stereo DAC MIXL" }, + { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll }, + { "DAC R1", NULL, "DAC R1 Power" }, + { "DAC R1", NULL, "Stereo DAC MIXR" }, + { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll }, + { "DAC L2", NULL, "Mono DAC MIXL" }, + { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll }, + { "DAC R2", NULL, "Mono DAC MIXR" }, + { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll }, + + { "OUT MIXL", "BST1 Switch", "BST1" }, + { "OUT MIXL", "INL Switch", "INL VOL" }, + { "OUT MIXL", "DAC L2 Switch", "DAC L2" }, + { "OUT MIXL", "DAC L1 Switch", "DAC L1" }, + + { "OUT MIXR", "BST2 Switch", "BST2" }, + { "OUT MIXR", "INR Switch", "INR VOL" }, + { "OUT MIXR", "DAC R2 Switch", "DAC R2" }, + { "OUT MIXR", "DAC R1 Switch", "DAC R1" }, + + { "HPOVOL MIXL", "DAC1 Switch", "DAC L1" }, + { "HPOVOL MIXL", "INL Switch", "INL VOL" }, + { "HPOVOL MIXR", "DAC1 Switch", "DAC R1" }, + { "HPOVOL MIXR", "INR Switch", "INR VOL" }, + + { "DAC 2", NULL, "DAC L2" }, + { "DAC 2", NULL, "DAC R2" }, + { "DAC 1", NULL, "DAC L1" }, + { "DAC 1", NULL, "DAC R1" }, + { "HPOVOL", NULL, "HPOVOL MIXL" }, + { "HPOVOL", NULL, "HPOVOL MIXR" }, + { "HPO MIX", "DAC1 Switch", "DAC 1" }, + { "HPO MIX", "HPVOL Switch", "HPOVOL" }, + + { "LOUT MIX", "DAC L1 Switch", "DAC L1" }, + { "LOUT MIX", "DAC R1 Switch", "DAC R1" }, + { "LOUT MIX", "OUTMIX L Switch", "OUT MIXL" }, + { "LOUT MIX", "OUTMIX R Switch", "OUT MIXR" }, + + { "PDM1 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, + { "PDM1 L Mux", "Mono DAC", "Mono DAC MIXL" }, + { "PDM1 L Mux", NULL, "PDM1 Power" }, + { "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, + { "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" }, + { "PDM1 R Mux", NULL, "PDM1 Power" }, + { "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, + { "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" }, + { "PDM2 L Mux", NULL, "PDM2 Power" }, + { "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, + { "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" }, + { "PDM2 R Mux", NULL, "PDM2 Power" }, + + { "HP Amp", NULL, "HPO MIX" }, + { "HP Amp", NULL, "Mic Det Power" }, + { "HPOL", NULL, "HP Amp" }, + { "HPOL", NULL, "HP L Amp" }, + { "HPOL", NULL, "Improve HP Amp Drv" }, + { "HPOR", NULL, "HP Amp" }, + { "HPOR", NULL, "HP R Amp" }, + { "HPOR", NULL, "Improve HP Amp Drv" }, + + { "LOUT Amp", NULL, "LOUT MIX" }, + { "LOUT L Playback", "Switch", "LOUT Amp" }, + { "LOUT R Playback", "Switch", "LOUT Amp" }, + { "LOUTL", NULL, "LOUT L Playback" }, + { "LOUTR", NULL, "LOUT R Playback" }, + { "LOUTL", NULL, "Improve HP Amp Drv" }, + { "LOUTR", NULL, "Improve HP Amp Drv" }, + + { "PDM1L", NULL, "PDM1 L Mux" }, + { "PDM1R", NULL, "PDM1 R Mux" }, + { "PDM2L", NULL, "PDM2 L Mux" }, + { "PDM2R", NULL, "PDM2 R Mux" }, +}; + +static int rt5670_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 rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk; + int pre_div, bclk_ms, frame_size; + + rt5670->lrck[dai->id] = params_rate(params); + pre_div = rl6231_get_clk_info(rt5670->sysclk, rt5670->lrck[dai->id]); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5670->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; + } + bclk_ms = frame_size > 32; + rt5670->bclk[dai->id] = rt5670->lrck[dai->id] * (32 << bclk_ms); + + dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", + rt5670->bclk[dai->id], rt5670->lrck[dai->id]); + dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", + bclk_ms, pre_div, dai->id); + + switch (params_width(params)) { + case 16: + break; + case 20: + val_len |= RT5670_I2S_DL_20; + break; + case 24: + val_len |= RT5670_I2S_DL_24; + break; + case 8: + val_len |= RT5670_I2S_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5670_AIF1: + mask_clk = RT5670_I2S_BCLK_MS1_MASK | RT5670_I2S_PD1_MASK; + val_clk = bclk_ms << RT5670_I2S_BCLK_MS1_SFT | + pre_div << RT5670_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5670_I2S1_SDP, + RT5670_I2S_DL_MASK, val_len); + snd_soc_update_bits(codec, RT5670_ADDA_CLK1, mask_clk, val_clk); + break; + case RT5670_AIF2: + mask_clk = RT5670_I2S_BCLK_MS2_MASK | RT5670_I2S_PD2_MASK; + val_clk = bclk_ms << RT5670_I2S_BCLK_MS2_SFT | + pre_div << RT5670_I2S_PD2_SFT; + snd_soc_update_bits(codec, RT5670_I2S2_SDP, + RT5670_I2S_DL_MASK, val_len); + snd_soc_update_bits(codec, RT5670_ADDA_CLK1, mask_clk, val_clk); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + return 0; +} + +static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5670->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5670_I2S_MS_S; + rt5670->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 |= RT5670_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 |= RT5670_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5670_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5670_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5670_AIF1: + snd_soc_update_bits(codec, RT5670_I2S1_SDP, + RT5670_I2S_MS_MASK | RT5670_I2S_BP_MASK | + RT5670_I2S_DF_MASK, reg_val); + break; + case RT5670_AIF2: + snd_soc_update_bits(codec, RT5670_I2S2_SDP, + RT5670_I2S_MS_MASK | RT5670_I2S_BP_MASK | + RT5670_I2S_DF_MASK, reg_val); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + return 0; +} + +static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) + return 0; + + switch (clk_id) { + case RT5670_SCLK_S_MCLK: + reg_val |= RT5670_SCLK_SRC_MCLK; + break; + case RT5670_SCLK_S_PLL1: + reg_val |= RT5670_SCLK_SRC_PLL1; + break; + case RT5670_SCLK_S_RCCLK: + reg_val |= RT5670_SCLK_SRC_RCCLK; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5670_GLB_CLK, + RT5670_SCLK_SRC_MASK, reg_val); + rt5670->sysclk = freq; + rt5670->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5670_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 rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (source == rt5670->pll_src && freq_in == rt5670->pll_in && + freq_out == rt5670->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5670->pll_in = 0; + rt5670->pll_out = 0; + snd_soc_update_bits(codec, RT5670_GLB_CLK, + RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_MCLK); + return 0; + } + + switch (source) { + case RT5670_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5670_GLB_CLK, + RT5670_PLL1_SRC_MASK, RT5670_PLL1_SRC_MCLK); + break; + case RT5670_PLL1_S_BCLK1: + case RT5670_PLL1_S_BCLK2: + case RT5670_PLL1_S_BCLK3: + case RT5670_PLL1_S_BCLK4: + switch (dai->id) { + case RT5670_AIF1: + snd_soc_update_bits(codec, RT5670_GLB_CLK, + RT5670_PLL1_SRC_MASK, RT5670_PLL1_SRC_BCLK1); + break; + case RT5670_AIF2: + snd_soc_update_bits(codec, RT5670_GLB_CLK, + RT5670_PLL1_SRC_MASK, RT5670_PLL1_SRC_BCLK2); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + 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, RT5670_PLL_CTRL1, + pll_code.n_code << RT5670_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5670_PLL_CTRL2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5670_PLL_M_SFT | + pll_code.m_bp << RT5670_PLL_M_BP_SFT); + + rt5670->pll_in = freq_in; + rt5670->pll_out = freq_out; + rt5670->pll_src = source; + + return 0; +} + +static int rt5670_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 |= (1 << 14); + + switch (slots) { + case 4: + val |= (1 << 12); + break; + case 6: + val |= (2 << 12); + break; + case 8: + val |= (3 << 12); + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + val |= (1 << 10); + break; + case 24: + val |= (2 << 10); + break; + case 32: + val |= (3 << 10); + break; + case 16: + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5670_TDM_CTRL_1, 0x7c00, val); + + return 0; +} + +static int rt5670_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { + snd_soc_update_bits(codec, RT5670_PWR_ANLG1, + RT5670_PWR_VREF1 | RT5670_PWR_MB | + RT5670_PWR_BG | RT5670_PWR_VREF2, + RT5670_PWR_VREF1 | RT5670_PWR_MB | + RT5670_PWR_BG | RT5670_PWR_VREF2); + mdelay(10); + snd_soc_update_bits(codec, RT5670_PWR_ANLG1, + RT5670_PWR_FV1 | RT5670_PWR_FV2, + RT5670_PWR_FV1 | RT5670_PWR_FV2); + snd_soc_update_bits(codec, RT5670_CHARGE_PUMP, + RT5670_OSW_L_MASK | RT5670_OSW_R_MASK, + 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); + } + break; + case SND_SOC_BIAS_STANDBY: + snd_soc_write(codec, RT5670_PWR_DIG1, 0x0000); + snd_soc_write(codec, RT5670_PWR_DIG2, 0x0001); + snd_soc_write(codec, RT5670_PWR_VOL, 0x0000); + snd_soc_write(codec, RT5670_PWR_MIXER, 0x0001); + snd_soc_write(codec, RT5670_PWR_ANLG1, 0x2800); + snd_soc_write(codec, RT5670_PWR_ANLG2, 0x0004); + snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0); + snd_soc_update_bits(codec, RT5670_PWR_ANLG1, + RT5670_LDO_SEL_MASK, 0x1); + break; + + default: + break; + } + codec->dapm.bias_level = level; + + return 0; +} + +static int rt5670_probe(struct snd_soc_codec *codec) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + rt5670->codec = codec; + + return 0; +} + +static int rt5670_remove(struct snd_soc_codec *codec) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + regmap_write(rt5670->regmap, RT5670_RESET, 0); + return 0; +} + +#ifdef CONFIG_PM +static int rt5670_suspend(struct snd_soc_codec *codec) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5670->regmap, true); + regcache_mark_dirty(rt5670->regmap); + return 0; +} + +static int rt5670_resume(struct snd_soc_codec *codec) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5670->regmap, false); + regcache_sync(rt5670->regmap); + + return 0; +} +#else +#define rt5670_suspend NULL +#define rt5670_resume NULL +#endif + +#define RT5670_STEREO_RATES SNDRV_PCM_RATE_8000_96000 +#define RT5670_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt5670_aif_dai_ops = { + .hw_params = rt5670_hw_params, + .set_fmt = rt5670_set_dai_fmt, + .set_sysclk = rt5670_set_dai_sysclk, + .set_tdm_slot = rt5670_set_tdm_slot, + .set_pll = rt5670_set_dai_pll, +}; + +static struct snd_soc_dai_driver rt5670_dai[] = { + { + .name = "rt5670-aif1", + .id = RT5670_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5670_STEREO_RATES, + .formats = RT5670_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5670_STEREO_RATES, + .formats = RT5670_FORMATS, + }, + .ops = &rt5670_aif_dai_ops, + }, + { + .name = "rt5670-aif2", + .id = RT5670_AIF2, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5670_STEREO_RATES, + .formats = RT5670_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5670_STEREO_RATES, + .formats = RT5670_FORMATS, + }, + .ops = &rt5670_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5670 = { + .probe = rt5670_probe, + .remove = rt5670_remove, + .suspend = rt5670_suspend, + .resume = rt5670_resume, + .set_bias_level = rt5670_set_bias_level, + .idle_bias_off = true, + .controls = rt5670_snd_controls, + .num_controls = ARRAY_SIZE(rt5670_snd_controls), + .dapm_widgets = rt5670_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5670_dapm_widgets), + .dapm_routes = rt5670_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5670_dapm_routes), +}; + +static const struct regmap_config rt5670_regmap = { + .reg_bits = 8, + .val_bits = 16, + .max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) * + RT5670_PR_SPACING), + .volatile_reg = rt5670_volatile_register, + .readable_reg = rt5670_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5670_reg, + .num_reg_defaults = ARRAY_SIZE(rt5670_reg), + .ranges = rt5670_ranges, + .num_ranges = ARRAY_SIZE(rt5670_ranges), +}; + +static const struct i2c_device_id rt5670_i2c_id[] = { + { "rt5670", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); + +static int rt5670_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5670_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5670_priv *rt5670; + int ret; + unsigned int val; + + rt5670 = devm_kzalloc(&i2c->dev, + sizeof(struct rt5670_priv), + GFP_KERNEL); + if (NULL == rt5670) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5670); + + if (pdata) + rt5670->pdata = *pdata; + + rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); + if (IS_ERR(rt5670->regmap)) { + ret = PTR_ERR(rt5670->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5670->regmap, RT5670_VENDOR_ID2, &val); + if (val != RT5670_DEVICE_ID) { + dev_err(&i2c->dev, + "Device with ID register %x is not rt5670/72\n", val); + return -ENODEV; + } + + regmap_write(rt5670->regmap, RT5670_RESET, 0); + regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, + RT5670_PWR_HP_L | RT5670_PWR_HP_R | + RT5670_PWR_VREF2, RT5670_PWR_VREF2); + msleep(100); + + regmap_write(rt5670->regmap, RT5670_RESET, 0); + + ret = regmap_register_patch(rt5670->regmap, init_list, + ARRAY_SIZE(init_list)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + if (rt5670->pdata.in2_diff) + regmap_update_bits(rt5670->regmap, RT5670_IN2, + RT5670_IN_DF2, RT5670_IN_DF2); + + if (i2c->irq) { + regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, + RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); + regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2, + RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); + + } + + if (rt5670->pdata.jd_mode) { + regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, + RT5670_PWR_MB, RT5670_PWR_MB); + regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2, + RT5670_PWR_JD1, RT5670_PWR_JD1); + regmap_update_bits(rt5670->regmap, RT5670_IRQ_CTRL1, + RT5670_JD1_1_EN_MASK, RT5670_JD1_1_EN); + regmap_update_bits(rt5670->regmap, RT5670_JD_CTRL3, + RT5670_JD_TRI_CBJ_SEL_MASK | + RT5670_JD_TRI_HPO_SEL_MASK, + RT5670_JD_CBJ_JD1_1 | RT5670_JD_HPO_JD1_1); + switch (rt5670->pdata.jd_mode) { + case 1: + regmap_update_bits(rt5670->regmap, RT5670_A_JD_CTRL1, + RT5670_JD1_MODE_MASK, + RT5670_JD1_MODE_0); + break; + case 2: + regmap_update_bits(rt5670->regmap, RT5670_A_JD_CTRL1, + RT5670_JD1_MODE_MASK, + RT5670_JD1_MODE_1); + break; + case 3: + regmap_update_bits(rt5670->regmap, RT5670_A_JD_CTRL1, + RT5670_JD1_MODE_MASK, + RT5670_JD1_MODE_2); + break; + default: + break; + } + } + + if (rt5670->pdata.dmic_en) { + regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, + RT5670_GP2_PIN_MASK, + RT5670_GP2_PIN_DMIC1_SCL); + + switch (rt5670->pdata.dmic1_data_pin) { + case RT5670_DMIC_DATA_IN2P: + regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1, + RT5670_DMIC_1_DP_MASK, + RT5670_DMIC_1_DP_IN2P); + break; + + case RT5670_DMIC_DATA_GPIO6: + regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1, + RT5670_DMIC_1_DP_MASK, + RT5670_DMIC_1_DP_GPIO6); + regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, + RT5670_GP6_PIN_MASK, + RT5670_GP6_PIN_DMIC1_SDA); + break; + + case RT5670_DMIC_DATA_GPIO7: + regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1, + RT5670_DMIC_1_DP_MASK, + RT5670_DMIC_1_DP_GPIO7); + regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, + RT5670_GP7_PIN_MASK, + RT5670_GP7_PIN_DMIC1_SDA); + break; + + default: + break; + } + + switch (rt5670->pdata.dmic2_data_pin) { + case RT5670_DMIC_DATA_IN3N: + regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1, + RT5670_DMIC_2_DP_MASK, + RT5670_DMIC_2_DP_IN3N); + break; + + case RT5670_DMIC_DATA_GPIO8: + regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1, + RT5670_DMIC_2_DP_MASK, + RT5670_DMIC_2_DP_GPIO8); + regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, + RT5670_GP8_PIN_MASK, + RT5670_GP8_PIN_DMIC2_SDA); + break; + + default: + break; + } + + switch (rt5670->pdata.dmic3_data_pin) { + case RT5670_DMIC_DATA_GPIO5: + regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL2, + RT5670_DMIC_3_DP_MASK, + RT5670_DMIC_3_DP_GPIO5); + regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, + RT5670_GP5_PIN_MASK, + RT5670_GP5_PIN_DMIC3_SDA); + break; + + case RT5670_DMIC_DATA_GPIO9: + case RT5670_DMIC_DATA_GPIO10: + dev_err(&i2c->dev, + "Always use GPIO5 as DMIC3 data pin\n"); + break; + + default: + break; + } + + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670, + rt5670_dai, ARRAY_SIZE(rt5670_dai)); + if (ret < 0) + goto err; + + return 0; +err: + return ret; +} + +static int rt5670_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static struct i2c_driver rt5670_i2c_driver = { + .driver = { + .name = "rt5670", + .owner = THIS_MODULE, + }, + .probe = rt5670_i2c_probe, + .remove = rt5670_i2c_remove, + .id_table = rt5670_i2c_id, +}; + +module_i2c_driver(rt5670_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5670 driver"); +MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h new file mode 100644 index 000000000000..a0b5c855b492 --- /dev/null +++ b/sound/soc/codecs/rt5670.h @@ -0,0 +1,2000 @@ +/* + * rt5670.h -- RT5670 ALSA SoC audio driver + * + * Copyright 2014 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 __RT5670_H__ +#define __RT5670_H__ + +#include <sound/rt5670.h> + +/* Info */ +#define RT5670_RESET 0x00 +#define RT5670_VENDOR_ID 0xfd +#define RT5670_VENDOR_ID1 0xfe +#define RT5670_VENDOR_ID2 0xff +/* I/O - Output */ +#define RT5670_HP_VOL 0x02 +#define RT5670_LOUT1 0x03 +/* I/O - Input */ +#define RT5670_CJ_CTRL1 0x0a +#define RT5670_CJ_CTRL2 0x0b +#define RT5670_CJ_CTRL3 0x0c +#define RT5670_IN2 0x0e +#define RT5670_INL1_INR1_VOL 0x0f +/* I/O - ADC/DAC/DMIC */ +#define RT5670_DAC1_DIG_VOL 0x19 +#define RT5670_DAC2_DIG_VOL 0x1a +#define RT5670_DAC_CTRL 0x1b +#define RT5670_STO1_ADC_DIG_VOL 0x1c +#define RT5670_MONO_ADC_DIG_VOL 0x1d +#define RT5670_ADC_BST_VOL1 0x1e +#define RT5670_STO2_ADC_DIG_VOL 0x1f +/* Mixer - D-D */ +#define RT5670_ADC_BST_VOL2 0x20 +#define RT5670_STO2_ADC_MIXER 0x26 +#define RT5670_STO1_ADC_MIXER 0x27 +#define RT5670_MONO_ADC_MIXER 0x28 +#define RT5670_AD_DA_MIXER 0x29 +#define RT5670_STO_DAC_MIXER 0x2a +#define RT5670_DD_MIXER 0x2b +#define RT5670_DIG_MIXER 0x2c +#define RT5670_DSP_PATH1 0x2d +#define RT5670_DSP_PATH2 0x2e +#define RT5670_DIG_INF1_DATA 0x2f +#define RT5670_DIG_INF2_DATA 0x30 +/* Mixer - PDM */ +#define RT5670_PDM_OUT_CTRL 0x31 +#define RT5670_PDM_DATA_CTRL1 0x32 +#define RT5670_PDM1_DATA_CTRL2 0x33 +#define RT5670_PDM1_DATA_CTRL3 0x34 +#define RT5670_PDM1_DATA_CTRL4 0x35 +#define RT5670_PDM2_DATA_CTRL2 0x36 +#define RT5670_PDM2_DATA_CTRL3 0x37 +#define RT5670_PDM2_DATA_CTRL4 0x38 +/* Mixer - ADC */ +#define RT5670_REC_L1_MIXER 0x3b +#define RT5670_REC_L2_MIXER 0x3c +#define RT5670_REC_R1_MIXER 0x3d +#define RT5670_REC_R2_MIXER 0x3e +/* Mixer - DAC */ +#define RT5670_HPO_MIXER 0x45 +#define RT5670_MONO_MIXER 0x4c +#define RT5670_OUT_L1_MIXER 0x4f +#define RT5670_OUT_R1_MIXER 0x52 +#define RT5670_LOUT_MIXER 0x53 +/* Power */ +#define RT5670_PWR_DIG1 0x61 +#define RT5670_PWR_DIG2 0x62 +#define RT5670_PWR_ANLG1 0x63 +#define RT5670_PWR_ANLG2 0x64 +#define RT5670_PWR_MIXER 0x65 +#define RT5670_PWR_VOL 0x66 +/* Private Register Control */ +#define RT5670_PRIV_INDEX 0x6a +#define RT5670_PRIV_DATA 0x6c +/* Format - ADC/DAC */ +#define RT5670_I2S4_SDP 0x6f +#define RT5670_I2S1_SDP 0x70 +#define RT5670_I2S2_SDP 0x71 +#define RT5670_I2S3_SDP 0x72 +#define RT5670_ADDA_CLK1 0x73 +#define RT5670_ADDA_CLK2 0x74 +#define RT5670_DMIC_CTRL1 0x75 +#define RT5670_DMIC_CTRL2 0x76 +/* Format - TDM Control */ +#define RT5670_TDM_CTRL_1 0x77 +#define RT5670_TDM_CTRL_2 0x78 +#define RT5670_TDM_CTRL_3 0x79 + +/* Function - Analog */ +#define RT5670_DSP_CLK 0x7f +#define RT5670_GLB_CLK 0x80 +#define RT5670_PLL_CTRL1 0x81 +#define RT5670_PLL_CTRL2 0x82 +#define RT5670_ASRC_1 0x83 +#define RT5670_ASRC_2 0x84 +#define RT5670_ASRC_3 0x85 +#define RT5670_ASRC_4 0x86 +#define RT5670_ASRC_5 0x87 +#define RT5670_ASRC_7 0x89 +#define RT5670_ASRC_8 0x8a +#define RT5670_ASRC_9 0x8b +#define RT5670_ASRC_10 0x8c +#define RT5670_ASRC_11 0x8d +#define RT5670_DEPOP_M1 0x8e +#define RT5670_DEPOP_M2 0x8f +#define RT5670_DEPOP_M3 0x90 +#define RT5670_CHARGE_PUMP 0x91 +#define RT5670_MICBIAS 0x93 +#define RT5670_A_JD_CTRL1 0x94 +#define RT5670_A_JD_CTRL2 0x95 +#define RT5670_ASRC_12 0x97 +#define RT5670_ASRC_13 0x98 +#define RT5670_ASRC_14 0x99 +#define RT5670_VAD_CTRL1 0x9a +#define RT5670_VAD_CTRL2 0x9b +#define RT5670_VAD_CTRL3 0x9c +#define RT5670_VAD_CTRL4 0x9d +#define RT5670_VAD_CTRL5 0x9e +/* Function - Digital */ +#define RT5670_ADC_EQ_CTRL1 0xae +#define RT5670_ADC_EQ_CTRL2 0xaf +#define RT5670_EQ_CTRL1 0xb0 +#define RT5670_EQ_CTRL2 0xb1 +#define RT5670_ALC_DRC_CTRL1 0xb2 +#define RT5670_ALC_DRC_CTRL2 0xb3 +#define RT5670_ALC_CTRL_1 0xb4 +#define RT5670_ALC_CTRL_2 0xb5 +#define RT5670_ALC_CTRL_3 0xb6 +#define RT5670_ALC_CTRL_4 0xb7 +#define RT5670_JD_CTRL 0xbb +#define RT5670_IRQ_CTRL1 0xbd +#define RT5670_IRQ_CTRL2 0xbe +#define RT5670_INT_IRQ_ST 0xbf +#define RT5670_GPIO_CTRL1 0xc0 +#define RT5670_GPIO_CTRL2 0xc1 +#define RT5670_GPIO_CTRL3 0xc2 +#define RT5670_SCRABBLE_FUN 0xcd +#define RT5670_SCRABBLE_CTRL 0xce +#define RT5670_BASE_BACK 0xcf +#define RT5670_MP3_PLUS1 0xd0 +#define RT5670_MP3_PLUS2 0xd1 +#define RT5670_ADJ_HPF1 0xd3 +#define RT5670_ADJ_HPF2 0xd4 +#define RT5670_HP_CALIB_AMP_DET 0xd6 +#define RT5670_SV_ZCD1 0xd9 +#define RT5670_SV_ZCD2 0xda +#define RT5670_IL_CMD 0xdb +#define RT5670_IL_CMD2 0xdc +#define RT5670_IL_CMD3 0xdd +#define RT5670_DRC_HL_CTRL1 0xe6 +#define RT5670_DRC_HL_CTRL2 0xe7 +#define RT5670_ADC_MONO_HP_CTRL1 0xec +#define RT5670_ADC_MONO_HP_CTRL2 0xed +#define RT5670_ADC_STO2_HP_CTRL1 0xee +#define RT5670_ADC_STO2_HP_CTRL2 0xef +#define RT5670_JD_CTRL3 0xf8 +#define RT5670_JD_CTRL4 0xf9 +/* General Control */ +#define RT5670_DIG_MISC 0xfa +#define RT5670_GEN_CTRL2 0xfb +#define RT5670_GEN_CTRL3 0xfc + + +/* Index of Codec Private Register definition */ +#define RT5670_DIG_VOL 0x00 +#define RT5670_PR_ALC_CTRL_1 0x01 +#define RT5670_PR_ALC_CTRL_2 0x02 +#define RT5670_PR_ALC_CTRL_3 0x03 +#define RT5670_PR_ALC_CTRL_4 0x04 +#define RT5670_PR_ALC_CTRL_5 0x05 +#define RT5670_PR_ALC_CTRL_6 0x06 +#define RT5670_BIAS_CUR1 0x12 +#define RT5670_BIAS_CUR3 0x14 +#define RT5670_CLSD_INT_REG1 0x1c +#define RT5670_MAMP_INT_REG2 0x37 +#define RT5670_CHOP_DAC_ADC 0x3d +#define RT5670_MIXER_INT_REG 0x3f +#define RT5670_3D_SPK 0x63 +#define RT5670_WND_1 0x6c +#define RT5670_WND_2 0x6d +#define RT5670_WND_3 0x6e +#define RT5670_WND_4 0x6f +#define RT5670_WND_5 0x70 +#define RT5670_WND_8 0x73 +#define RT5670_DIP_SPK_INF 0x75 +#define RT5670_HP_DCC_INT1 0x77 +#define RT5670_EQ_BW_LOP 0xa0 +#define RT5670_EQ_GN_LOP 0xa1 +#define RT5670_EQ_FC_BP1 0xa2 +#define RT5670_EQ_BW_BP1 0xa3 +#define RT5670_EQ_GN_BP1 0xa4 +#define RT5670_EQ_FC_BP2 0xa5 +#define RT5670_EQ_BW_BP2 0xa6 +#define RT5670_EQ_GN_BP2 0xa7 +#define RT5670_EQ_FC_BP3 0xa8 +#define RT5670_EQ_BW_BP3 0xa9 +#define RT5670_EQ_GN_BP3 0xaa +#define RT5670_EQ_FC_BP4 0xab +#define RT5670_EQ_BW_BP4 0xac +#define RT5670_EQ_GN_BP4 0xad +#define RT5670_EQ_FC_HIP1 0xae +#define RT5670_EQ_GN_HIP1 0xaf +#define RT5670_EQ_FC_HIP2 0xb0 +#define RT5670_EQ_BW_HIP2 0xb1 +#define RT5670_EQ_GN_HIP2 0xb2 +#define RT5670_EQ_PRE_VOL 0xb3 +#define RT5670_EQ_PST_VOL 0xb4 + + +/* global definition */ +#define RT5670_L_MUTE (0x1 << 15) +#define RT5670_L_MUTE_SFT 15 +#define RT5670_VOL_L_MUTE (0x1 << 14) +#define RT5670_VOL_L_SFT 14 +#define RT5670_R_MUTE (0x1 << 7) +#define RT5670_R_MUTE_SFT 7 +#define RT5670_VOL_R_MUTE (0x1 << 6) +#define RT5670_VOL_R_SFT 6 +#define RT5670_L_VOL_MASK (0x3f << 8) +#define RT5670_L_VOL_SFT 8 +#define RT5670_R_VOL_MASK (0x3f) +#define RT5670_R_VOL_SFT 0 + +/* Combo Jack Control 1 (0x0a) */ +#define RT5670_CBJ_BST1_MASK (0xf << 12) +#define RT5670_CBJ_BST1_SFT (12) +#define RT5670_CBJ_JD_HP_EN (0x1 << 9) +#define RT5670_CBJ_JD_MIC_EN (0x1 << 8) +#define RT5670_CBJ_BST1_EN (0x1 << 2) + +/* Combo Jack Control 1 (0x0b) */ +#define RT5670_CBJ_MN_JD (0x1 << 12) +#define RT5670_CAPLESS_EN (0x1 << 11) +#define RT5670_CBJ_DET_MODE (0x1 << 7) + +/* IN2 Control (0x0e) */ +#define RT5670_BST_MASK1 (0xf<<12) +#define RT5670_BST_SFT1 12 +#define RT5670_BST_MASK2 (0xf<<8) +#define RT5670_BST_SFT2 8 +#define RT5670_IN_DF1 (0x1 << 7) +#define RT5670_IN_SFT1 7 +#define RT5670_IN_DF2 (0x1 << 6) +#define RT5670_IN_SFT2 6 + +/* INL and INR Volume Control (0x0f) */ +#define RT5670_INL_SEL_MASK (0x1 << 15) +#define RT5670_INL_SEL_SFT 15 +#define RT5670_INL_SEL_IN4P (0x0 << 15) +#define RT5670_INL_SEL_MONOP (0x1 << 15) +#define RT5670_INL_VOL_MASK (0x1f << 8) +#define RT5670_INL_VOL_SFT 8 +#define RT5670_INR_SEL_MASK (0x1 << 7) +#define RT5670_INR_SEL_SFT 7 +#define RT5670_INR_SEL_IN4N (0x0 << 7) +#define RT5670_INR_SEL_MONON (0x1 << 7) +#define RT5670_INR_VOL_MASK (0x1f) +#define RT5670_INR_VOL_SFT 0 + +/* Sidetone Control (0x18) */ +#define RT5670_ST_SEL_MASK (0x7 << 9) +#define RT5670_ST_SEL_SFT 9 +#define RT5670_M_ST_DACR2 (0x1 << 8) +#define RT5670_M_ST_DACR2_SFT 8 +#define RT5670_M_ST_DACL2 (0x1 << 7) +#define RT5670_M_ST_DACL2_SFT 7 +#define RT5670_ST_EN (0x1 << 6) +#define RT5670_ST_EN_SFT 6 + +/* DAC1 Digital Volume (0x19) */ +#define RT5670_DAC_L1_VOL_MASK (0xff << 8) +#define RT5670_DAC_L1_VOL_SFT 8 +#define RT5670_DAC_R1_VOL_MASK (0xff) +#define RT5670_DAC_R1_VOL_SFT 0 + +/* DAC2 Digital Volume (0x1a) */ +#define RT5670_DAC_L2_VOL_MASK (0xff << 8) +#define RT5670_DAC_L2_VOL_SFT 8 +#define RT5670_DAC_R2_VOL_MASK (0xff) +#define RT5670_DAC_R2_VOL_SFT 0 + +/* DAC2 Control (0x1b) */ +#define RT5670_M_DAC_L2_VOL (0x1 << 13) +#define RT5670_M_DAC_L2_VOL_SFT 13 +#define RT5670_M_DAC_R2_VOL (0x1 << 12) +#define RT5670_M_DAC_R2_VOL_SFT 12 +#define RT5670_DAC2_L_SEL_MASK (0x7 << 4) +#define RT5670_DAC2_L_SEL_SFT 4 +#define RT5670_DAC2_R_SEL_MASK (0x7 << 0) +#define RT5670_DAC2_R_SEL_SFT 0 + +/* ADC Digital Volume Control (0x1c) */ +#define RT5670_ADC_L_VOL_MASK (0x7f << 8) +#define RT5670_ADC_L_VOL_SFT 8 +#define RT5670_ADC_R_VOL_MASK (0x7f) +#define RT5670_ADC_R_VOL_SFT 0 + +/* Mono ADC Digital Volume Control (0x1d) */ +#define RT5670_MONO_ADC_L_VOL_MASK (0x7f << 8) +#define RT5670_MONO_ADC_L_VOL_SFT 8 +#define RT5670_MONO_ADC_R_VOL_MASK (0x7f) +#define RT5670_MONO_ADC_R_VOL_SFT 0 + +/* ADC Boost Volume Control (0x1e) */ +#define RT5670_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5670_STO1_ADC_L_BST_SFT 14 +#define RT5670_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5670_STO1_ADC_R_BST_SFT 12 +#define RT5670_STO1_ADC_COMP_MASK (0x3 << 10) +#define RT5670_STO1_ADC_COMP_SFT 10 +#define RT5670_STO2_ADC_L_BST_MASK (0x3 << 8) +#define RT5670_STO2_ADC_L_BST_SFT 8 +#define RT5670_STO2_ADC_R_BST_MASK (0x3 << 6) +#define RT5670_STO2_ADC_R_BST_SFT 6 +#define RT5670_STO2_ADC_COMP_MASK (0x3 << 4) +#define RT5670_STO2_ADC_COMP_SFT 4 + +/* Stereo2 ADC Mixer Control (0x26) */ +#define RT5670_STO2_ADC_SRC_MASK (0x1 << 15) +#define RT5670_STO2_ADC_SRC_SFT 15 + +/* Stereo ADC Mixer Control (0x26 0x27) */ +#define RT5670_M_ADC_L1 (0x1 << 14) +#define RT5670_M_ADC_L1_SFT 14 +#define RT5670_M_ADC_L2 (0x1 << 13) +#define RT5670_M_ADC_L2_SFT 13 +#define RT5670_ADC_1_SRC_MASK (0x1 << 12) +#define RT5670_ADC_1_SRC_SFT 12 +#define RT5670_ADC_1_SRC_ADC (0x1 << 12) +#define RT5670_ADC_1_SRC_DACMIX (0x0 << 12) +#define RT5670_ADC_2_SRC_MASK (0x1 << 11) +#define RT5670_ADC_2_SRC_SFT 11 +#define RT5670_ADC_SRC_MASK (0x1 << 10) +#define RT5670_ADC_SRC_SFT 10 +#define RT5670_DMIC_SRC_MASK (0x3 << 8) +#define RT5670_DMIC_SRC_SFT 8 +#define RT5670_M_ADC_R1 (0x1 << 6) +#define RT5670_M_ADC_R1_SFT 6 +#define RT5670_M_ADC_R2 (0x1 << 5) +#define RT5670_M_ADC_R2_SFT 5 +#define RT5670_DMIC3_SRC_MASK (0x1 << 1) +#define RT5670_DMIC3_SRC_SFT 0 + +/* Mono ADC Mixer Control (0x28) */ +#define RT5670_M_MONO_ADC_L1 (0x1 << 14) +#define RT5670_M_MONO_ADC_L1_SFT 14 +#define RT5670_M_MONO_ADC_L2 (0x1 << 13) +#define RT5670_M_MONO_ADC_L2_SFT 13 +#define RT5670_MONO_ADC_L1_SRC_MASK (0x1 << 12) +#define RT5670_MONO_ADC_L1_SRC_SFT 12 +#define RT5670_MONO_ADC_L1_SRC_DACMIXL (0x0 << 12) +#define RT5670_MONO_ADC_L1_SRC_ADCL (0x1 << 12) +#define RT5670_MONO_ADC_L2_SRC_MASK (0x1 << 11) +#define RT5670_MONO_ADC_L2_SRC_SFT 11 +#define RT5670_MONO_ADC_L_SRC_MASK (0x1 << 10) +#define RT5670_MONO_ADC_L_SRC_SFT 10 +#define RT5670_MONO_DMIC_L_SRC_MASK (0x3 << 8) +#define RT5670_MONO_DMIC_L_SRC_SFT 8 +#define RT5670_M_MONO_ADC_R1 (0x1 << 6) +#define RT5670_M_MONO_ADC_R1_SFT 6 +#define RT5670_M_MONO_ADC_R2 (0x1 << 5) +#define RT5670_M_MONO_ADC_R2_SFT 5 +#define RT5670_MONO_ADC_R1_SRC_MASK (0x1 << 4) +#define RT5670_MONO_ADC_R1_SRC_SFT 4 +#define RT5670_MONO_ADC_R1_SRC_ADCR (0x1 << 4) +#define RT5670_MONO_ADC_R1_SRC_DACMIXR (0x0 << 4) +#define RT5670_MONO_ADC_R2_SRC_MASK (0x1 << 3) +#define RT5670_MONO_ADC_R2_SRC_SFT 3 +#define RT5670_MONO_DMIC_R_SRC_MASK (0x3) +#define RT5670_MONO_DMIC_R_SRC_SFT 0 + +/* ADC Mixer to DAC Mixer Control (0x29) */ +#define RT5670_M_ADCMIX_L (0x1 << 15) +#define RT5670_M_ADCMIX_L_SFT 15 +#define RT5670_M_DAC1_L (0x1 << 14) +#define RT5670_M_DAC1_L_SFT 14 +#define RT5670_DAC1_R_SEL_MASK (0x3 << 10) +#define RT5670_DAC1_R_SEL_SFT 10 +#define RT5670_DAC1_R_SEL_IF1 (0x0 << 10) +#define RT5670_DAC1_R_SEL_IF2 (0x1 << 10) +#define RT5670_DAC1_R_SEL_IF3 (0x2 << 10) +#define RT5670_DAC1_R_SEL_IF4 (0x3 << 10) +#define RT5670_DAC1_L_SEL_MASK (0x3 << 8) +#define RT5670_DAC1_L_SEL_SFT 8 +#define RT5670_DAC1_L_SEL_IF1 (0x0 << 8) +#define RT5670_DAC1_L_SEL_IF2 (0x1 << 8) +#define RT5670_DAC1_L_SEL_IF3 (0x2 << 8) +#define RT5670_DAC1_L_SEL_IF4 (0x3 << 8) +#define RT5670_M_ADCMIX_R (0x1 << 7) +#define RT5670_M_ADCMIX_R_SFT 7 +#define RT5670_M_DAC1_R (0x1 << 6) +#define RT5670_M_DAC1_R_SFT 6 + +/* Stereo DAC Mixer Control (0x2a) */ +#define RT5670_M_DAC_L1 (0x1 << 14) +#define RT5670_M_DAC_L1_SFT 14 +#define RT5670_DAC_L1_STO_L_VOL_MASK (0x1 << 13) +#define RT5670_DAC_L1_STO_L_VOL_SFT 13 +#define RT5670_M_DAC_L2 (0x1 << 12) +#define RT5670_M_DAC_L2_SFT 12 +#define RT5670_DAC_L2_STO_L_VOL_MASK (0x1 << 11) +#define RT5670_DAC_L2_STO_L_VOL_SFT 11 +#define RT5670_M_DAC_R1_STO_L (0x1 << 9) +#define RT5670_M_DAC_R1_STO_L_SFT 9 +#define RT5670_DAC_R1_STO_L_VOL_MASK (0x1 << 8) +#define RT5670_DAC_R1_STO_L_VOL_SFT 8 +#define RT5670_M_DAC_R1 (0x1 << 6) +#define RT5670_M_DAC_R1_SFT 6 +#define RT5670_DAC_R1_STO_R_VOL_MASK (0x1 << 5) +#define RT5670_DAC_R1_STO_R_VOL_SFT 5 +#define RT5670_M_DAC_R2 (0x1 << 4) +#define RT5670_M_DAC_R2_SFT 4 +#define RT5670_DAC_R2_STO_R_VOL_MASK (0x1 << 3) +#define RT5670_DAC_R2_STO_R_VOL_SFT 3 +#define RT5670_M_DAC_L1_STO_R (0x1 << 1) +#define RT5670_M_DAC_L1_STO_R_SFT 1 +#define RT5670_DAC_L1_STO_R_VOL_MASK (0x1) +#define RT5670_DAC_L1_STO_R_VOL_SFT 0 + +/* Mono DAC Mixer Control (0x2b) */ +#define RT5670_M_DAC_L1_MONO_L (0x1 << 14) +#define RT5670_M_DAC_L1_MONO_L_SFT 14 +#define RT5670_DAC_L1_MONO_L_VOL_MASK (0x1 << 13) +#define RT5670_DAC_L1_MONO_L_VOL_SFT 13 +#define RT5670_M_DAC_L2_MONO_L (0x1 << 12) +#define RT5670_M_DAC_L2_MONO_L_SFT 12 +#define RT5670_DAC_L2_MONO_L_VOL_MASK (0x1 << 11) +#define RT5670_DAC_L2_MONO_L_VOL_SFT 11 +#define RT5670_M_DAC_R2_MONO_L (0x1 << 10) +#define RT5670_M_DAC_R2_MONO_L_SFT 10 +#define RT5670_DAC_R2_MONO_L_VOL_MASK (0x1 << 9) +#define RT5670_DAC_R2_MONO_L_VOL_SFT 9 +#define RT5670_M_DAC_R1_MONO_R (0x1 << 6) +#define RT5670_M_DAC_R1_MONO_R_SFT 6 +#define RT5670_DAC_R1_MONO_R_VOL_MASK (0x1 << 5) +#define RT5670_DAC_R1_MONO_R_VOL_SFT 5 +#define RT5670_M_DAC_R2_MONO_R (0x1 << 4) +#define RT5670_M_DAC_R2_MONO_R_SFT 4 +#define RT5670_DAC_R2_MONO_R_VOL_MASK (0x1 << 3) +#define RT5670_DAC_R2_MONO_R_VOL_SFT 3 +#define RT5670_M_DAC_L2_MONO_R (0x1 << 2) +#define RT5670_M_DAC_L2_MONO_R_SFT 2 +#define RT5670_DAC_L2_MONO_R_VOL_MASK (0x1 << 1) +#define RT5670_DAC_L2_MONO_R_VOL_SFT 1 + +/* Digital Mixer Control (0x2c) */ +#define RT5670_M_STO_L_DAC_L (0x1 << 15) +#define RT5670_M_STO_L_DAC_L_SFT 15 +#define RT5670_STO_L_DAC_L_VOL_MASK (0x1 << 14) +#define RT5670_STO_L_DAC_L_VOL_SFT 14 +#define RT5670_M_DAC_L2_DAC_L (0x1 << 13) +#define RT5670_M_DAC_L2_DAC_L_SFT 13 +#define RT5670_DAC_L2_DAC_L_VOL_MASK (0x1 << 12) +#define RT5670_DAC_L2_DAC_L_VOL_SFT 12 +#define RT5670_M_STO_R_DAC_R (0x1 << 11) +#define RT5670_M_STO_R_DAC_R_SFT 11 +#define RT5670_STO_R_DAC_R_VOL_MASK (0x1 << 10) +#define RT5670_STO_R_DAC_R_VOL_SFT 10 +#define RT5670_M_DAC_R2_DAC_R (0x1 << 9) +#define RT5670_M_DAC_R2_DAC_R_SFT 9 +#define RT5670_DAC_R2_DAC_R_VOL_MASK (0x1 << 8) +#define RT5670_DAC_R2_DAC_R_VOL_SFT 8 +#define RT5670_M_DAC_R2_DAC_L (0x1 << 7) +#define RT5670_M_DAC_R2_DAC_L_SFT 7 +#define RT5670_DAC_R2_DAC_L_VOL_MASK (0x1 << 6) +#define RT5670_DAC_R2_DAC_L_VOL_SFT 6 +#define RT5670_M_DAC_L2_DAC_R (0x1 << 5) +#define RT5670_M_DAC_L2_DAC_R_SFT 5 +#define RT5670_DAC_L2_DAC_R_VOL_MASK (0x1 << 4) +#define RT5670_DAC_L2_DAC_R_VOL_SFT 4 + +/* DSP Path Control 1 (0x2d) */ +#define RT5670_RXDP_SEL_MASK (0x7 << 13) +#define RT5670_RXDP_SEL_SFT 13 +#define RT5670_RXDP_SRC_MASK (0x3 << 11) +#define RT5670_RXDP_SRC_SFT 11 +#define RT5670_RXDP_SRC_NOR (0x0 << 11) +#define RT5670_RXDP_SRC_DIV2 (0x1 << 11) +#define RT5670_RXDP_SRC_DIV3 (0x2 << 11) +#define RT5670_TXDP_SRC_MASK (0x3 << 4) +#define RT5670_TXDP_SRC_SFT 4 +#define RT5670_TXDP_SRC_NOR (0x0 << 4) +#define RT5670_TXDP_SRC_DIV2 (0x1 << 4) +#define RT5670_TXDP_SRC_DIV3 (0x2 << 4) +#define RT5670_TXDP_SLOT_SEL_MASK (0x3 << 2) +#define RT5670_TXDP_SLOT_SEL_SFT 2 +#define RT5670_DSP_UL_SEL (0x1 << 1) +#define RT5670_DSP_UL_SFT 1 +#define RT5670_DSP_DL_SEL 0x1 +#define RT5670_DSP_DL_SFT 0 + +/* DSP Path Control 2 (0x2e) */ +#define RT5670_TXDP_L_VOL_MASK (0x7f << 8) +#define RT5670_TXDP_L_VOL_SFT 8 +#define RT5670_TXDP_R_VOL_MASK (0x7f) +#define RT5670_TXDP_R_VOL_SFT 0 + +/* Digital Interface Data Control (0x2f) */ +#define RT5670_IF1_ADC2_IN_SEL (0x1 << 15) +#define RT5670_IF1_ADC2_IN_SFT 15 +#define RT5670_IF2_ADC_IN_MASK (0x7 << 12) +#define RT5670_IF2_ADC_IN_SFT 12 +#define RT5670_IF2_DAC_SEL_MASK (0x3 << 10) +#define RT5670_IF2_DAC_SEL_SFT 10 +#define RT5670_IF2_ADC_SEL_MASK (0x3 << 8) +#define RT5670_IF2_ADC_SEL_SFT 8 + +/* Digital Interface Data Control (0x30) */ +#define RT5670_IF4_ADC_IN_MASK (0x3 << 4) +#define RT5670_IF4_ADC_IN_SFT 4 + +/* PDM Output Control (0x31) */ +#define RT5670_PDM1_L_MASK (0x1 << 15) +#define RT5670_PDM1_L_SFT 15 +#define RT5670_M_PDM1_L (0x1 << 14) +#define RT5670_M_PDM1_L_SFT 14 +#define RT5670_PDM1_R_MASK (0x1 << 13) +#define RT5670_PDM1_R_SFT 13 +#define RT5670_M_PDM1_R (0x1 << 12) +#define RT5670_M_PDM1_R_SFT 12 +#define RT5670_PDM2_L_MASK (0x1 << 11) +#define RT5670_PDM2_L_SFT 11 +#define RT5670_M_PDM2_L (0x1 << 10) +#define RT5670_M_PDM2_L_SFT 10 +#define RT5670_PDM2_R_MASK (0x1 << 9) +#define RT5670_PDM2_R_SFT 9 +#define RT5670_M_PDM2_R (0x1 << 8) +#define RT5670_M_PDM2_R_SFT 8 +#define RT5670_PDM2_BUSY (0x1 << 7) +#define RT5670_PDM1_BUSY (0x1 << 6) +#define RT5670_PDM_PATTERN (0x1 << 5) +#define RT5670_PDM_GAIN (0x1 << 4) +#define RT5670_PDM_DIV_MASK (0x3) + +/* REC Left Mixer Control 1 (0x3b) */ +#define RT5670_G_HP_L_RM_L_MASK (0x7 << 13) +#define RT5670_G_HP_L_RM_L_SFT 13 +#define RT5670_G_IN_L_RM_L_MASK (0x7 << 10) +#define RT5670_G_IN_L_RM_L_SFT 10 +#define RT5670_G_BST4_RM_L_MASK (0x7 << 7) +#define RT5670_G_BST4_RM_L_SFT 7 +#define RT5670_G_BST3_RM_L_MASK (0x7 << 4) +#define RT5670_G_BST3_RM_L_SFT 4 +#define RT5670_G_BST2_RM_L_MASK (0x7 << 1) +#define RT5670_G_BST2_RM_L_SFT 1 + +/* REC Left Mixer Control 2 (0x3c) */ +#define RT5670_G_BST1_RM_L_MASK (0x7 << 13) +#define RT5670_G_BST1_RM_L_SFT 13 +#define RT5670_M_IN_L_RM_L (0x1 << 5) +#define RT5670_M_IN_L_RM_L_SFT 5 +#define RT5670_M_BST2_RM_L (0x1 << 3) +#define RT5670_M_BST2_RM_L_SFT 3 +#define RT5670_M_BST1_RM_L (0x1 << 1) +#define RT5670_M_BST1_RM_L_SFT 1 + +/* REC Right Mixer Control 1 (0x3d) */ +#define RT5670_G_HP_R_RM_R_MASK (0x7 << 13) +#define RT5670_G_HP_R_RM_R_SFT 13 +#define RT5670_G_IN_R_RM_R_MASK (0x7 << 10) +#define RT5670_G_IN_R_RM_R_SFT 10 +#define RT5670_G_BST4_RM_R_MASK (0x7 << 7) +#define RT5670_G_BST4_RM_R_SFT 7 +#define RT5670_G_BST3_RM_R_MASK (0x7 << 4) +#define RT5670_G_BST3_RM_R_SFT 4 +#define RT5670_G_BST2_RM_R_MASK (0x7 << 1) +#define RT5670_G_BST2_RM_R_SFT 1 + +/* REC Right Mixer Control 2 (0x3e) */ +#define RT5670_G_BST1_RM_R_MASK (0x7 << 13) +#define RT5670_G_BST1_RM_R_SFT 13 +#define RT5670_M_IN_R_RM_R (0x1 << 5) +#define RT5670_M_IN_R_RM_R_SFT 5 +#define RT5670_M_BST2_RM_R (0x1 << 3) +#define RT5670_M_BST2_RM_R_SFT 3 +#define RT5670_M_BST1_RM_R (0x1 << 1) +#define RT5670_M_BST1_RM_R_SFT 1 + +/* HPMIX Control (0x45) */ +#define RT5670_M_DAC2_HM (0x1 << 15) +#define RT5670_M_DAC2_HM_SFT 15 +#define RT5670_M_HPVOL_HM (0x1 << 14) +#define RT5670_M_HPVOL_HM_SFT 14 +#define RT5670_M_DAC1_HM (0x1 << 13) +#define RT5670_M_DAC1_HM_SFT 13 +#define RT5670_G_HPOMIX_MASK (0x1 << 12) +#define RT5670_G_HPOMIX_SFT 12 +#define RT5670_M_INR1_HMR (0x1 << 3) +#define RT5670_M_INR1_HMR_SFT 3 +#define RT5670_M_DACR1_HMR (0x1 << 2) +#define RT5670_M_DACR1_HMR_SFT 2 +#define RT5670_M_INL1_HML (0x1 << 1) +#define RT5670_M_INL1_HML_SFT 1 +#define RT5670_M_DACL1_HML (0x1) +#define RT5670_M_DACL1_HML_SFT 0 + +/* Mono Output Mixer Control (0x4c) */ +#define RT5670_M_DAC_R2_MA (0x1 << 15) +#define RT5670_M_DAC_R2_MA_SFT 15 +#define RT5670_M_DAC_L2_MA (0x1 << 14) +#define RT5670_M_DAC_L2_MA_SFT 14 +#define RT5670_M_OV_R_MM (0x1 << 13) +#define RT5670_M_OV_R_MM_SFT 13 +#define RT5670_M_OV_L_MM (0x1 << 12) +#define RT5670_M_OV_L_MM_SFT 12 +#define RT5670_G_MONOMIX_MASK (0x1 << 10) +#define RT5670_G_MONOMIX_SFT 10 +#define RT5670_M_DAC_R2_MM (0x1 << 9) +#define RT5670_M_DAC_R2_MM_SFT 9 +#define RT5670_M_DAC_L2_MM (0x1 << 8) +#define RT5670_M_DAC_L2_MM_SFT 8 +#define RT5670_M_BST4_MM (0x1 << 7) +#define RT5670_M_BST4_MM_SFT 7 + +/* Output Left Mixer Control 1 (0x4d) */ +#define RT5670_G_BST3_OM_L_MASK (0x7 << 13) +#define RT5670_G_BST3_OM_L_SFT 13 +#define RT5670_G_BST2_OM_L_MASK (0x7 << 10) +#define RT5670_G_BST2_OM_L_SFT 10 +#define RT5670_G_BST1_OM_L_MASK (0x7 << 7) +#define RT5670_G_BST1_OM_L_SFT 7 +#define RT5670_G_IN_L_OM_L_MASK (0x7 << 4) +#define RT5670_G_IN_L_OM_L_SFT 4 +#define RT5670_G_RM_L_OM_L_MASK (0x7 << 1) +#define RT5670_G_RM_L_OM_L_SFT 1 + +/* Output Left Mixer Control 2 (0x4e) */ +#define RT5670_G_DAC_R2_OM_L_MASK (0x7 << 13) +#define RT5670_G_DAC_R2_OM_L_SFT 13 +#define RT5670_G_DAC_L2_OM_L_MASK (0x7 << 10) +#define RT5670_G_DAC_L2_OM_L_SFT 10 +#define RT5670_G_DAC_L1_OM_L_MASK (0x7 << 7) +#define RT5670_G_DAC_L1_OM_L_SFT 7 + +/* Output Left Mixer Control 3 (0x4f) */ +#define RT5670_M_BST1_OM_L (0x1 << 5) +#define RT5670_M_BST1_OM_L_SFT 5 +#define RT5670_M_IN_L_OM_L (0x1 << 4) +#define RT5670_M_IN_L_OM_L_SFT 4 +#define RT5670_M_DAC_L2_OM_L (0x1 << 1) +#define RT5670_M_DAC_L2_OM_L_SFT 1 +#define RT5670_M_DAC_L1_OM_L (0x1) +#define RT5670_M_DAC_L1_OM_L_SFT 0 + +/* Output Right Mixer Control 1 (0x50) */ +#define RT5670_G_BST4_OM_R_MASK (0x7 << 13) +#define RT5670_G_BST4_OM_R_SFT 13 +#define RT5670_G_BST2_OM_R_MASK (0x7 << 10) +#define RT5670_G_BST2_OM_R_SFT 10 +#define RT5670_G_BST1_OM_R_MASK (0x7 << 7) +#define RT5670_G_BST1_OM_R_SFT 7 +#define RT5670_G_IN_R_OM_R_MASK (0x7 << 4) +#define RT5670_G_IN_R_OM_R_SFT 4 +#define RT5670_G_RM_R_OM_R_MASK (0x7 << 1) +#define RT5670_G_RM_R_OM_R_SFT 1 + +/* Output Right Mixer Control 2 (0x51) */ +#define RT5670_G_DAC_L2_OM_R_MASK (0x7 << 13) +#define RT5670_G_DAC_L2_OM_R_SFT 13 +#define RT5670_G_DAC_R2_OM_R_MASK (0x7 << 10) +#define RT5670_G_DAC_R2_OM_R_SFT 10 +#define RT5670_G_DAC_R1_OM_R_MASK (0x7 << 7) +#define RT5670_G_DAC_R1_OM_R_SFT 7 + +/* Output Right Mixer Control 3 (0x52) */ +#define RT5670_M_BST2_OM_R (0x1 << 6) +#define RT5670_M_BST2_OM_R_SFT 6 +#define RT5670_M_IN_R_OM_R (0x1 << 4) +#define RT5670_M_IN_R_OM_R_SFT 4 +#define RT5670_M_DAC_R2_OM_R (0x1 << 1) +#define RT5670_M_DAC_R2_OM_R_SFT 1 +#define RT5670_M_DAC_R1_OM_R (0x1) +#define RT5670_M_DAC_R1_OM_R_SFT 0 + +/* LOUT Mixer Control (0x53) */ +#define RT5670_M_DAC_L1_LM (0x1 << 15) +#define RT5670_M_DAC_L1_LM_SFT 15 +#define RT5670_M_DAC_R1_LM (0x1 << 14) +#define RT5670_M_DAC_R1_LM_SFT 14 +#define RT5670_M_OV_L_LM (0x1 << 13) +#define RT5670_M_OV_L_LM_SFT 13 +#define RT5670_M_OV_R_LM (0x1 << 12) +#define RT5670_M_OV_R_LM_SFT 12 +#define RT5670_G_LOUTMIX_MASK (0x1 << 11) +#define RT5670_G_LOUTMIX_SFT 11 + +/* Power Management for Digital 1 (0x61) */ +#define RT5670_PWR_I2S1 (0x1 << 15) +#define RT5670_PWR_I2S1_BIT 15 +#define RT5670_PWR_I2S2 (0x1 << 14) +#define RT5670_PWR_I2S2_BIT 14 +#define RT5670_PWR_DAC_L1 (0x1 << 12) +#define RT5670_PWR_DAC_L1_BIT 12 +#define RT5670_PWR_DAC_R1 (0x1 << 11) +#define RT5670_PWR_DAC_R1_BIT 11 +#define RT5670_PWR_DAC_L2 (0x1 << 7) +#define RT5670_PWR_DAC_L2_BIT 7 +#define RT5670_PWR_DAC_R2 (0x1 << 6) +#define RT5670_PWR_DAC_R2_BIT 6 +#define RT5670_PWR_ADC_L (0x1 << 2) +#define RT5670_PWR_ADC_L_BIT 2 +#define RT5670_PWR_ADC_R (0x1 << 1) +#define RT5670_PWR_ADC_R_BIT 1 +#define RT5670_PWR_CLS_D (0x1) +#define RT5670_PWR_CLS_D_BIT 0 + +/* Power Management for Digital 2 (0x62) */ +#define RT5670_PWR_ADC_S1F (0x1 << 15) +#define RT5670_PWR_ADC_S1F_BIT 15 +#define RT5670_PWR_ADC_MF_L (0x1 << 14) +#define RT5670_PWR_ADC_MF_L_BIT 14 +#define RT5670_PWR_ADC_MF_R (0x1 << 13) +#define RT5670_PWR_ADC_MF_R_BIT 13 +#define RT5670_PWR_I2S_DSP (0x1 << 12) +#define RT5670_PWR_I2S_DSP_BIT 12 +#define RT5670_PWR_DAC_S1F (0x1 << 11) +#define RT5670_PWR_DAC_S1F_BIT 11 +#define RT5670_PWR_DAC_MF_L (0x1 << 10) +#define RT5670_PWR_DAC_MF_L_BIT 10 +#define RT5670_PWR_DAC_MF_R (0x1 << 9) +#define RT5670_PWR_DAC_MF_R_BIT 9 +#define RT5670_PWR_ADC_S2F (0x1 << 8) +#define RT5670_PWR_ADC_S2F_BIT 8 +#define RT5670_PWR_PDM1 (0x1 << 7) +#define RT5670_PWR_PDM1_BIT 7 +#define RT5670_PWR_PDM2 (0x1 << 6) +#define RT5670_PWR_PDM2_BIT 6 + +/* Power Management for Analog 1 (0x63) */ +#define RT5670_PWR_VREF1 (0x1 << 15) +#define RT5670_PWR_VREF1_BIT 15 +#define RT5670_PWR_FV1 (0x1 << 14) +#define RT5670_PWR_FV1_BIT 14 +#define RT5670_PWR_MB (0x1 << 13) +#define RT5670_PWR_MB_BIT 13 +#define RT5670_PWR_LM (0x1 << 12) +#define RT5670_PWR_LM_BIT 12 +#define RT5670_PWR_BG (0x1 << 11) +#define RT5670_PWR_BG_BIT 11 +#define RT5670_PWR_HP_L (0x1 << 7) +#define RT5670_PWR_HP_L_BIT 7 +#define RT5670_PWR_HP_R (0x1 << 6) +#define RT5670_PWR_HP_R_BIT 6 +#define RT5670_PWR_HA (0x1 << 5) +#define RT5670_PWR_HA_BIT 5 +#define RT5670_PWR_VREF2 (0x1 << 4) +#define RT5670_PWR_VREF2_BIT 4 +#define RT5670_PWR_FV2 (0x1 << 3) +#define RT5670_PWR_FV2_BIT 3 +#define RT5670_LDO_SEL_MASK (0x3) +#define RT5670_LDO_SEL_SFT 0 + +/* Power Management for Analog 2 (0x64) */ +#define RT5670_PWR_BST1 (0x1 << 15) +#define RT5670_PWR_BST1_BIT 15 +#define RT5670_PWR_BST2 (0x1 << 13) +#define RT5670_PWR_BST2_BIT 13 +#define RT5670_PWR_MB1 (0x1 << 11) +#define RT5670_PWR_MB1_BIT 11 +#define RT5670_PWR_MB2 (0x1 << 10) +#define RT5670_PWR_MB2_BIT 10 +#define RT5670_PWR_PLL (0x1 << 9) +#define RT5670_PWR_PLL_BIT 9 +#define RT5670_PWR_BST1_P (0x1 << 6) +#define RT5670_PWR_BST1_P_BIT 6 +#define RT5670_PWR_BST2_P (0x1 << 4) +#define RT5670_PWR_BST2_P_BIT 4 +#define RT5670_PWR_JD1 (0x1 << 2) +#define RT5670_PWR_JD1_BIT 2 +#define RT5670_PWR_JD (0x1 << 1) +#define RT5670_PWR_JD_BIT 1 + +/* Power Management for Mixer (0x65) */ +#define RT5670_PWR_OM_L (0x1 << 15) +#define RT5670_PWR_OM_L_BIT 15 +#define RT5670_PWR_OM_R (0x1 << 14) +#define RT5670_PWR_OM_R_BIT 14 +#define RT5670_PWR_RM_L (0x1 << 11) +#define RT5670_PWR_RM_L_BIT 11 +#define RT5670_PWR_RM_R (0x1 << 10) +#define RT5670_PWR_RM_R_BIT 10 + +/* Power Management for Volume (0x66) */ +#define RT5670_PWR_HV_L (0x1 << 11) +#define RT5670_PWR_HV_L_BIT 11 +#define RT5670_PWR_HV_R (0x1 << 10) +#define RT5670_PWR_HV_R_BIT 10 +#define RT5670_PWR_IN_L (0x1 << 9) +#define RT5670_PWR_IN_L_BIT 9 +#define RT5670_PWR_IN_R (0x1 << 8) +#define RT5670_PWR_IN_R_BIT 8 +#define RT5670_PWR_MIC_DET (0x1 << 5) +#define RT5670_PWR_MIC_DET_BIT 5 + +/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71 0x72) */ +#define RT5670_I2S_MS_MASK (0x1 << 15) +#define RT5670_I2S_MS_SFT 15 +#define RT5670_I2S_MS_M (0x0 << 15) +#define RT5670_I2S_MS_S (0x1 << 15) +#define RT5670_I2S_IF_MASK (0x7 << 12) +#define RT5670_I2S_IF_SFT 12 +#define RT5670_I2S_O_CP_MASK (0x3 << 10) +#define RT5670_I2S_O_CP_SFT 10 +#define RT5670_I2S_O_CP_OFF (0x0 << 10) +#define RT5670_I2S_O_CP_U_LAW (0x1 << 10) +#define RT5670_I2S_O_CP_A_LAW (0x2 << 10) +#define RT5670_I2S_I_CP_MASK (0x3 << 8) +#define RT5670_I2S_I_CP_SFT 8 +#define RT5670_I2S_I_CP_OFF (0x0 << 8) +#define RT5670_I2S_I_CP_U_LAW (0x1 << 8) +#define RT5670_I2S_I_CP_A_LAW (0x2 << 8) +#define RT5670_I2S_BP_MASK (0x1 << 7) +#define RT5670_I2S_BP_SFT 7 +#define RT5670_I2S_BP_NOR (0x0 << 7) +#define RT5670_I2S_BP_INV (0x1 << 7) +#define RT5670_I2S_DL_MASK (0x3 << 2) +#define RT5670_I2S_DL_SFT 2 +#define RT5670_I2S_DL_16 (0x0 << 2) +#define RT5670_I2S_DL_20 (0x1 << 2) +#define RT5670_I2S_DL_24 (0x2 << 2) +#define RT5670_I2S_DL_8 (0x3 << 2) +#define RT5670_I2S_DF_MASK (0x3) +#define RT5670_I2S_DF_SFT 0 +#define RT5670_I2S_DF_I2S (0x0) +#define RT5670_I2S_DF_LEFT (0x1) +#define RT5670_I2S_DF_PCM_A (0x2) +#define RT5670_I2S_DF_PCM_B (0x3) + +/* I2S2 Audio Serial Data Port Control (0x71) */ +#define RT5670_I2S2_SDI_MASK (0x1 << 6) +#define RT5670_I2S2_SDI_SFT 6 +#define RT5670_I2S2_SDI_I2S1 (0x0 << 6) +#define RT5670_I2S2_SDI_I2S2 (0x1 << 6) + +/* ADC/DAC Clock Control 1 (0x73) */ +#define RT5670_I2S_BCLK_MS1_MASK (0x1 << 15) +#define RT5670_I2S_BCLK_MS1_SFT 15 +#define RT5670_I2S_BCLK_MS1_32 (0x0 << 15) +#define RT5670_I2S_BCLK_MS1_64 (0x1 << 15) +#define RT5670_I2S_PD1_MASK (0x7 << 12) +#define RT5670_I2S_PD1_SFT 12 +#define RT5670_I2S_PD1_1 (0x0 << 12) +#define RT5670_I2S_PD1_2 (0x1 << 12) +#define RT5670_I2S_PD1_3 (0x2 << 12) +#define RT5670_I2S_PD1_4 (0x3 << 12) +#define RT5670_I2S_PD1_6 (0x4 << 12) +#define RT5670_I2S_PD1_8 (0x5 << 12) +#define RT5670_I2S_PD1_12 (0x6 << 12) +#define RT5670_I2S_PD1_16 (0x7 << 12) +#define RT5670_I2S_BCLK_MS2_MASK (0x1 << 11) +#define RT5670_I2S_BCLK_MS2_SFT 11 +#define RT5670_I2S_BCLK_MS2_32 (0x0 << 11) +#define RT5670_I2S_BCLK_MS2_64 (0x1 << 11) +#define RT5670_I2S_PD2_MASK (0x7 << 8) +#define RT5670_I2S_PD2_SFT 8 +#define RT5670_I2S_PD2_1 (0x0 << 8) +#define RT5670_I2S_PD2_2 (0x1 << 8) +#define RT5670_I2S_PD2_3 (0x2 << 8) +#define RT5670_I2S_PD2_4 (0x3 << 8) +#define RT5670_I2S_PD2_6 (0x4 << 8) +#define RT5670_I2S_PD2_8 (0x5 << 8) +#define RT5670_I2S_PD2_12 (0x6 << 8) +#define RT5670_I2S_PD2_16 (0x7 << 8) +#define RT5670_I2S_BCLK_MS3_MASK (0x1 << 7) +#define RT5670_I2S_BCLK_MS3_SFT 7 +#define RT5670_I2S_BCLK_MS3_32 (0x0 << 7) +#define RT5670_I2S_BCLK_MS3_64 (0x1 << 7) +#define RT5670_I2S_PD3_MASK (0x7 << 4) +#define RT5670_I2S_PD3_SFT 4 +#define RT5670_I2S_PD3_1 (0x0 << 4) +#define RT5670_I2S_PD3_2 (0x1 << 4) +#define RT5670_I2S_PD3_3 (0x2 << 4) +#define RT5670_I2S_PD3_4 (0x3 << 4) +#define RT5670_I2S_PD3_6 (0x4 << 4) +#define RT5670_I2S_PD3_8 (0x5 << 4) +#define RT5670_I2S_PD3_12 (0x6 << 4) +#define RT5670_I2S_PD3_16 (0x7 << 4) +#define RT5670_DAC_OSR_MASK (0x3 << 2) +#define RT5670_DAC_OSR_SFT 2 +#define RT5670_DAC_OSR_128 (0x0 << 2) +#define RT5670_DAC_OSR_64 (0x1 << 2) +#define RT5670_DAC_OSR_32 (0x2 << 2) +#define RT5670_DAC_OSR_16 (0x3 << 2) +#define RT5670_ADC_OSR_MASK (0x3) +#define RT5670_ADC_OSR_SFT 0 +#define RT5670_ADC_OSR_128 (0x0) +#define RT5670_ADC_OSR_64 (0x1) +#define RT5670_ADC_OSR_32 (0x2) +#define RT5670_ADC_OSR_16 (0x3) + +/* ADC/DAC Clock Control 2 (0x74) */ +#define RT5670_DAC_L_OSR_MASK (0x3 << 14) +#define RT5670_DAC_L_OSR_SFT 14 +#define RT5670_DAC_L_OSR_128 (0x0 << 14) +#define RT5670_DAC_L_OSR_64 (0x1 << 14) +#define RT5670_DAC_L_OSR_32 (0x2 << 14) +#define RT5670_DAC_L_OSR_16 (0x3 << 14) +#define RT5670_ADC_R_OSR_MASK (0x3 << 12) +#define RT5670_ADC_R_OSR_SFT 12 +#define RT5670_ADC_R_OSR_128 (0x0 << 12) +#define RT5670_ADC_R_OSR_64 (0x1 << 12) +#define RT5670_ADC_R_OSR_32 (0x2 << 12) +#define RT5670_ADC_R_OSR_16 (0x3 << 12) +#define RT5670_DAHPF_EN (0x1 << 11) +#define RT5670_DAHPF_EN_SFT 11 +#define RT5670_ADHPF_EN (0x1 << 10) +#define RT5670_ADHPF_EN_SFT 10 + +/* Digital Microphone Control (0x75) */ +#define RT5670_DMIC_1_EN_MASK (0x1 << 15) +#define RT5670_DMIC_1_EN_SFT 15 +#define RT5670_DMIC_1_DIS (0x0 << 15) +#define RT5670_DMIC_1_EN (0x1 << 15) +#define RT5670_DMIC_2_EN_MASK (0x1 << 14) +#define RT5670_DMIC_2_EN_SFT 14 +#define RT5670_DMIC_2_DIS (0x0 << 14) +#define RT5670_DMIC_2_EN (0x1 << 14) +#define RT5670_DMIC_1L_LH_MASK (0x1 << 13) +#define RT5670_DMIC_1L_LH_SFT 13 +#define RT5670_DMIC_1L_LH_FALLING (0x0 << 13) +#define RT5670_DMIC_1L_LH_RISING (0x1 << 13) +#define RT5670_DMIC_1R_LH_MASK (0x1 << 12) +#define RT5670_DMIC_1R_LH_SFT 12 +#define RT5670_DMIC_1R_LH_FALLING (0x0 << 12) +#define RT5670_DMIC_1R_LH_RISING (0x1 << 12) +#define RT5670_DMIC_2_DP_MASK (0x1 << 10) +#define RT5670_DMIC_2_DP_SFT 10 +#define RT5670_DMIC_2_DP_GPIO8 (0x0 << 10) +#define RT5670_DMIC_2_DP_IN3N (0x1 << 10) +#define RT5670_DMIC_2L_LH_MASK (0x1 << 9) +#define RT5670_DMIC_2L_LH_SFT 9 +#define RT5670_DMIC_2L_LH_FALLING (0x0 << 9) +#define RT5670_DMIC_2L_LH_RISING (0x1 << 9) +#define RT5670_DMIC_2R_LH_MASK (0x1 << 8) +#define RT5670_DMIC_2R_LH_SFT 8 +#define RT5670_DMIC_2R_LH_FALLING (0x0 << 8) +#define RT5670_DMIC_2R_LH_RISING (0x1 << 8) +#define RT5670_DMIC_CLK_MASK (0x7 << 5) +#define RT5670_DMIC_CLK_SFT 5 +#define RT5670_DMIC_3_EN_MASK (0x1 << 4) +#define RT5670_DMIC_3_EN_SFT 4 +#define RT5670_DMIC_3_DIS (0x0 << 4) +#define RT5670_DMIC_3_EN (0x1 << 4) +#define RT5670_DMIC_1_DP_MASK (0x3 << 0) +#define RT5670_DMIC_1_DP_SFT 0 +#define RT5670_DMIC_1_DP_GPIO6 (0x0 << 0) +#define RT5670_DMIC_1_DP_IN2P (0x1 << 0) +#define RT5670_DMIC_1_DP_GPIO7 (0x2 << 0) + +/* Digital Microphone Control2 (0x76) */ +#define RT5670_DMIC_3_DP_MASK (0x3 << 6) +#define RT5670_DMIC_3_DP_SFT 6 +#define RT5670_DMIC_3_DP_GPIO9 (0x0 << 6) +#define RT5670_DMIC_3_DP_GPIO10 (0x1 << 6) +#define RT5670_DMIC_3_DP_GPIO5 (0x2 << 6) + +/* Global Clock Control (0x80) */ +#define RT5670_SCLK_SRC_MASK (0x3 << 14) +#define RT5670_SCLK_SRC_SFT 14 +#define RT5670_SCLK_SRC_MCLK (0x0 << 14) +#define RT5670_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5670_SCLK_SRC_RCCLK (0x2 << 14) /* 15MHz */ +#define RT5670_PLL1_SRC_MASK (0x3 << 12) +#define RT5670_PLL1_SRC_SFT 12 +#define RT5670_PLL1_SRC_MCLK (0x0 << 12) +#define RT5670_PLL1_SRC_BCLK1 (0x1 << 12) +#define RT5670_PLL1_SRC_BCLK2 (0x2 << 12) +#define RT5670_PLL1_SRC_BCLK3 (0x3 << 12) +#define RT5670_PLL1_PD_MASK (0x1 << 3) +#define RT5670_PLL1_PD_SFT 3 +#define RT5670_PLL1_PD_1 (0x0 << 3) +#define RT5670_PLL1_PD_2 (0x1 << 3) + +#define RT5670_PLL_INP_MAX 40000000 +#define RT5670_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x81) */ +#define RT5670_PLL_N_MAX 0x1ff +#define RT5670_PLL_N_MASK (RT5670_PLL_N_MAX << 7) +#define RT5670_PLL_N_SFT 7 +#define RT5670_PLL_K_MAX 0x1f +#define RT5670_PLL_K_MASK (RT5670_PLL_K_MAX) +#define RT5670_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x82) */ +#define RT5670_PLL_M_MAX 0xf +#define RT5670_PLL_M_MASK (RT5670_PLL_M_MAX << 12) +#define RT5670_PLL_M_SFT 12 +#define RT5670_PLL_M_BP (0x1 << 11) +#define RT5670_PLL_M_BP_SFT 11 + +/* ASRC Control 1 (0x83) */ +#define RT5670_STO_T_MASK (0x1 << 15) +#define RT5670_STO_T_SFT 15 +#define RT5670_STO_T_SCLK (0x0 << 15) +#define RT5670_STO_T_LRCK1 (0x1 << 15) +#define RT5670_M1_T_MASK (0x1 << 14) +#define RT5670_M1_T_SFT 14 +#define RT5670_M1_T_I2S2 (0x0 << 14) +#define RT5670_M1_T_I2S2_D3 (0x1 << 14) +#define RT5670_I2S2_F_MASK (0x1 << 12) +#define RT5670_I2S2_F_SFT 12 +#define RT5670_I2S2_F_I2S2_D2 (0x0 << 12) +#define RT5670_I2S2_F_I2S1_TCLK (0x1 << 12) +#define RT5670_DMIC_1_M_MASK (0x1 << 9) +#define RT5670_DMIC_1_M_SFT 9 +#define RT5670_DMIC_1_M_NOR (0x0 << 9) +#define RT5670_DMIC_1_M_ASYN (0x1 << 9) +#define RT5670_DMIC_2_M_MASK (0x1 << 8) +#define RT5670_DMIC_2_M_SFT 8 +#define RT5670_DMIC_2_M_NOR (0x0 << 8) +#define RT5670_DMIC_2_M_ASYN (0x1 << 8) + +/* ASRC Control 2 (0x84) */ +#define RT5670_MDA_L_M_MASK (0x1 << 15) +#define RT5670_MDA_L_M_SFT 15 +#define RT5670_MDA_L_M_NOR (0x0 << 15) +#define RT5670_MDA_L_M_ASYN (0x1 << 15) +#define RT5670_MDA_R_M_MASK (0x1 << 14) +#define RT5670_MDA_R_M_SFT 14 +#define RT5670_MDA_R_M_NOR (0x0 << 14) +#define RT5670_MDA_R_M_ASYN (0x1 << 14) +#define RT5670_MAD_L_M_MASK (0x1 << 13) +#define RT5670_MAD_L_M_SFT 13 +#define RT5670_MAD_L_M_NOR (0x0 << 13) +#define RT5670_MAD_L_M_ASYN (0x1 << 13) +#define RT5670_MAD_R_M_MASK (0x1 << 12) +#define RT5670_MAD_R_M_SFT 12 +#define RT5670_MAD_R_M_NOR (0x0 << 12) +#define RT5670_MAD_R_M_ASYN (0x1 << 12) +#define RT5670_ADC_M_MASK (0x1 << 11) +#define RT5670_ADC_M_SFT 11 +#define RT5670_ADC_M_NOR (0x0 << 11) +#define RT5670_ADC_M_ASYN (0x1 << 11) +#define RT5670_STO_DAC_M_MASK (0x1 << 5) +#define RT5670_STO_DAC_M_SFT 5 +#define RT5670_STO_DAC_M_NOR (0x0 << 5) +#define RT5670_STO_DAC_M_ASYN (0x1 << 5) +#define RT5670_I2S1_R_D_MASK (0x1 << 4) +#define RT5670_I2S1_R_D_SFT 4 +#define RT5670_I2S1_R_D_DIS (0x0 << 4) +#define RT5670_I2S1_R_D_EN (0x1 << 4) +#define RT5670_I2S2_R_D_MASK (0x1 << 3) +#define RT5670_I2S2_R_D_SFT 3 +#define RT5670_I2S2_R_D_DIS (0x0 << 3) +#define RT5670_I2S2_R_D_EN (0x1 << 3) +#define RT5670_PRE_SCLK_MASK (0x3) +#define RT5670_PRE_SCLK_SFT 0 +#define RT5670_PRE_SCLK_512 (0x0) +#define RT5670_PRE_SCLK_1024 (0x1) +#define RT5670_PRE_SCLK_2048 (0x2) + +/* ASRC Control 3 (0x85) */ +#define RT5670_I2S1_RATE_MASK (0xf << 12) +#define RT5670_I2S1_RATE_SFT 12 +#define RT5670_I2S2_RATE_MASK (0xf << 8) +#define RT5670_I2S2_RATE_SFT 8 + +/* ASRC Control 4 (0x89) */ +#define RT5670_I2S1_PD_MASK (0x7 << 12) +#define RT5670_I2S1_PD_SFT 12 +#define RT5670_I2S2_PD_MASK (0x7 << 8) +#define RT5670_I2S2_PD_SFT 8 + +/* HPOUT Over Current Detection (0x8b) */ +#define RT5670_HP_OVCD_MASK (0x1 << 10) +#define RT5670_HP_OVCD_SFT 10 +#define RT5670_HP_OVCD_DIS (0x0 << 10) +#define RT5670_HP_OVCD_EN (0x1 << 10) +#define RT5670_HP_OC_TH_MASK (0x3 << 8) +#define RT5670_HP_OC_TH_SFT 8 +#define RT5670_HP_OC_TH_90 (0x0 << 8) +#define RT5670_HP_OC_TH_105 (0x1 << 8) +#define RT5670_HP_OC_TH_120 (0x2 << 8) +#define RT5670_HP_OC_TH_135 (0x3 << 8) + +/* Class D Over Current Control (0x8c) */ +#define RT5670_CLSD_OC_MASK (0x1 << 9) +#define RT5670_CLSD_OC_SFT 9 +#define RT5670_CLSD_OC_PU (0x0 << 9) +#define RT5670_CLSD_OC_PD (0x1 << 9) +#define RT5670_AUTO_PD_MASK (0x1 << 8) +#define RT5670_AUTO_PD_SFT 8 +#define RT5670_AUTO_PD_DIS (0x0 << 8) +#define RT5670_AUTO_PD_EN (0x1 << 8) +#define RT5670_CLSD_OC_TH_MASK (0x3f) +#define RT5670_CLSD_OC_TH_SFT 0 + +/* Class D Output Control (0x8d) */ +#define RT5670_CLSD_RATIO_MASK (0xf << 12) +#define RT5670_CLSD_RATIO_SFT 12 +#define RT5670_CLSD_OM_MASK (0x1 << 11) +#define RT5670_CLSD_OM_SFT 11 +#define RT5670_CLSD_OM_MONO (0x0 << 11) +#define RT5670_CLSD_OM_STO (0x1 << 11) +#define RT5670_CLSD_SCH_MASK (0x1 << 10) +#define RT5670_CLSD_SCH_SFT 10 +#define RT5670_CLSD_SCH_L (0x0 << 10) +#define RT5670_CLSD_SCH_S (0x1 << 10) + +/* Depop Mode Control 1 (0x8e) */ +#define RT5670_SMT_TRIG_MASK (0x1 << 15) +#define RT5670_SMT_TRIG_SFT 15 +#define RT5670_SMT_TRIG_DIS (0x0 << 15) +#define RT5670_SMT_TRIG_EN (0x1 << 15) +#define RT5670_HP_L_SMT_MASK (0x1 << 9) +#define RT5670_HP_L_SMT_SFT 9 +#define RT5670_HP_L_SMT_DIS (0x0 << 9) +#define RT5670_HP_L_SMT_EN (0x1 << 9) +#define RT5670_HP_R_SMT_MASK (0x1 << 8) +#define RT5670_HP_R_SMT_SFT 8 +#define RT5670_HP_R_SMT_DIS (0x0 << 8) +#define RT5670_HP_R_SMT_EN (0x1 << 8) +#define RT5670_HP_CD_PD_MASK (0x1 << 7) +#define RT5670_HP_CD_PD_SFT 7 +#define RT5670_HP_CD_PD_DIS (0x0 << 7) +#define RT5670_HP_CD_PD_EN (0x1 << 7) +#define RT5670_RSTN_MASK (0x1 << 6) +#define RT5670_RSTN_SFT 6 +#define RT5670_RSTN_DIS (0x0 << 6) +#define RT5670_RSTN_EN (0x1 << 6) +#define RT5670_RSTP_MASK (0x1 << 5) +#define RT5670_RSTP_SFT 5 +#define RT5670_RSTP_DIS (0x0 << 5) +#define RT5670_RSTP_EN (0x1 << 5) +#define RT5670_HP_CO_MASK (0x1 << 4) +#define RT5670_HP_CO_SFT 4 +#define RT5670_HP_CO_DIS (0x0 << 4) +#define RT5670_HP_CO_EN (0x1 << 4) +#define RT5670_HP_CP_MASK (0x1 << 3) +#define RT5670_HP_CP_SFT 3 +#define RT5670_HP_CP_PD (0x0 << 3) +#define RT5670_HP_CP_PU (0x1 << 3) +#define RT5670_HP_SG_MASK (0x1 << 2) +#define RT5670_HP_SG_SFT 2 +#define RT5670_HP_SG_DIS (0x0 << 2) +#define RT5670_HP_SG_EN (0x1 << 2) +#define RT5670_HP_DP_MASK (0x1 << 1) +#define RT5670_HP_DP_SFT 1 +#define RT5670_HP_DP_PD (0x0 << 1) +#define RT5670_HP_DP_PU (0x1 << 1) +#define RT5670_HP_CB_MASK (0x1) +#define RT5670_HP_CB_SFT 0 +#define RT5670_HP_CB_PD (0x0) +#define RT5670_HP_CB_PU (0x1) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5670_DEPOP_MASK (0x1 << 13) +#define RT5670_DEPOP_SFT 13 +#define RT5670_DEPOP_AUTO (0x0 << 13) +#define RT5670_DEPOP_MAN (0x1 << 13) +#define RT5670_RAMP_MASK (0x1 << 12) +#define RT5670_RAMP_SFT 12 +#define RT5670_RAMP_DIS (0x0 << 12) +#define RT5670_RAMP_EN (0x1 << 12) +#define RT5670_BPS_MASK (0x1 << 11) +#define RT5670_BPS_SFT 11 +#define RT5670_BPS_DIS (0x0 << 11) +#define RT5670_BPS_EN (0x1 << 11) +#define RT5670_FAST_UPDN_MASK (0x1 << 10) +#define RT5670_FAST_UPDN_SFT 10 +#define RT5670_FAST_UPDN_DIS (0x0 << 10) +#define RT5670_FAST_UPDN_EN (0x1 << 10) +#define RT5670_MRES_MASK (0x3 << 8) +#define RT5670_MRES_SFT 8 +#define RT5670_MRES_15MO (0x0 << 8) +#define RT5670_MRES_25MO (0x1 << 8) +#define RT5670_MRES_35MO (0x2 << 8) +#define RT5670_MRES_45MO (0x3 << 8) +#define RT5670_VLO_MASK (0x1 << 7) +#define RT5670_VLO_SFT 7 +#define RT5670_VLO_3V (0x0 << 7) +#define RT5670_VLO_32V (0x1 << 7) +#define RT5670_DIG_DP_MASK (0x1 << 6) +#define RT5670_DIG_DP_SFT 6 +#define RT5670_DIG_DP_DIS (0x0 << 6) +#define RT5670_DIG_DP_EN (0x1 << 6) +#define RT5670_DP_TH_MASK (0x3 << 4) +#define RT5670_DP_TH_SFT 4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5670_CP_SYS_MASK (0x7 << 12) +#define RT5670_CP_SYS_SFT 12 +#define RT5670_CP_FQ1_MASK (0x7 << 8) +#define RT5670_CP_FQ1_SFT 8 +#define RT5670_CP_FQ2_MASK (0x7 << 4) +#define RT5670_CP_FQ2_SFT 4 +#define RT5670_CP_FQ3_MASK (0x7) +#define RT5670_CP_FQ3_SFT 0 +#define RT5670_CP_FQ_1_5_KHZ 0 +#define RT5670_CP_FQ_3_KHZ 1 +#define RT5670_CP_FQ_6_KHZ 2 +#define RT5670_CP_FQ_12_KHZ 3 +#define RT5670_CP_FQ_24_KHZ 4 +#define RT5670_CP_FQ_48_KHZ 5 +#define RT5670_CP_FQ_96_KHZ 6 +#define RT5670_CP_FQ_192_KHZ 7 + +/* HPOUT charge pump (0x91) */ +#define RT5670_OSW_L_MASK (0x1 << 11) +#define RT5670_OSW_L_SFT 11 +#define RT5670_OSW_L_DIS (0x0 << 11) +#define RT5670_OSW_L_EN (0x1 << 11) +#define RT5670_OSW_R_MASK (0x1 << 10) +#define RT5670_OSW_R_SFT 10 +#define RT5670_OSW_R_DIS (0x0 << 10) +#define RT5670_OSW_R_EN (0x1 << 10) +#define RT5670_PM_HP_MASK (0x3 << 8) +#define RT5670_PM_HP_SFT 8 +#define RT5670_PM_HP_LV (0x0 << 8) +#define RT5670_PM_HP_MV (0x1 << 8) +#define RT5670_PM_HP_HV (0x2 << 8) +#define RT5670_IB_HP_MASK (0x3 << 6) +#define RT5670_IB_HP_SFT 6 +#define RT5670_IB_HP_125IL (0x0 << 6) +#define RT5670_IB_HP_25IL (0x1 << 6) +#define RT5670_IB_HP_5IL (0x2 << 6) +#define RT5670_IB_HP_1IL (0x3 << 6) + +/* PV detection and SPK gain control (0x92) */ +#define RT5670_PVDD_DET_MASK (0x1 << 15) +#define RT5670_PVDD_DET_SFT 15 +#define RT5670_PVDD_DET_DIS (0x0 << 15) +#define RT5670_PVDD_DET_EN (0x1 << 15) +#define RT5670_SPK_AG_MASK (0x1 << 14) +#define RT5670_SPK_AG_SFT 14 +#define RT5670_SPK_AG_DIS (0x0 << 14) +#define RT5670_SPK_AG_EN (0x1 << 14) + +/* Micbias Control (0x93) */ +#define RT5670_MIC1_BS_MASK (0x1 << 15) +#define RT5670_MIC1_BS_SFT 15 +#define RT5670_MIC1_BS_9AV (0x0 << 15) +#define RT5670_MIC1_BS_75AV (0x1 << 15) +#define RT5670_MIC2_BS_MASK (0x1 << 14) +#define RT5670_MIC2_BS_SFT 14 +#define RT5670_MIC2_BS_9AV (0x0 << 14) +#define RT5670_MIC2_BS_75AV (0x1 << 14) +#define RT5670_MIC1_CLK_MASK (0x1 << 13) +#define RT5670_MIC1_CLK_SFT 13 +#define RT5670_MIC1_CLK_DIS (0x0 << 13) +#define RT5670_MIC1_CLK_EN (0x1 << 13) +#define RT5670_MIC2_CLK_MASK (0x1 << 12) +#define RT5670_MIC2_CLK_SFT 12 +#define RT5670_MIC2_CLK_DIS (0x0 << 12) +#define RT5670_MIC2_CLK_EN (0x1 << 12) +#define RT5670_MIC1_OVCD_MASK (0x1 << 11) +#define RT5670_MIC1_OVCD_SFT 11 +#define RT5670_MIC1_OVCD_DIS (0x0 << 11) +#define RT5670_MIC1_OVCD_EN (0x1 << 11) +#define RT5670_MIC1_OVTH_MASK (0x3 << 9) +#define RT5670_MIC1_OVTH_SFT 9 +#define RT5670_MIC1_OVTH_600UA (0x0 << 9) +#define RT5670_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5670_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5670_MIC2_OVCD_MASK (0x1 << 8) +#define RT5670_MIC2_OVCD_SFT 8 +#define RT5670_MIC2_OVCD_DIS (0x0 << 8) +#define RT5670_MIC2_OVCD_EN (0x1 << 8) +#define RT5670_MIC2_OVTH_MASK (0x3 << 6) +#define RT5670_MIC2_OVTH_SFT 6 +#define RT5670_MIC2_OVTH_600UA (0x0 << 6) +#define RT5670_MIC2_OVTH_1500UA (0x1 << 6) +#define RT5670_MIC2_OVTH_2000UA (0x2 << 6) +#define RT5670_PWR_MB_MASK (0x1 << 5) +#define RT5670_PWR_MB_SFT 5 +#define RT5670_PWR_MB_PD (0x0 << 5) +#define RT5670_PWR_MB_PU (0x1 << 5) +#define RT5670_PWR_CLK25M_MASK (0x1 << 4) +#define RT5670_PWR_CLK25M_SFT 4 +#define RT5670_PWR_CLK25M_PD (0x0 << 4) +#define RT5670_PWR_CLK25M_PU (0x1 << 4) + +/* Analog JD Control 1 (0x94) */ +#define RT5670_JD1_MODE_MASK (0x3 << 0) +#define RT5670_JD1_MODE_0 (0x0 << 0) +#define RT5670_JD1_MODE_1 (0x1 << 0) +#define RT5670_JD1_MODE_2 (0x2 << 0) + +/* VAD Control 4 (0x9d) */ +#define RT5670_VAD_SEL_MASK (0x3 << 8) +#define RT5670_VAD_SEL_SFT 8 + +/* EQ Control 1 (0xb0) */ +#define RT5670_EQ_SRC_MASK (0x1 << 15) +#define RT5670_EQ_SRC_SFT 15 +#define RT5670_EQ_SRC_DAC (0x0 << 15) +#define RT5670_EQ_SRC_ADC (0x1 << 15) +#define RT5670_EQ_UPD (0x1 << 14) +#define RT5670_EQ_UPD_BIT 14 +#define RT5670_EQ_CD_MASK (0x1 << 13) +#define RT5670_EQ_CD_SFT 13 +#define RT5670_EQ_CD_DIS (0x0 << 13) +#define RT5670_EQ_CD_EN (0x1 << 13) +#define RT5670_EQ_DITH_MASK (0x3 << 8) +#define RT5670_EQ_DITH_SFT 8 +#define RT5670_EQ_DITH_NOR (0x0 << 8) +#define RT5670_EQ_DITH_LSB (0x1 << 8) +#define RT5670_EQ_DITH_LSB_1 (0x2 << 8) +#define RT5670_EQ_DITH_LSB_2 (0x3 << 8) + +/* EQ Control 2 (0xb1) */ +#define RT5670_EQ_HPF1_M_MASK (0x1 << 8) +#define RT5670_EQ_HPF1_M_SFT 8 +#define RT5670_EQ_HPF1_M_HI (0x0 << 8) +#define RT5670_EQ_HPF1_M_1ST (0x1 << 8) +#define RT5670_EQ_LPF1_M_MASK (0x1 << 7) +#define RT5670_EQ_LPF1_M_SFT 7 +#define RT5670_EQ_LPF1_M_LO (0x0 << 7) +#define RT5670_EQ_LPF1_M_1ST (0x1 << 7) +#define RT5670_EQ_HPF2_MASK (0x1 << 6) +#define RT5670_EQ_HPF2_SFT 6 +#define RT5670_EQ_HPF2_DIS (0x0 << 6) +#define RT5670_EQ_HPF2_EN (0x1 << 6) +#define RT5670_EQ_HPF1_MASK (0x1 << 5) +#define RT5670_EQ_HPF1_SFT 5 +#define RT5670_EQ_HPF1_DIS (0x0 << 5) +#define RT5670_EQ_HPF1_EN (0x1 << 5) +#define RT5670_EQ_BPF4_MASK (0x1 << 4) +#define RT5670_EQ_BPF4_SFT 4 +#define RT5670_EQ_BPF4_DIS (0x0 << 4) +#define RT5670_EQ_BPF4_EN (0x1 << 4) +#define RT5670_EQ_BPF3_MASK (0x1 << 3) +#define RT5670_EQ_BPF3_SFT 3 +#define RT5670_EQ_BPF3_DIS (0x0 << 3) +#define RT5670_EQ_BPF3_EN (0x1 << 3) +#define RT5670_EQ_BPF2_MASK (0x1 << 2) +#define RT5670_EQ_BPF2_SFT 2 +#define RT5670_EQ_BPF2_DIS (0x0 << 2) +#define RT5670_EQ_BPF2_EN (0x1 << 2) +#define RT5670_EQ_BPF1_MASK (0x1 << 1) +#define RT5670_EQ_BPF1_SFT 1 +#define RT5670_EQ_BPF1_DIS (0x0 << 1) +#define RT5670_EQ_BPF1_EN (0x1 << 1) +#define RT5670_EQ_LPF_MASK (0x1) +#define RT5670_EQ_LPF_SFT 0 +#define RT5670_EQ_LPF_DIS (0x0) +#define RT5670_EQ_LPF_EN (0x1) +#define RT5670_EQ_CTRL_MASK (0x7f) + +/* Memory Test (0xb2) */ +#define RT5670_MT_MASK (0x1 << 15) +#define RT5670_MT_SFT 15 +#define RT5670_MT_DIS (0x0 << 15) +#define RT5670_MT_EN (0x1 << 15) + +/* DRC/AGC Control 1 (0xb4) */ +#define RT5670_DRC_AGC_P_MASK (0x1 << 15) +#define RT5670_DRC_AGC_P_SFT 15 +#define RT5670_DRC_AGC_P_DAC (0x0 << 15) +#define RT5670_DRC_AGC_P_ADC (0x1 << 15) +#define RT5670_DRC_AGC_MASK (0x1 << 14) +#define RT5670_DRC_AGC_SFT 14 +#define RT5670_DRC_AGC_DIS (0x0 << 14) +#define RT5670_DRC_AGC_EN (0x1 << 14) +#define RT5670_DRC_AGC_UPD (0x1 << 13) +#define RT5670_DRC_AGC_UPD_BIT 13 +#define RT5670_DRC_AGC_AR_MASK (0x1f << 8) +#define RT5670_DRC_AGC_AR_SFT 8 +#define RT5670_DRC_AGC_R_MASK (0x7 << 5) +#define RT5670_DRC_AGC_R_SFT 5 +#define RT5670_DRC_AGC_R_48K (0x1 << 5) +#define RT5670_DRC_AGC_R_96K (0x2 << 5) +#define RT5670_DRC_AGC_R_192K (0x3 << 5) +#define RT5670_DRC_AGC_R_441K (0x5 << 5) +#define RT5670_DRC_AGC_R_882K (0x6 << 5) +#define RT5670_DRC_AGC_R_1764K (0x7 << 5) +#define RT5670_DRC_AGC_RC_MASK (0x1f) +#define RT5670_DRC_AGC_RC_SFT 0 + +/* DRC/AGC Control 2 (0xb5) */ +#define RT5670_DRC_AGC_POB_MASK (0x3f << 8) +#define RT5670_DRC_AGC_POB_SFT 8 +#define RT5670_DRC_AGC_CP_MASK (0x1 << 7) +#define RT5670_DRC_AGC_CP_SFT 7 +#define RT5670_DRC_AGC_CP_DIS (0x0 << 7) +#define RT5670_DRC_AGC_CP_EN (0x1 << 7) +#define RT5670_DRC_AGC_CPR_MASK (0x3 << 5) +#define RT5670_DRC_AGC_CPR_SFT 5 +#define RT5670_DRC_AGC_CPR_1_1 (0x0 << 5) +#define RT5670_DRC_AGC_CPR_1_2 (0x1 << 5) +#define RT5670_DRC_AGC_CPR_1_3 (0x2 << 5) +#define RT5670_DRC_AGC_CPR_1_4 (0x3 << 5) +#define RT5670_DRC_AGC_PRB_MASK (0x1f) +#define RT5670_DRC_AGC_PRB_SFT 0 + +/* DRC/AGC Control 3 (0xb6) */ +#define RT5670_DRC_AGC_NGB_MASK (0xf << 12) +#define RT5670_DRC_AGC_NGB_SFT 12 +#define RT5670_DRC_AGC_TAR_MASK (0x1f << 7) +#define RT5670_DRC_AGC_TAR_SFT 7 +#define RT5670_DRC_AGC_NG_MASK (0x1 << 6) +#define RT5670_DRC_AGC_NG_SFT 6 +#define RT5670_DRC_AGC_NG_DIS (0x0 << 6) +#define RT5670_DRC_AGC_NG_EN (0x1 << 6) +#define RT5670_DRC_AGC_NGH_MASK (0x1 << 5) +#define RT5670_DRC_AGC_NGH_SFT 5 +#define RT5670_DRC_AGC_NGH_DIS (0x0 << 5) +#define RT5670_DRC_AGC_NGH_EN (0x1 << 5) +#define RT5670_DRC_AGC_NGT_MASK (0x1f) +#define RT5670_DRC_AGC_NGT_SFT 0 + +/* Jack Detect Control (0xbb) */ +#define RT5670_JD_MASK (0x7 << 13) +#define RT5670_JD_SFT 13 +#define RT5670_JD_DIS (0x0 << 13) +#define RT5670_JD_GPIO1 (0x1 << 13) +#define RT5670_JD_JD1_IN4P (0x2 << 13) +#define RT5670_JD_JD2_IN4N (0x3 << 13) +#define RT5670_JD_GPIO2 (0x4 << 13) +#define RT5670_JD_GPIO3 (0x5 << 13) +#define RT5670_JD_GPIO4 (0x6 << 13) +#define RT5670_JD_HP_MASK (0x1 << 11) +#define RT5670_JD_HP_SFT 11 +#define RT5670_JD_HP_DIS (0x0 << 11) +#define RT5670_JD_HP_EN (0x1 << 11) +#define RT5670_JD_HP_TRG_MASK (0x1 << 10) +#define RT5670_JD_HP_TRG_SFT 10 +#define RT5670_JD_HP_TRG_LO (0x0 << 10) +#define RT5670_JD_HP_TRG_HI (0x1 << 10) +#define RT5670_JD_SPL_MASK (0x1 << 9) +#define RT5670_JD_SPL_SFT 9 +#define RT5670_JD_SPL_DIS (0x0 << 9) +#define RT5670_JD_SPL_EN (0x1 << 9) +#define RT5670_JD_SPL_TRG_MASK (0x1 << 8) +#define RT5670_JD_SPL_TRG_SFT 8 +#define RT5670_JD_SPL_TRG_LO (0x0 << 8) +#define RT5670_JD_SPL_TRG_HI (0x1 << 8) +#define RT5670_JD_SPR_MASK (0x1 << 7) +#define RT5670_JD_SPR_SFT 7 +#define RT5670_JD_SPR_DIS (0x0 << 7) +#define RT5670_JD_SPR_EN (0x1 << 7) +#define RT5670_JD_SPR_TRG_MASK (0x1 << 6) +#define RT5670_JD_SPR_TRG_SFT 6 +#define RT5670_JD_SPR_TRG_LO (0x0 << 6) +#define RT5670_JD_SPR_TRG_HI (0x1 << 6) +#define RT5670_JD_MO_MASK (0x1 << 5) +#define RT5670_JD_MO_SFT 5 +#define RT5670_JD_MO_DIS (0x0 << 5) +#define RT5670_JD_MO_EN (0x1 << 5) +#define RT5670_JD_MO_TRG_MASK (0x1 << 4) +#define RT5670_JD_MO_TRG_SFT 4 +#define RT5670_JD_MO_TRG_LO (0x0 << 4) +#define RT5670_JD_MO_TRG_HI (0x1 << 4) +#define RT5670_JD_LO_MASK (0x1 << 3) +#define RT5670_JD_LO_SFT 3 +#define RT5670_JD_LO_DIS (0x0 << 3) +#define RT5670_JD_LO_EN (0x1 << 3) +#define RT5670_JD_LO_TRG_MASK (0x1 << 2) +#define RT5670_JD_LO_TRG_SFT 2 +#define RT5670_JD_LO_TRG_LO (0x0 << 2) +#define RT5670_JD_LO_TRG_HI (0x1 << 2) +#define RT5670_JD1_IN4P_MASK (0x1 << 1) +#define RT5670_JD1_IN4P_SFT 1 +#define RT5670_JD1_IN4P_DIS (0x0 << 1) +#define RT5670_JD1_IN4P_EN (0x1 << 1) +#define RT5670_JD2_IN4N_MASK (0x1) +#define RT5670_JD2_IN4N_SFT 0 +#define RT5670_JD2_IN4N_DIS (0x0) +#define RT5670_JD2_IN4N_EN (0x1) + +/* IRQ Control 1 (0xbd) */ +#define RT5670_IRQ_JD_MASK (0x1 << 15) +#define RT5670_IRQ_JD_SFT 15 +#define RT5670_IRQ_JD_BP (0x0 << 15) +#define RT5670_IRQ_JD_NOR (0x1 << 15) +#define RT5670_IRQ_OT_MASK (0x1 << 14) +#define RT5670_IRQ_OT_SFT 14 +#define RT5670_IRQ_OT_BP (0x0 << 14) +#define RT5670_IRQ_OT_NOR (0x1 << 14) +#define RT5670_JD_STKY_MASK (0x1 << 13) +#define RT5670_JD_STKY_SFT 13 +#define RT5670_JD_STKY_DIS (0x0 << 13) +#define RT5670_JD_STKY_EN (0x1 << 13) +#define RT5670_OT_STKY_MASK (0x1 << 12) +#define RT5670_OT_STKY_SFT 12 +#define RT5670_OT_STKY_DIS (0x0 << 12) +#define RT5670_OT_STKY_EN (0x1 << 12) +#define RT5670_JD_P_MASK (0x1 << 11) +#define RT5670_JD_P_SFT 11 +#define RT5670_JD_P_NOR (0x0 << 11) +#define RT5670_JD_P_INV (0x1 << 11) +#define RT5670_OT_P_MASK (0x1 << 10) +#define RT5670_OT_P_SFT 10 +#define RT5670_OT_P_NOR (0x0 << 10) +#define RT5670_OT_P_INV (0x1 << 10) +#define RT5670_JD1_1_EN_MASK (0x1 << 9) +#define RT5670_JD1_1_EN_SFT 9 +#define RT5670_JD1_1_DIS (0x0 << 9) +#define RT5670_JD1_1_EN (0x1 << 9) + +/* IRQ Control 2 (0xbe) */ +#define RT5670_IRQ_MB1_OC_MASK (0x1 << 15) +#define RT5670_IRQ_MB1_OC_SFT 15 +#define RT5670_IRQ_MB1_OC_BP (0x0 << 15) +#define RT5670_IRQ_MB1_OC_NOR (0x1 << 15) +#define RT5670_IRQ_MB2_OC_MASK (0x1 << 14) +#define RT5670_IRQ_MB2_OC_SFT 14 +#define RT5670_IRQ_MB2_OC_BP (0x0 << 14) +#define RT5670_IRQ_MB2_OC_NOR (0x1 << 14) +#define RT5670_MB1_OC_STKY_MASK (0x1 << 11) +#define RT5670_MB1_OC_STKY_SFT 11 +#define RT5670_MB1_OC_STKY_DIS (0x0 << 11) +#define RT5670_MB1_OC_STKY_EN (0x1 << 11) +#define RT5670_MB2_OC_STKY_MASK (0x1 << 10) +#define RT5670_MB2_OC_STKY_SFT 10 +#define RT5670_MB2_OC_STKY_DIS (0x0 << 10) +#define RT5670_MB2_OC_STKY_EN (0x1 << 10) +#define RT5670_MB1_OC_P_MASK (0x1 << 7) +#define RT5670_MB1_OC_P_SFT 7 +#define RT5670_MB1_OC_P_NOR (0x0 << 7) +#define RT5670_MB1_OC_P_INV (0x1 << 7) +#define RT5670_MB2_OC_P_MASK (0x1 << 6) +#define RT5670_MB2_OC_P_SFT 6 +#define RT5670_MB2_OC_P_NOR (0x0 << 6) +#define RT5670_MB2_OC_P_INV (0x1 << 6) +#define RT5670_MB1_OC_CLR (0x1 << 3) +#define RT5670_MB1_OC_CLR_SFT 3 +#define RT5670_MB2_OC_CLR (0x1 << 2) +#define RT5670_MB2_OC_CLR_SFT 2 + +/* GPIO Control 1 (0xc0) */ +#define RT5670_GP1_PIN_MASK (0x1 << 15) +#define RT5670_GP1_PIN_SFT 15 +#define RT5670_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5670_GP1_PIN_IRQ (0x1 << 15) +#define RT5670_GP2_PIN_MASK (0x1 << 14) +#define RT5670_GP2_PIN_SFT 14 +#define RT5670_GP2_PIN_GPIO2 (0x0 << 14) +#define RT5670_GP2_PIN_DMIC1_SCL (0x1 << 14) +#define RT5670_GP3_PIN_MASK (0x3 << 12) +#define RT5670_GP3_PIN_SFT 12 +#define RT5670_GP3_PIN_GPIO3 (0x0 << 12) +#define RT5670_GP3_PIN_DMIC1_SDA (0x1 << 12) +#define RT5670_GP3_PIN_IRQ (0x2 << 12) +#define RT5670_GP4_PIN_MASK (0x1 << 11) +#define RT5670_GP4_PIN_SFT 11 +#define RT5670_GP4_PIN_GPIO4 (0x0 << 11) +#define RT5670_GP4_PIN_DMIC2_SDA (0x1 << 11) +#define RT5670_DP_SIG_MASK (0x1 << 10) +#define RT5670_DP_SIG_SFT 10 +#define RT5670_DP_SIG_TEST (0x0 << 10) +#define RT5670_DP_SIG_AP (0x1 << 10) +#define RT5670_GPIO_M_MASK (0x1 << 9) +#define RT5670_GPIO_M_SFT 9 +#define RT5670_GPIO_M_FLT (0x0 << 9) +#define RT5670_GPIO_M_PH (0x1 << 9) +#define RT5670_I2S2_PIN_MASK (0x1 << 8) +#define RT5670_I2S2_PIN_SFT 8 +#define RT5670_I2S2_PIN_I2S (0x0 << 8) +#define RT5670_I2S2_PIN_GPIO (0x1 << 8) +#define RT5670_GP5_PIN_MASK (0x1 << 7) +#define RT5670_GP5_PIN_SFT 7 +#define RT5670_GP5_PIN_GPIO5 (0x0 << 7) +#define RT5670_GP5_PIN_DMIC3_SDA (0x1 << 7) +#define RT5670_GP6_PIN_MASK (0x1 << 6) +#define RT5670_GP6_PIN_SFT 6 +#define RT5670_GP6_PIN_GPIO6 (0x0 << 6) +#define RT5670_GP6_PIN_DMIC1_SDA (0x1 << 6) +#define RT5670_GP7_PIN_MASK (0x3 << 4) +#define RT5670_GP7_PIN_SFT 4 +#define RT5670_GP7_PIN_GPIO7 (0x0 << 4) +#define RT5670_GP7_PIN_DMIC1_SDA (0x1 << 4) +#define RT5670_GP7_PIN_PDM_SCL2 (0x2 << 4) +#define RT5670_GP8_PIN_MASK (0x1 << 3) +#define RT5670_GP8_PIN_SFT 3 +#define RT5670_GP8_PIN_GPIO8 (0x0 << 3) +#define RT5670_GP8_PIN_DMIC2_SDA (0x1 << 3) +#define RT5670_GP9_PIN_MASK (0x1 << 2) +#define RT5670_GP9_PIN_SFT 2 +#define RT5670_GP9_PIN_GPIO9 (0x0 << 2) +#define RT5670_GP9_PIN_DMIC3_SDA (0x1 << 2) +#define RT5670_GP10_PIN_MASK (0x3) +#define RT5670_GP10_PIN_SFT 0 +#define RT5670_GP10_PIN_GPIO9 (0x0) +#define RT5670_GP10_PIN_DMIC3_SDA (0x1) +#define RT5670_GP10_PIN_PDM_ADT2 (0x2) + +/* GPIO Control 2 (0xc1) */ +#define RT5670_GP4_PF_MASK (0x1 << 11) +#define RT5670_GP4_PF_SFT 11 +#define RT5670_GP4_PF_IN (0x0 << 11) +#define RT5670_GP4_PF_OUT (0x1 << 11) +#define RT5670_GP4_OUT_MASK (0x1 << 10) +#define RT5670_GP4_OUT_SFT 10 +#define RT5670_GP4_OUT_LO (0x0 << 10) +#define RT5670_GP4_OUT_HI (0x1 << 10) +#define RT5670_GP4_P_MASK (0x1 << 9) +#define RT5670_GP4_P_SFT 9 +#define RT5670_GP4_P_NOR (0x0 << 9) +#define RT5670_GP4_P_INV (0x1 << 9) +#define RT5670_GP3_PF_MASK (0x1 << 8) +#define RT5670_GP3_PF_SFT 8 +#define RT5670_GP3_PF_IN (0x0 << 8) +#define RT5670_GP3_PF_OUT (0x1 << 8) +#define RT5670_GP3_OUT_MASK (0x1 << 7) +#define RT5670_GP3_OUT_SFT 7 +#define RT5670_GP3_OUT_LO (0x0 << 7) +#define RT5670_GP3_OUT_HI (0x1 << 7) +#define RT5670_GP3_P_MASK (0x1 << 6) +#define RT5670_GP3_P_SFT 6 +#define RT5670_GP3_P_NOR (0x0 << 6) +#define RT5670_GP3_P_INV (0x1 << 6) +#define RT5670_GP2_PF_MASK (0x1 << 5) +#define RT5670_GP2_PF_SFT 5 +#define RT5670_GP2_PF_IN (0x0 << 5) +#define RT5670_GP2_PF_OUT (0x1 << 5) +#define RT5670_GP2_OUT_MASK (0x1 << 4) +#define RT5670_GP2_OUT_SFT 4 +#define RT5670_GP2_OUT_LO (0x0 << 4) +#define RT5670_GP2_OUT_HI (0x1 << 4) +#define RT5670_GP2_P_MASK (0x1 << 3) +#define RT5670_GP2_P_SFT 3 +#define RT5670_GP2_P_NOR (0x0 << 3) +#define RT5670_GP2_P_INV (0x1 << 3) +#define RT5670_GP1_PF_MASK (0x1 << 2) +#define RT5670_GP1_PF_SFT 2 +#define RT5670_GP1_PF_IN (0x0 << 2) +#define RT5670_GP1_PF_OUT (0x1 << 2) +#define RT5670_GP1_OUT_MASK (0x1 << 1) +#define RT5670_GP1_OUT_SFT 1 +#define RT5670_GP1_OUT_LO (0x0 << 1) +#define RT5670_GP1_OUT_HI (0x1 << 1) +#define RT5670_GP1_P_MASK (0x1) +#define RT5670_GP1_P_SFT 0 +#define RT5670_GP1_P_NOR (0x0) +#define RT5670_GP1_P_INV (0x1) + +/* Scramble Function (0xcd) */ +#define RT5670_SCB_KEY_MASK (0xff) +#define RT5670_SCB_KEY_SFT 0 + +/* Scramble Control (0xce) */ +#define RT5670_SCB_SWAP_MASK (0x1 << 15) +#define RT5670_SCB_SWAP_SFT 15 +#define RT5670_SCB_SWAP_DIS (0x0 << 15) +#define RT5670_SCB_SWAP_EN (0x1 << 15) +#define RT5670_SCB_MASK (0x1 << 14) +#define RT5670_SCB_SFT 14 +#define RT5670_SCB_DIS (0x0 << 14) +#define RT5670_SCB_EN (0x1 << 14) + +/* Baseback Control (0xcf) */ +#define RT5670_BB_MASK (0x1 << 15) +#define RT5670_BB_SFT 15 +#define RT5670_BB_DIS (0x0 << 15) +#define RT5670_BB_EN (0x1 << 15) +#define RT5670_BB_CT_MASK (0x7 << 12) +#define RT5670_BB_CT_SFT 12 +#define RT5670_BB_CT_A (0x0 << 12) +#define RT5670_BB_CT_B (0x1 << 12) +#define RT5670_BB_CT_C (0x2 << 12) +#define RT5670_BB_CT_D (0x3 << 12) +#define RT5670_M_BB_L_MASK (0x1 << 9) +#define RT5670_M_BB_L_SFT 9 +#define RT5670_M_BB_R_MASK (0x1 << 8) +#define RT5670_M_BB_R_SFT 8 +#define RT5670_M_BB_HPF_L_MASK (0x1 << 7) +#define RT5670_M_BB_HPF_L_SFT 7 +#define RT5670_M_BB_HPF_R_MASK (0x1 << 6) +#define RT5670_M_BB_HPF_R_SFT 6 +#define RT5670_G_BB_BST_MASK (0x3f) +#define RT5670_G_BB_BST_SFT 0 + +/* MP3 Plus Control 1 (0xd0) */ +#define RT5670_M_MP3_L_MASK (0x1 << 15) +#define RT5670_M_MP3_L_SFT 15 +#define RT5670_M_MP3_R_MASK (0x1 << 14) +#define RT5670_M_MP3_R_SFT 14 +#define RT5670_M_MP3_MASK (0x1 << 13) +#define RT5670_M_MP3_SFT 13 +#define RT5670_M_MP3_DIS (0x0 << 13) +#define RT5670_M_MP3_EN (0x1 << 13) +#define RT5670_EG_MP3_MASK (0x1f << 8) +#define RT5670_EG_MP3_SFT 8 +#define RT5670_MP3_HLP_MASK (0x1 << 7) +#define RT5670_MP3_HLP_SFT 7 +#define RT5670_MP3_HLP_DIS (0x0 << 7) +#define RT5670_MP3_HLP_EN (0x1 << 7) +#define RT5670_M_MP3_ORG_L_MASK (0x1 << 6) +#define RT5670_M_MP3_ORG_L_SFT 6 +#define RT5670_M_MP3_ORG_R_MASK (0x1 << 5) +#define RT5670_M_MP3_ORG_R_SFT 5 + +/* MP3 Plus Control 2 (0xd1) */ +#define RT5670_MP3_WT_MASK (0x1 << 13) +#define RT5670_MP3_WT_SFT 13 +#define RT5670_MP3_WT_1_4 (0x0 << 13) +#define RT5670_MP3_WT_1_2 (0x1 << 13) +#define RT5670_OG_MP3_MASK (0x1f << 8) +#define RT5670_OG_MP3_SFT 8 +#define RT5670_HG_MP3_MASK (0x3f) +#define RT5670_HG_MP3_SFT 0 + +/* 3D HP Control 1 (0xd2) */ +#define RT5670_3D_CF_MASK (0x1 << 15) +#define RT5670_3D_CF_SFT 15 +#define RT5670_3D_CF_DIS (0x0 << 15) +#define RT5670_3D_CF_EN (0x1 << 15) +#define RT5670_3D_HP_MASK (0x1 << 14) +#define RT5670_3D_HP_SFT 14 +#define RT5670_3D_HP_DIS (0x0 << 14) +#define RT5670_3D_HP_EN (0x1 << 14) +#define RT5670_3D_BT_MASK (0x1 << 13) +#define RT5670_3D_BT_SFT 13 +#define RT5670_3D_BT_DIS (0x0 << 13) +#define RT5670_3D_BT_EN (0x1 << 13) +#define RT5670_3D_1F_MIX_MASK (0x3 << 11) +#define RT5670_3D_1F_MIX_SFT 11 +#define RT5670_3D_HP_M_MASK (0x1 << 10) +#define RT5670_3D_HP_M_SFT 10 +#define RT5670_3D_HP_M_SUR (0x0 << 10) +#define RT5670_3D_HP_M_FRO (0x1 << 10) +#define RT5670_M_3D_HRTF_MASK (0x1 << 9) +#define RT5670_M_3D_HRTF_SFT 9 +#define RT5670_M_3D_D2H_MASK (0x1 << 8) +#define RT5670_M_3D_D2H_SFT 8 +#define RT5670_M_3D_D2R_MASK (0x1 << 7) +#define RT5670_M_3D_D2R_SFT 7 +#define RT5670_M_3D_REVB_MASK (0x1 << 6) +#define RT5670_M_3D_REVB_SFT 6 + +/* Adjustable high pass filter control 1 (0xd3) */ +#define RT5670_2ND_HPF_MASK (0x1 << 15) +#define RT5670_2ND_HPF_SFT 15 +#define RT5670_2ND_HPF_DIS (0x0 << 15) +#define RT5670_2ND_HPF_EN (0x1 << 15) +#define RT5670_HPF_CF_L_MASK (0x7 << 12) +#define RT5670_HPF_CF_L_SFT 12 +#define RT5670_1ST_HPF_MASK (0x1 << 11) +#define RT5670_1ST_HPF_SFT 11 +#define RT5670_1ST_HPF_DIS (0x0 << 11) +#define RT5670_1ST_HPF_EN (0x1 << 11) +#define RT5670_HPF_CF_R_MASK (0x7 << 8) +#define RT5670_HPF_CF_R_SFT 8 +#define RT5670_ZD_T_MASK (0x3 << 6) +#define RT5670_ZD_T_SFT 6 +#define RT5670_ZD_F_MASK (0x3 << 4) +#define RT5670_ZD_F_SFT 4 +#define RT5670_ZD_F_IM (0x0 << 4) +#define RT5670_ZD_F_ZC_IM (0x1 << 4) +#define RT5670_ZD_F_ZC_IOD (0x2 << 4) +#define RT5670_ZD_F_UN (0x3 << 4) + +/* HP calibration control and Amp detection (0xd6) */ +#define RT5670_SI_DAC_MASK (0x1 << 11) +#define RT5670_SI_DAC_SFT 11 +#define RT5670_SI_DAC_AUTO (0x0 << 11) +#define RT5670_SI_DAC_TEST (0x1 << 11) +#define RT5670_DC_CAL_M_MASK (0x1 << 10) +#define RT5670_DC_CAL_M_SFT 10 +#define RT5670_DC_CAL_M_CAL (0x0 << 10) +#define RT5670_DC_CAL_M_NOR (0x1 << 10) +#define RT5670_DC_CAL_MASK (0x1 << 9) +#define RT5670_DC_CAL_SFT 9 +#define RT5670_DC_CAL_DIS (0x0 << 9) +#define RT5670_DC_CAL_EN (0x1 << 9) +#define RT5670_HPD_RCV_MASK (0x7 << 6) +#define RT5670_HPD_RCV_SFT 6 +#define RT5670_HPD_PS_MASK (0x1 << 5) +#define RT5670_HPD_PS_SFT 5 +#define RT5670_HPD_PS_DIS (0x0 << 5) +#define RT5670_HPD_PS_EN (0x1 << 5) +#define RT5670_CAL_M_MASK (0x1 << 4) +#define RT5670_CAL_M_SFT 4 +#define RT5670_CAL_M_DEP (0x0 << 4) +#define RT5670_CAL_M_CAL (0x1 << 4) +#define RT5670_CAL_MASK (0x1 << 3) +#define RT5670_CAL_SFT 3 +#define RT5670_CAL_DIS (0x0 << 3) +#define RT5670_CAL_EN (0x1 << 3) +#define RT5670_CAL_TEST_MASK (0x1 << 2) +#define RT5670_CAL_TEST_SFT 2 +#define RT5670_CAL_TEST_DIS (0x0 << 2) +#define RT5670_CAL_TEST_EN (0x1 << 2) +#define RT5670_CAL_P_MASK (0x3) +#define RT5670_CAL_P_SFT 0 +#define RT5670_CAL_P_NONE (0x0) +#define RT5670_CAL_P_CAL (0x1) +#define RT5670_CAL_P_DAC_CAL (0x2) + +/* Soft volume and zero cross control 1 (0xd9) */ +#define RT5670_SV_MASK (0x1 << 15) +#define RT5670_SV_SFT 15 +#define RT5670_SV_DIS (0x0 << 15) +#define RT5670_SV_EN (0x1 << 15) +#define RT5670_SPO_SV_MASK (0x1 << 14) +#define RT5670_SPO_SV_SFT 14 +#define RT5670_SPO_SV_DIS (0x0 << 14) +#define RT5670_SPO_SV_EN (0x1 << 14) +#define RT5670_OUT_SV_MASK (0x1 << 13) +#define RT5670_OUT_SV_SFT 13 +#define RT5670_OUT_SV_DIS (0x0 << 13) +#define RT5670_OUT_SV_EN (0x1 << 13) +#define RT5670_HP_SV_MASK (0x1 << 12) +#define RT5670_HP_SV_SFT 12 +#define RT5670_HP_SV_DIS (0x0 << 12) +#define RT5670_HP_SV_EN (0x1 << 12) +#define RT5670_ZCD_DIG_MASK (0x1 << 11) +#define RT5670_ZCD_DIG_SFT 11 +#define RT5670_ZCD_DIG_DIS (0x0 << 11) +#define RT5670_ZCD_DIG_EN (0x1 << 11) +#define RT5670_ZCD_MASK (0x1 << 10) +#define RT5670_ZCD_SFT 10 +#define RT5670_ZCD_PD (0x0 << 10) +#define RT5670_ZCD_PU (0x1 << 10) +#define RT5670_M_ZCD_MASK (0x3f << 4) +#define RT5670_M_ZCD_SFT 4 +#define RT5670_M_ZCD_RM_L (0x1 << 9) +#define RT5670_M_ZCD_RM_R (0x1 << 8) +#define RT5670_M_ZCD_SM_L (0x1 << 7) +#define RT5670_M_ZCD_SM_R (0x1 << 6) +#define RT5670_M_ZCD_OM_L (0x1 << 5) +#define RT5670_M_ZCD_OM_R (0x1 << 4) +#define RT5670_SV_DLY_MASK (0xf) +#define RT5670_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0xda) */ +#define RT5670_ZCD_HP_MASK (0x1 << 15) +#define RT5670_ZCD_HP_SFT 15 +#define RT5670_ZCD_HP_DIS (0x0 << 15) +#define RT5670_ZCD_HP_EN (0x1 << 15) + + +/* Codec Private Register definition */ +/* 3D Speaker Control (0x63) */ +#define RT5670_3D_SPK_MASK (0x1 << 15) +#define RT5670_3D_SPK_SFT 15 +#define RT5670_3D_SPK_DIS (0x0 << 15) +#define RT5670_3D_SPK_EN (0x1 << 15) +#define RT5670_3D_SPK_M_MASK (0x3 << 13) +#define RT5670_3D_SPK_M_SFT 13 +#define RT5670_3D_SPK_CG_MASK (0x1f << 8) +#define RT5670_3D_SPK_CG_SFT 8 +#define RT5670_3D_SPK_SG_MASK (0x1f) +#define RT5670_3D_SPK_SG_SFT 0 + +/* Wind Noise Detection Control 1 (0x6c) */ +#define RT5670_WND_MASK (0x1 << 15) +#define RT5670_WND_SFT 15 +#define RT5670_WND_DIS (0x0 << 15) +#define RT5670_WND_EN (0x1 << 15) + +/* Wind Noise Detection Control 2 (0x6d) */ +#define RT5670_WND_FC_NW_MASK (0x3f << 10) +#define RT5670_WND_FC_NW_SFT 10 +#define RT5670_WND_FC_WK_MASK (0x3f << 4) +#define RT5670_WND_FC_WK_SFT 4 + +/* Wind Noise Detection Control 3 (0x6e) */ +#define RT5670_HPF_FC_MASK (0x3f << 6) +#define RT5670_HPF_FC_SFT 6 +#define RT5670_WND_FC_ST_MASK (0x3f) +#define RT5670_WND_FC_ST_SFT 0 + +/* Wind Noise Detection Control 4 (0x6f) */ +#define RT5670_WND_TH_LO_MASK (0x3ff) +#define RT5670_WND_TH_LO_SFT 0 + +/* Wind Noise Detection Control 5 (0x70) */ +#define RT5670_WND_TH_HI_MASK (0x3ff) +#define RT5670_WND_TH_HI_SFT 0 + +/* Wind Noise Detection Control 8 (0x73) */ +#define RT5670_WND_WIND_MASK (0x1 << 13) /* Read-Only */ +#define RT5670_WND_WIND_SFT 13 +#define RT5670_WND_STRONG_MASK (0x1 << 12) /* Read-Only */ +#define RT5670_WND_STRONG_SFT 12 +enum { + RT5670_NO_WIND, + RT5670_BREEZE, + RT5670_STORM, +}; + +/* Dipole Speaker Interface (0x75) */ +#define RT5670_DP_ATT_MASK (0x3 << 14) +#define RT5670_DP_ATT_SFT 14 +#define RT5670_DP_SPK_MASK (0x1 << 10) +#define RT5670_DP_SPK_SFT 10 +#define RT5670_DP_SPK_DIS (0x0 << 10) +#define RT5670_DP_SPK_EN (0x1 << 10) + +/* EQ Pre Volume Control (0xb3) */ +#define RT5670_EQ_PRE_VOL_MASK (0xffff) +#define RT5670_EQ_PRE_VOL_SFT 0 + +/* EQ Post Volume Control (0xb4) */ +#define RT5670_EQ_PST_VOL_MASK (0xffff) +#define RT5670_EQ_PST_VOL_SFT 0 + +/* Jack Detect Control 3 (0xf8) */ +#define RT5670_CMP_MIC_IN_DET_MASK (0x7 << 12) +#define RT5670_JD_CBJ_EN (0x1 << 7) +#define RT5670_JD_CBJ_POL (0x1 << 6) +#define RT5670_JD_TRI_CBJ_SEL_MASK (0x7 << 3) +#define RT5670_JD_TRI_CBJ_SEL_SFT (3) +#define RT5670_JD_CBJ_GPIO_JD1 (0x0 << 3) +#define RT5670_JD_CBJ_JD1_1 (0x1 << 3) +#define RT5670_JD_CBJ_JD1_2 (0x2 << 3) +#define RT5670_JD_CBJ_JD2 (0x3 << 3) +#define RT5670_JD_CBJ_JD3 (0x4 << 3) +#define RT5670_JD_CBJ_GPIO_JD2 (0x5 << 3) +#define RT5670_JD_CBJ_MX0B_12 (0x6 << 3) +#define RT5670_JD_TRI_HPO_SEL_MASK (0x7 << 3) +#define RT5670_JD_TRI_HPO_SEL_SFT (0) +#define RT5670_JD_HPO_GPIO_JD1 (0x0) +#define RT5670_JD_HPO_JD1_1 (0x1) +#define RT5670_JD_HPO_JD1_2 (0x2) +#define RT5670_JD_HPO_JD2 (0x3) +#define RT5670_JD_HPO_JD3 (0x4) +#define RT5670_JD_HPO_GPIO_JD2 (0x5) +#define RT5670_JD_HPO_MX0B_12 (0x6) + +/* Digital Misc Control (0xfa) */ +#define RT5670_RST_DSP (0x1 << 13) +#define RT5670_IF1_ADC1_IN1_SEL (0x1 << 12) +#define RT5670_IF1_ADC1_IN1_SFT 12 +#define RT5670_IF1_ADC1_IN2_SEL (0x1 << 11) +#define RT5670_IF1_ADC1_IN2_SFT 11 +#define RT5670_IF1_ADC2_IN1_SEL (0x1 << 10) +#define RT5670_IF1_ADC2_IN1_SFT 10 + +/* General Control2 (0xfb) */ +#define RT5670_RXDC_SRC_MASK (0x1 << 7) +#define RT5670_RXDC_SRC_STO (0x0 << 7) +#define RT5670_RXDC_SRC_MONO (0x1 << 7) +#define RT5670_RXDC_SRC_SFT (7) +#define RT5670_RXDP2_SEL_MASK (0x1 << 3) +#define RT5670_RXDP2_SEL_IF2 (0x0 << 3) +#define RT5670_RXDP2_SEL_ADC (0x1 << 3) +#define RT5670_RXDP2_SEL_SFT (3) + +/* System Clock Source */ +enum { + RT5670_SCLK_S_MCLK, + RT5670_SCLK_S_PLL1, + RT5670_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { + RT5670_PLL1_S_MCLK, + RT5670_PLL1_S_BCLK1, + RT5670_PLL1_S_BCLK2, + RT5670_PLL1_S_BCLK3, + RT5670_PLL1_S_BCLK4, +}; + +enum { + RT5670_AIF1, + RT5670_AIF2, + RT5670_AIF3, + RT5670_AIF4, + RT5670_AIFS, +}; + +enum { + RT5670_DMIC_DATA_GPIO6, + RT5670_DMIC_DATA_IN2P, + RT5670_DMIC_DATA_GPIO7, +}; + +enum { + RT5670_DMIC_DATA_GPIO8, + RT5670_DMIC_DATA_IN3N, +}; + +enum { + RT5670_DMIC_DATA_GPIO9, + RT5670_DMIC_DATA_GPIO10, + RT5670_DMIC_DATA_GPIO5, +}; + +struct rt5670_priv { + struct snd_soc_codec *codec; + struct rt5670_platform_data pdata; + struct regmap *regmap; + + int sysclk; + int sysclk_src; + int lrck[RT5670_AIFS]; + int bclk[RT5670_AIFS]; + int master[RT5670_AIFS]; + + int pll_src; + int pll_in; + int pll_out; + + int dsp_sw; /* expected parameter setting */ + int dsp_rate; + int jack_type; +}; + +#endif /* __RT5670_H__ */ diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 833231e27340..67f14556462f 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -27,6 +27,7 @@ #include <sound/initval.h> #include <sound/tlv.h> +#include "rl6231.h" #include "rt5677.h" #define RT5677_DEVICE_ID 0x6327 @@ -604,19 +605,19 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { adc_vol_tlv), /* ADC Boost Volume Control */ - SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5677_STO1_2_ADC_BST, + SOC_DOUBLE_TLV("STO1 ADC Boost Volume", RT5677_STO1_2_ADC_BST, RT5677_STO1_ADC_L_BST_SFT, RT5677_STO1_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), - SOC_DOUBLE_TLV("STO2 ADC Boost Gain", RT5677_STO1_2_ADC_BST, + SOC_DOUBLE_TLV("STO2 ADC Boost Volume", RT5677_STO1_2_ADC_BST, RT5677_STO2_ADC_L_BST_SFT, RT5677_STO2_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), - SOC_DOUBLE_TLV("STO3 ADC Boost Gain", RT5677_STO3_4_ADC_BST, + SOC_DOUBLE_TLV("STO3 ADC Boost Volume", RT5677_STO3_4_ADC_BST, RT5677_STO3_ADC_L_BST_SFT, RT5677_STO3_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), - SOC_DOUBLE_TLV("STO4 ADC Boost Gain", RT5677_STO3_4_ADC_BST, + SOC_DOUBLE_TLV("STO4 ADC Boost Volume", RT5677_STO3_4_ADC_BST, RT5677_STO4_ADC_L_BST_SFT, RT5677_STO4_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), - SOC_DOUBLE_TLV("Mono ADC Boost Gain", RT5677_ADC_BST_CTRL2, + SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2, RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), }; @@ -636,21 +637,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = w->codec; struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); - int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL, i; - int rate, red, bound, temp; - - rate = rt5677->sysclk; - red = 3000000 * 12; - for (i = 0; i < ARRAY_SIZE(div); i++) { - bound = div[i] * 3000000; - if (rate > bound) - continue; - temp = bound - rate; - if (temp < red) { - red = temp; - idx = i; - } - } + int idx = rl6231_calc_dmic_clk(rt5677->sysclk); if (idx < 0) dev_err(codec->dev, "Failed to set DMIC clock\n"); @@ -951,7 +938,7 @@ static const struct snd_kcontrol_new rt5677_ob_7_mix[] = { /* Mux */ -/* DAC1 L/R source */ /* MX-29 [10:8] */ +/* DAC1 L/R Source */ /* MX-29 [10:8] */ static const char * const rt5677_dac1_src[] = { "IF1 DAC 01", "IF2 DAC 01", "IF3 DAC LR", "IF4 DAC LR", "SLB DAC 01", "OB 01" @@ -962,9 +949,9 @@ static SOC_ENUM_SINGLE_DECL( RT5677_DAC1_L_SEL_SFT, rt5677_dac1_src); static const struct snd_kcontrol_new rt5677_dac1_mux = - SOC_DAPM_ENUM("DAC1 source", rt5677_dac1_enum); + SOC_DAPM_ENUM("DAC1 Source", rt5677_dac1_enum); -/* ADDA1 L/R source */ /* MX-29 [1:0] */ +/* ADDA1 L/R Source */ /* MX-29 [1:0] */ static const char * const rt5677_adda1_src[] = { "STO1 ADC MIX", "STO2 ADC MIX", "OB 67", }; @@ -974,10 +961,10 @@ static SOC_ENUM_SINGLE_DECL( RT5677_ADDA1_SEL_SFT, rt5677_adda1_src); static const struct snd_kcontrol_new rt5677_adda1_mux = - SOC_DAPM_ENUM("ADDA1 source", rt5677_adda1_enum); + SOC_DAPM_ENUM("ADDA1 Source", rt5677_adda1_enum); -/*DAC2 L/R source*/ /* MX-1B [6:4] [2:0] */ +/*DAC2 L/R Source*/ /* MX-1B [6:4] [2:0] */ static const char * const rt5677_dac2l_src[] = { "IF1 DAC 2", "IF2 DAC 2", "IF3 DAC L", "IF4 DAC L", "SLB DAC 2", "OB 2", @@ -988,7 +975,7 @@ static SOC_ENUM_SINGLE_DECL( RT5677_SEL_DAC2_L_SRC_SFT, rt5677_dac2l_src); static const struct snd_kcontrol_new rt5677_dac2_l_mux = - SOC_DAPM_ENUM("DAC2 L source", rt5677_dac2l_enum); + SOC_DAPM_ENUM("DAC2 L Source", rt5677_dac2l_enum); static const char * const rt5677_dac2r_src[] = { "IF1 DAC 3", "IF2 DAC 3", "IF3 DAC R", "IF4 DAC R", "SLB DAC 3", @@ -1000,9 +987,9 @@ static SOC_ENUM_SINGLE_DECL( RT5677_SEL_DAC2_R_SRC_SFT, rt5677_dac2r_src); static const struct snd_kcontrol_new rt5677_dac2_r_mux = - SOC_DAPM_ENUM("DAC2 R source", rt5677_dac2r_enum); + SOC_DAPM_ENUM("DAC2 R Source", rt5677_dac2r_enum); -/*DAC3 L/R source*/ /* MX-16 [6:4] [2:0] */ +/*DAC3 L/R Source*/ /* MX-16 [6:4] [2:0] */ static const char * const rt5677_dac3l_src[] = { "IF1 DAC 4", "IF2 DAC 4", "IF3 DAC L", "IF4 DAC L", "SLB DAC 4", "OB 4" @@ -1013,7 +1000,7 @@ static SOC_ENUM_SINGLE_DECL( RT5677_SEL_DAC3_L_SRC_SFT, rt5677_dac3l_src); static const struct snd_kcontrol_new rt5677_dac3_l_mux = - SOC_DAPM_ENUM("DAC3 L source", rt5677_dac3l_enum); + SOC_DAPM_ENUM("DAC3 L Source", rt5677_dac3l_enum); static const char * const rt5677_dac3r_src[] = { "IF1 DAC 5", "IF2 DAC 5", "IF3 DAC R", "IF4 DAC R", @@ -1025,9 +1012,9 @@ static SOC_ENUM_SINGLE_DECL( RT5677_SEL_DAC3_R_SRC_SFT, rt5677_dac3r_src); static const struct snd_kcontrol_new rt5677_dac3_r_mux = - SOC_DAPM_ENUM("DAC3 R source", rt5677_dac3r_enum); + SOC_DAPM_ENUM("DAC3 R Source", rt5677_dac3r_enum); -/*DAC4 L/R source*/ /* MX-16 [14:12] [10:8] */ +/*DAC4 L/R Source*/ /* MX-16 [14:12] [10:8] */ static const char * const rt5677_dac4l_src[] = { "IF1 DAC 6", "IF2 DAC 6", "IF3 DAC L", "IF4 DAC L", "SLB DAC 6", "OB 6" @@ -1038,7 +1025,7 @@ static SOC_ENUM_SINGLE_DECL( RT5677_SEL_DAC4_L_SRC_SFT, rt5677_dac4l_src); static const struct snd_kcontrol_new rt5677_dac4_l_mux = - SOC_DAPM_ENUM("DAC4 L source", rt5677_dac4l_enum); + SOC_DAPM_ENUM("DAC4 L Source", rt5677_dac4l_enum); static const char * const rt5677_dac4r_src[] = { "IF1 DAC 7", "IF2 DAC 7", "IF3 DAC R", "IF4 DAC R", @@ -1050,7 +1037,7 @@ static SOC_ENUM_SINGLE_DECL( RT5677_SEL_DAC4_R_SRC_SFT, rt5677_dac4r_src); static const struct snd_kcontrol_new rt5677_dac4_r_mux = - SOC_DAPM_ENUM("DAC4 R source", rt5677_dac4r_enum); + SOC_DAPM_ENUM("DAC4 R Source", rt5677_dac4r_enum); /* In/OutBound Source Pass SRC */ /* MX-A5 [3] [4] [0] [1] [2] */ static const char * const rt5677_iob_bypass_src[] = { @@ -1062,35 +1049,35 @@ static SOC_ENUM_SINGLE_DECL( RT5677_SEL_SRC_OB01_SFT, rt5677_iob_bypass_src); static const struct snd_kcontrol_new rt5677_ob01_bypass_src_mux = - SOC_DAPM_ENUM("OB01 Bypass source", rt5677_ob01_bypass_src_enum); + SOC_DAPM_ENUM("OB01 Bypass Source", rt5677_ob01_bypass_src_enum); static SOC_ENUM_SINGLE_DECL( rt5677_ob23_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL, RT5677_SEL_SRC_OB23_SFT, rt5677_iob_bypass_src); static const struct snd_kcontrol_new rt5677_ob23_bypass_src_mux = - SOC_DAPM_ENUM("OB23 Bypass source", rt5677_ob23_bypass_src_enum); + SOC_DAPM_ENUM("OB23 Bypass Source", rt5677_ob23_bypass_src_enum); static SOC_ENUM_SINGLE_DECL( rt5677_ib01_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL, RT5677_SEL_SRC_IB01_SFT, rt5677_iob_bypass_src); static const struct snd_kcontrol_new rt5677_ib01_bypass_src_mux = - SOC_DAPM_ENUM("IB01 Bypass source", rt5677_ib01_bypass_src_enum); + SOC_DAPM_ENUM("IB01 Bypass Source", rt5677_ib01_bypass_src_enum); static SOC_ENUM_SINGLE_DECL( rt5677_ib23_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL, RT5677_SEL_SRC_IB23_SFT, rt5677_iob_bypass_src); static const struct snd_kcontrol_new rt5677_ib23_bypass_src_mux = - SOC_DAPM_ENUM("IB23 Bypass source", rt5677_ib23_bypass_src_enum); + SOC_DAPM_ENUM("IB23 Bypass Source", rt5677_ib23_bypass_src_enum); static SOC_ENUM_SINGLE_DECL( rt5677_ib45_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL, RT5677_SEL_SRC_IB45_SFT, rt5677_iob_bypass_src); static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux = - SOC_DAPM_ENUM("IB45 Bypass source", rt5677_ib45_bypass_src_enum); + SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum); /* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */ static const char * const rt5677_stereo_adc2_src[] = { @@ -1102,21 +1089,21 @@ static SOC_ENUM_SINGLE_DECL( RT5677_SEL_STO1_ADC2_SFT, rt5677_stereo_adc2_src); static const struct snd_kcontrol_new rt5677_sto1_adc2_mux = - SOC_DAPM_ENUM("Stereo1 ADC2 source", rt5677_stereo1_adc2_enum); + SOC_DAPM_ENUM("Stereo1 ADC2 Source", rt5677_stereo1_adc2_enum); static SOC_ENUM_SINGLE_DECL( rt5677_stereo2_adc2_enum, RT5677_STO2_ADC_MIXER, RT5677_SEL_STO2_ADC2_SFT, rt5677_stereo_adc2_src); static const struct snd_kcontrol_new rt5677_sto2_adc2_mux = - SOC_DAPM_ENUM("Stereo2 ADC2 source", rt5677_stereo2_adc2_enum); + SOC_DAPM_ENUM("Stereo2 ADC2 Source", rt5677_stereo2_adc2_enum); static SOC_ENUM_SINGLE_DECL( rt5677_stereo3_adc2_enum, RT5677_STO3_ADC_MIXER, RT5677_SEL_STO3_ADC2_SFT, rt5677_stereo_adc2_src); static const struct snd_kcontrol_new rt5677_sto3_adc2_mux = - SOC_DAPM_ENUM("Stereo3 ADC2 source", rt5677_stereo3_adc2_enum); + SOC_DAPM_ENUM("Stereo3 ADC2 Source", rt5677_stereo3_adc2_enum); /* DMIC Source */ /* MX-28 [9:8][1:0] MX-27 MX-26 MX-25 MX-24 [9:8] */ static const char * const rt5677_dmic_src[] = { @@ -1128,44 +1115,44 @@ static SOC_ENUM_SINGLE_DECL( RT5677_SEL_MONO_DMIC_L_SFT, rt5677_dmic_src); static const struct snd_kcontrol_new rt5677_mono_dmic_l_mux = - SOC_DAPM_ENUM("Mono DMIC L source", rt5677_mono_dmic_l_enum); + SOC_DAPM_ENUM("Mono DMIC L Source", rt5677_mono_dmic_l_enum); static SOC_ENUM_SINGLE_DECL( rt5677_mono_dmic_r_enum, RT5677_MONO_ADC_MIXER, RT5677_SEL_MONO_DMIC_R_SFT, rt5677_dmic_s |