diff options
author | Michal Marek <mmarek@suse.cz> | 2011-06-07 15:37:51 +0200 |
---|---|---|
committer | Michal Marek <mmarek@suse.cz> | 2011-06-07 15:37:51 +0200 |
commit | 2e483528cebad089d0bb3f9aebb0ada22d968ffa (patch) | |
tree | d701405826b271e819a9a8500838cebd37b1364a /sound | |
parent | 163d3fe6a2357aba7b18b938d6ae6ce9570324e4 (diff) | |
parent | 55922c9d1b84b89cb946c777fddccb3247e7df2c (diff) | |
download | blackbird-op-linux-2e483528cebad089d0bb3f9aebb0ada22d968ffa.tar.gz blackbird-op-linux-2e483528cebad089d0bb3f9aebb0ada22d968ffa.zip |
Merge commit 'v3.0-rc1' into kbuild/kbuild
Diffstat (limited to 'sound')
251 files changed, 24919 insertions, 10640 deletions
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index 8808b82311b1..76e0d5695075 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -140,6 +140,9 @@ int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) if (!prtd || !prtd->params) return 0; + if (prtd->dma_ch == -1) + return -EINVAL; + DCSR(prtd->dma_ch) &= ~DCSR_RUN; DCSR(prtd->dma_ch) = 0; DCMD(prtd->dma_ch) = 0; diff --git a/sound/core/control.c b/sound/core/control.c index a08ad57c49b6..f8c5be464510 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -366,6 +366,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) EXPORT_SYMBOL(snd_ctl_add); /** + * snd_ctl_replace - replace the control instance of the card + * @card: the card instance + * @kcontrol: the control instance to replace + * @add_on_replace: add the control if not already added + * + * Replaces the given control. If the given control does not exist + * and the add_on_replace flag is set, the control is added. If the + * control exists, it is destroyed first. + * + * Returns zero if successful, or a negative error code on failure. + * + * It frees automatically the control which cannot be added or replaced. + */ +int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, + bool add_on_replace) +{ + struct snd_ctl_elem_id id; + unsigned int idx; + struct snd_kcontrol *old; + int ret; + + if (!kcontrol) + return -EINVAL; + if (snd_BUG_ON(!card || !kcontrol->info)) { + ret = -EINVAL; + goto error; + } + id = kcontrol->id; + down_write(&card->controls_rwsem); + old = snd_ctl_find_id(card, &id); + if (!old) { + if (add_on_replace) + goto add; + up_write(&card->controls_rwsem); + ret = -EINVAL; + goto error; + } + ret = snd_ctl_remove(card, old); + if (ret < 0) { + up_write(&card->controls_rwsem); + goto error; + } +add: + if (snd_ctl_find_hole(card, kcontrol->count) < 0) { + up_write(&card->controls_rwsem); + ret = -ENOMEM; + goto error; + } + list_add_tail(&kcontrol->list, &card->controls); + card->controls_count += kcontrol->count; + kcontrol->id.numid = card->last_numid + 1; + card->last_numid += kcontrol->count; + up_write(&card->controls_rwsem); + for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); + return 0; + +error: + snd_ctl_free_one(kcontrol); + return ret; +} +EXPORT_SYMBOL(snd_ctl_replace); + +/** * snd_ctl_remove - remove the control from the card and release it * @card: the card instance * @kcontrol: the control instance to remove @@ -640,13 +704,12 @@ static int snd_ctl_elem_list(struct snd_card *card, struct snd_ctl_elem_list list; struct snd_kcontrol *kctl; struct snd_ctl_elem_id *dst, *id; - unsigned int offset, space, first, jidx; + unsigned int offset, space, jidx; if (copy_from_user(&list, _list, sizeof(list))) return -EFAULT; offset = list.offset; space = list.space; - first = 0; /* try limit maximum space */ if (space > 16384) return -ENOMEM; diff --git a/sound/core/init.c b/sound/core/init.c index a0080aa45ae9..2c041bb36ab3 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -342,7 +342,6 @@ static const struct file_operations snd_shutdown_f_ops = int snd_card_disconnect(struct snd_card *card) { struct snd_monitor_file *mfile; - struct file *file; int err; if (!card) @@ -366,8 +365,6 @@ int snd_card_disconnect(struct snd_card *card) spin_lock(&card->files_lock); list_for_each_entry(mfile, &card->files_list, list) { - file = mfile->file; - /* it's critical part, use endless loop */ /* we have no room to fail */ mfile->disconnected_f_op = mfile->file->f_op; @@ -514,7 +511,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) id = card->id; if (*id == '\0') - strcpy(id, "default"); + strcpy(id, "Default"); while (1) { if (loops-- == 0) { diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c index 13b3f6f49fae..2045697f449d 100644 --- a/sound/core/oss/linear.c +++ b/sound/core/oss/linear.c @@ -90,11 +90,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin, struct snd_pcm_plugin_channel *dst_channels, snd_pcm_uframes_t frames) { - struct linear_priv *data; - if (snd_BUG_ON(!plugin || !src_channels || !dst_channels)) return -ENXIO; - data = (struct linear_priv *)plugin->extra_data; if (frames == 0) return 0; #ifdef CONFIG_SND_DEBUG diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a82e3756a72d..f1341308beda 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -189,6 +189,7 @@ static void xrun(struct snd_pcm_substream *substream) #define XRUN_LOG_CNT 10 struct hwptr_log_entry { + unsigned int in_interrupt; unsigned long jiffies; snd_pcm_uframes_t pos; snd_pcm_uframes_t period_size; @@ -204,7 +205,7 @@ struct snd_pcm_hwptr_log { }; static void xrun_log(struct snd_pcm_substream *substream, - snd_pcm_uframes_t pos) + snd_pcm_uframes_t pos, int in_interrupt) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hwptr_log *log = runtime->hwptr_log; @@ -220,6 +221,7 @@ static void xrun_log(struct snd_pcm_substream *substream, return; } entry = &log->entries[log->idx]; + entry->in_interrupt = in_interrupt; entry->jiffies = jiffies; entry->pos = pos; entry->period_size = runtime->period_size; @@ -246,9 +248,11 @@ static void xrun_log_show(struct snd_pcm_substream *substream) entry = &log->entries[idx]; if (entry->period_size == 0) break; - snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, " + snd_printd("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, " "hwptr=%ld/%ld\n", - name, entry->jiffies, (unsigned long)entry->pos, + name, entry->in_interrupt ? "[Q] " : "", + entry->jiffies, + (unsigned long)entry->pos, (unsigned long)entry->period_size, (unsigned long)entry->buffer_size, (unsigned long)entry->old_hw_ptr, @@ -262,7 +266,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream) #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ #define hw_ptr_error(substream, fmt, args...) do { } while (0) -#define xrun_log(substream, pos) do { } while (0) +#define xrun_log(substream, pos, in_interrupt) do { } while (0) #define xrun_log_show(substream) do { } while (0) #endif @@ -326,7 +330,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } pos -= pos % runtime->min_align; if (xrun_debug(substream, XRUN_DEBUG_LOG)) - xrun_log(substream, pos); + xrun_log(substream, pos, in_interrupt); hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; if (in_interrupt) { @@ -375,6 +379,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } if (runtime->no_period_wakeup) { + snd_pcm_sframes_t xrun_threshold; /* * Without regular period interrupts, we have to check * the elapsed time to detect xruns. @@ -383,7 +388,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (jdelta < runtime->hw_ptr_buffer_jiffies / 2) goto no_delta_check; hdelta = jdelta - delta * HZ / runtime->rate; - while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) { + xrun_threshold = runtime->hw_ptr_buffer_jiffies / 2 + 1; + while (hdelta > xrun_threshold) { delta += runtime->buffer_size; hw_base += runtime->buffer_size; if (hw_base >= runtime->boundary) @@ -1750,8 +1756,18 @@ static int wait_for_avail(struct snd_pcm_substream *substream, wait_queue_t wait; int err = 0; snd_pcm_uframes_t avail = 0; - long tout; - + long wait_time, tout; + + if (runtime->no_period_wakeup) + wait_time = MAX_SCHEDULE_TIMEOUT; + else { + wait_time = 10; + if (runtime->rate) { + long t = runtime->period_size * 2 / runtime->rate; + wait_time = max(t, wait_time); + } + wait_time = msecs_to_jiffies(wait_time * 1000); + } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->tsleep, &wait); for (;;) { @@ -1759,9 +1775,8 @@ static int wait_for_avail(struct snd_pcm_substream *substream, err = -ERESTARTSYS; break; } - set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); - tout = schedule_timeout(msecs_to_jiffies(10000)); + tout = schedule_timeout_interruptible(wait_time); snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_SUSPENDED: diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 917e4055ee30..150cb7edffee 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -253,7 +253,7 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type * @substream: the pcm substream instance * @type: DMA type (SNDRV_DMA_TYPE_*) - * @data: DMA type dependant data + * @data: DMA type dependent data * @size: the requested pre-allocation size in bytes * @max: the max. allowed pre-allocation size * @@ -278,10 +278,10 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); /** - * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams) + * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continuous memory type (all substreams) * @pcm: the pcm instance * @type: DMA type (SNDRV_DMA_TYPE_*) - * @data: DMA type dependant data + * @data: DMA type dependent data * @size: the requested pre-allocation size in bytes * @max: the max. allowed pre-allocation size * diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index fe5c8036beba..1c6be91dfb98 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -460,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, PM_QOS_CPU_DMA_LATENCY, usecs); return 0; _error: - /* hardware might be unuseable from this time, + /* hardware might be unusable from this time, so we force application to retry to set the correct hardware parameter settings */ runtime->status->state = SNDRV_PCM_STATE_OPEN; @@ -1481,11 +1481,20 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, break; /* all drained */ init_waitqueue_entry(&wait, current); add_wait_queue(&to_check->sleep, &wait); - set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); up_read(&snd_pcm_link_rwsem); snd_power_unlock(card); - tout = schedule_timeout(10 * HZ); + if (runtime->no_period_wakeup) + tout = MAX_SCHEDULE_TIMEOUT; + else { + tout = 10; + if (runtime->rate) { + long t = runtime->period_size * 2 / runtime->rate; + tout = max(t, tout); + } + tout = msecs_to_jiffies(tout * 1000); + } + tout = schedule_timeout_interruptible(tout); snd_power_lock(card); down_read(&snd_pcm_link_rwsem); snd_pcm_stream_lock_irq(substream); @@ -1518,13 +1527,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, static int snd_pcm_drop(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; - struct snd_card *card; int result = 0; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - card = substream->pcm->card; if (runtime->status->state == SNDRV_PCM_STATE_OPEN || runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED || @@ -2056,7 +2063,6 @@ static int snd_pcm_open_file(struct file *file, { struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream; - struct snd_pcm_str *str; int err; if (rpcm_file) @@ -2073,7 +2079,6 @@ static int snd_pcm_open_file(struct file *file, } pcm_file->substream = substream; if (substream->ref_count == 1) { - str = substream->pstr; substream->file = pcm_file; substream->pcm_release = pcm_release_private; } @@ -3015,11 +3020,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_status = static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) { - struct snd_pcm_runtime *runtime; long size; if (!(area->vm_flags & VM_READ)) return -EINVAL; - runtime = substream->runtime; size = area->vm_end - area->vm_start; if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))) return -EINVAL; @@ -3054,11 +3057,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_control = static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) { - struct snd_pcm_runtime *runtime; long size; if (!(area->vm_flags & VM_READ)) return -EINVAL; - runtime = substream->runtime; size = area->vm_end - area->vm_start; if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))) return -EINVAL; diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index f3bdc54b429a..1d7d90ca455e 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -50,7 +50,7 @@ option snd-seq-dummy ports=4 - The modle option "duplex=1" enables duplex operation to the port. + The model option "duplex=1" enables duplex operation to the port. In duplex mode, a pair of ports are created instead of single port, and events are tunneled between pair-ports. For example, input to port A is sent to output port of another port B and vice versa. diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index e7a8e9e4edb2..f9077361c119 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -467,13 +467,11 @@ int snd_seq_queue_timer_open(int queueid) int snd_seq_queue_timer_close(int queueid) { struct snd_seq_queue *queue; - struct snd_seq_timer *tmr; int result = 0; queue = queueptr(queueid); if (queue == NULL) return -EINVAL; - tmr = queue->timer; snd_seq_timer_close(queue); queuefree(queue); return result; diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index a89948ae9e8d..a39d3d8c2f9c 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -233,7 +233,7 @@ static void slave_free(struct snd_kcontrol *kcontrol) * Add a slave control to the group with the given master control * * All slaves must be the same type (returning the same information - * via info callback). The fucntion doesn't check it, so it's your + * via info callback). The function doesn't check it, so it's your * responsibility. * * Also, some additional limitations: diff --git a/sound/drivers/pcm-indirect2.c b/sound/drivers/pcm-indirect2.c index 3c93c23e4883..e73fafd761b3 100644 --- a/sound/drivers/pcm-indirect2.c +++ b/sound/drivers/pcm-indirect2.c @@ -264,7 +264,7 @@ snd_pcm_indirect2_playback_transfer(struct snd_pcm_substream *substream, if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) diff += runtime->boundary; /* number of bytes "added" by ALSA increases the number of - * bytes which are ready to "be transfered to HW"/"played" + * bytes which are ready to "be transferred to HW"/"played" * Then, set rec->appl_ptr to not count bytes twice next time. */ rec->sw_ready += (int)frames_to_bytes(runtime, diff); @@ -330,7 +330,7 @@ snd_pcm_indirect2_playback_transfer(struct snd_pcm_substream *substream, /* copy bytes from intermediate buffer position sw_data to the * HW and return number of bytes actually written * Furthermore, set hw_ready to 0, if the fifo isn't empty - * now => more could be transfered to fifo + * now => more could be transferred to fifo */ bytes = copy(substream, rec, bytes); rec->bytes2hw += bytes; diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 35a2f71a6af5..5e897b236cec 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -1189,7 +1189,7 @@ void vx_pcm_update_intr(struct vx_core *chip, unsigned int events) /* - * vx_init_audio_io - check the availabe audio i/o and allocate pipe arrays + * vx_init_audio_io - check the available audio i/o and allocate pipe arrays */ static int vx_init_audio_io(struct vx_core *chip) { diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index e486f48660fb..26071489970b 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -22,4 +22,15 @@ config SND_FIREWIRE_SPEAKERS To compile this driver as a module, choose M here: the module will be called snd-firewire-speakers. +config SND_ISIGHT + tristate "Apple iSight microphone" + select SND_PCM + select SND_FIREWIRE_LIB + help + Say Y here to include support for the front and rear microphones + of the Apple iSight web camera. + + To compile this driver as a module, choose M here: the module + will be called snd-isight. + endif # SND_FIREWIRE diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index e5b1634d9ad4..d71ed8935f76 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -1,6 +1,8 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp.o snd-firewire-speakers-objs := speakers.o +snd-isight-objs := isight.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o +obj-$(CONFIG_SND_ISIGHT) += snd-isight.o diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index b18140ff2b93..87657dd7714c 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -396,6 +396,7 @@ static void out_packet_callback(struct fw_iso_context *context, u32 cycle, for (i = 0; i < packets; ++i) queue_out_packet(s, ++cycle); + fw_iso_context_queue_flush(s->context); } static int queue_initial_skip_packets(struct amdtp_out_stream *s) diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c index 4a37f3a6fab9..14cacbc655dd 100644 --- a/sound/firewire/cmp.c +++ b/sound/firewire/cmp.c @@ -49,10 +49,9 @@ static int pcr_modify(struct cmp_connection *c, enum bus_reset_handling bus_reset_handling) { struct fw_device *device = fw_parent_device(c->resources.unit); - __be32 *buffer = c->resources.buffer; int generation = c->resources.generation; int rcode, errors = 0; - __be32 old_arg; + __be32 old_arg, buffer[2]; int err; buffer[0] = c->last_pcr_value; diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c new file mode 100644 index 000000000000..86ee16ca365e --- /dev/null +++ b/sound/firewire/isight.c @@ -0,0 +1,755 @@ +/* + * Apple iSight audio driver + * + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include <asm/byteorder.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/firewire.h> +#include <linux/firewire-constants.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/mutex.h> +#include <linux/string.h> +#include <sound/control.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/tlv.h> +#include "lib.h" +#include "iso-resources.h" +#include "packets-buffer.h" + +#define OUI_APPLE 0x000a27 +#define MODEL_APPLE_ISIGHT 0x000008 +#define SW_ISIGHT_AUDIO 0x000010 + +#define REG_AUDIO_ENABLE 0x000 +#define AUDIO_ENABLE 0x80000000 +#define REG_DEF_AUDIO_GAIN 0x204 +#define REG_GAIN_RAW_START 0x210 +#define REG_GAIN_RAW_END 0x214 +#define REG_GAIN_DB_START 0x218 +#define REG_GAIN_DB_END 0x21c +#define REG_SAMPLE_RATE_INQUIRY 0x280 +#define REG_ISO_TX_CONFIG 0x300 +#define SPEED_SHIFT 16 +#define REG_SAMPLE_RATE 0x400 +#define RATE_48000 0x80000000 +#define REG_GAIN 0x500 +#define REG_MUTE 0x504 + +#define MAX_FRAMES_PER_PACKET 475 + +#define QUEUE_LENGTH 20 + +struct isight { + struct snd_card *card; + struct fw_unit *unit; + struct fw_device *device; + u64 audio_base; + struct fw_address_handler iris_handler; + struct snd_pcm_substream *pcm; + struct mutex mutex; + struct iso_packets_buffer buffer; + struct fw_iso_resources resources; + struct fw_iso_context *context; + bool pcm_active; + bool pcm_running; + bool first_packet; + int packet_index; + u32 total_samples; + unsigned int buffer_pointer; + unsigned int period_counter; + s32 gain_min, gain_max; + unsigned int gain_tlv[4]; +}; + +struct audio_payload { + __be32 sample_count; + __be32 signature; + __be32 sample_total; + __be32 reserved; + __be16 samples[2 * MAX_FRAMES_PER_PACKET]; +}; + +MODULE_DESCRIPTION("iSight audio driver"); +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +MODULE_LICENSE("GPL v2"); + +static struct fw_iso_packet audio_packet = { + .payload_length = sizeof(struct audio_payload), + .interrupt = 1, + .header_length = 4, +}; + +static void isight_update_pointers(struct isight *isight, unsigned int count) +{ + struct snd_pcm_runtime *runtime = isight->pcm->runtime; + unsigned int ptr; + + smp_wmb(); /* update buffer data before buffer pointer */ + + ptr = isight->buffer_pointer; + ptr += count; + if (ptr >= runtime->buffer_size) + ptr -= runtime->buffer_size; + ACCESS_ONCE(isight->buffer_pointer) = ptr; + + isight->period_counter += count; + if (isight->period_counter >= runtime->period_size) { + isight->period_counter -= runtime->period_size; + snd_pcm_period_elapsed(isight->pcm); + } +} + +static void isight_samples(struct isight *isight, + const __be16 *samples, unsigned int count) +{ + struct snd_pcm_runtime *runtime; + unsigned int count1; + + if (!ACCESS_ONCE(isight->pcm_running)) + return; + + runtime = isight->pcm->runtime; + if (isight->buffer_pointer + count <= runtime->buffer_size) { + memcpy(runtime->dma_area + isight->buffer_pointer * 4, + samples, count * 4); + } else { + count1 = runtime->buffer_size - isight->buffer_pointer; + memcpy(runtime->dma_area + isight->buffer_pointer * 4, + samples, count1 * 4); + samples += count1 * 2; + memcpy(runtime->dma_area, samples, (count - count1) * 4); + } + + isight_update_pointers(isight, count); +} + +static void isight_pcm_abort(struct isight *isight) +{ + unsigned long flags; + + if (ACCESS_ONCE(isight->pcm_active)) { + snd_pcm_stream_lock_irqsave(isight->pcm, flags); + if (snd_pcm_running(isight->pcm)) + snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irqrestore(isight->pcm, flags); + } +} + +static void isight_dropped_samples(struct isight *isight, unsigned int total) +{ + struct snd_pcm_runtime *runtime; + u32 dropped; + unsigned int count1; + + if (!ACCESS_ONCE(isight->pcm_running)) + return; + + runtime = isight->pcm->runtime; + dropped = total - isight->total_samples; + if (dropped < runtime->buffer_size) { + if (isight->buffer_pointer + dropped <= runtime->buffer_size) { + memset(runtime->dma_area + isight->buffer_pointer * 4, + 0, dropped * 4); + } else { + count1 = runtime->buffer_size - isight->buffer_pointer; + memset(runtime->dma_area + isight->buffer_pointer * 4, + 0, count1 * 4); + memset(runtime->dma_area, 0, (dropped - count1) * 4); + } + isight_update_pointers(isight, dropped); + } else { + isight_pcm_abort(isight); + } +} + +static void isight_packet(struct fw_iso_context *context, u32 cycle, + size_t header_length, void *header, void *data) +{ + struct isight *isight = data; + const struct audio_payload *payload; + unsigned int index, length, count, total; + int err; + + if (isight->packet_index < 0) + return; + index = isight->packet_index; + payload = isight->buffer.packets[index].buffer; + length = be32_to_cpup(header) >> 16; + + if (likely(length >= 16 && + payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) { + count = be32_to_cpu(payload->sample_count); + if (likely(count <= (length - 16) / 4)) { + total = be32_to_cpu(payload->sample_total); + if (unlikely(total != isight->total_samples)) { + if (!isight->first_packet) + isight_dropped_samples(isight, total); + isight->first_packet = false; + isight->total_samples = total; + } + + isight_samples(isight, payload->samples, count); + isight->total_samples += count; + } + } + + err = fw_iso_context_queue(isight->context, &audio_packet, + &isight->buffer.iso_buffer, + isight->buffer.packets[index].offset); + if (err < 0) { + dev_err(&isight->unit->device, "queueing error: %d\n", err); + isight_pcm_abort(isight); + isight->packet_index = -1; + return; + } + + if (++index >= QUEUE_LENGTH) + index = 0; + isight->packet_index = index; +} + +static int isight_connect(struct isight *isight) +{ + int ch, err, rcode, errors = 0; + __be32 value; + +retry_after_bus_reset: + ch = fw_iso_resources_allocate(&isight->resources, + sizeof(struct audio_payload), + isight->device->max_speed); + if (ch < 0) { + err = ch; + goto error; + } + + value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT)); + for (;;) { + rcode = fw_run_transaction( + isight->device->card, + TCODE_WRITE_QUADLET_REQUEST, + isight->device->node_id, + isight->resources.generation, + isight->device->max_speed, + isight->audio_base + REG_ISO_TX_CONFIG, + &value, 4); + if (rcode == RCODE_COMPLETE) { + return 0; + } else if (rcode == RCODE_GENERATION) { + fw_iso_resources_free(&isight->resources); + goto retry_after_bus_reset; + } else if (rcode_is_permanent_error(rcode) || ++errors >= 3) { + err = -EIO; + goto err_resources; + } + msleep(5); + } + +err_resources: + fw_iso_resources_free(&isight->resources); +error: + return err; +} + +static int isight_open(struct snd_pcm_substream *substream) +{ + static const struct snd_pcm_hardware hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_BE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 4 * 1024 * 1024, + .period_bytes_min = MAX_FRAMES_PER_PACKET * 4, + .period_bytes_max = 1024 * 1024, + .periods_min = 2, + .periods_max = UINT_MAX, + }; + struct isight *isight = substream->private_data; + + substream->runtime->hw = hardware; + + return iso_packets_buffer_init(&isight->buffer, isight->unit, + QUEUE_LENGTH, + sizeof(struct audio_payload), + DMA_FROM_DEVICE); +} + +static int isight_close(struct snd_pcm_substream *substream) +{ + struct isight *isight = substream->private_data; + + iso_packets_buffer_destroy(&isight->buffer, isight->unit); + + return 0; +} + +static int isight_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct isight *isight = substream->private_data; + int err; + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; + + ACCESS_ONCE(isight->pcm_active) = true; + + return 0; +} + +static int reg_read(struct isight *isight, int offset, __be32 *value) +{ + return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST, + isight->audio_base + offset, value, 4); +} + +static int reg_write(struct isight *isight, int offset, __be32 value) +{ + return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST, + isight->audio_base + offset, &value, 4); +} + +static void isight_stop_streaming(struct isight *isight) +{ + if (!isight->context) + return; + + fw_iso_context_stop(isight->context); + fw_iso_context_destroy(isight->context); + isight->context = NULL; + fw_iso_resources_free(&isight->resources); + reg_write(isight, REG_AUDIO_ENABLE, 0); +} + +static int isight_hw_free(struct snd_pcm_substream *substream) +{ + struct isight *isight = substream->private_data; + + ACCESS_ONCE(isight->pcm_active) = false; + + mutex_lock(&isight->mutex); + isight_stop_streaming(isight); + mutex_unlock(&isight->mutex); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int isight_start_streaming(struct isight *isight) +{ + unsigned int i; + int err; + + if (isight->context) { + if (isight->packet_index < 0) + isight_stop_streaming(isight); + else + return 0; + } + + err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000)); + if (err < 0) + goto error; + + err = isight_connect(isight); + if (err < 0) + goto error; + + err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE)); + if (err < 0) + goto err_resources; + + isight->context = fw_iso_context_create(isight->device->card, + FW_ISO_CONTEXT_RECEIVE, + isight->resources.channel, + isight->device->max_speed, + 4, isight_packet, isight); + if (IS_ERR(isight->context)) { + err = PTR_ERR(isight->context); + isight->context = NULL; + goto err_resources; + } + + for (i = 0; i < QUEUE_LENGTH; ++i) { + err = fw_iso_context_queue(isight->context, &audio_packet, + &isight->buffer.iso_buffer, + isight->buffer.packets[i].offset); + if (err < 0) + goto err_context; + } + + isight->first_packet = true; + isight->packet_index = 0; + + err = fw_iso_context_start(isight->context, -1, 0, + FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/); + if (err < 0) + goto err_context; + + return 0; + +err_context: + fw_iso_context_destroy(isight->context); + isight->context = NULL; +err_resources: + fw_iso_resources_free(&isight->resources); + reg_write(isight, REG_AUDIO_ENABLE, 0); +error: + return err; +} + +static int isight_prepare(struct snd_pcm_substream *substream) +{ + struct isight *isight = substream->private_data; + int err; + + isight->buffer_pointer = 0; + isight->period_counter = 0; + + mutex_lock(&isight->mutex); + err = isight_start_streaming(isight); + mutex_unlock(&isight->mutex); + + return err; +} + +static int isight_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct isight *isight = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ACCESS_ONCE(isight->pcm_running) = true; + break; + case SNDRV_PCM_TRIGGER_STOP: + ACCESS_ONCE(isight->pcm_running) = false; + break; + default: + return -EINVAL; + } + return 0; +} + +static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream) +{ + struct isight *isight = substream->private_data; + + return ACCESS_ONCE(isight->buffer_pointer); +} + +static int isight_create_pcm(struct isight *isight) +{ + static struct snd_pcm_ops ops = { + .open = isight_open, + .close = isight_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = isight_hw_params, + .hw_free = isight_hw_free, + .prepare = isight_prepare, + .trigger = isight_trigger, + .pointer = isight_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm); + if (err < 0) + return err; + pcm->private_data = isight; + strcpy(pcm->name, "iSight"); + isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + isight->pcm->ops = &ops; + + return 0; +} + +static int isight_gain_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + struct isight *isight = ctl->private_data; + + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 1; + info->value.integer.min = isight->gain_min; + info->value.integer.max = isight->gain_max; + + return 0; +} + +static int isight_gain_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct isight *isight = ctl->private_data; + __be32 gain; + int err; + + err = reg_read(isight, REG_GAIN, &gain); + if (err < 0) + return err; + + value->value.integer.value[0] = (s32)be32_to_cpu(gain); + + return 0; +} + +static int isight_gain_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct isight *isight = ctl->private_data; + + if (value->value.integer.value[0] < isight->gain_min || + value->value.integer.value[0] > isight->gain_max) + return -EINVAL; + + return reg_write(isight, REG_GAIN, + cpu_to_be32(value->value.integer.value[0])); +} + +static int isight_mute_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct isight *isight = ctl->private_data; + __be32 mute; + int err; + + err = reg_read(isight, REG_MUTE, &mute); + if (err < 0) + return err; + + value->value.integer.value[0] = !mute; + + return 0; +} + +static int isight_mute_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct isight *isight = ctl->private_data; + + return reg_write(isight, REG_MUTE, + (__force __be32)!value->value.integer.value[0]); +} + +static int isight_create_mixer(struct isight *isight) +{ + static const struct snd_kcontrol_new gain_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Capture Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = isight_gain_info, + .get = isight_gain_get, + .put = isight_gain_put, + }; + static const struct snd_kcontrol_new mute_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Capture Switch", + .info = snd_ctl_boolean_mono_info, + .get = isight_mute_get, + .put = isight_mute_put, + }; + __be32 value; + struct snd_kcontrol *ctl; + int err; + + err = reg_read(isight, REG_GAIN_RAW_START, &value); + if (err < 0) + return err; + isight->gain_min = be32_to_cpu(value); + + err = reg_read(isight, REG_GAIN_RAW_END, &value); + if (err < 0) + return err; + isight->gain_max = be32_to_cpu(value); + + isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX; + isight->gain_tlv[1] = 2 * sizeof(unsigned int); + + err = reg_read(isight, REG_GAIN_DB_START, &value); + if (err < 0) + return err; + isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100; + + err = reg_read(isight, REG_GAIN_DB_END, &value); + if (err < 0) + return err; + isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100; + + ctl = snd_ctl_new1(&gain_control, isight); + if (ctl) + ctl->tlv.p = isight->gain_tlv; + err = snd_ctl_add(isight->card, ctl); + if (err < 0) + return err; + + err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight)); + if (err < 0) + return err; + + return 0; +} + +static void isight_card_free(struct snd_card *card) +{ + struct isight *isight = card->private_data; + + fw_iso_resources_destroy(&isight->resources); + fw_unit_put(isight->unit); + fw_device_put(isight->device); + mutex_destroy(&isight->mutex); +} + +static u64 get_unit_base(struct fw_unit *unit) +{ + struct fw_csr_iterator i; + int key, value; + + fw_csr_iterator_init(&i, unit->directory); + while (fw_csr_iterator_next(&i, &key, &value)) + if (key == CSR_OFFSET) + return CSR_REGISTER_BASE + value * 4; + return 0; +} + +static int isight_probe(struct device *unit_dev) +{ + struct fw_unit *unit = fw_unit(unit_dev); + struct fw_device *fw_dev = fw_parent_device(unit); + struct snd_card *card; + struct isight *isight; + int err; + + err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card); + if (err < 0) + return err; + snd_card_set_dev(card, unit_dev); + + isight = card->private_data; + isight->card = card; + mutex_init(&isight->mutex); + isight->unit = fw_unit_get(unit); + isight->device = fw_device_get(fw_dev); + isight->audio_base = get_unit_base(unit); + if (!isight->audio_base) { + dev_err(&unit->device, "audio unit base not found\n"); + err = -ENXIO; + goto err_unit; + } + fw_iso_resources_init(&isight->resources, unit); + + card->private_free = isight_card_free; + + strcpy(card->driver, "iSight"); + strcpy(card->shortname, "Apple iSight"); + snprintf(card->longname, sizeof(card->longname), + "Apple iSight (GUID %08x%08x) at %s, S%d", + fw_dev->config_rom[3], fw_dev->config_rom[4], + dev_name(&unit->device), 100 << fw_dev->max_speed); + strcpy(card->mixername, "iSight"); + + err = isight_create_pcm(isight); + if (err < 0) + goto error; + + err = isight_create_mixer(isight); + if (err < 0) + goto error; + + err = snd_card_register(card); + if (err < 0) + goto error; + + dev_set_drvdata(unit_dev, isight); + + return 0; + +err_unit: + fw_unit_put(isight->unit); + fw_device_put(isight->device); + mutex_destroy(&isight->mutex); +error: + snd_card_free(card); + return err; +} + +static int isight_remove(struct device *dev) +{ + struct isight *isight = dev_get_drvdata(dev); + + isight_pcm_abort(isight); + + snd_card_disconnect(isight->card); + + mutex_lock(&isight->mutex); + isight_stop_streaming(isight); + mutex_unlock(&isight->mutex); + + snd_card_free_when_closed(isight->card); + + return 0; +} + +static void isight_bus_reset(struct fw_unit *unit) +{ + struct isight *isight = dev_get_drvdata(&unit->device); + + if (fw_iso_resources_update(&isight->resources) < 0) { + isight_pcm_abort(isight); + + mutex_lock(&isight->mutex); + isight_stop_streaming(isight); + mutex_unlock(&isight->mutex); + } +} + +static const struct ieee1394_device_id isight_id_table[] = { + { + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .specifier_id = OUI_APPLE, + .version = SW_ISIGHT_AUDIO, + }, + { } +}; +MODULE_DEVICE_TABLE(ieee1394, isight_id_table); + +static struct fw_driver isight_driver = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .bus = &fw_bus_type, + .probe = isight_probe, + .remove = isight_remove, + }, + .update = isight_bus_reset, + .id_table = isight_id_table, +}; + +static int __init alsa_isight_init(void) +{ + return driver_register(&isight_driver.driver); +} + +static void __exit alsa_isight_exit(void) +{ + driver_unregister(&isight_driver.driver); +} + +module_init(alsa_isight_init); +module_exit(alsa_isight_exit); diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c index 775dbd5f3445..ffe20b877e9f 100644 --- a/sound/firewire/iso-resources.c +++ b/sound/firewire/iso-resources.c @@ -11,7 +11,6 @@ #include <linux/jiffies.h> #include <linux/mutex.h> #include <linux/sched.h> -#include <linux/slab.h> #include <linux/spinlock.h> #include "iso-resources.h" @@ -25,10 +24,6 @@ */ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) { - r->buffer = kmalloc(2 * 4, GFP_KERNEL); - if (!r->buffer) - return -ENOMEM; - r->channels_mask = ~0uLL; r->unit = fw_unit_get(unit); mutex_init(&r->mutex); @@ -36,6 +31,7 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) return 0; } +EXPORT_SYMBOL(fw_iso_resources_init); /** * fw_iso_resources_destroy - destroy a resource manager @@ -44,10 +40,10 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) void fw_iso_resources_destroy(struct fw_iso_resources *r) { WARN_ON(r->allocated); - kfree(r->buffer); mutex_destroy(&r->mutex); fw_unit_put(r->unit); } +EXPORT_SYMBOL(fw_iso_resources_destroy); static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed) { @@ -131,7 +127,7 @@ retry_after_bus_reset: bandwidth = r->bandwidth + r->bandwidth_overhead; fw_iso_resource_manage(card, r->generation, r->channels_mask, - &channel, &bandwidth, true, r->buffer); + &channel, &bandwidth, true); if (channel == -EAGAIN) { mutex_unlock(&r->mutex); goto retry_after_bus_reset; @@ -152,6 +148,7 @@ retry_after_bus_reset: return channel; } +EXPORT_SYMBOL(fw_iso_resources_allocate); /** * fw_iso_resources_update - update resource allocations after a bus reset @@ -184,7 +181,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r) bandwidth = r->bandwidth + r->bandwidth_overhead; fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, - &channel, &bandwidth, true, r->buffer); + &channel, &bandwidth, true); /* * When another bus reset happens, pretend that the allocation * succeeded; we will try again for the new generation later. @@ -203,6 +200,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r) return channel; } +EXPORT_SYMBOL(fw_iso_resources_update); /** * fw_iso_resources_free - frees allocated resources @@ -220,7 +218,7 @@ void fw_iso_resources_free(struct fw_iso_resources *r) if (r->allocated) { bandwidth = r->bandwidth + r->bandwidth_overhead; fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, - &channel, &bandwidth, false, r->buffer); + &channel, &bandwidth, false); if (channel < 0) dev_err(&r->unit->device, "isochronous resource deallocation failed\n"); @@ -230,3 +228,4 @@ void fw_iso_resources_free(struct fw_iso_resources *r) mutex_unlock(&r->mutex); } +EXPORT_SYMBOL(fw_iso_resources_free); diff --git a/sound/firewire/iso-resources.h b/sound/firewire/iso-resources.h index 3f0730e4d841..5a9af7c61657 100644 --- a/sound/firewire/iso-resources.h +++ b/sound/firewire/iso-resources.h @@ -24,7 +24,6 @@ struct fw_iso_resources { unsigned int bandwidth_overhead; int generation; /* in which allocation is valid */ bool allocated; - __be32 *buffer; }; int fw_iso_resources_init(struct fw_iso_resources *r, diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c index 1e20e60ba6a6..3c61ca2e6152 100644 --- a/sound/firewire/packets-buffer.c +++ b/sound/firewire/packets-buffer.c @@ -60,6 +60,7 @@ err_packets: error: return err; } +EXPORT_SYMBOL(iso_packets_buffer_init); /** * iso_packets_buffer_destroy - frees packet buffer resources @@ -72,3 +73,4 @@ void iso_packets_buffer_destroy(struct iso_packets_buffer *b, fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); kfree(b->packets); } +EXPORT_SYMBOL(iso_packets_buffer_destroy); diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c index 0fce9218abb1..5466de8527bd 100644 --- a/sound/firewire/speakers.c +++ b/sound/firewire/speakers.c @@ -778,10 +778,9 @@ static int __devexit fwspk_remove(struct device *dev) { struct fwspk *fwspk = dev_get_drvdata(dev); - snd_card_disconnect(fwspk->card); - mutex_lock(&fwspk->mutex); amdtp_out_stream_pcm_abort(&fwspk->stream); + snd_card_disconnect(fwspk->card); fwspk_stop_stream(fwspk); mutex_unlock(&fwspk->mutex); diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 2dad40f3f622..c95d8f1aae87 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile @@ -14,4 +14,4 @@ snd-tea575x-tuner-objs := tea575x-tuner.o obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o -obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o +obj-$(CONFIG_SND_TEA575X) += snd-tea575x-tuner.o diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index ee538f1ae846..4831800239d3 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -37,8 +37,8 @@ static int radio_nr = -1; module_param(radio_nr, int, 0); #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) -#define FREQ_LO (87 * 16000) -#define FREQ_HI (108 * 16000) +#define FREQ_LO (50UL * 16000) +#define FREQ_HI (150UL * 16000) /* * definitions @@ -77,27 +77,95 @@ static struct v4l2_queryctrl radio_qctrl[] = { * lowlevel part */ +static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val) +{ + u16 l; + u8 data; + + tea->ops->set_direction(tea, 1); + udelay(16); + + for (l = 25; l > 0; l--) { + data = (val >> 24) & TEA575X_DATA; + val <<= 1; /* shift data */ + tea->ops->set_pins(tea, data | TEA575X_WREN); + udelay(2); + tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK); + udelay(2); + tea->ops->set_pins(tea, data | TEA575X_WREN); + udelay(2); + } + + if (!tea->mute) + tea->ops->set_pins(tea, 0); +} + +static unsigned int snd_tea575x_read(struct snd_tea575x *tea) +{ + u16 l, rdata; + u32 data = 0; + + tea->ops->set_direction(tea, 0); + tea->ops->set_pins(tea, 0); + udelay(16); + + for (l = 24; l--;) { + tea->ops->set_pins(tea, TEA575X_CLK); + udelay(2); + if (!l) + tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1; + tea->ops->set_pins(tea, 0); + udelay(2); + data <<= 1; /* shift data */ + rdata = tea->ops->get_pins(tea); + if (!l) + tea->stereo = (rdata & TEA575X_MOST) ? 0 : 1; + if (rdata & TEA575X_DATA) + data++; + udelay(2); + } + + if (tea->mute) + tea->ops->set_pins(tea, TEA575X_WREN); + + return data; +} + +static void snd_tea575x_get_freq(struct snd_tea575x *tea) +{ + unsigned long freq; + + freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; + /* freq *= 12.5 */ + freq *= 125; + freq /= 10; + /* crystal fixup */ + if (tea->tea5759) + freq += TEA575X_FMIF; + else + freq -= TEA575X_FMIF; + + tea->freq = freq * 16; /* from kHz */ +} + static void snd_tea575x_set_freq(struct snd_tea575x *tea) { unsigned long freq; - freq = tea->freq / 16; /* to kHz */ - if (freq > 108000) - freq = 108000; - if (freq < 87000) - freq = 87000; + freq = clamp(tea->freq, FREQ_LO, FREQ_HI); + freq /= 16; /* to kHz */ /* crystal fixup */ if (tea->tea5759) - freq -= tea->freq_fixup; + freq -= TEA575X_FMIF; else - freq += tea->freq_fixup; + freq += TEA575X_FMIF; /* freq /= 12.5 */ freq *= 10; freq /= 125; tea->val &= ~TEA575X_BIT_FREQ_MASK; tea->val |= freq & TEA575X_BIT_FREQ_MASK; - tea->ops->write(tea, tea->val); + snd_tea575x_write(tea, tea->val); } /* @@ -109,29 +177,34 @@ static int vidioc_querycap(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); - strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757"); strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); - strlcpy(v->card, "Maestro Radio", sizeof(v->card)); - sprintf(v->bus_info, "PCI"); + strlcpy(v->card, tea->card, sizeof(v->card)); + strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); + strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { + struct snd_tea575x *tea = video_drvdata(file); + if (v->index > 0) return -EINVAL; + snd_tea575x_read(tea); + strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; v->rangelow = FREQ_LO; v->rangehigh = FREQ_HI; - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; + v->signal = tea->tuned ? 0xffff : 0; + return 0; } @@ -148,7 +221,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; + snd_tea575x_get_freq(tea); f->frequency = tea->freq; return 0; } @@ -158,6 +234,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct snd_tea575x *tea = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) return -EINVAL; @@ -209,10 +288,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - if (tea->ops->mute) { - ctrl->value = tea->mute; - return 0; - } + ctrl->value = tea->mute; + return 0; } return -EINVAL; } @@ -224,11 +301,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - if (tea->ops->mute) { - tea->ops->mute(tea, ctrl->value); + if (tea->mute != ctrl->value) { tea->mute = ctrl->value; - return 0; + snd_tea575x_set_freq(tea); } + return 0; } return -EINVAL; } @@ -293,18 +370,16 @@ static struct video_device tea575x_radio = { /* * initialize all the tea575x chips */ -void snd_tea575x_init(struct snd_tea575x *tea) +int snd_tea575x_init(struct snd_tea575x *tea) { int retval; - unsigned int val; struct video_device *tea575x_radio_inst; - val = tea->ops->read(tea); - if (val == 0x1ffffff || val == 0) { - snd_printk(KERN_ERR - "tea575x-tuner: Cannot find TEA575x chip\n"); - return; - } + tea->mute = 1; + + snd_tea575x_write(tea, 0x55AA); + if (snd_tea575x_read(tea) != 0x55AA) + return -ENODEV; tea->in_use = 0; tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; @@ -313,7 +388,7 @@ void snd_tea575x_init(struct snd_tea575x *tea) tea575x_radio_inst = video_device_alloc(); if (tea575x_radio_inst == NULL) { printk(KERN_ERR "tea575x-tuner: not enough memory\n"); - return; + return -ENOMEM; } memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio)); @@ -328,17 +403,13 @@ void snd_tea575x_init(struct snd_tea575x *tea) if (retval) { printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); kfree(tea575x_radio_inst); - return; + return retval; } snd_tea575x_set_freq(tea); - - /* mute on init */ - if (tea->ops->mute) { - tea->ops->mute(tea, 1); - tea->mute = 1; - } tea->vd = tea575x_radio_inst; + + return 0; } void snd_tea575x_exit(struct snd_tea575x *tea) diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 0c40951b6523..5d61f5a29130 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -370,7 +370,7 @@ init_arrays(struct snd_emu8000 *emu) /* * Size the onboard memory. - * This is written so as not to need arbitary delays after the write. It + * This is written so as not to need arbitrary delays after the write. It * seems that the only way to do this is to use the one channel and keep * reallocating between read and write. */ diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index f14a7c0b6998..65329f3abc30 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -537,7 +537,7 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card) } /* Turn on Virtual MIDI, but first *always* turn it off, - since otherwise consectutive reloads of the driver will + since otherwise consecutive reloads of the driver will never cause the hardware to generate the initial "internal" or "external" source bytes in the MIDI data stream. This is pretty important, since the internal hardware generally will diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 9191b32d9130..2a42cc377957 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -424,7 +424,7 @@ void snd_wss_mce_down(struct snd_wss *chip) /* * Wait for (possible -- during init auto-calibration may not be set) - * calibration process to start. Needs upto 5 sample periods on AD1848 + * calibration process to start. Needs up to 5 sample periods on AD1848 * which at the slowest possible rate of 5.5125 kHz means 907 us. */ msleep(1); diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 76c090218073..6c93e051f9ae 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -22,10 +22,6 @@ config SOUND_VWSND <file:Documentation/sound/oss/vwsnd> for more info on this driver's capabilities. -config SOUND_AU1550_AC97 - tristate "Au1550/Au1200 AC97 Sound" - depends on SOC_AU1550 || SOC_AU1200 - config SOUND_MSNDCLAS tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" depends on (m || !STANDALONE) && ISA diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 90ffb99c6b17..77f21b68bf0f 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -25,7 +25,6 @@ obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o -obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o obj-$(CONFIG_DMASOUND) += dmasound/ diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c deleted file mode 100644 index 854c303264dc..000000000000 --- a/sound/oss/ac97_codec.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* - * ac97_codec.c: Generic AC97 mixer/modem module - * - * Derived from ac97 mixer in maestro and trident driver. - * - * Copyright 2000 Silicon Integrated System Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ************************************************************************** - * - * The Intel Audio Codec '97 specification is available at: - * http://download.intel.com/support/motherboards/desktop/sb/ac97_r23.pdf - * - ************************************************************************** - * - * History - * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk> - * Removed non existant WM9700 - * Added support for WM9705, WM9708, WM9709, WM9710, WM9711 - * WM9712 and WM9717 - * Mar 28, 2002 Randolph Bentson <bentson@holmsjoen.com> - * corrections to support WM9707 in ViewPad 1000 - * v0.4 Mar 15 2000 Ollie Lho - * dual codecs support verified with 4 channels output - * v0.3 Feb 22 2000 Ollie Lho - * bug fix for record mask setting - * v0.2 Feb 10 2000 Ollie Lho - * add ac97_read_proc for /proc/driver/{vendor}/ac97 - * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw> - * Isolated from trident.c to support multiple ac97 codec - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/bitops.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <linux/ac97_codec.h> -#include <asm/uaccess.h> -#include <linux/mutex.h> - -#define CODEC_ID_BUFSZ 14 - -static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel); -static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, - unsigned int left, unsigned int right); -static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ); -static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask); -static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg); - -static int ac97_init_mixer(struct ac97_codec *codec); - -static int wolfson_init03(struct ac97_codec * codec); -static int wolfson_init04(struct ac97_codec * codec); -static int wolfson_init05(struct ac97_codec * codec); -static int wolfson_init11(struct ac97_codec * codec); -static int wolfson_init13(struct ac97_codec * codec); -static int tritech_init(struct ac97_codec * codec); -static int tritech_maestro_init(struct ac97_codec * codec); -static int sigmatel_9708_init(struct ac97_codec *codec); -static int sigmatel_9721_init(struct ac97_codec *codec); -static int sigmatel_9744_init(struct ac97_codec *codec); -static int ad1886_init(struct ac97_codec *codec); -static int eapd_control(struct ac97_codec *codec, int); -static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode); -static int cmedia_init(struct ac97_codec * codec); -static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode); -static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode); - - -/* - * AC97 operations. - * - * If you are adding a codec then you should be able to use - * eapd_ops - any codec that supports EAPD amp control (most) - * null_ops - any ancient codec that supports nothing - * - * The three functions are - * init - used for non AC97 standard initialisation - * amplifier - used to do amplifier control (1=on 0=off) - * digital - switch to digital modes (0 = analog) - * - * Not all codecs support all features, not all drivers use all the - * operations yet - */ - -static struct ac97_ops null_ops = { NULL, NULL, NULL }; -static struct ac97_ops default_ops = { NULL, eapd_control, NULL }; -static struct ac97_ops default_digital_ops = { NULL, eapd_control, generic_digital_control}; -static struct ac97_ops wolfson_ops03 = { wolfson_init03, NULL, NULL }; -static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL }; -static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL }; -static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL }; -static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL }; -static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL }; -static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL }; -static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL }; -static struct ac97_ops sigmatel_9721_ops = { sigmatel_9721_init, NULL, NULL }; -static struct ac97_ops sigmatel_9744_ops = { sigmatel_9744_init, NULL, NULL }; -static struct ac97_ops crystal_digital_ops = { NULL, eapd_control, crystal_digital_control }; -static struct ac97_ops ad1886_ops = { ad1886_init, eapd_control, NULL }; -static struct ac97_ops cmedia_ops = { NULL, eapd_control, NULL}; -static struct ac97_ops cmedia_digital_ops = { cmedia_init, eapd_control, cmedia_digital_control}; - -/* sorted by vendor/device id */ -static const struct { - u32 id; - char *name; - struct ac97_ops *ops; - int flags; -} ac97_codec_ids[] = { - {0x41445303, "Analog Devices AD1819", &null_ops}, - {0x41445340, "Analog Devices AD1881", &null_ops}, - {0x41445348, "Analog Devices AD1881A", &null_ops}, - {0x41445360, "Analog Devices AD1885", &default_ops}, - {0x41445361, "Analog Devices AD1886", &ad1886_ops}, - {0x41445370, "Analog Devices AD1981", &null_ops}, - {0x41445372, "Analog Devices AD1981A", &null_ops}, - {0x41445374, "Analog Devices AD1981B", &null_ops}, - {0x41445460, "Analog Devices AD1885", &default_ops}, - {0x41445461, "Analog Devices AD1886", &ad1886_ops}, - {0x414B4D00, "Asahi Kasei AK4540", &null_ops}, - {0x414B4D01, "Asahi Kasei AK4542", &null_ops}, - {0x414B4D02, "Asahi Kasei AK4543", &null_ops}, - {0x414C4326, "ALC100P", &null_ops}, - {0x414C4710, "ALC200/200P", &null_ops}, - {0x414C4720, "ALC650", &default_digital_ops}, - {0x434D4941, "CMedia", &cmedia_ops, AC97_NO_PCM_VOLUME }, - {0x434D4942, "CMedia", &cmedia_ops, AC97_NO_PCM_VOLUME }, - {0x434D4961, "CMedia", &cmedia_digital_ops, AC97_NO_PCM_VOLUME }, - {0x43525900, "Cirrus Logic CS4297", &default_ops}, - {0x43525903, "Cirrus Logic CS4297", &default_ops}, - {0x43525913, "Cirrus Logic CS4297A rev A", &default_ops}, - {0x43525914, "Cirrus Logic CS4297A rev B", &default_ops}, - {0x43525923, "Cirrus Logic CS4298", &null_ops}, - {0x4352592B, "Cirrus Logic CS4294", &null_ops}, - {0x4352592D, "Cirrus Logic CS4294", &null_ops}, - {0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops}, - {0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops}, - {0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops}, - {0x43585430, "CXT48", &default_ops, AC97_DELUDED_MODEM }, - {0x43585442, "CXT66", &default_ops, AC97_DELUDED_MODEM }, - {0x44543031, "Diamond Technology DT0893", &default_ops}, - {0x45838308, "ESS Allegro ES1988", &null_ops}, - {0x49434511, "ICE1232", &null_ops}, /* I hope --jk */ - {0x4e534331, "National Semiconductor LM4549", &null_ops}, - {0x53494c22, "Silicon Laboratory Si3036", &null_ops}, - {0x53494c23, "Silicon Laboratory Si3038", &null_ops}, - {0x545200FF, "TriTech TR?????", &tritech_m_ops}, - {0x54524102, "TriTech TR28022", &null_ops}, - {0x54524103, "TriTech TR28023", &null_ops}, - {0x54524106, "TriTech TR28026", &null_ops}, - {0x54524108, "TriTech TR28028", &tritech_ops}, - {0x54524123, "TriTech TR A5", &null_ops}, - {0x574D4C03, "Wolfson WM9703/07/08/17", &wolfson_ops03}, - {0x574D4C04, "Wolfson WM9704M/WM9704Q", &wolfson_ops04}, - {0x574D4C05, "Wolfson WM9705/WM9710", &wolfson_ops05}, - {0x574D4C09, "Wolfson WM9709", &null_ops}, - {0x574D4C12, "Wolfson WM9711/9712", &wolfson_ops11}, - {0x574D4C13, "Wolfson WM9713", &wolfson_ops13, AC97_DEFAULT_POWER_OFF}, - {0x83847600, "SigmaTel STAC????", &null_ops}, - {0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops}, - {0x83847605, "SigmaTel STAC9704", &null_ops}, - {0x83847608, "SigmaTel STAC9708", &sigmatel_9708_ops}, - {0x83847609, "SigmaTel STAC9721/23", &sigmatel_9721_ops}, - {0x83847644, "SigmaTel STAC9744/45", &sigmatel_9744_ops}, - {0x83847652, "SigmaTel STAC9752/53", &default_ops}, - {0x83847656, "SigmaTel STAC9756/57", &sigmatel_9744_ops}, - {0x83847666, "SigmaTel STAC9750T", &sigmatel_9744_ops}, - {0x83847684, "SigmaTel STAC9783/84?", &null_ops}, - {0x57454301, "Winbond 83971D", &null_ops}, -}; - -/* this table has default mixer values for all OSS mixers. */ -static struct mixer_defaults { - int mixer; - unsigned int value; -} mixer_defaults[SOUND_MIXER_NRDEVICES] = { - /* all values 0 -> 100 in bytes */ - {SOUND_MIXER_VOLUME, 0x4343}, - {SOUND_MIXER_BASS, 0x4343}, - {SOUND_MIXER_TREBLE, 0x4343}, - {SOUND_MIXER_PCM, 0x4343}, - {SOUND_MIXER_SPEAKER, 0x4343}, - {SOUND_MIXER_LINE, 0x4343}, - {SOUND_MIXER_MIC, 0x0000}, - {SOUND_MIXER_CD, 0x4343}, - {SOUND_MIXER_ALTPCM, 0x4343}, - {SOUND_MIXER_IGAIN, 0x4343}, - {SOUND_MIXER_LINE1, 0x4343}, - {SOUND_MIXER_PHONEIN, 0x4343}, - {SOUND_MIXER_PHONEOUT, 0x4343}, - {SOUND_MIXER_VIDEO, 0x4343}, - {-1,0} -}; - -/* table to scale scale from OSS mixer value to AC97 mixer register value */ -static struct ac97_mixer_hw { - unsigned char offset; - int scale; -} ac97_hw[SOUND_MIXER_NRDEVICES]= { - [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,64}, - [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 16}, - [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 16}, - [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 32}, - [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 16}, - [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 32}, - [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 32}, - [SOUND_MIXER_CD] = {AC97_CD_VOL, 32}, - [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 64}, - [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 16}, - [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 32}, - [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 32}, - [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 64}, - [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 32}, -}; - -/* the following tables allow us to go from OSS <-> ac97 quickly. */ -enum ac97_recsettings { - AC97_REC_MIC=0, - AC97_REC_CD, - AC97_REC_VIDEO, - AC97_REC_AUX, - AC97_REC_LINE, - AC97_REC_STEREO, /* combination of all enabled outputs.. */ - AC97_REC_MONO, /*.. or the mono equivalent */ - AC97_REC_PHONE -}; - -static const unsigned int ac97_rm2oss[] = { - [AC97_REC_MIC] = SOUND_MIXER_MIC, - [AC97_REC_CD] = SOUND_MIXER_CD, - [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, - [AC97_REC_AUX] = SOUND_MIXER_LINE1, - [AC97_REC_LINE] = SOUND_MIXER_LINE, - [AC97_REC_STEREO]= SOUND_MIXER_IGAIN, - [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN -}; - -/* indexed by bit position */ -static const unsigned int ac97_oss_rm[] = { - [SOUND_MIXER_MIC] = AC97_REC_MIC, - [SOUND_MIXER_CD] = AC97_REC_CD, - [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, - [SOUND_MIXER_LINE1] = AC97_REC_AUX, - [SOUND_MIXER_LINE] = AC97_REC_LINE, - [SOUND_MIXER_IGAIN] = AC97_REC_STEREO, - [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE -}; - -static LIST_HEAD(codecs); -static LIST_HEAD(codec_drivers); -static DEFINE_MUTEX(codec_mutex); - -/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows - about that given mixer, and should be holding a spinlock for the card */ -static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) -{ - u16 val; - int ret = 0; - int scale; - struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; - - val = codec->codec_read(codec , mh->offset); - - if (val & AC97_MUTE) { - ret = 0; - } else if (AC97_STEREO_MASK & (1 << oss_channel)) { - /* nice stereo mixers .. */ - int left,right; - - left = (val >> 8) & 0x7f; - right = val & 0x7f; - - if (oss_channel == SOUND_MIXER_IGAIN) { - right = (right * 100) / mh->scale; - left = (left * 100) / mh->scale; - } else { - /* these may have 5 or 6 bit resolution */ - if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM) - scale = (1 << codec->bit_resolution); - else - scale = mh->scale; - - right = 100 - ((right * 100) / scale); - left = 100 - ((left * 100) / scale); - } - ret = left | (right << 8); - } else if (oss_channel == SOUND_MIXER_SPEAKER) { - ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); - } else if (oss_channel == SOUND_MIXER_PHONEIN) { - ret = 100 - (((val & 0x1f) * 100) / mh->scale); - } else if (oss_channel == SOUND_MIXER_PHONEOUT) { - scale = (1 << codec->bit_resolution); - ret = 100 - (((val & 0x1f) * 100) / scale); - } else if (oss_channel == SOUND_MIXER_MIC) { - ret = 100 - (((val & 0x1f) * 100) / mh->scale); - /* the low bit is optional in the tone sliders and masking - it lets us avoid the 0xf 'bypass'.. */ - } else if (oss_channel == SOUND_MIXER_BASS) { - ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale); - } else if (oss_channel == SOUND_MIXER_TREBLE) { - ret = 100 - (((val & 0xe) * 100) / mh->scale); - } - -#ifdef DEBUG - printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), " - "0x%04x -> 0x%04x\n", - oss_channel, codec->id ? "Secondary" : "Primary", - mh->offset, val, ret); -#endif - - return ret; -} - -/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to - make sure all is well in arg land, call with spinlock held */ -static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, - unsigned int left, unsigned int right) -{ - u16 val = 0; - int scale; - struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; - -#ifdef DEBUG - printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), " - "left vol:%2d, right vol:%2d:", - oss_channel, codec->id ? "Secondary" : "Primary", - mh->offset, left, right); -#endif - - if (AC97_STEREO_MASK & (1 << oss_channel)) { - /* stereo mixers */ - if (left == 0 && right == 0) { - val = AC97_MUTE; - } else { - if (oss_channel == SOUND_MIXER_IGAIN) { - right = (right * mh->scale) / 100; - left = (left * mh->scale) / 100; - if (right >= mh->scale) - right = mh->scale-1; - if (left >= mh->scale) - left = mh->scale-1; - } else { - /* these may have 5 or 6 bit resolution */ - if (oss_channel == SOUND_MIXER_VOLUME || - oss_channel == SOUND_MIXER_ALTPCM) - scale = (1 << codec->bit_resolution); - else - scale = mh->scale; - - right = ((100 - right) * scale) / 100; - left = ((100 - left) * scale) / 100; - if (right >= scale) - right = scale-1; - if (left >= scale) - left = scale-1; - } - val = (left << 8) | right; - } - } else if (oss_channel == SOUND_MIXER_BASS) { - val = codec->codec_read(codec , mh->offset) & ~0x0f00; - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val |= (left << 8) & 0x0e00; - } else if (oss_channel == SOUND_MIXER_TREBLE) { - val = codec->codec_read(codec , mh->offset) & ~0x000f; - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val |= left & 0x000e; - } else if(left == 0) { - val = AC97_MUTE; - } else if (oss_channel == SOUND_MIXER_SPEAKER) { - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val = left << 1; - } else if (oss_channel == SOUND_MIXER_PHONEIN) { - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val = left; - } else if (oss_channel == SOUND_MIXER_PHONEOUT) { - scale = (1 << codec->bit_resolution); - left = ((100 - left) * scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val = left; - } else if (oss_channel == SOUND_MIXER_MIC) { - val = codec->codec_read(codec , mh->offset) & ~0x801f; - left = ((100 - left) * mh->scale) / 100; - if (left >= mh->scale) - left = mh->scale-1; - val |= left; - /* the low bit is optional in the tone sliders and masking - it lets us avoid the 0xf 'bypass'.. */ - } -#ifdef DEBUG - printk(" 0x%04x", val); -#endif - - codec->codec_write(codec, mh->offset, val); - -#ifdef DEBUG - val = codec->codec_read(codec, mh->offset); - printk(" -> 0x%04x\n", val); -#endif -} - -/* a thin wrapper for write_mixer */ -static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ) -{ - unsigned int left,right; - - /* cleanse input a little */ - right = ((val >> 8) & 0xff) ; - left = (val & 0xff) ; - - if (right > 100) right = 100; - if (left > 100) left = 100; - - codec->mixer_state[oss_mixer] = (right << 8) | left; - codec->write_mixer(codec, oss_mixer, left, right); -} - -/* read or write the recmask, the ac97 can really have left and right recording - inputs independantly set, but OSS doesn't seem to want us to express that to - the user. the caller guarantees that we have a supported bit set, and they - must be holding the card's spinlock */ -static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) -{ - unsigned int val; - - if (rw) { - /* read it from the card */ - val = codec->codec_read(codec, AC97_RECORD_SELECT); -#ifdef DEBUG - printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val); -#endif - return (1 << ac97_rm2oss[val & 0x07]); - } - - /* else, write the first set in the mask as the - output */ - /* clear out current set value first (AC97 supports only 1 input!) */ - val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]); - if (mask != val) - mask &= ~val; - - val = ffs(mask); - val = ac97_oss_rm[val-1]; - val |= val << 8; /* set both channels */ - -#ifdef DEBUG - printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val); -#endif - - codec->codec_write(codec, AC97_RECORD_SELECT, val); - - return 0; -}; - -static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg) -{ - int i, val = 0; - - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, codec->name, sizeof(info.id)); - strlcpy(info.name, codec->name, sizeof(info.name)); - info.modify_counter = codec->modcnt; - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, codec->name, sizeof(info.id)); - strlcpy(info.name, codec->name, sizeof(info.name)); - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - - if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int __user *)arg); - - if (_SIOC_DIR(cmd) == _SIOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* give them the current record source */ - if (!codec->recmask_io) { - val = 0; - } else { - val = codec->recmask_io(codec, 1, 0); - } - break; - - case SOUND_MIXER_DEVMASK: /* give them the supported mixers */ - val = codec->supported_mixers; - break; - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - val = codec->record_sources; - break; - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - val = codec->stereo_mixers; - break; - - case SOUND_MIXER_CAPS: - val = SOUND_CAP_EXCL_INPUT; - break; - - default: /* read a specific mixer */ - i = _IOC_NR(cmd); - - if (!supported_mixer(codec, i)) - return -EINVAL; - - /* do we ever want to touch the hardware? */ - /* val = codec->read_mixer(codec, i); */ - val = codec->mixer_state[i]; - break; - } - return put_user(val, (int __user *)arg); - } - - if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) { - codec->modcnt++; - if (get_user(val, (int __user *)arg)) - return -EFAULT; - - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - if (!codec->recmask_io) return -EINVAL; - if (!val) return 0; - if (!(val &= codec->record_sources)) return -EINVAL; - - codec->recmask_io(codec, 0, val); - - return 0; - default: /* write a specific mixer */ - i = _IOC_NR(cmd); - - if (!supported_mixer(codec, i)) - return -EINVAL; - - ac97_set_mixer(codec, i, val); - - return 0; - } - } - return -EINVAL; -} - -/** - * codec_id - Turn id1/id2 into a PnP string - * @id1: Vendor ID1 - * @id2: Vendor ID2 - * @buf: CODEC_ID_BUFSZ byte buffer - * - * Fills buf with a zero terminated PnP ident string for the id1/id2 - * pair. For convenience the return is the passed in buffer pointer. - */ - -static char *codec_id(u16 id1, u16 id2, char *buf) -{ - if(id1&0x8080) { - snprintf(buf, CODEC_ID_BUFSZ, "0x%04x:0x%04x", id1, id2); - } else { - buf[0] = (id1 >> 8); - buf[1] = (id1 & 0xFF); - buf[2] = (id2 >> 8); - snprintf(buf+3, CODEC_ID_BUFSZ - 3, "%d", id2&0xFF); - } - return buf; -} - -/** - * ac97_check_modem - Check if the Codec is a modem - * @codec: codec to check - * - * Return true if the device is an AC97 1.0 or AC97 2.0 modem - */ - -static int ac97_check_modem(struct ac97_codec *codec) -{ - /* Check for an AC97 1.0 soft modem (ID1) */ - if(codec->codec_read(codec, AC97_RESET) & 2) - return 1; - /* Check for an AC97 2.x soft modem */ - codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L); - if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1) - return 1; - return 0; -} - - -/** - * ac97_alloc_codec - Allocate an AC97 codec - * - * Returns a new AC97 codec structure. AC97 codecs may become - * refcounted soon so this interface is needed. Returns with - * one reference taken. - */ - -struct ac97_codec *ac97_alloc_codec(void) -{ - struct ac97_codec *codec = kzalloc(sizeof(struct ac97_codec), GFP_KERNEL); - if(!codec) - return NULL; - - spin_lock_init(&codec->lock); - INIT_LIST_HEAD(&codec->list); - return codec; -} - -EXPORT_SYMBOL(ac97_alloc_codec); - -/** - * ac97_release_codec - Release an AC97 codec - * @codec: codec to release - * - * Release an allocated AC97 codec. This will be refcounted in - * time but for the moment is trivial. Calls the unregister - * handler if the codec is now defunct. - */ - -void ac97_release_codec(struct ac97_codec *codec) -{ - /* Remove from the list first, we don't want to be - "rediscovered" */ - mutex_lock(&codec_mutex); - list_del(&codec->list); - mutex_unlock(&codec_mutex); - /* - * The driver needs to deal with internal - * locking to avoid accidents here. - */ - if(codec->driver) - codec->driver->remove(codec, codec->driver); - kfree(codec); -} - -EXPORT_SYMBOL(ac97_release_codec); - -/** - * ac97_probe_codec - Initialize and setup AC97-compatible codec - * @codec: (in/out) Kernel info for a single AC97 codec - * - * Reset the AC97 codec, then initialize the mixer and - * the rest of the @codec structure. - * - * The codec_read and codec_write fields of @codec are - * required to be setup and working when this function - * is called. All other fields are set by this function. - * - * codec_wait field of @codec can optionally be provided - * when calling this function. If codec_wait is not %NULL, - * this function will call codec_wait any time it is - * necessary to wait for the audio chip to reach the - * codec-ready state. If codec_wait is %NULL, then - * the default behavior is to call schedule_timeout. - * Currently codec_wait is used to wait for AC97 codec - * reset to complete. - * - * Some codecs will power down when a register reset is - * performed. We now check for such codecs. - * - * Returns 1 (true) on success, or 0 (false) on failure. - */ - -int ac97_probe_codec(struct ac97_codec *codec) -{ - u16 id1, id2; - u16 audio; - int i; - char cidbuf[CODEC_ID_BUFSZ]; - u16 f; - struct list_head *l; - struct ac97_driver *d; - - /* wait for codec-ready state */ - if (codec->codec_wait) - codec->codec_wait(codec); - else - udelay(10); - - /* will the codec power down if register reset ? */ - id1 = codec->codec_read(codec, AC97_VENDOR_ID1); - id2 = codec->codec_read(codec, AC97_VENDOR_ID2); - codec->name = NULL; - codec->codec_ops = &null_ops; - for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) { - if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { - codec->type = ac97_codec_ids[i].id; - codec->name = ac97_codec_ids[i].name; - codec->codec_ops = ac97_codec_ids[i].ops; - codec->flags = ac97_codec_ids[i].flags; - break; - } - } - - codec->model = (id1 << 16) | id2; - if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) { - /* reset codec and wait for the ready bit before we continue */ - codec->codec_write(codec, AC97_RESET, 0L); - if (codec->codec_wait) - codec->codec_wait(codec); - else - udelay(10); - } - - /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should - * be read zero. - * - * FIXME: is the following comment outdated? -jgarzik - * Probing of AC97 in this way is not reliable, it is not even SAFE !! - */ - if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { - printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", - (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") - : (codec->id&1 ? "Secondary": "Primary")); - return 0; - } - - /* probe for Modem Codec */ - codec->modem = ac97_check_modem(codec); - - /* enable SPDIF */ - f = codec->codec_read(codec, AC97_EXTENDED_STATUS); - if((codec->codec_ops == &null_ops) && (f & 4)) - codec->codec_ops = &default_digital_ops; - - /* A device which thinks its a modem but isnt */ - if(codec->flags & AC97_DELUDED_MODEM) - codec->modem = 0; - - if (codec->name == NULL) - codec->name = "Unknown"; - printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s (%s)\n", - codec->modem ? "Modem" : (audio ? "Audio" : ""), - codec_id(id1, id2, cidbuf), codec->name); - - if(!ac97_init_mixer(codec)) - return 0; - - /* - * Attach last so the caller can override the mixer - * callbacks. - */ - - mutex_lock(&codec_mutex); - list_add(&codec->list, &codecs); - - list_for_each(l, &codec_drivers) { - d = list_entry(l, struct ac97_driver, list); - if ((codec->model ^ d->codec_id) & d->codec_mask) - continue; - if(d->probe(codec, d) == 0) - { - codec->driver = d; - break; - } - } - - mutex_unlock(&codec_mutex); - return 1; -} - -static int ac97_init_mixer(struct ac97_codec *codec) -{ - u16 cap; - int i; - - cap = codec->codec_read(codec, AC97_RESET); - - /* mixer masks */ - codec->supported_mixers = AC97_SUPPORTED_MASK; - codec->stereo_mixers = AC97_STEREO_MASK; - codec->record_sources = AC97_RECORD_MASK; - if (!(cap & 0x04)) - codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE); - if (!(cap & 0x10)) - codec->supported_mixers &= ~SOUND_MASK_ALTPCM; - - - /* detect bit resolution */ - codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020); - if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x2020) - codec->bit_resolution = 6; - else - codec->bit_resolution = 5; - - /* generic OSS to AC97 wrapper */ - codec->read_mixer = ac97_read_mixer; - codec->write_mixer = ac97_write_mixer; - codec->recmask_io = ac97_recmask_io; - codec->mixer_ioctl = ac97_mixer_ioctl; - - /* initialize mixer channel volumes */ - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - struct mixer_defaults *md = &mixer_defaults[i]; - if (md->mixer == -1) - break; - if (!supported_mixer(codec, md->mixer)) - continue; - ac97_set_mixer(codec, md->mixer, md->value); - } - - /* codec specific initialization for 4-6 channel output or secondary codec stuff */ - if (codec->codec_ops->init != NULL) { - codec->codec_ops->init(codec); - } - - /* - * Volume is MUTE only on this device. We have to initialise - * it but its useless beyond that. - */ - if(codec->flags & AC97_NO_PCM_VOLUME) - { - codec->supported_mixers &= ~SOUND_MASK_PCM; - printk(KERN_WARNING "AC97 codec does not have proper volume support.\n"); - } - return 1; -} - -#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */ -#define AC97_SIGMATEL_DAC2INVERT 0x6e -#define AC97_SIGMATEL_BIAS1 0x70 -#define AC97_SIGMATEL_BIAS2 0x72 -#define AC97_SIGMATEL_MULTICHN 0x74 /* Multi-Channel programming */ -#define AC97_SIGMATEL_CIC1 0x76 -#define AC97_SIGMATEL_CIC2 0x78 - - -static int sigmatel_9708_init(struct ac97_codec * codec) -{ - u16 codec72, codec6c; - - codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000; - codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG); - - if ((codec72==0) && (codec6c==0)) { - codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000); - codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007); - } else if ((codec72==0x8000) && (codec6c==0)) { - codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001); - codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008); - } else if ((codec72==0x8000) && (codec6c==0x0080)) { - /* nothing */ - } - codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); - return 0; -} - - -static int sigmatel_9721_init(struct ac97_codec * codec) -{ - /* Only set up secondary codec */ - if (codec->id == 0) - return 0; - - codec->codec_write(codec, AC97_SURROUND_MASTER, 0L); - - /* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link - sloc 3,4 = 0x01, slot 7,8 = 0x00, */ - codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00); - - /* we don't have the crystal when we are on an AMR card, so use - BIT_CLK as our clock source. Write the magic word ABBA and read - back to enable register 0x78 */ - codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); - codec->codec_read(codec, AC97_SIGMATEL_CIC1); - - /* sync all the clocks*/ - codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802); - - return 0; -} - - -static int sigmatel_9744_init(struct ac97_codec * codec) -{ - // patch for SigmaTel - codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk - codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); - codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002); - codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); - return 0; -} - -static int cmedia_init(struct ac97_codec *codec) -{ - /* Initialise the CMedia 9739 */ - /* - We could set various options here - Register 0x20 bit 0x100 sets mic as center bass - Also do multi_channel_ctrl &=~0x3000 |=0x1000 - - For now we set up the GPIO and PC beep - */ - - u16 v; - - /* MIC */ - codec->codec_write(codec, 0x64, 0x3000); - v = codec->codec_read(codec, 0x64); - v &= ~0x8000; - codec->codec_write(codec, 0x64, v); - codec->codec_write(codec, 0x70, 0x0100); - codec->codec_write(codec, 0x72, 0x0020); - return 0; -} - -#define AC97_WM97XX_FMIXER_VOL 0x72 -#define AC97_WM97XX_RMIXER_VOL 0x74 -#define AC97_WM97XX_TEST 0x5a -#define AC97_WM9704_RPCM_VOL 0x70 -#define AC97_WM9711_OUT3VOL 0x16 - -static int wolfson_init03(struct ac97_codec * codec) -{ - /* this is known to work for the ViewSonic ViewPad 1000 */ - codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808); - codec->codec_write(codec, AC97_GENERAL_PURPOSE, 0x8000); - return 0; -} - -static int wolfson_init04(struct ac97_codec * codec) -{ - codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808); - codec->codec_write(codec, AC97_WM97XX_RMIXER_VOL, 0x0808); - - // patch for DVD noise - codec->codec_write(codec, AC97_WM97XX_TEST, 0x0200); - - // init vol as PCM vol - codec->codec_write(codec, AC97_WM9704_RPCM_VOL, - codec->codec_read(codec, AC97_PCMOUT_VOL)); - - /* set rear surround volume */ - codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); - return 0; -} - -/* WM9705, WM9710 */ -static int wolfson_init05(struct ac97_codec * codec) -{ - /* set front mixer volume */ - codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808); - return 0; -} - -/* WM9711, WM9712 */ -static int wolfson_init11(struct ac97_codec * codec) -{ - /* stop pop's during suspend/resume */ - codec->codec_write(codec, AC97_WM97XX_TEST, - codec->codec_read(codec, AC97_WM97XX_TEST) & 0xffbf); - - /* set out3 volume */ - codec->codec_write(codec, AC97_WM9711_OUT3VOL, 0x0808); - return 0; -} - -/* WM9713 */ -static int wolfson_init13(struct ac97_codec * codec) -{ - codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0); - codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000); - codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00); - codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810); - codec->codec_write(codec, AC97_PHONE_VOL, 0x0808); - codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808); - - return 0; -} - -static int tritech_init(struct ac97_codec * codec) -{ - codec->codec_write(codec, 0x26, 0x0300); - codec->codec_write(codec, 0x26, 0x0000); - codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); - codec->codec_write(codec, AC97_RESERVED_3A, 0x0000); - return 0; -} - - -/* copied from drivers/sound/maestro.c */ -static int tritech_maestro_init(struct ac97_codec * codec) -{ - /* no idea what this does */ - codec->codec_write(codec, 0x2A, 0x0001); - codec->codec_write(codec, 0x2C, 0x0000); - codec->codec_write(codec, 0x2C, 0XFFFF); - return 0; -} - - - -/* - * Presario700 workaround - * for Jack Sense/SPDIF Register mis-setting causing - * no audible output - * by Santiago Nullo 04/05/2002 - */ - -#define AC97_AD1886_JACK_SENSE 0x72 - -static int ad1886_init(struct ac97_codec * codec) -{ - /* from AD1886 Specs */ - codec->codec_write(codec, AC97_AD1886_JACK_SENSE, 0x0010); - return 0; -} - - - - -/* - * This is basically standard AC97. It should work as a default for - * almost all modern codecs. Note that some cards wire EAPD *backwards* - * That side of it is up to the card driver not us to cope with. - * - */ - -static int eapd_control(struct ac97_codec * codec, int on) -{ - if(on) - codec->codec_write(codec, AC97_POWER_CONTROL, - codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000); - else - codec->codec_write(codec, AC97_POWER_CONTROL, - codec->codec_read(codec, AC97_POWER_CONTROL)&~0x8000); - return 0; -} - -static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode) -{ - u16 reg; - - reg = codec->codec_read(codec, AC97_SPDIF_CONTROL); - - switch(rate) - { - /* Off by default */ - default: - case 0: - reg = codec->codec_read(codec, AC97_EXTENDED_STATUS); - codec->codec_write(codec, AC97_EXTENDED_STATUS, (reg & ~AC97_EA_SPDIF)); - if(rate == 0) - return 0; - return -EINVAL; - case 1: - reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K; - break; - case 2: - reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K; - break; - case 3: - reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K; - break; - } - - reg &= ~AC97_SC_CC_MASK; - reg |= (mode & AUDIO_CCMASK) << 6; - - if(mode & AUDIO_DIGITAL) - reg |= 2; - if(mode & AUDIO_PRO) - reg |= 1; - if(mode & AUDIO_DRS) - reg |= 0x4000; - - codec->codec_write(codec, AC97_SPDIF_CONTROL, reg); - - reg = codec->codec_read(codec, AC97_EXTENDED_STATUS); - reg &= (AC97_EA_SLOT_MASK); - reg |= AC97_EA_VRA | AC97_EA_SPDIF | slots; - codec->codec_write(codec, AC97_EXTENDED_STATUS, reg); - - reg = codec->codec_read(codec, AC97_EXTENDED_STATUS); - if(!(reg & 0x0400)) - { - codec->codec_write(codec, AC97_EXTENDED_STATUS, reg & ~ AC97_EA_SPDIF); - return -EINVAL; - } - return 0; -} - -/* - * Crystal digital audio control (CS4299) - */ - -static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode) -{ - u16 cv; - - if(mode & AUDIO_DIGITAL) - return -EINVAL; - - switch(rate) - { - case 0: cv = 0x0; break; /* SPEN off */ - case 48000: cv = 0x8004; break; /* 48KHz digital */ - case 44100: cv = 0x8104; break; /* 44.1KHz digital */ - case 32768: /* 32Khz */ - default: - return -EINVAL; - } - codec->codec_write(codec, 0x68, cv); - return 0; -} - -/* - * CMedia digital audio control - * Needs more work. - */ - -static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode) -{ - u16 cv; - - if(mode & AUDIO_DIGITAL) - return -EINVAL; - - switch(rate) - { - case 0: cv = 0x0001; break; /* SPEN off */ - case 48000: cv = 0x0009; break; /* 48KHz digital */ - default: - return -EINVAL; - } - codec->codec_write(codec, 0x2A, 0x05c4); - codec->codec_write(codec, 0x6C, cv); - - /* Switch on mix to surround */ - cv = codec->codec_read(codec, 0x64); - cv &= ~0x0200; - if(mode) - cv |= 0x0200; - codec->codec_write(codec, 0x64, cv); - return 0; -} - - -/* copied from drivers/sound/maestro.c */ -#if 0 /* there has been 1 person on the planet with a pt101 that we - know of. If they care, they can put this back in :) */ -static int pt101_init(struct ac97_codec * codec) -{ - printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n"); - /* who knows.. */ - codec->codec_write(codec, 0x2A, 0x0001); - codec->codec_write(codec, 0x2C, 0x0000); - codec->codec_write(codec, 0x2C, 0xFFFF); - codec->codec_write(codec, 0x10, 0x9F1F); - codec->codec_write(codec, 0x12, 0x0808); - codec->codec_write(codec, 0x14, 0x9F1F); - codec->codec_write(codec, 0x16, 0x9F1F); - codec->codec_write(codec, 0x18, 0x0404); - codec->codec_write(codec, 0x1A, 0x0000); - codec->codec_write(codec, 0x1C, 0x0000); - codec->codec_write(codec, 0x02, 0x0404); - codec->codec_write(codec, 0x04, 0x0808); - codec->codec_write(codec, 0x0C, 0x801F); - codec->codec_write(codec, 0x0E, 0x801F); - return 0; -} -#endif - - -EXPORT_SYMBOL(ac97_probe_codec); - -MODULE_LICENSE("GPL"); - diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c deleted file mode 100644 index a8f626d99c5b..000000000000 --- a/sound/oss/au1550_ac97.c +++ /dev/null @@ -1,2147 +0,0 @@ -/* - * au1550_ac97.c -- Sound driver for Alchemy Au1550 MIPS Internet Edge - * Processor. - * - * Copyright 2004 Embedded Edge, LLC - * dan@embeddededge.com - * - * Mostly copied from the au1000.c driver and some from the - * PowerMac dbdma driver. - * We assume the processor can do memory coherent DMA. - * - * Ported to 2.6 by Matt Porter <mporter@kernel.crashing.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#undef DEBUG - -#include <linux/module.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/sound.h> -#include <linux/slab.h> -#include <linux/soundcard.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/poll.h> -#include <linux/bitops.h> -#include <linux/spinlock.h> -#include <linux/ac97_codec.h> -#include <linux/mutex.h> - -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/hardirq.h> -#include <asm/mach-au1x00/au1xxx_psc.h> -#include <asm/mach-au1x00/au1xxx_dbdma.h> -#include <asm/mach-au1x00/au1xxx.h> - -#undef OSS_DOCUMENTED_MIXER_SEMANTICS - -/* misc stuff */ -#define POLL_COUNT 0x50000 -#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC) - -/* The number of DBDMA ring descriptors to allocate. No sense making - * this too large....if you can't keep up with a few you aren't likely - * to be able to with lots of them, either. - */ -#define NUM_DBDMA_DESCRIPTORS 4 - -#define err(format, arg...) printk(KERN_ERR format "\n" , ## arg) - -/* Boot options - * 0 = no VRA, 1 = use VRA if codec supports it - */ -static DEFINE_MUTEX(au1550_ac97_mutex); -static int vra = 1; -module_param(vra, bool, 0); -MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); - -static struct au1550_state { - /* soundcore stuff */ - int dev_audio; - - struct ac97_codec *codec; - unsigned codec_base_caps; /* AC'97 reg 00h, "Reset Register" */ - unsigned codec_ext_caps; /* AC'97 reg 28h, "Extended Audio ID" */ - int no_vra; /* do not use VRA */ - - spinlock_t lock; - struct mutex open_mutex; - struct mutex sem; - fmode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - u32 dmanr; - unsigned sample_rate; - unsigned src_factor; - unsigned sample_size; - int num_channels; - int dma_bytes_per_sample; - int user_bytes_per_sample; - int cnt_factor; - - void *rawbuf; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - void *nextIn; - void *nextOut; - int count; - unsigned total_bytes; - unsigned error; - wait_queue_head_t wait; - - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dma_fragsize; - unsigned dmasize; - unsigned dma_qcount; - - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned stopped:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac, dma_adc; -} au1550_state; - -static unsigned -ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -static void -au1550_delay(int msec) -{ - if (in_interrupt()) - return; - - schedule_timeout_uninterruptible(msecs_to_jiffies(msec)); -} - -static u16 -rdcodec(struct ac97_codec *codec, u8 addr) -{ - struct au1550_state *s = codec->private_data; - unsigned long flags; - u32 cmd, val; - u16 data; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) - err("rdcodec: codec cmd pending expired!"); - - cmd = (u32)PSC_AC97CDC_INDX(addr); - cmd |= PSC_AC97CDC_RD; /* read command */ - au_writel(cmd, PSC_AC97CDC); - au_sync(); - - /* now wait for the data - */ - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) { - err("rdcodec: read poll expired!"); - data = 0; - goto out; - } - - /* wait for command done? - */ - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97EVNT); - au_sync(); - if (val & PSC_AC97EVNT_CD) - break; - } - if (i == POLL_COUNT) { - err("rdcodec: read cmdwait expired!"); - data = 0; - goto out; - } - - data = au_readl(PSC_AC97CDC) & 0xffff; - au_sync(); - - /* Clear command done event. - */ - au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT); - au_sync(); - - out: - spin_unlock_irqrestore(&s->lock, flags); - - return data; -} - - -static void -wrcodec(struct ac97_codec *codec, u8 addr, u16 data) -{ - struct au1550_state *s = codec->private_data; - unsigned long flags; - u32 cmd, val; - int i; - - spin_lock_irqsave(&s->lock, flags); - - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) - err("wrcodec: codec cmd pending expired!"); - - cmd = (u32)PSC_AC97CDC_INDX(addr); - cmd |= (u32)data; - au_writel(cmd, PSC_AC97CDC); - au_sync(); - - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) - err("wrcodec: codec cmd pending expired!"); - - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97EVNT); - au_sync(); - if (val & PSC_AC97EVNT_CD) - break; - } - if (i == POLL_COUNT) - err("wrcodec: read cmdwait expired!"); - - /* Clear command done event. - */ - au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT); - au_sync(); - - spin_unlock_irqrestore(&s->lock, flags); -} - -static void -waitcodec(struct ac97_codec *codec) -{ - u16 temp; - u32 val; - int i; - - /* codec_wait is used to wait for a ready state after - * an AC97C_RESET. - */ - au1550_delay(10); - - /* first poll the CODEC_READY tag bit - */ - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (val & PSC_AC97STAT_CR) - break; - } - if (i == POLL_COUNT) { - err("waitcodec: CODEC_READY poll expired!"); - return; - } - - /* get AC'97 powerdown control/status register - */ - temp = rdcodec(codec, AC97_POWER_CONTROL); - - /* If anything is powered down, power'em up - */ - if (temp & 0x7f00) { - /* Power on - */ - wrcodec(codec, AC97_POWER_CONTROL, 0); - au1550_delay(100); - - /* Reread - */ - temp = rdcodec(codec, AC97_POWER_CONTROL); - } - - /* Check if Codec REF,ANL,DAC,ADC ready - */ - if ((temp & 0x7f0f) != 0x000f) - err("codec reg 26 status (0x%x) not ready!!", temp); -} - -/* stop the ADC before calling */ -static void -set_adc_rate(struct au1550_state *s, unsigned rate) -{ - struct dmabuf *adc = &s->dma_adc; - struct dmabuf *dac = &s->dma_dac; - unsigned adc_rate, dac_rate; - u16 ac97_extstat; - - if (s->no_vra) { - /* calc SRC factor - */ - adc->src_factor = ((96000 / rate) + 1) >> 1; - adc->sample_rate = 48000 / adc->src_factor; - return; - } - - adc->src_factor = 1; - - ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS); - - rate = rate > 48000 ? 48000 : rate; - - /* enable VRA - */ - wrcodec(s->codec, AC97_EXTENDED_STATUS, - ac97_extstat | AC97_EXTSTAT_VRA); - - /* now write the sample rate - */ - wrcodec(s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate); - - /* read it back for actual supported rate - */ - adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE); - - pr_debug("set_adc_rate: set to %d Hz\n", adc_rate); - - /* some codec's don't allow unequal DAC and ADC rates, in which case - * writing one rate reg actually changes both. - */ - dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE); - if (dac->num_channels > 2) - wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate); - if (dac->num_channels > 4) - wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate); - - adc->sample_rate = adc_rate; - dac->sample_rate = dac_rate; -} - -/* stop the DAC before calling */ -static void -set_dac_rate(struct au1550_state *s, unsigned rate) -{ - struct dmabuf *dac = &s->dma_dac; - struct dmabuf *adc = &s->dma_adc; - unsigned adc_rate, dac_rate; - u16 ac97_extstat; - - if (s->no_vra) { - /* calc SRC factor - */ - dac->src_factor = ((96000 / rate) + 1) >> 1; - dac->sample_rate = 48000 / dac->src_factor; - return; - } - - dac->src_factor = 1; - - ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS); - - rate = rate > 48000 ? 48000 : rate; - - /* enable VRA - */ - wrcodec(s->codec, AC97_EXTENDED_STATUS, - ac97_extstat | AC97_EXTSTAT_VRA); - - /* now write the sample rate - */ - wrcodec(s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate); - - /* I don't support different sample rates for multichannel, - * so make these channels the same. - */ - if (dac->num_channels > 2) - wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate); - if (dac->num_channels > 4) - wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate); - /* read it back for actual supported rate - */ - dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE); - - pr_debug("set_dac_rate: set to %d Hz\n", dac_rate); - - /* some codec's don't allow unequal DAC and ADC rates, in which case - * writing one rate reg actually changes both. - */ - adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE); - - dac->sample_rate = dac_rate; - adc->sample_rate = adc_rate; -} - -static void -stop_dac(struct au1550_state *s) -{ - struct dmabuf *db = &s->dma_dac; - u32 stat; - unsigned long flags; - - if (db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - au_writel(PSC_AC97PCR_TP, PSC_AC97PCR); - au_sync(); - - /* Wait for Transmit Busy to show disabled. - */ - do { - stat = au_readl(PSC_AC97STAT); - au_sync(); - } while ((stat & PSC_AC97STAT_TB) != 0); - - au1xxx_dbdma_reset(db->dmanr); - - db->stopped = 1; - - spin_unlock_irqrestore(&s->lock, flags); -} - -static void -stop_adc(struct au1550_state *s) -{ - struct dmabuf *db = &s->dma_adc; - unsigned long flags; - u32 stat; - - if (db->stopped) - return; - - spin_lock_irqsave(&s->lock, flags); - - au_writel(PSC_AC97PCR_RP, PSC_AC97PCR); - au_sync(); - - /* Wait for Receive Busy to show disabled. - */ - do { - stat = au_readl(PSC_AC97STAT); - au_sync(); - } while ((stat & PSC_AC97STAT_RB) != 0); - - au1xxx_dbdma_reset(db->dmanr); - - db->stopped = 1; - - spin_unlock_irqrestore(&s->lock, flags); -} - - -static void -set_xmit_slots(int num_channels) -{ - u32 ac97_config, stat; - - ac97_config = au_readl(PSC_AC97CFG); - au_sync(); - ac97_config &= ~(PSC_AC97CFG_TXSLOT_MASK | PSC_AC97CFG_DE_ENABLE); - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - switch (num_channels) { - case 6: /* stereo with surround and center/LFE, - * slots 3,4,6,7,8,9 - */ - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(6); - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(9); - - case 4: /* stereo with surround, slots 3,4,7,8 */ - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(7); - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(8); - - case 2: /* stereo, slots 3,4 */ - case 1: /* mono */ - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(3); - ac97_config |= PSC_AC97CFG_TXSLOT_ENA(4); - } - - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - ac97_config |= PSC_AC97CFG_DE_ENABLE; - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - /* Wait for Device ready. - */ - do { - stat = au_readl(PSC_AC97STAT); - au_sync(); - } while ((stat & PSC_AC97STAT_DR) == 0); -} - -static void -set_recv_slots(int num_channels) -{ - u32 ac97_config, stat; - - ac97_config = au_readl(PSC_AC97CFG); - au_sync(); - ac97_config &= ~(PSC_AC97CFG_RXSLOT_MASK | PSC_AC97CFG_DE_ENABLE); - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - /* Always enable slots 3 and 4 (stereo). Slot 6 is - * optional Mic ADC, which we don't support yet. - */ - ac97_config |= PSC_AC97CFG_RXSLOT_ENA(3); - ac97_config |= PSC_AC97CFG_RXSLOT_ENA(4); - - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - ac97_config |= PSC_AC97CFG_DE_ENABLE; - au_writel(ac97_config, PSC_AC97CFG); - au_sync(); - - /* Wait for Device ready. - */ - do { - stat = au_readl(PSC_AC97STAT); - au_sync(); - } while ((stat & PSC_AC97STAT_DR) == 0); -} - -/* Hold spinlock for both start_dac() and start_adc() calls */ -static void -start_dac(struct au1550_state *s) -{ - struct dmabuf *db = &s->dma_dac; - - if (!db->stopped) - return; - - set_xmit_slots(db->num_channels); - au_writel(PSC_AC97PCR_TC, PSC_AC97PCR); - au_sync(); - au_writel(PSC_AC97PCR_TS, PSC_AC97PCR); - au_sync(); - - au1xxx_dbdma_start(db->dmanr); - - db->stopped = 0; -} - -static void -start_adc(struct au1550_state *s) -{ - struct dmabuf *db = &s->dma_adc; - int i; - - if (!db->stopped) - return; - - /* Put two buffers on the ring to get things started. - */ - for (i=0; i<2; i++) { - au1xxx_dbdma_put_dest(db->dmanr, virt_to_phys(db->nextIn), - db->dma_fragsize, DDMA_FLAGS_IE); - - db->nextIn += db->dma_fragsize; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; - } - - set_recv_slots(db->num_channels); - au1xxx_dbdma_start(db->dmanr); - au_writel(PSC_AC97PCR_RC, PSC_AC97PCR); - au_sync(); - au_writel(PSC_AC97PCR_RS, PSC_AC97PCR); - au_sync(); - - db->stopped = 0; -} - -static int -prog_dmabuf(struct au1550_state *s, struct dmabuf *db) -{ - unsigned user_bytes_per_sec; - unsigned bufs; - unsigned rate = db->sample_rate; - - if (!db->rawbuf) { - db->ready = db->mapped = 0; - db->buforder = 5; /* 32 * PAGE_SIZE */ - db->rawbuf = kmalloc((PAGE_SIZE << db->buforder), GFP_KERNEL); - if (!db->rawbuf) - return -ENOMEM; - } - - db->cnt_factor = 1; - if (db->sample_size == 8) - db->cnt_factor *= 2; - if (db->num_channels == 1) - db->cnt_factor *= 2; - db->cnt_factor *= db->src_factor; - - db->count = 0; - db->dma_qcount = 0; - db->nextIn = db->nextOut = db->rawbuf; - - db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels; - db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ? - 2 : db->num_channels); - - user_bytes_per_sec = rate * db->user_bytes_per_sample; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < user_bytes_per_sec) - db->fragshift = ld2(user_bytes_per_sec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(user_bytes_per_sec / 100 / - (db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - - db->fragsize = 1 << db->fragshift; - db->dma_fragsize = db->fragsize * db->cnt_factor; - db->numfrag = bufs / db->dma_fragsize; - - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->fragsize = 1 << db->fragshift; - db->dma_fragsize = db->fragsize * db->cnt_factor; - db->numfrag = bufs / db->dma_fragsize; - } - - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - - db->dmasize = db->dma_fragsize * db->numfrag; - memset(db->rawbuf, 0, bufs); - - pr_debug("prog_dmabuf: rate=%d, samplesize=%d, channels=%d\n", - rate, db->sample_size, db->num_channels); - pr_debug("prog_dmabuf: fragsize=%d, cnt_factor=%d, dma_fragsize=%d\n", - db->fragsize, db->cnt_factor, db->dma_fragsize); - pr_debug("prog_dmabuf: numfrag=%d, dmasize=%d\n", db->numfrag, db->dmasize); - - db->ready = 1; - return 0; -} - -static int -prog_dmabuf_adc(struct au1550_state *s) -{ - stop_adc(s); - return prog_dmabuf(s, &s->dma_adc); - -} - -static int -prog_dmabuf_dac(struct au1550_state *s) -{ - stop_dac(s); - return prog_dmabuf(s, &s->dma_dac); -} - - -static void dac_dma_interrupt(int irq, void *dev_id) -{ - struct au1550_state *s = (struct au1550_state *) dev_id; - struct dmabuf *db = &s->dma_dac; - u32 ac97c_stat; - - spin_lock(&s->lock); - - ac97c_stat = au_readl(PSC_AC97STAT); - if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE)) - pr_debug("AC97C status = 0x%08x\n", ac97c_stat); - db->dma_qcount--; - - if (db->count >= db->fragsize) { - if (au1xxx_dbdma_put_source(db->dmanr, - virt_to_phys(db->nextOut), db->fragsize, - DDMA_FLAGS_IE) == 0) { - err("qcount < 2 and no ring room!"); - } - db->nextOut += db->fragsize; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - db->count -= db->fragsize; - db->total_bytes += db->dma_fragsize; - db->dma_qcount++; - } - - /* wake up anybody listening */ - if (waitqueue_active(&db->wait)) - wake_up(&db->wait); - - spin_unlock(&s->lock); -} - - -static void adc_dma_interrupt(int irq, void *dev_id) -{ - struct au1550_state *s = (struct au1550_state *)dev_id; - struct dmabuf *dp = &s->dma_adc; - u32 obytes; - char *obuf; - - spin_lock(&s->lock); - - /* Pull the buffer from the dma queue. - */ - au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes); - - if ((dp->count + obytes) > dp->dmasize) { - /* Overrun. Stop ADC and log the error - */ - spin_unlock(&s->lock); - stop_adc(s); - dp->error++; - err("adc overrun"); - return; - } - - /* Put a new empty buffer on the destination DMA. - */ - au1xxx_dbdma_put_dest(dp->dmanr, virt_to_phys(dp->nextIn), - dp->dma_fragsize, DDMA_FLAGS_IE); - - dp->nextIn += dp->dma_fragsize; - if (dp->nextIn >= dp->rawbuf + dp->dmasize) - dp->nextIn -= dp->dmasize; - - dp->count += obytes; - dp->total_bytes += obytes; - - /* wake up anybody listening - */ - if (waitqueue_active(&dp->wait)) - wake_up(&dp->wait); - - spin_unlock(&s->lock); -} - -static loff_t -au1550_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - - -static int -au1550_open_mixdev(struct inode *inode, struct file *file) -{ - mutex_lock(&au1550_ac97_mutex); - file->private_data = &au1550_state; - mutex_unlock(&au1550_ac97_mutex); - return 0; -} - -static int -au1550_release_mixdev(struct inode *inode, struct file *file) -{ - return 0; -} - -static int -mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, - unsigned long arg) -{ - return codec->mixer_ioctl(codec, cmd, arg); -} - -static long -au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct au1550_state *s = file->private_data; - struct ac97_codec *codec = s->codec; - int ret; - - mutex_lock(&au1550_ac97_mutex); - ret = mixdev_ioctl(codec, cmd, arg); - mutex_unlock(&au1550_ac97_mutex); - - return ret; -} - -static /*const */ struct file_operations au1550_mixer_fops = { - .owner = THIS_MODULE, - .llseek = au1550_llseek, - .unlocked_ioctl = au1550_ioctl_mixdev, - .open = au1550_open_mixdev, - .release = au1550_release_mixdev, -}; - -static int -drain_dac(struct au1550_state *s, int nonblock) -{ - unsigned long flags; - int count, tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped) - return 0; - - for (;;) { - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= s->dma_dac.fragsize) - break; - if (signal_pending(current)) - break; - if (nonblock) - return -EBUSY; - tmo = 1000 * count / (s->no_vra ? - 48000 : s->dma_dac.sample_rate); - tmo /= s->dma_dac.dma_bytes_per_sample; - au1550_delay(tmo); - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static inline u8 S16_TO_U8(s16 ch) -{ - return (u8) (ch >> 8) + 0x80; -} -static inline s16 U8_TO_S16(u8 ch) -{ - return (s16) (ch - 0x80) << 8; -} - -/* - * Translates user samples to dma buffer suitable for AC'97 DAC data: - * If mono, copy left channel to right channel in dma buffer. - * If 8 bit samples, cvt to 16-bit before writing to dma buffer. - * If interpolating (no VRA), duplicate every audio frame src_factor times. - */ -static int -translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf, - int dmacount) -{ - int sample, i; - int interp_bytes_per_sample; - int num_samples; - int mono = (db->num_channels == 1); - char usersample[12]; - s16 ch, dmasample[6]; - - if (db->sample_size == 16 && !mono && db->src_factor == 1) { - /* no translation necessary, just copy - */ - if (copy_from_user(dmabuf, userbuf, dmacount)) - return -EFAULT; - return dmacount; - } - - interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor; - num_samples = dmacount / interp_bytes_per_sample; - - for (sample = 0; sample < num_samples; sample++) { - if (copy_from_user(usersample, userbuf, - db->user_bytes_per_sample)) { - return -EFAULT; - } - - for (i = 0; i < db->num_channels; i++) { - if (db->sample_size == 8) - ch = U8_TO_S16(usersample[i]); - else - ch = *((s16 *) (&usersample[i * 2])); - dmasample[i] = ch; - if (mono) - dmasample[i + 1] = ch; /* right channel */ - } - - /* duplicate every audio frame src_factor times - */ - for (i = 0; i < db->src_factor; i++) - memcpy(dmabuf, dmasample, db->dma_bytes_per_sample); - - userbuf += db->user_bytes_per_sample; - dmabuf += interp_bytes_per_sample; - } - - return num_samples * interp_bytes_per_sample; -} - -/* - * Translates AC'97 ADC samples to user buffer: - * If mono, send only left channel to user buffer. - * If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer. - * If decimating (no VRA), skip over src_factor audio frames. - */ -static int -translate_to_user(struct dmabuf *db, char* userbuf, char* dmabuf, - int dmacount) -{ - int sample, i; - int interp_bytes_per_sample; - int num_samples; - int mono = (db->num_channels == 1); - char usersample[12]; - - if (db->sample_size == 16 && !mono && db->src_factor == 1) { - /* no translation necessary, just copy - */ - if (copy_to_user(userbuf, dmabuf, dmacount)) - return -EFAULT; - return dmacount; - } - - interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor; - num_samples = dmacount / interp_bytes_per_sample; - - for (sample = 0; sample < num_samples; sample++) { - for (i = 0; i < db->num_channels; i++) { - if (db->sample_size == 8) - usersample[i] = - S16_TO_U8(*((s16 *) (&dmabuf[i * 2]))); - else - *((s16 *) (&usersample[i * 2])) = - *((s16 *) (&dmabuf[i * 2])); - } - - if (copy_to_user(userbuf, usersample, - db->user_bytes_per_sample)) { - return -EFAULT; - } - - userbuf += db->user_bytes_per_sample; - dmabuf += interp_bytes_per_sample; - } - - return num_samples * interp_bytes_per_sample; -} - -/* - * Copy audio data to/from user buffer from/to dma buffer, taking care - * that we wrap when reading/writing the dma buffer. Returns actual byte - * count written to or read from the dma buffer. - */ -static int -copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user) -{ - char *bufptr = to_user ? db->nextOut : db->nextIn; - char *bufend = db->rawbuf + db->dmasize; - int cnt, ret; - - if (bufptr + count > bufend) { - int partial = (int) (bufend - bufptr); - if (to_user) { - if ((cnt = translate_to_user(db, userbuf, - bufptr, partial)) < 0) - return cnt; - ret = cnt; - if ((cnt = translate_to_user(db, userbuf + partial, - db->rawbuf, - count - partial)) < 0) - return cnt; - ret += cnt; - } else { - if ((cnt = translate_from_user(db, bufptr, userbuf, - partial)) < 0) - return cnt; - ret = cnt; - if ((cnt = translate_from_user(db, db->rawbuf, - userbuf + partial, - count - partial)) < 0) - return cnt; - ret += cnt; - } - } else { - if (to_user) - ret = translate_to_user(db, userbuf, bufptr, count); - else - ret = translate_from_user(db, bufptr, userbuf, count); - } - - return ret; -} - - -static ssize_t -au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -{ - struct au1550_state *s = file->private_data; - struct dmabuf *db = &s->dma_adc; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - int cnt, usercnt, avail; - - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - - count *= db->cnt_factor; - - mutex_lock(&s->sem); - add_wait_queue(&db->wait, &wait); - - while (count > 0) { - /* wait for samples in ADC dma buffer - */ - do { - spin_lock_irqsave(&s->lock, flags); - if (db->stopped) - start_adc(s); - avail = db->count; - if (avail <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - } - } while (avail <= 0); - - /* copy from nextOut to user - */ - if ((cnt = copy_dmabuf_user(db, buffer, - count > avail ? - avail : count, 1)) < 0) { - if (!ret) - ret = -EFAULT; - goto out; - } - - spin_lock_irqsave(&s->lock, flags); - db->count -= cnt; - db->nextOut += cnt; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - spin_unlock_irqrestore(&s->lock, flags); - - count -= cnt; - usercnt = cnt / db->cnt_factor; - buffer += usercnt; - ret += usercnt; - } /* while (count > 0) */ - -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&db->wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static ssize_t -au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) -{ - struct au1550_state *s = file->private_data; - struct dmabuf *db = &s->dma_dac; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - int cnt, usercnt, avail; - - pr_debug("write: count=%d\n", count); - - if (db->mapped) - return -ENXIO; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - - count *= db->cnt_factor; - - mutex_lock(&s->sem); - add_wait_queue(&db->wait, &wait); - - while (count > 0) { - /* wait for space in playback buffer - */ - do { - spin_lock_irqsave(&s->lock, flags); - avail = (int) db->dmasize - db->count; - if (avail <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (avail <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - } - } while (avail <= 0); - - /* copy from user to nextIn - */ - if ((cnt = copy_dmabuf_user(db, (char *) buffer, - count > avail ? - avail : count, 0)) < 0) { - if (!ret) - ret = -EFAULT; - goto out; - } - - spin_lock_irqsave(&s->lock, flags); - db->count += cnt; - db->nextIn += cnt; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; - - /* If the data is available, we want to keep two buffers - * on the dma queue. If the queue count reaches zero, - * we know the dma has stopped. - */ - while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) { - if (au1xxx_dbdma_put_source(db->dmanr, - virt_to_phys(db->nextOut), db->fragsize, - DDMA_FLAGS_IE) == 0) { - err("qcount < 2 and no ring room!"); - } - db->nextOut += db->fragsize; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - db->total_bytes += db->dma_fragsize; - if (db->dma_qcount == 0) - start_dac(s); - db->dma_qcount++; - } - spin_unlock_irqrestore(&s->lock, flags); - - count -= cnt; - usercnt = cnt / db->cnt_factor; - buffer += usercnt; - ret += usercnt; - } /* while (count > 0) */ - -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&db->wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - - -/* No kernel lock - we have our own spinlock */ -static unsigned int -au1550_poll(struct file *file, struct poll_table_struct *wait) -{ - struct au1550_state *s = file->private_data; - unsigned long flags; - unsigned int mask = 0; - - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready) - return 0; - poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - - spin_lock_irqsave(&s->lock, flags); - - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= - (signed)s->dma_dac.dma_fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed) s->dma_dac.dmasize >= - s->dma_dac.count + (signed)s->dma_dac.dma_fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int -au1550_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct au1550_state *s = file->private_data; - struct dmabuf *db; - unsigned long size; - int ret = 0; - - mutex_lock(&au1550_ac97_mutex); - mutex_lock(&s->sem); - if (vma->vm_flags & VM_WRITE) - db = &s->dma_dac; - else if (vma->vm_flags & VM_READ) - db = &s->dma_adc; - else { - ret = -EINVAL; - goto out; - } - if (vma->vm_pgoff != 0) { - ret = -EINVAL; - goto out; - } - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) { - ret = -EINVAL; - goto out; - } - if (remap_pfn_range(vma, vma->vm_start, page_to_pfn(virt_to_page(db->rawbuf)), - size, vma->vm_page_prot)) { - ret = -EAGAIN; - goto out; - } - vma->vm_flags &= ~VM_IO; - db->mapped = 1; -out: - mutex_unlock(&s->sem); - mutex_unlock(&au1550_ac97_mutex); - return ret; -} - -#ifdef DEBUG -static struct ioctl_str_t { - unsigned int cmd; - const char *str; -} ioctl_str[] = { - {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"}, - {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"}, - {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"}, - {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"}, - {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"}, - {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"}, - {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"}, - {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"}, - {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"}, - {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"}, - {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"}, - {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"}, - {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"}, - {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"}, - {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"}, - {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"}, - {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"}, - {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"}, - {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"}, - {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"}, - {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"}, - {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"}, - {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"}, - {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"}, - {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"}, - {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"}, - {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"}, - {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"}, - {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"}, - {OSS_GETVERSION, "OSS_GETVERSION"}, - {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"}, - {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"}, - {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"}, - {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"} -}; -#endif - -static int -dma_count_done(struct dmabuf *db) -{ - if (db->stopped) - return 0; - - return db->dma_fragsize - au1xxx_get_dma_residue(db->dmanr); -} - - -static int -au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct au1550_state *s = file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, mapped, ret, diff; - - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - -#ifdef DEBUG - for (count = 0; count < ARRAY_SIZE(ioctl_str); count++) { - if (ioctl_str[count].cmd == cmd) - break; - } - if (count < ARRAY_SIZE(ioctl_str)) - pr_debug("ioctl %s, arg=0x%lxn", ioctl_str[count].str, arg); - else - pr_debug("ioctl 0x%x unknown, arg=0x%lx\n", cmd, arg); -#endif - - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, (int *) arg); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, file->f_flags & O_NONBLOCK); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | - DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(); - s->dma_dac.count = s->dma_dac.total_bytes = 0; - s->dma_dac.nextIn = s->dma_dac.nextOut = - s->dma_dac.rawbuf; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(); - s->dma_adc.count = s->dma_adc.total_bytes = 0; - s->dma_adc.nextIn = s->dma_adc.nextOut = - s->dma_adc.rawbuf; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - set_adc_rate(s, val); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - set_dac_rate(s, val); - } - if (s->open_mode & FMODE_READ) - if ((ret = prog_dmabuf_adc(s))) - return ret; - if (s->open_mode & FMODE_WRITE) - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return put_user((file->f_mode & FMODE_READ) ? - s->dma_adc.sample_rate : - s->dma_dac.sample_rate, - (int *)arg); - - case SNDCTL_DSP_STEREO: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.num_channels = val ? 2 : 1; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.num_channels = val ? 2 : 1; - if (s->codec_ext_caps & AC97_EXT_DACS) { - /* disable surround and center/lfe in AC'97 - */ - u16 ext_stat = rdcodec(s->codec, - AC97_EXTENDED_STATUS); - wrcodec(s->codec, AC97_EXTENDED_STATUS, - ext_stat | (AC97_EXTSTAT_PRI | - AC97_EXTSTAT_PRJ | - AC97_EXTSTAT_PRK)); - } - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_READ) { - if (val < 0 || val > 2) - return -EINVAL; - stop_adc(s); - s->dma_adc.num_channels = val; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - switch (val) { - case 1: - case 2: - break; - case 3: - case 5: - return -EINVAL; - case 4: - if (!(s->codec_ext_caps & - AC97_EXTID_SDAC)) - return -EINVAL; - break; - case 6: - if ((s->codec_ext_caps & - AC97_EXT_DACS) != AC97_EXT_DACS) - return -EINVAL; - break; - default: - return -EINVAL; - } - - stop_dac(s); - if (val <= 2 && - (s->codec_ext_caps & AC97_EXT_DACS)) { - /* disable surround and center/lfe - * channels in AC'97 - */ - u16 ext_stat = - rdcodec(s->codec, - AC97_EXTENDED_STATUS); - wrcodec(s->codec, - AC97_EXTENDED_STATUS, - ext_stat | (AC97_EXTSTAT_PRI | - AC97_EXTSTAT_PRJ | - AC97_EXTSTAT_PRK)); - } else if (val >= 4) { - /* enable surround, center/lfe - * channels in AC'97 - */ - u16 ext_stat = - rdcodec(s->codec, - AC97_EXTENDED_STATUS); - ext_stat &= ~AC97_EXTSTAT_PRJ; - if (val == 6) - ext_stat &= - ~(AC97_EXTSTAT_PRI | - AC97_EXTSTAT_PRK); - wrcodec(s->codec, - AC97_EXTENDED_STATUS, - ext_stat); - } - - s->dma_dac.num_channels = val; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } - return put_user(val, (int *) arg); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - if (val == AFMT_S16_LE) - s->dma_adc.sample_size = 16; - else { - val = AFMT_U8; - s->dma_adc.sample_size = 8; - } - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - if (val == AFMT_S16_LE) - s->dma_dac.sample_size = 16; - else { - val = AFMT_U8; - s->dma_dac.sample_size = 8; - } - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - } else { - if (file->f_mode & FMODE_READ) - val = (s->dma_adc.sample_size == 16) ? - AFMT_S16_LE : AFMT_U8; - else - val = (s->dma_dac.sample_size == 16) ? - AFMT_S16_LE : AFMT_U8; - } - return put_user(val, (int *) arg); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ && !s->dma_adc.stopped) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped) - val |= PCM_ENABLE_OUTPUT; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, (int *) arg); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - spin_lock_irqsave(&s->lock, flags); - start_adc(s); - spin_unlock_irqrestore(&s->lock, flags); - } else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - spin_lock_irqsave(&s->lock, flags); - start_dac(s); - spin_unlock_irqrestore(&s->lock, flags); - } else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - abinfo.fragsize = s->dma_dac.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - count -= dma_count_done(&s->dma_dac); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = (s->dma_dac.dmasize - count) / - s->dma_dac.cnt_factor; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - pr_debug("ioctl SNDCTL_DSP_GETOSPACE: bytes=%d, fragments=%d\n", abinfo.bytes, abinfo.fragments); - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - abinfo.fragsize = s->dma_adc.fragsize; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_adc.count; - count += dma_count_done(&s->dma_adc); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - abinfo.bytes = count / s->dma_adc.cnt_factor; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - return copy_to_user((void *) arg, &abinfo, - sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - spin_lock(&file->f_lock); - file->f_flags |= O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - count -= dma_count_done(&s->dma_dac); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - count /= s->dma_dac.cnt_factor; - return put_user(count, (int *) arg); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_adc.count; - if (!s->dma_adc.stopped) { - diff = dma_count_done(&s->dma_adc); - count += diff; - cinfo.bytes += diff; - cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) + diff - - virt_to_phys(s->dma_adc.rawbuf); - } else - cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) - - virt_to_phys(s->dma_adc.rawbuf); - if (s->dma_adc.mapped) - s->dma_adc.count &= (s->dma_adc.dma_fragsize-1); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_adc.fragshift; - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&s->lock, flags); - cinfo.bytes = s->dma_dac.total_bytes; - count = s->dma_dac.count; - if (!s->dma_dac.stopped) { - diff = dma_count_done(&s->dma_dac); - count -= diff; - cinfo.bytes += diff; - cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff - - virt_to_phys(s->dma_dac.rawbuf); - } else - cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) - - virt_to_phys(s->dma_dac.rawbuf); - if (s->dma_dac.mapped) - s->dma_dac.count &= (s->dma_dac.dma_fragsize-1); - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac.fragshift; - return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) - return put_user(s->dma_dac.fragsize, (int *) arg); - else - return put_user(s->dma_adc.fragsize, (int *) arg); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (int *) arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, (int *) arg)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.subdivision = val; - if ((ret = prog_dmabuf_adc(s))) - return ret; - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.subdivision = val; - if ((ret = prog_dmabuf_dac(s))) - return ret; - } - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? - s->dma_adc.sample_rate : - s->dma_dac.sample_rate, - (int *)arg); - - case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_READ) - return put_user(s->dma_adc.num_channels, (int *)arg); - else - return put_user(s->dma_dac.num_channels, (int *)arg); - - case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_READ) - return put_user(s->dma_adc.sample_size, (int *)arg); - else - return put_user(s->dma_dac.sample_size, (int *)arg); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } - - return mixdev_ioctl(s->codec, cmd, arg); -} - -static long -au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&au1550_ac97_mutex); - ret = au1550_ioctl(file, cmd, arg); - mutex_unlock(&au1550_ac97_mutex); - - return ret; -} - -static int -au1550_open(struct inode *inode, struct file *file) -{ - int minor = MINOR(inode->i_rdev); - DECLARE_WAITQUEUE(wait, current); - struct au1550_state *s = &au1550_state; - int ret; - -#ifdef DEBUG - if (file->f_flags & O_NONBLOCK) - pr_debug("open: non-blocking\n"); - else - pr_debug("open: blocking\n"); -#endif - - file->private_data = s; - mutex_lock(&au1550_ac97_mutex); - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - ret = -EBUSY; - if (file->f_flags & O_NONBLOCK) - goto out; - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - ret = -ERESTARTSYS; - if (signal_pending(current)) - goto out2; - mutex_lock(&s->open_mutex); - } - - stop_dac(s); - stop_adc(s); - - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = - s->dma_adc.subdivision = s->dma_adc.total_bytes = 0; - s->dma_adc.num_channels = 1; - s->dma_adc.sample_size = 8; - set_adc_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->dma_adc.sample_size = 16; - } - - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = - s->dma_dac.subdivision = s->dma_dac.total_bytes = 0; - s->dma_dac.num_channels = 1; - s->dma_dac.sample_size = 8; - set_dac_rate(s, 8000); - if ((minor & 0xf) == SND_DEV_DSP16) - s->dma_dac.sample_size = 16; - } - - if (file->f_mode & FMODE_READ) { - if ((ret = prog_dmabuf_adc(s))) - goto out; - } - if (file->f_mode & FMODE_WRITE) { - if ((ret = prog_dmabuf_dac(s))) - goto out; - } - - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_init(&s->sem); - ret = 0; -out: - mutex_unlock(&s->open_mutex); -out2: - mutex_unlock(&au1550_ac97_mutex); - return ret; -} - -static int -au1550_release(struct inode *inode, struct file *file) -{ - struct au1550_state *s = file->private_data; - - mutex_lock(&au1550_ac97_mutex); - - if (file->f_mode & FMODE_WRITE) { - mutex_unlock(&au1550_ac97_mutex); - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&au1550_ac97_mutex); - } - - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - kfree(s->dma_dac.rawbuf); - s->dma_dac.rawbuf = NULL; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - kfree(s->dma_adc.rawbuf); - s->dma_adc.rawbuf = NULL; - } - s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - mutex_unlock(&au1550_ac97_mutex); - return 0; -} - -static /*const */ struct file_operations au1550_audio_fops = { - .owner = THIS_MODULE, - .llseek = au1550_llseek, - .read = au1550_read, - .write = au1550_write, - .poll = au1550_poll, - .unlocked_ioctl = au1550_unlocked_ioctl, - .mmap = au1550_mmap, - .open = au1550_open, - .release = au1550_release, -}; - -MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com"); -MODULE_DESCRIPTION("Au1550 AC97 Audio Driver"); -MODULE_LICENSE("GPL"); - - -static int __devinit -au1550_probe(void) -{ - struct au1550_state *s = &au1550_state; - int val; - - memset(s, 0, sizeof(struct au1550_state)); - - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - - s->codec = ac97_alloc_codec(); - if(s->codec == NULL) { - err("Out of memory"); - return -1; - } - s->codec->private_data = s; - s->codec->id = 0; - s->codec->codec_read = rdcodec; - s->codec->codec_write = wrcodec; - s->codec->codec_wait = waitcodec; - - if (!request_mem_region(CPHYSADDR(AC97_PSC_SEL), - 0x30, "Au1550 AC97")) { - err("AC'97 ports in use"); - } - - /* Allocate the DMA Channels - */ - if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN, - DBDMA_AC97_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) { - err("Can't get DAC DMA"); - goto err_dma1; - } - au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16); - if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr, - NUM_DBDMA_DESCRIPTORS) == 0) { - err("Can't get DAC DMA descriptors"); - goto err_dma1; - } - - if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_AC97_RX_CHAN, - DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) { - err("Can't get ADC DMA"); - goto err_dma2; - } - au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16); - if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr, - NUM_DBDMA_DESCRIPTORS) == 0) { - err("Can't get ADC DMA descriptors"); - goto err_dma2; - } - - pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_AC97_TX_CHAN, DBDMA_AC97_RX_CHAN); - - /* register devices */ - - if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0) - goto err_dev1; - if ((s->codec->dev_mixer = - register_sound_mixer(&au1550_mixer_fops, -1)) < 0) - goto err_dev2; - - /* The GPIO for the appropriate PSC was configured by the - * board specific start up. - * - * configure PSC for AC'97 - */ - au_writel(0, AC97_PSC_CTRL); /* Disable PSC */ - au_sync(); - au_writel((PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE), AC97_PSC_SEL); - au_sync(); - - /* cold reset the AC'97 - */ - au_writel(PSC_AC97RST_RST, PSC_AC97RST); - au_sync(); - au1550_delay(10); - au_writel(0, PSC_AC97RST); - au_sync(); - - /* need to delay around 500msec(bleech) to give - some CODECs enough time to wakeup */ - au1550_delay(500); - - /* warm reset the AC'97 to start the bitclk - */ - au_writel(PSC_AC97RST_SNC, PSC_AC97RST); - au_sync(); - udelay(100); - au_writel(0, PSC_AC97RST); - au_sync(); - - /* Enable PSC - */ - au_writel(PSC_CTRL_ENABLE, AC97_PSC_CTRL); - au_sync(); - - /* Wait for PSC ready. - */ - do { - val = au_readl(PSC_AC97STAT); - au_sync(); - } while ((val & PSC_AC97STAT_SR) == 0); - - /* Configure AC97 controller. - * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size. - */ - val = PSC_AC97CFG_SET_LEN(16); - val |= PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8; - - /* Enable device so we can at least - * talk over the AC-link. - */ - au_writel(val, PSC_AC97CFG); - au_writel(PSC_AC97MSK_ALLMASK, PSC_AC97MSK); - au_sync(); - val |= PSC_AC97CFG_DE_ENABLE; - au_writel(val, PSC_AC97CFG); - au_sync(); - - /* Wait for Device ready. - */ - do { - val = au_readl(PSC_AC97STAT); - au_sync(); - } while ((val & PSC_AC97STAT_DR) == 0); - - /* codec init */ - if (!ac97_probe_codec(s->codec)) - goto err_dev3; - - s->codec_base_caps = rdcodec(s->codec, AC97_RESET); - s->codec_ext_caps = rdcodec(s->codec, AC97_EXTENDED_ID); - pr_info("AC'97 Base/Extended ID = %04x/%04x", - s->codec_base_caps, s->codec_ext_caps); - - if (!(s->codec_ext_caps & AC97_EXTID_VRA)) { - /* codec does not support VRA - */ - s->no_vra = 1; - } else if (!vra) { - /* Boot option says disable VRA - */ - u16 ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS); - wrcodec(s->codec, AC97_EXTENDED_STATUS, - ac97_extstat & ~AC97_EXTSTAT_VRA); - s->no_vra = 1; - } - if (s->no_vra) - pr_info("no VRA, interpolating and decimating"); - - /* set mic to be the recording source */ - val = SOUND_MASK_MIC; - mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC, - (unsigned long) &val); - - return 0; - - err_dev3: - unregister_sound_mixer(s->codec->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - au1xxx_dbdma_chan_free(s->dma_adc.dmanr); - err_dma2: - au1xxx_dbdma_chan_free(s->dma_dac.dmanr); - err_dma1: - release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30); - - ac97_release_codec(s->codec); - return -1; -} - -static void __devinit -au1550_remove(void) -{ - struct au1550_state *s = &au1550_state; - - if (!s) - return; - synchronize_irq(); - au1xxx_dbdma_chan_free(s->dma_adc.dmanr); - au1xxx_dbdma_chan_free(s->dma_dac.dmanr); - release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->codec->dev_mixer); - ac97_release_codec(s->codec); -} - -static int __init -init_au1550(void) -{ - return au1550_probe(); -} - -static void __exit -cleanup_au1550(void) -{ - au1550_remove(); -} - -module_init(init_au1550); -module_exit(cleanup_au1550); - -#ifndef MODULE - -static int __init -au1550_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ","))) { - if (!*this_opt) - continue; - if (!strncmp(this_opt, "vra", 3)) { - vra = 1; - } - } - - return 1; -} - -__setup("au1550_audio=", au1550_setup); - -#endif /* MODULE */ diff --git a/sound/oss/audio.c b/sound/oss/audio.c index 7df48a25c4ee..4b958b1c497c 100644 --- a/sound/oss/audio.c +++ b/sound/oss/audio.c @@ -514,7 +514,7 @@ int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg) count += dmap->bytes_in_use; /* Pointer wrap not handled yet */ count += dmap->byte_counter; - /* Substract current count from the number of bytes written by app */ + /* Subtract current count from the number of bytes written by app */ count = dmap->user_counter - count; if (count < 0) count = 0; @@ -931,7 +931,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg) if (count < dmap_out->fragment_size && dmap_out->qhead != 0) count += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ count += dmap_out->byte_counter; - /* Substract current count from the number of bytes written by app */ + /* Subtract current count from the number of bytes written by app */ count = dmap_out->user_counter - count; if (count < 0) count = 0; diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 87e2c72651f5..c918313c2206 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -1021,7 +1021,7 @@ static int sq_ioctl(struct file *file, u_int cmd, u_long arg) case SNDCTL_DSP_SYNC: /* This call, effectively, has the same behaviour as SNDCTL_DSP_RESET except that it waits for output to finish before resetting - everything - read, however, is killed imediately. + everything - read, however, is killed immediately. */ result = 0 ; if (file->f_mode & FMODE_WRITE) { diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c index ceedb1eff203..8cdb2cfe65c8 100644 --- a/sound/oss/midibuf.c +++ b/sound/oss/midibuf.c @@ -295,7 +295,7 @@ int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count) for (i = 0; i < n; i++) { - /* BROKE BROKE BROKE - CANT DO THIS WITH CLI !! */ + /* BROKE BROKE BROKE - CAN'T DO THIS WITH CLI !! */ /* yes, think the same, so I removed the cli() brackets QUEUE_BYTE is protected against interrupts */ if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) { diff --git a/sound/oss/sb_card.c b/sound/oss/sb_card.c index 84ef4d06c1c2..fb5d7250de38 100644 --- a/sound/oss/sb_card.c +++ b/sound/oss/sb_card.c @@ -1,7 +1,7 @@ /* * sound/oss/sb_card.c * - * Detection routine for the ISA Sound Blaster and compatable sound + * Detection routine for the ISA Sound Blaster and compatible sound * cards. * * This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c index 9890cf2066ff..5c773dff5ac5 100644 --- a/sound/oss/sb_ess.c +++ b/sound/oss/sb_ess.c @@ -168,7 +168,7 @@ * corresponding playback levels, unless recmask says they aren't recorded. In * the latter case the recording volumes are 0. * Now recording levels of inputs can be controlled, by changing the playback - * levels. Futhermore several devices can be recorded together (which is not + * levels. Furthermore several devices can be recorded together (which is not * possible with the ES1688). * Besides the separate recording level control for each input, the common * recording level can also be controlled by RECLEV as described above. diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index 44357d877a27..09d46484bc1a 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c @@ -875,7 +875,7 @@ static void start_adc(struct cs4297a_state *s) if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) { // // now only use 16 bit capture, due to truncation issue - // in the chip, noticable distortion occurs. + // in the chip, noticeable distortion occurs. // allocate buffer and then convert from 16 bit to // 8 bit for the user buffer. // diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c index f0e0caa53200..12ba28e7b933 100644 --- a/sound/oss/vidc.c +++ b/sound/oss/vidc.c @@ -227,7 +227,7 @@ static int vidc_audio_set_speed(int dev, int rate) } else { /*printk("VIDC: internal %d %d %d\n", rate, rate_int, hwrate);*/ hwctrl=0x00000003; - /* Allow rougly 0.4% tolerance */ + /* Allow roughly 0.4% tolerance */ if (diff_int > (rate/256)) rate=rate_int; } diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 389cd7931668..e90d103e177e 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -534,6 +534,14 @@ config SND_ES1968_INPUT If you say N the buttons will directly control the master volume. It is recommended to say Y. +config SND_ES1968_RADIO + bool "Enable TEA5757 radio tuner support for es1968" + depends on SND_ES1968 + depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_ES1968 + help + Say Y here to include support for TEA5757 radio tuner integrated on + some MediaForte cards (e.g. SF64-PCE2). + config SND_FM801 tristate "ForteMedia FM801" select SND_OPL3_LIB @@ -552,13 +560,13 @@ config SND_FM801_TEA575X_BOOL depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801 help Say Y here to include support for soundcards based on the ForteMedia - FM801 chip with a TEA5757 tuner connected to GPIO1-3 pins (Media - Forte SF256-PCS-02) into the snd-fm801 driver. + FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and + SF64-PCR) into the snd-fm801 driver. -config SND_FM801_TEA575X +config SND_TEA575X tristate - depends on SND_FM801_TEA575X_BOOL - default SND_FM801 + depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO + default SND_FM801 || SND_ES1968 source "sound/pci/hda/Kconfig" @@ -658,6 +666,15 @@ config SND_KORG1212 To compile this driver as a module, choose M here: the module will be called snd-korg1212. +config SND_LOLA + tristate "Digigram Lola" + select SND_PCM + help + Say Y to include support for Digigram Lola boards. + + To compile this driver as a module, choose M here: the module + will be called snd-lola. + config SND_LX6464ES tristate "Digigram LX6464ES" select SND_PCM diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 9cf4348ec137..54fe325e3aa5 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_SND) += \ ca0106/ \ cs46xx/ \ cs5535audio/ \ + lola/ \ lx6464es/ \ echoaudio/ \ emu10k1/ \ diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 4382d0fa6b9a..d8f6fd65ebbb 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -29,7 +29,7 @@ * PM support * MIDI support * Game Port support - * SG DMA support (this will need *alot* of work) + * SG DMA support (this will need *a lot* of work) */ #include <linux/init.h> diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index f53a31e939c1..2ca6f4f85b41 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -42,10 +42,29 @@ #include <sound/tlv.h> #include <sound/hwdep.h> + MODULE_LICENSE("GPL"); MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); +#if defined CONFIG_SND_DEBUG +/* copied from pcm_lib.c, hope later patch will make that version public +and this copy can be removed */ +static void pcm_debug_name(struct snd_pcm_substream *substream, + char *name, size_t len) +{ + snprintf(name, len, "pcmC%dD%d%c:%d", + substream->pcm->card->number, + substream->pcm->device, + substream->stream ? 'c' : 'p', + substream->number); +} +#define DEBUG_NAME(substream, name) char name[16]; pcm_debug_name(substream, name, sizeof(name)) +#else +#define pcm_debug_name(s, n, l) do { } while (0) +#define DEBUG_NAME(name, substream) do { } while (0) +#endif + #if defined CONFIG_SND_DEBUG_VERBOSE /** * snd_printddd - very verbose debug printk @@ -58,7 +77,7 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); #define snd_printddd(format, args...) \ __snd_printk(3, __FILE__, __LINE__, format, ##args) #else -#define snd_printddd(format, args...) do { } while (0) +#define snd_printddd(format, args...) do { } while (0) #endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */ @@ -101,13 +120,6 @@ static int adapter_fs = DEFAULT_SAMPLERATE; #define PERIOD_BYTES_MIN 2048 #define BUFFER_BYTES_MAX (512 * 1024) -/* convert stream to character */ -#define SCHR(s) ((s == SNDRV_PCM_STREAM_PLAYBACK) ? 'P' : 'C') - -/*#define TIMER_MILLISECONDS 20 -#define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000) -*/ - #define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7) struct clk_source { @@ -136,7 +148,7 @@ struct snd_card_asihpi { u32 h_mixer; struct clk_cache cc; - u16 support_mmap; + u16 can_dma; u16 support_grouping; u16 support_mrx; u16 update_interval_frames; @@ -155,6 +167,7 @@ struct snd_card_asihpi_pcm { unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */ unsigned int pcm_buf_dma_ofs; /* DMA R/W offset in buffer */ unsigned int pcm_buf_elapsed_dma_ofs; /* DMA R/W offset in buffer */ + unsigned int drained_count; struct snd_pcm_substream *substream; u32 h_stream; struct hpi_format format; @@ -288,19 +301,26 @@ static u16 handle_error(u16 err, int line, char *filename) #define hpi_handle_error(x) handle_error(x, __LINE__, __FILE__) /***************************** GENERAL PCM ****************/ -static void print_hwparams(struct snd_pcm_hw_params *p) + +static void print_hwparams(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *p) { - snd_printd("HWPARAMS \n"); - snd_printd("samplerate %d \n", params_rate(p)); - snd_printd("Channels %d \n", params_channels(p)); - snd_printd("Format %d \n", params_format(p)); - snd_printd("subformat %d \n", params_subformat(p)); - snd_printd("Buffer bytes %d \n", params_buffer_bytes(p)); - snd_printd("Period bytes %d \n", params_period_bytes(p)); - snd_printd("access %d \n", params_access(p)); - snd_printd("period_size %d \n", params_period_size(p)); - snd_printd("periods %d \n", params_periods(p)); - snd_printd("buffer_size %d \n", params_buffer_size(p)); + DEBUG_NAME(substream, name); + snd_printd("%s HWPARAMS\n", name); + snd_printd(" samplerate %d Hz\n", params_rate(p)); + snd_printd(" channels %d\n", params_channels(p)); + snd_printd(" format %d\n", params_format(p)); + snd_printd(" subformat %d\n", params_subformat(p)); + snd_printd(" buffer %d B\n", params_buffer_bytes(p)); + snd_printd(" period %d B\n", params_period_bytes(p)); + snd_printd(" access %d\n", params_access(p)); + snd_printd(" period_size %d\n", params_period_size(p)); + snd_printd(" periods %d\n", params_periods(p)); + snd_printd(" buffer_size %d\n", params_buffer_size(p)); + snd_printd(" %d B/s\n", params_rate(p) * + params_channels(p) * + snd_pcm_format_width(params_format(p)) / 8); + } static snd_pcm_format_t hpi_to_alsa_formats[] = { @@ -451,7 +471,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, int width; unsigned int bytes_per_sec; - print_hwparams(params); + print_hwparams(substream, params); err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (err < 0) return err; @@ -459,10 +479,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, if (err) return err; - snd_printdd("format %d, %d chans, %d_hz\n", - format, params_channels(params), - params_rate(params)); - hpi_handle_error(hpi_format_create(&dpcm->format, params_channels(params), format, params_rate(params), 0, 0)); @@ -477,8 +493,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, } dpcm->hpi_buffer_attached = 0; - if (card->support_mmap) { - + if (card->can_dma) { err = hpi_stream_host_buffer_attach(dpcm->h_stream, params_buffer_bytes(params), runtime->dma_addr); if (err == 0) { @@ -509,8 +524,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, dpcm->bytes_per_sec = bytes_per_sec; dpcm->buffer_bytes = params_buffer_bytes(params); dpcm->period_bytes = params_period_bytes(params); - snd_printdd("buffer_bytes=%d, period_bytes=%d, bps=%d\n", - dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec); return 0; } @@ -564,9 +577,10 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); struct snd_pcm_substream *s; u16 e; + DEBUG_NAME(substream, name); + + snd_printdd("%s trigger\n", name); - snd_printdd("%c%d trigger\n", - SCHR(substream->stream), substream->number); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_pcm_group_for_each_entry(s, substream) { @@ -580,8 +594,8 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, if (substream->stream != s->stream) continue; - if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) && - (card->support_mmap)) { + ds->drained_count = 0; + if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* How do I know how much valid data is present * in buffer? Must be at least one period! * Guessing 2 periods, but if @@ -599,9 +613,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, } if (card->support_grouping) { - snd_printdd("\t%c%d group\n", - SCHR(s->stream), - s->number); + snd_printdd("%d group\n", s->number); e = hpi_stream_group_add( dpcm->h_stream, ds->h_stream); @@ -618,7 +630,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, /* start the master stream */ snd_card_asihpi_pcm_timer_start(substream); if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || - !card->support_mmap) + !card->can_dma) hpi_handle_error(hpi_stream_start(dpcm->h_stream)); break; @@ -636,9 +648,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, s->runtime->status->state = SNDRV_PCM_STATE_SETUP; if (card->support_grouping) { - snd_printdd("\t%c%d group\n", - SCHR(s->stream), - s->number); + snd_printdd("%d group\n", s->number); snd_pcm_trigger_done(s, substream); } else break; @@ -732,9 +742,9 @@ static void snd_card_asihpi_timer_function(unsigned long data) int loops = 0; u16 state; u32 buffer_size, bytes_avail, samples_played, on_card_bytes; + DEBUG_NAME(substream, name); - snd_printdd("%c%d snd_card_asihpi_timer_function\n", - SCHR(substream->stream), substream->number); + snd_printdd("%s snd_card_asihpi_timer_function\n", name); /* find minimum newdata and buffer pos in group */ snd_pcm_group_for_each_entry(s, substream) { @@ -756,6 +766,9 @@ static void snd_card_asihpi_timer_function(unsigned long data) /* number of bytes in on-card buffer */ runtime->delay = on_card_bytes; + if (!card->can_dma) + on_card_bytes = bytes_avail; + if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail; if (state == HPI_STATE_STOPPED) { @@ -763,12 +776,18 @@ static void snd_card_asihpi_timer_function(unsigned long data) (on_card_bytes < ds->pcm_buf_host_rw_ofs)) { hpi_handle_error(hpi_stream_start(ds->h_stream)); snd_printdd("P%d start\n", s->number); + ds->drained_count = 0; } } else if (state == HPI_STATE_DRAINED) { snd_printd(KERN_WARNING "P%d drained\n", s->number); - /*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); - continue; */ + ds->drained_count++; + if (ds->drained_count > 2) { + snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); + continue; + } + } else { + ds->drained_count = 0; } } else pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs; @@ -786,16 +805,18 @@ static void snd_card_asihpi_timer_function(unsigned long data) newdata); } - snd_printdd("hw_ptr x%04lX, appl_ptr x%04lX\n", + snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n", (unsigned long)frames_to_bytes(runtime, runtime->status->hw_ptr), (unsigned long)frames_to_bytes(runtime, runtime->control->appl_ptr)); - snd_printdd("%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X," - " aux=x%04X space=x%04X\n", - loops, SCHR(s->stream), s->number, - state, ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail, + snd_printdd("%d S=%d, " + "rw=0x%04X, dma=0x%04X, left=0x%04X, " + "aux=0x%04X space=0x%04X\n", + s->number, state, + ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, + (int)bytes_avail, (int)on_card_bytes, buffer_size-bytes_avail); loops++; } @@ -814,7 +835,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) next_jiffies = max(next_jiffies, 1U); dpcm->timer.expires = jiffies + next_jiffies; - snd_printdd("jif %d buf pos x%04X newdata x%04X xfer x%04X\n", + snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%04X\n", next_jiffies, pcm_buf_dma_ofs, newdata, xfercount); snd_pcm_group_for_each_entry(s, substream) { @@ -826,30 +847,63 @@ static void snd_card_asihpi_timer_function(unsigned long data) ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs; - if (xfercount && (on_card_bytes <= ds->period_bytes)) { - if (card->support_mmap) { - if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { - snd_printddd("P%d write x%04x\n", + if (xfercount && + /* Limit use of on card fifo for playback */ + ((on_card_bytes <= ds->period_bytes) || + (s->stream == SNDRV_PCM_STREAM_CAPTURE))) + + { + + unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes; + unsigned int xfer1, xfer2; + char *pd = &s->runtime->dma_area[buf_ofs]; + + if (card->can_dma) { /* buffer wrap is handled at lower level */ + xfer1 = xfercount; + xfer2 = 0; + } else { + xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs); + xfer2 = xfercount - xfer1; + } + + if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { + snd_printddd("P%d write1 0x%04X 0x%04X\n", + s->number, xfer1, buf_ofs); + hpi_handle_error( + hpi_outstream_write_buf( + ds->h_stream, pd, xfer1, + &ds->format)); + + if (xfer2) { + pd = s->runtime->dma_area; + + snd_printddd("P%d write2 0x%04X 0x%04X\n", s->number, - ds->period_bytes); + xfercount - xfer1, buf_ofs); hpi_handle_error( hpi_outstream_write_buf( - ds->h_stream, - &s->runtime-> - dma_area[0], - xfercount, + ds->h_stream, pd, + xfercount - xfer1, &ds->format)); - } else { - snd_printddd("C%d read x%04x\n", - s->number, - xfercount); + } + } else { + snd_printddd("C%d read1 0x%04x\n", + s->number, xfer1); + hpi_handle_error( + hpi_instream_read_buf( + ds->h_stream, + pd, xfer1)); + if (xfer2) { + pd = s->runtime->dma_area; + snd_printddd("C%d read2 0x%04x\n", + s->number, xfer2); hpi_handle_error( hpi_instream_read_buf( ds->h_stream, - NULL, xfercount)); + pd, xfer2)); } - ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount; - } /* else R/W will be handled by read/write callbacks */ + } + ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount; ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs; snd_pcm_period_elapsed(s); } @@ -863,7 +917,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { - snd_printdd(KERN_INFO "Playback ioctl %d\n", cmd); + snd_printddd(KERN_INFO "P%d ioctl %d\n", substream->number, cmd); return snd_pcm_lib_ioctl(substream, cmd, arg); } @@ -873,7 +927,7 @@ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream * struct snd_pcm_runtime *runtime = substream->runtime; struct snd_card_asihpi_pcm *dpcm = runtime->private_data; - snd_printdd("playback prepare %d\n", substream->number); + snd_printdd("P%d prepare\n", substream->number); hpi_handle_error(hpi_outstream_reset(dpcm->h_stream)); dpcm->pcm_buf_host_rw_ofs = 0; @@ -890,7 +944,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t ptr; ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes); - snd_printddd("playback_pointer=x%04lx\n", (unsigned long)ptr); + snd_printddd("P%d pointer = 0x%04lx\n", substream->number, (unsigned long)ptr); return ptr; } @@ -963,7 +1017,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) /*? also check ASI5000 samplerate source If external, only support external rate. - If internal and other stream playing, cant switch + If internal and other stream playing, can't switch */ init_timer(&dpcm->timer); @@ -986,11 +1040,9 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) SNDRV_PCM_INFO_DOUBLE | SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_PAUSE; - - if (card->support_mmap) - snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID; + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID; if (card->support_grouping) snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START; @@ -998,7 +1050,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) /* struct is copied, so can create initializer dynamically */ runtime->hw = snd_card_asihpi_playback; - if (card->support_mmap) + if (card->can_dma) err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); if (err < 0) @@ -1028,58 +1080,6 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream) return 0; } -static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream, - int channel, - snd_pcm_uframes_t pos, - void __user *src, - snd_pcm_uframes_t count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_card_asihpi_pcm *dpcm = runtime->private_data; - unsigned int len; - - len = frames_to_bytes(runtime, count); - - if (copy_from_user(runtime->dma_area, src, len)) - return -EFAULT; - - snd_printddd("playback copy%d %u bytes\n", - substream->number, len); - - hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream, - runtime->dma_area, len, &dpcm->format)); - - dpcm->pcm_buf_host_rw_ofs += len; - - return 0; -} - -static int snd_card_asihpi_playback_silence(struct snd_pcm_substream * - substream, int channel, - snd_pcm_uframes_t pos, - snd_pcm_uframes_t count) -{ - /* Usually writes silence to DMA buffer, which should be overwritten - by real audio later. Our fifos cannot be overwritten, and are not - free-running DMAs. Silence is output on fifo underflow. - This callback is still required to allow the copy callback to be used. - */ - return 0; -} - -static struct snd_pcm_ops snd_card_asihpi_playback_ops = { - .open = snd_card_asihpi_playback_open, - .close = snd_card_asihpi_playback_close, - .ioctl = snd_card_asihpi_playback_ioctl, - .hw_params = snd_card_asihpi_pcm_hw_params, - .hw_free = snd_card_asihpi_hw_free, - .prepare = snd_card_asihpi_playback_prepare, - .trigger = snd_card_asihpi_trigger, - .pointer = snd_card_asihpi_playback_pointer, - .copy = snd_card_asihpi_playback_copy, - .silence = snd_card_asihpi_playback_silence, -}; - static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = { .open = snd_card_asihpi_playback_open, .close = snd_card_asihpi_playback_close, @@ -1211,18 +1211,16 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) snd_card_asihpi_capture_format(card, dpcm->h_stream, &snd_card_asihpi_capture); snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture); - snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED; - - if (card->support_mmap) - snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID; + snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID; if (card->support_grouping) snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START; runtime->hw = snd_card_asihpi_capture; - if (card->support_mmap) + if (card->can_dma) err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); if (err < 0) @@ -1246,28 +1244,6 @@ static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream) return 0; } -static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream, - int channel, snd_pcm_uframes_t pos, - void __user *dst, snd_pcm_uframes_t count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_card_asihpi_pcm *dpcm = runtime->private_data; - u32 len; - - len = frames_to_bytes(runtime, count); - - snd_printddd("capture copy%d %d bytes\n", substream->number, len); - hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream, - runtime->dma_area, len)); - - dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len; - - if (copy_to_user(dst, runtime->dma_area, len)) - return -EFAULT; - - return 0; -} - static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = { .open = snd_card_asihpi_capture_open, .close = snd_card_asihpi_capture_close, @@ -1279,18 +1255,6 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = { .pointer = snd_card_asihpi_capture_pointer, }; -static struct snd_pcm_ops snd_card_asihpi_capture_ops = { - .open = snd_card_asihpi_capture_open, - .close = snd_card_asihpi_capture_close, - .ioctl = snd_card_asihpi_capture_ioctl, - .hw_params = snd_card_asihpi_pcm_hw_params, - .hw_free = snd_card_asihpi_hw_free, - .prepare = snd_card_asihpi_capture_prepare, - .trigger = snd_card_asihpi_trigger, - .pointer = snd_card_asihpi_capture_pointer, - .copy = snd_card_asihpi_capture_copy -}; - static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device, int substreams) { @@ -1303,17 +1267,10 @@ static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, if (err < 0) return err; /* pointer to ops struct is stored, dont change ops afterwards! */ - if (asihpi->support_mmap) { snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_asihpi_playback_mmap_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_asihpi_capture_mmap_ops); - } else { - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_card_asihpi_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_card_asihpi_capture_ops); - } pcm->private_data = asihpi; pcm->info_flags = 0; @@ -1413,14 +1370,16 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, struct hpi_control *hpi_ctl, char *name) { - char *dir = ""; + char *dir; memset(snd_control, 0, sizeof(*snd_control)); snd_control->name = hpi_ctl->name; snd_control->private_value = hpi_ctl->h_control; snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER; snd_control->index = 0; - if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM) + if (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE == HPI_SOURCENODE_CLOCK_SOURCE) + dir = ""; /* clock is neither capture nor playback */ + else if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM) dir = "Capture "; /* On or towards a PCM capture destination*/ else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) && (!hpi_ctl->dst_node_type)) @@ -1433,7 +1392,7 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, dir = "Playback "; /* PCM Playback source, or output node */ if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type) - sprintf(hpi_ctl->name, "%s%d %s%d %s%s", + sprintf(hpi_ctl->name, "%s %d %s %d %s%s", asihpi_src_names[hpi_ctl->src_node_type], hpi_ctl->src_node_index, asihpi_dst_names[hpi_ctl->dst_node_type], @@ -2875,14 +2834,14 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, if (err) asihpi->update_interval_frames = 512; - if (!asihpi->support_mmap) + if (!asihpi->can_dma) asihpi->update_interval_frames *= 2; hpi_handle_error(hpi_instream_open(asihpi->adapter_index, 0, &h_stream)); err = hpi_instream_host_buffer_free(h_stream); - asihpi->support_mmap = (!err); + asihpi->can_dma = (!err); hpi_handle_error(hpi_instream_close(h_stream)); @@ -2894,8 +2853,8 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, asihpi->out_max_chans = 2; } - snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n", - asihpi->support_mmap, + snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n", + asihpi->can_dma, asihpi->support_grouping, asihpi->support_mrx ); @@ -2925,10 +2884,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, by enable_hwdep module param*/ snd_asihpi_hpi_new(asihpi, 0, NULL); - if (asihpi->support_mmap) - strcpy(card->driver, "ASIHPI-MMAP"); - else - strcpy(card->driver, "ASIHPI"); + strcpy(card->driver, "ASIHPI"); sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type); sprintf(card->longname, "%s %i", diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h index 6fc025c448de..255429c32c1c 100644 --- a/sound/pci/asihpi/hpi.h +++ b/sound/pci/asihpi/hpi.h @@ -725,7 +725,7 @@ enum HPI_AESEBU_ERRORS { #define HPI_PAD_TITLE_LEN 64 /** The text string containing the comment. */ #define HPI_PAD_COMMENT_LEN 256 -/** The PTY when the tuner has not recieved any PTY. */ +/** The PTY when the tuner has not received any PTY. */ #define HPI_PAD_PROGRAM_TYPE_INVALID 0xffff /** \} */ diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c index 3e3c2ef6efd8..df4aed5295dd 100644 --- a/sound/pci/asihpi/hpi6000.c +++ b/sound/pci/asihpi/hpi6000.c @@ -200,8 +200,8 @@ static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata, static void subsys_create_adapter(struct hpi_message *phm, struct hpi_response *phr); -static void subsys_delete_adapter(struct hpi_message *phm, - struct hpi_response *phr); +static void adapter_delete(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr); static void adapter_get_asserts(struct hpi_adapter_obj *pao, struct hpi_message *phm, struct hpi_response *phr); @@ -222,9 +222,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) case HPI_SUBSYS_CREATE_ADAPTER: subsys_create_adapter(phm, phr); break; - case HPI_SUBSYS_DELETE_ADAPTER: - subsys_delete_adapter(phm, phr); - break; default: phr->error = HPI_ERROR_INVALID_FUNC; break; @@ -279,6 +276,10 @@ static void adapter_message(struct hpi_adapter_obj *pao, adapter_get_asserts(pao, phm, phr); break; + case HPI_ADAPTER_DELETE: + adapter_delete(pao, phm, phr); + break; + default: hw_message(pao, phm, phr); break; @@ -333,26 +334,22 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr) { struct hpi_adapter_obj *pao = NULL; - /* subsytem messages get executed by every HPI. */ - /* All other messages are ignored unless the adapter index matches */ - /* an adapter in the HPI */ - /*HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->wObject, phm->wFunction); */ - - /* if Dsp has crashed then do not communicate with it any more */ if (phm->object != HPI_OBJ_SUBSYSTEM) { pao = hpi_find_adapter(phm->adapter_index); if (!pao) { - HPI_DEBUG_LOG(DEBUG, - " %d,%d refused, for another HPI?\n", - phm->object, phm->function); + hpi_init_response(phr, phm->object, phm->function, + HPI_ERROR_BAD_ADAPTER_NUMBER); + HPI_DEBUG_LOG(DEBUG, "invalid adapter index: %d \n", + phm->adapter_index); return; } + /* Don't even try to communicate with crashed DSP */ if (pao->dsp_crashed >= 10) { hpi_init_response(phr, phm->object, phm->function, HPI_ERROR_DSP_HARDWARE); - HPI_DEBUG_LOG(DEBUG, " %d,%d dsp crashed.\n", - phm->object, phm->function); + HPI_DEBUG_LOG(DEBUG, "adapter %d dsp crashed\n", + phm->adapter_index); return; } } @@ -423,7 +420,7 @@ static void subsys_create_adapter(struct hpi_message *phm, ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL); if (!ao.priv) { - HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n"); + HPI_DEBUG_LOG(ERROR, "can't get mem for adapter object\n"); phr->error = HPI_ERROR_MEMORY_ALLOC; return; } @@ -463,15 +460,9 @@ static void subsys_create_adapter(struct hpi_message *phm, phr->error = 0; } -static void subsys_delete_adapter(struct hpi_message *phm, - struct hpi_response *phr) +static void adapter_delete(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr) { - struct hpi_adapter_obj *pao = NULL; - - pao = hpi_find_adapter(phm->obj_index); - if (!pao) - return; - delete_adapter_obj(pao); hpi_delete_adapter(pao); phr->error = 0; diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c index 620525bdac59..9d5df54a6b46 100644 --- a/sound/pci/asihpi/hpi6205.c +++ b/sound/pci/asihpi/hpi6205.c @@ -152,8 +152,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, static void subsys_create_adapter(struct hpi_message *phm, struct hpi_response *phr); -static void subsys_delete_adapter(struct hpi_message *phm, - struct hpi_response *phr); +static void adapter_delete(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr); static u16 create_adapter_obj(struct hpi_adapter_obj *pao, u32 *pos_error_code); @@ -223,15 +223,13 @@ static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index); /*****************************************************************************/ -static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) +static void subsys_message(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr) { switch (phm->function) { case HPI_SUBSYS_CREATE_ADAPTER: subsys_create_adapter(phm, phr); break; - case HPI_SUBSYS_DELETE_ADAPTER: - subsys_delete_adapter(phm, phr); - break; default: phr->error = HPI_ERROR_INVALID_FUNC; break; @@ -279,6 +277,10 @@ static void adapter_message(struct hpi_adapter_obj *pao, struct hpi_message *phm, struct hpi_response *phr) { switch (phm->function) { + case HPI_ADAPTER_DELETE: + adapter_delete(pao, phm, phr); + break; + default: hw_message(pao, phm, phr); break; @@ -371,36 +373,17 @@ static void instream_message(struct hpi_adapter_obj *pao, /** Entry point to this HPI backend * All calls to the HPI start here */ -void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) +void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm, + struct hpi_response *phr) { - struct hpi_adapter_obj *pao = NULL; - - /* subsytem messages are processed by every HPI. - * All other messages are ignored unless the adapter index matches - * an adapter in the HPI - */ - /* HPI_DEBUG_LOG(DEBUG, "HPI Obj=%d, Func=%d\n", phm->wObject, - phm->wFunction); */ - - /* if Dsp has crashed then do not communicate with it any more */ - if (phm->object != HPI_OBJ_SUBSYSTEM) { - pao = hpi_find_adapter(phm->adapter_index); - if (!pao) { - HPI_DEBUG_LOG(DEBUG, - " %d,%d refused, for another HPI?\n", - phm->object, phm->function); - return; - } - - if ((pao->dsp_crashed >= 10) - && (phm->function != HPI_ADAPTER_DEBUG_READ)) { - /* allow last resort debug read even after crash */ - hpi_init_response(phr, phm->object, phm->function, - HPI_ERROR_DSP_HARDWARE); - HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", - phm->object, phm->function); - return; - } + if (pao && (pao->dsp_crashed >= 10) + && (phm->function != HPI_ADAPTER_DEBUG_READ)) { + /* allow last resort debug read even after crash */ + hpi_init_response(phr, phm->object, phm->function, + HPI_ERROR_DSP_HARDWARE); + HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", phm->object, + phm->function); + return; } /* Init default response */ @@ -412,7 +395,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) case HPI_TYPE_MESSAGE: switch (phm->object) { case HPI_OBJ_SUBSYSTEM: - subsys_message(phm, phr); + subsys_message(pao, phm, phr); break; case HPI_OBJ_ADAPTER: @@ -444,6 +427,26 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) } } +void HPI_6205(struct hpi_message *phm, struct hpi_response *phr) +{ + struct hpi_adapter_obj *pao = NULL; + + if (phm->object != HPI_OBJ_SUBSYSTEM) { + /* normal messages must have valid adapter index */ + pao = hpi_find_adapter(phm->adapter_index); + } else { + /* subsys messages don't address an adapter */ + _HPI_6205(NULL, phm, phr); + return; + } + + if (pao) + _HPI_6205(pao, phm, phr); + else + hpi_init_response(phr, phm->object, phm->function, + HPI_ERROR_BAD_ADAPTER_NUMBER); +} + /*****************************************************************************/ /* SUBSYSTEM */ @@ -466,7 +469,7 @@ static void subsys_create_adapter(struct hpi_message *phm, ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL); if (!ao.priv) { - HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n"); + HPI_DEBUG_LOG(ERROR, "can't get mem for adapter object\n"); phr->error = HPI_ERROR_MEMORY_ALLOC; return; } @@ -491,13 +494,11 @@ static void subsys_create_adapter(struct hpi_message *phm, } /** delete an adapter - required by WDM driver */ -static void subsys_delete_adapter(struct hpi_message *phm, - struct hpi_response *phr) +static void adapter_delete(struct hpi_adapter_obj *pao, + struct hpi_message *phm, struct hpi_response *phr) { - struct hpi_adapter_obj *pao; struct hpi_hw_obj *phw; - pao = hpi_find_adapter(phm->obj_index); if (!pao) { phr->error = HPI_ERROR_INVALID_OBJ_INDEX; return; @@ -563,11 +564,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, } err = adapter_boot_load_dsp(pao, pos_error_code); - if (err) + if (err) { + HPI_DEBUG_LOG(ERROR, "DSP code load failed\n"); /* no need to clean up as SubSysCreateAdapter */ /* calls DeleteAdapter on error. */ return err; - + } HPI_DEBUG_LOG(INFO, "load DSP code OK\n"); /* allow boot load even if mem alloc wont work */ @@ -604,6 +606,7 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, control_cache.number_of_controls, interface->control_cache.size_in_bytes, p_control_cache_virtual); + if (!phw->p_cache) err = HPI_ERROR_MEMORY_ALLOC; } @@ -675,16 +678,14 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, } /** Free memory areas allocated by adapter - * this routine is called from SubSysDeleteAdapter, + * this routine is called from AdapterDelete, * and SubSysCreateAdapter if duplicate index */ static void delete_adapter_obj(struct hpi_adapter_obj *pao) { - struct hpi_hw_obj *phw; + struct hpi_hw_obj *phw = pao->priv; int i; - phw = pao->priv; - if (hpios_locked_mem_valid(&phw->h_control_cache)) { hpios_locked_mem_free(&phw->h_control_cache); hpi_free_control_cache(phw->p_cache); @@ -1275,6 +1276,7 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, case HPI_ADAPTER_FAMILY_ASI(0x6300): boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400); break; + case HPI_ADAPTER_FAMILY_ASI(0x5500): case HPI_ADAPTER_FAMILY_ASI(0x5600): case HPI_ADAPTER_FAMILY_ASI(0x6500): boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600); @@ -2059,7 +2061,6 @@ static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us) static void send_dsp_command(struct hpi_hw_obj *phw, int cmd) { struct bus_master_interface *interface = phw->p_interface_buffer; - u32 r; interface->host_cmd = cmd; diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h index af678be0aa15..bf5eced76bac 100644 --- a/sound/pci/asihpi/hpi_internal.h +++ b/sound/pci/asihpi/hpi_internal.h @@ -294,7 +294,7 @@ enum HPI_CONTROL_ATTRIBUTES { /* These defines are used to fill in protocol information for an Ethernet packet sent using HMI on CS18102 */ -/** ID supplied by Cirrius for ASI packets. */ +/** ID supplied by Cirrus for ASI packets. */ #define HPI_ETHERNET_PACKET_ID 0x85 /** Simple packet - no special routing required */ #define HPI_ETHERNET_PACKET_V1 0x01 @@ -307,7 +307,7 @@ enum HPI_CONTROL_ATTRIBUTES { /** This packet must make its way to the host across the HPI interface */ #define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI_V1 0x41 -#define HPI_ETHERNET_UDP_PORT (44600) /*!< UDP messaging port */ +#define HPI_ETHERNET_UDP_PORT 44600 /**< HPI UDP service */ /** Default network timeout in milli-seconds. */ #define HPI_ETHERNET_TIMEOUT_MS 500 @@ -397,14 +397,14 @@ enum HPI_FUNCTION_IDS { HPI_SUBSYS_OPEN = HPI_FUNC_ID(SUBSYSTEM, 1), HPI_SUBSYS_GET_VERSION = HPI_FUNC_ID(SUBSYSTEM, 2), HPI_SUBSYS_GET_INFO = HPI_FUNC_ID(SUBSYSTEM, 3), - HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4), + /* HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4), */ HPI_SUBSYS_CREATE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 5), HPI_SUBSYS_CLOSE = HPI_FUNC_ID(SUBSYSTEM, 6), - HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7), + /* HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7), */ HPI_SUBSYS_DRIVER_LOAD = HPI_FUNC_ID(SUBSYSTEM, 8), HPI_SUBSYS_DRIVER_UNLOAD = HPI_FUNC_ID(SUBSYSTEM, 9), - HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10), - HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11), + /* HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10), */ + /* HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11), */ HPI_SUBSYS_GET_NUM_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 12), HPI_SUBSYS_GET_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 13), HPI_SUBSYS_SET_NETWORK_INTERFACE = HPI_FUNC_ID(SUBSYSTEM, 14), @@ -433,7 +433,8 @@ enum HPI_FUNCTION_IDS { HPI_ADAPTER_DEBUG_READ = HPI_FUNC_ID(ADAPTER, 18), HPI_ADAPTER_IRQ_QUERY_AND_CLEAR = HPI_FUNC_ID(ADAPTER, 19), HPI_ADAPTER_IRQ_CALLBACK = HPI_FUNC_ID(ADAPTER, 20), -#define HPI_ADAPTER_FUNCTION_COUNT 20 + HPI_ADAPTER_DELETE = HPI_FUNC_ID(ADAPTER, 21), +#define HPI_ADAPTER_FUNCTION_COUNT 21 HPI_OSTREAM_OPEN = HPI_FUNC_ID(OSTREAM, 1), HPI_OSTREAM_CLOSE = HPI_FUNC_ID(OSTREAM, 2), @@ -607,7 +608,7 @@ struct hpi_data_compat32 { #endif struct hpi_buffer { - /** placehoder for backward compatability (see dwBufferSize) */ + /** placehoder for backward compatibility (see dwBufferSize) */ struct hpi_msg_format reserved; u32 command; /**< HPI_BUFFER_CMD_xxx*/ u32 pci_address; /**< PCI physical address of buffer for DSP DMA */ @@ -1561,8 +1562,6 @@ void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr); u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource, u16 *pw_adapter_index); -u16 hpi_subsys_delete_adapter(u16 adapter_index); - u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer, struct hpi_hostbuffer_status **pp_status); @@ -1584,9 +1583,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR); /*////////////////////////////////////////////////////////////////////////// */ /* declarations for individual HPI entry points */ -hpi_handler_func HPI_1000; hpi_handler_func HPI_6000; hpi_handler_func HPI_6205; -hpi_handler_func HPI_COMMON; #endif /* _HPI_INTERNAL_H_ */ diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c index 3e9c5c289764..b15a02e91f82 100644 --- a/sound/pci/asihpi/hpicmn.c +++ b/sound/pci/asihpi/hpicmn.c @@ -227,8 +227,9 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC) if (info->control_type) { pC->p_info[info->control_index] = info; cached++; - } else /* dummy cache entry */ + } else { /* dummy cache entry */ pC->p_info[info->control_index] = NULL; + } byte_count += info->size_in32bit_words * 4; @@ -298,7 +299,7 @@ struct pad_ofs_size { unsigned int field_size; }; -static struct pad_ofs_size pad_desc[] = { +static const struct pad_ofs_size pad_desc[] = { HPICMN_PAD_OFS_AND_SIZE(c_channel), /* HPI_PAD_CHANNEL_NAME */ HPICMN_PAD_OFS_AND_SIZE(c_artist), /* HPI_PAD_ARTIST */ HPICMN_PAD_OFS_AND_SIZE(c_title), /* HPI_PAD_TITLE */ @@ -617,6 +618,10 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, } } +/** Allocate control cache. + +\return Cache pointer, or NULL if allocation fails. +*/ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, const u32 size_in_bytes, u8 *p_dsp_control_buffer) { @@ -667,7 +672,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr) phr->u.s.num_adapters = adapters.gw_num_adapters; break; case HPI_SUBSYS_CREATE_ADAPTER: - case HPI_SUBSYS_DELETE_ADAPTER: break; default: phr->error = HPI_ERROR_INVALID_FUNC; diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h index 590f0b69e655..d53cdf6e535f 100644 --- a/sound/pci/asihpi/hpicmn.h +++ b/sound/pci/asihpi/hpicmn.h @@ -60,3 +60,5 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC, struct hpi_message *phm, struct hpi_response *phr); u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr); + +hpi_handler_func HPI_COMMON; diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c index c38fc9487560..7397b169b89f 100644 --- a/sound/pci/asihpi/hpifunc.c +++ b/sound/pci/asihpi/hpifunc.c @@ -105,33 +105,6 @@ u16 hpi_subsys_get_version_ex(u32 *pversion_ex) return hr.error; } -u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource, - u16 *pw_adapter_index) -{ - struct hpi_message hm; - struct hpi_response hr; - - hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, - HPI_SUBSYS_CREATE_ADAPTER); - hm.u.s.resource = *p_resource; - - hpi_send_recv(&hm, &hr); - - *pw_adapter_index = hr.u.s.adapter_index; - return hr.error; -} - -u16 hpi_subsys_delete_adapter(u16 adapter_index) -{ - struct hpi_message hm; - struct hpi_response hr; - hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, - HPI_SUBSYS_DELETE_ADAPTER); - hm.obj_index = adapter_index; - hpi_send_recv(&hm, &hr); - return hr.error; -} - u16 hpi_subsys_get_num_adapters(int *pn_num_adapters) { struct hpi_message hm; diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c index bcbdf30a6aa0..7352a5f7b4f7 100644 --- a/sound/pci/asihpi/hpimsgx.c +++ b/sound/pci/asihpi/hpimsgx.c @@ -211,24 +211,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr, HPIMSGX__init(phm, phr); break; - case HPI_SUBSYS_DELETE_ADAPTER: - HPIMSGX__cleanup(phm->obj_index, h_owner); - { - struct hpi_message hm; - struct hpi_response hr; - hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, - HPI_ADAPTER_CLOSE); - hm.adapter_index = phm->obj_index; - hw_entry_point(&hm, &hr); - } - if ((phm->obj_index < HPI_MAX_ADAPTERS) - && hpi_entry_points[phm->obj_index]) { - hpi_entry_points[phm->obj_index] (phm, phr); - hpi_entry_points[phm->obj_index] = NULL; - } else - phr->error = HPI_ERROR_INVALID_OBJ_INDEX; - - break; default: /* Must explicitly handle every subsys message in this switch */ hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, @@ -247,6 +229,19 @@ static void adapter_message(struct hpi_message *phm, struct hpi_response *phr, case HPI_ADAPTER_CLOSE: adapter_close(phm, phr); break; + case HPI_ADAPTER_DELETE: + HPIMSGX__cleanup(phm->adapter_index, h_owner); + { + struct hpi_message hm; + struct hpi_response hr; + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_CLOSE); + hm.adapter_index = phm->adapter_index; + hw_entry_point(&hm, &hr); + } + hw_entry_point(phm, phr); + break; + default: hw_entry_point(phm, phr); break; @@ -722,7 +717,7 @@ static u16 HPIMSGX__init(struct hpi_message *phm, return phr->error; } if (hr.error == 0) { - /* the adapter was created succesfully + /* the adapter was created successfully save the mapping for future use */ hpi_entry_points[hr.u.s.adapter_index] = entry_point_func; /* prepare adapter (pre-open streams etc.) */ diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index cd624f13ff8e..d8e7047512f8 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -25,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions #include "hpidebug.h" #include "hpimsgx.h" #include "hpioctl.h" +#include "hpicmn.h" #include <linux/fs.h> #include <linux/slab.h> @@ -161,26 +162,24 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto out; } - pa = &adapters[hm->h.adapter_index]; + switch (hm->h.function) { + case HPI_SUBSYS_CREATE_ADAPTER: + case HPI_ADAPTER_DELETE: + /* Application must not use these functions! */ + hr->h.size = sizeof(hr->h); + hr->h.error = HPI_ERROR_INVALID_OPERATION; + hr->h.function = hm->h.function; + uncopied_bytes = copy_to_user(puhr, hr, hr->h.size); + if (uncopied_bytes) + err = -EFAULT; + else + err = 0; + goto out; + } + hr->h.size = res_max_size; if (hm->h.object == HPI_OBJ_SUBSYSTEM) { - switch (hm->h.function) { - case HPI_SUBSYS_CREATE_ADAPTER: - case HPI_SUBSYS_DELETE_ADAPTER: - /* Application must not use these functions! */ - hr->h.size = sizeof(hr->h); - hr->h.error = HPI_ERROR_INVALID_OPERATION; - hr->h.function = hm->h.function; - uncopied_bytes = copy_to_user(puhr, hr, hr->h.size); - if (uncopied_bytes) - err = -EFAULT; - else - err = 0; - goto out; - - default: - hpi_send_recv_f(&hm->m0, &hr->r0, file); - } + hpi_send_recv_f(&hm->m0, &hr->r0, file); } else { u16 __user *ptr = NULL; u32 size = 0; @@ -188,8 +187,9 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* -1=no data 0=read from user mem, 1=write to user mem */ int wrflag = -1; u32 adapter = hm->h.adapter_index; + pa = &adapters[adapter]; - if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) { + if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) { hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER, HPI_ADAPTER_OPEN, HPI_ERROR_BAD_ADAPTER_NUMBER); @@ -317,7 +317,7 @@ out: int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { - int err, idx, nm; + int idx, nm; unsigned int memlen; struct hpi_message hm; struct hpi_response hr; @@ -351,11 +351,8 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, nm = HPI_MAX_ADAPTER_MEM_SPACES; for (idx = 0; idx < nm; idx++) { - HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n", - idx, pci_dev->resource[idx].name, - (unsigned long long)pci_resource_start(pci_dev, idx), - (unsigned long long)pci_resource_end(pci_dev, idx), - (unsigned long long)pci_resource_flags(pci_dev, idx)); + HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx, + &pci_dev->resource[idx]); if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) { memlen = pci_resource_len(pci_dev, idx); @@ -395,17 +392,20 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, adapter.index = hr.u.s.adapter_index; adapter.type = hr.u.s.adapter_type; + + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_OPEN); hm.adapter_index = adapter.index; + hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); - err = hpi_adapter_open(adapter.index); - if (err) + if (hr.error) goto err; adapter.snd_card_asihpi = NULL; /* WARNING can't init mutex in 'adapter' * and then copy it to adapters[] ?!?! */ - adapters[hr.u.s.adapter_index] = adapter; + adapters[adapter.index] = adapter; mutex_init(&adapters[adapter.index].mutex); pci_set_drvdata(pci_dev, &adapters[adapter.index]); @@ -440,10 +440,9 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev) struct hpi_adapter *pa; pa = pci_get_drvdata(pci_dev); - hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, - HPI_SUBSYS_DELETE_ADAPTER); - hm.obj_index = pa->index; - hm.adapter_index = HPI_ADAPTER_INDEX_INVALID; + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_DELETE); + hm.adapter_index = pa->index; hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); /* unmap PCI memory space, mapped during device init. */ diff --git a/sound/pci/au88x0/au8810.h b/sound/pci/au88x0/au8810.h index 5d69c31fe3f4..79fbee3845eb 100644 --- a/sound/pci/au88x0/au8810.h +++ b/sound/pci/au88x0/au8810.h @@ -4,7 +4,7 @@ #define CHIP_AU8810 -#define CARD_NAME "Aureal Advantage 3D Sound Processor" +#define CARD_NAME "Aureal Advantage" #define CARD_NAME_SHORT "au8810" #define NR_ADB 0x10 diff --git a/sound/pci/au88x0/au8820.h b/sound/pci/au88x0/au8820.h index abbe85e4f7a9..cafdb9668a34 100644 --- a/sound/pci/au88x0/au8820.h +++ b/sound/pci/au88x0/au8820.h @@ -11,7 +11,7 @@ #define CHIP_AU8820 -#define CARD_NAME "Aureal Vortex 3D Sound Processor" +#define CARD_NAME "Aureal Vortex" #define CARD_NAME_SHORT "au8820" /* Number of ADB and WT channels */ diff --git a/sound/pci/au88x0/au8830.h b/sound/pci/au88x0/au8830.h index 04ece1b1c218..999b29ab34ad 100644 --- a/sound/pci/au88x0/au8830.h +++ b/sound/pci/au88x0/au8830.h @@ -11,7 +11,7 @@ #define CHIP_AU8830 -#define CARD_NAME "Aureal Vortex 2 3D Sound Processor" +#define CARD_NAME "Aureal Vortex 2" #define CARD_NAME_SHORT "au8830" #define NR_ADB 0x20 diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index ecb8f4daf408..02f6e08f7592 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h @@ -104,7 +104,7 @@ #define MIX_PLAYB(x) (vortex->mixplayb[x]) #define MIX_SPDIF(x) (vortex->mixspdif[x]) -#define NR_WTPB 0x20 /* WT channels per eahc bank. */ +#define NR_WTPB 0x20 /* WT channels per each bank. */ /* Structs */ typedef struct { diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index f4aa8ff6f5f9..9ae8b3b17651 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c @@ -53,7 +53,7 @@ a3dsrc_GetTimeConsts(a3dsrc_t * a, short *HrtfTrack, short *ItdTrack, } #endif -/* Atmospheric absorbtion. */ +/* Atmospheric absorption. */ static void a3dsrc_SetAtmosTarget(a3dsrc_t * a, short aa, short b, short c, short d, @@ -835,7 +835,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol, params[i] = ucontrol->value.integer.value[i]; /* Translate generic filter params to a3d filter params. */ vortex_a3d_translate_filter(a->filter, params); - /* Atmospheric absorbtion and filtering. */ + /* Atmospheric absorption and filtering. */ a3dsrc_SetAtmosTarget(a, a->filter[0], a->filter[1], a->filter[2], a->filter[3], a->filter[4]); diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 5439d662d104..c5f7ae46afef 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -44,10 +44,10 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_adb = { .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 0x10000, - .period_bytes_min = 0x1, + .period_bytes_min = 0x20, .period_bytes_max = 0x1000, .periods_min = 2, - .periods_max = 32, + .periods_max = 1024, }; #ifndef CHIP_AU8820 @@ -140,6 +140,9 @@ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) return err; + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 64); + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { #ifndef CHIP_AU8820 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) { @@ -423,11 +426,11 @@ static struct snd_pcm_ops snd_vortex_playback_ops = { */ static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = { - "AU88x0 ADB", - "AU88x0 SPDIF", - "AU88x0 A3D", - "AU88x0 WT", - "AU88x0 I2S", + CARD_NAME " ADB", + CARD_NAME " SPDIF", + CARD_NAME " A3D", + CARD_NAME " WT", + CARD_NAME " I2S", }; static char *vortex_pcm_name[VORTEX_PCM_LAST] = { "adb", @@ -515,7 +518,7 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) return -ENODEV; /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the - * same dma engine. WT uses it own separate dma engine whcih cant capture. */ + * same dma engine. WT uses it own separate dma engine which can't capture. */ if (idx == VORTEX_PCM_ADB) nr_capt = nr; else @@ -524,7 +527,8 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) nr_capt, &pcm); if (err < 0) return err; - strcpy(pcm->name, vortex_pcm_name[idx]); + snprintf(pcm->name, sizeof(pcm->name), + "%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]); chip->pcm[idx] = pcm; // This is an evil hack, but it saves a lot of duplicated code. VORTEX_PCM_TYPE(pcm) = idx; diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 5715c4d05573..9b7a6346037a 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -140,7 +140,7 @@ * Possible remedies: * - use speaker (amplifier) output instead of headphone output * (in case crackling is due to overloaded output clipping) - * - plug card into a different PCI slot, preferrably one that isn't shared + * - plug card into a different PCI slot, preferably one that isn't shared * too much (this helps a lot, but not completely!) * - get rid of PCI VGA card, use AGP instead * - upgrade or downgrade BIOS diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index fc53b9bca26d..e8e8ccc96403 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -51,7 +51,7 @@ * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) * * - * This code was initally based on code from ALSA's emu10k1x.c which is: + * This code was initially based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> * * This program is free software; you can redistribute it and/or modify @@ -175,7 +175,7 @@ /* CA0106 pointer-offset register set, accessed through the PTR and DATA registers */ /********************************************************************************************************/ -/* Initally all registers from 0x00 to 0x3f have zero contents. */ +/* Initially all registers from 0x00 to 0x3f have zero contents. */ #define PLAYBACK_LIST_ADDR 0x00 /* Base DMA address of a list of pointers to each period/size */ /* One list entry: 4 bytes for DMA address, * 4 bytes for period_size << 16. @@ -223,7 +223,7 @@ * The jack has 4 poles. I will call 1 - Tip, 2 - Next to 1, 3 - Next to 2, 4 - Next to 3 * For Analogue: 1 -> Center Speaker, 2 -> Sub Woofer, 3 -> Ground, 4 -> Ground * For Digital: 1 -> Front SPDIF, 2 -> Rear SPDIF, 3 -> Center/Subwoofer SPDIF, 4 -> Ground. - * Standard 4 pole Video A/V cable with RCA outputs: 1 -> White, 2 -> Yellow, 3 -> Sheild on all three, 4 -> Red. + * Standard 4 pole Video A/V cable with RCA outputs: 1 -> White, 2 -> Yellow, 3 -> Shield on all three, 4 -> Red. * So, from this you can see that you cannot use a Standard 4 pole Video A/V cable with the SB Audigy LS card. */ /* The Front SPDIF PCM gets mixed with samples from the AC97 codec, so can only work for Stereo PCM and not AC3/DTS diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 01b49388fafd..437759239694 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -117,7 +117,7 @@ * DAC: Unknown * Trying to handle it like the SB0410. * - * This code was initally based on code from ALSA's emu10k1x.c which is: + * This code was initially based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> * * This program is free software; you can redistribute it and/or modify diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 630aa4998189..84f3f92436b5 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -42,7 +42,7 @@ * 0.0.18 * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) * - * This code was initally based on code from ALSA's emu10k1x.c which is: + * This code was initially based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> * * This program is free software; you can redistribute it and/or modify diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index ba96428c9f4c..c694464b1168 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -42,7 +42,7 @@ * 0.0.18 * Implement support for Line-in capture on SB Live 24bit. * - * This code was initally based on code from ALSA's emu10k1x.c which is: + * This code was initially based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> * * This program is free software; you can redistribute it and/or modify diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index b5bb036ef73c..f4e573555da3 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -73,7 +73,7 @@ MODULE_PARM_DESC(mpu_port, "MPU-401 port."); module_param_array(fm_port, long, NULL, 0444); MODULE_PARM_DESC(fm_port, "FM port."); module_param_array(soft_ac3, bool, NULL, 0444); -MODULE_PARM_DESC(soft_ac3, "Sofware-conversion of raw SPDIF packets (model 033 only)."); +MODULE_PARM_DESC(soft_ac3, "Software-conversion of raw SPDIF packets (model 033 only)."); #ifdef SUPPORT_JOYSTICK module_param_array(joystick_port, int, NULL, 0444); MODULE_PARM_DESC(joystick_port, "Joystick port address."); @@ -656,8 +656,8 @@ out: } /* - * Program pll register bits, I assume that the 8 registers 0xf8 upto 0xff - * are mapped onto the 8 ADC/DAC sampling frequency which can be choosen + * Program pll register bits, I assume that the 8 registers 0xf8 up to 0xff + * are mapped onto the 8 ADC/DAC sampling frequency which can be chosen * at the register CM_REG_FUNCTRL1 (0x04). * Problem: other ways are also possible (any information about that?) */ @@ -666,7 +666,7 @@ static void snd_cmipci_set_pll(struct cmipci *cm, unsigned int rate, unsigned in unsigned int reg = CM_REG_PLL + slot; /* * Guess that this programs at reg. 0x04 the pos 15:13/12:10 - * for DSFC/ASFC (000 upto 111). + * for DSFC/ASFC (000 up to 111). */ /* FIXME: Init (Do we've to set an other register first before programming?) */ diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index b9321544c31c..13f33c0719d3 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1627,7 +1627,7 @@ static struct ct_atc atc_preset __devinitdata = { * Creates and initializes a hardware manager. * * Creates kmallocated ct_atc structure. Initializes hardware. - * Returns 0 if suceeds, or negative error code if fails. + * Returns 0 if succeeds, or negative error code if fails. */ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 0cf400f879f9..a5c957db5cea 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1285,7 +1285,7 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) hw_write_20kx(hw, PTPALX, ptp_phys_low); hw_write_20kx(hw, PTPAHX, ptp_phys_high); hw_write_20kx(hw, TRNCTL, trnctl); - hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */ + hw_write_20kx(hw, TRNIS, 0x200c01); /* really needed? */ return 0; } diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 7a9401462c1c..dae4050ede5c 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -303,6 +303,9 @@ static const u32 db_table[101] = { static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0); +/* EMU10K1 bass/treble db gain */ +static const DECLARE_TLV_DB_SCALE(snd_emu10k1_bass_treble_db_scale, -1200, 60, 0); + static const u32 onoff_table[2] = { 0x00000000, 0x00000001 }; @@ -2163,6 +2166,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) ctl->min = 0; ctl->max = 40; ctl->value[0] = ctl->value[1] = 20; + ctl->tlv = snd_emu10k1_bass_treble_db_scale; ctl->translation = EMU10K1_GPR_TRANSLATION_BASS; ctl = &controls[i + 1]; ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -2172,6 +2176,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) ctl->min = 0; ctl->max = 40; ctl->value[0] = ctl->value[1] = 20; + ctl->tlv = snd_emu10k1_bass_treble_db_scale; ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE; #define BASS_GPR 0x8c diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 05afe06e353a..9d890a5aec5a 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1729,8 +1729,6 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "Master Mono Playback Volume", "PCM Out Path & Mute", "Mono Output Select", - "Front Playback Switch", - "Front Playback Volume", "Surround Playback Switch", "Surround Playback Volume", "Center Playback Switch", @@ -1879,6 +1877,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, emu->rear_ac97 = 1; snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); + remove_ctl(card,"Front Playback Volume"); + remove_ctl(card,"Front Playback Switch"); } /* remove unused AC97 controls */ snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); @@ -1913,6 +1913,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, for (; *c; c += 2) rename_ctl(card, c[0], c[1]); + if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */ + remove_ctl(card, "Center Playback Volume"); + remove_ctl(card, "LFE Playback Volume"); + remove_ctl(card, "Wave Center Playback Volume"); + remove_ctl(card, "Wave LFE Playback Volume"); + } if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 957a311514c8..c250614dadd0 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -248,7 +248,7 @@ static int is_valid_page(struct snd_emu10k1 *emu, dma_addr_t addr) /* * map the given memory block on PTB. * if the block is already mapped, update the link order. - * if no empty pages are found, tries to release unsed memory blocks + * if no empty pages are found, tries to release unused memory blocks * and retry the mapping. */ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 61b8ab39800f..a81dc44228ea 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -69,7 +69,7 @@ * ADC: Philips 1361T (Stereo 24bit) * DAC: CS4382-K (8-channel, 24bit, 192Khz) * - * This code was initally based on code from ALSA's emu10k1x.c which is: + * This code was initially based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> * * This program is free software; you can redistribute it and/or modify diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h index 00f4817533b1..4e0ee1a9747a 100644 --- a/sound/pci/emu10k1/p16v.h +++ b/sound/pci/emu10k1/p16v.h @@ -59,7 +59,7 @@ * ADC: Philips 1361T (Stereo 24bit) * DAC: CS4382-K (8-channel, 24bit, 192Khz) * - * This code was initally based on code from ALSA's emu10k1x.c which is: + * This code was initially based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> * * This program is free software; you can redistribute it and/or modify @@ -86,7 +86,7 @@ * The sample rate is also controlled by the same registers that control the rate of the EMU10K2 sample rate converters. */ -/* Initally all registers from 0x00 to 0x3f have zero contents. */ +/* Initially all registers from 0x00 to 0x3f have zero contents. */ #define PLAYBACK_LIST_ADDR 0x00 /* Base DMA address of a list of pointers to each period/size */ /* One list entry: 4 bytes for DMA address, * 4 bytes for period_size << 16. diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 537cfba829a5..863eafea691f 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -229,6 +229,7 @@ MODULE_PARM_DESC(lineio, "Line In to Rear Out (0 = auto, 1 = force)."); #define ES_REG_1371_CODEC 0x14 /* W/R: Codec Read/Write register address */ #define ES_1371_CODEC_RDY (1<<31) /* codec ready */ #define ES_1371_CODEC_WIP (1<<30) /* codec register access in progress */ +#define EV_1938_CODEC_MAGIC (1<<26) #define ES_1371_CODEC_PIRD (1<<23) /* codec read/write select register */ #define ES_1371_CODEC_WRITE(a,d) ((((a)&0x7f)<<16)|(((d)&0xffff)<<0)) #define ES_1371_CODEC_READS(a) ((((a)&0x7f)<<16)|ES_1371_CODEC_PIRD) @@ -603,12 +604,18 @@ static void snd_es1370_codec_write(struct snd_ak4531 *ak4531, #ifdef CHIP1371 +static inline bool is_ev1938(struct ensoniq *ensoniq) +{ + return ensoniq->pci->device == 0x8938; +} + static void snd_es1371_codec_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { struct ensoniq *ensoniq = ac97->private_data; - unsigned int t, x; + unsigned int t, x, flag; + flag = is_ev1938(ensoniq) ? EV_1938_CODEC_MAGIC : 0; mutex_lock(&ensoniq->src_mutex); for (t = 0; t < POLL_COUNT; t++) { if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) { @@ -630,7 +637,8 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97, 0x00010000) break; } - outl(ES_1371_CODEC_WRITE(reg, val), ES_REG(ensoniq, 1371_CODEC)); + outl(ES_1371_CODEC_WRITE(reg, val) | flag, + ES_REG(ensoniq, 1371_CODEC)); /* restore SRC reg */ snd_es1371_wait_src_ready(ensoniq); outl(x, ES_REG(ensoniq, 1371_SMPRATE)); @@ -647,8 +655,9 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97, unsigned short reg) { struct ensoniq *ensoniq = ac97->private_data; - unsigned int t, x, fail = 0; + unsigned int t, x, flag, fail = 0; + flag = is_ev1938(ensoniq) ? EV_1938_CODEC_MAGIC : 0; __again: mutex_lock(&ensoniq->src_mutex); for (t = 0; t < POLL_COUNT; t++) { @@ -671,7 +680,8 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97, 0x00010000) break; } - outl(ES_1371_CODEC_READS(reg), ES_REG(ensoniq, 1371_CODEC)); + outl(ES_1371_CODEC_READS(reg) | flag, + ES_REG(ensoniq, 1371_CODEC)); /* restore SRC reg */ snd_es1371_wait_src_ready(ensoniq); outl(x, ES_REG(ensoniq, 1371_SMPRATE)); @@ -683,6 +693,11 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97, /* now wait for the stinkin' data (RDY) */ for (t = 0; t < POLL_COUNT; t++) { if ((x = inl(ES_REG(ensoniq, 1371_CODEC))) & ES_1371_CODEC_RDY) { + if (is_ev1938(ensoniq)) { + for (t = 0; t < 100; t++) + inl(ES_REG(ensoniq, CONTROL)); + x = inl(ES_REG(ensoniq, 1371_CODEC)); + } mutex_unlock(&ensoniq->src_mutex); return ES_1371_CODEC_READ(x); } diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 7c17f45d876d..ab0a6156a704 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -112,6 +112,10 @@ #include <sound/ac97_codec.h> #include <sound/initval.h> +#ifdef CONFIG_SND_ES1968_RADIO +#include <sound/tea575x-tuner.h> +#endif + #define CARD_NAME "ESS Maestro1/2" #define DRIVER_NAME "ES1968" @@ -553,6 +557,10 @@ struct es1968 { spinlock_t ac97_lock; struct tasklet_struct hwvol_tq; #endif + +#ifdef CONFIG_SND_ES1968_RADIO + struct snd_tea575x tea; +#endif }; static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); @@ -2571,6 +2579,63 @@ static int __devinit snd_es1968_input_register(struct es1968 *chip) } #endif /* CONFIG_SND_ES1968_INPUT */ +#ifdef CONFIG_SND_ES1968_RADIO +#define GPIO_DATA 0x60 +#define IO_MASK 4 /* mask register offset from GPIO_DATA + bits 1=unmask write to given bit */ +#define IO_DIR 8 /* direction register offset from GPIO_DATA + bits 0/1=read/write direction */ +/* mask bits for GPIO lines */ +#define STR_DATA 0x0040 /* GPIO6 */ +#define STR_CLK 0x0080 /* GPIO7 */ +#define STR_WREN 0x0100 /* GPIO8 */ +#define STR_MOST 0x0200 /* GPIO9 */ + +static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) +{ + struct es1968 *chip = tea->private_data; + unsigned long io = chip->io_port + GPIO_DATA; + u16 val = 0; + + val |= (pins & TEA575X_DATA) ? STR_DATA : 0; + val |= (pins & TEA575X_CLK) ? STR_CLK : 0; + val |= (pins & TEA575X_WREN) ? STR_WREN : 0; + + outw(val, io); +} + +static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea) +{ + struct es1968 *chip = tea->private_data; + unsigned long io = chip->io_port + GPIO_DATA; + u16 val = inw(io); + + return (val & STR_DATA) ? TEA575X_DATA : 0 | + (val & STR_MOST) ? TEA575X_MOST : 0; +} + +static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool output) +{ + struct es1968 *chip = tea->private_data; + unsigned long io = chip->io_port + GPIO_DATA; + u16 odir = inw(io + IO_DIR); + + if (output) { + outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); + outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR); + } else { + outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK); + outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR); + } +} + +static struct snd_tea575x_ops snd_es1968_tea_ops = { + .set_pins = snd_es1968_tea575x_set_pins, + .get_pins = snd_es1968_tea575x_get_pins, + .set_direction = snd_es1968_tea575x_set_direction, +}; +#endif + static int snd_es1968_free(struct es1968 *chip) { #ifdef CONFIG_SND_ES1968_INPUT @@ -2585,6 +2650,10 @@ static int snd_es1968_free(struct es1968 *chip) outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */ } +#ifdef CONFIG_SND_ES1968_RADIO + snd_tea575x_exit(&chip->tea); +#endif + if (chip->irq >= 0) free_irq(chip->irq, chip); snd_es1968_free_gameport(chip); @@ -2723,6 +2792,15 @@ static int __devinit snd_es1968_create(struct snd_card *card, snd_card_set_dev(card, &pci->dev); +#ifdef CONFIG_SND_ES1968_RADIO + chip->tea.private_data = chip; + chip->tea.ops = &snd_es1968_tea_ops; + strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card)); + sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); + if (!snd_tea575x_init(&chip->tea)) + printk(KERN_INFO "es1968: detected TEA575x radio\n"); +#endif + *chip_ret = chip; return 0; diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index e1baad74ea4b..eacd4901a308 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -38,7 +38,6 @@ #ifdef CONFIG_SND_FM801_TEA575X_BOOL #include <sound/tea575x-tuner.h> -#define TEA575X_RADIO 1 #endif MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); @@ -53,7 +52,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * /* * Enable TEA575x tuner * 1 = MediaForte 256-PCS - * 2 = MediaForte 256-PCPR + * 2 = MediaForte 256-PCP * 3 = MediaForte 64-PCR * 16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card * High 16-bits are video (radio) device number + 1 @@ -67,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); module_param_array(tea575x_tuner, int, NULL, 0444); -MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only)."); +MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only)."); #define TUNER_ONLY (1<<4) #define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF) @@ -196,7 +195,7 @@ struct fm801 { spinlock_t reg_lock; struct snd_info_entry *proc_entry; -#ifdef TEA575X_RADIO +#ifdef CONFIG_SND_FM801_TEA575X_BOOL struct snd_tea575x tea; #endif @@ -715,310 +714,89 @@ static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pc * TEA5757 radio */ -#ifdef TEA575X_RADIO - -/* 256PCS GPIO numbers */ -#define TEA_256PCS_DATA 1 -#define TEA_256PCS_WRITE_ENABLE 2 /* inverted */ -#define TEA_256PCS_BUS_CLOCK 3 - -static void snd_fm801_tea575x_256pcs_write(struct snd_tea575x *tea, unsigned int val) -{ - struct fm801 *chip = tea->private_data; - unsigned short reg; - int i = 25; +#ifdef CONFIG_SND_FM801_TEA575X_BOOL - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines and set write enable bit */ - reg |= FM801_GPIO_GS(TEA_256PCS_DATA) | - FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK); - /* all of lines are in the write direction */ - /* clear data and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_256PCS_DATA) | - FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCS_DATA) | - FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE)); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - - while (i--) { - if (val & (1 << i)) - reg |= FM801_GPIO_GP(TEA_256PCS_DATA); - else - reg &= ~FM801_GPIO_GP(TEA_256PCS_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - } +/* GPIO to TEA575x maps */ +struct snd_fm801_tea575x_gpio { + u8 data, clk, wren, most; + char *name; +}; - /* and reset the write enable bit */ - reg |= FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GP(TEA_256PCS_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - spin_unlock_irq(&chip->reg_lock); -} +static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = { + { .data = 1, .clk = 3, .wren = 2, .most = 0, .name = "SF256-PCS" }, + { .data = 1, .clk = 0, .wren = 2, .most = 3, .name = "SF256-PCP" }, + { .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" }, +}; -static unsigned int snd_fm801_tea575x_256pcs_read(struct snd_tea575x *tea) +static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) { struct fm801 *chip = tea->private_data; - unsigned short reg; - unsigned int val = 0; - int i; - - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines, set data direction to input */ - reg |= FM801_GPIO_GS(TEA_256PCS_DATA) | - FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK) | - FM801_GPIO_GD(TEA_256PCS_DATA) | - FM801_GPIO_GP(TEA_256PCS_DATA) | - FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE); - /* all of lines are in the write direction, except data */ - /* clear data, write enable and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK)); - - for (i = 0; i < 24; i++) { - reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - val <<= 1; - if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCS_DATA)) - val |= 1; - } + unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; - spin_unlock_irq(&chip->reg_lock); + reg &= ~(FM801_GPIO_GP(gpio.data) | + FM801_GPIO_GP(gpio.clk) | + FM801_GPIO_GP(gpio.wren)); - return val; -} + reg |= (pins & TEA575X_DATA) ? FM801_GPIO_GP(gpio.data) : 0; + reg |= (pins & TEA575X_CLK) ? FM801_GPIO_GP(gpio.clk) : 0; + /* WRITE_ENABLE is inverted */ + reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren); -/* 256PCPR GPIO numbers */ -#define TEA_256PCPR_BUS_CLOCK 0 -#define TEA_256PCPR_DATA 1 -#define TEA_256PCPR_WRITE_ENABLE 2 /* inverted */ - -static void snd_fm801_tea575x_256pcpr_write(struct snd_tea575x *tea, unsigned int val) -{ - struct fm801 *chip = tea->private_data; - unsigned short reg; - int i = 25; - - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines and set write enable bit */ - reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) | - FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK); - /* all of lines are in the write direction */ - /* clear data and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_256PCPR_DATA) | - FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCPR_DATA) | - FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE)); outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - - while (i--) { - if (val & (1 << i)) - reg |= FM801_GPIO_GP(TEA_256PCPR_DATA); - else - reg &= ~FM801_GPIO_GP(TEA_256PCPR_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - } - - /* and reset the write enable bit */ - reg |= FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GP(TEA_256PCPR_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - spin_unlock_irq(&chip->reg_lock); } -static unsigned int snd_fm801_tea575x_256pcpr_read(struct snd_tea575x *tea) +static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea) { struct fm801 *chip = tea->private_data; - unsigned short reg; - unsigned int val = 0; - int i; - - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines, set data direction to input */ - reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) | - FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK) | - FM801_GPIO_GD(TEA_256PCPR_DATA) | - FM801_GPIO_GP(TEA_256PCPR_DATA) | - FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE); - /* all of lines are in the write direction, except data */ - /* clear data, write enable and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK)); - - for (i = 0; i < 24; i++) { - reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - val <<= 1; - if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCPR_DATA)) - val |= 1; - } + unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; - spin_unlock_irq(&chip->reg_lock); - - return val; + return (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 | + (reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0; } -/* 64PCR GPIO numbers */ -#define TEA_64PCR_BUS_CLOCK 0 -#define TEA_64PCR_WRITE_ENABLE 1 /* inverted */ -#define TEA_64PCR_DATA 2 - -static void snd_fm801_tea575x_64pcr_write(struct snd_tea575x *tea, unsigned int val) +static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output) { struct fm801 *chip = tea->private_data; - unsigned short reg; - int i = 25; + unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); /* use GPIO lines and set write enable bit */ - reg |= FM801_GPIO_GS(TEA_64PCR_DATA) | - FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK); - /* all of lines are in the write direction */ - /* clear data and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_64PCR_DATA) | - FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_64PCR_DATA) | - FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE)); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - - while (i--) { - if (val & (1 << i)) - reg |= FM801_GPIO_GP(TEA_64PCR_DATA); - else - reg &= ~FM801_GPIO_GP(TEA_64PCR_DATA); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); + reg |= FM801_GPIO_GS(gpio.data) | + FM801_GPIO_GS(gpio.wren) | + FM801_GPIO_GS(gpio.clk) | + FM801_GPIO_GS(gpio.most); + if (output) { + /* all of lines are in the write direction */ + /* clear data and clock lines */ + reg &= ~(FM801_GPIO_GD(gpio.data) | + FM801_GPIO_GD(gpio.wren) | + FM801_GPIO_GD(gpio.clk) | + FM801_GPIO_GP(gpio.data) | + FM801_GPIO_GP(gpio.clk) | + FM801_GPIO_GP(gpio.wren)); + } else { + /* use GPIO lines, set data direction to input */ + reg |= FM801_GPIO_GD(gpio.data) | + FM801_GPIO_GD(gpio.most) | + FM801_GPIO_GP(gpio.data) | + FM801_GPIO_GP(gpio.most) | + FM801_GPIO_GP(gpio.wren); + /* all of lines are in the write direction, except data */ + /* clear data, write enable and clock lines */ + reg &= ~(FM801_GPIO_GD(gpio.wren) | + FM801_GPIO_GD(gpio.clk) | + FM801_GPIO_GP(gpio.clk)); } - /* and reset the write enable bit */ - reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GP(TEA_64PCR_DATA); outw(reg, FM801_REG(chip, GPIO_CTRL)); - spin_unlock_irq(&chip->reg_lock); -} - -static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea) -{ - struct fm801 *chip = tea->private_data; - unsigned short reg; - unsigned int val = 0; - int i; - - spin_lock_irq(&chip->reg_lock); - reg = inw(FM801_REG(chip, GPIO_CTRL)); - /* use GPIO lines, set data direction to input */ - reg |= FM801_GPIO_GS(TEA_64PCR_DATA) | - FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK) | - FM801_GPIO_GD(TEA_64PCR_DATA) | - FM801_GPIO_GP(TEA_64PCR_DATA) | - FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); - /* all of lines are in the write direction, except data */ - /* clear data, write enable and clock lines */ - reg &= ~(FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) | - FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) | - FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK)); - - for (i = 0; i < 24; i++) { - reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - val <<= 1; - if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_64PCR_DATA)) - val |= 1; - } - - spin_unlock_irq(&chip->reg_lock); - - return val; } -static void snd_fm801_tea575x_64pcr_mute(struct snd_tea575x *tea, - unsigned int mute) -{ - struct fm801 *chip = tea->private_data; - unsigned short reg; - - spin_lock_irq(&chip->reg_lock); - - reg = inw(FM801_REG(chip, GPIO_CTRL)); - if (mute) - /* 0xf800 (mute) */ - reg &= ~FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); - else - /* 0xf802 (unmute) */ - reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); - outw(reg, FM801_REG(chip, GPIO_CTRL)); - udelay(1); - - spin_unlock_irq(&chip->reg_lock); -} - -static struct snd_tea575x_ops snd_fm801_tea_ops[3] = { - { - /* 1 = MediaForte 256-PCS */ - .write = snd_fm801_tea575x_256pcs_write, - .read = snd_fm801_tea575x_256pcs_read, - }, - { - /* 2 = MediaForte 256-PCPR */ - .write = snd_fm801_tea575x_256pcpr_write, - .read = snd_fm801_tea575x_256pcpr_read, - }, - { - /* 3 = MediaForte 64-PCR */ - .write = snd_fm801_tea575x_64pcr_write, - .read = snd_fm801_tea575x_64pcr_read, - .mute = snd_fm801_tea575x_64pcr_mute, - } +static struct snd_tea575x_ops snd_fm801_tea_ops = { + .set_pins = snd_fm801_tea575x_set_pins, + .get_pins = snd_fm801_tea575x_get_pins, + .set_direction = snd_fm801_tea575x_set_direction, }; #endif @@ -1371,7 +1149,7 @@ static int snd_fm801_free(struct fm801 *chip) outw(cmdw, FM801_REG(chip, IRQ_MASK)); __end_hw: -#ifdef TEA575X_RADIO +#ifdef CONFIG_SND_FM801_TEA575X_BOOL snd_tea575x_exit(&chip->tea); #endif if (chip->irq >= 0) @@ -1450,16 +1228,25 @@ static int __devinit snd_fm801_create(struct snd_card *card, snd_card_set_dev(card, &pci->dev); -#ifdef TEA575X_RADIO +#ifdef CONFIG_SND_FM801_TEA575X_BOOL + chip->tea.private_data = chip; + chip->tea.ops = &snd_fm801_tea_ops; + sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 && (tea575x_tuner & TUNER_TYPE_MASK) < 4) { - chip->tea.dev_nr = tea575x_tuner >> 16; - chip->tea.card = card; - chip->tea.freq_fixup = 10700; - chip->tea.private_data = chip; - chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1]; - snd_tea575x_init(&chip->tea); - } + if (snd_tea575x_init(&chip->tea)) + snd_printk(KERN_ERR "TEA575x radio not found\n"); + } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) + /* autodetect tuner connection */ + for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) { + chip->tea575x_tuner = tea575x_tuner; + if (!snd_tea575x_init(&chip->tea)) { + snd_printk(KERN_INFO "detected TEA575x radio type %s\n", + snd_fm801_tea575x_gpios[tea575x_tuner - 1].name); + break; + } + } + strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card)); #endif *rchip = chip; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2c79e96d0324..45b4a8d70e08 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -307,6 +307,12 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns); +static bool add_conn_list(struct snd_array *array, hda_nid_t nid); +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len); + /** * snd_hda_get_connections - get connection list * @codec: the HDA codec @@ -320,7 +326,44 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); * Returns the number of connections, or a negative error code. */ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns) + hda_nid_t *conn_list, int max_conns) +{ + struct snd_array *array = &codec->conn_lists; + int i, len, old_used; + hda_nid_t list[HDA_MAX_CONNECTIONS]; + + /* look up the cached results */ + for (i = 0; i < array->used; ) { + hda_nid_t *p = snd_array_elem(array, i); + len = p[1]; + if (nid == *p) + return copy_conn_list(nid, conn_list, max_conns, + p + 2, len); + i += len + 2; + } + + len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS); + if (len < 0) + return len; + + /* add to the cache */ + old_used = array->used; + if (!add_conn_list(array, nid) || !add_conn_list(array, len)) + goto error_add; + for (i = 0; i < len; i++) + if (!add_conn_list(array, list[i])) + goto error_add; + + return copy_conn_list(nid, conn_list, max_conns, list, len); + + error_add: + array->used = old_used; + return -ENOMEM; +} +EXPORT_SYMBOL_HDA(snd_hda_get_connections); + +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns) { unsigned int parm; int i, conn_len, conns; @@ -417,8 +460,28 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, } return conns; } -EXPORT_SYMBOL_HDA(snd_hda_get_connections); +static bool add_conn_list(struct snd_array *array, hda_nid_t nid) +{ + hda_nid_t *p = snd_array_new(array); + if (!p) + return false; + *p = nid; + return true; +} + +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len) +{ + if (len > max_dst) { + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + len, nid); + return -EINVAL; + } + memcpy(dst, src, len * sizeof(hda_nid_t)); + return len; +} /** * snd_hda_queue_unsol_event - add an unsolicited event to queue @@ -937,6 +1000,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec) } EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); +#ifdef SND_HDA_NEEDS_RESUME /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ static void restore_shutup_pins(struct hda_codec *codec) { @@ -953,6 +1017,7 @@ static void restore_shutup_pins(struct hda_codec *codec) } codec->pins_shutup = 0; } +#endif static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); @@ -1017,6 +1082,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) list_del(&codec->list); snd_array_free(&codec->mixers); snd_array_free(&codec->nids); + snd_array_free(&codec->conn_lists); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -1077,6 +1143,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); + snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { @@ -1329,6 +1396,7 @@ static void purify_inactive_streams(struct hda_codec *codec) } } +#ifdef SND_HDA_NEEDS_RESUME /* clean up all streams; called from suspend */ static void hda_cleanup_all_streams(struct hda_codec *codec) { @@ -1340,6 +1408,7 @@ static void hda_cleanup_all_streams(struct hda_codec *codec) really_cleanup_stream(codec, p); } } +#endif /* * amp access functions @@ -2552,7 +2621,7 @@ static unsigned int convert_to_spdif_status(unsigned short val) static void set_dig_out(struct hda_codec *codec, hda_nid_t nid, int verb, int val) { - hda_nid_t *d; + const hda_nid_t *d; snd_hda_codec_write_cache(codec, nid, 0, verb, val); d = codec->slave_dig_outs; @@ -3661,7 +3730,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) * with the proper parameters for set up. * ops.cleanup should be called in hw_free for clean up of streams. * - * This function returns 0 if successfull, or a negative error code. + * This function returns 0 if successful, or a negative error code. */ int __devinit snd_hda_build_pcms(struct hda_bus *bus) { @@ -3803,7 +3872,8 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config); * * Returns 0 if successful, or a negative error code. */ -int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) +int snd_hda_add_new_ctls(struct hda_codec *codec, + const struct snd_kcontrol_new *knew) { int err; @@ -3946,7 +4016,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, hda_nid_t nid) { - struct hda_amp_list *p; + const struct hda_amp_list *p; int ch, v; if (!check->amplist) @@ -4114,7 +4184,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, -1); snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); if (codec->slave_dig_outs) { - hda_nid_t *d; + const hda_nid_t *d; for (d = codec->slave_dig_outs; *d; d++) snd_hda_codec_setup_stream(codec, *d, stream_tag, 0, format); @@ -4129,7 +4199,7 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) { snd_hda_codec_cleanup_stream(codec, nid); if (codec->slave_dig_outs) { - hda_nid_t *d; + const hda_nid_t *d; for (d = codec->slave_dig_outs; *d; d++) snd_hda_codec_cleanup_stream(codec, *d); } @@ -4276,7 +4346,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, unsigned int format, struct snd_pcm_substream *substream) { - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int chs = substream->runtime->channels; int i; @@ -4331,7 +4401,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare); int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) { - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int i; for (i = 0; i < mout->num_dacs; i++) @@ -4356,7 +4426,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup); * Helper for automatic pin configuration */ -static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) +static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) { for (; *list; list++) if (*list == nid) @@ -4437,7 +4507,7 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) */ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, - hda_nid_t *ignore_nids) + const hda_nid_t *ignore_nids) { hda_nid_t nid, end_nid; short seq, assoc_line_out, assoc_speaker; @@ -4628,10 +4698,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, /* * debug prints of the parsed results */ - snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], cfg->line_out_pins[2], cfg->line_out_pins[3], - cfg->line_out_pins[4]); + cfg->line_out_pins[4], + cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : + (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? + "speaker" : "line")); snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", cfg->speaker_outs, cfg->speaker_pins[0], cfg->speaker_pins[1], cfg->speaker_pins[2], @@ -4646,7 +4719,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, cfg->dig_out_pins[0], cfg->dig_out_pins[1]); snd_printd(" inputs:"); for (i = 0; i < cfg->num_inputs; i++) { - snd_printdd(" %s=0x%x", + snd_printd(" %s=0x%x", hda_get_autocfg_input_label(codec, cfg, i), cfg->inputs[i].pin); } @@ -4851,7 +4924,7 @@ EXPORT_SYMBOL_HDA(snd_hda_suspend); * * Returns 0 if successful. * - * This fucntion is defined only when POWER_SAVE isn't set. + * This function is defined only when POWER_SAVE isn't set. * In the power-save mode, the codec is resumed dynamically. */ int snd_hda_resume(struct hda_bus *bus) @@ -4982,6 +5055,8 @@ static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid, return "Line-out"; case SND_JACK_HEADSET: return "Headset"; + case SND_JACK_VIDEOOUT: + return "HDMI/DP"; default: return "Misc"; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index e46d5420a9f2..59c97306c1de 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -825,12 +825,14 @@ struct hda_codec { struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ + struct snd_array conn_lists; /* connection-list array */ + struct mutex spdif_mutex; struct mutex control_mutex; unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ - hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ + const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ struct snd_array init_pins; /* initial (BIOS) pin configurations */ struct snd_array driver_pins; /* pin configs set by codec parser */ struct snd_array cvt_setups; /* audio convert setups */ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 74b0560289c0..b05f7be9dc1b 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -312,23 +312,6 @@ out_fail: return -EINVAL; } -static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) -{ - int eldv; - int present; - - present = snd_hda_pin_sense(codec, nid); - eldv = (present & AC_PINSENSE_ELDV); - present = (present & AC_PINSENSE_PRESENCE); - -#ifdef CONFIG_SND_DEBUG_VERBOSE - printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n", - !!present, !!eldv); -#endif - - return eldv && present; -} - int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) { return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, @@ -343,7 +326,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, int size; unsigned char *buf; - if (!hdmi_eld_valid(codec, nid)) + if (!eld->eld_valid) return -ENOENT; size = snd_hdmi_get_eld_size(codec, nid); @@ -477,6 +460,8 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present); snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid); + if (!e->eld_valid) + return; snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); snd_iprintf(buffer, "connection_type\t\t%s\n", eld_connection_type_names[e->conn_type]); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 70a9d32f0e96..486f6deb3eee 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -126,6 +126,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH10}," "{Intel, PCH}," "{Intel, CPT}," + "{Intel, PPT}," "{Intel, PBG}," "{Intel, SCH}," "{ATI, SB450}," @@ -390,6 +391,7 @@ struct azx { /* chip type specific */ int driver_type; + unsigned int driver_caps; int playback_streams; int playback_index_offset; int capture_streams; @@ -463,6 +465,34 @@ enum { AZX_NUM_DRIVERS, /* keep this as last entry */ }; +/* driver quirks (capabilities) */ +/* bits 0-7 are used for indicating driver type */ +#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */ +#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ +#define AZX_DCAPS_ATI_SNOOP (1 << 10) /* ATI snoop enable */ +#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11) /* Nvidia snoop enable */ +#define AZX_DCAPS_SCH_SNOOP (1 << 12) /* SCH/PCH snoop enable */ +#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ +#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */ +#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ +#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ +#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ +#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ +#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ + +/* quirks for ATI SB / AMD Hudson */ +#define AZX_DCAPS_PRESET_ATI_SB \ + (AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \ + AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB) + +/* quirks for ATI/AMD HDMI */ +#define AZX_DCAPS_PRESET_ATI_HDMI \ + (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB) + +/* quirks for Nvidia */ +#define AZX_DCAPS_PRESET_NVIDIA \ + (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI) + static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", @@ -565,7 +595,7 @@ static void azx_init_cmd_io(struct azx *chip) /* reset the rirb hw write pointer */ azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); /* set N=1, get RIRB response interrupt for new entry */ - if (chip->driver_type == AZX_DRIVER_CTX) + if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) azx_writew(chip, RINTCNT, 0xc0); else azx_writew(chip, RINTCNT, 1); @@ -1055,19 +1085,24 @@ static void azx_init_pci(struct azx *chip) * codecs. * The PCI register TCSEL is defined in the Intel manuals. */ - if (chip->driver_type != AZX_DRIVER_ATI && - chip->driver_type != AZX_DRIVER_ATIHDMI) + if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) { + snd_printdd(SFX "Clearing TCSEL\n"); update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + } - switch (chip->driver_type) { - case AZX_DRIVER_ATI: - /* For ATI SB450 azalia HD audio, we need to enable snoop */ + /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio, + * we need to enable snoop. + */ + if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) { + snd_printdd(SFX "Enabling ATI snoop\n"); update_pci_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP); - break; - case AZX_DRIVER_NVIDIA: - /* For NVIDIA HDA, enable snoop */ + } + + /* For NVIDIA HDA, enable snoop */ + if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) { + snd_printdd(SFX "Enabling Nvidia snoop\n"); update_pci_byte(chip->pci, NVIDIA_HDA_TRANSREG_ADDR, 0x0f, NVIDIA_HDA_ENABLE_COHBITS); @@ -1077,9 +1112,10 @@ static void azx_init_pci(struct azx *chip) update_pci_byte(chip->pci, NVIDIA_HDA_OSTRM_COH, 0x01, NVIDIA_HDA_ENABLE_COHBIT); - break; - case AZX_DRIVER_SCH: - case AZX_DRIVER_PCH: + } + + /* Enable SCH/PCH snoop if needed */ + if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) { pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, @@ -1090,8 +1126,6 @@ static void azx_init_pci(struct azx *chip) (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ? "Failed" : "OK"); } - break; - } } @@ -1145,7 +1179,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { if (status & RIRB_INT_RESPONSE) { - if (chip->driver_type == AZX_DRIVER_CTX) + if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY) udelay(80); azx_update_rirb(chip); } @@ -1414,8 +1448,10 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) if (err < 0) return err; - if (chip->driver_type == AZX_DRIVER_NVIDIA) + if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { + snd_printd(SFX "Enable delay in RIRB handling\n"); chip->bus->needs_damn_long_delay = 1; + } codecs = 0; max_slots = azx_max_codecs[chip->driver_type]; @@ -1446,6 +1482,16 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) } } + /* AMD chipsets often cause the communication stalls upon certain + * sequence like the pin-detection. It seems that forcing the synced + * access works around the stall. Grrr... + */ + if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) { + snd_printd(SFX "Enable sync_write for stable communication\n"); + chip->bus->sync_write = 1; + chip->bus->allow_bus_reset = 1; + } + /* Then create codec instances */ for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { @@ -1702,7 +1748,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) stream_tag = azx_dev->stream_tag; /* CA-IBG chips need the playback stream starting from 1 */ - if (chip->driver_type == AZX_DRIVER_CTX && + if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) && stream_tag > chip->capture_streams) stream_tag -= chip->capture_streams; return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag, @@ -2347,13 +2393,14 @@ static int __devinit check_position_fix(struct azx *chip, int fix) } /* Check VIA/ATI HD Audio Controller exist */ - switch (chip->driver_type) { - case AZX_DRIVER_VIA: - case AZX_DRIVER_ATI: - /* Use link position directly, avoid any transfer problem. */ + if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) { + snd_printd(SFX "Using VIACOMBO position fix\n"); return POS_FIX_VIACOMBO; } - + if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) { + snd_printd(SFX "Using LPIB position fix\n"); + return POS_FIX_LPIB; + } return POS_FIX_AUTO; } @@ -2435,8 +2482,8 @@ static void __devinit check_msi(struct azx *chip) } /* NVidia chipsets seem to cause troubles with MSI */ - if (chip->driver_type == AZX_DRIVER_NVIDIA) { - printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n"); + if (chip->driver_caps & AZX_DCAPS_NO_MSI) { + printk(KERN_INFO "hda_intel: Disabling MSI\n"); chip->msi = 0; } } @@ -2446,7 +2493,7 @@ static void __devinit check_msi(struct azx *chip) * constructor */ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, - int dev, int driver_type, + int dev, unsigned int driver_caps, struct azx **rchip) { struct azx *chip; @@ -2474,7 +2521,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->card = card; chip->pci = pci; chip->irq = -1; - chip->driver_type = driver_type; + chip->driver_caps = driver_caps; + chip->driver_type = driver_caps & 0xff; check_msi(chip); chip->dev_index = dev; INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); @@ -2538,8 +2586,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap); /* disable SB600 64bit support for safety */ - if ((chip->driver_type == AZX_DRIVER_ATI) || - (chip->driver_type == AZX_DRIVER_ATIHDMI)) { + if (chip->pci->vendor == PCI_VENDOR_ID_ATI) { struct pci_dev *p_smbus; p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, @@ -2551,10 +2598,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } } - /* disable 64bit DMA address for Teradici */ - /* it does not work with device 6549:1200 subsys e4a2:040b */ - if (chip->driver_type == AZX_DRIVER_TERA) + /* disable 64bit DMA address on some devices */ + if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { + snd_printd(SFX "Disabling 64bit DMA\n"); gcap &= ~ICH6_GCAP_64OK; + } /* allow 64bit DMA address if supported by H/W */ if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) @@ -2756,36 +2804,62 @@ static void __devexit azx_remove(struct pci_dev *pci) /* PCI IDs */ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* CPT */ - { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, + { PCI_DEVICE(0x8086, 0x1c20), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, /* PBG */ - { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH }, + { PCI_DEVICE(0x8086, 0x1d20), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, + /* Panther Point */ + { PCI_DEVICE(0x8086, 0x1e20), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, /* SCH */ - { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, + { PCI_DEVICE(0x8086, 0x811b), + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP }, /* Generic Intel */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_ICH }, - /* ATI SB 450/600 */ - { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI }, - { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI }, + /* ATI SB 450/600/700/800/900 */ + { PCI_DEVICE(0x1002, 0x437b), + .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, + { PCI_DEVICE(0x1002, 0x4383), + .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, + /* AMD Hudson */ + { PCI_DEVICE(0x1022, 0x780d), + .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, /* ATI HDMI */ - { PCI_DEVICE(0x1002, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0x970f), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI }, - { PCI_DEVICE(0x1002, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI }, + { PCI_DEVICE(0x1002, 0x793b), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0x7919), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0x960f), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0x970f), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa00), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa08), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa10), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa18), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa20), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa28), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa30), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa38), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa40), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa48), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, /* VIA VT8251/VT8237A */ - { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, + { PCI_DEVICE(0x1106, 0x3288), + .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA }, /* SIS966 */ { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS }, /* ULI M5461 */ @@ -2794,9 +2868,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_NVIDIA }, + .driver_data = AZX_DRIVER_NVIDIA | AZX_DCAPS_PRESET_NVIDIA }, /* Teradici */ - { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, + { PCI_DEVICE(0x6549, 0x1200), + .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT }, /* Creative X-Fi (CA0110-IBG) */ #if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE) /* the following entry conflicts with snd-ctxfi driver, @@ -2806,10 +2881,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_CTX }, + .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | + AZX_DCAPS_RIRB_PRE_DELAY }, #else /* this entry seems still valid -- i.e. without emu20kx chip */ - { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX }, + { PCI_DEVICE(0x1102, 0x0009), + .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | + AZX_DCAPS_RIRB_PRE_DELAY }, #endif /* Vortex86MX */ { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, @@ -2819,11 +2897,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_GENERIC }, + .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_GENERIC }, + .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index ff5e2ac2239a..08ec073444e2 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -267,11 +267,11 @@ enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */ struct hda_multi_out { int num_dacs; /* # of DACs, must be more than 1 */ - hda_nid_t *dac_nids; /* DAC list */ + const hda_nid_t *dac_nids; /* DAC list */ hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */ hda_nid_t extra_out_nid[3]; /* optional DACs, 0 when not exists */ hda_nid_t dig_out_nid; /* digital out audio widget */ - hda_nid_t *slave_dig_outs; + const hda_nid_t *slave_dig_outs; int max_channels; /* currently supported analog channels */ int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ int no_share_stream; /* don't share a stream with multiple pins */ @@ -347,7 +347,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, int num_configs, const char * const *models, const struct snd_pci_quirk *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, - struct snd_kcontrol_new *knew); + const struct snd_kcontrol_new *knew); /* * unsolicited event handler @@ -443,7 +443,7 @@ struct auto_pin_cfg { int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, - hda_nid_t *ignore_nids); + const hda_nid_t *ignore_nids); /* amp values */ #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) @@ -493,6 +493,12 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); +static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) +{ + return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) && + (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP); +} + /* flags for hda_nid_item */ #define HDA_NID_ITEM_AMP (1<<0) @@ -567,7 +573,7 @@ struct hda_amp_list { }; struct hda_loopback_check { - struct hda_amp_list *amplist; + const struct hda_amp_list *amplist; int power_on; }; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2942d2a9ea10..696ac2590307 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -30,7 +30,7 @@ #include "hda_beep.h" struct ad198x_spec { - struct snd_kcontrol_new *mixers[6]; + const struct snd_kcontrol_new *mixers[6]; int num_mixers; unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ const struct hda_verb *init_verbs[6]; /* initialization verbs @@ -46,17 +46,17 @@ struct ad198x_spec { unsigned int cur_eapd; unsigned int need_dac_fix; - hda_nid_t *alt_dac_nid; - struct hda_pcm_stream *stream_analog_alt_playback; + const hda_nid_t *alt_dac_nid; + const struct hda_pcm_stream *stream_analog_alt_playback; /* capture */ unsigned int num_adc_nids; - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ /* capture source */ const struct hda_input_mux *input_mux; - hda_nid_t *capsrc_nids; + const hda_nid_t *capsrc_nids; unsigned int cur_mux[3]; /* channel model */ @@ -182,13 +182,13 @@ static void ad198x_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ -static struct snd_kcontrol_new ad_beep_mixer[] = { +static const struct snd_kcontrol_new ad_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT), { } /* end */ }; -static struct snd_kcontrol_new ad_beep2_mixer[] = { +static const struct snd_kcontrol_new ad_beep2_mixer[] = { HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT), HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT), { } /* end */ @@ -231,7 +231,7 @@ static int ad198x_build_controls(struct hda_codec *codec) /* create beep controls if needed */ #ifdef CONFIG_SND_HDA_INPUT_BEEP if (spec->beep_amp) { - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; for ( ; knew->name; knew++) { struct snd_kcontrol *kctl; @@ -331,7 +331,7 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); } -static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { +static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -403,7 +403,7 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, /* */ -static struct hda_pcm_stream ad198x_pcm_analog_playback = { +static const struct hda_pcm_stream ad198x_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 6, /* changed later */ @@ -415,7 +415,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_playback = { }, }; -static struct hda_pcm_stream ad198x_pcm_analog_capture = { +static const struct hda_pcm_stream ad198x_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -426,7 +426,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_capture = { }, }; -static struct hda_pcm_stream ad198x_pcm_digital_playback = { +static const struct hda_pcm_stream ad198x_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -439,7 +439,7 @@ static struct hda_pcm_stream ad198x_pcm_digital_playback = { }, }; -static struct hda_pcm_stream ad198x_pcm_digital_capture = { +static const struct hda_pcm_stream ad198x_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -489,11 +489,6 @@ static int ad198x_build_pcms(struct hda_codec *codec) return 0; } -static inline void ad198x_shutup(struct hda_codec *codec) -{ - snd_hda_shutup_pins(codec); -} - static void ad198x_free_kctls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -547,6 +542,12 @@ static void ad198x_power_eapd(struct hda_codec *codec) } } +static void ad198x_shutup(struct hda_codec *codec) +{ + snd_hda_shutup_pins(codec); + ad198x_power_eapd(codec); +} + static void ad198x_free(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -564,12 +565,11 @@ static void ad198x_free(struct hda_codec *codec) static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) { ad198x_shutup(codec); - ad198x_power_eapd(codec); return 0; } #endif -static struct hda_codec_ops ad198x_patch_ops = { +static const struct hda_codec_ops ad198x_patch_ops = { .build_controls = ad198x_build_controls, .build_pcms = ad198x_build_pcms, .init = ad198x_init, @@ -639,13 +639,13 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, #define AD1986A_CLFE_DAC 0x05 #define AD1986A_ADC 0x06 -static hda_nid_t ad1986a_dac_nids[3] = { +static const hda_nid_t ad1986a_dac_nids[3] = { AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC }; -static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; -static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; +static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; +static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; -static struct hda_input_mux ad1986a_capture_source = { +static const struct hda_input_mux ad1986a_capture_source = { .num_items = 7, .items = { { "Mic", 0x0 }, @@ -659,7 +659,7 @@ static struct hda_input_mux ad1986a_capture_source = { }; -static struct hda_bind_ctls ad1986a_bind_pcm_vol = { +static const struct hda_bind_ctls ad1986a_bind_pcm_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), @@ -669,7 +669,7 @@ static struct hda_bind_ctls ad1986a_bind_pcm_vol = { }, }; -static struct hda_bind_ctls ad1986a_bind_pcm_sw = { +static const struct hda_bind_ctls ad1986a_bind_pcm_sw = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), @@ -682,7 +682,7 @@ static struct hda_bind_ctls ad1986a_bind_pcm_sw = { /* * mixers */ -static struct snd_kcontrol_new ad1986a_mixers[] = { +static const struct snd_kcontrol_new ad1986a_mixers[] = { /* * bind volumes/mutes of 3 DACs as a single PCM control for simplicity */ @@ -723,7 +723,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { }; /* additional mixers for 3stack mode */ -static struct snd_kcontrol_new ad1986a_3st_mixers[] = { +static const struct snd_kcontrol_new ad1986a_3st_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -735,10 +735,10 @@ static struct snd_kcontrol_new ad1986a_3st_mixers[] = { }; /* laptop model - 2ch only */ -static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; +static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; /* master controls both pins 0x1a and 0x1b */ -static struct hda_bind_ctls ad1986a_laptop_master_vol = { +static const struct hda_bind_ctls ad1986a_laptop_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), @@ -747,7 +747,7 @@ static struct hda_bind_ctls ad1986a_laptop_master_vol = { }, }; -static struct hda_bind_ctls ad1986a_laptop_master_sw = { +static const struct hda_bind_ctls ad1986a_laptop_master_sw = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), @@ -756,7 +756,7 @@ static struct hda_bind_ctls ad1986a_laptop_master_sw = { }, }; -static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { +static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), @@ -787,7 +787,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { /* laptop-eapd model - 2ch only */ -static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { +static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -796,7 +796,7 @@ static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { }, }; -static struct hda_input_mux ad1986a_automic_capture_source = { +static const struct hda_input_mux ad1986a_automic_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -804,13 +804,13 @@ static struct hda_input_mux ad1986a_automic_capture_source = { }, }; -static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = { +static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), { } /* end */ }; -static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { +static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), @@ -837,7 +837,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { +static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), { } /* end */ @@ -931,7 +931,7 @@ static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { +static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -949,7 +949,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { /* * initialization verbs */ -static struct hda_verb ad1986a_init_verbs[] = { +static const struct hda_verb ad1986a_init_verbs[] = { /* Front, Surround, CLFE DAC; mute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, @@ -1004,7 +1004,7 @@ static struct hda_verb ad1986a_init_verbs[] = { { } /* end */ }; -static struct hda_verb ad1986a_ch2_init[] = { +static const struct hda_verb ad1986a_ch2_init[] = { /* Surround out -> Line In */ { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line-in selectors */ @@ -1016,7 +1016,7 @@ static struct hda_verb ad1986a_ch2_init[] = { { } /* end */ }; -static struct hda_verb ad1986a_ch4_init[] = { +static const struct hda_verb ad1986a_ch4_init[] = { /* Surround out -> Surround */ { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, @@ -1026,7 +1026,7 @@ static struct hda_verb ad1986a_ch4_init[] = { { } /* end */ }; -static struct hda_verb ad1986a_ch6_init[] = { +static const struct hda_verb ad1986a_ch6_init[] = { /* Surround out -> Surround out */ { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, @@ -1036,19 +1036,19 @@ static struct hda_verb ad1986a_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode ad1986a_modes[3] = { +static const struct hda_channel_mode ad1986a_modes[3] = { { 2, ad1986a_ch2_init }, { 4, ad1986a_ch4_init }, { 6, ad1986a_ch6_init }, }; /* eapd initialization */ -static struct hda_verb ad1986a_eapd_init_verbs[] = { +static const struct hda_verb ad1986a_eapd_init_verbs[] = { {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, {} }; -static struct hda_verb ad1986a_automic_verbs[] = { +static const struct hda_verb ad1986a_automic_verbs[] = { {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/ @@ -1058,7 +1058,7 @@ static struct hda_verb ad1986a_automic_verbs[] = { }; /* Ultra initialization */ -static struct hda_verb ad1986a_ultra_init[] = { +static const struct hda_verb ad1986a_ultra_init[] = { /* eapd initialization */ { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* CLFE -> Mic in */ @@ -1069,7 +1069,7 @@ static struct hda_verb ad1986a_ultra_init[] = { }; /* pin sensing on HP jack */ -static struct hda_verb ad1986a_hp_init_verbs[] = { +static const struct hda_verb ad1986a_hp_init_verbs[] = { {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, {} }; @@ -1120,7 +1120,7 @@ static const char * const ad1986a_models[AD1986A_MODELS] = { [AD1986A_SAMSUNG_P50] = "samsung-p50", }; -static struct snd_pci_quirk ad1986a_cfg_tbl[] = { +static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), @@ -1152,7 +1152,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1986a_loopbacks[] = { +static const struct hda_amp_list ad1986a_loopbacks[] = { { 0x13, HDA_OUTPUT, 0 }, /* Mic */ { 0x14, HDA_OUTPUT, 0 }, /* Phone */ { 0x15, HDA_OUTPUT, 0 }, /* CD */ @@ -1329,11 +1329,11 @@ static int patch_ad1986a(struct hda_codec *codec) #define AD1983_DAC 0x03 #define AD1983_ADC 0x04 -static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; -static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; -static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; +static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; +static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; +static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; -static struct hda_input_mux ad1983_capture_source = { +static const struct hda_input_mux ad1983_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -1348,7 +1348,7 @@ static struct hda_input_mux ad1983_capture_source = { */ static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "PCM", "ADC" }; + static const char * const texts[] = { "PCM", "ADC" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1385,7 +1385,7 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ return 0; } -static struct snd_kcontrol_new ad1983_mixers[] = { +static const struct snd_kcontrol_new ad1983_mixers[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), @@ -1418,7 +1418,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = { { } /* end */ }; -static struct hda_verb ad1983_init_verbs[] = { +static const struct hda_verb ad1983_init_verbs[] = { /* Front, HP, Mono; mute as default */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, @@ -1458,7 +1458,7 @@ static struct hda_verb ad1983_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1983_loopbacks[] = { +static const struct hda_amp_list ad1983_loopbacks[] = { { 0x12, HDA_OUTPUT, 0 }, /* Mic */ { 0x13, HDA_OUTPUT, 0 }, /* Line */ { } /* end */ @@ -1518,12 +1518,12 @@ static int patch_ad1983(struct hda_codec *codec) #define AD1981_DAC 0x03 #define AD1981_ADC 0x04 -static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; -static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; -static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; +static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; +static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; +static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ -static struct hda_input_mux ad1981_capture_source = { +static const struct hda_input_mux ad1981_capture_source = { .num_items = 7, .items = { { "Front Mic", 0x0 }, @@ -1536,7 +1536,7 @@ static struct hda_input_mux ad1981_capture_source = { }, }; -static struct snd_kcontrol_new ad1981_mixers[] = { +static const struct snd_kcontrol_new ad1981_mixers[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), @@ -1577,7 +1577,7 @@ static struct snd_kcontrol_new ad1981_mixers[] = { { } /* end */ }; -static struct hda_verb ad1981_init_verbs[] = { +static const struct hda_verb ad1981_init_verbs[] = { /* Front, HP, Mono; mute as default */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, @@ -1625,7 +1625,7 @@ static struct hda_verb ad1981_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1981_loopbacks[] = { +static const struct hda_amp_list ad1981_loopbacks[] = { { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ { 0x13, HDA_OUTPUT, 0 }, /* Line */ { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ @@ -1645,7 +1645,7 @@ static struct hda_amp_list ad1981_loopbacks[] = { #define AD1981_HP_EVENT 0x37 #define AD1981_MIC_EVENT 0x38 -static struct hda_verb ad1981_hp_init_verbs[] = { +static const struct hda_verb ad1981_hp_init_verbs[] = { {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ /* pin sensing on HP and Mic jacks */ {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, @@ -1674,7 +1674,7 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, } /* bind volumes of both NID 0x05 and 0x06 */ -static struct hda_bind_ctls ad1981_hp_bind_master_vol = { +static const struct hda_bind_ctls ad1981_hp_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), @@ -1696,12 +1696,12 @@ static void ad1981_hp_automute(struct hda_codec *codec) /* toggle input of built-in and mic jack appropriately */ static void ad1981_hp_automic(struct hda_codec *codec) { - static struct hda_verb mic_jack_on[] = { + static const struct hda_verb mic_jack_on[] = { {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, {} }; - static struct hda_verb mic_jack_off[] = { + static const struct hda_verb mic_jack_off[] = { {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, {} @@ -1730,7 +1730,7 @@ static void ad1981_hp_unsol_event(struct hda_codec *codec, } } -static struct hda_input_mux ad1981_hp_capture_source = { +static const struct hda_input_mux ad1981_hp_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -1739,7 +1739,7 @@ static struct hda_input_mux ad1981_hp_capture_source = { }, }; -static struct snd_kcontrol_new ad1981_hp_mixers[] = { +static const struct snd_kcontrol_new ad1981_hp_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1790,7 +1790,7 @@ static int ad1981_hp_init(struct hda_codec *codec) } /* configuration for Toshiba Laptops */ -static struct hda_verb ad1981_toshiba_init_verbs[] = { +static const struct hda_verb ad1981_toshiba_init_verbs[] = { {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */ /* pin sensing on HP and Mic jacks */ {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, @@ -1798,14 +1798,14 @@ static struct hda_verb ad1981_toshiba_init_verbs[] = { {} }; -static struct snd_kcontrol_new ad1981_toshiba_mixers[] = { +static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = { HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT), { } }; /* configuration for Lenovo Thinkpad T60 */ -static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { +static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), @@ -1835,7 +1835,7 @@ static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { { } /* end */ }; -static struct hda_input_mux ad1981_thinkpad_capture_source = { +static const struct hda_input_mux ad1981_thinkpad_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -1860,7 +1860,7 @@ static const char * const ad1981_models[AD1981_MODELS] = { [AD1981_TOSHIBA] = "toshiba" }; -static struct snd_pci_quirk ad1981_cfg_tbl[] = { +static const struct snd_pci_quirk ad1981_cfg_tbl[] = { SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), /* All HP models */ @@ -2075,32 +2075,32 @@ enum { * mixers */ -static hda_nid_t ad1988_6stack_dac_nids[4] = { +static const hda_nid_t ad1988_6stack_dac_nids[4] = { 0x04, 0x06, 0x05, 0x0a }; -static hda_nid_t ad1988_3stack_dac_nids[3] = { +static const hda_nid_t ad1988_3stack_dac_nids[3] = { 0x04, 0x05, 0x0a }; /* for AD1988A revision-2, DAC2-4 are swapped */ -static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { +static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { 0x04, 0x05, 0x0a, 0x06 }; -static hda_nid_t ad1988_alt_dac_nid[1] = { +static const hda_nid_t ad1988_alt_dac_nid[1] = { 0x03 }; -static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { +static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { 0x04, 0x0a, 0x06 }; -static hda_nid_t ad1988_adc_nids[3] = { +static const hda_nid_t ad1988_adc_nids[3] = { 0x08, 0x09, 0x0f }; -static hda_nid_t ad1988_capsrc_nids[3] = { +static const hda_nid_t ad1988_capsrc_nids[3] = { 0x0c, 0x0d, 0x0e }; @@ -2108,11 +2108,11 @@ static hda_nid_t ad1988_capsrc_nids[3] = { #define AD1988_SPDIF_OUT_HDMI 0x0b #define AD1988_SPDIF_IN 0x07 -static hda_nid_t ad1989b_slave_dig_outs[] = { +static const hda_nid_t ad1989b_slave_dig_outs[] = { AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0 }; -static struct hda_input_mux ad1988_6stack_capture_source = { +static const struct hda_input_mux ad1988_6stack_capture_source = { .num_items = 5, .items = { { "Front Mic", 0x1 }, /* port-B */ @@ -2123,7 +2123,7 @@ static struct hda_input_mux ad1988_6stack_capture_source = { }, }; -static struct hda_input_mux ad1988_laptop_capture_source = { +static const struct hda_input_mux ad1988_laptop_capture_source = { .num_items = 3, .items = { { "Mic/Line", 0x1 }, /* port-B */ @@ -2166,7 +2166,7 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, } /* 6-stack mode */ -static struct snd_kcontrol_new ad1988_6stack_mixers1[] = { +static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), @@ -2175,7 +2175,7 @@ static struct snd_kcontrol_new ad1988_6stack_mixers1[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { +static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), @@ -2184,7 +2184,7 @@ static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { +static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = { HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), @@ -2211,14 +2211,14 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { +static const struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), { } /* end */ }; /* 3-stack mode */ -static struct snd_kcontrol_new ad1988_3stack_mixers1[] = { +static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), @@ -2226,7 +2226,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers1[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { +static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT), @@ -2234,7 +2234,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_3stack_mixers2[] = { +static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = { HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT), HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT), @@ -2268,7 +2268,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = { }; /* laptop mode */ -static struct snd_kcontrol_new ad1988_laptop_mixers[] = { +static const struct snd_kcontrol_new ad1988_laptop_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT), HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), @@ -2299,7 +2299,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { }; /* capture */ -static struct snd_kcontrol_new ad1988_capture_mixers[] = { +static const struct snd_kcontrol_new ad1988_capture_mixers[] = { HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), @@ -2324,7 +2324,7 @@ static struct snd_kcontrol_new ad1988_capture_mixers[] = { static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "PCM", "ADC1", "ADC2", "ADC3" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -2405,7 +2405,7 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { +static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -2418,12 +2418,12 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { +static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT), { } /* end */ }; -static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { +static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT), { } /* end */ @@ -2436,7 +2436,7 @@ static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { /* * for 6-stack (+dig) */ -static struct hda_verb ad1988_6stack_init_verbs[] = { +static const struct hda_verb ad1988_6stack_init_verbs[] = { /* Front, Surround, CLFE, side DAC; unmute as default */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -2496,7 +2496,7 @@ static struct hda_verb ad1988_6stack_init_verbs[] = { { } }; -static struct hda_verb ad1988_6stack_fp_init_verbs[] = { +static const struct hda_verb ad1988_6stack_fp_init_verbs[] = { /* Headphone; unmute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Port-A front headphon path */ @@ -2509,7 +2509,7 @@ static struct hda_verb ad1988_6stack_fp_init_verbs[] = { { } }; -static struct hda_verb ad1988_capture_init_verbs[] = { +static const struct hda_verb ad1988_capture_init_verbs[] = { /* mute analog mix */ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -2527,7 +2527,7 @@ static struct hda_verb ad1988_capture_init_verbs[] = { { } }; -static struct hda_verb ad1988_spdif_init_verbs[] = { +static const struct hda_verb ad1988_spdif_init_verbs[] = { /* SPDIF out sel */ {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ @@ -2539,14 +2539,14 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { { } }; -static struct hda_verb ad1988_spdif_in_init_verbs[] = { +static const struct hda_verb ad1988_spdif_in_init_verbs[] = { /* unmute SPDIF input pin */ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { } }; /* AD1989 has no ADC -> SPDIF route */ -static struct hda_verb ad1989_spdif_init_verbs[] = { +static const struct hda_verb ad1989_spdif_init_verbs[] = { /* SPDIF-1 out pin */ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ @@ -2559,7 +2559,7 @@ static struct hda_verb ad1989_spdif_init_verbs[] = { /* * verbs for 3stack (+dig) */ -static struct hda_verb ad1988_3stack_ch2_init[] = { +static const struct hda_verb ad1988_3stack_ch2_init[] = { /* set port-C to line-in */ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -2569,7 +2569,7 @@ static struct hda_verb ad1988_3stack_ch2_init[] = { { } /* end */ }; -static struct hda_verb ad1988_3stack_ch6_init[] = { +static const struct hda_verb ad1988_3stack_ch6_init[] = { /* set port-C to surround out */ { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -2579,12 +2579,12 @@ static struct hda_verb ad1988_3stack_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode ad1988_3stack_modes[2] = { +static const struct hda_channel_mode ad1988_3stack_modes[2] = { { 2, ad1988_3stack_ch2_init }, { 6, ad1988_3stack_ch6_init }, }; -static struct hda_verb ad1988_3stack_init_verbs[] = { +static const struct hda_verb ad1988_3stack_init_verbs[] = { /* Front, Surround, CLFE, side DAC; unmute as default */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -2644,13 +2644,13 @@ static struct hda_verb ad1988_3stack_init_verbs[] = { /* * verbs for laptop mode (+dig) */ -static struct hda_verb ad1988_laptop_hp_on[] = { +static const struct hda_verb ad1988_laptop_hp_on[] = { /* unmute port-A and mute port-D */ { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { } /* end */ }; -static struct hda_verb ad1988_laptop_hp_off[] = { +static const struct hda_verb ad1988_laptop_hp_off[] = { /* mute port-A and unmute port-D */ { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -2659,7 +2659,7 @@ static struct hda_verb ad1988_laptop_hp_off[] = { #define AD1988_HP_EVENT 0x01 -static struct hda_verb ad1988_laptop_init_verbs[] = { +static const struct hda_verb ad1988_laptop_init_verbs[] = { /* Front, Surround, CLFE, side DAC; unmute as default */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -2723,7 +2723,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1988_loopbacks[] = { +static const struct hda_amp_list ad1988_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ { 0x20, HDA_INPUT, 1 }, /* Line */ { 0x20, HDA_INPUT, 4 }, /* Mic */ @@ -2741,7 +2741,7 @@ enum { AD_CTL_WIDGET_MUTE, AD_CTL_BIND_MUTE, }; -static struct snd_kcontrol_new ad1988_control_templates[] = { +static const struct snd_kcontrol_new ad1988_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), HDA_BIND_MUTE(NULL, 0, 0, 0), @@ -2770,18 +2770,18 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, #define AD1988_PIN_CD_NID 0x18 #define AD1988_PIN_BEEP_NID 0x10 -static hda_nid_t ad1988_mixer_nids[8] = { +static const hda_nid_t ad1988_mixer_nids[8] = { /* A B C D E F G H */ 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28 }; static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx) { - static hda_nid_t idx_to_dac[8] = { + static const hda_nid_t idx_to_dac[8] = { /* A B C D E F G H */ 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a }; - static hda_nid_t idx_to_dac_rev2[8] = { + static const hda_nid_t idx_to_dac_rev2[8] = { /* A B C D E F G H */ 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06 }; @@ -2791,13 +2791,13 @@ static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx) return idx_to_dac[idx]; } -static hda_nid_t ad1988_boost_nids[8] = { +static const hda_nid_t ad1988_boost_nids[8] = { 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0 }; static int ad1988_pin_idx(hda_nid_t nid) { - static hda_nid_t ad1988_io_pins[8] = { + static const hda_nid_t ad1988_io_pins[8] = { 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25 }; int i; @@ -2809,7 +2809,7 @@ static int ad1988_pin_idx(hda_nid_t nid) static int ad1988_pin_to_loopback_idx(hda_nid_t nid) { - static int loopback_idx[8] = { + static const int loopback_idx[8] = { 2, 0, 1, 3, 4, 5, 1, 4 }; switch (nid) { @@ -2822,7 +2822,7 @@ static int ad1988_pin_to_loopback_idx(hda_nid_t nid) static int ad1988_pin_to_adc_idx(hda_nid_t nid) { - static int adc_idx[8] = { + static const int adc_idx[8] = { 0, 1, 2, 8, 4, 3, 6, 7 }; switch (nid) { @@ -2845,7 +2845,7 @@ static int ad1988_auto_fill_dac_nids(struct hda_codec *codec, /* check the pins hardwired to audio widget */ for (i = 0; i < cfg->line_outs; i++) { idx = ad1988_pin_idx(cfg->line_out_pins[i]); - spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx); + spec->private_dac_nids[i] = ad1988_idx_to_dac(codec, idx); } spec->multiout.num_dacs = cfg->line_outs; return 0; @@ -3070,6 +3070,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; + int type = cfg->inputs[i].type; switch (nid) { case 0x15: /* port-C */ snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0); @@ -3079,7 +3080,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec) break; } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN); + type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN); if (nid != AD1988_PIN_CD_NID) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); @@ -3154,10 +3155,11 @@ static const char * const ad1988_models[AD1988_MODEL_LAST] = { [AD1988_AUTO] = "auto", }; -static struct snd_pci_quirk ad1988_cfg_tbl[] = { +static const struct snd_pci_quirk ad1988_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG), + SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG), {} }; @@ -3342,21 +3344,21 @@ static int patch_ad1988(struct hda_codec *codec) * but no build-up framework is given, so far. */ -static hda_nid_t ad1884_dac_nids[1] = { +static const hda_nid_t ad1884_dac_nids[1] = { 0x04, }; -static hda_nid_t ad1884_adc_nids[2] = { +static const hda_nid_t ad1884_adc_nids[2] = { 0x08, 0x09, }; -static hda_nid_t ad1884_capsrc_nids[2] = { +static const hda_nid_t ad1884_capsrc_nids[2] = { 0x0c, 0x0d, }; #define AD1884_SPDIF_OUT 0x02 -static struct hda_input_mux ad1884_capture_source = { +static const struct hda_input_mux ad1884_capture_source = { .num_items = 4, .items = { { "Front Mic", 0x0 }, @@ -3366,7 +3368,7 @@ static struct hda_input_mux ad1884_capture_source = { }, }; -static struct snd_kcontrol_new ad1884_base_mixers[] = { +static const struct snd_kcontrol_new ad1884_base_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), @@ -3410,7 +3412,7 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1984_dmic_mixers[] = { +static const struct snd_kcontrol_new ad1984_dmic_mixers[] = { HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0, @@ -3423,7 +3425,7 @@ static struct snd_kcontrol_new ad1984_dmic_mixers[] = { /* * initialization verbs */ -static struct hda_verb ad1884_init_verbs[] = { +static const struct hda_verb ad1884_init_verbs[] = { /* DACs; mute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -3469,7 +3471,7 @@ static struct hda_verb ad1884_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1884_loopbacks[] = { +static const struct hda_amp_list ad1884_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ { 0x20, HDA_INPUT, 1 }, /* Mic */ { 0x20, HDA_INPUT, 2 }, /* CD */ @@ -3541,7 +3543,7 @@ static int patch_ad1884(struct hda_codec *codec) /* * Lenovo Thinkpad T61/X61 */ -static struct hda_input_mux ad1984_thinkpad_capture_source = { +static const struct hda_input_mux ad1984_thinkpad_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -3555,7 +3557,7 @@ static struct hda_input_mux ad1984_thinkpad_capture_source = { /* * Dell Precision T3400 */ -static struct hda_input_mux ad1984_dell_desktop_capture_source = { +static const struct hda_input_mux ad1984_dell_desktop_capture_source = { .num_items = 3, .items = { { "Front Mic", 0x0 }, @@ -3565,7 +3567,7 @@ static struct hda_input_mux ad1984_dell_desktop_capture_source = { }; -static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { +static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), @@ -3611,7 +3613,7 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { }; /* additional verbs */ -static struct hda_verb ad1984_thinkpad_init_verbs[] = { +static const struct hda_verb ad1984_thinkpad_init_verbs[] = { /* Port-E (docking station mic) pin */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, @@ -3629,7 +3631,7 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = { /* * Dell Precision T3400 */ -static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { +static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), @@ -3680,7 +3682,7 @@ static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream ad1984_pcm_dmic_capture = { +static const struct hda_pcm_stream ad1984_pcm_dmic_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -3722,7 +3724,7 @@ static const char * const ad1984_models[AD1984_MODELS] = { [AD1984_DELL_DESKTOP] = "dell_desktop", }; -static struct snd_pci_quirk ad1984_cfg_tbl[] = { +static const struct snd_pci_quirk ad1984_cfg_tbl[] = { /* Lenovo Thinkpad T61/X61 */ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), @@ -3787,7 +3789,7 @@ static int patch_ad1984(struct hda_codec *codec) * We share the single DAC for both HP and line-outs (see AD1884/1984). */ -static hda_nid_t ad1884a_dac_nids[1] = { +static const hda_nid_t ad1884a_dac_nids[1] = { 0x03, }; @@ -3796,7 +3798,7 @@ static hda_nid_t ad1884a_dac_nids[1] = { #define AD1884A_SPDIF_OUT 0x02 -static struct hda_input_mux ad1884a_capture_source = { +static const struct hda_input_mux ad1884a_capture_source = { .num_items = 5, .items = { { "Front Mic", 0x0 }, @@ -3807,7 +3809,7 @@ static struct hda_input_mux ad1884a_capture_source = { }, }; -static struct snd_kcontrol_new ad1884a_base_mixers[] = { +static const struct snd_kcontrol_new ad1884a_base_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), @@ -3859,7 +3861,7 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = { /* * initialization verbs */ -static struct hda_verb ad1884a_init_verbs[] = { +static const struct hda_verb ad1884a_init_verbs[] = { /* DACs; unmute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ @@ -3914,7 +3916,7 @@ static struct hda_verb ad1884a_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1884a_loopbacks[] = { +static const struct hda_amp_list ad1884a_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ { 0x20, HDA_INPUT, 1 }, /* Mic */ { 0x20, HDA_INPUT, 2 }, /* CD */ @@ -3947,7 +3949,7 @@ static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, return ret; } -static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { +static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -3975,7 +3977,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { +static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ { @@ -4095,7 +4097,7 @@ static int ad1884a_laptop_init(struct hda_codec *codec) } /* additional verbs for laptop model */ -static struct hda_verb ad1884a_laptop_verbs[] = { +static const struct hda_verb ad1884a_laptop_verbs[] = { /* Port-A (HP) pin - always unmuted */ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Port-F (int speaker) mixer - route only from analog mixer */ @@ -4126,7 +4128,7 @@ static struct hda_verb ad1884a_laptop_verbs[] = { { } /* end */ }; -static struct hda_verb ad1884a_mobile_verbs[] = { +static const struct hda_verb ad1884a_mobile_verbs[] = { /* DACs; unmute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ @@ -4181,7 +4183,7 @@ static struct hda_verb ad1884a_mobile_verbs[] = { * 0x17 - built-in mic */ -static struct hda_verb ad1984a_thinkpad_verbs[] = { +static const struct hda_verb ad1984a_thinkpad_verbs[] = { /* HP unmute */ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* analog mix */ @@ -4198,7 +4200,7 @@ static struct hda_verb ad1984a_thinkpad_verbs[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { +static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), @@ -4219,7 +4221,7 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { { } /* end */ }; -static struct hda_input_mux ad1984a_thinkpad_capture_source = { +static const struct hda_input_mux ad1984a_thinkpad_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -4262,7 +4264,7 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec) * 0x15 - mic-in */ -static struct hda_verb ad1984a_precision_verbs[] = { +static const struct hda_verb ad1984a_precision_verbs[] = { /* Unmute main output path */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ @@ -4288,7 +4290,7 @@ static struct hda_verb ad1984a_precision_verbs[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1984a_precision_mixers[] = { +static const struct snd_kcontrol_new ad1984a_precision_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), @@ -4344,7 +4346,7 @@ static int ad1984a_precision_init(struct hda_codec *codec) * digital-mic (0x17) - Internal mic */ -static struct hda_verb ad1984a_touchsmart_verbs[] = { +static const struct hda_verb ad1984a_touchsmart_verbs[] = { /* DACs; unmute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ @@ -4396,7 +4398,7 @@ static struct hda_verb ad1984a_touchsmart_verbs[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { +static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ { @@ -4475,7 +4477,7 @@ static const char * const ad1884a_models[AD1884A_MODELS] = { [AD1984A_PRECISION] = "precision", }; -static struct snd_pci_quirk ad1884a_cfg_tbl[] = { +static const struct snd_pci_quirk ad1884a_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), @@ -4614,22 +4616,22 @@ static int patch_ad1884a(struct hda_codec *codec) * port-G - rear clfe-out (6stack) */ -static hda_nid_t ad1882_dac_nids[3] = { +static const hda_nid_t ad1882_dac_nids[3] = { 0x04, 0x03, 0x05 }; -static hda_nid_t ad1882_adc_nids[2] = { +static const hda_nid_t ad1882_adc_nids[2] = { 0x08, 0x09, }; -static hda_nid_t ad1882_capsrc_nids[2] = { +static const hda_nid_t ad1882_capsrc_nids[2] = { 0x0c, 0x0d, }; #define AD1882_SPDIF_OUT 0x02 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */ -static struct hda_input_mux ad1882_capture_source = { +static const struct hda_input_mux ad1882_capture_source = { .num_items = 5, .items = { { "Front Mic", 0x1 }, @@ -4641,7 +4643,7 @@ static struct hda_input_mux ad1882_capture_source = { }; /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */ -static struct hda_input_mux ad1882a_capture_source = { +static const struct hda_input_mux ad1882a_capture_source = { .num_items = 5, .items = { { "Front Mic", 0x1 }, @@ -4652,7 +4654,7 @@ static struct hda_input_mux ad1882a_capture_source = { }, }; -static struct snd_kcontrol_new ad1882_base_mixers[] = { +static const struct snd_kcontrol_new ad1882_base_mixers[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), @@ -4694,7 +4696,7 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1882_loopback_mixers[] = { +static const struct snd_kcontrol_new ad1882_loopback_mixers[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), @@ -4706,7 +4708,7 @@ static struct snd_kcontrol_new ad1882_loopback_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1882a_loopback_mixers[] = { +static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), @@ -4719,7 +4721,7 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1882_3stack_mixers[] = { +static const struct snd_kcontrol_new ad1882_3stack_mixers[] = { HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT), @@ -4733,14 +4735,14 @@ static struct snd_kcontrol_new ad1882_3stack_mixers[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1882_6stack_mixers[] = { +static const struct snd_kcontrol_new ad1882_6stack_mixers[] = { HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT), { } /* end */ }; -static struct hda_verb ad1882_ch2_init[] = { +static const struct hda_verb ad1882_ch2_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -4750,7 +4752,7 @@ static struct hda_verb ad1882_ch2_init[] = { { } /* end */ }; -static struct hda_verb ad1882_ch4_init[] = { +static const struct hda_verb ad1882_ch4_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -4760,7 +4762,7 @@ static struct hda_verb ad1882_ch4_init[] = { { } /* end */ }; -static struct hda_verb ad1882_ch6_init[] = { +static const struct hda_verb ad1882_ch6_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -4770,7 +4772,7 @@ static struct hda_verb ad1882_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode ad1882_modes[3] = { +static const struct hda_channel_mode ad1882_modes[3] = { { 2, ad1882_ch2_init }, { 4, ad1882_ch4_init }, { 6, ad1882_ch6_init }, @@ -4779,7 +4781,7 @@ static struct hda_channel_mode ad1882_modes[3] = { /* * initialization verbs */ -static struct hda_verb ad1882_init_verbs[] = { +static const struct hda_verb ad1882_init_verbs[] = { /* DACs; mute as default */ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -4848,7 +4850,7 @@ static struct hda_verb ad1882_init_verbs[] = { }; #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list ad1882_loopbacks[] = { +static const struct hda_amp_list ad1882_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ { 0x20, HDA_INPUT, 1 }, /* Mic */ { 0x20, HDA_INPUT, 4 }, /* Line */ @@ -4945,7 +4947,7 @@ static int patch_ad1882(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_analog[] = { +static const struct hda_codec_preset snd_hda_preset_analog[] = { { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index 46c8bf48c31f..61b92634b161 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -134,7 +134,7 @@ static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, /* */ -static char *dirstr[2] = { "Playback", "Capture" }; +static const char * const dirstr[2] = { "Playback", "Capture" }; static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, int chan, int dir) @@ -171,7 +171,7 @@ static int ca0110_build_controls(struct hda_codec *codec) { struct ca0110_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - static char *prefix[AUTO_CFG_MAX_OUTS] = { + static const char * const prefix[AUTO_CFG_MAX_OUTS] = { "Front", "Surround", NULL, "Side", "Multi" }; hda_nid_t mutenid; @@ -259,7 +259,7 @@ static int ca0110_build_controls(struct hda_codec *codec) /* */ -static struct hda_pcm_stream ca0110_pcm_analog_playback = { +static const struct hda_pcm_stream ca0110_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -270,7 +270,7 @@ static struct hda_pcm_stream ca0110_pcm_analog_playback = { }, }; -static struct hda_pcm_stream ca0110_pcm_analog_capture = { +static const struct hda_pcm_stream ca0110_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -280,7 +280,7 @@ static struct hda_pcm_stream ca0110_pcm_analog_capture = { }, }; -static struct hda_pcm_stream ca0110_pcm_digital_playback = { +static const struct hda_pcm_stream ca0110_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -291,7 +291,7 @@ static struct hda_pcm_stream ca0110_pcm_digital_playback = { }, }; -static struct hda_pcm_stream ca0110_pcm_digital_capture = { +static const struct hda_pcm_stream ca0110_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -389,7 +389,7 @@ static void ca0110_free(struct hda_codec *codec) kfree(codec->spec); } -static struct hda_codec_ops ca0110_patch_ops = { +static const struct hda_codec_ops ca0110_patch_ops = { .build_controls = ca0110_build_controls, .build_pcms = ca0110_build_pcms, .init = ca0110_init, @@ -539,7 +539,7 @@ static int patch_ca0110(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_ca0110[] = { +static const struct hda_codec_preset snd_hda_preset_ca0110[] = { { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 }, { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 }, { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 }, diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 067982f4f182..26a1521045bb 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -51,7 +51,7 @@ struct cs_spec { unsigned int cur_adc_format; hda_nid_t dig_in; - struct hda_bind_ctls *capture_bind[2]; + const struct hda_bind_ctls *capture_bind[2]; unsigned int gpio_mask; unsigned int gpio_dir; @@ -231,7 +231,7 @@ static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, /* */ -static struct hda_pcm_stream cs_pcm_analog_playback = { +static const struct hda_pcm_stream cs_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -242,7 +242,7 @@ static struct hda_pcm_stream cs_pcm_analog_playback = { }, }; -static struct hda_pcm_stream cs_pcm_analog_capture = { +static const struct hda_pcm_stream cs_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -252,7 +252,7 @@ static struct hda_pcm_stream cs_pcm_analog_capture = { }, }; -static struct hda_pcm_stream cs_pcm_digital_playback = { +static const struct hda_pcm_stream cs_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -264,7 +264,7 @@ static struct hda_pcm_stream cs_pcm_digital_playback = { }, }; -static struct hda_pcm_stream cs_pcm_digital_capture = { +static const struct hda_pcm_stream cs_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -331,8 +331,8 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx) struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t pin = cfg->inputs[idx].pin; - unsigned int val = snd_hda_query_pin_caps(codec, pin); - if (!(val & AC_PINCAP_PRES_DETECT)) + unsigned int val; + if (!is_jack_detectable(codec, pin)) return 0; val = snd_hda_codec_get_pincfg(codec, pin); return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT); @@ -349,8 +349,7 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, hda_nid_t pins[2]; unsigned int type; int j, nums; - type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) - >> AC_WCAP_TYPE_SHIFT; + type = get_wcaps_type(get_wcaps(codec, nid)); if (type != AC_WID_AUD_IN) continue; nums = snd_hda_get_connections(codec, nid, pins, @@ -559,10 +558,10 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, const char *name; int err, index; struct snd_kcontrol *kctl; - static char *speakers[] = { + static const char * const speakers[] = { "Front Speaker", "Surround Speaker", "Bass Speaker" }; - static char *line_outs[] = { + static const char * const line_outs[] = { "Front Line-Out", "Surround Line-Out", "Bass Line-Out" }; @@ -642,7 +641,7 @@ static int build_output(struct hda_codec *codec) /* */ -static struct snd_kcontrol_new cs_capture_ctls[] = { +static const struct snd_kcontrol_new cs_capture_ctls[] = { HDA_BIND_SW("Capture Switch", 0), HDA_BIND_VOL("Capture Volume", 0), }; @@ -710,7 +709,7 @@ static int cs_capture_source_put(struct snd_kcontrol *kcontrol, return change_cur_input(codec, idx, 0); } -static struct snd_kcontrol_new cs_capture_source = { +static const struct snd_kcontrol_new cs_capture_source = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -719,7 +718,7 @@ static struct snd_kcontrol_new cs_capture_source = { .put = cs_capture_source_put, }; -static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, +static const struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, struct hda_ctl_ops *ops) { struct cs_spec *spec = codec->spec; @@ -847,15 +846,14 @@ static void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int caps, hp_present; + unsigned int hp_present; hda_nid_t nid; int i; hp_present = 0; for (i = 0; i < cfg->hp_outs; i++) { nid = cfg->hp_pins[i]; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_PRES_DETECT)) + if (!is_jack_detectable(codec, nid)) continue; hp_present = snd_hda_jack_detect(codec, nid); if (hp_present) @@ -924,7 +922,7 @@ static void init_output(struct hda_codec *codec) AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); if (!cfg->speaker_outs) continue; - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { + if (is_jack_detectable(codec, nid)) { snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | HP_EVENT); @@ -983,7 +981,7 @@ static void init_input(struct hda_codec *codec) cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); } -static struct hda_verb cs_coef_init_verbs[] = { +static const struct hda_verb cs_coef_init_verbs[] = { {0x11, AC_VERB_SET_PROC_STATE, 1}, {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, {0x11, AC_VERB_SET_PROC_COEF, @@ -1017,7 +1015,7 @@ static struct hda_verb cs_coef_init_verbs[] = { * blocks, which will alleviate the issue. */ -static struct hda_verb cs_errata_init_verbs[] = { +static const struct hda_verb cs_errata_init_verbs[] = { {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */ {0x11, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ @@ -1126,7 +1124,7 @@ static void cs_unsol_event(struct hda_codec *codec, unsigned int res) } } -static struct hda_codec_ops cs_patch_ops = { +static const struct hda_codec_ops cs_patch_ops = { .build_controls = cs_build_controls, .build_pcms = cs_build_pcms, .init = cs_init, @@ -1166,7 +1164,7 @@ static const char * const cs420x_models[CS420X_MODELS] = { }; -static struct snd_pci_quirk cs420x_cfg_tbl[] = { +static const struct snd_pci_quirk cs420x_cfg_tbl[] = { SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53), SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), @@ -1180,7 +1178,7 @@ struct cs_pincfg { u32 val; }; -static struct cs_pincfg mbp53_pincfgs[] = { +static const struct cs_pincfg mbp53_pincfgs[] = { { 0x09, 0x012b4050 }, { 0x0a, 0x90100141 }, { 0x0b, 0x90100140 }, @@ -1194,7 +1192,7 @@ static struct cs_pincfg mbp53_pincfgs[] = { {} /* terminator */ }; -static struct cs_pincfg mbp55_pincfgs[] = { +static const struct cs_pincfg mbp55_pincfgs[] = { { 0x09, 0x012b4030 }, { 0x0a, 0x90100121 }, { 0x0b, 0x90100120 }, @@ -1208,7 +1206,7 @@ static struct cs_pincfg mbp55_pincfgs[] = { {} /* terminator */ }; -static struct cs_pincfg imac27_pincfgs[] = { +static const struct cs_pincfg imac27_pincfgs[] = { { 0x09, 0x012b4050 }, { 0x0a, 0x90100140 }, { 0x0b, 0x90100142 }, @@ -1222,7 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = { {} /* terminator */ }; -static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { +static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { [CS420X_MBP53] = mbp53_pincfgs, [CS420X_MBP55] = mbp55_pincfgs, [CS420X_IMAC27] = imac27_pincfgs, @@ -1283,7 +1281,7 @@ static int patch_cs420x(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_cirrus[] = { +static const struct hda_codec_preset snd_hda_preset_cirrus[] = { { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, {} /* terminator */ diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 1f8bbcd0f802..ab3308daa960 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -53,7 +53,7 @@ struct cmi_spec { int num_dacs; /* capture */ - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; hda_nid_t dig_in_nid; /* capture source */ @@ -110,7 +110,7 @@ static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v */ /* 3-stack / 2 channel */ -static struct hda_verb cmi9880_ch2_init[] = { +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 */ @@ -121,7 +121,7 @@ static struct hda_verb cmi9880_ch2_init[] = { }; /* 3-stack / 6 channel */ -static struct hda_verb cmi9880_ch6_init[] = { +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 */ @@ -132,7 +132,7 @@ static struct hda_verb cmi9880_ch6_init[] = { }; /* 3-stack+front / 8 channel */ -static struct hda_verb cmi9880_ch8_init[] = { +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 */ @@ -142,7 +142,7 @@ static struct hda_verb cmi9880_ch8_init[] = { {} }; -static struct hda_channel_mode cmi9880_channel_modes[3] = { +static const struct hda_channel_mode cmi9880_channel_modes[3] = { { 2, cmi9880_ch2_init }, { 6, cmi9880_ch6_init }, { 8, cmi9880_ch8_init }, @@ -174,7 +174,7 @@ static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va /* */ -static struct snd_kcontrol_new cmi9880_basic_mixer[] = { +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), @@ -205,7 +205,7 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = { /* * shared I/O pins */ -static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { +static const struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -219,7 +219,7 @@ static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = { /* AUD-in selections: * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20 */ -static struct hda_input_mux cmi9880_basic_mux = { +static const struct hda_input_mux cmi9880_basic_mux = { .num_items = 4, .items = { { "Front Mic", 0x5 }, @@ -229,7 +229,7 @@ static struct hda_input_mux cmi9880_basic_mux = { } }; -static struct hda_input_mux cmi9880_no_line_mux = { +static const struct hda_input_mux cmi9880_no_line_mux = { .num_items = 3, .items = { { "Front Mic", 0x5 }, @@ -239,11 +239,11 @@ static struct hda_input_mux cmi9880_no_line_mux = { }; /* front, rear, clfe, rear_surr */ -static hda_nid_t cmi9880_dac_nids[4] = { +static const hda_nid_t cmi9880_dac_nids[4] = { 0x03, 0x04, 0x05, 0x06 }; /* ADC0, ADC1 */ -static hda_nid_t cmi9880_adc_nids[2] = { +static const hda_nid_t cmi9880_adc_nids[2] = { 0x08, 0x09 }; @@ -252,7 +252,7 @@ static hda_nid_t cmi9880_adc_nids[2] = { /* */ -static struct hda_verb cmi9880_basic_init[] = { +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) */ @@ -281,7 +281,7 @@ static struct hda_verb cmi9880_basic_init[] = { {} /* terminator */ }; -static struct hda_verb cmi9880_allout_init[] = { +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) */ @@ -528,7 +528,7 @@ static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, /* */ -static struct hda_pcm_stream cmi9880_pcm_analog_playback = { +static const struct hda_pcm_stream cmi9880_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -540,7 +540,7 @@ static struct hda_pcm_stream cmi9880_pcm_analog_playback = { }, }; -static struct hda_pcm_stream cmi9880_pcm_analog_capture = { +static const struct hda_pcm_stream cmi9880_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -551,7 +551,7 @@ static struct hda_pcm_stream cmi9880_pcm_analog_capture = { }, }; -static struct hda_pcm_stream cmi9880_pcm_digital_playback = { +static const struct hda_pcm_stream cmi9880_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -563,7 +563,7 @@ static struct hda_pcm_stream cmi9880_pcm_digital_playback = { }, }; -static struct hda_pcm_stream cmi9880_pcm_digital_capture = { +static const struct hda_pcm_stream cmi9880_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -617,14 +617,14 @@ static const char * const cmi9880_models[CMI_MODELS] = { [CMI_AUTO] = "auto", }; -static struct snd_pci_quirk cmi9880_cfg_tbl[] = { +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 struct hda_codec_ops cmi9880_patch_ops = { +static const struct hda_codec_ops cmi9880_patch_ops = { .build_controls = cmi9880_build_controls, .build_pcms = cmi9880_build_pcms, .init = cmi9880_init, @@ -745,7 +745,7 @@ static int patch_cmi9880(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_cmedia[] = { +static const struct hda_codec_preset snd_hda_preset_cmedia[] = { { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 }, { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 }, {} /* terminator */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index d08cf31596f3..3e6b9a8539c2 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -39,6 +39,7 @@ #define CONEXANT_HP_EVENT 0x37 #define CONEXANT_MIC_EVENT 0x38 +#define CONEXANT_LINE_EVENT 0x39 /* Conexant 5051 specific */ @@ -55,9 +56,16 @@ struct pin_dac_pair { int type; }; +struct imux_info { + hda_nid_t pin; /* input pin NID */ + hda_nid_t adc; /* connected ADC NID */ + hda_nid_t boost; /* optional boost volume NID */ + int index; /* corresponding to autocfg.input */ +}; + struct conexant_spec { - struct snd_kcontrol_new *mixers[5]; + const struct snd_kcontrol_new *mixers[5]; int num_mixers; hda_nid_t vmaster_nid; @@ -74,14 +82,17 @@ struct conexant_spec { */ unsigned int cur_eapd; unsigned int hp_present; + unsigned int line_present; unsigned int auto_mic; - int auto_mic_ext; /* autocfg.inputs[] index for ext mic */ + int auto_mic_ext; /* imux_pins[] index for ext mic */ + int auto_mic_dock; /* imux_pins[] index for dock mic */ + int auto_mic_int; /* imux_pins[] index for int mic */ unsigned int need_dac_fix; hda_nid_t slave_dig_outs[2]; /* capture */ unsigned int num_adc_nids; - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ unsigned int cur_adc_idx; @@ -89,9 +100,11 @@ struct conexant_spec { 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; - hda_nid_t *capsrc_nids; + const hda_nid_t *capsrc_nids; unsigned int cur_mux[3]; /* channel model */ @@ -106,12 +119,17 @@ struct conexant_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct hda_input_mux private_imux; + struct imux_info imux_info[HDA_MAX_NUM_INPUTS]; + hda_nid_t private_adc_nids[HDA_MAX_NUM_INPUTS]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; struct pin_dac_pair dac_info[8]; int dac_info_filled; unsigned int port_d_mode; unsigned int auto_mute:1; /* used in auto-parser */ + unsigned int detect_line:1; /* Line-out detection enabled */ + unsigned int automute_lines:1; /* automute line-out as well */ + unsigned int automute_hp_lo:1; /* both HP and LO available */ unsigned int dell_automute:1; unsigned int dell_vostro:1; unsigned int ideapad:1; @@ -119,6 +137,8 @@ struct conexant_spec { unsigned int hp_laptop:1; unsigned int asus:1; + unsigned int adc_switching:1; + unsigned int ext_mic_present; unsigned int recording; void (*capture_prepare)(struct hda_codec *codec); @@ -227,7 +247,7 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, -static struct hda_pcm_stream conexant_pcm_analog_playback = { +static const struct hda_pcm_stream conexant_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -239,7 +259,7 @@ static struct hda_pcm_stream conexant_pcm_analog_playback = { }, }; -static struct hda_pcm_stream conexant_pcm_analog_capture = { +static const struct hda_pcm_stream conexant_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -251,7 +271,7 @@ static struct hda_pcm_stream conexant_pcm_analog_capture = { }; -static struct hda_pcm_stream conexant_pcm_digital_playback = { +static const struct hda_pcm_stream conexant_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -263,7 +283,7 @@ static struct hda_pcm_stream conexant_pcm_digital_playback = { }, }; -static struct hda_pcm_stream conexant_pcm_digital_capture = { +static const struct hda_pcm_stream conexant_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -294,7 +314,7 @@ static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream cx5051_pcm_analog_capture = { +static const struct hda_pcm_stream cx5051_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -319,13 +339,19 @@ static int conexant_build_pcms(struct hda_codec *codec) spec->multiout.max_channels; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - 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; + 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) { @@ -433,7 +459,7 @@ static void conexant_free(struct hda_codec *codec) kfree(codec->spec); } -static struct snd_kcontrol_new cxt_capture_mixers[] = { +static const struct snd_kcontrol_new cxt_capture_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", @@ -446,7 +472,7 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = { #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ -static struct snd_kcontrol_new cxt_beep_mixer[] = { +static const struct snd_kcontrol_new cxt_beep_mixer[] = { HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), { } /* end */ @@ -456,12 +482,18 @@ static struct snd_kcontrol_new cxt_beep_mixer[] = { static const char * const slave_vols[] = { "Headphone Playback Volume", "Speaker Playback Volume", + "Front Playback Volume", + "Surround Playback Volume", + "CLFE Playback Volume", NULL }; static const char * const slave_sws[] = { "Headphone Playback Switch", "Speaker Playback Switch", + "Front Playback Switch", + "Surround Playback Switch", + "CLFE Playback Switch", NULL }; @@ -521,7 +553,7 @@ static int conexant_build_controls(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_INPUT_BEEP /* create beep controls if needed */ if (spec->beep_amp) { - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; for (knew = cxt_beep_mixer; knew->name; knew++) { struct snd_kcontrol *kctl; kctl = snd_ctl_new1(knew, codec); @@ -546,7 +578,7 @@ static int conexant_suspend(struct hda_codec *codec, pm_message_t state) } #endif -static struct hda_codec_ops conexant_patch_ops = { +static const struct hda_codec_ops conexant_patch_ops = { .build_controls = conexant_build_controls, .build_pcms = conexant_build_pcms, .init = conexant_init, @@ -564,6 +596,7 @@ static struct hda_codec_ops conexant_patch_ops = { #define set_beep_amp(spec, nid, idx, dir) /* NOP */ #endif +static int patch_conexant_auto(struct hda_codec *codec); /* * EAPD control * the private value = nid | (invert << 8) @@ -662,16 +695,16 @@ static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, /* Conexant 5045 specific */ -static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; -static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; -static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; +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 struct hda_channel_mode cxt5045_modes[1] = { +static const struct hda_channel_mode cxt5045_modes[1] = { { 2, NULL }, }; -static struct hda_input_mux cxt5045_capture_source = { +static const struct hda_input_mux cxt5045_capture_source = { .num_items = 2, .items = { { "IntMic", 0x1 }, @@ -679,7 +712,7 @@ static struct hda_input_mux cxt5045_capture_source = { } }; -static struct hda_input_mux cxt5045_capture_source_benq = { +static const struct hda_input_mux cxt5045_capture_source_benq = { .num_items = 5, .items = { { "IntMic", 0x1 }, @@ -690,7 +723,7 @@ static struct hda_input_mux cxt5045_capture_source_benq = { } }; -static struct hda_input_mux cxt5045_capture_source_hp530 = { +static const struct hda_input_mux cxt5045_capture_source_hp530 = { .num_items = 2, .items = { { "ExtMic", 0x1 }, @@ -723,7 +756,7 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, } /* bind volumes of both NID 0x10 and 0x11 */ -static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { +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), @@ -735,12 +768,12 @@ static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { /* toggle input of built-in and mic jack appropriately */ static void cxt5045_hp_automic(struct hda_codec *codec) { - static struct hda_verb mic_jack_on[] = { + 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 struct hda_verb mic_jack_off[] = { + static const struct hda_verb mic_jack_off[] = { {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, {} @@ -784,7 +817,7 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec, } } -static struct snd_kcontrol_new cxt5045_mixers[] = { +static const struct snd_kcontrol_new cxt5045_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), @@ -808,7 +841,7 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5045_benq_mixers[] = { +static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), @@ -825,7 +858,7 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { +static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = { HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), @@ -849,7 +882,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { {} }; -static struct hda_verb cxt5045_init_verbs[] = { +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 }, @@ -875,7 +908,7 @@ static struct hda_verb cxt5045_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5045_benq_init_verbs[] = { +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 }, @@ -901,13 +934,13 @@ static struct hda_verb cxt5045_benq_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5045_hp_sense_init_verbs[] = { +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 struct hda_verb cxt5045_mic_sense_init_verbs[] = { +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 */ @@ -917,7 +950,7 @@ static struct hda_verb cxt5045_mic_sense_init_verbs[] = { /* Test configuration for debugging, modelled after the ALC260 test * configuration. */ -static struct hda_input_mux cxt5045_test_capture_source = { +static const struct hda_input_mux cxt5045_test_capture_source = { .num_items = 5, .items = { { "MIXER", 0x0 }, @@ -928,7 +961,7 @@ static struct hda_input_mux cxt5045_test_capture_source = { }, }; -static struct snd_kcontrol_new cxt5045_test_mixer[] = { +static const struct snd_kcontrol_new cxt5045_test_mixer[] = { /* Output controls */ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), @@ -978,7 +1011,7 @@ static struct snd_kcontrol_new cxt5045_test_mixer[] = { { } /* end */ }; -static struct hda_verb cxt5045_test_init_verbs[] = { +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 }, @@ -1047,6 +1080,7 @@ enum { #ifdef CONFIG_SND_DEBUG CXT5045_TEST, #endif + CXT5045_AUTO, CXT5045_MODELS }; @@ -1059,9 +1093,10 @@ static const char * const cxt5045_models[CXT5045_MODELS] = { #ifdef CONFIG_SND_DEBUG [CXT5045_TEST] = "test", #endif + [CXT5045_AUTO] = "auto", }; -static struct snd_pci_quirk cxt5045_cfg_tbl[] = { +static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", CXT5045_LAPTOP_HPSENSE), @@ -1085,6 +1120,16 @@ 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 0 /* use the old method just for safety */ + if (board_config < 0) + board_config = CXT5045_AUTO; +#endif + if (board_config == CXT5045_AUTO) + return patch_conexant_auto(codec); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; @@ -1111,9 +1156,6 @@ static int patch_cxt5045(struct hda_codec *codec) codec->patch_ops = conexant_patch_ops; - board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, - cxt5045_models, - cxt5045_cfg_tbl); switch (board_config) { case CXT5045_LAPTOP_HPSENSE: codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; @@ -1196,15 +1238,15 @@ static int patch_cxt5045(struct hda_codec *codec) /* Conexant 5047 specific */ #define CXT5047_SPDIF_OUT 0x11 -static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ -static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; -static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; +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 struct hda_channel_mode cxt5047_modes[1] = { +static const struct hda_channel_mode cxt5047_modes[1] = { { 2, NULL }, }; -static struct hda_input_mux cxt5047_toshiba_capture_source = { +static const struct hda_input_mux cxt5047_toshiba_capture_source = { .num_items = 2, .items = { { "ExtMic", 0x2 }, @@ -1256,12 +1298,12 @@ static void cxt5047_hp_automute(struct hda_codec *codec) /* toggle input of built-in and mic jack appropriately */ static void cxt5047_hp_automic(struct hda_codec *codec) { - static struct hda_verb mic_jack_on[] = { + 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 struct hda_verb mic_jack_off[] = { + 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}, {} @@ -1289,7 +1331,7 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec, } } -static struct snd_kcontrol_new cxt5047_base_mixers[] = { +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), @@ -1309,19 +1351,19 @@ static struct snd_kcontrol_new cxt5047_base_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { +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 struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { +static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), { } /* end */ }; -static struct hda_verb cxt5047_init_verbs[] = { +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 }, @@ -1348,7 +1390,7 @@ static struct hda_verb cxt5047_init_verbs[] = { }; /* configuration for Toshiba Laptops */ -static struct hda_verb cxt5047_toshiba_init_verbs[] = { +static const struct hda_verb cxt5047_toshiba_init_verbs[] = { {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ {} }; @@ -1357,7 +1399,7 @@ static struct hda_verb cxt5047_toshiba_init_verbs[] = { * configuration. */ #ifdef CONFIG_SND_DEBUG -static struct hda_input_mux cxt5047_test_capture_source = { +static const struct hda_input_mux cxt5047_test_capture_source = { .num_items = 4, .items = { { "LINE1 pin", 0x0 }, @@ -1367,7 +1409,7 @@ static struct hda_input_mux cxt5047_test_capture_source = { }, }; -static struct snd_kcontrol_new cxt5047_test_mixer[] = { +static const struct snd_kcontrol_new cxt5047_test_mixer[] = { /* Output only controls */ HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), @@ -1420,7 +1462,7 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { { } /* end */ }; -static struct hda_verb cxt5047_test_init_verbs[] = { +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}, @@ -1492,6 +1534,7 @@ enum { #ifdef CONFIG_SND_DEBUG CXT5047_TEST, #endif + CXT5047_AUTO, CXT5047_MODELS }; @@ -1502,9 +1545,10 @@ static const char * const cxt5047_models[CXT5047_MODELS] = { #ifdef CONFIG_SND_DEBUG [CXT5047_TEST] = "test", #endif + [CXT5047_AUTO] = "auto", }; -static struct snd_pci_quirk cxt5047_cfg_tbl[] = { +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), @@ -1517,6 +1561,16 @@ 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 0 /* not enabled as default, as BIOS often broken for this codec */ + if (board_config < 0) + board_config = CXT5047_AUTO; +#endif + if (board_config == CXT5047_AUTO) + return patch_conexant_auto(codec); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; @@ -1540,9 +1594,6 @@ static int patch_cxt5047(struct hda_codec *codec) codec->patch_ops = conexant_patch_ops; - board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, - cxt5047_models, - cxt5047_cfg_tbl); switch (board_config) { case CXT5047_LAPTOP: spec->num_mixers = 2; @@ -1591,10 +1642,10 @@ static int patch_cxt5047(struct hda_codec *codec) } /* Conexant 5051 specific */ -static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; -static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; +static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; +static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; -static struct hda_channel_mode cxt5051_modes[1] = { +static const struct hda_channel_mode cxt5051_modes[1] = { { 2, NULL }, }; @@ -1696,7 +1747,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, snd_hda_input_jack_report(codec, nid); } -static struct snd_kcontrol_new cxt5051_playback_mixers[] = { +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, @@ -1709,7 +1760,7 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5051_capture_mixers[] = { +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), @@ -1719,7 +1770,7 @@ static struct snd_kcontrol_new cxt5051_capture_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5051_hp_mixers[] = { +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), @@ -1727,19 +1778,19 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { +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 struct snd_kcontrol_new cxt5051_f700_mixers[] = { +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 struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { +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), @@ -1747,7 +1798,7 @@ static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { {} }; -static struct hda_verb cxt5051_init_verbs[] = { +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}, @@ -1776,7 +1827,7 @@ static struct hda_verb cxt5051_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { +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}, @@ -1801,7 +1852,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { +static const struct hda_verb cxt5051_lenovo_x200_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}, @@ -1834,7 +1885,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5051_f700_init_verbs[] = { +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}, @@ -1869,7 +1920,7 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, snd_hda_input_jack_report(codec, nid); } -static struct hda_verb cxt5051_ideapad_init_verbs[] = { +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}, @@ -1906,6 +1957,7 @@ enum { CXT5051_F700, /* HP Compaq Presario F700 */ CXT5051_TOSHIBA, /* Toshiba M300 & co */ CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ + CXT5051_AUTO, /* auto-parser */ CXT5051_MODELS }; @@ -1917,9 +1969,10 @@ static const char *const cxt5051_models[CXT5051_MODELS] = { [CXT5051_F700] = "hp-700", [CXT5051_TOSHIBA] = "toshiba", [CXT5051_IDEAPAD] = "ideapad", + [CXT5051_AUTO] = "auto", }; -static struct snd_pci_quirk cxt5051_cfg_tbl[] = { +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), @@ -1937,6 +1990,16 @@ 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 0 /* use the old method just for safety */ + if (board_config < 0) + board_config = CXT5051_AUTO; +#endif + if (board_config == CXT5051_AUTO) + return patch_conexant_auto(codec); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; @@ -1967,9 +2030,6 @@ static int patch_cxt5051(struct hda_codec *codec) codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; - board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, - cxt5051_models, - cxt5051_cfg_tbl); spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; switch (board_config) { case CXT5051_HP: @@ -2011,17 +2071,17 @@ static int patch_cxt5051(struct hda_codec *codec) /* Conexant 5066 specific */ -static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; -static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; -static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; -static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; +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 }; /* OLPC's microphone port is DC coupled for use with external sensors, * therefore we use a 50% mic bias in order to center the input signal with * the DC input range of the codec. */ #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 -static struct hda_channel_mode cxt5066_modes[1] = { +static const struct hda_channel_mode cxt5066_modes[1] = { { 2, NULL }, }; @@ -2176,7 +2236,7 @@ static void cxt5066_vostro_automic(struct hda_codec *codec) {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {} }; - static struct hda_verb ext_mic_absent[] = { + static const struct hda_verb ext_mic_absent[] = { /* enable internal mic, port C */ {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -2209,7 +2269,7 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {} }; - static struct hda_verb ext_mic_absent[] = { + 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}, @@ -2257,7 +2317,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) { unsigned int ext_present, dock_present; - static struct hda_verb ext_mic_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}, @@ -2265,7 +2325,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {} }; - static struct hda_verb dock_mic_present[] = { + 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}, @@ -2273,7 +2333,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, {} }; - static struct hda_verb ext_mic_absent[] = { + 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}, @@ -2537,7 +2597,7 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) } static void conexant_check_dig_outs(struct hda_codec *codec, - hda_nid_t *dig_pins, + const hda_nid_t *dig_pins, int num_pins) { struct conexant_spec *spec = codec->spec; @@ -2557,7 +2617,7 @@ static void conexant_check_dig_outs(struct hda_codec *codec, } } -static struct hda_input_mux cxt5066_capture_source = { +static const struct hda_input_mux cxt5066_capture_source = { .num_items = 4, .items = { { "Mic B", 0 }, @@ -2567,7 +2627,7 @@ static struct hda_input_mux cxt5066_capture_source = { }, }; -static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { +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), @@ -2576,7 +2636,7 @@ static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { }, }; -static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { +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), @@ -2585,12 +2645,12 @@ static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { }, }; -static struct snd_kcontrol_new cxt5066_mixer_master[] = { +static const struct snd_kcontrol_new cxt5066_mixer_master[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), {} }; -static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { +static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", @@ -2609,7 +2669,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { {} }; -static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { +static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DC Mode Enable Switch", @@ -2627,7 +2687,7 @@ static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { {} }; -static struct snd_kcontrol_new cxt5066_mixers[] = { +static const struct snd_kcontrol_new cxt5066_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -2650,7 +2710,7 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { {} }; -static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { +static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Internal Mic Boost Capture Enum", @@ -2662,7 +2722,7 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { {} }; -static struct hda_verb cxt5066_init_verbs[] = { +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 */ @@ -2717,7 +2777,7 @@ static struct hda_verb cxt5066_init_verbs[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_olpc[] = { +static const struct hda_verb cxt5066_init_verbs_olpc[] = { /* Port A: headphones */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ @@ -2778,7 +2838,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_vostro[] = { +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 */ @@ -2839,7 +2899,7 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_ideapad[] = { +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 */ @@ -2889,7 +2949,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_thinkpad[] = { +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 */ @@ -2947,13 +3007,13 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = { { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_portd_lo[] = { +static const struct hda_verb cxt5066_init_verbs_portd_lo[] = { {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, { } /* end */ }; -static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { +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}, @@ -2997,6 +3057,7 @@ enum { 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 }; @@ -3009,9 +3070,10 @@ static const char * const cxt5066_models[CXT5066_MODELS] = { [CXT5066_THINKPAD] = "thinkpad", [CXT5066_ASUS] = "asus", [CXT5066_HP_LAPTOP] = "hp-laptop", + [CXT5066_AUTO] = "auto", }; -static struct snd_pci_quirk cxt5066_cfg_tbl[] = { +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), @@ -3034,7 +3096,11 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), + SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO), SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */ {} }; @@ -3044,6 +3110,15 @@ 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 0 /* use the old method just for safety */ + if (board_config < 0) + board_config = CXT5066_AUTO; +#endif + if (board_config == CXT5066_AUTO) + return patch_conexant_auto(codec); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; @@ -3074,8 +3149,6 @@ static int patch_cxt5066(struct hda_codec *codec) set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); - board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, - cxt5066_models, cxt5066_cfg_tbl); switch (board_config) { default: case CXT5066_LAPTOP: @@ -3193,7 +3266,45 @@ static int patch_cxt5066(struct hda_codec *codec) * Automatic parser for CX20641 & co */ -static hda_nid_t cx_auto_adc_nids[] = { 0x14 }; +static int cx_auto_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; + hda_nid_t adc = spec->imux_info[spec->cur_mux[0]].adc; + if (spec->adc_switching) { + spec->cur_adc = adc; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + } + snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format); + return 0; +} + +static int cx_auto_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 cx_auto_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = cx_auto_capture_pcm_prepare, + .cleanup = cx_auto_capture_pcm_cleanup + }, +}; + +static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; /* get the connection index of @nid in the widget @mux */ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, @@ -3318,61 +3429,349 @@ static void cx_auto_parse_output(struct hda_codec *codec) spec->multiout.dac_nids = spec->private_dac_nids; spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (cfg->hp_outs > 0) - spec->auto_mute = 1; + for (i = 0; i < cfg->hp_outs; i++) { + if (is_jack_detectable(codec, cfg->hp_pins[i])) { + spec->auto_mute = 1; + break; + } + } + if (spec->auto_mute && + cfg->line_out_pins[0] && + cfg->line_out_type != AUTO_PIN_SPEAKER_OUT && + cfg->line_out_pins[0] != cfg->hp_pins[0] && + cfg->line_out_pins[0] != cfg->speaker_pins[0]) { + for (i = 0; i < cfg->line_outs; i++) { + if (is_jack_detectable(codec, cfg->line_out_pins[i])) { + spec->detect_line = 1; + break; + } + } + spec->automute_lines = spec->detect_line; + } + spec->vmaster_nid = spec->private_dac_nids[0]; } +static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, bool on); + +static void do_automute(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, bool on) +{ + int i; + for (i = 0; i < num_pins; i++) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + on ? PIN_OUT : 0); + cx_auto_turn_eapd(codec, num_pins, pins, on); +} + +static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) +{ + int i, present = 0; + + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; + if (!nid || !is_jack_detectable(codec, nid)) + break; + snd_hda_input_jack_report(codec, nid); + present |= snd_hda_jack_detect(codec, nid); + } + return present; +} + /* auto-mute/unmute speaker and line outs according to headphone jack */ +static void cx_auto_update_speakers(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int on = 1; + + /* turn on HP EAPD when HP jacks are present */ + if (spec->auto_mute) + on = spec->hp_present; + cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); + /* mute speakers in auto-mode if HP or LO jacks are plugged */ + if (spec->auto_mute) + on = !(spec->hp_present || + (spec->detect_line && spec->line_present)); + do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, on); + + /* toggle line-out mutes if needed, too */ + /* if LO is a copy of either HP or Speaker, don't need to handle it */ + if (cfg->line_out_pins[0] == cfg->hp_pins[0] || + cfg->line_out_pins[0] == cfg->speaker_pins[0]) + return; + if (spec->auto_mute) { + /* mute LO in auto-mode when HP jack is present */ + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT || + spec->automute_lines) + on = !spec->hp_present; + else + on = 1; + } + do_automute(codec, cfg->line_outs, cfg->line_out_pins, on); +} + static void cx_auto_hp_automute(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i, present; if (!spec->auto_mute) return; - present = 0; - for (i = 0; i < cfg->hp_outs; i++) { - if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) { - present = 1; - break; - } + spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins); + cx_auto_update_speakers(codec); +} + +static void cx_auto_line_automute(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (!spec->auto_mute || !spec->detect_line) + return; + spec->line_present = detect_jacks(codec, cfg->line_outs, + cfg->line_out_pins); + cx_auto_update_speakers(codec); +} + +static int cx_automute_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; + static const char * const texts2[] = { + "Disabled", "Enabled" + }; + static const char * const texts3[] = { + "Disabled", "Speaker Only", "Line-Out+Speaker" + }; + const char * const *texts; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + if (spec->automute_hp_lo) { + uinfo->value.enumerated.items = 3; + texts = texts3; + } else { + uinfo->value.enumerated.items = 2; + texts = texts2; } - for (i = 0; i < cfg->line_outs; i++) { - snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - present ? 0 : PIN_OUT); + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int cx_automute_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; + unsigned int val; + if (!spec->auto_mute) + val = 0; + else if (!spec->automute_lines) + val = 1; + else + val = 2; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int cx_automute_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; + + switch (ucontrol->value.enumerated.item[0]) { + case 0: + if (!spec->auto_mute) + return 0; + spec->auto_mute = 0; + break; + case 1: + if (spec->auto_mute && !spec->automute_lines) + return 0; + spec->auto_mute = 1; + spec->automute_lines = 0; + break; + case 2: + if (!spec->automute_hp_lo) + return -EINVAL; + if (spec->auto_mute && spec->automute_lines) + return 0; + spec->auto_mute = 1; + spec->automute_lines = 1; + break; + default: + return -EINVAL; } - for (i = 0; !present && i < cfg->line_outs; i++) - if (snd_hda_jack_detect(codec, cfg->line_out_pins[i])) - present = 1; - for (i = 0; i < cfg->speaker_outs; i++) { - snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - present ? 0 : PIN_OUT); + cx_auto_update_speakers(codec); + return 1; +} + +static const struct snd_kcontrol_new cx_automute_mode_enum[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Auto-Mute Mode", + .info = cx_automute_mode_info, + .get = cx_automute_mode_get, + .put = cx_automute_mode_put, + }, + { } +}; + +static int cx_auto_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->private_imux, uinfo); +} + +static int cx_auto_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->cur_mux[0]; + return 0; +} + +/* look for the route the given pin from mux and return the index; + * if do_select is set, actually select the route. + */ +static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t pin, hda_nid_t *srcp, + bool do_select, int depth) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + switch (get_wcaps_type(get_wcaps(codec, mux))) { + case AC_WID_AUD_IN: + case AC_WID_AUD_SEL: + case AC_WID_AUD_MIX: + break; + default: + return -1; + } + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == pin) { + if (do_select) + snd_hda_codec_write(codec, mux, 0, + AC_VERB_SET_CONNECT_SEL, i); + if (srcp) + *srcp = mux; + return i; + } + depth++; + if (depth == 2) + return -1; + for (i = 0; i < nums; i++) { + int ret = __select_input_connection(codec, conn[i], pin, srcp, + do_select, depth); + if (ret >= 0) { + if (do_select) + snd_hda_codec_write(codec, mux, 0, + AC_VERB_SET_CONNECT_SEL, i); + return i; + } } + return -1; +} + +static void select_input_connection(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t pin) +{ + __select_input_connection(codec, mux, pin, NULL, true, 0); +} + +static int get_input_connection(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t pin) +{ + return __select_input_connection(codec, mux, pin, NULL, false, 0); +} + +static int cx_auto_mux_enum_update(struct hda_codec *codec, + const struct hda_input_mux *imux, + unsigned int idx) +{ + struct conexant_spec *spec = codec->spec; + hda_nid_t adc; + int changed = 1; + + if (!imux->num_items) + return 0; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (spec->cur_mux[0] == idx) + changed = 0; + adc = spec->imux_info[idx].adc; + select_input_connection(codec, spec->imux_info[idx].adc, + spec->imux_info[idx].pin); + if (spec->cur_adc && spec->cur_adc != adc) { + /* stream is running, let's swap the current ADC */ + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = adc; + snd_hda_codec_setup_stream(codec, adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + } + spec->cur_mux[0] = idx; + return changed; +} + +static int cx_auto_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; + + return cx_auto_mux_enum_update(codec, &spec->private_imux, + ucontrol->value.enumerated.item[0]); +} + +static const struct snd_kcontrol_new cx_auto_capture_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = cx_auto_mux_enum_info, + .get = cx_auto_mux_enum_get, + .put = cx_auto_mux_enum_put + }, + {} +}; + +static bool select_automic(struct hda_codec *codec, int idx, bool detect) +{ + struct conexant_spec *spec = codec->spec; + if (idx < 0) + return false; + if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin)) + return false; + cx_auto_mux_enum_update(codec, &spec->private_imux, idx); + return true; } /* automatic switch internal and external mic */ static void cx_auto_automic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct hda_input_mux *imux = &spec->private_imux; - int ext_idx = spec->auto_mic_ext; if (!spec->auto_mic) return; - if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) { - snd_hda_codec_write(codec, spec->adc_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[ext_idx].index); - } else { - snd_hda_codec_write(codec, spec->adc_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[!ext_idx].index); - } + if (!select_automic(codec, spec->auto_mic_ext, true)) + if (!select_automic(codec, spec->auto_mic_dock, true)) + select_automic(codec, spec->auto_mic_int, false); } static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) @@ -3381,7 +3780,9 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) switch (res >> 26) { case CONEXANT_HP_EVENT: cx_auto_hp_automute(codec); - snd_hda_input_jack_report(codec, nid); + break; + case CONEXANT_LINE_EVENT: + cx_auto_line_automute(codec); break; case CONEXANT_MIC_EVENT: cx_auto_automic(codec); @@ -3390,43 +3791,45 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) } } -/* return true if it's an internal-mic pin */ -static int is_int_mic(struct hda_codec *codec, hda_nid_t pin) -{ - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); - return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT; -} - -/* return true if it's an external-mic pin */ -static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) -{ - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); - return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL && - (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT); -} - /* check whether the pin config is suitable for auto-mic switching; - * auto-mic is enabled only when one int-mic and one-ext mic exist + * auto-mic is enabled only when one int-mic and one ext- and/or + * one dock-mic exist */ static void cx_auto_check_auto_mic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; + int pset[INPUT_PIN_ATTR_NORMAL + 1]; + int i; - if (is_ext_mic(codec, cfg->inputs[0].pin) && - is_int_mic(codec, cfg->inputs[1].pin)) { - spec->auto_mic = 1; - spec->auto_mic_ext = 1; - return; - } - if (is_int_mic(codec, cfg->inputs[1].pin) && - is_ext_mic(codec, cfg->inputs[0].pin)) { - spec->auto_mic = 1; - spec->auto_mic_ext = 0; - return; + for (i = 0; i < ARRAY_SIZE(pset); i++) + pset[i] = -1; + for (i = 0; i < spec->private_imux.num_items; i++) { + hda_nid_t pin = spec->imux_info[i].pin; + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); + int type, attr; + attr = snd_hda_get_input_pin_attr(def_conf); + if (attr == INPUT_PIN_ATTR_UNUSED) + return; /* invalid entry */ + if (attr > INPUT_PIN_ATTR_NORMAL) + attr = INPUT_PIN_ATTR_NORMAL; + if (attr != INPUT_PIN_ATTR_INT && + !is_jack_detectable(codec, pin)) + return; /* non-detectable pin */ + type = get_defcfg_device(def_conf); + if (type != AC_JACK_MIC_IN && + (attr != INPUT_PIN_ATTR_DOCK || type != AC_JACK_LINE_IN)) + return; /* no valid input type */ + if (pset[attr] >= 0) + return; /* already occupied */ + pset[attr] = i; } + if (pset[INPUT_PIN_ATTR_INT] < 0 || + (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK])) + return; /* no input to switch*/ + spec->auto_mic = 1; + spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL]; + spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK]; + spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT]; } static void cx_auto_parse_input(struct hda_codec *codec) @@ -3434,22 +3837,37 @@ static void cx_auto_parse_input(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; struct hda_input_mux *imux; - int i; + int i, j; imux = &spec->private_imux; for (i = 0; i < cfg->num_inputs; i++) { - int idx = get_connection_index(codec, spec->adc_nids[0], - cfg->inputs[i].pin); - if (idx >= 0) { - const char *label; - label = hda_get_autocfg_input_label(codec, cfg, i); - snd_hda_add_imux_item(imux, label, idx, NULL); + for (j = 0; j < spec->num_adc_nids; j++) { + hda_nid_t adc = spec->adc_nids[j]; + int idx = get_input_connection(codec, adc, + cfg->inputs[i].pin); + if (idx >= 0) { + const char *label; + label = hda_get_autocfg_input_label(codec, cfg, i); + spec->imux_info[imux->num_items].index = i; + spec->imux_info[imux->num_items].boost = 0; + spec->imux_info[imux->num_items].adc = adc; + spec->imux_info[imux->num_items].pin = + cfg->inputs[i].pin; + snd_hda_add_imux_item(imux, label, idx, NULL); + break; + } } } - if (imux->num_items == 2 && cfg->num_inputs == 2) + if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items) cx_auto_check_auto_mic(codec); - if (imux->num_items > 1 && !spec->auto_mic) - spec->input_mux = imux; + if (imux->num_items > 1 && !spec->auto_mic) { + for (i = 1; i < imux->num_items; i++) { + if (spec->imux_info[i].adc != spec->imux_info[0].adc) { + spec->adc_switching = 1; + break; + } + } + } } /* get digital-input audio widget corresponding to the given pin */ @@ -3515,14 +3933,15 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec) return 0; } -static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins, - hda_nid_t *pins) +static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, bool on) { int i; for (i = 0; i < num_pins; i++) { if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) snd_hda_codec_write(codec, pins[i], 0, - AC_VERB_SET_EAPD_BTLENABLE, 0x02); + AC_VERB_SET_EAPD_BTLENABLE, + on ? 0x02 : 0); } } @@ -3535,6 +3954,34 @@ static void select_connection(struct hda_codec *codec, hda_nid_t pin, AC_VERB_SET_CONNECT_SEL, idx); } +static void mute_outputs(struct hda_codec *codec, int num_nids, + const hda_nid_t *nids) +{ + int i, val; + + for (i = 0; i < num_nids; i++) { + hda_nid_t nid = nids[i]; + if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + continue; + if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE) + val = AMP_OUT_MUTE; + else + val = AMP_OUT_ZERO; + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, val); + } +} + +static void enable_unsol_pins(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, unsigned int tag) +{ + int i; + for (i = 0; i < num_pins; i++) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | tag); +} + static void cx_auto_init_output(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -3542,51 +3989,53 @@ static void cx_auto_init_output(struct hda_codec *codec) hda_nid_t nid; int i; - for (i = 0; i < spec->multiout.num_dacs; i++) - snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - + mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids); for (i = 0; i < cfg->hp_outs; i++) snd_hda_codec_write(codec, cfg->hp_pins[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); - if (spec->auto_mute) { - for (i = 0; i < cfg->hp_outs; i++) { - snd_hda_codec_write(codec, cfg->hp_pins[i], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | CONEXANT_HP_EVENT); - } - cx_auto_hp_automute(codec); - } else { - for (i = 0; i < cfg->line_outs; i++) - snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - for (i = 0; i < cfg->speaker_outs; i++) - snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - } - + mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); + mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); + mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins); for (i = 0; i < spec->dac_info_filled; i++) { nid = spec->dac_info[i].dac; if (!nid) nid = spec->multiout.dac_nids[0]; select_connection(codec, spec->dac_info[i].pin, nid); } - - /* turn on EAPD */ - cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins); - cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins); - cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins); + if (spec->auto_mute) { + enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins, + CONEXANT_HP_EVENT); + spec->hp_present = detect_jacks(codec, cfg->hp_outs, + cfg->hp_pins); + if (spec->detect_line) { + enable_unsol_pins(codec, cfg->line_outs, + cfg->line_out_pins, + CONEXANT_LINE_EVENT); + spec->line_present = + detect_jacks(codec, cfg->line_outs, + cfg->line_out_pins); + } + } + cx_auto_update_speakers(codec); } static void cx_auto_init_input(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + int i, val; - for (i = 0; i < spec->num_adc_nids; i++) - snd_hda_codec_write(codec, spec->adc_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)); + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t nid = spec->adc_nids[i]; + if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) + continue; + if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE) + val = AMP_IN_MUTE(0); + else + val = AMP_IN_UNMUTE(0); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + val); + } for (i = 0; i < cfg->num_inputs; i++) { unsigned int type; @@ -3599,17 +4048,22 @@ static void cx_auto_init_input(struct hda_codec *codec) } if (spec->auto_mic) { - int ext_idx = spec->auto_mic_ext; - snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | CONEXANT_MIC_EVENT); + if (spec->auto_mic_ext >= 0) { + snd_hda_codec_write(codec, + cfg->inputs[spec->auto_mic_ext].pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | CONEXANT_MIC_EVENT); + } + if (spec->auto_mic_dock >= 0) { + snd_hda_codec_write(codec, + cfg->inputs[spec->auto_mic_dock].pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | CONEXANT_MIC_EVENT); + } cx_auto_automic(codec); } else { - for (i = 0; i < spec->num_adc_nids; i++) { - snd_hda_codec_write(codec, spec->adc_nids[i], 0, - AC_VERB_SET_CONNECT_SEL, - spec->private_imux.items[0].index); - } + select_input_connection(codec, spec->imux_info[0].adc, + spec->imux_info[0].pin); } } @@ -3644,7 +4098,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, HDA_CODEC_VOLUME(name, 0, 0, 0), HDA_CODEC_MUTE(name, 0, 0, 0), }; - static char *sfx[2] = { "Volume", "Switch" }; + static const char * const sfx[2] = { "Volume", "Switch" }; int i, err; for (i = 0; i < 2; i++) { @@ -3672,6 +4126,19 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, #define cx_auto_add_pb_volume(codec, nid, str, idx) \ cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) +static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac, + hda_nid_t pin, const char *name, int idx) +{ + unsigned int caps; + caps = query_amp_caps(codec, dac, HDA_OUTPUT); + if (caps & AC_AMPCAP_NUM_STEPS) + return cx_auto_add_pb_volume(codec, dac, name, idx); + caps = query_amp_caps(codec, pin, HDA_OUTPUT); + if (caps & AC_AMPCAP_NUM_STEPS) + return cx_auto_add_pb_volume(codec, pin, name, idx); + return 0; +} + static int cx_auto_build_output_controls(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -3680,8 +4147,10 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) static const char * const texts[3] = { "Front", "Surround", "CLFE" }; if (spec->dac_info_filled == 1) - return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac, - "Master", 0); + return try_add_pb_volume(codec, spec->dac_info[0].dac, + spec->dac_info[0].pin, + "Master", 0); + for (i = 0; i < spec->dac_info_filled; i++) { const char *label; int idx, type; @@ -3705,74 +4174,123 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) idx = num_spk++; break; } - err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac, - label, idx); + err = try_add_pb_volume(codec, spec->dac_info[i].dac, + spec->dac_info[i].pin, + label, idx); if (err < 0) return err; } + + if (spec->auto_mute) { + err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum); + if (err < 0) + return err; + } + + return 0; +} + +static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, + const char *label, const char *pfx, + int cidx) +{ + struct conexant_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t adc_nid = spec->adc_nids[i]; + int idx = get_input_connection(codec, adc_nid, nid); + if (idx < 0) + continue; + return cx_auto_add_volume_idx(codec, label, pfx, + cidx, adc_nid, HDA_INPUT, idx); + } + return 0; +} + +static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx, + const char *label, int cidx) +{ + struct conexant_spec *spec = codec->spec; + hda_nid_t mux, nid; + int i, con; + + nid = spec->imux_info[idx].pin; + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) + return cx_auto_add_volume(codec, label, " Boost", cidx, + nid, HDA_INPUT); + con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, + &mux, false, 0); + if (con < 0) + return 0; + for (i = 0; i < idx; i++) { + if (spec->imux_info[i].boost == mux) + return 0; /* already present */ + } + + if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) { + spec->imux_info[idx].boost = mux; + return cx_auto_add_volume(codec, label, " Boost", 0, + mux, HDA_OUTPUT); + } return 0; } static int cx_auto_build_input_controls(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - static const char *prev_label; - int i, err, cidx, conn_len; - hda_nid_t conn[HDA_MAX_CONNECTIONS]; - - int multi_adc_volume = 0; /* If the ADC nid has several input volumes */ - int adc_nid = spec->adc_nids[0]; - - conn_len = snd_hda_get_connections(codec, adc_nid, conn, - HDA_MAX_CONNECTIONS); - if (conn_len < 0) - return conn_len; - - multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1; - if (!multi_adc_volume) { - err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid, - HDA_INPUT); - if (err < 0) - return err; + struct hda_input_mux *imux = &spec->private_imux; + const char *prev_label; + int input_conn[HDA_MAX_NUM_INPUTS]; + int i, err, cidx; + int multi_connection; + + multi_connection = 0; + for (i = 0; i < imux->num_items; i++) { + cidx = get_input_connection(codec, spec->imux_info[i].adc, + spec->imux_info[i].pin); + input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; + if (i > 0 && input_conn[i] != input_conn[0]) + multi_connection = 1; } prev_label = NULL; cidx = 0; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; + for (i = 0; i < imux->num_items; i++) { + hda_nid_t nid = spec->imux_info[i].pin; const char *label; - int j; - int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP; - if (!pin_amp && !multi_adc_volume) - continue; - label = hda_get_autocfg_input_label(codec, cfg, i); + label = hda_get_autocfg_input_label(codec, &spec->autocfg, + spec->imux_info[i].index); if (label == prev_label) cidx++; else cidx = 0; prev_label = label; - if (pin_amp) { - err = cx_auto_add_volume(codec, label, " Boost", cidx, - nid, HDA_INPUT); - if (err < 0) - return err; - } + err = cx_auto_add_boost_volume(codec, i, label, cidx); + if (err < 0) + return err; - if (!multi_adc_volume) - continue; - for (j = 0; j < conn_len; j++) { - if (conn[j] == nid) { - err = cx_auto_add_volume_idx(codec, label, - " Capture", cidx, adc_nid, HDA_INPUT, j); - if (err < 0) - return err; - break; - } + if (!multi_connection) { + if (i > 0) + continue; + err = cx_auto_add_capture_volume(codec, nid, + "Capture", "", cidx); + } else { + err = cx_auto_add_capture_volume(codec, nid, + label, " Capture", cidx); } + if (err < 0) + return err; + } + + if (spec->private_imux.num_items > 1 && !spec->auto_mic) { + err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers); + if (err < 0) + return err; } + return 0; } @@ -3789,7 +4307,29 @@ static int cx_auto_build_controls(struct hda_codec *codec) return conexant_build_controls(codec); } -static struct hda_codec_ops cx_auto_patch_ops = { +static int cx_auto_search_adcs(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + hda_nid_t nid, end_nid; + + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) { + unsigned int caps = get_wcaps(codec, nid); + if (get_wcaps_type(caps) != AC_WID_AUD_IN) + continue; + if (caps & AC_WCAP_DIGITAL) + continue; + if (snd_BUG_ON(spec->num_adc_nids >= + ARRAY_SIZE(spec->private_adc_nids))) + break; + spec->private_adc_nids[spec->num_adc_nids++] = nid; + } + spec->adc_nids = spec->private_adc_nids; + return 0; +} + + +static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = cx_auto_build_controls, .build_pcms = conexant_build_pcms, .init = cx_auto_init, @@ -3806,19 +4346,24 @@ static int patch_conexant_auto(struct hda_codec *codec) struct conexant_spec *spec; int err; + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; codec->spec = spec; - spec->adc_nids = cx_auto_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids); - spec->capsrc_nids = spec->adc_nids; + codec->pin_amp_workaround = 1; + err = cx_auto_search_adcs(codec); + if (err < 0) + return err; err = cx_auto_parse_auto_config(codec); if (err < 0) { kfree(codec->spec); codec->spec = NULL; return err; } + spec->capture_stream = &cx_auto_pcm_analog_capture; codec->patch_ops = cx_auto_patch_ops; if (spec->beep_amp) snd_hda_attach_beep_device(codec, spec->beep_amp); @@ -3828,7 +4373,7 @@ static int patch_conexant_auto(struct hda_codec *codec) /* */ -static struct hda_codec_preset snd_hda_preset_conexant[] = { +static const struct hda_codec_preset snd_hda_preset_conexant[] = { { .id = 0x14f15045, .name = "CX20549 (Venice)", .patch = patch_cxt5045 }, { .id = 0x14f15047, .name = "CX20551 (Waikiki)", diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 251773e45f61..bd0ae697f9c4 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <linux/moduleparam.h> #include <sound/core.h> +#include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" @@ -47,8 +48,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); * * The HDA correspondence of pipes/ports are converter/pin nodes. */ -#define MAX_HDMI_CVTS 3 -#define MAX_HDMI_PINS 3 +#define MAX_HDMI_CVTS 4 +#define MAX_HDMI_PINS 4 struct hdmi_spec { int num_cvts; @@ -76,11 +77,7 @@ struct hdmi_spec { * ati/nvhdmi specific */ struct hda_multi_out multiout; - struct hda_pcm_stream *pcm_playback; - - /* misc flags */ - /* PD bit indicates only the update, not the current state */ - unsigned int old_pin_detect:1; + const struct hda_pcm_stream *pcm_playback; }; @@ -299,13 +296,6 @@ static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) return -EINVAL; } -static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_eld *eld) -{ - if (!snd_hdmi_get_eld(eld, codec, pin_nid)) - snd_hdmi_show_eld(eld); -} - #ifdef BE_PARANOID static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, int *packet_index, int *byte_index) @@ -693,33 +683,20 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) { struct hdmi_spec *spec = codec->spec; - int tag = res >> AC_UNSOL_RES_TAG_SHIFT; - int pind = !!(res & AC_UNSOL_RES_PD); + int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT; + int pd = !!(res & AC_UNSOL_RES_PD); int eldv = !!(res & AC_UNSOL_RES_ELDV); int index; printk(KERN_INFO "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - tag, pind, eldv); + pin_nid, pd, eldv); - index = hda_node_index(spec->pin, tag); + index = hda_node_index(spec->pin, pin_nid); if (index < 0) return; - if (spec->old_pin_detect) { - if (pind) - hdmi_present_sense(codec, tag, &spec->sink_eld[index]); - pind = spec->sink_eld[index].monitor_present; - } - - spec->sink_eld[index].monitor_present = pind; - spec->sink_eld[index].eld_valid = eldv; - - if (pind && eldv) { - hdmi_get_show_eld(codec, spec->pin[index], - &spec->sink_eld[index]); - /* TODO: do real things about ELD */ - } + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -900,18 +877,39 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, struct hdmi_eld *eld) { + /* + * Always execute a GetPinSense verb here, even when called from + * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited + * response's PD bit is not the real PD value, but indicates that + * the real PD value changed. An older version of the HD-audio + * specification worked this way. Hence, we just ignore the data in + * the unsolicited response to avoid custom WARs. + */ int present = snd_hda_pin_sense(codec, pin_nid); + memset(eld, 0, sizeof(*eld)); + eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); - eld->eld_valid = !!(present & AC_PINSENSE_ELDV); + if (eld->monitor_present) + eld->eld_valid = !!(present & AC_PINSENSE_ELDV); + else + eld->eld_valid = 0; + + printk(KERN_INFO + "HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", + pin_nid, eld->monitor_present, eld->eld_valid); + + if (eld->eld_valid) + if (!snd_hdmi_get_eld(eld, codec, pin_nid)) + snd_hdmi_show_eld(eld); - if (present & AC_PINSENSE_ELDV) - hdmi_get_show_eld(codec, pin_nid, eld); + snd_hda_input_jack_report(codec, pin_nid); } static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) { struct hdmi_spec *spec = codec->spec; + int err; if (spec->num_pins >= MAX_HDMI_PINS) { snd_printk(KERN_WARNING @@ -919,6 +917,11 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) return -E2BIG; } + err = snd_hda_input_jack_add(codec, pin_nid, + SND_JACK_VIDEOOUT, NULL); + if (err < 0) + return err; + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); spec->pin[spec->num_pins] = pin_nid; @@ -1024,6 +1027,7 @@ static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = { "HDMI 0", "HDMI 1", "HDMI 2", + "HDMI 3", }; /* @@ -1044,7 +1048,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); } -static struct hda_pcm_stream generic_hdmi_pcm_playback = { +static const struct hda_pcm_stream generic_hdmi_pcm_playback = { .substreams = 1, .channels_min = 2, .ops = { @@ -1120,11 +1124,12 @@ static void generic_hdmi_free(struct hda_codec *codec) for (i = 0; i < spec->num_pins; i++) snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); + snd_hda_input_jack_free(codec); kfree(spec); } -static struct hda_codec_ops generic_hdmi_patch_ops = { +static const struct hda_codec_ops generic_hdmi_patch_ops = { .init = generic_hdmi_init, .free = generic_hdmi_free, .build_pcms = generic_hdmi_build_pcms, @@ -1169,12 +1174,12 @@ static int patch_generic_hdmi(struct hda_codec *codec) #define nvhdmi_master_con_nid_7x 0x04 #define nvhdmi_master_pin_nid_7x 0x05 -static hda_nid_t nvhdmi_con_nids_7x[4] = { +static const hda_nid_t nvhdmi_con_nids_7x[4] = { /*front, rear, clfe, rear_surr */ 0x6, 0x8, 0xa, 0xc, }; -static struct hda_verb nvhdmi_basic_init_7x[] = { +static const struct hda_verb nvhdmi_basic_init_7x[] = { /* set audio protect on */ { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, /* enable digital output on pin widget */ @@ -1280,6 +1285,39 @@ static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo, stream_tag, format, substream); } +static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec, + int channels) +{ + unsigned int chanmask; + int chan = channels ? (channels - 1) : 1; + + switch (channels) { + default: + case 0: + case 2: + chanmask = 0x00; + break; + case 4: + chanmask = 0x08; + break; + case 6: + chanmask = 0x0b; + break; + case 8: + chanmask = 0x13; + break; + } + + /* Set the audio infoframe channel allocation and checksum fields. The + * channel count is computed implicitly by the hardware. */ + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Channel_Allocation, chanmask); + + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Info_Frame_Checksum, + (0x71 - chan - chanmask)); +} + static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) @@ -1298,6 +1336,10 @@ static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo, AC_VERB_SET_STREAM_FORMAT, 0); } + /* The audio hardware sends a channel count of 0x7 (8ch) when all the + * streams are disabled. */ + nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8); + return snd_hda_multi_out_dig_close(codec, &spec->multiout); } @@ -1308,37 +1350,16 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { int chs; - unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id; + unsigned int dataDCC1, dataDCC2, channel_id; int i; mutex_lock(&codec->spdif_mutex); chs = substream->runtime->channels; - chan = chs ? (chs - 1) : 1; - switch (chs) { - default: - case 0: - case 2: - chanmask = 0x00; - break; - case 4: - chanmask = 0x08; - break; - case 6: - chanmask = 0x0b; - break; - case 8: - chanmask = 0x13; - break; - } dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT; dataDCC2 = 0x2; - /* set the Audio InforFrame Channel Allocation */ - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Channel_Allocation, chanmask); - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, @@ -1413,16 +1434,13 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, } } - /* set the Audio Info Frame Checksum */ - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Info_Frame_Checksum, - (0x71 - chan - chanmask)); + nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs); mutex_unlock(&codec->spdif_mutex); return 0; } -static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { +static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -1437,7 +1455,7 @@ static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { }, }; -static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = { +static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1452,32 +1470,20 @@ static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = { }, }; -static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { +static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { .build_controls = generic_hdmi_build_controls, .build_pcms = generic_hdmi_build_pcms, .init = nvhdmi_7x_init, .free = generic_hdmi_free, }; -static struct hda_codec_ops nvhdmi_patch_ops_2ch = { +static const struct hda_codec_ops nvhdmi_patch_ops_2ch = { .build_controls = generic_hdmi_build_controls, .build_pcms = generic_hdmi_build_pcms, .init = nvhdmi_7x_init, .free = generic_hdmi_free, }; -static int patch_nvhdmi_8ch_89(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int err = patch_generic_hdmi(codec); - - if (err < 0) - return err; - spec = codec->spec; - spec->old_pin_detect = 1; - return 0; -} - static int patch_nvhdmi_2ch(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -1491,7 +1497,6 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; - spec->old_pin_detect = 1; spec->num_cvts = 1; spec->cvt[0] = nvhdmi_master_con_nid_7x; spec->pcm_playback = &nvhdmi_pcm_playback_2ch; @@ -1512,6 +1517,11 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) spec->multiout.max_channels = 8; spec->pcm_playback = &nvhdmi_pcm_playback_8ch_7x; codec->patch_ops = nvhdmi_patch_ops_8ch_7x; + + /* Initialize the audio infoframe channel mask and checksum to something + * valid */ + nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8); + return 0; } @@ -1550,7 +1560,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream atihdmi_pcm_digital_playback = { +static const struct hda_pcm_stream atihdmi_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1562,7 +1572,7 @@ static struct hda_pcm_stream atihdmi_pcm_digital_playback = { }, }; -static struct hda_verb atihdmi_basic_init[] = { +static const struct hda_verb atihdmi_basic_init[] = { /* enable digital output on pin widget */ { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, {} /* terminator */ @@ -1581,7 +1591,7 @@ static int atihdmi_init(struct hda_codec *codec) return 0; } -static struct hda_codec_ops atihdmi_patch_ops = { +static const struct hda_codec_ops atihdmi_patch_ops = { .build_controls = generic_hdmi_build_controls, .build_pcms = generic_hdmi_build_pcms, .init = atihdmi_init, @@ -1616,7 +1626,7 @@ static int patch_atihdmi(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_hdmi[] = { +static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, @@ -1629,28 +1639,28 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, -{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_generic_hdmi }, /* 17 is known to be absent */ -{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, -{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, @@ -1659,6 +1669,7 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi }, { .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, {} /* terminator */ }; @@ -1704,6 +1715,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862802"); MODULE_ALIAS("snd-hda-codec-id:80862803"); MODULE_ALIAS("snd-hda-codec-id:80862804"); MODULE_ALIAS("snd-hda-codec-id:80862805"); +MODULE_ALIAS("snd-hda-codec-id:80862806"); 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 0ef0035fe99f..7a4e10002f56 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -299,11 +299,23 @@ struct alc_customize_define { struct alc_fixup; +struct alc_multi_io { + hda_nid_t pin; /* multi-io widget pin NID */ + hda_nid_t dac; /* DAC to be connected */ + unsigned int ctl_in; /* cached input-pin control value */ +}; + +enum { + ALC_AUTOMUTE_PIN, /* change the pin control */ + ALC_AUTOMUTE_AMP, /* mute/unmute the pin AMP */ + ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */ +}; + struct alc_spec { /* codec parameterization */ - struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ + const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ unsigned int num_mixers; - struct snd_kcontrol_new *cap_mixer; /* capture mixer */ + const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ const struct hda_verb *init_verbs[10]; /* initialization verbs @@ -313,14 +325,14 @@ struct alc_spec { unsigned int num_init_verbs; char stream_name_analog[32]; /* analog PCM stream */ - struct hda_pcm_stream *stream_analog_playback; - struct hda_pcm_stream *stream_analog_capture; - struct hda_pcm_stream *stream_analog_alt_playback; - struct hda_pcm_stream *stream_analog_alt_capture; + const struct hda_pcm_stream *stream_analog_playback; + const struct hda_pcm_stream *stream_analog_capture; + const struct hda_pcm_stream *stream_analog_alt_playback; + const struct hda_pcm_stream *stream_analog_alt_capture; char stream_name_digital[32]; /* digital PCM stream */ - struct hda_pcm_stream *stream_digital_playback; - struct hda_pcm_stream *stream_digital_capture; + const struct hda_pcm_stream *stream_digital_playback; + const struct hda_pcm_stream *stream_digital_capture; /* playback */ struct hda_multi_out multiout; /* playback set-up @@ -333,8 +345,8 @@ struct alc_spec { /* capture */ unsigned int num_adc_nids; - hda_nid_t *adc_nids; - hda_nid_t *capsrc_nids; + const hda_nid_t *adc_nids; + const hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ /* capture setup for dynamic dual-adc switch */ @@ -348,6 +360,7 @@ struct alc_spec { const struct hda_input_mux *input_mux; unsigned int cur_mux[3]; struct alc_mic_route ext_mic; + struct alc_mic_route dock_mic; struct alc_mic_route int_mic; /* channel model */ @@ -375,17 +388,27 @@ struct alc_spec { #ifdef CONFIG_SND_HDA_POWER_SAVE void (*power_hook)(struct hda_codec *codec); #endif + void (*shutup)(struct hda_codec *codec); /* for pin sensing */ - unsigned int sense_updated: 1; unsigned int jack_present: 1; - unsigned int master_sw: 1; + unsigned int line_jack_present:1; + unsigned int master_mute:1; unsigned int auto_mic:1; + unsigned int automute:1; /* HP automute enabled */ + unsigned int detect_line:1; /* Line-out detection enabled */ + unsigned int automute_lines:1; /* automute line-out as well */ + unsigned int automute_hp_lo:1; /* both HP and LO available */ /* other flags */ unsigned int no_analog :1; /* digital I/O only */ unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ unsigned int single_input_src:1; + + /* auto-mute control */ + int automute_mode; + hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS]; + int init_amp; int codec_variant; /* flag for other variants */ @@ -403,25 +426,29 @@ struct alc_spec { int fixup_id; const struct alc_fixup *fixup_list; const char *fixup_name; + + /* multi-io */ + int multi_ios; + struct alc_multi_io multi_io[4]; }; /* * configuration template - to be copied to the spec instance */ struct alc_config_preset { - struct snd_kcontrol_new *mixers[5]; /* should be identical size + const struct snd_kcontrol_new *mixers[5]; /* should be identical size * with spec */ - struct snd_kcontrol_new *cap_mixer; /* capture mixer */ + const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ const struct hda_verb *init_verbs[5]; unsigned int num_dacs; - hda_nid_t *dac_nids; + const hda_nid_t *dac_nids; hda_nid_t dig_out_nid; /* optional */ hda_nid_t hp_nid; /* optional */ - hda_nid_t *slave_dig_outs; + const hda_nid_t *slave_dig_outs; unsigned int num_adc_nids; - hda_nid_t *adc_nids; - hda_nid_t *capsrc_nids; + const hda_nid_t *adc_nids; + const hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; unsigned int num_channel_mode; const struct hda_channel_mode *channel_mode; @@ -433,7 +460,7 @@ struct alc_config_preset { void (*setup)(struct hda_codec *); void (*init_hook)(struct hda_codec *); #ifdef CONFIG_SND_HDA_POWER_SAVE - struct hda_amp_list *loopbacks; + const struct hda_amp_list *loopbacks; void (*power_hook)(struct hda_codec *codec); #endif }; @@ -549,7 +576,7 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, /* * Control the mode of pin widget settings via the mixer. "pc" is used - * instead of "%" to avoid consequences of accidently treating the % as + * instead of "%" to avoid consequences of accidentally treating the % as * being part of a format specifier. Maximum allowed length of a value is * 63 characters plus NULL terminator. * @@ -560,11 +587,11 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, * NIDs 0x0f and 0x10 have been observed to have this behaviour as of * March 2006. */ -static char *alc_pin_mode_names[] = { +static const char * const alc_pin_mode_names[] = { "Mic 50pc bias", "Mic 80pc bias", "Line in", "Line out", "Headphone out", }; -static unsigned char alc_pin_mode_values[] = { +static const unsigned char alc_pin_mode_values[] = { PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP, }; /* The control can present all 5 options, or it can limit the options based @@ -583,7 +610,7 @@ static unsigned char alc_pin_mode_values[] = { /* Info about the pin modes supported by the different pin direction modes. * For each direction the minimum and maximum values are given. */ -static signed char alc_pin_mode_dir_info[5][2] = { +static const signed char alc_pin_mode_dir_info[5][2] = { { 0, 2 }, /* ALC_PIN_DIR_IN */ { 3, 4 }, /* ALC_PIN_DIR_OUT */ { 0, 4 }, /* ALC_PIN_DIR_INOUT */ @@ -900,7 +927,7 @@ static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec) /* */ -static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix) +static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix) { if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers))) return; @@ -971,21 +998,21 @@ static void setup_preset(struct hda_codec *codec, } /* Enable GPIO mask and set output */ -static struct hda_verb alc_gpio1_init_verbs[] = { +static const struct hda_verb alc_gpio1_init_verbs[] = { {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, { } }; -static struct hda_verb alc_gpio2_init_verbs[] = { +static const struct hda_verb alc_gpio2_init_verbs[] = { {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, { } }; -static struct hda_verb alc_gpio3_init_verbs[] = { +static const struct hda_verb alc_gpio3_init_verbs[] = { {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, @@ -1031,6 +1058,7 @@ static int alc_init_jacks(struct hda_codec *codec) int err; unsigned int hp_nid = spec->autocfg.hp_pins[0]; unsigned int mic_nid = spec->ext_mic.pin; + unsigned int dock_nid = spec->dock_mic.pin; if (hp_nid) { err = snd_hda_input_jack_add(codec, hp_nid, @@ -1047,46 +1075,116 @@ static int alc_init_jacks(struct hda_codec *codec) return err; snd_hda_input_jack_report(codec, mic_nid); } + if (dock_nid) { + err = snd_hda_input_jack_add(codec, dock_nid, + SND_JACK_MICROPHONE, NULL); + if (err < 0) + return err; + snd_hda_input_jack_report(codec, dock_nid); + } #endif /* CONFIG_SND_HDA_INPUT_JACK */ return 0; } -static void alc_automute_speaker(struct hda_codec *codec, int pinctl) +static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) { - struct alc_spec *spec = codec->spec; - unsigned int mute; - hda_nid_t nid; - int i; + int i, present = 0; - spec->jack_present = 0; - for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { - nid = spec->autocfg.hp_pins[i]; + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; if (!nid) break; snd_hda_input_jack_report(codec, nid); - spec->jack_present |= snd_hda_jack_detect(codec, nid); + present |= snd_hda_jack_detect(codec, nid); } + return present; +} - mute = spec->jack_present ? HDA_AMP_MUTE : 0; - /* Toggle internal speakers muting */ - for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { - nid = spec->autocfg.speaker_pins[i]; +static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, + bool mute, bool hp_out) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0; + unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT); + int i; + + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; if (!nid) break; - if (pinctl) { + switch (spec->automute_mode) { + case ALC_AUTOMUTE_PIN: snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spec->jack_present ? 0 : PIN_OUT); - } else { + AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_bits); + break; + case ALC_AUTOMUTE_AMP: snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); + HDA_AMP_MUTE, mute_bits); + break; + case ALC_AUTOMUTE_MIXER: + nid = spec->automute_mixer_nid[i]; + if (!nid) + break; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, mute_bits); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1, + HDA_AMP_MUTE, mute_bits); + break; } } } -static void alc_automute_pin(struct hda_codec *codec) +/* Toggle internal speakers muting */ +static void update_speakers(struct hda_codec *codec) { - alc_automute_speaker(codec, 1); + struct alc_spec *spec = codec->spec; + int on; + + if (!spec->automute) + on = 0; + else + on = spec->jack_present | spec->line_jack_present; + on |= spec->master_mute; + do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), + spec->autocfg.speaker_pins, on, false); + + /* toggle line-out mutes if needed, too */ + /* if LO is a copy of either HP or Speaker, don't need to handle it */ + if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || + spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) + return; + if (!spec->automute_lines || !spec->automute) + on = 0; + else + on = spec->jack_present; + on |= spec->master_mute; + do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), + spec->autocfg.line_out_pins, on, false); +} + +static void alc_hp_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->automute) + return; + spec->jack_present = + detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), + spec->autocfg.hp_pins); + update_speakers(codec); +} + +static void alc_line_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->automute || !spec->detect_line) + return; + spec->line_jack_present = + detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), + spec->autocfg.line_out_pins); + update_speakers(codec); } static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, @@ -1128,7 +1226,7 @@ static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec) static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct alc_mic_route *dead, *alive; + struct alc_mic_route *dead1, *dead2, *alive; unsigned int present, type; hda_nid_t cap_nid; @@ -1146,13 +1244,24 @@ static void alc_mic_automute(struct hda_codec *codec) cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; + alive = &spec->int_mic; + dead1 = &spec->ext_mic; + dead2 = &spec->dock_mic; + present = snd_hda_jack_detect(codec, spec->ext_mic.pin); if (present) { alive = &spec->ext_mic; - dead = &spec->int_mic; - } else { - alive = &spec->int_mic; - dead = &spec->ext_mic; + dead1 = &spec->int_mic; + dead2 = &spec->dock_mic; + } + if (!present && spec->dock_mic.pin > 0) { + present = snd_hda_jack_detect(codec, spec->dock_mic.pin); + if (present) { + alive = &spec->dock_mic; + dead1 = &spec->int_mic; + dead2 = &spec->ext_mic; + } + snd_hda_input_jack_report(codec, spec->dock_mic.pin); } type = get_wcaps_type(get_wcaps(codec, cap_nid)); @@ -1161,9 +1270,14 @@ static void alc_mic_automute(struct hda_codec *codec) snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, alive->mux_idx, HDA_AMP_MUTE, 0); - snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, - dead->mux_idx, - HDA_AMP_MUTE, HDA_AMP_MUTE); + if (dead1->pin > 0) + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + dead1->mux_idx, + HDA_AMP_MUTE, HDA_AMP_MUTE); + if (dead2->pin > 0) + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + dead2->mux_idx, + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { /* MUX style (e.g. ALC880) */ snd_hda_codec_write_cache(codec, cap_nid, 0, @@ -1184,7 +1298,10 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) res >>= 26; switch (res) { case ALC880_HP_EVENT: - alc_automute_pin(codec); + alc_hp_automute(codec); + break; + case ALC880_FRONT_EVENT: + alc_line_automute(codec); break; case ALC880_MIC_EVENT: alc_mic_automute(codec); @@ -1194,7 +1311,8 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) static void alc_inithook(struct hda_codec *codec) { - alc_automute_pin(codec); + alc_hp_automute(codec); + alc_line_automute(codec); alc_mic_automute(codec); } @@ -1236,6 +1354,43 @@ static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on) on ? 2 : 0); } +/* turn on/off EAPD controls of the codec */ +static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) +{ + /* We currently only handle front, HP */ + switch (codec->vendor_id) { + case 0x10ec0260: + set_eapd(codec, 0x0f, on); + set_eapd(codec, 0x10, on); + break; + case 0x10ec0262: + case 0x10ec0267: + case 0x10ec0268: + case 0x10ec0269: + case 0x10ec0270: + case 0x10ec0272: + case 0x10ec0660: + case 0x10ec0662: + case 0x10ec0663: + case 0x10ec0665: + case 0x10ec0862: + case 0x10ec0889: + case 0x10ec0892: + set_eapd(codec, 0x14, on); + set_eapd(codec, 0x15, on); + break; + } +} + +/* generic shutup callback; + * just turning off EPAD and a little pause for avoiding pop-noise + */ +static void alc_eapd_shutup(struct hda_codec *codec) +{ + alc_auto_setup_eapd(codec, false); + msleep(200); +} + static void alc_auto_init_amp(struct hda_codec *codec, int type) { unsigned int tmp; @@ -1251,27 +1406,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; case ALC_INIT_DEFAULT: - switch (codec->vendor_id) { - case 0x10ec0260: - set_eapd(codec, 0x0f, 1); - set_eapd(codec, 0x10, 1); - break; - case 0x10ec0262: - case 0x10ec0267: - case 0x10ec0268: - case 0x10ec0269: - case 0x10ec0270: - case 0x10ec0272: - case 0x10ec0660: - case 0x10ec0662: - case 0x10ec0663: - case 0x10ec0665: - case 0x10ec0862: - case 0x10ec0889: - set_eapd(codec, 0x14, 1); - set_eapd(codec, 0x15, 1); - break; - } + alc_auto_setup_eapd(codec, true); switch (codec->vendor_id) { case 0x10ec0260: snd_hda_codec_write(codec, 0x1a, 0, @@ -1315,20 +1450,128 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) } } +static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + static const char * const texts2[] = { + "Disabled", "Enabled" + }; + static const char * const texts3[] = { + "Disabled", "Speaker Only", "Line-Out+Speaker" + }; + const char * const *texts; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + if (spec->automute_hp_lo) { + uinfo->value.enumerated.items = 3; + texts = texts3; + } else { + uinfo->value.enumerated.items = 2; + texts = texts2; + } + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_automute_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + unsigned int val; + if (!spec->automute) + val = 0; + else if (!spec->automute_lines) + val = 1; + else + val = 2; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int alc_automute_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + + switch (ucontrol->value.enumerated.item[0]) { + case 0: + if (!spec->automute) + return 0; + spec->automute = 0; + break; + case 1: + if (spec->automute && !spec->automute_lines) + return 0; + spec->automute = 1; + spec->automute_lines = 0; + break; + case 2: + if (!spec->automute_hp_lo) + return -EINVAL; + if (spec->automute && spec->automute_lines) + return 0; + spec->automute = 1; + spec->automute_lines = 1; + break; + default: + return -EINVAL; + } + update_speakers(codec); + return 1; +} + +static const struct snd_kcontrol_new alc_automute_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Auto-Mute Mode", + .info = alc_automute_mode_info, + .get = alc_automute_mode_get, + .put = alc_automute_mode_put, +}; + +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec); + +static int alc_add_automute_mode_enum(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + + knew = alc_kcontrol_new(spec); + if (!knew) + return -ENOMEM; + *knew = alc_automute_mode_enum; + knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL); + if (!knew->name) + return -ENOMEM; + return 0; +} + static void alc_init_auto_hp(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; + int present = 0; int i; - if (!cfg->hp_pins[0]) { - if (cfg->line_out_type != AUTO_PIN_HP_OUT) - return; - } + if (cfg->hp_pins[0]) + present++; + if (cfg->line_out_pins[0]) + present++; + if (cfg->speaker_pins[0]) + present++; + if (present < 2) /* need two different output types */ + return; + if (present == 3) + spec->automute_hp_lo = 1; /* both HP and LO automute */ if (!cfg->speaker_pins[0]) { - if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) - return; memcpy(cfg->speaker_pins, cfg->line_out_pins, sizeof(cfg->speaker_pins)); cfg->speaker_outs = cfg->line_outs; @@ -1341,28 +1584,49 @@ static void alc_init_auto_hp(struct hda_codec *codec) } for (i = 0; i < cfg->hp_outs; i++) { + hda_nid_t nid = cfg->hp_pins[i]; + if (!is_jack_detectable(codec, nid)) + continue; snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", - cfg->hp_pins[i]); - snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0, + nid); + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT); + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + } + if (spec->automute && cfg->line_out_pins[0] && + cfg->line_out_pins[0] != cfg->hp_pins[0] && + cfg->line_out_pins[0] != cfg->speaker_pins[0]) { + for (i = 0; i < cfg->line_outs; i++) { + hda_nid_t nid = cfg->line_out_pins[i]; + if (!is_jack_detectable(codec, nid)) + continue; + snd_printdd("realtek: Enable Line-Out auto-muting " + "on NID 0x%x\n", nid); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_FRONT_EVENT); + spec->detect_line = 1; + } + spec->automute_lines = spec->detect_line; + } + + if (spec->automute) { + /* create a control for automute mode */ + alc_add_automute_mode_enum(codec); + spec->unsol_event = alc_sku_unsol_event; } - spec->unsol_event = alc_sku_unsol_event; } static void alc_init_auto_mic(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t fixed, ext; + hda_nid_t fixed, ext, dock; int i; - /* there must be only two mic inputs exclusively */ - for (i = 0; i < cfg->num_inputs; i++) - if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN) - return; - - fixed = ext = 0; + fixed = ext = dock = 0; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; unsigned int defcfg; @@ -1371,26 +1635,45 @@ static void alc_init_auto_mic(struct hda_codec *codec) case INPUT_PIN_ATTR_INT: if (fixed) return; /* already occupied */ + if (cfg->inputs[i].type != AUTO_PIN_MIC) + return; /* invalid type */ fixed = nid; break; case INPUT_PIN_ATTR_UNUSED: return; /* invalid entry */ + case INPUT_PIN_ATTR_DOCK: + if (dock) + return; /* already occupied */ + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) + return; /* invalid type */ + dock = nid; + break; default: if (ext) return; /* already occupied */ + if (cfg->inputs[i].type != AUTO_PIN_MIC) + return; /* invalid type */ ext = nid; break; } } + if (!ext && dock) { + ext = dock; + dock = 0; + } if (!ext || !fixed) return; - if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) + if (!is_jack_detectable(codec, ext)) + return; /* no unsol support */ + if (dock && !is_jack_detectable(codec, dock)) return; /* no unsol support */ - snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n", - ext, fixed); + snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", + ext, fixed, dock); spec->ext_mic.pin = ext; + spec->dock_mic.pin = dock; spec->int_mic.pin = fixed; spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ spec->auto_mic = 1; snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0, @@ -1583,9 +1866,6 @@ do_sku: return 1; spec->autocfg.hp_pins[0] = nid; } - - alc_init_auto_hp(codec); - alc_init_auto_mic(codec); return 1; } @@ -1598,9 +1878,10 @@ static void alc_ssid_check(struct hda_codec *codec, snd_printd("realtek: " "Enable default setup for auto mode as fallback\n"); spec->init_amp = ALC_INIT_DEFAULT; - alc_init_auto_hp(codec); - alc_init_auto_mic(codec); } + + alc_init_auto_hp(codec); + alc_init_auto_mic(codec); } /* @@ -1704,11 +1985,11 @@ static void alc_apply_fixup(struct hda_codec *codec, int action) codec->chip_name, fix->type); break; } - if (!fix[id].chained) + if (!fix->chained) break; if (++depth > 10) break; - id = fix[id].chain_id; + id = fix->chain_id; } } @@ -1842,7 +2123,7 @@ static void alc_auto_parse_digital(struct hda_codec *codec) /* * 2ch mode */ -static struct hda_verb alc888_4ST_ch2_intel_init[] = { +static const struct hda_verb alc888_4ST_ch2_intel_init[] = { /* Mic-in jack as mic in */ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -1857,7 +2138,7 @@ static struct hda_verb alc888_4ST_ch2_intel_init[] = { /* * 4ch mode */ -static struct hda_verb alc888_4ST_ch4_intel_init[] = { +static const struct hda_verb alc888_4ST_ch4_intel_init[] = { /* Mic-in jack as mic in */ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -1872,7 +2153,7 @@ static struct hda_verb alc888_4ST_ch4_intel_init[] = { /* * 6ch mode */ -static struct hda_verb alc888_4ST_ch6_intel_init[] = { +static const struct hda_verb alc888_4ST_ch6_intel_init[] = { /* Mic-in jack as CLFE */ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -1887,7 +2168,7 @@ static struct hda_verb alc888_4ST_ch6_intel_init[] = { /* * 8ch mode */ -static struct hda_verb alc888_4ST_ch8_intel_init[] = { +static const struct hda_verb alc888_4ST_ch8_intel_init[] = { /* Mic-in jack as CLFE */ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -1899,7 +2180,7 @@ static struct hda_verb alc888_4ST_ch8_intel_init[] = { { } /* end */ }; -static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { +static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { { 2, alc888_4ST_ch2_intel_init }, { 4, alc888_4ST_ch4_intel_init }, { 6, alc888_4ST_ch6_intel_init }, @@ -1910,7 +2191,7 @@ static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { * ALC888 Fujitsu Siemens Amillo xa3530 */ -static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { +static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = { /* Front Mic: set to PIN_IN (empty by default) */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Connect Internal HP to Front */ @@ -1943,22 +2224,6 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { {} }; -static void alc_automute_amp(struct hda_codec *codec) -{ - alc_automute_speaker(codec, 0); -} - -static void alc_automute_amp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if (codec->vendor_id == 0x10ec0880) - res >>= 28; - else - res >>= 26; - if (res == ALC880_HP_EVENT) - alc_automute_amp(codec); -} - static void alc889_automute_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1969,12 +2234,14 @@ static void alc889_automute_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x17; spec->autocfg.speaker_pins[3] = 0x19; spec->autocfg.speaker_pins[4] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc889_intel_init_hook(struct hda_codec *codec) { alc889_coef_init(codec); - alc_automute_amp(codec); + alc_hp_automute(codec); } static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) @@ -1985,13 +2252,15 @@ static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) spec->autocfg.hp_pins[1] = 0x1b; /* hp */ spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ spec->autocfg.speaker_pins[1] = 0x15; /* bass */ + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* * ALC888 Acer Aspire 4930G model */ -static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { +static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = { /* Front Mic: set to PIN_IN (empty by default) */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Unselect Front Mic by default in input mixer 3 */ @@ -2014,7 +2283,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { * ALC888 Acer Aspire 6530G model */ -static struct hda_verb alc888_acer_aspire_6530g_verbs[] = { +static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = { /* Route to built-in subwoofer as well as speakers */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -2044,7 +2313,7 @@ static struct hda_verb alc888_acer_aspire_6530g_verbs[] = { *ALC888 Acer Aspire 7730G model */ -static struct hda_verb alc888_acer_aspire_7730G_verbs[] = { +static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = { /* Bias voltage on for external mic port */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, /* Front Mic: set to PIN_IN (empty by default) */ @@ -2074,7 +2343,7 @@ static struct hda_verb alc888_acer_aspire_7730G_verbs[] = { * ALC889 Acer Aspire 8930G model */ -static struct hda_verb alc889_acer_aspire_8930g_verbs[] = { +static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = { /* Front Mic: set to PIN_IN (empty by default) */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Unselect Front Mic by default in input mixer 3 */ @@ -2120,7 +2389,7 @@ static struct hda_verb alc889_acer_aspire_8930g_verbs[] = { { } }; -static struct hda_input_mux alc888_2_capture_sources[2] = { +static const struct hda_input_mux alc888_2_capture_sources[2] = { /* Front mic only available on one ADC */ { .num_items = 4, @@ -2141,7 +2410,7 @@ static struct hda_input_mux alc888_2_capture_sources[2] = { } }; -static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { +static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { /* Interal mic only available on one ADC */ { .num_items = 5, @@ -2164,7 +2433,7 @@ static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { } }; -static struct hda_input_mux alc889_capture_sources[3] = { +static const struct hda_input_mux alc889_capture_sources[3] = { /* Digital mic only available on first "ADC" */ { .num_items = 5, @@ -2196,7 +2465,7 @@ static struct hda_input_mux alc889_capture_sources[3] = { } }; -static struct snd_kcontrol_new alc888_base_mixer[] = { +static const struct snd_kcontrol_new alc888_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2218,7 +2487,7 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { +static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2240,7 +2509,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { +static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2267,6 +2536,8 @@ static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) @@ -2277,6 +2548,8 @@ static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) @@ -2287,6 +2560,8 @@ static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) @@ -2297,6 +2572,8 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* @@ -2307,12 +2584,12 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) * F-Mic = 0x1b, HP = 0x19 */ -static hda_nid_t alc880_dac_nids[4] = { +static const hda_nid_t alc880_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x05, 0x04, 0x03 }; -static hda_nid_t alc880_adc_nids[3] = { +static const hda_nid_t alc880_adc_nids[3] = { /* ADC0-2 */ 0x07, 0x08, 0x09, }; @@ -2321,7 +2598,7 @@ static hda_nid_t alc880_adc_nids[3] = { * but it shows zero connection in the real implementation on some devices. * Note: this is a 915GAV bug, fixed on 915GLV */ -static hda_nid_t alc880_adc_nids_alt[2] = { +static const hda_nid_t alc880_adc_nids_alt[2] = { /* ADC1-2 */ 0x08, 0x09, }; @@ -2329,7 +2606,7 @@ static hda_nid_t alc880_adc_nids_alt[2] = { #define ALC880_DIGOUT_NID 0x06 #define ALC880_DIGIN_NID 0x0a -static struct hda_input_mux alc880_capture_source = { +static const struct hda_input_mux alc880_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -2341,7 +2618,7 @@ static struct hda_input_mux alc880_capture_source = { /* channel source setting (2/6 channel selection for 3-stack) */ /* 2ch mode */ -static struct hda_verb alc880_threestack_ch2_init[] = { +static const struct hda_verb alc880_threestack_ch2_init[] = { /* set line-in to input, mute it */ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -2352,7 +2629,7 @@ static struct hda_verb alc880_threestack_ch2_init[] = { }; /* 6ch mode */ -static struct hda_verb alc880_threestack_ch6_init[] = { +static const struct hda_verb alc880_threestack_ch6_init[] = { /* set line-in to output, unmute it */ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -2362,12 +2639,12 @@ static struct hda_verb alc880_threestack_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc880_threestack_modes[2] = { +static const struct hda_channel_mode alc880_threestack_modes[2] = { { 2, alc880_threestack_ch2_init }, { 6, alc880_threestack_ch6_init }, }; -static struct snd_kcontrol_new alc880_three_stack_mixer[] = { +static const struct snd_kcontrol_new alc880_three_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), @@ -2512,14 +2789,14 @@ static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, } #define DEFINE_CAPMIX(num) \ -static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ +static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ _DEFINE_CAPMIX(num), \ _DEFINE_CAPSRC(num), \ { } /* end */ \ } #define DEFINE_CAPMIX_NOSRC(num) \ -static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ +static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ _DEFINE_CAPMIX(num), \ { } /* end */ \ } @@ -2542,7 +2819,7 @@ DEFINE_CAPMIX_NOSRC(3); */ /* additional mixers to alc880_three_stack_mixer */ -static struct snd_kcontrol_new alc880_five_stack_mixer[] = { +static const struct snd_kcontrol_new alc880_five_stack_mixer[] = { HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), { } /* end */ @@ -2550,7 +2827,7 @@ static struct snd_kcontrol_new alc880_five_stack_mixer[] = { /* channel source setting (6/8 channel selection for 5-stack) */ /* 6ch mode */ -static struct hda_verb alc880_fivestack_ch6_init[] = { +static const struct hda_verb alc880_fivestack_ch6_init[] = { /* set line-in to input, mute it */ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -2558,14 +2835,14 @@ static struct hda_verb alc880_fivestack_ch6_init[] = { }; /* 8ch mode */ -static struct hda_verb alc880_fivestack_ch8_init[] = { +static const struct hda_verb alc880_fivestack_ch8_init[] = { /* set line-in to output, unmute it */ { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { } /* end */ }; -static struct hda_channel_mode alc880_fivestack_modes[2] = { +static const struct hda_channel_mode alc880_fivestack_modes[2] = { { 6, alc880_fivestack_ch6_init }, { 8, alc880_fivestack_ch8_init }, }; @@ -2580,12 +2857,12 @@ static struct hda_channel_mode alc880_fivestack_modes[2] = { * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b */ -static hda_nid_t alc880_6st_dac_nids[4] = { +static const hda_nid_t alc880_6st_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x03, 0x04, 0x05 }; -static struct hda_input_mux alc880_6stack_capture_source = { +static const struct hda_input_mux alc880_6stack_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -2596,11 +2873,11 @@ static struct hda_input_mux alc880_6stack_capture_source = { }; /* fixed 8-channels */ -static struct hda_channel_mode alc880_sixstack_modes[1] = { +static const struct hda_channel_mode alc880_sixstack_modes[1] = { { 8, NULL }, }; -static struct snd_kcontrol_new alc880_six_stack_mixer[] = { +static const struct snd_kcontrol_new alc880_six_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2655,18 +2932,18 @@ static struct snd_kcontrol_new alc880_six_stack_mixer[] = { * haven't setup any initialization verbs for these yet... */ -static hda_nid_t alc880_w810_dac_nids[3] = { +static const hda_nid_t alc880_w810_dac_nids[3] = { /* front, rear/surround, clfe */ 0x02, 0x03, 0x04 }; /* fixed 6 channels */ -static struct hda_channel_mode alc880_w810_modes[1] = { +static const struct hda_channel_mode alc880_w810_modes[1] = { { 6, NULL } }; /* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ -static struct snd_kcontrol_new alc880_w810_base_mixer[] = { +static const struct snd_kcontrol_new alc880_w810_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2688,17 +2965,17 @@ static struct snd_kcontrol_new alc880_w810_base_mixer[] = { * Line = 0x1a */ -static hda_nid_t alc880_z71v_dac_nids[1] = { +static const hda_nid_t alc880_z71v_dac_nids[1] = { 0x02 }; #define ALC880_Z71V_HP_DAC 0x03 /* fixed 2 channels */ -static struct hda_channel_mode alc880_2_jack_modes[1] = { +static const struct hda_channel_mode alc880_2_jack_modes[1] = { { 2, NULL } }; -static struct snd_kcontrol_new alc880_z71v_mixer[] = { +static const struct snd_kcontrol_new alc880_z71v_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2718,12 +2995,12 @@ static struct snd_kcontrol_new alc880_z71v_mixer[] = { * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 */ -static hda_nid_t alc880_f1734_dac_nids[1] = { +static const hda_nid_t alc880_f1734_dac_nids[1] = { 0x03 }; #define ALC880_F1734_HP_DAC 0x02 -static struct snd_kcontrol_new alc880_f1734_mixer[] = { +static const struct snd_kcontrol_new alc880_f1734_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2735,7 +3012,7 @@ static struct snd_kcontrol_new alc880_f1734_mixer[] = { { } /* end */ }; -static struct hda_input_mux alc880_f1734_capture_source = { +static const struct hda_input_mux alc880_f1734_capture_source = { .num_items = 2, .items = { { "Mic", 0x1 }, @@ -2755,7 +3032,7 @@ static struct hda_input_mux alc880_f1734_capture_source = { #define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ #define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ -static struct snd_kcontrol_new alc880_asus_mixer[] = { +static const struct snd_kcontrol_new alc880_asus_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2789,14 +3066,14 @@ static struct snd_kcontrol_new alc880_asus_mixer[] = { */ /* additional mixers to alc880_asus_mixer */ -static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { +static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), { } /* end */ }; /* TCL S700 */ -static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { +static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -2810,7 +3087,7 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { }; /* Uniwill */ -static struct snd_kcontrol_new alc880_uniwill_mixer[] = { +static const struct snd_kcontrol_new alc880_uniwill_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2837,7 +3114,7 @@ static struct snd_kcontrol_new alc880_uniwill_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { +static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2851,7 +3128,7 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { +static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -2878,7 +3155,6 @@ static const char * const alc_slave_vols[] = { "Speaker Playback Volume", "Mono Playback Volume", "Line-Out Playback Volume", - "PCM Playback Volume", NULL, }; @@ -2893,7 +3169,6 @@ static const char * const alc_slave_sws[] = { "Mono Playback Switch", "IEC958 Playback Switch", "Line-Out Playback Switch", - "PCM Playback Switch", NULL, }; @@ -2914,7 +3189,7 @@ static void alc_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ -static struct snd_kcontrol_new alc_beep_mixer[] = { +static const struct snd_kcontrol_new alc_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), { } /* end */ @@ -2925,7 +3200,7 @@ static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct snd_kcontrol *kctl = NULL; - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; int i, j, err; unsigned int u; hda_nid_t nid; @@ -2962,7 +3237,7 @@ static int alc_build_controls(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_INPUT_BEEP /* create beep controls if needed */ if (spec->beep_amp) { - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; for (knew = alc_beep_mixer; knew->name; knew++) { struct snd_kcontrol *kctl; kctl = snd_ctl_new1(knew, codec); @@ -3001,7 +3276,7 @@ static int alc_build_controls(struct hda_codec *codec) if (!kctl) kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); for (i = 0; kctl && i < kctl->count; i++) { - hda_nid_t *nids = spec->capsrc_nids; + const hda_nid_t *nids = spec->capsrc_nids; if (!nids) nids = spec->adc_nids; err = snd_hda_add_nid(codec, kctl, i, nids[i]); @@ -3079,7 +3354,7 @@ static int alc_build_controls(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc880_volume_init_verbs[] = { +static const struct hda_verb alc880_volume_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -3130,7 +3405,7 @@ static struct hda_verb alc880_volume_init_verbs[] = { * 3-stack pin configuration: * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b */ -static struct hda_verb alc880_pin_3stack_init_verbs[] = { +static const struct hda_verb alc880_pin_3stack_init_verbs[] = { /* * preset connection lists of input pins * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround @@ -3168,7 +3443,7 @@ static struct hda_verb alc880_pin_3stack_init_verbs[] = { * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, * line-in/side = 0x1a, f-mic = 0x1b */ -static struct hda_verb alc880_pin_5stack_init_verbs[] = { +static const struct hda_verb alc880_pin_5stack_init_verbs[] = { /* * preset connection lists of input pins * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround @@ -3212,7 +3487,7 @@ static struct hda_verb alc880_pin_5stack_init_verbs[] = { * W810 pin configuration: * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b */ -static struct hda_verb alc880_pin_w810_init_verbs[] = { +static const struct hda_verb alc880_pin_w810_init_verbs[] = { /* hphone/speaker input selector: front DAC */ {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, @@ -3233,7 +3508,7 @@ static struct hda_verb alc880_pin_w810_init_verbs[] = { * Z71V pin configuration: * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) */ -static struct hda_verb alc880_pin_z71v_init_verbs[] = { +static const struct hda_verb alc880_pin_z71v_init_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -3252,7 +3527,7 @@ static struct hda_verb alc880_pin_z71v_init_verbs[] = { * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, * f-mic = 0x19, line = 0x1a, HP = 0x1b */ -static struct hda_verb alc880_pin_6stack_init_verbs[] = { +static const struct hda_verb alc880_pin_6stack_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -3282,7 +3557,7 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = { * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, * line = 0x1a */ -static struct hda_verb alc880_uniwill_init_verbs[] = { +static const struct hda_verb alc880_uniwill_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -3320,7 +3595,7 @@ static struct hda_verb alc880_uniwill_init_verbs[] = { * Uniwill P53 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, */ -static struct hda_verb alc880_uniwill_p53_init_verbs[] = { +static const struct hda_verb alc880_uniwill_p53_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -3349,7 +3624,7 @@ static struct hda_verb alc880_uniwill_p53_init_verbs[] = { { } }; -static struct hda_verb alc880_beep_init_verbs[] = { +static const struct hda_verb alc880_beep_init_verbs[] = { { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, { } }; @@ -3372,11 +3647,13 @@ static void alc880_uniwill_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc880_uniwill_init_hook(struct hda_codec *codec) { - alc_automute_amp(codec); + alc_hp_automute(codec); alc88x_simple_mic_automute(codec); } @@ -3391,7 +3668,7 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, alc88x_simple_mic_automute(codec); break; default: - alc_automute_amp_unsol_event(codec, res); + alc_sku_unsol_event(codec, res); break; } } @@ -3402,6 +3679,8 @@ static void alc880_uniwill_p53_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -3426,14 +3705,14 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, if ((res >> 28) == ALC880_DCVOL_EVENT) alc880_uniwill_p53_dcvol_automute(codec); else - alc_automute_amp_unsol_event(codec, res); + alc_sku_unsol_event(codec, res); } /* * F1734 pin configuration: * HP = 0x14, speaker-out = 0x15, mic = 0x18 */ -static struct hda_verb alc880_pin_f1734_init_verbs[] = { +static const struct hda_verb alc880_pin_f1734_init_verbs[] = { {0x07, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -3465,7 +3744,7 @@ static struct hda_verb alc880_pin_f1734_init_verbs[] = { * ASUS pin configuration: * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a */ -static struct hda_verb alc880_pin_asus_init_verbs[] = { +static const struct hda_verb alc880_pin_asus_init_verbs[] = { {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, @@ -3499,7 +3778,7 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = { #define alc880_gpio3_init_verbs alc_gpio3_init_verbs /* Clevo m520g init */ -static struct hda_verb alc880_pin_clevo_init_verbs[] = { +static const struct hda_verb alc880_pin_clevo_init_verbs[] = { /* headphone output */ {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line-out */ @@ -3527,7 +3806,7 @@ static struct hda_verb alc880_pin_clevo_init_verbs[] = { { } }; -static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { +static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { /* change to EAPD mode */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, @@ -3565,12 +3844,12 @@ static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { */ /* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ -static hda_nid_t alc880_lg_dac_nids[3] = { +static const hda_nid_t alc880_lg_dac_nids[3] = { 0x05, 0x02, 0x03 }; /* seems analog CD is not working */ -static struct hda_input_mux alc880_lg_capture_source = { +static const struct hda_input_mux alc880_lg_capture_source = { .num_items = 3, .items = { { "Mic", 0x1 }, @@ -3580,34 +3859,34 @@ static struct hda_input_mux alc880_lg_capture_source = { }; /* 2,4,6 channel modes */ -static struct hda_verb alc880_lg_ch2_init[] = { +static const struct hda_verb alc880_lg_ch2_init[] = { /* set line-in and mic-in to input */ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { } }; -static struct hda_verb alc880_lg_ch4_init[] = { +static const struct hda_verb alc880_lg_ch4_init[] = { /* set line-in to out and mic-in to input */ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { } }; -static struct hda_verb alc880_lg_ch6_init[] = { +static const struct hda_verb alc880_lg_ch6_init[] = { /* set line-in and mic-in to output */ { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { } }; -static struct hda_channel_mode alc880_lg_ch_modes[3] = { +static const struct hda_channel_mode alc880_lg_ch_modes[3] = { { 2, alc880_lg_ch2_init }, { 4, alc880_lg_ch4_init }, { 6, alc880_lg_ch6_init }, }; -static struct snd_kcontrol_new alc880_lg_mixer[] = { +static const struct snd_kcontrol_new alc880_lg_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), @@ -3632,7 +3911,7 @@ static struct snd_kcontrol_new alc880_lg_mixer[] = { { } /* end */ }; -static struct hda_verb alc880_lg_init_verbs[] = { +static const struct hda_verb alc880_lg_init_verbs[] = { /* set capture source to mic-in */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -3670,6 +3949,8 @@ static void alc880_lg_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* @@ -3684,7 +3965,7 @@ static void alc880_lg_setup(struct hda_codec *codec) * SPDIF-Out: 0x1e */ -static struct hda_input_mux alc880_lg_lw_capture_source = { +static const struct hda_input_mux alc880_lg_lw_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -3695,7 +3976,7 @@ static struct hda_input_mux alc880_lg_lw_capture_source = { #define alc880_lg_lw_modes alc880_threestack_modes -static struct snd_kcontrol_new alc880_lg_lw_mixer[] = { +static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), @@ -3720,7 +4001,7 @@ static struct snd_kcontrol_new alc880_lg_lw_mixer[] = { { } /* end */ }; -static struct hda_verb alc880_lg_lw_init_verbs[] = { +static const struct hda_verb alc880_lg_lw_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ @@ -3754,9 +4035,11 @@ static void alc880_lg_lw_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { +static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -3766,7 +4049,7 @@ static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { { } /* end */ }; -static struct hda_input_mux alc880_medion_rim_capture_source = { +static const struct hda_input_mux alc880_medion_rim_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -3774,7 +4057,7 @@ static struct hda_input_mux alc880_medion_rim_capture_source = { }, }; -static struct hda_verb alc880_medion_rim_init_verbs[] = { +static const struct hda_verb alc880_medion_rim_init_verbs[] = { {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -3801,7 +4084,7 @@ static struct hda_verb alc880_medion_rim_init_verbs[] = { static void alc880_medion_rim_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - alc_automute_amp(codec); + alc_hp_automute(codec); /* toggle EAPD */ if (spec->jack_present) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); @@ -3825,10 +4108,12 @@ static void alc880_medion_rim_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list alc880_loopbacks[] = { +static const struct hda_amp_list alc880_loopbacks[] = { { 0x0b, HDA_INPUT, 0 }, { 0x0b, HDA_INPUT, 1 }, { 0x0b, HDA_INPUT, 2 }, @@ -3837,7 +4122,7 @@ static struct hda_amp_list alc880_loopbacks[] = { { } /* end */ }; -static struct hda_amp_list alc880_lg_loopbacks[] = { +static const struct hda_amp_list alc880_lg_loopbacks[] = { { 0x0b, HDA_INPUT, 1 }, { 0x0b, HDA_INPUT, 6 }, { 0x0b, HDA_INPUT, 7 }, @@ -4009,7 +4294,7 @@ static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream dualmic_pcm_analog_capture = { +static const struct hda_pcm_stream dualmic_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -4022,7 +4307,7 @@ static struct hda_pcm_stream dualmic_pcm_analog_capture = { /* */ -static struct hda_pcm_stream alc880_pcm_analog_playback = { +static const struct hda_pcm_stream alc880_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -4034,21 +4319,21 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = { }, }; -static struct hda_pcm_stream alc880_pcm_analog_capture = { +static const struct hda_pcm_stream alc880_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in alc_build_pcms */ }; -static struct hda_pcm_stream alc880_pcm_analog_alt_playback = { +static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in alc_build_pcms */ }; -static struct hda_pcm_stream alc880_pcm_analog_alt_capture = { +static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = { .substreams = 2, /* can be overridden */ .channels_min = 2, .channels_max = 2, @@ -4059,7 +4344,7 @@ static struct hda_pcm_stream alc880_pcm_analog_alt_capture = { }, }; -static struct hda_pcm_stream alc880_pcm_digital_playback = { +static const struct hda_pcm_stream alc880_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -4072,7 +4357,7 @@ static struct hda_pcm_stream alc880_pcm_digital_playback = { }, }; -static struct hda_pcm_stream alc880_pcm_digital_capture = { +static const struct hda_pcm_stream alc880_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -4080,7 +4365,7 @@ static struct hda_pcm_stream alc880_pcm_digital_capture = { }; /* Used by alc_build_pcms to flag that a PCM has no playback stream */ -static struct hda_pcm_stream alc_pcm_null_stream = { +static const struct hda_pcm_stream alc_pcm_null_stream = { .substreams = 0, .channels_min = 0, .channels_max = 0, @@ -4174,7 +4459,7 @@ static int alc_build_pcms(struct hda_codec *codec) alc_pcm_null_stream; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; } - if (spec->num_adc_nids > 1) { + if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) { info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->stream_analog_alt_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = @@ -4193,6 +4478,10 @@ static int alc_build_pcms(struct hda_codec *codec) static inline void alc_shutup(struct hda_codec *codec) { + struct alc_spec *spec = codec->spec; + + if (spec && spec->shutup) + spec->shutup(codec); snd_hda_shutup_pins(codec); } @@ -4226,28 +4515,7 @@ static void alc_free(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE static void alc_power_eapd(struct hda_codec *codec) { - /* We currently only handle front, HP */ - switch (codec->vendor_id) { - case 0x10ec0260: - set_eapd(codec, 0x0f, 0); - set_eapd(codec, 0x10, 0); - break; - case 0x10ec0262: - case 0x10ec0267: - case 0x10ec0268: - case 0x10ec0269: - case 0x10ec0270: - case 0x10ec0272: - case 0x10ec0660: - case 0x10ec0662: - case 0x10ec0663: - case 0x10ec0665: - case 0x10ec0862: - case 0x10ec0889: - set_eapd(codec, 0x14, 0); - set_eapd(codec, 0x15, 0); - break; - } + alc_auto_setup_eapd(codec, false); } static int alc_suspend(struct hda_codec *codec, pm_message_t state) @@ -4263,6 +4531,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state) #ifdef SND_HDA_NEEDS_RESUME static int alc_resume(struct hda_codec *codec) { + msleep(150); /* to avoid pop noise */ codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); @@ -4273,7 +4542,7 @@ static int alc_resume(struct hda_codec *codec) /* */ -static struct hda_codec_ops alc_patch_ops = { +static const struct hda_codec_ops alc_patch_ops = { .build_controls = alc_build_controls, .build_pcms = alc_build_pcms, .init = alc_init, @@ -4308,11 +4577,11 @@ static int alc_codec_rename(struct hda_codec *codec, const char *name) * enum controls. */ #ifdef CONFIG_SND_DEBUG -static hda_nid_t alc880_test_dac_nids[4] = { +static const hda_nid_t alc880_test_dac_nids[4] = { 0x02, 0x03, 0x04, 0x05 }; -static struct hda_input_mux alc880_test_capture_source = { +static const struct hda_input_mux alc880_test_capture_source = { .num_items = 7, .items = { { "In-1", 0x0 }, @@ -4325,7 +4594,7 @@ static struct hda_input_mux alc880_test_capture_source = { }, }; -static struct hda_channel_mode alc880_test_modes[4] = { +static const struct hda_channel_mode alc880_test_modes[4] = { { 2, NULL }, { 4, NULL }, { 6, NULL }, @@ -4335,7 +4604,7 @@ static struct hda_channel_mode alc880_test_modes[4] = { static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "N/A", "Line Out", "HP Out", "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" }; @@ -4380,7 +4649,7 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - static unsigned int ctls[] = { + static const unsigned int ctls[] = { 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, @@ -4410,7 +4679,7 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "Front", "Surround", "CLFE", "Side" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -4471,7 +4740,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, .private_value = nid \ } -static struct snd_kcontrol_new alc880_test_mixer[] = { +static const struct snd_kcontrol_new alc880_test_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), @@ -4512,7 +4781,7 @@ static struct snd_kcontrol_new alc880_test_mixer[] = { { } /* end */ }; -static struct hda_verb alc880_test_init_verbs[] = { +static const struct hda_verb alc880_test_init_verbs[] = { /* Unmute inputs of 0x0c - 0x0f */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -4596,7 +4865,7 @@ static const char * const alc880_models[ALC880_MODEL_LAST] = { [ALC880_AUTO] = "auto", }; -static struct snd_pci_quirk alc880_cfg_tbl[] = { +static const struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), @@ -4676,7 +4945,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { /* * ALC880 codec presets */ -static struct alc_config_preset alc880_presets[] = { +static const struct alc_config_preset alc880_presets[] = { [ALC880_3ST] = { .mixers = { alc880_three_stack_mixer }, .init_verbs = { alc880_volume_init_verbs, @@ -4794,7 +5063,7 @@ static struct alc_config_preset alc880_presets[] = { .input_mux = &alc880_f1734_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, .setup = alc880_uniwill_p53_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC880_ASUS] = { .mixers = { alc880_asus_mixer }, @@ -4885,7 +5154,7 @@ static struct alc_config_preset alc880_presets[] = { .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, .setup = alc880_uniwill_p53_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC880_FUJITSU] = { .mixers = { alc880_fujitsu_mixer }, @@ -4900,7 +5169,7 @@ static struct alc_config_preset alc880_presets[] = { .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, .setup = alc880_uniwill_p53_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC880_CLEVO] = { .mixers = { alc880_three_stack_mixer }, @@ -4925,9 +5194,9 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_lg_ch_modes, .need_dac_fix = 1, .input_mux = &alc880_lg_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc880_lg_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, #ifdef CONFIG_SND_HDA_POWER_SAVE .loopbacks = alc880_lg_loopbacks, #endif @@ -4942,9 +5211,9 @@ static struct alc_config_preset alc880_presets[] = { .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), .channel_mode = alc880_lg_lw_modes, .input_mux = &alc880_lg_lw_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc880_lg_lw_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC880_MEDION_RIM] = { .mixers = { alc880_medion_rim_mixer }, @@ -4984,20 +5253,25 @@ enum { ALC_CTL_WIDGET_MUTE, ALC_CTL_BIND_MUTE, }; -static struct snd_kcontrol_new alc880_control_templates[] = { +static const struct snd_kcontrol_new alc880_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), HDA_BIND_MUTE(NULL, 0, 0, 0), }; +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec) +{ + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); + return snd_array_new(&spec->kctls); +} + /* add dynamic controls */ static int add_control(struct alc_spec *spec, int type, const char *name, int cidx, unsigned long val) { struct snd_kcontrol_new *knew; - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); + knew = alc_kcontrol_new(spec); if (!knew) return -ENOMEM; *knew = alc880_control_templates[type]; @@ -5055,7 +5329,7 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, nid = cfg->line_out_pins[i]; if (alc880_is_fixed_pin(nid)) { int idx = alc880_fixed_pin_idx(nid); - spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx); + spec->private_dac_nids[i] = alc880_idx_to_dac(idx); assigned[idx] = 1; } } @@ -5067,7 +5341,7 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, /* search for an empty channel */ for (j = 0; j < cfg->line_outs; j++) { if (!assigned[j]) { - spec->multiout.dac_nids[i] = + spec->private_dac_nids[i] = alc880_idx_to_dac(j); assigned[j] = 1; break; @@ -5078,10 +5352,13 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, return 0; } -static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg, +static const char *alc_get_line_out_pfx(struct alc_spec *spec, bool can_be_master) { - if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master) + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (cfg->line_outs == 1 && !spec->multi_ios && + !cfg->hp_outs && !cfg->speaker_outs && can_be_master) return "Master"; switch (cfg->line_out_type) { @@ -5092,7 +5369,7 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg, case AUTO_PIN_HP_OUT: return "Headphone"; default: - if (cfg->line_outs == 1) + if (cfg->line_outs == 1 && !spec->multi_ios) return "PCM"; break; } @@ -5106,11 +5383,15 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; - const char *pfx = alc_get_line_out_pfx(cfg, false); + const char *pfx = alc_get_line_out_pfx(spec, false); hda_nid_t nid; - int i, err; + int i, err, noutputs; - for (i = 0; i < cfg->line_outs; i++) { + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { if (!spec->multiout.dac_nids[i]) continue; nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); @@ -5376,6 +5657,8 @@ static void alc880_auto_init_input_src(struct hda_codec *codec) } } +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec); + /* parse the BIOS configuration and set up the alc_spec */ /* return 1 if successful, 0 if the proper config is not found, * or a negative error code @@ -5384,7 +5667,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc880_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc880_ignore); @@ -5396,6 +5679,9 @@ static int alc880_parse_auto_config(struct hda_codec *codec) err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; @@ -5467,6 +5753,12 @@ static void fixup_automic_adc(struct hda_codec *codec) spec->capsrc_nids += i; spec->adc_nids += i; spec->num_adc_nids = 1; + /* optional dock-mic */ + eidx = get_connection_index(codec, cap, spec->dock_mic.pin); + if (eidx < 0) + spec->dock_mic.pin = 0; + else + spec->dock_mic.mux_idx = eidx; return; } snd_printd(KERN_INFO "hda_codec: %s: " @@ -5494,6 +5786,8 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) struct alc_spec *spec = codec->spec; int i; + if (!pin) + return 0; for (i = 0; i < spec->num_adc_nids; i++) { hda_nid_t cap = spec->capsrc_nids ? spec->capsrc_nids[i] : spec->adc_nids[i]; @@ -5534,6 +5828,7 @@ static void fixup_dual_adc_switch(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; init_capsrc_for_pin(codec, spec->ext_mic.pin); + init_capsrc_for_pin(codec, spec->dock_mic.pin); init_capsrc_for_pin(codec, spec->int_mic.pin); } @@ -5550,7 +5845,7 @@ static void alc_init_special_input_src(struct hda_codec *codec) static void set_capture_mixer(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - static struct snd_kcontrol_new *caps[2][3] = { + static const struct snd_kcontrol_new *caps[2][3] = { { alc_capture_mixer_nosrc1, alc_capture_mixer_nosrc2, alc_capture_mixer_nosrc3 }, @@ -5576,7 +5871,7 @@ static void set_capture_mixer(struct hda_codec *codec) } /* fill adc_nids (and capsrc_nids) containing all active input pins */ -static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, +static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids, int num_nids) { struct alc_spec *spec = codec->spec; @@ -5642,9 +5937,11 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, #define set_beep_amp(spec, nid, idx, dir) \ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) -static struct snd_pci_quirk beep_white_list[] = { +static const struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), {} }; @@ -5752,17 +6049,17 @@ static int patch_alc880(struct hda_codec *codec) * ALC260 support */ -static hda_nid_t alc260_dac_nids[1] = { +static const hda_nid_t alc260_dac_nids[1] = { /* front */ 0x02, }; -static hda_nid_t alc260_adc_nids[1] = { +static const hda_nid_t alc260_adc_nids[1] = { /* ADC0 */ 0x04, }; -static hda_nid_t alc260_adc_nids_alt[1] = { +static const hda_nid_t alc260_adc_nids_alt[1] = { /* ADC1 */ 0x05, }; @@ -5770,7 +6067,7 @@ static hda_nid_t alc260_adc_nids_alt[1] = { /* NIDs used when simultaneous access to both ADCs makes sense. Note that * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. */ -static hda_nid_t alc260_dual_adc_nids[2] = { +static const hda_nid_t alc260_dual_adc_nids[2] = { /* ADC0, ADC1 */ 0x04, 0x05 }; @@ -5778,7 +6075,7 @@ static hda_nid_t alc260_dual_adc_nids[2] = { #define ALC260_DIGOUT_NID 0x03 #define ALC260_DIGIN_NID 0x06 -static struct hda_input_mux alc260_capture_source = { +static const struct hda_input_mux alc260_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -5794,7 +6091,7 @@ static struct hda_input_mux alc260_capture_source = { * recording the mixer output on the second ADC (ADC0 doesn't have a * connection to the mixer output). */ -static struct hda_input_mux alc260_fujitsu_capture_sources[2] = { +static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = { { .num_items = 3, .items = { @@ -5818,7 +6115,7 @@ static struct hda_input_mux alc260_fujitsu_capture_sources[2] = { /* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to * the Fujitsu S702x, but jacks are marked differently. */ -static struct hda_input_mux alc260_acer_capture_sources[2] = { +static const struct hda_input_mux alc260_acer_capture_sources[2] = { { .num_items = 4, .items = { @@ -5841,7 +6138,7 @@ static struct hda_input_mux alc260_acer_capture_sources[2] = { }; /* Maxdata Favorit 100XS */ -static struct hda_input_mux alc260_favorit100_capture_sources[2] = { +static const struct hda_input_mux alc260_favorit100_capture_sources[2] = { { .num_items = 2, .items = { @@ -5865,7 +6162,7 @@ static struct hda_input_mux alc260_favorit100_capture_sources[2] = { * element which allows changing the channel mode, so the verb list is * never used. */ -static struct hda_channel_mode alc260_modes[1] = { +static const struct hda_channel_mode alc260_modes[1] = { { 2, NULL }, }; @@ -5879,7 +6176,7 @@ static struct hda_channel_mode alc260_modes[1] = { * acer: acer + capture */ -static struct snd_kcontrol_new alc260_base_output_mixer[] = { +static const struct snd_kcontrol_new alc260_base_output_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), @@ -5889,7 +6186,7 @@ static struct snd_kcontrol_new alc260_base_output_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc260_input_mixer[] = { +static const struct snd_kcontrol_new alc260_input_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), @@ -5902,21 +6199,14 @@ static struct snd_kcontrol_new alc260_input_mixer[] = { }; /* update HP, line and mono out pins according to the master switch */ -static void alc260_hp_master_update(struct hda_codec *codec, - hda_nid_t hp, hda_nid_t line, - hda_nid_t mono) +static void alc260_hp_master_update(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int val = spec->master_sw ? PIN_HP : 0; - /* change HP and line-out pins */ - snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - val); - snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - val); - /* mono (speaker) depending on the HP jack sense */ - val = (val && !spec->jack_present) ? PIN_OUT : 0; - snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - val); + + /* change HP pins */ + do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), + spec->autocfg.hp_pins, spec->master_mute, true); + update_speakers(codec); } static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, @@ -5924,7 +6214,7 @@ static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - *ucontrol->value.integer.value = spec->master_sw; + *ucontrol->value.integer.value = !spec->master_mute; return 0; } @@ -5933,20 +6223,16 @@ static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - int val = !!*ucontrol->value.integer.value; - hda_nid_t hp, line, mono; + int val = !*ucontrol->value.integer.value; - if (val == spec->master_sw) + if (val == spec->master_mute) return 0; - spec->master_sw = val; - hp = (kcontrol->private_value >> 16) & 0xff; - line = (kcontrol->private_value >> 8) & 0xff; - mono = kcontrol->private_value & 0xff; - alc260_hp_master_update(codec, hp, line, mono); + spec->master_mute = val; + alc260_hp_master_update(codec); return 1; } -static struct snd_kcontrol_new alc260_hp_output_mixer[] = { +static const struct snd_kcontrol_new alc260_hp_output_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -5954,7 +6240,6 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = { .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, - .private_value = (0x0f << 16) | (0x10 << 8) | 0x11 }, HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), @@ -5966,26 +6251,23 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = { { } /* end */ }; -static struct hda_verb alc260_hp_unsol_verbs[] = { +static const struct hda_verb alc260_hp_unsol_verbs[] = { {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {}, }; -static void alc260_hp_automute(struct hda_codec *codec) +static void alc260_hp_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->jack_present = snd_hda_jack_detect(codec, 0x10); - alc260_hp_master_update(codec, 0x0f, 0x10, 0x11); + spec->autocfg.hp_pins[0] = 0x0f; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } -static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc260_hp_automute(codec); -} - -static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { +static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -5993,7 +6275,6 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, - .private_value = (0x15 << 16) | (0x10 << 8) | 0x11 }, HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), @@ -6006,7 +6287,18 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc260_dc7600_bind_master_vol = { +static void alc260_hp_3013_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x10; + spec->autocfg.speaker_pins[1] = 0x11; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; +} + +static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT), @@ -6016,7 +6308,7 @@ static struct hda_bind_ctls alc260_dc7600_bind_master_vol = { }, }; -static struct hda_bind_ctls alc260_dc7600_bind_switch = { +static const struct hda_bind_ctls alc260_dc7600_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), @@ -6025,7 +6317,7 @@ static struct hda_bind_ctls alc260_dc7600_bind_switch = { }, }; -static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { +static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol), HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch), HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT), @@ -6033,49 +6325,27 @@ static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { { } /* end */ }; -static struct hda_verb alc260_hp_3013_unsol_verbs[] = { +static const struct hda_verb alc260_hp_3013_unsol_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {}, }; -static void alc260_hp_3013_automute(struct hda_codec *codec) +static void alc260_hp_3012_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->jack_present = snd_hda_jack_detect(codec, 0x15); - alc260_hp_master_update(codec, 0x15, 0x10, 0x11); -} - -static void alc260_hp_3013_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc260_hp_3013_automute(codec); -} - -static void alc260_hp_3012_automute(struct hda_codec *codec) -{ - unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT; - - snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); - snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); -} - -static void alc260_hp_3012_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc260_hp_3012_automute(codec); + spec->autocfg.hp_pins[0] = 0x10; + spec->autocfg.speaker_pins[0] = 0x0f; + spec->autocfg.speaker_pins[1] = 0x11; + spec->autocfg.speaker_pins[2] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } /* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. */ -static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { +static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT), @@ -6112,7 +6382,7 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { * controls for such models. On models without a "mono speaker" the control * won't do anything. */ -static struct snd_kcontrol_new alc260_acer_mixer[] = { +static const struct snd_kcontrol_new alc260_acer_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), @@ -6133,7 +6403,7 @@ static struct snd_kcontrol_new alc260_acer_mixer[] = { /* Maxdata Favorit 100XS: one output and one input (0x12) jack */ -static struct snd_kcontrol_new alc260_favorit100_mixer[] = { +static const struct snd_kcontrol_new alc260_favorit100_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), @@ -6146,7 +6416,7 @@ static struct snd_kcontrol_new alc260_favorit100_mixer[] = { /* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12, * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17. */ -static struct snd_kcontrol_new alc260_will_mixer[] = { +static const struct snd_kcontrol_new alc260_will_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), @@ -6163,7 +6433,7 @@ static struct snd_kcontrol_new alc260_will_mixer[] = { /* Replacer 672V ALC260 pin usage: Mic jack = 0x12, * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f. */ -static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { +static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), @@ -6180,7 +6450,7 @@ static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { /* * initialization verbs */ -static struct hda_verb alc260_init_verbs[] = { +static const struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ @@ -6244,7 +6514,7 @@ static struct hda_verb alc260_init_verbs[] = { }; #if 0 /* should be identical with alc260_init_verbs? */ -static struct hda_verb alc260_hp_init_verbs[] = { +static const struct hda_verb alc260_hp_init_verbs[] = { /* Headphone and output */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, /* mono output */ @@ -6294,7 +6564,7 @@ static struct hda_verb alc260_hp_init_verbs[] = { }; #endif -static struct hda_verb alc260_hp_3013_init_verbs[] = { +static const struct hda_verb alc260_hp_3013_init_verbs[] = { /* Line out and output */ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* mono output */ @@ -6347,7 +6617,7 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = { * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD * audio = 0x16, internal speaker = 0x10. */ -static struct hda_verb alc260_fujitsu_init_verbs[] = { +static const struct hda_verb alc260_fujitsu_init_verbs[] = { /* Disable all GPIOs */ {0x01, AC_VERB_SET_GPIO_MASK, 0}, /* Internal speaker is connected to headphone pin */ @@ -6429,7 +6699,7 @@ static struct hda_verb alc260_fujitsu_init_verbs[] = { /* Initialisation sequence for ALC260 as configured in Acer TravelMate and * similar laptops (adapted from Fujitsu init verbs). */ -static struct hda_verb alc260_acer_init_verbs[] = { +static const struct hda_verb alc260_acer_init_verbs[] = { /* On TravelMate laptops, GPIO 0 enables the internal speaker and * the headphone jack. Turn this on and rely on the standard mute * methods whenever the user wants to turn these outputs off. @@ -6517,7 +6787,7 @@ static struct hda_verb alc260_acer_init_verbs[] = { /* Initialisation sequence for Maxdata Favorit 100XS * (adapted from Acer init verbs). */ -static struct hda_verb alc260_favorit100_init_verbs[] = { +static const struct hda_verb alc260_favorit100_init_verbs[] = { /* GPIO 0 enables the output jack. * Turn this on and rely on the standard mute * methods whenever the user wants to turn these outputs off. @@ -6597,7 +6867,7 @@ static struct hda_verb alc260_favorit100_init_verbs[] = { { } }; -static struct hda_verb alc260_will_verbs[] = { +static const struct hda_verb alc260_will_verbs[] = { {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -6607,7 +6877,7 @@ static struct hda_verb alc260_will_verbs[] = { {} }; -static struct hda_verb alc260_replacer_672v_verbs[] = { +static const struct hda_verb alc260_replacer_672v_verbs[] = { {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, {0x1a, AC_VERB_SET_PROC_COEF, 0x3050}, @@ -6649,7 +6919,7 @@ static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, alc260_replacer_672v_automute(codec); } -static struct hda_verb alc260_hp_dc7600_verbs[] = { +static const struct hda_verb alc260_hp_dc7600_verbs[] = { {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -6667,17 +6937,17 @@ static struct hda_verb alc260_hp_dc7600_verbs[] = { * configuration. */ #ifdef CONFIG_SND_DEBUG -static hda_nid_t alc260_test_dac_nids[1] = { +static const hda_nid_t alc260_test_dac_nids[1] = { 0x02, }; -static hda_nid_t alc260_test_adc_nids[2] = { +static const hda_nid_t alc260_test_adc_nids[2] = { 0x04, 0x05, }; /* For testing the ALC260, each input MUX needs its own definition since * the signal assignments are different. This assumes that the first ADC * is NID 0x04. */ -static struct hda_input_mux alc260_test_capture_sources[2] = { +static const struct hda_input_mux alc260_test_capture_sources[2] = { { .num_items = 7, .items = { @@ -6704,7 +6974,7 @@ static struct hda_input_mux alc260_test_capture_sources[2] = { }, }, }; -static struct snd_kcontrol_new alc260_test_mixer[] = { +static const struct snd_kcontrol_new alc260_test_mixer[] = { /* Output driver widgets */ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), @@ -6768,7 +7038,7 @@ static struct snd_kcontrol_new alc260_test_mixer[] = { { } /* end */ }; -static struct hda_verb alc260_test_init_verbs[] = { +static const struct hda_verb alc260_test_init_verbs[] = { /* Enable all GPIOs as outputs with an initial value of 0 */ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, @@ -6906,7 +7176,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, spec->multiout.num_dacs = 1; spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.dac_nids[0] = 0x02; + spec->private_dac_nids[0] = 0x02; nid = cfg->line_out_pins[0]; if (nid) { @@ -7004,7 +7274,7 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc260_volume_init_verbs[] = { +static const struct hda_verb alc260_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -7049,7 +7319,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc260_ignore[] = { 0x17, 0 }; + static const hda_nid_t alc260_ignore[] = { 0x17, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc260_ignore); @@ -7094,7 +7364,7 @@ static void alc260_auto_init(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list alc260_loopbacks[] = { +static const struct hda_amp_list alc260_loopbacks[] = { { 0x07, HDA_INPUT, 0 }, { 0x07, HDA_INPUT, 1 }, { 0x07, HDA_INPUT, 2 }, @@ -7121,7 +7391,7 @@ static const struct alc_fixup alc260_fixups[] = { }, }; -static struct snd_pci_quirk alc260_fixup_tbl[] = { +static const struct snd_pci_quirk alc260_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), {} }; @@ -7145,7 +7415,7 @@ static const char * const alc260_models[ALC260_MODEL_LAST] = { [ALC260_AUTO] = "auto", }; -static struct snd_pci_quirk alc260_cfg_tbl[] = { +static const struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), @@ -7169,7 +7439,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { {} }; -static struct alc_config_preset alc260_presets[] = { +static const struct alc_config_preset alc260_presets[] = { [ALC260_BASIC] = { .mixers = { alc260_base_output_mixer, alc260_input_mixer }, @@ -7194,8 +7464,9 @@ static struct alc_config_preset alc260_presets[] = { .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, - .unsol_event = alc260_hp_unsol_event, - .init_hook = alc260_hp_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_setup, + .init_hook = alc_inithook, }, [ALC260_HP_DC7600] = { .mixers = { alc260_hp_dc7600_mixer, @@ -7209,8 +7480,9 @@ static struct alc_config_preset alc260_presets[] = { .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, - .unsol_event = alc260_hp_3012_unsol_event, - .init_hook = alc260_hp_3012_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3012_setup, + .init_hook = alc_inithook, }, [ALC260_HP_3013] = { .mixers = { alc260_hp_3013_mixer, @@ -7224,8 +7496,9 @@ static struct alc_config_preset alc260_presets[] = { .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, - .unsol_event = alc260_hp_3013_unsol_event, - .init_hook = alc260_hp_3013_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc260_hp_3013_setup, + .init_hook = alc_inithook, }, [ALC260_FUJITSU_S702X] = { .mixers = { alc260_fujitsu_mixer }, @@ -7383,6 +7656,7 @@ static int patch_alc260(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC260_AUTO) spec->init_hook = alc260_auto_init; + spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc260_loopbacks; @@ -7410,12 +7684,12 @@ static int patch_alc260(struct hda_codec *codec) #define ALC1200_DIGOUT_NID 0x10 -static struct hda_channel_mode alc882_ch_modes[1] = { +static const struct hda_channel_mode alc882_ch_modes[1] = { { 8, NULL } }; /* DACs */ -static hda_nid_t alc882_dac_nids[4] = { +static const hda_nid_t alc882_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x03, 0x04, 0x05 }; @@ -7425,20 +7699,20 @@ static hda_nid_t alc882_dac_nids[4] = { #define alc882_adc_nids alc880_adc_nids #define alc882_adc_nids_alt alc880_adc_nids_alt #define alc883_adc_nids alc882_adc_nids_alt -static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 }; -static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; +static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 }; +static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; #define alc889_adc_nids alc880_adc_nids -static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 }; -static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; +static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 }; +static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; #define alc883_capsrc_nids alc882_capsrc_nids_alt -static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; +static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; #define alc889_capsrc_nids alc882_capsrc_nids /* input MUX */ /* FIXME: should be a matrix-type input source selection */ -static struct hda_input_mux alc882_capture_source = { +static const struct hda_input_mux alc882_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -7450,7 +7724,7 @@ static struct hda_input_mux alc882_capture_source = { #define alc883_capture_source alc882_capture_source -static struct hda_input_mux alc889_capture_source = { +static const struct hda_input_mux alc889_capture_source = { .num_items = 3, .items = { { "Front Mic", 0x0 }, @@ -7459,7 +7733,7 @@ static struct hda_input_mux alc889_capture_source = { }, }; -static struct hda_input_mux mb5_capture_source = { +static const struct hda_input_mux mb5_capture_source = { .num_items = 3, .items = { { "Mic", 0x1 }, @@ -7468,7 +7742,7 @@ static struct hda_input_mux mb5_capture_source = { }, }; -static struct hda_input_mux macmini3_capture_source = { +static const struct hda_input_mux macmini3_capture_source = { .num_items = 2, .items = { { "Line", 0x2 }, @@ -7476,7 +7750,7 @@ static struct hda_input_mux macmini3_capture_source = { }, }; -static struct hda_input_mux alc883_3stack_6ch_intel = { +static const struct hda_input_mux alc883_3stack_6ch_intel = { .num_items = 4, .items = { { "Mic", 0x1 }, @@ -7486,7 +7760,7 @@ static struct hda_input_mux alc883_3stack_6ch_intel = { }, }; -static struct hda_input_mux alc883_lenovo_101e_capture_source = { +static const struct hda_input_mux alc883_lenovo_101e_capture_source = { .num_items = 2, .items = { { "Mic", 0x1 }, @@ -7494,7 +7768,7 @@ static struct hda_input_mux alc883_lenovo_101e_capture_source = { }, }; -static struct hda_input_mux alc883_lenovo_nb0763_capture_source = { +static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -7504,7 +7778,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = { }, }; -static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { +static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -7512,7 +7786,7 @@ static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { }, }; -static struct hda_input_mux alc883_lenovo_sky_capture_source = { +static const struct hda_input_mux alc883_lenovo_sky_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -7521,7 +7795,7 @@ static struct hda_input_mux alc883_lenovo_sky_capture_source = { }, }; -static struct hda_input_mux alc883_asus_eee1601_capture_source = { +static const struct hda_input_mux alc883_asus_eee1601_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -7529,7 +7803,7 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = { }, }; -static struct hda_input_mux alc889A_mb31_capture_source = { +static const struct hda_input_mux alc889A_mb31_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -7540,7 +7814,7 @@ static struct hda_input_mux alc889A_mb31_capture_source = { }, }; -static struct hda_input_mux alc889A_imac91_capture_source = { +static const struct hda_input_mux alc889A_imac91_capture_source = { .num_items = 2, .items = { { "Mic", 0x01 }, @@ -7551,14 +7825,14 @@ static struct hda_input_mux alc889A_imac91_capture_source = { /* * 2ch mode */ -static struct hda_channel_mode alc883_3ST_2ch_modes[1] = { +static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = { { 2, NULL } }; /* * 2ch mode */ -static struct hda_verb alc882_3ST_ch2_init[] = { +static const struct hda_verb alc882_3ST_ch2_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -7569,7 +7843,7 @@ static struct hda_verb alc882_3ST_ch2_init[] = { /* * 4ch mode */ -static struct hda_verb alc882_3ST_ch4_init[] = { +static const struct hda_verb alc882_3ST_ch4_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7581,7 +7855,7 @@ static struct hda_verb alc882_3ST_ch4_init[] = { /* * 6ch mode */ -static struct hda_verb alc882_3ST_ch6_init[] = { +static const struct hda_verb alc882_3ST_ch6_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -7591,7 +7865,7 @@ static struct hda_verb alc882_3ST_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc882_3ST_6ch_modes[3] = { +static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = { { 2, alc882_3ST_ch2_init }, { 4, alc882_3ST_ch4_init }, { 6, alc882_3ST_ch6_init }, @@ -7602,7 +7876,7 @@ static struct hda_channel_mode alc882_3ST_6ch_modes[3] = { /* * 2ch mode */ -static struct hda_verb alc883_3ST_ch2_clevo_init[] = { +static const struct hda_verb alc883_3ST_ch2_clevo_init[] = { { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -7614,7 +7888,7 @@ static struct hda_verb alc883_3ST_ch2_clevo_init[] = { /* * 4ch mode */ -static struct hda_verb alc883_3ST_ch4_clevo_init[] = { +static const struct hda_verb alc883_3ST_ch4_clevo_init[] = { { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, @@ -7627,7 +7901,7 @@ static struct hda_verb alc883_3ST_ch4_clevo_init[] = { /* * 6ch mode */ -static struct hda_verb alc883_3ST_ch6_clevo_init[] = { +static const struct hda_verb alc883_3ST_ch6_clevo_init[] = { { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -7638,7 +7912,7 @@ static struct hda_verb alc883_3ST_ch6_clevo_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { +static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { { 2, alc883_3ST_ch2_clevo_init }, { 4, alc883_3ST_ch4_clevo_init }, { 6, alc883_3ST_ch6_clevo_init }, @@ -7648,7 +7922,7 @@ static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { /* * 6ch mode */ -static struct hda_verb alc882_sixstack_ch6_init[] = { +static const struct hda_verb alc882_sixstack_ch6_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7659,7 +7933,7 @@ static struct hda_verb alc882_sixstack_ch6_init[] = { /* * 8ch mode */ -static struct hda_verb alc882_sixstack_ch8_init[] = { +static const struct hda_verb alc882_sixstack_ch8_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7667,7 +7941,7 @@ static struct hda_verb alc882_sixstack_ch8_init[] = { { } /* end */ }; -static struct hda_channel_mode alc882_sixstack_modes[2] = { +static const struct hda_channel_mode alc882_sixstack_modes[2] = { { 6, alc882_sixstack_ch6_init }, { 8, alc882_sixstack_ch8_init }, }; @@ -7675,7 +7949,7 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = { /* Macbook Air 2,1 */ -static struct hda_channel_mode alc885_mba21_ch_modes[1] = { +static const struct hda_channel_mode alc885_mba21_ch_modes[1] = { { 2, NULL }, }; @@ -7686,7 +7960,7 @@ static struct hda_channel_mode alc885_mba21_ch_modes[1] = { /* * 2ch mode */ -static struct hda_verb alc885_mbp_ch2_init[] = { +static const struct hda_verb alc885_mbp_ch2_init[] = { { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -7696,7 +7970,7 @@ static struct hda_verb alc885_mbp_ch2_init[] = { /* * 4ch mode */ -static struct hda_verb alc885_mbp_ch4_init[] = { +static const struct hda_verb alc885_mbp_ch4_init[] = { { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, @@ -7705,7 +7979,7 @@ static struct hda_verb alc885_mbp_ch4_init[] = { { } /* end */ }; -static struct hda_channel_mode alc885_mbp_4ch_modes[2] = { +static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = { { 2, alc885_mbp_ch2_init }, { 4, alc885_mbp_ch4_init }, }; @@ -7715,7 +7989,7 @@ static struct hda_channel_mode alc885_mbp_4ch_modes[2] = { * Speakers/Woofer/HP = Front * LineIn = Input */ -static struct hda_verb alc885_mb5_ch2_init[] = { +static const struct hda_verb alc885_mb5_ch2_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, { } /* end */ @@ -7727,14 +8001,14 @@ static struct hda_verb alc885_mb5_ch2_init[] = { * Woofer = LFE * LineIn = Surround */ -static struct hda_verb alc885_mb5_ch6_init[] = { +static const struct hda_verb alc885_mb5_ch6_init[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, { } /* end */ }; -static struct hda_channel_mode alc885_mb5_6ch_modes[2] = { +static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = { { 2, alc885_mb5_ch2_init }, { 6, alc885_mb5_ch6_init }, }; @@ -7744,7 +8018,7 @@ static struct hda_channel_mode alc885_mb5_6ch_modes[2] = { /* * 2ch mode */ -static struct hda_verb alc883_4ST_ch2_init[] = { +static const struct hda_verb alc883_4ST_ch2_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, @@ -7757,7 +8031,7 @@ static struct hda_verb alc883_4ST_ch2_init[] = { /* * 4ch mode */ -static struct hda_verb alc883_4ST_ch4_init[] = { +static const struct hda_verb alc883_4ST_ch4_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, @@ -7771,7 +8045,7 @@ static struct hda_verb alc883_4ST_ch4_init[] = { /* * 6ch mode */ -static struct hda_verb alc883_4ST_ch6_init[] = { +static const struct hda_verb alc883_4ST_ch6_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7786,7 +8060,7 @@ static struct hda_verb alc883_4ST_ch6_init[] = { /* * 8ch mode */ -static struct hda_verb alc883_4ST_ch8_init[] = { +static const struct hda_verb alc883_4ST_ch8_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, @@ -7799,7 +8073,7 @@ static struct hda_verb alc883_4ST_ch8_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_4ST_8ch_modes[4] = { +static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = { { 2, alc883_4ST_ch2_init }, { 4, alc883_4ST_ch4_init }, { 6, alc883_4ST_ch6_init }, @@ -7810,7 +8084,7 @@ static struct hda_channel_mode alc883_4ST_8ch_modes[4] = { /* * 2ch mode */ -static struct hda_verb alc883_3ST_ch2_intel_init[] = { +static const struct hda_verb alc883_3ST_ch2_intel_init[] = { { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -7821,7 +8095,7 @@ static struct hda_verb alc883_3ST_ch2_intel_init[] = { /* * 4ch mode */ -static struct hda_verb alc883_3ST_ch4_intel_init[] = { +static const struct hda_verb alc883_3ST_ch4_intel_init[] = { { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7833,7 +8107,7 @@ static struct hda_verb alc883_3ST_ch4_intel_init[] = { /* * 6ch mode */ -static struct hda_verb alc883_3ST_ch6_intel_init[] = { +static const struct hda_verb alc883_3ST_ch6_intel_init[] = { { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -7843,7 +8117,7 @@ static struct hda_verb alc883_3ST_ch6_intel_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { +static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { { 2, alc883_3ST_ch2_intel_init }, { 4, alc883_3ST_ch4_intel_init }, { 6, alc883_3ST_ch6_intel_init }, @@ -7852,7 +8126,7 @@ static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { /* * 2ch mode */ -static struct hda_verb alc889_ch2_intel_init[] = { +static const struct hda_verb alc889_ch2_intel_init[] = { { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 }, { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 }, @@ -7865,7 +8139,7 @@ static struct hda_verb alc889_ch2_intel_init[] = { /* * 6ch mode */ -static struct hda_verb alc889_ch6_intel_init[] = { +static const struct hda_verb alc889_ch6_intel_init[] = { { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -7878,7 +8152,7 @@ static struct hda_verb alc889_ch6_intel_init[] = { /* * 8ch mode */ -static struct hda_verb alc889_ch8_intel_init[] = { +static const struct hda_verb alc889_ch8_intel_init[] = { { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -7889,7 +8163,7 @@ static struct hda_verb alc889_ch8_intel_init[] = { { } /* end */ }; -static struct hda_channel_mode alc889_8ch_intel_modes[3] = { +static const struct hda_channel_mode alc889_8ch_intel_modes[3] = { { 2, alc889_ch2_intel_init }, { 6, alc889_ch6_intel_init }, { 8, alc889_ch8_intel_init }, @@ -7898,7 +8172,7 @@ static struct hda_channel_mode alc889_8ch_intel_modes[3] = { /* * 6ch mode */ -static struct hda_verb alc883_sixstack_ch6_init[] = { +static const struct hda_verb alc883_sixstack_ch6_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7909,7 +8183,7 @@ static struct hda_verb alc883_sixstack_ch6_init[] = { /* * 8ch mode */ -static struct hda_verb alc883_sixstack_ch8_init[] = { +static const struct hda_verb alc883_sixstack_ch8_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -7917,7 +8191,7 @@ static struct hda_verb alc883_sixstack_ch8_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_sixstack_modes[2] = { +static const struct hda_channel_mode alc883_sixstack_modes[2] = { { 6, alc883_sixstack_ch6_init }, { 8, alc883_sixstack_ch8_init }, }; @@ -7926,7 +8200,7 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = { /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ -static struct snd_kcontrol_new alc882_base_mixer[] = { +static const struct snd_kcontrol_new alc882_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -7953,14 +8227,14 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { /* Macbook Air 2,1 same control for HP and internal Speaker */ -static struct snd_kcontrol_new alc885_mba21_mixer[] = { +static const struct snd_kcontrol_new alc885_mba21_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT), { } }; -static struct snd_kcontrol_new alc885_mbp3_mixer[] = { +static const struct snd_kcontrol_new alc885_mbp3_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT), @@ -7975,7 +8249,7 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc885_mb5_mixer[] = { +static const struct snd_kcontrol_new alc885_mb5_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), @@ -7993,7 +8267,7 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc885_macmini3_mixer[] = { +static const struct snd_kcontrol_new alc885_macmini3_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), @@ -8008,14 +8282,14 @@ static struct snd_kcontrol_new alc885_macmini3_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc885_imac91_mixer[] = { +static const struct snd_kcontrol_new alc885_imac91_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), { } /* end */ }; -static struct snd_kcontrol_new alc882_w2jc_mixer[] = { +static const struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -8028,7 +8302,7 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc882_targa_mixer[] = { +static const struct snd_kcontrol_new alc882_targa_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -8048,7 +8322,7 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = { /* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ??? * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c */ -static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { +static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -8065,7 +8339,7 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { +static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -8079,7 +8353,7 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc882_chmode_mixer[] = { +static const struct snd_kcontrol_new alc882_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -8090,7 +8364,7 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = { { } /* end */ }; -static struct hda_verb alc882_base_init_verbs[] = { +static const struct hda_verb alc882_base_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -8152,7 +8426,7 @@ static struct hda_verb alc882_base_init_verbs[] = { { } }; -static struct hda_verb alc882_adc1_init_verbs[] = { +static const struct hda_verb alc882_adc1_init_verbs[] = { /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, @@ -8164,26 +8438,26 @@ static struct hda_verb alc882_adc1_init_verbs[] = { { } }; -static struct hda_verb alc882_eapd_verbs[] = { +static const struct hda_verb alc882_eapd_verbs[] = { /* change to EAPD mode */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, { } }; -static struct hda_verb alc889_eapd_verbs[] = { +static const struct hda_verb alc889_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc_hp15_unsol_verbs[] = { +static const struct hda_verb alc_hp15_unsol_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {} }; -static struct hda_verb alc885_init_verbs[] = { +static const struct hda_verb alc885_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -8242,7 +8516,7 @@ static struct hda_verb alc885_init_verbs[] = { { } }; -static struct hda_verb alc885_init_input_verbs[] = { +static const struct hda_verb alc885_init_input_verbs[] = { {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, @@ -8251,7 +8525,7 @@ static struct hda_verb alc885_init_input_verbs[] = { /* Unmute Selector 24h and set the default input to front mic */ -static struct hda_verb alc889_init_input_verbs[] = { +static const struct hda_verb alc889_init_input_verbs[] = { {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, { } @@ -8261,7 +8535,7 @@ static struct hda_verb alc889_init_input_verbs[] = { #define alc883_init_verbs alc882_base_init_verbs /* Mac Pro test */ -static struct snd_kcontrol_new alc882_macpro_mixer[] = { +static const struct snd_kcontrol_new alc882_macpro_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT), @@ -8274,7 +8548,7 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = { { } /* end */ }; -static struct hda_verb alc882_macpro_init_verbs[] = { +static const struct hda_verb alc882_macpro_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -8326,7 +8600,7 @@ static struct hda_verb alc882_macpro_init_verbs[] = { }; /* Macbook 5,1 */ -static struct hda_verb alc885_mb5_init_verbs[] = { +static const struct hda_verb alc885_mb5_init_verbs[] = { /* DACs */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -8375,7 +8649,7 @@ static struct hda_verb alc885_mb5_init_verbs[] = { }; /* Macmini 3,1 */ -static struct hda_verb alc885_macmini3_init_verbs[] = { +static const struct hda_verb alc885_macmini3_init_verbs[] = { /* DACs */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -8422,7 +8696,7 @@ static struct hda_verb alc885_macmini3_init_verbs[] = { }; -static struct hda_verb alc885_mba21_init_verbs[] = { +static const struct hda_verb alc885_mba21_init_verbs[] = { /*Internal and HP Speaker Mixer*/ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -8445,7 +8719,7 @@ static struct hda_verb alc885_mba21_init_verbs[] = { /* Macbook Pro rev3 */ -static struct hda_verb alc885_mbp3_init_verbs[] = { +static const struct hda_verb alc885_mbp3_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -8509,7 +8783,7 @@ static struct hda_verb alc885_mbp3_init_verbs[] = { }; /* iMac 9,1 */ -static struct hda_verb alc885_imac91_init_verbs[] = { +static const struct hda_verb alc885_imac91_init_verbs[] = { /* Internal Speaker Pin (0x0c) */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -8564,14 +8838,14 @@ static struct hda_verb alc885_imac91_init_verbs[] = { }; /* iMac 24 mixer. */ -static struct snd_kcontrol_new alc885_imac24_mixer[] = { +static const struct snd_kcontrol_new alc885_imac24_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT), { } /* end */ }; /* iMac 24 init verbs. */ -static struct hda_verb alc885_imac24_init_verbs[] = { +static const struct hda_verb alc885_imac24_init_verbs[] = { /* Internal speakers: output 0 (0x0c) */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -8599,6 +8873,8 @@ static void alc885_imac24_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; spec->autocfg.speaker_pins[1] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } #define alc885_mb5_setup alc885_imac24_setup @@ -8611,6 +8887,8 @@ static void alc885_mba21_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } @@ -8621,6 +8899,8 @@ static void alc885_mbp3_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc885_imac91_setup(struct hda_codec *codec) @@ -8630,9 +8910,11 @@ static void alc885_imac91_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; spec->autocfg.speaker_pins[1] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc882_targa_verbs[] = { +static const struct hda_verb alc882_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -8651,7 +8933,7 @@ static struct hda_verb alc882_targa_verbs[] = { static void alc882_targa_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - alc_automute_amp(codec); + alc_hp_automute(codec); snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, spec->jack_present ? 1 : 3); } @@ -8662,6 +8944,8 @@ static void alc882_targa_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) @@ -8670,7 +8954,7 @@ static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) alc882_targa_automute(codec); } -static struct hda_verb alc882_asus_a7j_verbs[] = { +static const struct hda_verb alc882_asus_a7j_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -8688,7 +8972,7 @@ static struct hda_verb alc882_asus_a7j_verbs[] = { { } /* end */ }; -static struct hda_verb alc882_asus_a7m_verbs[] = { +static const struct hda_verb alc882_asus_a7m_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -8749,13 +9033,13 @@ static void alc885_macpro_init_hook(struct hda_codec *codec) static void alc885_imac24_init_hook(struct hda_codec *codec) { alc885_macpro_init_hook(codec); - alc_automute_amp(codec); + alc_hp_automute(codec); } /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc883_auto_init_verbs[] = { +static const struct hda_verb alc883_auto_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -8795,7 +9079,7 @@ static struct hda_verb alc883_auto_init_verbs[] = { }; /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ -static struct hda_verb alc889A_mb31_ch2_init[] = { +static const struct hda_verb alc889A_mb31_ch2_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ @@ -8804,7 +9088,7 @@ static struct hda_verb alc889A_mb31_ch2_init[] = { }; /* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ -static struct hda_verb alc889A_mb31_ch4_init[] = { +static const struct hda_verb alc889A_mb31_ch4_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ @@ -8813,7 +9097,7 @@ static struct hda_verb alc889A_mb31_ch4_init[] = { }; /* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ -static struct hda_verb alc889A_mb31_ch5_init[] = { +static const struct hda_verb alc889A_mb31_ch5_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ @@ -8822,7 +9106,7 @@ static struct hda_verb alc889A_mb31_ch5_init[] = { }; /* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ -static struct hda_verb alc889A_mb31_ch6_init[] = { +static const struct hda_verb alc889A_mb31_ch6_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ @@ -8830,14 +9114,14 @@ static struct hda_verb alc889A_mb31_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { +static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { { 2, alc889A_mb31_ch2_init }, { 4, alc889A_mb31_ch4_init }, { 5, alc889A_mb31_ch5_init }, { 6, alc889A_mb31_ch6_init }, }; -static struct hda_verb alc883_medion_eapd_verbs[] = { +static const struct hda_verb alc883_medion_eapd_verbs[] = { /* eanable EAPD on medion laptop */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, @@ -8846,7 +9130,7 @@ static struct hda_verb alc883_medion_eapd_verbs[] = { #define alc883_base_mixer alc882_base_mixer -static struct snd_kcontrol_new alc883_mitac_mixer[] = { +static const struct snd_kcontrol_new alc883_mitac_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), @@ -8863,7 +9147,7 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { +static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8877,7 +9161,7 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { +static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8891,7 +9175,7 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { +static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -8908,7 +9192,7 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { +static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8931,7 +9215,7 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { +static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8955,7 +9239,7 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { +static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -8979,7 +9263,7 @@ static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_fivestack_mixer[] = { +static const struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -9002,7 +9286,7 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_targa_mixer[] = { +static const struct snd_kcontrol_new alc883_targa_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9023,7 +9307,7 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { +static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9039,7 +9323,7 @@ static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { +static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), @@ -9048,7 +9332,7 @@ static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { +static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -9060,7 +9344,7 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { +static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9073,7 +9357,7 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { +static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -9083,7 +9367,7 @@ static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = { { } /* end */ }; -static struct hda_verb alc883_medion_wim2160_verbs[] = { +static const struct hda_verb alc883_medion_wim2160_verbs[] = { /* Unmute front mixer */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -9107,9 +9391,11 @@ static void alc883_medion_wim2160_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1a; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { +static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9121,7 +9407,7 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { +static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -9134,7 +9420,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { +static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT), @@ -9159,7 +9445,7 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc889A_mb31_mixer[] = { +static const struct snd_kcontrol_new alc889A_mb31_mixer[] = { /* Output mixers */ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), @@ -9185,7 +9471,7 @@ static struct snd_kcontrol_new alc889A_mb31_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_vaiott_mixer[] = { +static const struct snd_kcontrol_new alc883_vaiott_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -9195,7 +9481,7 @@ static struct snd_kcontrol_new alc883_vaiott_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc883_bind_cap_vol = { +static const struct hda_bind_ctls alc883_bind_cap_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), @@ -9204,7 +9490,7 @@ static struct hda_bind_ctls alc883_bind_cap_vol = { }, }; -static struct hda_bind_ctls alc883_bind_cap_switch = { +static const struct hda_bind_ctls alc883_bind_cap_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), @@ -9213,7 +9499,7 @@ static struct hda_bind_ctls alc883_bind_cap_switch = { }, }; -static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { +static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -9225,7 +9511,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { +static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), { @@ -9240,7 +9526,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_chmode_mixer[] = { +static const struct snd_kcontrol_new alc883_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -9259,9 +9545,11 @@ static void alc883_mitac_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc883_mitac_verbs[] = { +static const struct hda_verb alc883_mitac_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9276,7 +9564,7 @@ static struct hda_verb alc883_mitac_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_clevo_m540r_verbs[] = { +static const struct hda_verb alc883_clevo_m540r_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9292,7 +9580,7 @@ static struct hda_verb alc883_clevo_m540r_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_clevo_m720_verbs[] = { +static const struct hda_verb alc883_clevo_m720_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9307,7 +9595,7 @@ static struct hda_verb alc883_clevo_m720_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { +static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { /* HP */ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9321,7 +9609,7 @@ static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_targa_verbs[] = { +static const struct hda_verb alc883_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -9350,14 +9638,14 @@ static struct hda_verb alc883_targa_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_lenovo_101e_verbs[] = { +static const struct hda_verb alc883_lenovo_101e_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN}, { } /* end */ }; -static struct hda_verb alc883_lenovo_nb0763_verbs[] = { +static const struct hda_verb alc883_lenovo_nb0763_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, @@ -9365,7 +9653,7 @@ static struct hda_verb alc883_lenovo_nb0763_verbs[] = { { } /* end */ }; -static struct hda_verb alc888_lenovo_ms7195_verbs[] = { +static const struct hda_verb alc888_lenovo_ms7195_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -9374,7 +9662,7 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_haier_w66_verbs[] = { +static const struct hda_verb alc883_haier_w66_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -9387,7 +9675,7 @@ static struct hda_verb alc883_haier_w66_verbs[] = { { } /* end */ }; -static struct hda_verb alc888_lenovo_sky_verbs[] = { +static const struct hda_verb alc888_lenovo_sky_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -9399,12 +9687,12 @@ static struct hda_verb alc888_lenovo_sky_verbs[] = { { } /* end */ }; -static struct hda_verb alc888_6st_dell_verbs[] = { +static const struct hda_verb alc888_6st_dell_verbs[] = { {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, { } }; -static struct hda_verb alc883_vaiott_verbs[] = { +static const struct hda_verb alc883_vaiott_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -9423,9 +9711,11 @@ static void alc888_3st_hp_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x18; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc888_3st_hp_verbs[] = { +static const struct hda_verb alc888_3st_hp_verbs[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */ {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */ @@ -9436,7 +9726,7 @@ static struct hda_verb alc888_3st_hp_verbs[] = { /* * 2ch mode */ -static struct hda_verb alc888_3st_hp_2ch_init[] = { +static const struct hda_verb alc888_3st_hp_2ch_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -9447,7 +9737,7 @@ static struct hda_verb alc888_3st_hp_2ch_init[] = { /* * 4ch mode */ -static struct hda_verb alc888_3st_hp_4ch_init[] = { +static const struct hda_verb alc888_3st_hp_4ch_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -9459,7 +9749,7 @@ static struct hda_verb alc888_3st_hp_4ch_init[] = { /* * 6ch mode */ -static struct hda_verb alc888_3st_hp_6ch_init[] = { +static const struct hda_verb alc888_3st_hp_6ch_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -9469,39 +9759,21 @@ static struct hda_verb alc888_3st_hp_6ch_init[] = { { } /* end */ }; -static struct hda_channel_mode alc888_3st_hp_modes[3] = { +static const struct hda_channel_mode alc888_3st_hp_modes[3] = { { 2, alc888_3st_hp_2ch_init }, { 4, alc888_3st_hp_4ch_init }, { 6, alc888_3st_hp_6ch_init }, }; -/* toggle front-jack and RCA according to the hp-jack state */ -static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec) -{ - unsigned int present = snd_hda_jack_detect(codec, 0x1b); - - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - -/* toggle RCA according to the front-jack state */ -static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec) +static void alc888_lenovo_ms7195_setup(struct hda_codec *codec) { - unsigned int present = snd_hda_jack_detect(codec, 0x14); - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} + struct alc_spec *spec = codec->spec; -static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc888_lenovo_ms7195_front_automute(codec); - if ((res >> 26) == ALC880_FRONT_EVENT) - alc888_lenovo_ms7195_rca_automute(codec); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* toggle speaker-output according to the hp-jack state */ @@ -9511,6 +9783,8 @@ static void alc883_lenovo_nb0763_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* toggle speaker-output according to the hp-jack state */ @@ -9523,11 +9797,13 @@ static void alc883_clevo_m720_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_clevo_m720_init_hook(struct hda_codec *codec) { - alc_automute_amp(codec); + alc_hp_automute(codec); alc88x_simple_mic_automute(codec); } @@ -9539,7 +9815,7 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, alc88x_simple_mic_automute(codec); break; default: - alc_automute_amp_unsol_event(codec, res); + alc_sku_unsol_event(codec, res); break; } } @@ -9551,6 +9827,8 @@ static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_haier_w66_setup(struct hda_codec *codec) @@ -9559,33 +9837,21 @@ static void alc883_haier_w66_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) +static void alc883_lenovo_101e_setup(struct hda_codec *codec) { - int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) -{ - int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} + struct alc_spec *spec = codec->spec; -static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc883_lenovo_101e_all_automute(codec); - if ((res >> 26) == ALC880_FRONT_EVENT) - alc883_lenovo_101e_ispeaker_automute(codec); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* toggle speaker-output according to the hp-jack state */ @@ -9596,9 +9862,11 @@ static void alc883_acer_aspire_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[1] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc883_acer_eapd_verbs[] = { +static const struct hda_verb alc883_acer_eapd_verbs[] = { /* HP Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -9625,6 +9893,8 @@ static void alc888_6st_dell_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[1] = 0x15; spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc888_lenovo_sky_setup(struct hda_codec *codec) @@ -9637,6 +9907,8 @@ static void alc888_lenovo_sky_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; spec->autocfg.speaker_pins[4] = 0x1a; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc883_vaiott_setup(struct hda_codec *codec) @@ -9646,9 +9918,11 @@ static void alc883_vaiott_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc888_asus_m90v_verbs[] = { +static const struct hda_verb alc888_asus_m90v_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -9671,9 +9945,11 @@ static void alc883_mode2_setup(struct hda_codec *codec) spec->ext_mic.mux_idx = 0; spec->int_mic.mux_idx = 1; spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct hda_verb alc888_asus_eee1601_verbs[] = { +static const struct hda_verb alc888_asus_eee1601_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -9692,10 +9968,10 @@ static void alc883_eee1601_inithook(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; - alc_automute_pin(codec); + alc_hp_automute(codec); } -static struct hda_verb alc889A_mb31_verbs[] = { +static const struct hda_verb alc889A_mb31_verbs[] = { /* Init rear pin (used as headphone output) */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ @@ -9741,11 +10017,11 @@ static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) #define alc882_pcm_digital_playback alc880_pcm_digital_playback #define alc882_pcm_digital_capture alc880_pcm_digital_capture -static hda_nid_t alc883_slave_dig_outs[] = { +static const hda_nid_t alc883_slave_dig_outs[] = { ALC1200_DIGOUT_NID, 0, }; -static hda_nid_t alc1200_slave_dig_outs[] = { +static const hda_nid_t alc1200_slave_dig_outs[] = { ALC883_DIGOUT_NID, 0, }; @@ -9804,7 +10080,7 @@ static const char * const alc882_models[ALC882_MODEL_LAST] = { [ALC882_AUTO] = "auto", }; -static struct snd_pci_quirk alc882_cfg_tbl[] = { +static const struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), @@ -9836,7 +10112,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), - SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), @@ -9931,7 +10207,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { }; /* codec SSID table for Intel Mac */ -static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { +static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3), @@ -9958,7 +10234,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { {} /* terminator */ }; -static struct alc_config_preset alc882_presets[] = { +static const struct alc_config_preset alc882_presets[] = { [ALC882_3ST_DIG] = { .mixers = { alc882_base_mixer }, .init_verbs = { alc882_base_init_verbs, @@ -10014,9 +10290,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc885_mba21_ch_modes, .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), .input_mux = &alc882_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_mba21_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC885_MBP3] = { .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, @@ -10030,9 +10306,9 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc882_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_mbp3_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC885_MB5] = { .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, @@ -10045,9 +10321,9 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &mb5_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_mb5_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC885_MACMINI3] = { .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer }, @@ -10060,9 +10336,9 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &macmini3_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_macmini3_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC885_MACPRO] = { .mixers = { alc882_macpro_mixer }, @@ -10086,7 +10362,7 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_imac24_setup, .init_hook = alc885_imac24_init_hook, }, @@ -10101,9 +10377,9 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc889A_imac91_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc885_imac91_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC882_TARGA] = { .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, @@ -10119,7 +10395,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc882_3ST_6ch_modes, .need_dac_fix = 1, .input_mux = &alc882_capture_source, - .unsol_event = alc882_targa_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc882_targa_setup, .init_hook = alc882_targa_automute, }, @@ -10213,8 +10489,8 @@ static struct alc_config_preset alc882_presets[] = { .capsrc_nids = alc889_capsrc_nids, .input_mux = &alc889_capture_source, .setup = alc889_automute_setup, - .init_hook = alc_automute_amp, - .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc_hp_automute, + .unsol_event = alc_sku_unsol_event, .need_dac_fix = 1, }, [ALC889_INTEL] = { @@ -10234,7 +10510,7 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc889_capture_source, .setup = alc889_automute_setup, .init_hook = alc889_intel_init_hook, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .need_dac_fix = 1, }, [ALC883_6ST_DIG] = { @@ -10323,9 +10599,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_acer_aspire_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_ACER_ASPIRE_4930G] = { .mixers = { alc888_acer_aspire_4930g_mixer, @@ -10345,9 +10621,9 @@ static struct alc_config_preset alc882_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_acer_aspire_4930g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_ACER_ASPIRE_6530G] = { .mixers = { alc888_acer_aspire_6530_mixer }, @@ -10364,9 +10640,9 @@ static struct alc_config_preset alc882_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_acer_aspire_6530_sources, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_acer_aspire_6530g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_ACER_ASPIRE_8930G] = { .mixers = { alc889_acer_aspire_8930g_mixer, @@ -10387,9 +10663,9 @@ static struct alc_config_preset alc882_presets[] = { .num_mux_defs = ARRAY_SIZE(alc889_capture_sources), .input_mux = alc889_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc889_acer_aspire_8930g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, #ifdef CONFIG_SND_HDA_POWER_SAVE .power_hook = alc_power_eapd, #endif @@ -10410,9 +10686,9 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .const_channel_count = 6, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_acer_aspire_7730g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, @@ -10439,9 +10715,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_medion_wim2160_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC883_LAPTOP_EAPD] = { .mixers = { alc883_base_mixer }, @@ -10491,8 +10767,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_lenovo_101e_capture_source, - .unsol_event = alc883_lenovo_101e_unsol_event, - .init_hook = alc883_lenovo_101e_all_automute, + .setup = alc883_lenovo_101e_setup, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc_inithook, }, [ALC883_LENOVO_NB0763] = { .mixers = { alc883_lenovo_nb0763_mixer }, @@ -10503,9 +10780,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_nb0763_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_lenovo_nb0763_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_LENOVO_MS7195_DIG] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -10517,8 +10794,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_6ch_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, - .unsol_event = alc883_lenovo_ms7195_unsol_event, - .init_hook = alc888_lenovo_ms7195_front_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc888_lenovo_ms7195_setup, + .init_hook = alc_inithook, }, [ALC883_HAIER_W66] = { .mixers = { alc883_targa_2ch_mixer}, @@ -10529,9 +10807,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_haier_w66_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_3ST_HP] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -10542,9 +10820,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc888_3st_hp_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_3st_hp_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_6ST_DELL] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -10556,9 +10834,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_6st_dell_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC883_MITAC] = { .mixers = { alc883_mitac_mixer }, @@ -10568,9 +10846,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_mitac_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC883_FUJITSU_PI2515] = { .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, @@ -10582,9 +10860,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_2ch_fujitsu_pi2515_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_FUJITSU_XA3530] = { .mixers = { alc888_base_mixer, alc883_chmode_mixer }, @@ -10601,9 +10879,9 @@ static struct alc_config_preset alc882_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_fujitsu_xa3530_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, @@ -10615,9 +10893,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_sixstack_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_sky_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc888_lenovo_sky_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC888_ASUS_M90V] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -10685,9 +10963,9 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc883_vaiott_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, }; @@ -10733,7 +11011,7 @@ static const struct alc_fixup alc882_fixups[] = { }, }; -static struct snd_pci_quirk alc882_fixup_tbl[] = { +static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), @@ -10841,6 +11119,11 @@ static void alc882_auto_init_input_src(struct hda_codec *codec) const struct hda_input_mux *imux; int conns, mute, idx, item; + /* mute ADC */ + snd_hda_codec_write(codec, spec->adc_nids[c], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + conns = snd_hda_get_connections(codec, nid, conn_list, ARRAY_SIZE(conn_list)); if (conns < 0) @@ -10920,7 +11203,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) static int alc882_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - static hda_nid_t alc882_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc882_ignore[] = { 0x1d, 0 }; int err; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, @@ -10933,6 +11216,9 @@ static int alc882_parse_auto_config(struct hda_codec *codec) err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; @@ -11134,14 +11420,14 @@ static int patch_alc882(struct hda_codec *codec) #define alc262_modes alc260_modes #define alc262_capture_source alc882_capture_source -static hda_nid_t alc262_dmic_adc_nids[1] = { +static const hda_nid_t alc262_dmic_adc_nids[1] = { /* ADC0 */ 0x09 }; -static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 }; +static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 }; -static struct snd_kcontrol_new alc262_base_mixer[] = { +static const struct snd_kcontrol_new alc262_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -11162,71 +11448,30 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { }; /* update HP, line and mono-out pins according to the master switch */ -static void alc262_hp_master_update(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int val = spec->master_sw; - - /* HP & line-out */ - snd_hda_codec_write_cache(codec, 0x1b, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - val ? PIN_HP : 0); - snd_hda_codec_write_cache(codec, 0x15, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - val ? PIN_HP : 0); - /* mono (speaker) depending on the HP jack sense */ - val = val && !spec->jack_present; - snd_hda_codec_write_cache(codec, 0x16, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - val ? PIN_OUT : 0); -} +#define alc262_hp_master_update alc260_hp_master_update -static void alc262_hp_bpc_automute(struct hda_codec *codec) +static void alc262_hp_bpc_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->jack_present = snd_hda_jack_detect(codec, 0x1b); - alc262_hp_master_update(codec); -} - -static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hp_bpc_automute(codec); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } -static void alc262_hp_wildwest_automute(struct hda_codec *codec) +static void alc262_hp_wildwest_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->jack_present = snd_hda_jack_detect(codec, 0x15); - alc262_hp_master_update(codec); -} - -static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hp_wildwest_automute(codec); + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } #define alc262_hp_master_sw_get alc260_hp_master_sw_get - -static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int val = !!*ucontrol->value.integer.value; - - if (val == spec->master_sw) - return 0; - spec->master_sw = val; - alc262_hp_master_update(codec); - return 1; -} +#define alc262_hp_master_sw_put alc260_hp_master_sw_put #define ALC262_HP_MASTER_SWITCH \ { \ @@ -11243,7 +11488,7 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { +static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { ALC262_HP_MASTER_SWITCH, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -11267,7 +11512,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { ALC262_HP_MASTER_SWITCH, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -11287,7 +11532,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { +static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT), @@ -11301,9 +11546,11 @@ static void alc262_hp_t5735_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } -static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { +static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -11314,7 +11561,7 @@ static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_hp_t5735_verbs[] = { +static const struct hda_verb alc262_hp_t5735_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -11322,7 +11569,7 @@ static struct hda_verb alc262_hp_t5735_verbs[] = { { } }; -static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { +static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT), @@ -11332,7 +11579,7 @@ static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_hp_rp5700_verbs[] = { +static const struct hda_verb alc262_hp_rp5700_verbs[] = { {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -11346,7 +11593,7 @@ static struct hda_verb alc262_hp_rp5700_verbs[] = { {} }; -static struct hda_input_mux alc262_hp_rp5700_capture_source = { +static const struct hda_input_mux alc262_hp_rp5700_capture_source = { .num_items = 1, .items = { { "Line", 0x1 }, @@ -11354,44 +11601,9 @@ static struct hda_input_mux alc262_hp_rp5700_capture_source = { }; /* bind hp and internal speaker mute (with plug check) as master switch */ -static void alc262_hippo_master_update(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; - hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; - hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0]; - unsigned int mute; - - /* HP */ - mute = spec->master_sw ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - /* mute internal speaker per jack sense */ - if (spec->jack_present) - mute = HDA_AMP_MUTE; - if (line_nid) - snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - if (speaker_nid && speaker_nid != line_nid) - snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); -} - +#define alc262_hippo_master_update alc262_hp_master_update #define alc262_hippo_master_sw_get alc262_hp_master_sw_get - -static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int val = !!*ucontrol->value.integer.value; - - if (val == spec->master_sw) - return 0; - spec->master_sw = val; - alc262_hippo_master_update(codec); - return 1; -} +#define alc262_hippo_master_sw_put alc262_hp_master_sw_put #define ALC262_HIPPO_MASTER_SWITCH \ { \ @@ -11408,7 +11620,7 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, (SUBDEV_SPEAKER(0) << 16), \ } -static struct snd_kcontrol_new alc262_hippo_mixer[] = { +static const struct snd_kcontrol_new alc262_hippo_mixer[] = { ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -11425,7 +11637,7 @@ static struct snd_kcontrol_new alc262_hippo_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_hippo1_mixer[] = { +static const struct snd_kcontrol_new alc262_hippo1_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -11442,28 +11654,14 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; - - spec->jack_present = snd_hda_jack_detect(codec, hp_nid); - alc262_hippo_master_update(codec); -} - -static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hippo_automute(codec); -} - static void alc262_hippo_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc262_hippo1_setup(struct hda_codec *codec) @@ -11472,10 +11670,12 @@ static void alc262_hippo1_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct snd_kcontrol_new alc262_sony_mixer[] = { +static const struct snd_kcontrol_new alc262_sony_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -11485,7 +11685,7 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { +static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -11496,7 +11696,7 @@ static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_tyan_mixer[] = { +static const struct snd_kcontrol_new alc262_tyan_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT), @@ -11512,7 +11712,7 @@ static struct snd_kcontrol_new alc262_tyan_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_tyan_verbs[] = { +static const struct hda_verb alc262_tyan_verbs[] = { /* Headphone automute */ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -11534,6 +11734,8 @@ static void alc262_tyan_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } @@ -11543,7 +11745,7 @@ static void alc262_tyan_setup(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc262_init_verbs[] = { +static const struct hda_verb alc262_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -11619,13 +11821,13 @@ static struct hda_verb alc262_init_verbs[] = { { } }; -static struct hda_verb alc262_eapd_verbs[] = { +static const struct hda_verb alc262_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc262_hippo1_unsol_verbs[] = { +static const struct hda_verb alc262_hippo1_unsol_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, @@ -11635,7 +11837,7 @@ static struct hda_verb alc262_hippo1_unsol_verbs[] = { {} }; -static struct hda_verb alc262_sony_unsol_verbs[] = { +static const struct hda_verb alc262_sony_unsol_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic @@ -11645,7 +11847,7 @@ static struct hda_verb alc262_sony_unsol_verbs[] = { {} }; -static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { +static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -11654,7 +11856,7 @@ static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_toshiba_s06_verbs[] = { +static const struct hda_verb alc262_toshiba_s06_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -11677,6 +11879,8 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec) spec->int_mic.pin = 0x12; spec->int_mic.mux_idx = 9; spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } /* @@ -11686,7 +11890,7 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec) * 0x18 = external mic */ -static struct snd_kcontrol_new alc262_nec_mixer[] = { +static const struct snd_kcontrol_new alc262_nec_mixer[] = { HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT), @@ -11699,7 +11903,7 @@ static struct snd_kcontrol_new alc262_nec_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_nec_verbs[] = { +static const struct hda_verb alc262_nec_verbs[] = { /* Unmute Speaker */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -11722,7 +11926,7 @@ static struct hda_verb alc262_nec_verbs[] = { #define ALC_HP_EVENT 0x37 -static struct hda_verb alc262_fujitsu_unsol_verbs[] = { +static const struct hda_verb alc262_fujitsu_unsol_verbs[] = { {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, @@ -11730,20 +11934,20 @@ static struct hda_verb alc262_fujitsu_unsol_verbs[] = { {} }; -static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = { +static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = { {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {} }; -static struct hda_verb alc262_lenovo_3000_init_verbs[] = { +static const struct hda_verb alc262_lenovo_3000_init_verbs[] = { /* Front Mic pin: input vref at 50% */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {} }; -static struct hda_input_mux alc262_fujitsu_capture_source = { +static const struct hda_input_mux alc262_fujitsu_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -11752,7 +11956,7 @@ static struct hda_input_mux alc262_fujitsu_capture_source = { }, }; -static struct hda_input_mux alc262_HP_capture_source = { +static const struct hda_input_mux alc262_HP_capture_source = { .num_items = 5, .items = { { "Mic", 0x0 }, @@ -11763,7 +11967,7 @@ static struct hda_input_mux alc262_HP_capture_source = { }, }; -static struct hda_input_mux alc262_HP_D7000_capture_source = { +static const struct hda_input_mux alc262_HP_D7000_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -11773,44 +11977,19 @@ static struct hda_input_mux alc262_HP_D7000_capture_source = { }, }; -/* mute/unmute internal speaker according to the hp jacks and mute state */ -static void alc262_fujitsu_automute(struct hda_codec *codec, int force) +static void alc262_fujitsu_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int mute; - - if (force || !spec->sense_updated) { - spec->jack_present = snd_hda_jack_detect(codec, 0x14) || - snd_hda_jack_detect(codec, 0x1b); - spec->sense_updated = 1; - } - /* unmute internal speaker only if both HPs are unplugged and - * master switch is on - */ - if (spec->jack_present) - mute = HDA_AMP_MUTE; - else - mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); -} -/* unsolicited event for HP jack sensing */ -static void alc262_fujitsu_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC_HP_EVENT) - return; - alc262_fujitsu_automute(codec, 1); -} - -static void alc262_fujitsu_init_hook(struct hda_codec *codec) -{ - alc262_fujitsu_automute(codec, 1); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.hp_pins[1] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } /* bind volumes of both NID 0x0c and 0x0d */ -static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { +static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), @@ -11819,78 +11998,15 @@ static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { }, }; -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force) -{ - struct alc_spec *spec = codec->spec; - unsigned int mute; - - if (force || !spec->sense_updated) { - spec->jack_present = snd_hda_jack_detect(codec, 0x1b); - spec->sense_updated = 1; - } - if (spec->jack_present) { - /* mute internal speaker */ - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } -} - -/* unsolicited event for HP jack sensing */ -static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC_HP_EVENT) - return; - alc262_lenovo_3000_automute(codec, 1); -} - -static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid, - int dir, int idx, long *valp) -{ - int i, change = 0; - - for (i = 0; i < 2; i++, valp++) - change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx, - HDA_AMP_MUTE, - *valp ? 0 : HDA_AMP_MUTE); - return change; -} - -/* bind hp and internal speaker mute (with plug check) */ -static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp); - change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp); - if (change) - alc262_fujitsu_automute(codec, 0); - return change; -} - -static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { +static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc262_fujitsu_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, }, { .iface = NID_MAPPING, @@ -11908,30 +12024,26 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { { } /* end */ }; -/* bind hp and internal speaker mute (with plug check) */ -static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void alc262_lenovo_3000_setup(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; + struct alc_spec *spec = codec->spec; - change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp); - if (change) - alc262_lenovo_3000_automute(codec, 0); - return change; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } -static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { +static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc262_lenovo_3000_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, }, HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -11944,7 +12056,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { +static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -11957,13 +12069,13 @@ static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { }; /* additional init verbs for Benq laptops */ -static struct hda_verb alc262_EAPD_verbs[] = { +static const struct hda_verb alc262_EAPD_verbs[] = { {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, {} }; -static struct hda_verb alc262_benq_t31_EAPD_verbs[] = { +static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, @@ -11973,7 +12085,7 @@ static struct hda_verb alc262_benq_t31_EAPD_verbs[] = { }; /* Samsung Q1 Ultra Vista model setup */ -static struct snd_kcontrol_new alc262_ultra_mixer[] = { +static const struct snd_kcontrol_new alc262_ultra_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), @@ -11983,7 +12095,7 @@ static struct snd_kcontrol_new alc262_ultra_mixer[] = { { } /* end */ }; -static struct hda_verb alc262_ultra_verbs[] = { +static const struct hda_verb alc262_ultra_verbs[] = { /* output mixer */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, @@ -12046,7 +12158,7 @@ static void alc262_ultra_unsol_event(struct hda_codec *codec, alc262_ultra_automute(codec); } -static struct hda_input_mux alc262_ultra_capture_source = { +static const struct hda_input_mux alc262_ultra_capture_source = { .num_items = 2, .items = { { "Mic", 0x1 }, @@ -12072,7 +12184,7 @@ static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol, return ret; } -static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { +static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), { @@ -12147,9 +12259,9 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, spec->multiout.num_dacs = 1; /* only use one dac */ spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.dac_nids[0] = 2; + spec->private_dac_nids[0] = 2; - pfx = alc_get_line_out_pfx(cfg, true); + pfx = alc_get_line_out_pfx(spec, true); if (!pfx) pfx = "Front"; for (i = 0; i < 2; i++) { @@ -12203,7 +12315,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc262_volume_init_verbs[] = { +static const struct hda_verb alc262_volume_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -12264,7 +12376,7 @@ static struct hda_verb alc262_volume_init_verbs[] = { { } }; -static struct hda_verb alc262_HP_BPC_init_verbs[] = { +static const struct hda_verb alc262_HP_BPC_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -12368,7 +12480,7 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { { } }; -static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { +static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -12464,7 +12576,7 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { { } }; -static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { +static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, @@ -12500,7 +12612,7 @@ static const struct alc_fixup alc262_fixups[] = { }, }; -static struct snd_pci_quirk alc262_fixup_tbl[] = { +static const struct snd_pci_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270), {} }; @@ -12523,7 +12635,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc262_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc262_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc262_ignore); @@ -12608,7 +12720,7 @@ static const char * const alc262_models[ALC262_MODEL_LAST] = { [ALC262_AUTO] = "auto", }; -static struct snd_pci_quirk alc262_cfg_tbl[] = { +static const struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series", @@ -12660,7 +12772,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { {} }; -static struct alc_config_preset alc262_presets[] = { +static const struct alc_config_preset alc262_presets[] = { [ALC262_BASIC] = { .mixers = { alc262_base_mixer }, .init_verbs = { alc262_init_verbs }, @@ -12681,9 +12793,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -12695,9 +12807,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo1_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, @@ -12710,8 +12822,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_fujitsu_capture_source, - .unsol_event = alc262_fujitsu_unsol_event, - .init_hook = alc262_fujitsu_init_hook, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_fujitsu_setup, + .init_hook = alc_inithook, }, [ALC262_HP_BPC] = { .mixers = { alc262_HP_BPC_mixer }, @@ -12722,8 +12835,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_HP_capture_source, - .unsol_event = alc262_hp_bpc_unsol_event, - .init_hook = alc262_hp_bpc_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_bpc_setup, + .init_hook = alc_inithook, }, [ALC262_HP_BPC_D7000_WF] = { .mixers = { alc262_HP_BPC_WildWest_mixer }, @@ -12734,8 +12848,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_HP_D7000_capture_source, - .unsol_event = alc262_hp_wildwest_unsol_event, - .init_hook = alc262_hp_wildwest_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, }, [ALC262_HP_BPC_D7000_WL] = { .mixers = { alc262_HP_BPC_WildWest_mixer, @@ -12747,8 +12862,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_HP_D7000_capture_source, - .unsol_event = alc262_hp_wildwest_unsol_event, - .init_hook = alc262_hp_wildwest_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_hp_wildwest_setup, + .init_hook = alc_inithook, }, [ALC262_HP_TC_T5735] = { .mixers = { alc262_hp_t5735_mixer }, @@ -12791,9 +12907,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -12805,9 +12921,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_ULTRA] = { .mixers = { alc262_ultra_mixer }, @@ -12836,7 +12952,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_fujitsu_capture_source, - .unsol_event = alc262_lenovo_3000_unsol_event, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_lenovo_3000_setup, + .init_hook = alc_inithook, }, [ALC262_NEC] = { .mixers = { alc262_nec_mixer }, @@ -12873,9 +12991,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc_inithook, }, [ALC262_TYAN] = { .mixers = { alc262_tyan_mixer }, @@ -12887,9 +13005,9 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc262_tyan_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, }; @@ -13010,6 +13128,7 @@ static int patch_alc262(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC262_AUTO) spec->init_hook = alc262_auto_init; + spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -13026,24 +13145,24 @@ static int patch_alc262(struct hda_codec *codec) #define ALC268_DIGOUT_NID ALC880_DIGOUT_NID #define alc268_modes alc260_modes -static hda_nid_t alc268_dac_nids[2] = { +static const hda_nid_t alc268_dac_nids[2] = { /* front, hp */ 0x02, 0x03 }; -static hda_nid_t alc268_adc_nids[2] = { +static const hda_nid_t alc268_adc_nids[2] = { /* ADC0-1 */ 0x08, 0x07 }; -static hda_nid_t alc268_adc_nids_alt[1] = { +static const hda_nid_t alc268_adc_nids_alt[1] = { /* ADC0 */ 0x08 }; -static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; +static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 }; -static struct snd_kcontrol_new alc268_base_mixer[] = { +static const struct snd_kcontrol_new alc268_base_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -13055,7 +13174,7 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { { } }; -static struct snd_kcontrol_new alc268_toshiba_mixer[] = { +static const struct snd_kcontrol_new alc268_toshiba_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), @@ -13067,7 +13186,7 @@ static struct snd_kcontrol_new alc268_toshiba_mixer[] = { }; /* bind Beep switches of both NID 0x0f and 0x10 */ -static struct hda_bind_ctls alc268_bind_beep_sw = { +static const struct hda_bind_ctls alc268_bind_beep_sw = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT), @@ -13076,27 +13195,27 @@ static struct hda_bind_ctls alc268_bind_beep_sw = { }, }; -static struct snd_kcontrol_new alc268_beep_mixer[] = { +static const struct snd_kcontrol_new alc268_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT), HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw), { } }; -static struct hda_verb alc268_eapd_verbs[] = { +static const struct hda_verb alc268_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; /* Toshiba specific */ -static struct hda_verb alc268_toshiba_verbs[] = { +static const struct hda_verb alc268_toshiba_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, { } /* end */ }; /* Acer specific */ /* bind volumes of both NID 0x02 and 0x03 */ -static struct hda_bind_ctls alc268_acer_bind_master_vol = { +static const struct hda_bind_ctls alc268_acer_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), @@ -13105,66 +13224,44 @@ static struct hda_bind_ctls alc268_acer_bind_master_vol = { }, }; -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_acer_automute(struct hda_codec *codec, int force) +static void alc268_acer_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int mute; - if (force || !spec->sense_updated) { - spec->jack_present = snd_hda_jack_detect(codec, 0x14); - spec->sense_updated = 1; - } - if (spec->jack_present) - mute = HDA_AMP_MUTE; /* mute internal speaker */ - else /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } +#define alc268_acer_master_sw_get alc262_hp_master_sw_get +#define alc268_acer_master_sw_put alc262_hp_master_sw_put -/* bind hp and internal speaker mute (with plug check) */ -static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp); - if (change) - alc268_acer_automute(codec, 0); - return change; -} - -static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { +static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, + .subdevice = HDA_SUBDEV_NID_FLAG | 0x15, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT), { } }; -static struct snd_kcontrol_new alc268_acer_mixer[] = { +static const struct snd_kcontrol_new alc268_acer_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), @@ -13172,24 +13269,23 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { { } }; -static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { +static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, + .subdevice = HDA_SUBDEV_NID_FLAG | 0x14, + .info = snd_ctl_boolean_mono_info, + .get = alc268_acer_master_sw_get, .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), { } }; -static struct hda_verb alc268_acer_aspire_one_verbs[] = { +static const struct hda_verb alc268_acer_aspire_one_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, @@ -13199,7 +13295,7 @@ static struct hda_verb alc268_acer_aspire_one_verbs[] = { { } }; -static struct hda_verb alc268_acer_verbs[] = { +static const struct hda_verb alc268_acer_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -13211,53 +13307,16 @@ static struct hda_verb alc268_acer_verbs[] = { }; /* unsolicited event for HP jack sensing */ -#define alc268_toshiba_unsol_event alc262_hippo_unsol_event #define alc268_toshiba_setup alc262_hippo_setup -#define alc268_toshiba_automute alc262_hippo_automute - -static void alc268_acer_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc268_acer_automute(codec, 1); -} - -static void alc268_acer_init_hook(struct hda_codec *codec) -{ - alc268_acer_automute(codec, 1); -} - -/* toggle speaker-output according to the hp-jack state */ -static void alc268_aspire_one_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x15); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); -} - -static void alc268_acer_lc_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc268_aspire_one_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} static void alc268_acer_lc_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0f; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -13265,13 +13324,7 @@ static void alc268_acer_lc_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc268_acer_lc_init_hook(struct hda_codec *codec) -{ - alc268_aspire_one_speaker_automute(codec); - alc_mic_automute(codec); -} - -static struct snd_kcontrol_new alc268_dell_mixer[] = { +static const struct snd_kcontrol_new alc268_dell_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -13282,7 +13335,7 @@ static struct snd_kcontrol_new alc268_dell_mixer[] = { { } }; -static struct hda_verb alc268_dell_verbs[] = { +static const struct hda_verb alc268_dell_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, @@ -13302,9 +13355,11 @@ static void alc268_dell_setup(struct hda_codec *codec) spec->int_mic.pin = 0x19; spec->int_mic.mux_idx = 1; spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } -static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { +static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), @@ -13316,7 +13371,7 @@ static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { { } }; -static struct hda_verb alc267_quanta_il1_verbs[] = { +static const struct hda_verb alc267_quanta_il1_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, { } @@ -13332,12 +13387,14 @@ static void alc267_quanta_il1_setup(struct hda_codec *codec) spec->int_mic.pin = 0x19; spec->int_mic.mux_idx = 1; spec->auto_mic = 1; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; } /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc268_base_init_verbs[] = { +static const struct hda_verb alc268_base_init_verbs[] = { /* Unmute DAC0-1 and set vol = 0 */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -13385,7 +13442,7 @@ static struct hda_verb alc268_base_init_verbs[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc268_volume_init_verbs[] = { +static const struct hda_verb alc268_volume_init_verbs[] = { /* set output DAC */ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -13411,20 +13468,20 @@ static struct hda_verb alc268_volume_init_verbs[] = { { } }; -static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { +static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), { } /* end */ }; -static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { +static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), _DEFINE_CAPSRC(1), { } /* end */ }; -static struct snd_kcontrol_new alc268_capture_mixer[] = { +static const struct snd_kcontrol_new alc268_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), @@ -13433,7 +13490,7 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = { { } /* end */ }; -static struct hda_input_mux alc268_capture_source = { +static const struct hda_input_mux alc268_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -13443,7 +13500,7 @@ static struct hda_input_mux alc268_capture_source = { }, }; -static struct hda_input_mux alc268_acer_capture_source = { +static const struct hda_input_mux alc268_acer_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -13452,7 +13509,7 @@ static struct hda_input_mux alc268_acer_capture_source = { }, }; -static struct hda_input_mux alc268_acer_dmic_capture_source = { +static const struct hda_input_mux alc268_acer_dmic_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -13462,7 +13519,7 @@ static struct hda_input_mux alc268_acer_dmic_capture_source = { }; #ifdef CONFIG_SND_DEBUG -static struct snd_kcontrol_new alc268_test_mixer[] = { +static const struct snd_kcontrol_new alc268_test_mixer[] = { /* Volume widgets */ HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -13541,7 +13598,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, HDA_OUTPUT)); if (err < 0) return err; - spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } if (nid != 0x16) @@ -13714,7 +13771,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc268_ignore[] = { 0 }; + static const hda_nid_t alc268_ignore[] = { 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc268_ignore); @@ -13794,7 +13851,7 @@ static const char * const alc268_models[ALC268_MODEL_LAST] = { [ALC268_AUTO] = "auto", }; -static struct snd_pci_quirk alc268_cfg_tbl[] = { +static const struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER), SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), @@ -13819,7 +13876,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { }; /* Toshiba laptops have no unique PCI SSID but only codec SSID */ -static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { +static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO), SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO), SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", @@ -13827,7 +13884,7 @@ static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = { {} }; -static struct alc_config_preset alc268_presets[] = { +static const struct alc_config_preset alc268_presets[] = { [ALC267_QUANTA_IL1] = { .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer, alc268_capture_nosrc_mixer }, @@ -13873,9 +13930,9 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, - .unsol_event = alc268_toshiba_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc268_toshiba_setup, - .init_hook = alc268_toshiba_automute, + .init_hook = alc_inithook, }, [ALC268_ACER] = { .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, @@ -13891,8 +13948,9 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_acer_capture_source, - .unsol_event = alc268_acer_unsol_event, - .init_hook = alc268_acer_init_hook, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, }, [ALC268_ACER_DMIC] = { .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, @@ -13908,8 +13966,9 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_acer_dmic_capture_source, - .unsol_event = alc268_acer_unsol_event, - .init_hook = alc268_acer_init_hook, + .unsol_event = alc_sku_unsol_event, + .setup = alc268_acer_setup, + .init_hook = alc_inithook, }, [ALC268_ACER_ASPIRE_ONE] = { .mixers = { alc268_acer_aspire_one_mixer, @@ -13925,9 +13984,9 @@ static struct alc_config_preset alc268_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, - .unsol_event = alc268_acer_lc_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc268_acer_lc_setup, - .init_hook = alc268_acer_lc_init_hook, + .init_hook = alc_inithook, }, [ALC268_DELL] = { .mixers = { alc268_dell_mixer, alc268_beep_mixer, @@ -13961,8 +14020,9 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, + .unsol_event = alc_sku_unsol_event, .setup = alc268_toshiba_setup, - .init_hook = alc268_toshiba_automute, + .init_hook = alc_inithook, }, #ifdef CONFIG_SND_DEBUG [ALC268_TEST] = { @@ -14084,6 +14144,7 @@ static int patch_alc268(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC268_AUTO) spec->init_hook = alc268_auto_init; + spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); @@ -14097,32 +14158,32 @@ static int patch_alc268(struct hda_codec *codec) #define alc269_dac_nids alc260_dac_nids -static hda_nid_t alc269_adc_nids[1] = { +static const hda_nid_t alc269_adc_nids[1] = { /* ADC1 */ 0x08, }; -static hda_nid_t alc269_capsrc_nids[1] = { +static const hda_nid_t alc269_capsrc_nids[1] = { 0x23, }; -static hda_nid_t alc269vb_adc_nids[1] = { +static const hda_nid_t alc269vb_adc_nids[1] = { /* ADC1 */ 0x09, }; -static hda_nid_t alc269vb_capsrc_nids[1] = { +static const hda_nid_t alc269vb_capsrc_nids[1] = { 0x22, }; -static hda_nid_t alc269_adc_candidates[] = { - 0x08, 0x09, 0x07, +static const hda_nid_t alc269_adc_candidates[] = { + 0x08, 0x09, 0x07, 0x11, }; #define alc269_modes alc260_modes #define alc269_capture_source alc880_lg_lw_capture_source -static struct snd_kcontrol_new alc269_base_mixer[] = { +static const struct snd_kcontrol_new alc269_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -14138,7 +14199,7 @@ static struct snd_kcontrol_new alc269_base_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { +static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { @@ -14159,7 +14220,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { { } }; -static struct snd_kcontrol_new alc269_lifebook_mixer[] = { +static const struct snd_kcontrol_new alc269_lifebook_mixer[] = { /* output mixer control */ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), { @@ -14183,7 +14244,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { { } }; -static struct snd_kcontrol_new alc269_laptop_mixer[] = { +static const struct snd_kcontrol_new alc269_laptop_mixer[] = { HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -14191,7 +14252,7 @@ static struct snd_kcontrol_new alc269_laptop_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269vb_laptop_mixer[] = { +static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = { HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), @@ -14199,14 +14260,14 @@ static struct snd_kcontrol_new alc269vb_laptop_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269_asus_mixer[] = { +static const struct snd_kcontrol_new alc269_asus_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT), { } /* end */ }; /* capture mixer elements */ -static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { +static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), @@ -14214,14 +14275,14 @@ static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { +static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), { } /* end */ }; -static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { +static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), @@ -14229,7 +14290,7 @@ static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { +static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), @@ -14239,7 +14300,7 @@ static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { /* FSC amilo */ #define alc269_fujitsu_mixer alc269_laptop_mixer -static struct hda_verb alc269_quanta_fl1_verbs[] = { +static const struct hda_verb alc269_quanta_fl1_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -14249,7 +14310,7 @@ static struct hda_verb alc269_quanta_fl1_verbs[] = { { } }; -static struct hda_verb alc269_lifebook_verbs[] = { +static const struct hda_verb alc269_lifebook_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -14266,15 +14327,7 @@ static struct hda_verb alc269_lifebook_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x15); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); + alc_hp_automute(codec); snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x0c); @@ -14287,34 +14340,8 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x480); } -/* toggle speaker-output according to the hp-jacks state */ -static void alc269_lifebook_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - /* Check laptop headphone socket */ - present = snd_hda_jack_detect(codec, 0x15); - - /* Check port replicator headphone socket */ - present |= snd_hda_jack_detect(codec, 0x1a); - - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x680); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x480); -} +#define alc269_lifebook_speaker_automute \ + alc269_quanta_fl1_speaker_automute static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) { @@ -14363,6 +14390,9 @@ static void alc269_quanta_fl1_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -14376,13 +14406,24 @@ static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) alc_mic_automute(codec); } +static void alc269_lifebook_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.hp_pins[1] = 0x1a; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; +} + static void alc269_lifebook_init_hook(struct hda_codec *codec) { alc269_lifebook_speaker_automute(codec); alc269_lifebook_mic_autoswitch(codec); } -static struct hda_verb alc269_laptop_dmic_init_verbs[] = { +static const struct hda_verb alc269_laptop_dmic_init_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -14393,7 +14434,7 @@ static struct hda_verb alc269_laptop_dmic_init_verbs[] = { {} }; -static struct hda_verb alc269_laptop_amic_init_verbs[] = { +static const struct hda_verb alc269_laptop_amic_init_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -14403,7 +14444,7 @@ static struct hda_verb alc269_laptop_amic_init_verbs[] = { {} }; -static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { +static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x22, AC_VERB_SET_CONNECT_SEL, 0x06}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -14414,7 +14455,7 @@ static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = { {} }; -static struct hda_verb alc269vb_laptop_amic_init_verbs[] = { +static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = { {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 }, @@ -14425,7 +14466,7 @@ static struct hda_verb alc269vb_laptop_amic_init_verbs[] = { {} }; -static struct hda_verb alc271_acer_dmic_verbs[] = { +static const struct hda_verb alc271_acer_dmic_verbs[] = { {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -14439,42 +14480,14 @@ static struct hda_verb alc271_acer_dmic_verbs[] = { { } }; -/* toggle speaker-output according to the hp-jack state */ -static void alc269_speaker_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - unsigned int nid = spec->autocfg.hp_pins[0]; - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, nid); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); - snd_hda_input_jack_report(codec, nid); -} - -/* unsolicited event for HP jack sensing */ -static void alc269_laptop_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc269_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - static void alc269_laptop_amic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -14487,6 +14500,9 @@ static void alc269_laptop_dmic_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -14499,6 +14515,9 @@ static void alc269vb_laptop_amic_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x21; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -14511,6 +14530,9 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x21; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -14518,16 +14540,10 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc269_laptop_inithook(struct hda_codec *codec) -{ - alc269_speaker_automute(codec); - alc_mic_automute(codec); -} - /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc269_init_verbs[] = { +static const struct hda_verb alc269_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -14570,7 +14586,7 @@ static struct hda_verb alc269_init_verbs[] = { { } }; -static struct hda_verb alc269vb_init_verbs[] = { +static const struct hda_verb alc269vb_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -14628,7 +14644,7 @@ static struct hda_verb alc269vb_init_verbs[] = { #define alc269_pcm_digital_playback alc880_pcm_digital_playback #define alc269_pcm_digital_capture alc880_pcm_digital_capture -static struct hda_pcm_stream alc269_44k_pcm_analog_playback = { +static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -14641,7 +14657,7 @@ static struct hda_pcm_stream alc269_44k_pcm_analog_playback = { }, }; -static struct hda_pcm_stream alc269_44k_pcm_analog_capture = { +static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -14725,7 +14741,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc269_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc269_ignore); @@ -14795,7 +14811,6 @@ static void alc269_auto_init(struct hda_codec *codec) alc_inithook(codec); } -#ifdef SND_HDA_NEEDS_RESUME static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) { int val = alc_read_coef_idx(codec, 0x04); @@ -14806,25 +14821,17 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) alc_write_coef_idx(codec, 0x04, val); } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static int alc269_suspend(struct hda_codec *codec, pm_message_t state) +static void alc269_shutup(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) alc269_toggle_power_output(codec, 0); if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { alc269_toggle_power_output(codec, 0); msleep(150); } - - alc_shutup(codec); - if (spec && spec->power_hook) - spec->power_hook(codec); - return 0; } -#endif /* CONFIG_SND_HDA_POWER_SAVE */ +#ifdef SND_HDA_NEEDS_RESUME static int alc269_resume(struct hda_codec *codec) { if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { @@ -14860,6 +14867,23 @@ static void alc269_fixup_hweq(struct hda_codec *codec, alc_write_coef_idx(codec, 0x1e, coef | 0x80); } +static void alc271_fixup_dmic(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + static const struct hda_verb verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, + {} + }; + unsigned int cfg; + + if (strcmp(codec->chip_name, "ALC271X")) + return; + cfg = snd_hda_codec_get_pincfg(codec, 0x12); + if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED) + snd_hda_sequence_write(codec, verbs); +} + enum { ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, @@ -14868,6 +14892,7 @@ enum { ALC269_FIXUP_ASUS_G73JW, ALC269_FIXUP_LENOVO_EAPD, ALC275_FIXUP_SONY_HWEQ, + ALC271_FIXUP_DMIC, }; static const struct alc_fixup alc269_fixups[] = { @@ -14921,15 +14946,20 @@ static const struct alc_fixup alc269_fixups[] = { .v.func = alc269_fixup_hweq, .chained = true, .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 - } + }, + [ALC271_FIXUP_DMIC] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc271_fixup_dmic, + }, }; -static struct snd_pci_quirk alc269_fixup_tbl[] = { +static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), 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_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), 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), @@ -14954,7 +14984,7 @@ static const char * const alc269_models[ALC269_MODEL_LAST] = { [ALC269_AUTO] = "auto", }; -static struct snd_pci_quirk alc269_cfg_tbl[] = { +static const struct snd_pci_quirk alc269_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER), SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", @@ -15012,7 +15042,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { {} }; -static struct alc_config_preset alc269_presets[] = { +static const struct alc_config_preset alc269_presets[] = { [ALC269_BASIC] = { .mixers = { alc269_base_mixer }, .init_verbs = { alc269_init_verbs }, @@ -15046,9 +15076,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269_laptop_amic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269_DMIC] = { .mixers = { alc269_laptop_mixer }, @@ -15060,9 +15090,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269_laptop_dmic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269VB_AMIC] = { .mixers = { alc269vb_laptop_mixer }, @@ -15074,9 +15104,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269vb_laptop_amic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269VB_DMIC] = { .mixers = { alc269vb_laptop_mixer }, @@ -15088,9 +15118,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269vb_laptop_dmic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269_FUJITSU] = { .mixers = { alc269_fujitsu_mixer }, @@ -15102,9 +15132,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_laptop_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc269_laptop_dmic_setup, - .init_hook = alc269_laptop_inithook, + .init_hook = alc_inithook, }, [ALC269_LIFEBOOK] = { .mixers = { alc269_lifebook_mixer }, @@ -15116,6 +15146,7 @@ static struct alc_config_preset alc269_presets[] = { .channel_mode = alc269_modes, .input_mux = &alc269_capture_source, .unsol_event = alc269_lifebook_unsol_event, + .setup = alc269_lifebook_setup, .init_hook = alc269_lifebook_init_hook, }, [ALC271_ACER] = { @@ -15161,14 +15192,21 @@ static int alc269_fill_coef(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0xd); if ((val & 0x0c00) >> 10 != 0x1) { /* Capless ramp up clock control */ - alc_write_coef_idx(codec, 0xd, val | 1<<10); + alc_write_coef_idx(codec, 0xd, val | (1<<10)); } val = alc_read_coef_idx(codec, 0x17); if ((val & 0x01c0) >> 6 != 0x4) { /* Class D power on reset */ - alc_write_coef_idx(codec, 0x17, val | 1<<7); + alc_write_coef_idx(codec, 0x17, val | (1<<7)); } } + + val = alc_read_coef_idx(codec, 0xd); /* Class D */ + alc_write_coef_idx(codec, 0xd, val | (1<<14)); + + val = alc_read_coef_idx(codec, 0x4); /* HP */ + alc_write_coef_idx(codec, 0x4, val | (1<<11)); + return 0; } @@ -15289,14 +15327,12 @@ static int patch_alc269(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; -#ifdef CONFIG_SND_HDA_POWER_SAVE - codec->patch_ops.suspend = alc269_suspend; -#endif #ifdef SND_HDA_NEEDS_RESUME codec->patch_ops.resume = alc269_resume; #endif if (board_config == ALC269_AUTO) spec->init_hook = alc269_auto_init; + spec->shutup = alc269_shutup; alc_init_jacks(codec); #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -15317,7 +15353,7 @@ static int patch_alc269(struct hda_codec *codec) * set the path ways for 2 channel output * need to set the codec line out and mic 1 pin widgets to inputs */ -static struct hda_verb alc861_threestack_ch2_init[] = { +static const struct hda_verb alc861_threestack_ch2_init[] = { /* set pin widget 1Ah (line in) for input */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, /* set pin widget 18h (mic1/2) for input, for mic also enable @@ -15336,7 +15372,7 @@ static struct hda_verb alc861_threestack_ch2_init[] = { * 6ch mode * need to set the codec line out and mic 1 pin widgets to outputs */ -static struct hda_verb alc861_threestack_ch6_init[] = { +static const struct hda_verb alc861_threestack_ch6_init[] = { /* set pin widget 1Ah (line in) for output (Back Surround)*/ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, /* set pin widget 18h (mic1) for output (CLFE)*/ @@ -15353,30 +15389,30 @@ static struct hda_verb alc861_threestack_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc861_threestack_modes[2] = { +static const struct hda_channel_mode alc861_threestack_modes[2] = { { 2, alc861_threestack_ch2_init }, { 6, alc861_threestack_ch6_init }, }; /* Set mic1 as input and unmute the mixer */ -static struct hda_verb alc861_uniwill_m31_ch2_init[] = { +static const struct hda_verb alc861_uniwill_m31_ch2_init[] = { { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ { } /* end */ }; /* Set mic1 as output and mute mixer */ -static struct hda_verb alc861_uniwill_m31_ch4_init[] = { +static const struct hda_verb alc861_uniwill_m31_ch4_init[] = { { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ { } /* end */ }; -static struct hda_channel_mode alc861_uniwill_m31_modes[2] = { +static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = { { 2, alc861_uniwill_m31_ch2_init }, { 4, alc861_uniwill_m31_ch4_init }, }; /* Set mic1 and line-in as input and unmute the mixer */ -static struct hda_verb alc861_asus_ch2_init[] = { +static const struct hda_verb alc861_asus_ch2_init[] = { /* set pin widget 1Ah (line in) for input */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, /* set pin widget 18h (mic1/2) for input, for mic also enable @@ -15392,7 +15428,7 @@ static struct hda_verb alc861_asus_ch2_init[] = { { } /* end */ }; /* Set mic1 nad line-in as output and mute mixer */ -static struct hda_verb alc861_asus_ch6_init[] = { +static const struct hda_verb alc861_asus_ch6_init[] = { /* set pin widget 1Ah (line in) for output (Back Surround)*/ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */ @@ -15410,14 +15446,14 @@ static struct hda_verb alc861_asus_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc861_asus_modes[2] = { +static const struct hda_channel_mode alc861_asus_modes[2] = { { 2, alc861_asus_ch2_init }, { 6, alc861_asus_ch6_init }, }; /* patch-ALC861 */ -static struct snd_kcontrol_new alc861_base_mixer[] = { +static const struct snd_kcontrol_new alc861_base_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), @@ -15440,7 +15476,7 @@ static struct snd_kcontrol_new alc861_base_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861_3ST_mixer[] = { +static const struct snd_kcontrol_new alc861_3ST_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), @@ -15471,7 +15507,7 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861_toshiba_mixer[] = { +static const struct snd_kcontrol_new alc861_toshiba_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), @@ -15480,7 +15516,7 @@ static struct snd_kcontrol_new alc861_toshiba_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { +static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), @@ -15511,7 +15547,7 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861_asus_mixer[] = { +static const struct snd_kcontrol_new alc861_asus_mixer[] = { /* output mixer control */ HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), @@ -15543,7 +15579,7 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = { }; /* additional mixer */ -static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { +static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), { } @@ -15552,7 +15588,7 @@ static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc861_base_init_verbs[] = { +static const struct hda_verb alc861_base_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15618,7 +15654,7 @@ static struct hda_verb alc861_base_init_verbs[] = { { } }; -static struct hda_verb alc861_threestack_init_verbs[] = { +static const struct hda_verb alc861_threestack_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15679,7 +15715,7 @@ static struct hda_verb alc861_threestack_init_verbs[] = { { } }; -static struct hda_verb alc861_uniwill_m31_init_verbs[] = { +static const struct hda_verb alc861_uniwill_m31_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15741,7 +15777,7 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = { { } }; -static struct hda_verb alc861_asus_init_verbs[] = { +static const struct hda_verb alc861_asus_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15807,7 +15843,7 @@ static struct hda_verb alc861_asus_init_verbs[] = { }; /* additional init verbs for ASUS laptops */ -static struct hda_verb alc861_asus_laptop_init_verbs[] = { +static const struct hda_verb alc861_asus_laptop_init_verbs[] = { { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */ { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */ { } @@ -15816,7 +15852,7 @@ static struct hda_verb alc861_asus_laptop_init_verbs[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc861_auto_init_verbs[] = { +static const struct hda_verb alc861_auto_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -15865,7 +15901,7 @@ static struct hda_verb alc861_auto_init_verbs[] = { { } }; -static struct hda_verb alc861_toshiba_init_verbs[] = { +static const struct hda_verb alc861_toshiba_init_verbs[] = { {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, { } @@ -15898,26 +15934,26 @@ static void alc861_toshiba_unsol_event(struct hda_codec *codec, #define ALC861_DIGOUT_NID 0x07 -static struct hda_channel_mode alc861_8ch_modes[1] = { +static const struct hda_channel_mode alc861_8ch_modes[1] = { { 8, NULL } }; -static hda_nid_t alc861_dac_nids[4] = { +static const hda_nid_t alc861_dac_nids[4] = { /* front, surround, clfe, side */ 0x03, 0x06, 0x05, 0x04 }; -static hda_nid_t alc660_dac_nids[3] = { +static const hda_nid_t alc660_dac_nids[3] = { /* front, clfe, surround */ 0x03, 0x05, 0x06 }; -static hda_nid_t alc861_adc_nids[1] = { +static const hda_nid_t alc861_adc_nids[1] = { /* ADC0-2 */ 0x08, }; -static struct hda_input_mux alc861_capture_source = { +static const struct hda_input_mux alc861_capture_source = { .num_items = 5, .items = { { "Mic", 0x0 }, @@ -15967,7 +16003,7 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec, dac = alc861_look_for_dac(codec, nid); if (!dac) continue; - spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } return 0; } @@ -15990,11 +16026,15 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec, static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; - const char *pfx = alc_get_line_out_pfx(cfg, true); + const char *pfx = alc_get_line_out_pfx(spec, true); hda_nid_t nid; - int i, err; + int i, err, noutputs; - for (i = 0; i < cfg->line_outs; i++) { + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { nid = spec->multiout.dac_nids[i]; if (!nid) continue; @@ -16127,7 +16167,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc861_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc861_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc861_ignore); @@ -16139,6 +16179,9 @@ static int alc861_parse_auto_config(struct hda_codec *codec) err = alc861_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -16183,7 +16226,7 @@ static void alc861_auto_init(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list alc861_loopbacks[] = { +static const struct hda_amp_list alc861_loopbacks[] = { { 0x15, HDA_INPUT, 0 }, { 0x15, HDA_INPUT, 1 }, { 0x15, HDA_INPUT, 2 }, @@ -16208,7 +16251,7 @@ static const char * const alc861_models[ALC861_MODEL_LAST] = { [ALC861_AUTO] = "auto", }; -static struct snd_pci_quirk alc861_cfg_tbl[] = { +static const struct snd_pci_quirk alc861_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), @@ -16232,7 +16275,7 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = { {} }; -static struct alc_config_preset alc861_presets[] = { +static const struct alc_config_preset alc861_presets[] = { [ALC861_3ST] = { .mixers = { alc861_3ST_mixer }, .init_verbs = { alc861_threestack_init_verbs }, @@ -16355,7 +16398,7 @@ static const struct alc_fixup alc861_fixups[] = { }, }; -static struct snd_pci_quirk alc861_fixup_tbl[] = { +static const struct snd_pci_quirk alc861_fixup_tbl[] = { SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), {} }; @@ -16448,7 +16491,7 @@ static int patch_alc861(struct hda_codec *codec) */ #define ALC861VD_DIGOUT_NID 0x06 -static hda_nid_t alc861vd_dac_nids[4] = { +static const hda_nid_t alc861vd_dac_nids[4] = { /* front, surr, clfe, side surr */ 0x02, 0x03, 0x04, 0x05 }; @@ -16460,21 +16503,21 @@ static hda_nid_t alc861vd_dac_nids[4] = { * - and it is the same as in 861vd. * adc_nids in ALC660vd are (is) the same as in 861vd */ -static hda_nid_t alc660vd_dac_nids[3] = { +static const hda_nid_t alc660vd_dac_nids[3] = { /* front, rear, clfe, rear_surr */ 0x02, 0x04, 0x03 }; -static hda_nid_t alc861vd_adc_nids[1] = { +static const hda_nid_t alc861vd_adc_nids[1] = { /* ADC0 */ 0x09, }; -static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; +static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 }; /* input MUX */ /* FIXME: should be a matrix-type input source selection */ -static struct hda_input_mux alc861vd_capture_source = { +static const struct hda_input_mux alc861vd_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -16484,7 +16527,7 @@ static struct hda_input_mux alc861vd_capture_source = { }, }; -static struct hda_input_mux alc861vd_dallas_capture_source = { +static const struct hda_input_mux alc861vd_dallas_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, @@ -16492,7 +16535,7 @@ static struct hda_input_mux alc861vd_dallas_capture_source = { }, }; -static struct hda_input_mux alc861vd_hp_capture_source = { +static const struct hda_input_mux alc861vd_hp_capture_source = { .num_items = 2, .items = { { "Front Mic", 0x0 }, @@ -16503,14 +16546,14 @@ static struct hda_input_mux alc861vd_hp_capture_source = { /* * 2ch mode */ -static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { +static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = { { 2, NULL } }; /* * 6ch mode */ -static struct hda_verb alc861vd_6stack_ch6_init[] = { +static const struct hda_verb alc861vd_6stack_ch6_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -16521,7 +16564,7 @@ static struct hda_verb alc861vd_6stack_ch6_init[] = { /* * 8ch mode */ -static struct hda_verb alc861vd_6stack_ch8_init[] = { +static const struct hda_verb alc861vd_6stack_ch8_init[] = { { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -16529,12 +16572,12 @@ static struct hda_verb alc861vd_6stack_ch8_init[] = { { } /* end */ }; -static struct hda_channel_mode alc861vd_6stack_modes[2] = { +static const struct hda_channel_mode alc861vd_6stack_modes[2] = { { 6, alc861vd_6stack_ch6_init }, { 8, alc861vd_6stack_ch8_init }, }; -static struct snd_kcontrol_new alc861vd_chmode_mixer[] = { +static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -16548,7 +16591,7 @@ static struct snd_kcontrol_new alc861vd_chmode_mixer[] = { /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ -static struct snd_kcontrol_new alc861vd_6st_mixer[] = { +static const struct snd_kcontrol_new alc861vd_6st_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -16584,7 +16627,7 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861vd_3st_mixer[] = { +static const struct snd_kcontrol_new alc861vd_3st_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -16607,7 +16650,7 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { +static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/ HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -16631,7 +16674,7 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { /* Pin assignment: Speaker=0x14, HP = 0x15, * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d */ -static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { +static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -16648,7 +16691,7 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { /* Pin assignment: Speaker=0x14, Line-out = 0x15, * Front Mic=0x18, ATAPI Mic = 0x19, */ -static struct snd_kcontrol_new alc861vd_hp_mixer[] = { +static const struct snd_kcontrol_new alc861vd_hp_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -16664,7 +16707,7 @@ static struct snd_kcontrol_new alc861vd_hp_mixer[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc861vd_volume_init_verbs[] = { +static const struct hda_verb alc861vd_volume_init_verbs[] = { /* * Unmute ADC0 and set the default input to mic-in */ @@ -16714,7 +16757,7 @@ static struct hda_verb alc861vd_volume_init_verbs[] = { * 3-stack pin configuration: * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b */ -static struct hda_verb alc861vd_3stack_init_verbs[] = { +static const struct hda_verb alc861vd_3stack_init_verbs[] = { /* * Set pin mode and muting */ @@ -16745,7 +16788,7 @@ static struct hda_verb alc861vd_3stack_init_verbs[] = { /* * 6-stack pin configuration: */ -static struct hda_verb alc861vd_6stack_init_verbs[] = { +static const struct hda_verb alc861vd_6stack_init_verbs[] = { /* * Set pin mode and muting */ @@ -16786,18 +16829,18 @@ static struct hda_verb alc861vd_6stack_init_verbs[] = { { } }; -static struct hda_verb alc861vd_eapd_verbs[] = { +static const struct hda_verb alc861vd_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc660vd_eapd_verbs[] = { +static const struct hda_verb alc660vd_eapd_verbs[] = { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { +static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, @@ -16811,11 +16854,13 @@ static void alc861vd_lenovo_setup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc861vd_lenovo_init_hook(struct hda_codec *codec) { - alc_automute_amp(codec); + alc_hp_automute(codec); alc88x_simple_mic_automute(codec); } @@ -16827,12 +16872,12 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, alc88x_simple_mic_automute(codec); break; default: - alc_automute_amp_unsol_event(codec, res); + alc_sku_unsol_event(codec, res); break; } } -static struct hda_verb alc861vd_dallas_verbs[] = { +static const struct hda_verb alc861vd_dallas_verbs[] = { {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, @@ -16884,6 +16929,8 @@ static void alc861vd_dallas_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -16912,7 +16959,7 @@ static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC861VD_AUTO] = "auto", }; -static struct snd_pci_quirk alc861vd_cfg_tbl[] = { +static const struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), @@ -16931,7 +16978,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { {} }; -static struct alc_config_preset alc861vd_presets[] = { +static const struct alc_config_preset alc861vd_presets[] = { [ALC660VD_3ST] = { .mixers = { alc861vd_3st_mixer }, .init_verbs = { alc861vd_volume_init_verbs, @@ -17008,9 +17055,9 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_dallas_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc861vd_dallas_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC861VD_HP] = { .mixers = { alc861vd_hp_mixer }, @@ -17021,9 +17068,9 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_hp_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc861vd_dallas_setup, - .init_hook = alc_automute_amp, + .init_hook = alc_hp_automute, }, [ALC660VD_ASUS_V1S] = { .mixers = { alc861vd_lenovo_mixer }, @@ -17122,11 +17169,15 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, static const char * const chname[4] = { "Front", "Surround", "CLFE", "Side" }; - const char *pfx = alc_get_line_out_pfx(cfg, true); + const char *pfx = alc_get_line_out_pfx(spec, true); hda_nid_t nid_v, nid_s; - int i, err; + int i, err, noutputs; - for (i = 0; i < cfg->line_outs; i++) { + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { if (!spec->multiout.dac_nids[i]) continue; nid_v = alc861vd_idx_to_mixer_vol( @@ -17239,7 +17290,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc861vd_ignore); @@ -17251,6 +17302,9 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; @@ -17319,7 +17373,7 @@ static const struct alc_fixup alc861vd_fixups[] = { }, }; -static struct snd_pci_quirk alc861vd_fixup_tbl[] = { +static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), {} }; @@ -17402,6 +17456,7 @@ static int patch_alc861vd(struct hda_codec *codec) if (board_config == ALC861VD_AUTO) spec->init_hook = alc861vd_auto_init; + spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc861vd_loopbacks; @@ -17424,32 +17479,32 @@ static int patch_alc861vd(struct hda_codec *codec) #define ALC662_DIGOUT_NID 0x06 #define ALC662_DIGIN_NID 0x0a -static hda_nid_t alc662_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ +static const hda_nid_t alc662_dac_nids[3] = { + /* front, rear, clfe */ 0x02, 0x03, 0x04 }; -static hda_nid_t alc272_dac_nids[2] = { +static const hda_nid_t alc272_dac_nids[2] = { 0x02, 0x03 }; -static hda_nid_t alc662_adc_nids[2] = { +static const hda_nid_t alc662_adc_nids[2] = { /* ADC1-2 */ 0x09, 0x08 }; -static hda_nid_t alc272_adc_nids[1] = { +static const hda_nid_t alc272_adc_nids[1] = { /* ADC1-2 */ 0x08, }; -static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; -static hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; +static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; +static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; /* input MUX */ /* FIXME: should be a matrix-type input source selection */ -static struct hda_input_mux alc662_capture_source = { +static const struct hda_input_mux alc662_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, @@ -17459,7 +17514,7 @@ static struct hda_input_mux alc662_capture_source = { }, }; -static struct hda_input_mux alc662_lenovo_101e_capture_source = { +static const struct hda_input_mux alc662_lenovo_101e_capture_source = { .num_items = 2, .items = { { "Mic", 0x1 }, @@ -17467,7 +17522,7 @@ static struct hda_input_mux alc662_lenovo_101e_capture_source = { }, }; -static struct hda_input_mux alc663_capture_source = { +static const struct hda_input_mux alc663_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -17477,7 +17532,7 @@ static struct hda_input_mux alc663_capture_source = { }; #if 0 /* set to 1 for testing other input sources below */ -static struct hda_input_mux alc272_nc10_capture_source = { +static const struct hda_input_mux alc272_nc10_capture_source = { .num_items = 16, .items = { { "Autoselect Mic", 0x0 }, @@ -17503,14 +17558,14 @@ static struct hda_input_mux alc272_nc10_capture_source = { /* * 2ch mode */ -static struct hda_channel_mode alc662_3ST_2ch_modes[1] = { +static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = { { 2, NULL } }; /* * 2ch mode */ -static struct hda_verb alc662_3ST_ch2_init[] = { +static const struct hda_verb alc662_3ST_ch2_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, @@ -17521,7 +17576,7 @@ static struct hda_verb alc662_3ST_ch2_init[] = { /* * 6ch mode */ -static struct hda_verb alc662_3ST_ch6_init[] = { +static const struct hda_verb alc662_3ST_ch6_init[] = { { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, @@ -17531,7 +17586,7 @@ static struct hda_verb alc662_3ST_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc662_3ST_6ch_modes[2] = { +static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = { { 2, alc662_3ST_ch2_init }, { 6, alc662_3ST_ch6_init }, }; @@ -17539,7 +17594,7 @@ static struct hda_channel_mode alc662_3ST_6ch_modes[2] = { /* * 2ch mode */ -static struct hda_verb alc662_sixstack_ch6_init[] = { +static const struct hda_verb alc662_sixstack_ch6_init[] = { { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, @@ -17549,14 +17604,14 @@ static struct hda_verb alc662_sixstack_ch6_init[] = { /* * 6ch mode */ -static struct hda_verb alc662_sixstack_ch8_init[] = { +static const struct hda_verb alc662_sixstack_ch8_init[] = { { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { } /* end */ }; -static struct hda_channel_mode alc662_5stack_modes[2] = { +static const struct hda_channel_mode alc662_5stack_modes[2] = { { 2, alc662_sixstack_ch6_init }, { 6, alc662_sixstack_ch8_init }, }; @@ -17565,7 +17620,7 @@ static struct hda_channel_mode alc662_5stack_modes[2] = { * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ -static struct snd_kcontrol_new alc662_base_mixer[] = { +static const struct snd_kcontrol_new alc662_base_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), @@ -17589,7 +17644,7 @@ static struct snd_kcontrol_new alc662_base_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { +static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -17604,7 +17659,7 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { +static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17625,7 +17680,7 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { +static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17638,7 +17693,7 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { +static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, @@ -17652,7 +17707,7 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { +static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17666,7 +17721,7 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_bind_master_vol = { +static const struct hda_bind_ctls alc663_asus_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), @@ -17675,7 +17730,7 @@ static struct hda_bind_ctls alc663_asus_bind_master_vol = { }, }; -static struct hda_bind_ctls alc663_asus_one_bind_switch = { +static const struct hda_bind_ctls alc663_asus_one_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17684,7 +17739,7 @@ static struct hda_bind_ctls alc663_asus_one_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_m51va_mixer[] = { +static const struct snd_kcontrol_new alc663_m51va_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -17692,7 +17747,7 @@ static struct snd_kcontrol_new alc663_m51va_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_tree_bind_switch = { +static const struct hda_bind_ctls alc663_asus_tree_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17702,7 +17757,7 @@ static struct hda_bind_ctls alc663_asus_tree_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { +static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -17713,7 +17768,7 @@ static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_four_bind_switch = { +static const struct hda_bind_ctls alc663_asus_four_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17723,7 +17778,7 @@ static struct hda_bind_ctls alc663_asus_four_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { +static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -17733,7 +17788,7 @@ static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc662_1bjd_mixer[] = { +static const struct snd_kcontrol_new alc662_1bjd_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -17744,7 +17799,7 @@ static struct snd_kcontrol_new alc662_1bjd_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_two_bind_master_vol = { +static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), @@ -17753,7 +17808,7 @@ static struct hda_bind_ctls alc663_asus_two_bind_master_vol = { }, }; -static struct hda_bind_ctls alc663_asus_two_bind_switch = { +static const struct hda_bind_ctls alc663_asus_two_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17762,7 +17817,7 @@ static struct hda_bind_ctls alc663_asus_two_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { +static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_two_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), @@ -17773,7 +17828,7 @@ static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { +static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17783,7 +17838,7 @@ static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc663_g71v_mixer[] = { +static const struct snd_kcontrol_new alc663_g71v_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -17797,7 +17852,7 @@ static struct snd_kcontrol_new alc663_g71v_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc663_g50v_mixer[] = { +static const struct snd_kcontrol_new alc663_g50v_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), @@ -17811,7 +17866,7 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { +static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17823,7 +17878,7 @@ static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { }, }; -static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { +static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), @@ -17832,7 +17887,7 @@ static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { }, }; -static struct snd_kcontrol_new alc663_mode7_mixer[] = { +static const struct snd_kcontrol_new alc663_mode7_mixer[] = { HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), @@ -17845,7 +17900,7 @@ static struct snd_kcontrol_new alc663_mode7_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc663_mode8_mixer[] = { +static const struct snd_kcontrol_new alc663_mode8_mixer[] = { HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), @@ -17857,7 +17912,7 @@ static struct snd_kcontrol_new alc663_mode8_mixer[] = { }; -static struct snd_kcontrol_new alc662_chmode_mixer[] = { +static const struct snd_kcontrol_new alc662_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -17868,7 +17923,7 @@ static struct snd_kcontrol_new alc662_chmode_mixer[] = { { } /* end */ }; -static struct hda_verb alc662_init_verbs[] = { +static const struct hda_verb alc662_init_verbs[] = { /* ADC: mute amp left and right */ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -17914,55 +17969,36 @@ static struct hda_verb alc662_init_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* always trun on EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - - { } -}; - -static struct hda_verb alc663_init_verbs[] = { - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, { } }; -static struct hda_verb alc272_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +static const struct hda_verb alc662_eapd_init_verbs[] = { + /* always trun on EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; -static struct hda_verb alc662_sue_init_verbs[] = { +static const struct hda_verb alc662_sue_init_verbs[] = { {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, {} }; -static struct hda_verb alc662_eeepc_sue_init_verbs[] = { +static const struct hda_verb alc662_eeepc_sue_init_verbs[] = { {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {} }; /* Set Unsolicited Event*/ -static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { +static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, {} }; -static struct hda_verb alc663_m51va_init_verbs[] = { +static const struct hda_verb alc663_m51va_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -17975,7 +18011,7 @@ static struct hda_verb alc663_m51va_init_verbs[] = { {} }; -static struct hda_verb alc663_21jd_amic_init_verbs[] = { +static const struct hda_verb alc663_21jd_amic_init_verbs[] = { {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ @@ -17986,7 +18022,7 @@ static struct hda_verb alc663_21jd_amic_init_verbs[] = { {} }; -static struct hda_verb alc662_1bjd_amic_init_verbs[] = { +static const struct hda_verb alc662_1bjd_amic_init_verbs[] = { {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -17998,7 +18034,7 @@ static struct hda_verb alc662_1bjd_amic_init_verbs[] = { {} }; -static struct hda_verb alc663_15jd_amic_init_verbs[] = { +static const struct hda_verb alc663_15jd_amic_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ @@ -18009,7 +18045,7 @@ static struct hda_verb alc663_15jd_amic_init_verbs[] = { {} }; -static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { +static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -18025,7 +18061,7 @@ static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { {} }; -static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { +static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -18041,7 +18077,7 @@ static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { {} }; -static struct hda_verb alc663_g71v_init_verbs[] = { +static const struct hda_verb alc663_g71v_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ @@ -18056,7 +18092,7 @@ static struct hda_verb alc663_g71v_init_verbs[] = { {} }; -static struct hda_verb alc663_g50v_init_verbs[] = { +static const struct hda_verb alc663_g50v_init_verbs[] = { {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ @@ -18066,7 +18102,7 @@ static struct hda_verb alc663_g50v_init_verbs[] = { {} }; -static struct hda_verb alc662_ecs_init_verbs[] = { +static const struct hda_verb alc662_ecs_init_verbs[] = { {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, @@ -18074,7 +18110,7 @@ static struct hda_verb alc662_ecs_init_verbs[] = { {} }; -static struct hda_verb alc272_dell_zm1_init_verbs[] = { +static const struct hda_verb alc272_dell_zm1_init_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -18089,7 +18125,7 @@ static struct hda_verb alc272_dell_zm1_init_verbs[] = { {} }; -static struct hda_verb alc272_dell_init_verbs[] = { +static const struct hda_verb alc272_dell_init_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -18104,7 +18140,7 @@ static struct hda_verb alc272_dell_init_verbs[] = { {} }; -static struct hda_verb alc663_mode7_init_verbs[] = { +static const struct hda_verb alc663_mode7_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -18123,7 +18159,7 @@ static struct hda_verb alc663_mode7_init_verbs[] = { {} }; -static struct hda_verb alc663_mode8_init_verbs[] = { +static const struct hda_verb alc663_mode8_init_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -18143,61 +18179,29 @@ static struct hda_verb alc663_mode8_init_verbs[] = { {} }; -static struct snd_kcontrol_new alc662_auto_capture_mixer[] = { +static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), { } /* end */ }; -static struct snd_kcontrol_new alc272_auto_capture_mixer[] = { +static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), { } /* end */ }; -static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x14); - bits = present ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x1b); - bits = present ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc662_lenovo_101e_setup(struct hda_codec *codec) { - if ((res >> 26) == ALC880_HP_EVENT) - alc662_lenovo_101e_all_automute(codec); - if ((res >> 26) == ALC880_FRONT_EVENT) - alc662_lenovo_101e_ispeaker_automute(codec); -} + struct alc_spec *spec = codec->spec; -/* unsolicited event for HP jack sensing */ -static void alc662_eeepc_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_MIC_EVENT) - alc_mic_automute(codec); - else - alc262_hippo_unsol_event(codec, res); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.line_out_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->automute = 1; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc662_eeepc_setup(struct hda_codec *codec) @@ -18212,180 +18216,24 @@ static void alc662_eeepc_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc662_eeepc_inithook(struct hda_codec *codec) -{ - alc262_hippo_automute(codec); - alc_mic_automute(codec); -} - static void alc662_eeepc_ep20_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; -} - -#define alc662_eeepc_ep20_inithook alc262_hippo_master_update - -static void alc663_m51va_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x21); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); -} - -static void alc663_21jd_two_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x21); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); -} - -static void alc663_15jd_two_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x15); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); -} - -static void alc662_f5z_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x1b); - bits = present ? 0 : PIN_OUT; - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, bits); -} - -static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec) -{ - unsigned int present1, present2; - - present1 = snd_hda_jack_detect(codec, 0x21); - present2 = snd_hda_jack_detect(codec, 0x15); - - if (present1 || present2) { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - } else { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - } -} - -static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec) -{ - unsigned int present1, present2; - - present1 = snd_hda_jack_detect(codec, 0x1b); - present2 = snd_hda_jack_detect(codec, 0x15); - - if (present1 || present2) { - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - HDA_AMP_MUTE, 0); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - HDA_AMP_MUTE, 0); - } -} - -static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec) -{ - unsigned int present1, present2; - - present1 = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - present2 = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - - if (present1 || present2) { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - } else { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - } -} - -static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec) -{ - unsigned int present1, present2; - - present1 = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - present2 = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - - if (present1 || present2) { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - } else { - snd_hda_codec_write_cache(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - snd_hda_codec_write_cache(codec, 0x17, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - } -} - -static void alc663_m51va_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_m51va_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc663_m51va_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -18393,18 +18241,15 @@ static void alc663_m51va_setup(struct hda_codec *codec) spec->auto_mic = 1; } -static void alc663_m51va_inithook(struct hda_codec *codec) -{ - alc663_m51va_speaker_automute(codec); - alc_mic_automute(codec); -} - /* ***************** Mode1 ******************************/ -#define alc663_mode1_unsol_event alc663_m51va_unsol_event - static void alc663_mode1_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -18412,229 +18257,144 @@ static void alc663_mode1_setup(struct hda_codec *codec) spec->auto_mic = 1; } -#define alc663_mode1_inithook alc663_m51va_inithook - /* ***************** Mode2 ******************************/ -static void alc662_mode2_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc662_mode2_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc662_f5z_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#define alc662_mode2_setup alc663_mode1_setup - -static void alc662_mode2_inithook(struct hda_codec *codec) -{ - alc662_f5z_speaker_automute(codec); - alc_mic_automute(codec); -} /* ***************** Mode3 ******************************/ -static void alc663_mode3_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_mode3_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_two_hp_m1_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#define alc663_mode3_setup alc663_mode1_setup - -static void alc663_mode3_inithook(struct hda_codec *codec) -{ - alc663_two_hp_m1_speaker_automute(codec); - alc_mic_automute(codec); -} /* ***************** Mode4 ******************************/ -static void alc663_mode4_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_mode4_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_21jd_two_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#define alc663_mode4_setup alc663_mode1_setup - -static void alc663_mode4_inithook(struct hda_codec *codec) -{ - alc663_21jd_two_speaker_automute(codec); - alc_mic_automute(codec); -} /* ***************** Mode5 ******************************/ -static void alc663_mode5_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_mode5_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_15jd_two_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute_mixer_nid[1] = 0x0e; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -#define alc663_mode5_setup alc663_mode1_setup - -static void alc663_mode5_inithook(struct hda_codec *codec) -{ - alc663_15jd_two_speaker_automute(codec); - alc_mic_automute(codec); -} /* ***************** Mode6 ******************************/ -static void alc663_mode6_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_two_hp_m2_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -#define alc663_mode6_setup alc663_mode1_setup - -static void alc663_mode6_inithook(struct hda_codec *codec) +static void alc663_mode6_setup(struct hda_codec *codec) { - alc663_two_hp_m2_speaker_automute(codec); - alc_mic_automute(codec); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute_mixer_nid[0] = 0x0c; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_MIXER; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } /* ***************** Mode7 ******************************/ -static void alc663_mode7_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_two_hp_m7_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -#define alc663_mode7_setup alc663_mode1_setup - -static void alc663_mode7_inithook(struct hda_codec *codec) +static void alc663_mode7_setup(struct hda_codec *codec) { - alc663_two_hp_m7_speaker_automute(codec); - alc_mic_automute(codec); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } /* ***************** Mode8 ******************************/ -static void alc663_mode8_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_mode8_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_two_hp_m8_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -#define alc663_mode8_setup alc663_m51va_setup - -static void alc663_mode8_inithook(struct hda_codec *codec) -{ - alc663_two_hp_m8_speaker_automute(codec); - alc_mic_automute(codec); -} - -static void alc663_g71v_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x21); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc663_g71v_front_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x15); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc663_g71v_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_g71v_hp_automute(codec); - break; - case ALC880_FRONT_EVENT: - alc663_g71v_front_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } -} - -#define alc663_g71v_setup alc663_m51va_setup - -static void alc663_g71v_inithook(struct hda_codec *codec) -{ - alc663_g71v_front_automute(codec); - alc663_g71v_hp_automute(codec); - alc_mic_automute(codec); + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.hp_pins[1] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x17; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_PIN; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; } -static void alc663_g50v_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc663_g71v_setup(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_m51va_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x21; + spec->autocfg.line_out_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; + spec->detect_line = 1; + spec->automute_lines = 1; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; } #define alc663_g50v_setup alc663_m51va_setup -static void alc663_g50v_inithook(struct hda_codec *codec) -{ - alc663_m51va_speaker_automute(codec); - alc_mic_automute(codec); -} - -static struct snd_kcontrol_new alc662_ecs_mixer[] = { +static const struct snd_kcontrol_new alc662_ecs_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, @@ -18648,7 +18408,7 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc272_nc10_mixer[] = { +static const struct snd_kcontrol_new alc272_nc10_mixer[] = { /* Master Playback automatically created from Speaker and Headphone */ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -18683,7 +18443,7 @@ static const char * const alc662_models[ALC662_MODEL_LAST] = { [ALC662_3ST_2ch_DIG] = "3stack-dig", [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", [ALC662_3ST_6ch] = "3stack-6ch", - [ALC662_5ST_DIG] = "6stack-dig", + [ALC662_5ST_DIG] = "5stack-dig", [ALC662_LENOVO_101E] = "lenovo-101e", [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", @@ -18706,7 +18466,7 @@ static const char * const alc662_models[ALC662_MODEL_LAST] = { [ALC662_AUTO] = "auto", }; -static struct snd_pci_quirk alc662_cfg_tbl[] = { +static const struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL), SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1), @@ -18788,10 +18548,10 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { {} }; -static struct alc_config_preset alc662_presets[] = { +static const struct alc_config_preset alc662_presets[] = { [ALC662_3ST_2ch_DIG] = { .mixers = { alc662_3ST_2ch_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18802,7 +18562,7 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_3ST_6ch_DIG] = { .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18814,7 +18574,7 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_3ST_6ch] = { .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), @@ -18824,7 +18584,7 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_5ST_DIG] = { .mixers = { alc662_base_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18835,104 +18595,120 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_LENOVO_101E] = { .mixers = { alc662_lenovo_101e_mixer }, - .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc662_lenovo_101e_unsol_event, - .init_hook = alc662_lenovo_101e_all_automute, + .unsol_event = alc_sku_unsol_event, + .setup = alc662_lenovo_101e_setup, + .init_hook = alc_inithook, }, [ALC662_ASUS_EEEPC_P701] = { .mixers = { alc662_eeepc_p701_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_eeepc_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc662_eeepc_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc662_eeepc_setup, - .init_hook = alc662_eeepc_inithook, + .init_hook = alc_inithook, }, [ALC662_ASUS_EEEPC_EP20] = { .mixers = { alc662_eeepc_ep20_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_eeepc_ep20_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc662_eeepc_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc662_eeepc_ep20_setup, - .init_hook = alc662_eeepc_ep20_inithook, + .init_hook = alc_inithook, }, [ALC662_ECS] = { .mixers = { alc662_ecs_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_ecs_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc662_eeepc_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc662_eeepc_setup, - .init_hook = alc662_eeepc_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_M51VA] = { .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_m51va_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_m51va_setup, - .init_hook = alc663_m51va_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_G71V] = { .mixers = { alc663_g71v_mixer }, - .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g71v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_g71v_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_g71v_setup, - .init_hook = alc663_g71v_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_H13] = { .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_m51va_unsol_event, - .init_hook = alc663_m51va_inithook, + .setup = alc663_m51va_setup, + .unsol_event = alc_sku_unsol_event, + .init_hook = alc_inithook, }, [ALC663_ASUS_G50V] = { .mixers = { alc663_g50v_mixer }, - .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g50v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc663_capture_source, - .unsol_event = alc663_g50v_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_g50v_setup, - .init_hook = alc663_g50v_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE1] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_21jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -18940,28 +18716,30 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode1_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode1_setup, - .init_hook = alc663_mode1_inithook, + .init_hook = alc_inithook, }, [ALC662_ASUS_MODE2] = { .mixers = { alc662_1bjd_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_1bjd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc662_mode2_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc662_mode2_setup, - .init_hook = alc662_mode2_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE3] = { .mixers = { alc663_two_hp_m1_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_two_hp_amic_m1_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -18969,14 +18747,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode3_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode3_setup, - .init_hook = alc663_mode3_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE4] = { .mixers = { alc663_asus_21jd_clfe_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_21jd_amic_init_verbs}, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -18984,14 +18763,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode4_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode4_setup, - .init_hook = alc663_mode4_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE5] = { .mixers = { alc663_asus_15jd_clfe_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_15jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -18999,14 +18779,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode5_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode5_setup, - .init_hook = alc663_mode5_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE6] = { .mixers = { alc663_two_hp_m2_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_two_hp_amic_m2_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19014,14 +18795,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode6_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode6_setup, - .init_hook = alc663_mode6_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE7] = { .mixers = { alc663_mode7_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_mode7_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19029,14 +18811,15 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode7_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode7_setup, - .init_hook = alc663_mode7_inithook, + .init_hook = alc_inithook, }, [ALC663_ASUS_MODE8] = { .mixers = { alc663_mode8_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_mode8_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19044,52 +18827,57 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_mode8_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode8_setup, - .init_hook = alc663_mode8_inithook, + .init_hook = alc_inithook, }, [ALC272_DELL] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc272_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_init_verbs }, .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc662_dac_nids, + .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .adc_nids = alc272_adc_nids, .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), .capsrc_nids = alc272_capsrc_nids, .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_m51va_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_m51va_setup, - .init_hook = alc663_m51va_inithook, + .init_hook = alc_inithook, }, [ALC272_DELL_ZM1] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_zm1_init_verbs }, .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc662_dac_nids, + .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .adc_nids = alc662_adc_nids, .num_adc_nids = 1, .capsrc_nids = alc662_capsrc_nids, .channel_mode = alc662_3ST_2ch_modes, - .unsol_event = alc663_m51va_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_m51va_setup, - .init_hook = alc663_m51va_inithook, + .init_hook = alc_inithook, }, [ALC272_SAMSUNG_NC10] = { .mixers = { alc272_nc10_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_21jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc272_dac_nids), .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, /*.input_mux = &alc272_nc10_capture_source,*/ - .unsol_event = alc663_mode4_unsol_event, + .unsol_event = alc_sku_unsol_event, .setup = alc663_mode4_setup, - .init_hook = alc663_mode4_inithook, + .init_hook = alc_inithook, }, }; @@ -19099,45 +18887,79 @@ static struct alc_config_preset alc662_presets[] = { */ /* convert from MIX nid to DAC */ -static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) -{ - if (nid == 0x0f) - return 0x02; - else if (nid >= 0x0c && nid <= 0x0e) - return nid - 0x0c + 0x02; - else if (nid == 0x26) /* ALC887-VD has this DAC too */ - return 0x25; - else - return 0; +static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid) +{ + hda_nid_t list[5]; + int i, num; + + num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list)); + for (i = 0; i < num; i++) { + if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT) + return list[i]; + } + return 0; +} + +/* go down to the selector widget before the mixer */ +static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin) +{ + hda_nid_t srcs[5]; + int num = snd_hda_get_connections(codec, pin, srcs, + ARRAY_SIZE(srcs)); + if (num != 1 || + get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL) + return pin; + return srcs[0]; } /* get MIX nid connected to the given pin targeted to DAC */ -static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, +static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) { hda_nid_t mix[5]; int i, num; + pin = alc_go_down_to_selector(codec, pin); num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); for (i = 0; i < num; i++) { - if (alc662_mix_to_dac(mix[i]) == dac) + if (alc_auto_mix_to_dac(codec, mix[i]) == dac) return mix[i]; } return 0; } +/* select the connection from pin to DAC if needed */ +static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t dac) +{ + hda_nid_t mix[5]; + int i, num; + + pin = alc_go_down_to_selector(codec, pin); + num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); + if (num < 2) + return 0; + for (i = 0; i < num; i++) { + if (alc_auto_mix_to_dac(codec, mix[i]) == dac) { + snd_hda_codec_update_cache(codec, pin, 0, + AC_VERB_SET_CONNECT_SEL, i); + return 0; + } + } + return 0; +} + /* look for an empty DAC slot */ -static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) { struct alc_spec *spec = codec->spec; hda_nid_t srcs[5]; int i, j, num; + pin = alc_go_down_to_selector(codec, pin); num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); - if (num < 0) - return 0; for (i = 0; i < num; i++) { - hda_nid_t nid = alc662_mix_to_dac(srcs[i]); + hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); if (!nid) continue; for (j = 0; j < spec->multiout.num_dacs; j++) @@ -19159,10 +18981,10 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec, spec->multiout.dac_nids = spec->private_dac_nids; for (i = 0; i < cfg->line_outs; i++) { - dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]); + dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]); if (!dac) continue; - spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } return 0; } @@ -19198,15 +19020,23 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; - const char *pfx = alc_get_line_out_pfx(cfg, true); - hda_nid_t nid, mix; - int i, err; + const char *pfx = alc_get_line_out_pfx(spec, true); + hda_nid_t nid, mix, pin; + int i, err, noutputs; - for (i = 0; i < cfg->line_outs; i++) { + noutputs = cfg->line_outs; + if (spec->multi_ios > 0) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { nid = spec->multiout.dac_nids[i]; if (!nid) continue; - mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid); + if (i >= cfg->line_outs) + pin = spec->multi_io[i - 1].pin; + else + pin = cfg->line_out_pins[i]; + mix = alc_auto_dac_to_mix(codec, pin, nid); if (!mix) continue; if (!pfx && i == 2) { @@ -19252,7 +19082,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, if (!pin) return 0; - nid = alc662_look_for_dac(codec, pin); + nid = alc_auto_look_for_dac(codec, pin); if (!nid) { /* the corresponding DAC is already occupied */ if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) @@ -19262,7 +19092,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); } - mix = alc662_dac_to_mix(codec, pin, nid); + mix = alc_auto_dac_to_mix(codec, pin, nid); if (!mix) return 0; err = alc662_add_vol_ctl(spec, pfx, nid, 3); @@ -19286,14 +19116,21 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t srcs[HDA_MAX_CONNECTIONS]; alc_set_pin_output(codec, nid, pin_type); - /* need the manual connection? */ num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); - if (num <= 1) - return; for (i = 0; i < num; i++) { - if (alc662_mix_to_dac(srcs[i]) != dac) + if (alc_auto_mix_to_dac(codec, srcs[i]) != dac) continue; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i); + /* need the manual connection? */ + if (num > 1) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, i); + /* unmute mixer widget inputs */ + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); return; } } @@ -19350,11 +19187,164 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec) #define alc662_auto_init_input_src alc882_auto_init_input_src +/* + * multi-io helper + */ +static int alc_auto_fill_multi_ios(struct hda_codec *codec, + unsigned int location) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int type, i, num_pins = 0; + + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + hda_nid_t dac; + unsigned int defcfg, caps; + if (cfg->inputs[i].type != type) + continue; + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) + continue; + if (location && get_defcfg_location(defcfg) != location) + continue; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_OUT)) + continue; + dac = alc_auto_look_for_dac(codec, nid); + if (!dac) + continue; + spec->multi_io[num_pins].pin = nid; + spec->multi_io[num_pins].dac = dac; + num_pins++; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; + } + } + spec->multiout.num_dacs = 1; + if (num_pins < 2) + return 0; + return num_pins; +} + +static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = spec->multi_ios + 1; + if (uinfo->value.enumerated.item > spec->multi_ios) + uinfo->value.enumerated.item = spec->multi_ios; + sprintf(uinfo->value.enumerated.name, "%dch", + (uinfo->value.enumerated.item + 1) * 2); + return 0; +} + +static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; + return 0; +} + +static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = spec->multi_io[idx].pin; + + if (!spec->multi_io[idx].ctl_in) + spec->multi_io[idx].ctl_in = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (output) { + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); + alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac); + } else { + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->multi_io[idx].ctl_in); + } + return 0; +} + +static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int i, ch; + + ch = ucontrol->value.enumerated.item[0]; + if (ch < 0 || ch > spec->multi_ios) + return -EINVAL; + if (ch == (spec->ext_channel_count - 1) / 2) + return 0; + spec->ext_channel_count = (ch + 1) * 2; + for (i = 0; i < spec->multi_ios; i++) + alc_set_multi_io(codec, i, i < ch); + spec->multiout.max_channels = spec->ext_channel_count; + return 1; +} + +static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_auto_ch_mode_info, + .get = alc_auto_ch_mode_get, + .put = alc_auto_ch_mode_put, +}; + +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int location, defcfg; + int num_pins; + + if (cfg->line_outs != 1 || + cfg->line_out_type != AUTO_PIN_LINE_OUT) + return 0; + + defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); + location = get_defcfg_location(defcfg); + + num_pins = alc_auto_fill_multi_ios(codec, location); + if (num_pins > 0) { + struct snd_kcontrol_new *knew; + + knew = alc_kcontrol_new(spec); + if (!knew) + return -ENOMEM; + *knew = alc_auto_channel_mode_enum; + knew->name = kstrdup("Channel Mode", GFP_KERNEL); + if (!knew->name) + return -ENOMEM; + + spec->multi_ios = num_pins; + spec->ext_channel_count = 2; + spec->multiout.num_dacs = num_pins + 1; + } + return 0; +} + static int alc662_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc662_ignore[] = { 0x1d, 0 }; + static const hda_nid_t alc662_ignore[] = { 0x1d, 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc662_ignore); @@ -19366,6 +19356,9 @@ static int alc662_parse_auto_config(struct hda_codec *codec) err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err; + err = alc_auto_add_multi_channel_mode(codec); + if (err < 0) + return err; err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -19396,14 +19389,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - add_verb(spec, alc662_init_verbs); - if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || - codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) - add_verb(spec, alc663_init_verbs); - - if (codec->vendor_id == 0x10ec0272) - add_verb(spec, alc272_init_verbs); - err = alc_auto_add_mic_boost(codec); if (err < 0) return err; @@ -19449,6 +19434,7 @@ enum { ALC662_FIXUP_IDEAPAD, ALC272_FIXUP_MARIO, ALC662_FIXUP_CZC_P10T, + ALC662_FIXUP_SKU_IGNORE, }; static const struct alc_fixup alc662_fixups[] = { @@ -19477,10 +19463,15 @@ static const struct alc_fixup alc662_fixups[] = { {} } }, + [ALC662_FIXUP_SKU_IGNORE] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, + }, }; -static struct snd_pci_quirk alc662_fixup_tbl[] = { +static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), @@ -19596,6 +19587,7 @@ static int patch_alc662(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC662_AUTO) spec->init_hook = alc662_auto_init; + spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); @@ -19624,6 +19616,15 @@ static int patch_alc888(struct hda_codec *codec) return patch_alc882(codec); } +static int patch_alc899(struct hda_codec *codec) +{ + if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) { + kfree(codec->chip_name); + codec->chip_name = kstrdup("ALC898", GFP_KERNEL); + } + return patch_alc882(codec); +} + /* * ALC680 support */ @@ -19631,12 +19632,12 @@ static int patch_alc888(struct hda_codec *codec) #define ALC680_DIGOUT_NID ALC880_DIGOUT_NID #define alc680_modes alc260_modes -static hda_nid_t alc680_dac_nids[3] = { +static const hda_nid_t alc680_dac_nids[3] = { /* Lout1, Lout2, hp */ 0x02, 0x03, 0x04 }; -static hda_nid_t alc680_adc_nids[3] = { +static const hda_nid_t alc680_adc_nids[3] = { /* ADC0-2 */ /* DMIC, MIC, Line-in*/ 0x07, 0x08, 0x09 @@ -19656,8 +19657,7 @@ static void alc680_rec_autoswitch(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { nid = cfg->inputs[i].pin; - if (!(snd_hda_query_pin_caps(codec, nid) & - AC_PINCAP_PRES_DETECT)) + if (!is_jack_detectable(codec, nid)) continue; if (snd_hda_jack_detect(codec, nid)) { if (cfg->inputs[i].type < type_found) { @@ -19704,7 +19704,7 @@ static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream alc680_pcm_analog_auto_capture = { +static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = { .substreams = 1, /* can be overridden */ .channels_min = 2, .channels_max = 2, @@ -19715,7 +19715,7 @@ static struct hda_pcm_stream alc680_pcm_analog_auto_capture = { }, }; -static struct snd_kcontrol_new alc680_base_mixer[] = { +static const struct snd_kcontrol_new alc680_base_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -19727,7 +19727,7 @@ static struct snd_kcontrol_new alc680_base_mixer[] = { { } }; -static struct hda_bind_ctls alc680_bind_cap_vol = { +static const struct hda_bind_ctls alc680_bind_cap_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), @@ -19737,7 +19737,7 @@ static struct hda_bind_ctls alc680_bind_cap_vol = { }, }; -static struct hda_bind_ctls alc680_bind_cap_switch = { +static const struct hda_bind_ctls alc680_bind_cap_switch = { .ops = &snd_hda_bind_sw, .values = { HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), @@ -19747,7 +19747,7 @@ static struct hda_bind_ctls alc680_bind_cap_switch = { }, }; -static struct snd_kcontrol_new alc680_master_capture_mixer[] = { +static const struct snd_kcontrol_new alc680_master_capture_mixer[] = { HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), { } /* end */ @@ -19756,7 +19756,7 @@ static struct snd_kcontrol_new alc680_master_capture_mixer[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc680_init_verbs[] = { +static const struct hda_verb alc680_init_verbs[] = { {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -19794,20 +19794,22 @@ static void alc680_base_setup(struct hda_codec *codec) spec->autocfg.inputs[0].type = AUTO_PIN_MIC; spec->autocfg.inputs[1].pin = 0x19; spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; + spec->automute = 1; + spec->automute_mode = ALC_AUTOMUTE_AMP; } static void alc680_unsol_event(struct hda_codec *codec, unsigned int res) { if ((res >> 26) == ALC880_HP_EVENT) - alc_automute_amp(codec); + alc_hp_automute(codec); if ((res >> 26) == ALC880_MIC_EVENT) alc680_rec_autoswitch(codec); } static void alc680_inithook(struct hda_codec *codec) { - alc_automute_amp(codec); + alc_hp_automute(codec); alc680_rec_autoswitch(codec); } @@ -19844,7 +19846,7 @@ static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid, if (err < 0) return err; - spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } return 0; @@ -19930,7 +19932,7 @@ static int alc680_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int err; - static hda_nid_t alc680_ignore[] = { 0 }; + static const hda_nid_t alc680_ignore[] = { 0 }; err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, alc680_ignore); @@ -19988,12 +19990,12 @@ static const char * const alc680_models[ALC680_MODEL_LAST] = { [ALC680_AUTO] = "auto", }; -static struct snd_pci_quirk alc680_cfg_tbl[] = { +static const struct snd_pci_quirk alc680_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), {} }; -static struct alc_config_preset alc680_presets[] = { +static const struct alc_config_preset alc680_presets[] = { [ALC680_BASE] = { .mixers = { alc680_base_mixer }, .cap_mixer = alc680_master_capture_mixer, @@ -20074,7 +20076,8 @@ static int patch_alc680(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_realtek[] = { +static const struct hda_codec_preset snd_hda_preset_realtek[] = { + { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 }, { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, @@ -20083,6 +20086,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 }, { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 }, { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 }, + { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, @@ -20110,6 +20114,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 }, { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 }, { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 }, + { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index f419ee8d75f0..2f55f32876fa 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -130,7 +130,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new si3054_modem_mixer[] = { +static const struct snd_kcontrol_new si3054_modem_mixer[] = { SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH), SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID), {} @@ -181,7 +181,7 @@ static int si3054_pcm_open(struct hda_pcm_stream *hinfo, } -static struct hda_pcm_stream si3054_pcm = { +static const struct hda_pcm_stream si3054_pcm = { .substreams = 1, .channels_min = 1, .channels_max = 1, @@ -200,12 +200,13 @@ static int si3054_build_pcms(struct hda_codec *codec) { struct si3054_spec *spec = codec->spec; struct hda_pcm *info = &spec->pcm; - si3054_pcm.nid = codec->mfg; codec->num_pcms = 1; codec->pcm_info = info; info->name = "Si3054 Modem"; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm; info->stream[SNDRV_PCM_STREAM_CAPTURE] = si3054_pcm; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->mfg; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = codec->mfg; info->pcm_type = HDA_PCM_TYPE_MODEM; return 0; } @@ -263,7 +264,7 @@ static void si3054_free(struct hda_codec *codec) /* */ -static struct hda_codec_ops si3054_patch_ops = { +static const struct hda_codec_ops si3054_patch_ops = { .build_controls = si3054_build_controls, .build_pcms = si3054_build_pcms, .init = si3054_init, @@ -283,7 +284,7 @@ static int patch_si3054(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_si3054[] = { +static const struct hda_codec_preset snd_hda_preset_si3054[] = { { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 05fcd60cc46f..7f81cc2274f3 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -217,15 +217,15 @@ struct sigmatel_spec { unsigned int stream_delay; /* analog loopback */ - struct snd_kcontrol_new *aloopback_ctl; + const struct snd_kcontrol_new *aloopback_ctl; unsigned char aloopback_mask; unsigned char aloopback_shift; /* power management */ unsigned int num_pwrs; - unsigned int *pwr_mapping; - hda_nid_t *pwr_nids; - hda_nid_t *dac_list; + const unsigned int *pwr_mapping; + const hda_nid_t *pwr_nids; + const hda_nid_t *dac_list; /* events */ struct snd_array events; @@ -241,20 +241,20 @@ struct sigmatel_spec { int volume_offset; /* capture */ - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; unsigned int num_adcs; - hda_nid_t *mux_nids; + const hda_nid_t *mux_nids; unsigned int num_muxes; - hda_nid_t *dmic_nids; + const hda_nid_t *dmic_nids; unsigned int num_dmics; - hda_nid_t *dmux_nids; + const hda_nid_t *dmux_nids; unsigned int num_dmuxes; - hda_nid_t *smux_nids; + const hda_nid_t *smux_nids; unsigned int num_smuxes; unsigned int num_analog_muxes; - unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ - unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ + const unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ + const unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ unsigned int num_caps; /* number of capture volume/switch elements */ struct sigmatel_mic_route ext_mic; @@ -269,12 +269,12 @@ struct sigmatel_spec { hda_nid_t digbeep_nid; /* pin widgets */ - hda_nid_t *pin_nids; + const hda_nid_t *pin_nids; unsigned int num_pins; /* codec specific stuff */ - struct hda_verb *init; - struct snd_kcontrol_new *mixer; + const struct hda_verb *init; + const struct snd_kcontrol_new *mixer; /* capture source */ struct hda_input_mux *dinput_mux; @@ -317,52 +317,52 @@ struct sigmatel_spec { hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; }; -static hda_nid_t stac9200_adc_nids[1] = { +static const hda_nid_t stac9200_adc_nids[1] = { 0x03, }; -static hda_nid_t stac9200_mux_nids[1] = { +static const hda_nid_t stac9200_mux_nids[1] = { 0x0c, }; -static hda_nid_t stac9200_dac_nids[1] = { +static const hda_nid_t stac9200_dac_nids[1] = { 0x02, }; -static hda_nid_t stac92hd73xx_pwr_nids[8] = { +static const hda_nid_t stac92hd73xx_pwr_nids[8] = { 0x0a, 0x0b, 0x0c, 0xd, 0x0e, 0x0f, 0x10, 0x11 }; -static hda_nid_t stac92hd73xx_slave_dig_outs[2] = { +static const hda_nid_t stac92hd73xx_slave_dig_outs[2] = { 0x26, 0, }; -static hda_nid_t stac92hd73xx_adc_nids[2] = { +static const hda_nid_t stac92hd73xx_adc_nids[2] = { 0x1a, 0x1b }; #define STAC92HD73XX_NUM_DMICS 2 -static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { +static const hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { 0x13, 0x14, 0 }; #define STAC92HD73_DAC_COUNT 5 -static hda_nid_t stac92hd73xx_mux_nids[2] = { +static const hda_nid_t stac92hd73xx_mux_nids[2] = { 0x20, 0x21, }; -static hda_nid_t stac92hd73xx_dmux_nids[2] = { +static const hda_nid_t stac92hd73xx_dmux_nids[2] = { 0x20, 0x21, }; -static hda_nid_t stac92hd73xx_smux_nids[2] = { +static const hda_nid_t stac92hd73xx_smux_nids[2] = { 0x22, 0x23, }; #define STAC92HD73XX_NUM_CAPS 2 -static unsigned long stac92hd73xx_capvols[] = { +static const unsigned long stac92hd73xx_capvols[] = { HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), }; @@ -370,137 +370,141 @@ static unsigned long stac92hd73xx_capvols[] = { #define STAC92HD83_DAC_COUNT 3 -static hda_nid_t stac92hd83xxx_pwr_nids[4] = { +static const hda_nid_t stac92hd83xxx_pwr_nids[4] = { 0xa, 0xb, 0xd, 0xe, }; -static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = { +static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = { 0x1e, 0, }; -static unsigned int stac92hd83xxx_pwr_mapping[4] = { +static const unsigned int stac92hd83xxx_pwr_mapping[4] = { 0x03, 0x0c, 0x20, 0x40, }; -static hda_nid_t stac92hd83xxx_dmic_nids[] = { +static const hda_nid_t stac92hd83xxx_dmic_nids[] = { 0x11, 0x20, }; -static hda_nid_t stac92hd71bxx_pwr_nids[3] = { +static const hda_nid_t stac92hd71bxx_pwr_nids[3] = { 0x0a, 0x0d, 0x0f }; -static hda_nid_t stac92hd71bxx_adc_nids[2] = { +static const hda_nid_t stac92hd71bxx_adc_nids[2] = { 0x12, 0x13, }; -static hda_nid_t stac92hd71bxx_mux_nids[2] = { +static const hda_nid_t stac92hd71bxx_mux_nids[2] = { 0x1a, 0x1b }; -static hda_nid_t stac92hd71bxx_dmux_nids[2] = { +static const hda_nid_t stac92hd71bxx_dmux_nids[2] = { 0x1c, 0x1d, }; -static hda_nid_t stac92hd71bxx_smux_nids[2] = { +static const hda_nid_t stac92hd71bxx_smux_nids[2] = { 0x24, 0x25, }; #define STAC92HD71BXX_NUM_DMICS 2 -static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { +static const hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { 0x18, 0x19, 0 }; -static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = { +static const hda_nid_t stac92hd71bxx_dmic_5port_nids[STAC92HD71BXX_NUM_DMICS] = { + 0x18, 0 +}; + +static const hda_nid_t stac92hd71bxx_slave_dig_outs[2] = { 0x22, 0 }; #define STAC92HD71BXX_NUM_CAPS 2 -static unsigned long stac92hd71bxx_capvols[] = { +static const unsigned long stac92hd71bxx_capvols[] = { HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), }; #define stac92hd71bxx_capsws stac92hd71bxx_capvols -static hda_nid_t stac925x_adc_nids[1] = { +static const hda_nid_t stac925x_adc_nids[1] = { 0x03, }; -static hda_nid_t stac925x_mux_nids[1] = { +static const hda_nid_t stac925x_mux_nids[1] = { 0x0f, }; -static hda_nid_t stac925x_dac_nids[1] = { +static const hda_nid_t stac925x_dac_nids[1] = { 0x02, }; #define STAC925X_NUM_DMICS 1 -static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { +static const hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { 0x15, 0 }; -static hda_nid_t stac925x_dmux_nids[1] = { +static const hda_nid_t stac925x_dmux_nids[1] = { 0x14, }; -static unsigned long stac925x_capvols[] = { +static const unsigned long stac925x_capvols[] = { HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), }; -static unsigned long stac925x_capsws[] = { +static const unsigned long stac925x_capsws[] = { HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }; -static hda_nid_t stac922x_adc_nids[2] = { +static const hda_nid_t stac922x_adc_nids[2] = { 0x06, 0x07, }; -static hda_nid_t stac922x_mux_nids[2] = { +static const hda_nid_t stac922x_mux_nids[2] = { 0x12, 0x13, }; #define STAC922X_NUM_CAPS 2 -static unsigned long stac922x_capvols[] = { +static const unsigned long stac922x_capvols[] = { HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT), HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), }; #define stac922x_capsws stac922x_capvols -static hda_nid_t stac927x_slave_dig_outs[2] = { +static const hda_nid_t stac927x_slave_dig_outs[2] = { 0x1f, 0, }; -static hda_nid_t stac927x_adc_nids[3] = { +static const hda_nid_t stac927x_adc_nids[3] = { 0x07, 0x08, 0x09 }; -static hda_nid_t stac927x_mux_nids[3] = { +static const hda_nid_t stac927x_mux_nids[3] = { 0x15, 0x16, 0x17 }; -static hda_nid_t stac927x_smux_nids[1] = { +static const hda_nid_t stac927x_smux_nids[1] = { 0x21, }; -static hda_nid_t stac927x_dac_nids[6] = { +static const hda_nid_t stac927x_dac_nids[6] = { 0x02, 0x03, 0x04, 0x05, 0x06, 0 }; -static hda_nid_t stac927x_dmux_nids[1] = { +static const hda_nid_t stac927x_dmux_nids[1] = { 0x1b, }; #define STAC927X_NUM_DMICS 2 -static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = { +static const hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = { 0x13, 0x14, 0 }; #define STAC927X_NUM_CAPS 3 -static unsigned long stac927x_capvols[] = { +static const unsigned long stac927x_capvols[] = { HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT), HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT), }; -static unsigned long stac927x_capsws[] = { +static const unsigned long stac927x_capsws[] = { HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), @@ -511,77 +515,77 @@ static const char * const stac927x_spdif_labels[5] = { "Analog Mux 2", "Analog Mux 3" }; -static hda_nid_t stac9205_adc_nids[2] = { +static const hda_nid_t stac9205_adc_nids[2] = { 0x12, 0x13 }; -static hda_nid_t stac9205_mux_nids[2] = { +static const hda_nid_t stac9205_mux_nids[2] = { 0x19, 0x1a }; -static hda_nid_t stac9205_dmux_nids[1] = { +static const hda_nid_t stac9205_dmux_nids[1] = { 0x1d, }; -static hda_nid_t stac9205_smux_nids[1] = { +static const hda_nid_t stac9205_smux_nids[1] = { 0x21, }; #define STAC9205_NUM_DMICS 2 -static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { +static const hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { 0x17, 0x18, 0 }; #define STAC9205_NUM_CAPS 2 -static unsigned long stac9205_capvols[] = { +static const unsigned long stac9205_capvols[] = { HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT), HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT), }; -static unsigned long stac9205_capsws[] = { +static const unsigned long stac9205_capsws[] = { HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT), }; -static hda_nid_t stac9200_pin_nids[8] = { +static const hda_nid_t stac9200_pin_nids[8] = { 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, }; -static hda_nid_t stac925x_pin_nids[8] = { +static const hda_nid_t stac925x_pin_nids[8] = { 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x11, }; -static hda_nid_t stac922x_pin_nids[10] = { +static const hda_nid_t stac922x_pin_nids[10] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x15, 0x1b, }; -static hda_nid_t stac92hd73xx_pin_nids[13] = { +static const hda_nid_t stac92hd73xx_pin_nids[13] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x22, 0x23 }; #define STAC92HD71BXX_NUM_PINS 13 -static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { +static const hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x14, 0x18, 0x19, 0x1e, 0x1f, 0x20, 0x27 }; -static hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = { +static const hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x14, 0x18, 0x19, 0x1e, 0x1f, 0x20, 0x27 }; -static hda_nid_t stac927x_pin_nids[14] = { +static const hda_nid_t stac927x_pin_nids[14] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, }; -static hda_nid_t stac9205_pin_nids[12] = { +static const hda_nid_t stac9205_pin_nids[12] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x14, 0x16, 0x17, 0x18, 0x21, 0x22, @@ -841,45 +845,45 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, return 1; } -static struct hda_verb stac9200_core_init[] = { +static const struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, {} }; -static struct hda_verb stac9200_eapd_init[] = { +static const struct hda_verb stac9200_eapd_init[] = { /* set dac0mux for dac converter */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, {} }; -static struct hda_verb dell_eq_core_init[] = { +static const struct hda_verb dell_eq_core_init[] = { /* set master volume to max value without distortion * and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec}, {} }; -static struct hda_verb stac92hd73xx_core_init[] = { +static const struct hda_verb stac92hd73xx_core_init[] = { /* set master volume and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, {} }; -static struct hda_verb stac92hd83xxx_core_init[] = { +static const struct hda_verb stac92hd83xxx_core_init[] = { /* power state controls amps */ { 0x01, AC_VERB_SET_EAPD, 1 << 2}, {} }; -static struct hda_verb stac92hd71bxx_core_init[] = { +static const struct hda_verb stac92hd71bxx_core_init[] = { /* set master volume and direct control */ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, {} }; -static struct hda_verb stac92hd71bxx_unmute_core_init[] = { +static const struct hda_verb stac92hd71bxx_unmute_core_init[] = { /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */ { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -887,7 +891,7 @@ static struct hda_verb stac92hd71bxx_unmute_core_init[] = { {} }; -static struct hda_verb stac925x_core_init[] = { +static const struct hda_verb stac925x_core_init[] = { /* set dac0mux for dac converter */ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, /* mute the master volume */ @@ -895,13 +899,13 @@ static struct hda_verb stac925x_core_init[] = { {} }; -static struct hda_verb stac922x_core_init[] = { +static const struct hda_verb stac922x_core_init[] = { /* set master volume and direct control */ { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, {} }; -static struct hda_verb d965_core_init[] = { +static const struct hda_verb d965_core_init[] = { /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* unmute node 0x1b */ @@ -911,7 +915,7 @@ static struct hda_verb d965_core_init[] = { {} }; -static struct hda_verb dell_3st_core_init[] = { +static const struct hda_verb dell_3st_core_init[] = { /* don't set delta bit */ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f}, /* unmute node 0x1b */ @@ -921,7 +925,7 @@ static struct hda_verb dell_3st_core_init[] = { {} }; -static struct hda_verb stac927x_core_init[] = { +static const struct hda_verb stac927x_core_init[] = { /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* enable analog pc beep path */ @@ -929,7 +933,7 @@ static struct hda_verb stac927x_core_init[] = { {} }; -static struct hda_verb stac927x_volknob_core_init[] = { +static const struct hda_verb stac927x_volknob_core_init[] = { /* don't set delta bit */ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f}, /* enable analog pc beep path */ @@ -937,7 +941,7 @@ static struct hda_verb stac927x_volknob_core_init[] = { {} }; -static struct hda_verb stac9205_core_init[] = { +static const struct hda_verb stac9205_core_init[] = { /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* enable analog pc beep path */ @@ -977,7 +981,7 @@ static struct hda_verb stac9205_core_init[] = { .private_value = nid, \ } -static struct snd_kcontrol_new stac9200_mixer[] = { +static const struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), @@ -985,38 +989,38 @@ static struct snd_kcontrol_new stac9200_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = { +static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), {} }; -static struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = { +static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4), {} }; -static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = { +static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5), {} }; -static struct snd_kcontrol_new stac92hd71bxx_loopback[] = { +static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2) }; -static struct snd_kcontrol_new stac925x_mixer[] = { +static const struct snd_kcontrol_new stac925x_mixer[] = { HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT), { } /* end */ }; -static struct snd_kcontrol_new stac9205_loopback[] = { +static const struct snd_kcontrol_new stac9205_loopback[] = { STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1), {} }; -static struct snd_kcontrol_new stac927x_loopback[] = { +static const struct snd_kcontrol_new stac927x_loopback[] = { STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1), {} }; @@ -1182,16 +1186,16 @@ static int stac92xx_build_controls(struct hda_codec *codec) return 0; } -static unsigned int ref9200_pin_configs[8] = { +static const unsigned int ref9200_pin_configs[8] = { 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; -static unsigned int gateway9200_m4_pin_configs[8] = { +static const unsigned int gateway9200_m4_pin_configs[8] = { 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, }; -static unsigned int gateway9200_m4_2_pin_configs[8] = { +static const unsigned int gateway9200_m4_2_pin_configs[8] = { 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, }; @@ -1202,7 +1206,7 @@ static unsigned int gateway9200_m4_2_pin_configs[8] = { 102801DE 102801E8 */ -static unsigned int dell9200_d21_pin_configs[8] = { +static const unsigned int dell9200_d21_pin_configs[8] = { 0x400001f0, 0x400001f1, 0x02214030, 0x01014010, 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; @@ -1212,7 +1216,7 @@ static unsigned int dell9200_d21_pin_configs[8] = { 102801C0 102801C1 */ -static unsigned int dell9200_d22_pin_configs[8] = { +static const unsigned int dell9200_d22_pin_configs[8] = { 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 0x01813020, 0x02a19021, 0x90100140, 0x400001f2, }; @@ -1226,7 +1230,7 @@ static unsigned int dell9200_d22_pin_configs[8] = { 102801DA 102801E3 */ -static unsigned int dell9200_d23_pin_configs[8] = { +static const unsigned int dell9200_d23_pin_configs[8] = { 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 0x01813020, 0x01a19021, 0x90100140, 0x400001f2, }; @@ -1237,7 +1241,7 @@ static unsigned int dell9200_d23_pin_configs[8] = { 102801B5 (Dell Inspiron 630m) 102801D8 (Dell Inspiron 640m) */ -static unsigned int dell9200_m21_pin_configs[8] = { +static const unsigned int dell9200_m21_pin_configs[8] = { 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310, 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd, }; @@ -1250,7 +1254,7 @@ static unsigned int dell9200_m21_pin_configs[8] = { 102801D4 102801D6 */ -static unsigned int dell9200_m22_pin_configs[8] = { +static const unsigned int dell9200_m22_pin_configs[8] = { 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc, }; @@ -1260,7 +1264,7 @@ static unsigned int dell9200_m22_pin_configs[8] = { 102801CE (Dell XPS M1710) 102801CF (Dell Precision M90) */ -static unsigned int dell9200_m23_pin_configs[8] = { +static const unsigned int dell9200_m23_pin_configs[8] = { 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310, 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc, }; @@ -1272,7 +1276,7 @@ static unsigned int dell9200_m23_pin_configs[8] = { 102801CB (Dell Latitude 120L) 102801D3 */ -static unsigned int dell9200_m24_pin_configs[8] = { +static const unsigned int dell9200_m24_pin_configs[8] = { 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, }; @@ -1283,7 +1287,7 @@ static unsigned int dell9200_m24_pin_configs[8] = { 102801EE 102801EF */ -static unsigned int dell9200_m25_pin_configs[8] = { +static const unsigned int dell9200_m25_pin_configs[8] = { 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd, }; @@ -1293,7 +1297,7 @@ static unsigned int dell9200_m25_pin_configs[8] = { 102801F5 (Dell Inspiron 1501) 102801F6 */ -static unsigned int dell9200_m26_pin_configs[8] = { +static const unsigned int dell9200_m26_pin_configs[8] = { 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe, }; @@ -1302,18 +1306,18 @@ static unsigned int dell9200_m26_pin_configs[8] = { STAC 9200-32 102801CD (Dell Inspiron E1705/9400) */ -static unsigned int dell9200_m27_pin_configs[8] = { +static const unsigned int dell9200_m27_pin_configs[8] = { 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc, }; -static unsigned int oqo9200_pin_configs[8] = { +static const unsigned int oqo9200_pin_configs[8] = { 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210, 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3, }; -static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { +static const unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { [STAC_REF] = ref9200_pin_configs, [STAC_9200_OQO] = oqo9200_pin_configs, [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, @@ -1350,7 +1354,7 @@ static const char * const stac9200_models[STAC_9200_MODELS] = { [STAC_9200_PANASONIC] = "panasonic", }; -static struct snd_pci_quirk stac9200_cfg_tbl[] = { +static const struct snd_pci_quirk stac9200_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), @@ -1426,47 +1430,47 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref925x_pin_configs[8] = { +static const unsigned int ref925x_pin_configs[8] = { 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, 0x90a70320, 0x02214210, 0x01019020, 0x9033032e, }; -static unsigned int stac925xM1_pin_configs[8] = { +static const unsigned int stac925xM1_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM1_2_pin_configs[8] = { +static const unsigned int stac925xM1_2_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM2_pin_configs[8] = { +static const unsigned int stac925xM2_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM2_2_pin_configs[8] = { +static const unsigned int stac925xM2_2_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM3_pin_configs[8] = { +static const unsigned int stac925xM3_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3, }; -static unsigned int stac925xM5_pin_configs[8] = { +static const unsigned int stac925xM5_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, }; -static unsigned int stac925xM6_pin_configs[8] = { +static const unsigned int stac925xM6_pin_configs[8] = { 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, 0x40a000f0, 0x90100210, 0x400003f1, 0x90330320, }; -static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { +static const unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { [STAC_REF] = ref925x_pin_configs, [STAC_M1] = stac925xM1_pin_configs, [STAC_M1_2] = stac925xM1_2_pin_configs, @@ -1489,7 +1493,7 @@ static const char * const stac925x_models[STAC_925x_MODELS] = { [STAC_M6] = "m6", }; -static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { +static const struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2), SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5), SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1), @@ -1503,7 +1507,7 @@ static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { {} /* terminator */ }; -static struct snd_pci_quirk stac925x_cfg_tbl[] = { +static const struct snd_pci_quirk stac925x_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), @@ -1515,33 +1519,33 @@ static struct snd_pci_quirk stac925x_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref92hd73xx_pin_configs[13] = { +static const unsigned int ref92hd73xx_pin_configs[13] = { 0x02214030, 0x02a19040, 0x01a19020, 0x02214030, 0x0181302e, 0x01014010, 0x01014020, 0x01014030, 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050, 0x01452050, }; -static unsigned int dell_m6_pin_configs[13] = { +static const unsigned int dell_m6_pin_configs[13] = { 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110, 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, }; -static unsigned int alienware_m17x_pin_configs[13] = { +static const unsigned int alienware_m17x_pin_configs[13] = { 0x0321101f, 0x0321101f, 0x03a11020, 0x03014020, 0x90170110, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0, 0x904601b0, }; -static unsigned int intel_dg45id_pin_configs[13] = { +static const unsigned int intel_dg45id_pin_configs[13] = { 0x02214230, 0x02A19240, 0x01013214, 0x01014210, 0x01A19250, 0x01011212, 0x01016211 }; -static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { +static const unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, [STAC_DELL_M6_AMIC] = dell_m6_pin_configs, [STAC_DELL_M6_DMIC] = dell_m6_pin_configs, @@ -1563,7 +1567,7 @@ static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = { [STAC_ALIENWARE_M17X] = "alienware", }; -static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), @@ -1600,11 +1604,11 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe, "Dell Studio XPS 1645", STAC_DELL_M6_BOTH), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, - "Dell Studio 1558", STAC_DELL_M6_BOTH), + "Dell Studio 1558", STAC_DELL_M6_DMIC), {} /* terminator */ }; -static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1, "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a, @@ -1612,25 +1616,25 @@ static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref92hd83xxx_pin_configs[10] = { +static const unsigned int ref92hd83xxx_pin_configs[10] = { 0x02214030, 0x02211010, 0x02a19020, 0x02170130, 0x01014050, 0x01819040, 0x01014020, 0x90a3014e, 0x01451160, 0x98560170, }; -static unsigned int dell_s14_pin_configs[10] = { +static const unsigned int dell_s14_pin_configs[10] = { 0x0221403f, 0x0221101f, 0x02a19020, 0x90170110, 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a60160, 0x40f000f0, 0x40f000f0, }; -static unsigned int hp_dv7_4000_pin_configs[10] = { +static const unsigned int hp_dv7_4000_pin_configs[10] = { 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110, 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140, 0x40f000f0, 0x40f000f0, }; -static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { +static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, [STAC_DELL_S14] = dell_s14_pin_configs, @@ -1646,7 +1650,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_HP_DV7_4000] = "hp-dv7-4000", }; -static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD83XXX_REF), @@ -1659,35 +1663,35 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = { +static const unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = { 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0, 0x90a000f0, 0x01452050, 0x01452050, 0x00000000, 0x00000000 }; -static unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = { +static const unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = { 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, 0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000, 0x00000000 }; -static unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = { +static const unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = { 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, 0x00000000 }; -static unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = { +static const unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = { 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0, 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, 0x00000000 }; -static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { +static const unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs, [STAC_DELL_M4_1] = dell_m4_1_pin_configs, [STAC_DELL_M4_2] = dell_m4_2_pin_configs, @@ -1712,7 +1716,7 @@ static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr", }; -static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD71BXX_REF), @@ -1769,7 +1773,7 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref922x_pin_configs[10] = { +static const unsigned int ref922x_pin_configs[10] = { 0x01014010, 0x01016011, 0x01012012, 0x0221401f, 0x01813122, 0x01011014, 0x01441030, 0x01c41030, 0x40000100, 0x40000100, @@ -1783,7 +1787,7 @@ static unsigned int ref922x_pin_configs[10] = { 102801D1 102801D2 */ -static unsigned int dell_922x_d81_pin_configs[10] = { +static const unsigned int dell_922x_d81_pin_configs[10] = { 0x02214030, 0x01a19021, 0x01111012, 0x01114010, 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1, 0x01813122, 0x400001f2, @@ -1794,7 +1798,7 @@ static unsigned int dell_922x_d81_pin_configs[10] = { 102801AC 102801D0 */ -static unsigned int dell_922x_d82_pin_configs[10] = { +static const unsigned int dell_922x_d82_pin_configs[10] = { 0x02214030, 0x01a19021, 0x01111012, 0x01114010, 0x02a19020, 0x01117011, 0x01451140, 0x400001f0, 0x01813122, 0x400001f1, @@ -1804,7 +1808,7 @@ static unsigned int dell_922x_d82_pin_configs[10] = { STAC 922X pin configs for 102801BF */ -static unsigned int dell_922x_m81_pin_configs[10] = { +static const unsigned int dell_922x_m81_pin_configs[10] = { 0x0321101f, 0x01112024, 0x01111222, 0x91174220, 0x03a11050, 0x01116221, 0x90a70330, 0x01452340, 0x40C003f1, 0x405003f0, @@ -1814,61 +1818,61 @@ static unsigned int dell_922x_m81_pin_configs[10] = { STAC 9221 A1 pin configs for 102801D7 (Dell XPS M1210) */ -static unsigned int dell_922x_m82_pin_configs[10] = { +static const unsigned int dell_922x_m82_pin_configs[10] = { 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, 0x508003f3, 0x405003f4, }; -static unsigned int d945gtp3_pin_configs[10] = { +static const unsigned int d945gtp3_pin_configs[10] = { 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x02a19120, 0x40000100, }; -static unsigned int d945gtp5_pin_configs[10] = { +static const unsigned int d945gtp5_pin_configs[10] = { 0x0221401f, 0x01011012, 0x01813024, 0x01014010, 0x01a19021, 0x01016011, 0x01452130, 0x40000100, 0x02a19320, 0x40000100, }; -static unsigned int intel_mac_v1_pin_configs[10] = { +static const unsigned int intel_mac_v1_pin_configs[10] = { 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd, 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240, 0x400000fc, 0x400000fb, }; -static unsigned int intel_mac_v2_pin_configs[10] = { +static const unsigned int intel_mac_v2_pin_configs[10] = { 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd, 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa, 0x400000fc, 0x400000fb, }; -static unsigned int intel_mac_v3_pin_configs[10] = { +static const unsigned int intel_mac_v3_pin_configs[10] = { 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd, 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240, 0x400000fc, 0x400000fb, }; -static unsigned int intel_mac_v4_pin_configs[10] = { +static const unsigned int intel_mac_v4_pin_configs[10] = { 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f, 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240, 0x400000fc, 0x400000fb, }; -static unsigned int intel_mac_v5_pin_configs[10] = { +static const unsigned int intel_mac_v5_pin_configs[10] = { 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f, 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240, 0x400000fc, 0x400000fb, }; -static unsigned int ecs202_pin_configs[10] = { +static const unsigned int ecs202_pin_configs[10] = { 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010, 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1, 0x9037012e, 0x40e000f2, }; -static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { +static const unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { [STAC_D945_REF] = ref922x_pin_configs, [STAC_D945GTP3] = d945gtp3_pin_configs, [STAC_D945GTP5] = d945gtp5_pin_configs, @@ -1917,7 +1921,7 @@ static const char * const stac922x_models[STAC_922X_MODELS] = { [STAC_922X_DELL_M82] = "dell-m82", }; -static struct snd_pci_quirk stac922x_cfg_tbl[] = { +static const struct snd_pci_quirk stac922x_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D945_REF), @@ -2008,42 +2012,42 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref927x_pin_configs[14] = { +static const unsigned int ref927x_pin_configs[14] = { 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, 0x01a19040, 0x01011012, 0x01016011, 0x0101201f, 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070, 0x01c42190, 0x40000100, }; -static unsigned int d965_3st_pin_configs[14] = { +static const unsigned int d965_3st_pin_configs[14] = { 0x0221401f, 0x02a19120, 0x40000100, 0x01014011, 0x01a19021, 0x01813024, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x40000100 }; -static unsigned int d965_5st_pin_configs[14] = { +static const unsigned int d965_5st_pin_configs[14] = { 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, 0x01a19040, 0x01011012, 0x01016011, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x01442070, 0x40000100, 0x40000100 }; -static unsigned int d965_5st_no_fp_pin_configs[14] = { +static const unsigned int d965_5st_no_fp_pin_configs[14] = { 0x40000100, 0x40000100, 0x0181304e, 0x01014010, 0x01a19040, 0x01011012, 0x01016011, 0x40000100, 0x40000100, 0x40000100, 0x40000100, 0x01442070, 0x40000100, 0x40000100 }; -static unsigned int dell_3st_pin_configs[14] = { +static const unsigned int dell_3st_pin_configs[14] = { 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, 0x01111212, 0x01116211, 0x01813050, 0x01112214, 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb, 0x40c003fc, 0x40000100 }; -static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { +static const unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { [STAC_D965_REF_NO_JD] = ref927x_pin_configs, [STAC_D965_REF] = ref927x_pin_configs, [STAC_D965_3ST] = d965_3st_pin_configs, @@ -2066,7 +2070,7 @@ static const char * const stac927x_models[STAC_927X_MODELS] = { [STAC_927X_VOLKNOB] = "volknob", }; -static struct snd_pci_quirk stac927x_cfg_tbl[] = { +static const struct snd_pci_quirk stac927x_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D965_REF), @@ -2104,7 +2108,7 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { {} /* terminator */ }; -static unsigned int ref9205_pin_configs[12] = { +static const unsigned int ref9205_pin_configs[12] = { 0x40000100, 0x40000100, 0x01016011, 0x01014010, 0x01813122, 0x01a19021, 0x01019020, 0x40000100, 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 @@ -2121,7 +2125,7 @@ static unsigned int ref9205_pin_configs[12] = { 10280228 (Dell Vostro 1500) 10280229 (Dell Vostro 1700) */ -static unsigned int dell_9205_m42_pin_configs[12] = { +static const unsigned int dell_9205_m42_pin_configs[12] = { 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9, 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE, @@ -2137,19 +2141,19 @@ static unsigned int dell_9205_m42_pin_configs[12] = { 10280200 10280201 */ -static unsigned int dell_9205_m43_pin_configs[12] = { +static const unsigned int dell_9205_m43_pin_configs[12] = { 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310, 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9, 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8, }; -static unsigned int dell_9205_m44_pin_configs[12] = { +static const unsigned int dell_9205_m44_pin_configs[12] = { 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, }; -static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { +static const unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { [STAC_9205_REF] = ref9205_pin_configs, [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, @@ -2166,7 +2170,7 @@ static const char * const stac9205_models[STAC_9205_MODELS] = { [STAC_9205_EAPD] = "eapd", }; -static struct snd_pci_quirk stac9205_cfg_tbl[] = { +static const struct snd_pci_quirk stac9205_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), @@ -2214,7 +2218,7 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { }; static void stac92xx_set_config_regs(struct hda_codec *codec, - unsigned int *pincfgs) + const unsigned int *pincfgs) { int i; struct sigmatel_spec *spec = codec->spec; @@ -2334,7 +2338,7 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream stac92xx_pcm_digital_playback = { +static const struct hda_pcm_stream stac92xx_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2347,14 +2351,14 @@ static struct hda_pcm_stream stac92xx_pcm_digital_playback = { }, }; -static struct hda_pcm_stream stac92xx_pcm_digital_capture = { +static const struct hda_pcm_stream stac92xx_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in stac92xx_build_pcms */ }; -static struct hda_pcm_stream stac92xx_pcm_analog_playback = { +static const struct hda_pcm_stream stac92xx_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, @@ -2366,7 +2370,7 @@ static struct hda_pcm_stream stac92xx_pcm_analog_playback = { }, }; -static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { +static const struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2378,7 +2382,7 @@ static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { }, }; -static struct hda_pcm_stream stac92xx_pcm_analog_capture = { +static const struct hda_pcm_stream stac92xx_pcm_analog_capture = { .channels_min = 2, .channels_max = 2, /* NID + .substreams is set in stac92xx_build_pcms */ @@ -2475,7 +2479,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; - /* check to be sure that the ports are upto date with + /* check to be sure that the ports are up to date with * switch changes */ stac_issue_unsol_event(codec, nid); @@ -2487,7 +2491,7 @@ static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int i; - static char *texts[] = { + static const char * const texts[] = { "Mic In", "Line In", "Line Out" }; @@ -2556,7 +2560,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2]; + char *texts[2]; struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; @@ -2687,7 +2691,7 @@ enum { STAC_CTL_WIDGET_DC_BIAS }; -static struct snd_kcontrol_new stac92xx_control_templates[] = { +static const struct snd_kcontrol_new stac92xx_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0), @@ -2701,7 +2705,7 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { /* add dynamic controls */ static struct snd_kcontrol_new * stac_control_new(struct sigmatel_spec *spec, - struct snd_kcontrol_new *ktemp, + const struct snd_kcontrol_new *ktemp, const char *name, unsigned int subdev) { @@ -2724,7 +2728,7 @@ stac_control_new(struct sigmatel_spec *spec, } static int stac92xx_add_control_temp(struct sigmatel_spec *spec, - struct snd_kcontrol_new *ktemp, + const struct snd_kcontrol_new *ktemp, int idx, const char *name, unsigned long val) { @@ -2754,7 +2758,7 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type, return stac92xx_add_control_idx(spec, type, 0, name, val); } -static struct snd_kcontrol_new stac_input_src_temp = { +static const struct snd_kcontrol_new stac_input_src_temp = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Source", .info = stac92xx_mux_enum_info, @@ -3072,7 +3076,8 @@ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); return 1; } else { - spec->multiout.dac_nids[spec->multiout.num_dacs] = nid; + snd_BUG_ON(spec->multiout.dac_nids != spec->dac_nids); + spec->dac_nids[spec->multiout.num_dacs] = nid; spec->multiout.num_dacs++; } return 0; @@ -3109,8 +3114,7 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) { if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) { - wid_caps = get_wcaps(codec, pins[i]); - if (wid_caps & AC_WCAP_UNSOL_CAP) + if (is_jack_detectable(codec, pins[i])) spec->hp_detect = 1; } nid = dac_nids[i]; @@ -3309,7 +3313,7 @@ static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol, return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]); } -static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { +static const struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = stac92xx_dig_beep_switch_info, .get = stac92xx_dig_beep_switch_get, @@ -3408,6 +3412,9 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, hda_nid_t conn[HDA_MAX_NUM_INPUTS]; int i, nums; + if (!(get_wcaps(codec, mux) & AC_WCAP_CONN_LIST)) + return -1; + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); for (i = 0; i < nums; i++) if (conn[i] == nid) @@ -3513,14 +3520,18 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock) { unsigned int cfg; + unsigned int type; if (!nid) return 0; cfg = snd_hda_codec_get_pincfg(codec, nid); + type = get_defcfg_device(cfg); switch (snd_hda_get_input_pin_attr(cfg)) { case INPUT_PIN_ATTR_INT: if (*fixed) return 1; /* already occupied */ + if (type != AC_JACK_MIC_IN) + return 1; /* invalid type */ *fixed = nid; break; case INPUT_PIN_ATTR_UNUSED: @@ -3528,11 +3539,15 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, case INPUT_PIN_ATTR_DOCK: if (*dock) return 1; /* already occupied */ + if (type != AC_JACK_MIC_IN && type != AC_JACK_LINE_IN) + return 1; /* invalid type */ *dock = nid; break; default: if (*ext) return 1; /* already occupied */ + if (type != AC_JACK_MIC_IN) + return 1; /* invalid type */ *ext = nid; break; } @@ -3588,10 +3603,6 @@ static int stac_check_auto_mic(struct hda_codec *codec) hda_nid_t fixed, ext, dock; int i; - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN) - return 0; /* must be exclusively mics */ - } fixed = ext = dock = 0; for (i = 0; i < cfg->num_inputs; i++) if (check_mic_pin(codec, cfg->inputs[i].pin, @@ -3603,7 +3614,7 @@ static int stac_check_auto_mic(struct hda_codec *codec) return 0; if (!fixed || (!ext && !dock)) return 0; /* no input to switch */ - if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) + if (!is_jack_detectable(codec, ext)) return 0; /* no unsol support */ if (set_mic_route(codec, &spec->ext_mic, ext) || set_mic_route(codec, &spec->int_mic, fixed) || @@ -3918,13 +3929,11 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, { struct sigmatel_spec *spec = codec->spec; hda_nid_t pin = cfg->hp_pins[0]; - unsigned int wid_caps; if (! pin) return 0; - wid_caps = get_wcaps(codec, pin); - if (wid_caps & AC_WCAP_UNSOL_CAP) + if (is_jack_detectable(codec, pin)) spec->hp_detect = 1; return 0; @@ -4135,7 +4144,7 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, struct sigmatel_event *event; int tag; - if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + if (!is_jack_detectable(codec, nid)) return 0; event = stac_get_event(codec, nid); if (event) { @@ -4168,7 +4177,7 @@ static void stac92xx_power_down(struct hda_codec *codec) struct sigmatel_spec *spec = codec->spec; /* power down inactive DACs */ - hda_nid_t *dac; + const hda_nid_t *dac; for (dac = spec->dac_list; *dac; dac++) if (!check_all_dac_nids(spec, *dac)) snd_hda_codec_write(codec, *dac, 0, @@ -4641,7 +4650,7 @@ static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) } static int stac92xx_connected_ports(struct hda_codec *codec, - hda_nid_t *nids, int num_nids) + const hda_nid_t *nids, int num_nids) { struct sigmatel_spec *spec = codec->spec; int idx, num; @@ -4965,7 +4974,7 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) } #endif -static struct hda_codec_ops stac92xx_patch_ops = { +static const struct hda_codec_ops stac92xx_patch_ops = { .build_controls = stac92xx_build_controls, .build_pcms = stac92xx_build_pcms, .init = stac92xx_init, @@ -5585,7 +5594,7 @@ static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { +static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = stac_hp_bass_gpio_info, .get = stac_hp_bass_gpio_get, @@ -5609,7 +5618,7 @@ static int stac_add_hp_bass_switch(struct hda_codec *codec) static int patch_stac92hd71bxx(struct hda_codec *codec) { struct sigmatel_spec *spec; - struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; + const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; unsigned int pin_cfg; int err = 0; @@ -5702,9 +5711,9 @@ again: unmute_init++; snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0); snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3); - stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0; + spec->dmic_nids = stac92hd71bxx_dmic_5port_nids; spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd71bxx_dmic_nids, + stac92hd71bxx_dmic_5port_nids, STAC92HD71BXX_NUM_DMICS - 1); break; case 0x111d7603: /* 6 Port with Analog Mixer */ @@ -5726,15 +5735,6 @@ again: if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) snd_hda_sequence_write_cache(codec, unmute_init); - /* Some HP machines seem to have unstable codec communications - * especially with ATI fglrx driver. For recovering from the - * CORB/RIRB stall, allow the BUS reset and keep always sync - */ - if (spec->board_config == STAC_HP_DV5) { - codec->bus->sync_write = 1; - codec->bus->allow_bus_reset = 1; - } - spec->aloopback_ctl = stac92hd71bxx_loopback; spec->aloopback_mask = 0x50; spec->aloopback_shift = 0; @@ -6220,31 +6220,31 @@ static int patch_stac9205(struct hda_codec *codec) * STAC9872 hack */ -static struct hda_verb stac9872_core_init[] = { +static const struct hda_verb stac9872_core_init[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */ {} }; -static hda_nid_t stac9872_pin_nids[] = { +static const hda_nid_t stac9872_pin_nids[] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x14, }; -static hda_nid_t stac9872_adc_nids[] = { +static const hda_nid_t stac9872_adc_nids[] = { 0x8 /*,0x6*/ }; -static hda_nid_t stac9872_mux_nids[] = { +static const hda_nid_t stac9872_mux_nids[] = { 0x15 }; -static unsigned long stac9872_capvols[] = { +static const unsigned long stac9872_capvols[] = { HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), }; #define stac9872_capsws stac9872_capvols -static unsigned int stac9872_vaio_pin_configs[9] = { +static const unsigned int stac9872_vaio_pin_configs[9] = { 0x03211020, 0x411111f0, 0x411111f0, 0x03a15030, 0x411111f0, 0x90170110, 0x411111f0, 0x411111f0, 0x90a7013e @@ -6255,11 +6255,11 @@ static const char * const stac9872_models[STAC_9872_MODELS] = { [STAC_9872_VAIO] = "vaio", }; -static unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = { +static const unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = { [STAC_9872_VAIO] = stac9872_vaio_pin_configs, }; -static struct snd_pci_quirk stac9872_cfg_tbl[] = { +static const struct snd_pci_quirk stac9872_cfg_tbl[] = { SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0, "Sony VAIO F/S", STAC_9872_VAIO), {} /* terminator */ @@ -6313,7 +6313,7 @@ static int patch_stac9872(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_sigmatel[] = { +static const struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 }, { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x }, { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x }, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 1371b57c11e8..605c99e1e520 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -98,24 +98,30 @@ enum VIA_HDA_CODEC { VT1716S, VT2002P, VT1812, + VT1802, CODEC_TYPES, }; +#define VT2002P_COMPATIBLE(spec) \ + ((spec)->codec_type == VT2002P ||\ + (spec)->codec_type == VT1812 ||\ + (spec)->codec_type == VT1802) + struct via_spec { /* codec parameterization */ - struct snd_kcontrol_new *mixers[6]; + const struct snd_kcontrol_new *mixers[6]; unsigned int num_mixers; - struct hda_verb *init_verbs[5]; + const struct hda_verb *init_verbs[5]; unsigned int num_iverbs; char *stream_name_analog; - struct hda_pcm_stream *stream_analog_playback; - struct hda_pcm_stream *stream_analog_capture; + const struct hda_pcm_stream *stream_analog_playback; + const struct hda_pcm_stream *stream_analog_capture; char *stream_name_digital; - struct hda_pcm_stream *stream_digital_playback; - struct hda_pcm_stream *stream_digital_capture; + const struct hda_pcm_stream *stream_digital_playback; + const struct hda_pcm_stream *stream_digital_capture; /* playback */ struct hda_multi_out multiout; @@ -123,7 +129,7 @@ struct via_spec { /* capture */ unsigned int num_adc_nids; - hda_nid_t *adc_nids; + const hda_nid_t *adc_nids; hda_nid_t mux_nids[3]; hda_nid_t dig_in_nid; hda_nid_t dig_in_pin; @@ -154,6 +160,9 @@ struct via_spec { struct delayed_work vt1708_hp_work; int vt1708_jack_detectect; int vt1708_hp_present; + + void (*set_widgets_power_state)(struct hda_codec *codec); + #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; #endif @@ -218,17 +227,19 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT1812; else if (dev_id == 0x0440) codec_type = VT1708S; + else if ((dev_id & 0xfff) == 0x446) + codec_type = VT1802; else codec_type = UNKNOWN; return codec_type; }; +#define VIA_JACK_EVENT 0x20 #define VIA_HP_EVENT 0x01 #define VIA_GPIO_EVENT 0x02 -#define VIA_JACK_EVENT 0x04 -#define VIA_MONO_EVENT 0x08 -#define VIA_SPEAKER_EVENT 0x10 -#define VIA_BIND_HP_EVENT 0x20 +#define VIA_MONO_EVENT 0x03 +#define VIA_SPEAKER_EVENT 0x04 +#define VIA_BIND_HP_EVENT 0x05 enum { VIA_CTL_WIDGET_VOL, @@ -245,7 +256,6 @@ enum { }; static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); -static void set_jack_power_state(struct hda_codec *codec); static int is_aa_path_mute(struct hda_codec *codec); static void vt1708_start_hp_work(struct via_spec *spec) @@ -271,6 +281,12 @@ static void vt1708_stop_hp_work(struct via_spec *spec) cancel_delayed_work_sync(&spec->vt1708_hp_work); } +static void set_widgets_power_state(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + if (spec->set_widgets_power_state) + spec->set_widgets_power_state(codec); +} static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -278,7 +294,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - set_jack_power_state(codec); + set_widgets_power_state(codec); analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (is_aa_path_mute(codec)) @@ -394,54 +410,54 @@ static int bind_pin_switch_put(struct snd_kcontrol *kcontrol, .put = bind_pin_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } -static struct snd_kcontrol_new via_control_templates[] = { +static const struct snd_kcontrol_new via_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), ANALOG_INPUT_MUTE, BIND_PIN_MUTE, }; -static hda_nid_t vt1708_adc_nids[2] = { +static const hda_nid_t vt1708_adc_nids[2] = { /* ADC1-2 */ 0x15, 0x27 }; -static hda_nid_t vt1709_adc_nids[3] = { +static const hda_nid_t vt1709_adc_nids[3] = { /* ADC1-2 */ 0x14, 0x15, 0x16 }; -static hda_nid_t vt1708B_adc_nids[2] = { +static const hda_nid_t vt1708B_adc_nids[2] = { /* ADC1-2 */ 0x13, 0x14 }; -static hda_nid_t vt1708S_adc_nids[2] = { +static const hda_nid_t vt1708S_adc_nids[2] = { /* ADC1-2 */ 0x13, 0x14 }; -static hda_nid_t vt1702_adc_nids[3] = { +static const hda_nid_t vt1702_adc_nids[3] = { /* ADC1-2 */ 0x12, 0x20, 0x1F }; -static hda_nid_t vt1718S_adc_nids[2] = { +static const hda_nid_t vt1718S_adc_nids[2] = { /* ADC1-2 */ 0x10, 0x11 }; -static hda_nid_t vt1716S_adc_nids[2] = { +static const hda_nid_t vt1716S_adc_nids[2] = { /* ADC1-2 */ 0x13, 0x14 }; -static hda_nid_t vt2002P_adc_nids[2] = { +static const hda_nid_t vt2002P_adc_nids[2] = { /* ADC1-2 */ 0x10, 0x11 }; -static hda_nid_t vt1812_adc_nids[2] = { +static const hda_nid_t vt1812_adc_nids[2] = { /* ADC1-2 */ 0x10, 0x11 }; @@ -471,7 +487,7 @@ static int __via_add_control(struct via_spec *spec, int type, const char *name, __via_add_control(spec, type, name, 0, val) static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, - struct snd_kcontrol_new *tmpl) + const struct snd_kcontrol_new *tmpl) { struct snd_kcontrol_new *knew; @@ -602,482 +618,6 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); } -static void set_jack_power_state(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int imux_is_smixer; - unsigned int parm; - - if (spec->codec_type == VT1702) { - imux_is_smixer = snd_hda_codec_read( - codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; - /* inputs */ - /* PW 1/2/5 (14h/15h/18h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x14, &parm); - set_pin_power_state(codec, 0x15, &parm); - set_pin_power_state(codec, 0x18, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */ - /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW 3/4 (16h/17h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x16, &parm); - set_pin_power_state(codec, 0x17, &parm); - /* MW0 (1ah), AOW 0/1 (10h/1dh) */ - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, - parm); - } else if (spec->codec_type == VT1708B_8CH - || spec->codec_type == VT1708B_4CH - || spec->codec_type == VT1708S) { - /* SW0 (17h) = stereo mixer */ - int is_8ch = spec->codec_type != VT1708B_4CH; - imux_is_smixer = snd_hda_codec_read( - codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) - == ((spec->codec_type == VT1708S) ? 5 : 0); - /* inputs */ - /* PW 1/2/5 (1ah/1bh/1eh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1a, &parm); - set_pin_power_state(codec, 0x1b, &parm); - set_pin_power_state(codec, 0x1e, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* SW0 (17h), AIW 0/1 (13h/14h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW0 (19h), SW1 (18h), AOW1 (11h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x19, &parm); - if (spec->smart51_enabled) - parm = AC_PWRST_D0; - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW6 (22h), SW2 (26h), AOW2 (24h) */ - if (is_8ch) { - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x22, &parm); - if (spec->smart51_enabled) - parm = AC_PWRST_D0; - snd_hda_codec_write(codec, 0x26, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x24, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* PW 3/4/7 (1ch/1dh/23h) */ - parm = AC_PWRST_D3; - /* force to D0 for internal Speaker */ - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - if (is_8ch) - set_pin_power_state(codec, 0x23, &parm); - /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - if (is_8ch) { - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x27, 0, - AC_VERB_SET_POWER_STATE, parm); - } - } else if (spec->codec_type == VT1718S) { - /* MUX6 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x27, &parm); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW2 (26h), AOW2 (ah) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x26, &parm); - snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW0/1 (24h/25h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - set_pin_power_state(codec, 0x25, &parm); - if (!spec->hp_independent_mode) /* check for redirected HP */ - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, - parm); - /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ - snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - if (spec->hp_independent_mode) { - /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x1b, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0xc, 0, - AC_VERB_SET_POWER_STATE, parm); - } - } else if (spec->codec_type == VT1716S) { - unsigned int mono_out, present; - /* SW0 (17h) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 1/2/5 (1ah/1bh/1eh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1a, &parm); - set_pin_power_state(codec, 0x1b, &parm); - set_pin_power_state(codec, 0x1e, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* SW0 (17h), AIW0(13h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1e, &parm); - /* PW11 (22h) */ - if (spec->dmic_enabled) - set_pin_power_state(codec, 0x22, &parm); - else - snd_hda_codec_write( - codec, 0x22, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - - /* SW2(26h), AIW1(14h) */ - snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW0 (19h), SW1 (18h), AOW1 (11h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x19, &parm); - /* Smart 5.1 PW2(1bh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1b, &parm); - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW7 (23h), SW3 (27h), AOW3 (25h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x23, &parm); - /* Smart 5.1 PW1(1ah) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1a, &parm); - snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* Smart 5.1 PW5(1eh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1e, &parm); - snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* Mono out */ - /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ - present = snd_hda_jack_detect(codec, 0x1c); - if (present) - mono_out = 0; - else { - present = snd_hda_jack_detect(codec, 0x1d); - if (!spec->hp_independent_mode && present) - mono_out = 0; - else - mono_out = 1; - } - parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; - snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW 3/4 (1ch/1dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - /* HP Independent Mode, power on AOW3 */ - if (spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* force to D0 for internal Speaker */ - /* MW0 (16h), AOW0 (10h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - mono_out ? AC_PWRST_D0 : parm); - } else if (spec->codec_type == VT2002P) { - unsigned int present; - /* MUX9 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* outputs */ - /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - - /* PW4 (26h), MW4 (1ch), MUX4(37h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x26, &parm); - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x37, - 0, AC_VERB_SET_POWER_STATE, parm); - - /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x19, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); - if (spec->hp_independent_mode) { - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* Class-D */ - /* PW0 (24h), MW0(18h), MUX0(34h) */ - present = snd_hda_jack_detect(codec, 0x25); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - if (present) { - snd_hda_codec_write( - codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write( - codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else { - snd_hda_codec_write( - codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write( - codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - - /* Mono Out */ - /* PW15 (31h), MW8(17h), MUX8(3bh) */ - present = snd_hda_jack_detect(codec, 0x26); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x31, &parm); - if (present) { - snd_hda_codec_write( - codec, 0x17, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write( - codec, 0x3b, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else { - snd_hda_codec_write( - codec, 0x17, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write( - codec, 0x3b, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - - /* MW9 (21h) */ - if (imux_is_smixer || !is_aa_path_mute(codec)) - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - else - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else if (spec->codec_type == VT1812) { - unsigned int present; - /* MUX10 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* outputs */ - /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - - /* PW4 (28h), MW4 (18h), MUX4(38h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x38, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x15, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); - if (spec->hp_independent_mode) { - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* Internal Speaker */ - /* PW0 (24h), MW0(14h), MUX0(34h) */ - present = snd_hda_jack_detect(codec, 0x25); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - if (present) { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - } else { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - } - /* Mono Out */ - /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ - present = snd_hda_jack_detect(codec, 0x28); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x31, &parm); - if (present) { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - } else { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - } - - /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x33, &parm); - snd_hda_codec_write(codec, 0x1d, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x3d, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* MW9 (21h) */ - if (imux_is_smixer || !is_aa_path_mute(codec)) - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - else - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } -} - /* * input MUX handling */ @@ -1120,7 +660,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); /* update jack power state */ - set_jack_power_state(codec); + set_widgets_power_state(codec); return ret; } @@ -1168,6 +708,9 @@ static hda_nid_t side_mute_channel(struct via_spec *spec) case VT1709_10CH: return 0x29; case VT1708B_8CH: /* fall thru */ case VT1708S: return 0x27; + case VT2002P: return 0x19; + case VT1802: return 0x15; + case VT1812: return 0x15; default: return 0; } } @@ -1176,13 +719,22 @@ static int update_side_mute_status(struct hda_codec *codec) { /* mute side channel */ struct via_spec *spec = codec->spec; - unsigned int parm = spec->hp_independent_mode - ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; + unsigned int parm; hda_nid_t sw3 = side_mute_channel(spec); - if (sw3) - snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, - parm); + if (sw3) { + if (VT2002P_COMPATIBLE(spec)) + parm = spec->hp_independent_mode ? + AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1); + else + parm = spec->hp_independent_mode ? + AMP_OUT_MUTE : AMP_OUT_UNMUTE; + snd_hda_codec_write(codec, sw3, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + if (spec->codec_type == VT1812) + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + } return 0; } @@ -1217,19 +769,18 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, || spec->codec_type == VT1702 || spec->codec_type == VT1718S || spec->codec_type == VT1716S - || spec->codec_type == VT2002P - || spec->codec_type == VT1812) { + || VT2002P_COMPATIBLE(spec)) { activate_ctl(codec, "Headphone Playback Volume", spec->hp_independent_mode); activate_ctl(codec, "Headphone Playback Switch", spec->hp_independent_mode); } /* update jack power state */ - set_jack_power_state(codec); + set_widgets_power_state(codec); return 0; } -static struct snd_kcontrol_new via_hp_mixer[2] = { +static const struct snd_kcontrol_new via_hp_mixer[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Independent HP", @@ -1256,6 +807,7 @@ static int via_hp_build(struct hda_codec *codec) nid = 0x34; break; case VT2002P: + case VT1802: nid = 0x35; break; case VT1812: @@ -1292,14 +844,18 @@ static void notify_aa_path_ctls(struct hda_codec *codec) { int i; struct snd_ctl_elem_id id; - const char *labels[] = {"Mic", "Front Mic", "Line"}; + const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"}; + struct snd_kcontrol *ctl; memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; for (i = 0; i < ARRAY_SIZE(labels); i++) { sprintf(id.name, "%s Playback Volume", labels[i]); - snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, - &id); + ctl = snd_hda_find_mixer_ctl(codec, id.name); + if (ctl) + snd_ctl_notify(codec->bus->card, + SNDRV_CTL_EVENT_MASK_VALUE, + &ctl->id); } } @@ -1443,11 +999,11 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, } } spec->smart51_enabled = *ucontrol->value.integer.value; - set_jack_power_state(codec); + set_widgets_power_state(codec); return 1; } -static struct snd_kcontrol_new via_smart51_mixer[2] = { +static const struct snd_kcontrol_new via_smart51_mixer[2] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Smart 5.1", @@ -1469,6 +1025,11 @@ static int via_smart51_build(struct via_spec *spec) hda_nid_t nid; int i; + if (!cfg) + return 0; + if (cfg->line_outs > 2) + return 0; + knew = via_clone_control(spec, &via_smart51_mixer[0]); if (knew == NULL) return -ENOMEM; @@ -1488,7 +1049,7 @@ static int via_smart51_build(struct via_spec *spec) } /* capture mixer elements */ -static struct snd_kcontrol_new vt1708_capture_mixer[] = { +static const struct snd_kcontrol_new vt1708_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT), @@ -1539,6 +1100,7 @@ static int is_aa_path_mute(struct hda_codec *codec) break; case VT2002P: case VT1812: + case VT1802: nid_mixer = 0x21; start_idx = 0; end_idx = 2; @@ -1603,6 +1165,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) break; case VT2002P: case VT1812: + case VT1802: verb = 0xf93; parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ break; @@ -1616,7 +1179,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1708_volume_init_verbs[] = { +static const struct hda_verb vt1708_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -1646,6 +1209,8 @@ static struct hda_verb vt1708_volume_init_verbs[] = { {0x20, AC_VERB_SET_CONNECT_SEL, 0}, /* PW9 Output enable */ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* power down jack detect function */ + {0x1, 0xf81, 0x1}, { } }; @@ -1668,7 +1233,7 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec, { struct via_spec *spec = codec->spec; struct hda_multi_out *mout = &spec->multiout; - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int chs = substream->runtime->channels; int i; @@ -1737,7 +1302,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, { struct via_spec *spec = codec->spec; struct hda_multi_out *mout = &spec->multiout; - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; if (substream->number == 0) playback_multi_pcm_prep_0(codec, stream_tag, format, @@ -1758,7 +1323,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, { struct via_spec *spec = codec->spec; struct hda_multi_out *mout = &spec->multiout; - hda_nid_t *nids = mout->dac_nids; + const hda_nid_t *nids = mout->dac_nids; int i; if (substream->number == 0) { @@ -1856,7 +1421,7 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream vt1708_pcm_analog_playback = { +static const struct hda_pcm_stream vt1708_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -1868,7 +1433,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { +static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -1885,7 +1450,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { }, }; -static struct hda_pcm_stream vt1708_pcm_analog_capture = { +static const struct hda_pcm_stream vt1708_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -1896,7 +1461,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1708_pcm_digital_playback = { +static const struct hda_pcm_stream vt1708_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1909,7 +1474,7 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1708_pcm_digital_capture = { +static const struct hda_pcm_stream vt1708_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -1919,7 +1484,7 @@ static int via_build_controls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; struct snd_kcontrol *kctl; - struct snd_kcontrol_new *knew; + const struct snd_kcontrol_new *knew; int err, i; for (i = 0; i < spec->num_mixers; i++) { @@ -1967,7 +1532,7 @@ static int via_build_controls(struct hda_codec *codec) } /* init power states */ - set_jack_power_state(codec); + set_widgets_power_state(codec); analog_low_current_mode(codec, 1); via_free_kctls(codec); /* no longer needed */ @@ -2131,7 +1696,7 @@ static void via_speaker_automute(struct hda_codec *codec) unsigned int hp_present; struct via_spec *spec = codec->spec; - if (spec->codec_type != VT2002P && spec->codec_type != VT1812) + if (!VT2002P_COMPATIBLE(spec)) return; hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); @@ -2190,17 +1755,21 @@ static void via_unsol_event(struct hda_codec *codec, unsigned int res) { res >>= 26; - if (res & VIA_HP_EVENT) + + if (res & VIA_JACK_EVENT) + set_widgets_power_state(codec); + + res &= ~VIA_JACK_EVENT; + + if (res == VIA_HP_EVENT) via_hp_automute(codec); - if (res & VIA_GPIO_EVENT) + else if (res == VIA_GPIO_EVENT) via_gpio_control(codec); - if (res & VIA_JACK_EVENT) - set_jack_power_state(codec); - if (res & VIA_MONO_EVENT) + else if (res == VIA_MONO_EVENT) via_mono_automute(codec); - if (res & VIA_SPEAKER_EVENT) + else if (res == VIA_SPEAKER_EVENT) via_speaker_automute(codec); - if (res & VIA_BIND_HP_EVENT) + else if (res == VIA_BIND_HP_EVENT) via_hp_bind_automute(codec); } @@ -2250,7 +1819,7 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) /* */ -static struct hda_codec_ops via_patch_ops = { +static const struct hda_codec_ops via_patch_ops = { .build_controls = via_build_controls, .build_pcms = via_build_pcms, .init = via_init, @@ -2280,16 +1849,16 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x12; + spec->private_dac_nids[i] = 0x12; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x13; + spec->private_dac_nids[i] = 0x13; break; } } @@ -2433,7 +2002,8 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg, hda_nid_t cap_nid, - hda_nid_t pin_idxs[], int num_idxs) + const hda_nid_t pin_idxs[], + int num_idxs) { struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; @@ -2479,13 +2049,13 @@ static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; + static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs, ARRAY_SIZE(pin_idxs)); } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1708_loopbacks[] = { +static const struct hda_amp_list vt1708_loopbacks[] = { { 0x17, HDA_INPUT, 1 }, { 0x17, HDA_INPUT, 2 }, { 0x17, HDA_INPUT, 3 }, @@ -2544,7 +2114,7 @@ static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new vt1708_jack_detectect[] = { +static const struct snd_kcontrol_new vt1708_jack_detectect[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Jack Detect", @@ -2619,7 +2189,8 @@ static int via_auto_init(struct hda_codec *codec) via_auto_init_multi_out(codec); via_auto_init_hp_out(codec); via_auto_init_analog_input(codec); - if (spec->codec_type == VT2002P || spec->codec_type == VT1812) { + + if (VT2002P_COMPATIBLE(spec)) { via_hp_bind_automute(codec); } else { via_hp_automute(codec); @@ -2723,7 +2294,7 @@ static int patch_vt1708(struct hda_codec *codec) } /* capture mixer elements */ -static struct snd_kcontrol_new vt1709_capture_mixer[] = { +static const struct snd_kcontrol_new vt1709_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT), @@ -2745,7 +2316,7 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1709_uniwill_init_verbs[] = { +static const struct hda_verb vt1709_uniwill_init_verbs[] = { {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, { } @@ -2754,7 +2325,7 @@ static struct hda_verb vt1709_uniwill_init_verbs[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1709_10ch_volume_init_verbs[] = { +static const struct hda_verb vt1709_10ch_volume_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -2794,7 +2365,7 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 10, @@ -2806,7 +2377,7 @@ static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 6, @@ -2818,7 +2389,7 @@ static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1709_pcm_analog_capture = { +static const struct hda_pcm_stream vt1709_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -2829,7 +2400,7 @@ static struct hda_pcm_stream vt1709_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1709_pcm_digital_playback = { +static const struct hda_pcm_stream vt1709_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2840,7 +2411,7 @@ static struct hda_pcm_stream vt1709_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1709_pcm_digital_capture = { +static const struct hda_pcm_stream vt1709_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -2867,26 +2438,26 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec, switch (i) { case AUTO_SEQ_FRONT: /* AOW0 */ - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: /* AOW2 */ - spec->multiout.dac_nids[i] = 0x12; + spec->private_dac_nids[i] = 0x12; break; case AUTO_SEQ_SURROUND: /* AOW3 */ - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: /* AOW1 */ - spec->multiout.dac_nids[i] = 0x27; + spec->private_dac_nids[i] = 0x27; break; default: break; } } } - spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ + spec->private_dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ } else if (cfg->line_outs == 3) { /* 6 channels */ for (i = 0; i < cfg->line_outs; i++) { @@ -2896,15 +2467,15 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec, switch (i) { case AUTO_SEQ_FRONT: /* AOW0 */ - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: /* AOW2 */ - spec->multiout.dac_nids[i] = 0x12; + spec->private_dac_nids[i] = 0x12; break; case AUTO_SEQ_SURROUND: /* AOW1 */ - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; default: break; @@ -3052,7 +2623,7 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 }; + static const hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -3102,7 +2673,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1709_loopbacks[] = { +static const struct hda_amp_list vt1709_loopbacks[] = { { 0x18, HDA_INPUT, 1 }, { 0x18, HDA_INPUT, 2 }, { 0x18, HDA_INPUT, 3 }, @@ -3163,7 +2734,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1709_6ch_volume_init_verbs[] = { +static const struct hda_verb vt1709_6ch_volume_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ @@ -3253,7 +2824,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec) } /* capture mixer elements */ -static struct snd_kcontrol_new vt1708B_capture_mixer[] = { +static const struct snd_kcontrol_new vt1708B_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), @@ -3275,7 +2846,7 @@ static struct snd_kcontrol_new vt1708B_capture_mixer[] = { /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb vt1708B_8ch_volume_init_verbs[] = { +static const struct hda_verb vt1708B_8ch_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -3310,7 +2881,7 @@ static struct hda_verb vt1708B_8ch_volume_init_verbs[] = { { } }; -static struct hda_verb vt1708B_4ch_volume_init_verbs[] = { +static const struct hda_verb vt1708B_4ch_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -3345,7 +2916,7 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = { { } }; -static struct hda_verb vt1708B_uniwill_init_verbs[] = { +static const struct hda_verb vt1708B_uniwill_init_verbs[] = { {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -3369,7 +2940,7 @@ static int via_pcm_open_close(struct hda_pcm_stream *hinfo, return 0; } -static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -3382,7 +2953,7 @@ static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { +static const struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 4, @@ -3394,7 +2965,7 @@ static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1708B_pcm_analog_capture = { +static const struct hda_pcm_stream vt1708B_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -3407,7 +2978,7 @@ static struct hda_pcm_stream vt1708B_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1708B_pcm_digital_playback = { +static const struct hda_pcm_stream vt1708B_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -3420,7 +2991,7 @@ static struct hda_pcm_stream vt1708B_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1708B_pcm_digital_capture = { +static const struct hda_pcm_stream vt1708B_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -3443,16 +3014,16 @@ static int vt1708B_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x24; + spec->private_dac_nids[i] = 0x24; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x25; + spec->private_dac_nids[i] = 0x25; break; } } @@ -3584,7 +3155,7 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e }; + static const hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -3634,7 +3205,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1708B_loopbacks[] = { +static const struct hda_amp_list vt1708B_loopbacks[] = { { 0x16, HDA_INPUT, 1 }, { 0x16, HDA_INPUT, 2 }, { 0x16, HDA_INPUT, 3 }, @@ -3642,6 +3213,87 @@ static struct hda_amp_list vt1708B_loopbacks[] = { { } /* end */ }; #endif + +static void set_widgets_power_state_vt1708B(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + int is_8ch = 0; + if ((spec->codec_type != VT1708B_4CH) && + (codec->vendor_id != 0x11064397)) + is_8ch = 1; + + /* SW0 (17h) = stereo mixer */ + imux_is_smixer = + (snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) + == ((spec->codec_type == VT1708S) ? 5 : 0)); + /* inputs */ + /* PW 1/2/5 (1ah/1bh/1eh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1a, &parm); + set_pin_power_state(codec, 0x1b, &parm); + set_pin_power_state(codec, 0x1e, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* SW0 (17h), AIW 0/1 (13h/14h) */ + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW0 (19h), SW1 (18h), AOW1 (11h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x19, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1b, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW6 (22h), SW2 (26h), AOW2 (24h) */ + if (is_8ch) { + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x22, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x26, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x24, 0, + AC_VERB_SET_POWER_STATE, parm); + } else if (codec->vendor_id == 0x11064397) { + /* PW7(23h), SW2(27h), AOW2(25h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x23, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x27, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + /* PW 3/4/7 (1ch/1dh/23h) */ + parm = AC_PWRST_D3; + /* force to D0 for internal Speaker */ + set_pin_power_state(codec, 0x1c, &parm); + set_pin_power_state(codec, 0x1d, &parm); + if (is_8ch) + set_pin_power_state(codec, 0x23, &parm); + + /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + if (is_8ch) { + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x27, 0, + AC_VERB_SET_POWER_STATE, parm); + } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); +} + static int patch_vt1708S(struct hda_codec *codec); static int patch_vt1708B_8ch(struct hda_codec *codec) { @@ -3692,6 +3344,8 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) spec->loopback.amplist = vt1708B_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + return 0; } @@ -3742,13 +3396,15 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) spec->loopback.amplist = vt1708B_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + return 0; } /* Patch for VT1708S */ /* capture mixer elements */ -static struct snd_kcontrol_new vt1708S_capture_mixer[] = { +static const struct snd_kcontrol_new vt1708S_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), @@ -3771,7 +3427,7 @@ static struct snd_kcontrol_new vt1708S_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1708S_volume_init_verbs[] = { +static const struct hda_verb vt1708S_volume_init_verbs[] = { /* Unmute ADC0-1 and set the default input to mic-in */ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -3797,7 +3453,7 @@ static struct hda_verb vt1708S_volume_init_verbs[] = { { } }; -static struct hda_verb vt1708S_uniwill_init_verbs[] = { +static const struct hda_verb vt1708S_uniwill_init_verbs[] = { {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -3810,7 +3466,19 @@ static struct hda_verb vt1708S_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1708S_pcm_analog_playback = { +static const struct hda_verb vt1705_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static const struct hda_pcm_stream vt1708S_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 8, @@ -3823,7 +3491,20 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1708S_pcm_analog_capture = { +static const struct hda_pcm_stream vt1705_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + +static const struct hda_pcm_stream vt1708S_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -3836,7 +3517,7 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1708S_pcm_digital_playback = { +static const struct hda_pcm_stream vt1708S_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -3866,16 +3547,19 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x24; + if (spec->codec->vendor_id == 0x11064397) + spec->private_dac_nids[i] = 0x25; + else + spec->private_dac_nids[i] = 0x24; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x25; + spec->private_dac_nids[i] = 0x25; break; } } @@ -3884,23 +3568,29 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, /* for Smart 5.1, line/mic inputs double as output pins */ if (cfg->line_outs == 1) { spec->multiout.num_dacs = 3; - spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11; - spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24; + spec->private_dac_nids[AUTO_SEQ_SURROUND] = 0x11; + if (spec->codec->vendor_id == 0x11064397) + spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x25; + else + spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x24; } return 0; } /* add playback controls from the parsed DAC table */ -static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, +static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { + struct via_spec *spec = codec->spec; char name[32]; static const char * const chname[4] = { "Front", "Surround", "C/LFE", "Side" }; - hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25}; - hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27}; + hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25}, + {0x10, 0x11, 0x25, 0} }; + hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27}, + {0x1C, 0x18, 0x27, 0} }; hda_nid_t nid, nid_vol, nid_mute; int i, err; @@ -3911,8 +3601,15 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, if (!nid && i > AUTO_SEQ_CENLFE) continue; - nid_vol = nid_vols[i]; - nid_mute = nid_mutes[i]; + if (codec->vendor_id == 0x11064397) { + nid_vol = nid_vols[1][i]; + nid_mute = nid_mutes[1][i]; + } else { + nid_vol = nid_vols[0][i]; + nid_mute = nid_mutes[0][i]; + } + if (!nid_vol && !nid_mute) + continue; if (i == AUTO_SEQ_CENLFE) { /* Center/LFE */ @@ -4022,7 +3719,7 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -4066,7 +3763,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) return 0; /* can't find valid BIOS pin config */ - err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg); + err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); @@ -4093,7 +3790,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1708S_loopbacks[] = { +static const struct hda_amp_list vt1708S_loopbacks[] = { { 0x16, HDA_INPUT, 1 }, { 0x16, HDA_INPUT, 2 }, { 0x16, HDA_INPUT, 3 }, @@ -4133,17 +3830,29 @@ static int patch_vt1708S(struct hda_codec *codec) } spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; - spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs; + if (codec->vendor_id == 0x11064397) + spec->init_verbs[spec->num_iverbs++] = + vt1705_uniwill_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt1708S_uniwill_init_verbs; if (codec->vendor_id == 0x11060440) spec->stream_name_analog = "VT1818S Analog"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_analog = "VT1705 Analog"; else spec->stream_name_analog = "VT1708S Analog"; - spec->stream_analog_playback = &vt1708S_pcm_analog_playback; + if (codec->vendor_id == 0x11064397) + spec->stream_analog_playback = &vt1705_pcm_analog_playback; + else + spec->stream_analog_playback = &vt1708S_pcm_analog_playback; spec->stream_analog_capture = &vt1708S_pcm_analog_capture; if (codec->vendor_id == 0x11060440) spec->stream_name_digital = "VT1818S Digital"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_digital = "VT1705 Digital"; else spec->stream_name_digital = "VT1708S Digital"; spec->stream_digital_playback = &vt1708S_pcm_digital_playback; @@ -4181,13 +3890,22 @@ static int patch_vt1708S(struct hda_codec *codec) spec->stream_name_analog = "VT1818S Analog"; spec->stream_name_digital = "VT1818S Digital"; } + /* correct names for VT1705 */ + if (codec->vendor_id == 0x11064397) { + kfree(codec->chip_name); + codec->chip_name = kstrdup("VT1705", GFP_KERNEL); + snprintf(codec->bus->card->mixername, + sizeof(codec->bus->card->mixername), + "%s %s", codec->vendor_name, codec->chip_name); + } + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; return 0; } /* Patch for VT1702 */ /* capture mixer elements */ -static struct snd_kcontrol_new vt1702_capture_mixer[] = { +static const struct snd_kcontrol_new vt1702_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT), @@ -4211,7 +3929,7 @@ static struct snd_kcontrol_new vt1702_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1702_volume_init_verbs[] = { +static const struct hda_verb vt1702_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -4242,7 +3960,7 @@ static struct hda_verb vt1702_volume_init_verbs[] = { { } }; -static struct hda_verb vt1702_uniwill_init_verbs[] = { +static const struct hda_verb vt1702_uniwill_init_verbs[] = { {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -4252,7 +3970,7 @@ static struct hda_verb vt1702_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1702_pcm_analog_playback = { +static const struct hda_pcm_stream vt1702_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -4265,7 +3983,7 @@ static struct hda_pcm_stream vt1702_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1702_pcm_analog_capture = { +static const struct hda_pcm_stream vt1702_pcm_analog_capture = { .substreams = 3, .channels_min = 2, .channels_max = 2, @@ -4278,7 +3996,7 @@ static struct hda_pcm_stream vt1702_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1702_pcm_digital_playback = { +static const struct hda_pcm_stream vt1702_pcm_digital_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -4300,7 +4018,7 @@ static int vt1702_auto_fill_dac_nids(struct via_spec *spec, if (cfg->line_out_pins[0]) { /* config dac list */ - spec->multiout.dac_nids[0] = 0x10; + spec->private_dac_nids[0] = 0x10; } return 0; @@ -4378,7 +4096,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -4429,7 +4147,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1702_loopbacks[] = { +static const struct hda_amp_list vt1702_loopbacks[] = { { 0x1A, HDA_INPUT, 1 }, { 0x1A, HDA_INPUT, 2 }, { 0x1A, HDA_INPUT, 3 }, @@ -4438,6 +4156,37 @@ static struct hda_amp_list vt1702_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1702(struct hda_codec *codec) +{ + int imux_is_smixer = + snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + unsigned int parm; + /* inputs */ + /* PW 1/2/5 (14h/15h/18h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x14, &parm); + set_pin_power_state(codec, 0x15, &parm); + set_pin_power_state(codec, 0x18, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */ + /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW 3/4 (16h/17h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x17, &parm); + set_pin_power_state(codec, 0x16, &parm); + /* MW0 (1ah), AOW 0/1 (10h/1dh) */ + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); +} + static int patch_vt1702(struct hda_codec *codec) { struct via_spec *spec; @@ -4484,13 +4233,14 @@ static int patch_vt1702(struct hda_codec *codec) spec->loopback.amplist = vt1702_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1702; return 0; } /* Patch for VT1718S */ /* capture mixer elements */ -static struct snd_kcontrol_new vt1718S_capture_mixer[] = { +static const struct snd_kcontrol_new vt1718S_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), @@ -4512,14 +4262,15 @@ static struct snd_kcontrol_new vt1718S_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1718S_volume_init_verbs[] = { +static const struct hda_verb vt1718S_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - + /* Enable MW0 adjust Gain 5 */ + {0x1, 0xfb2, 0x10}, /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget */ @@ -4528,7 +4279,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = { {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, /* Setup default input of Front HP to MW9 */ {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, @@ -4559,7 +4310,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = { }; -static struct hda_verb vt1718S_uniwill_init_verbs[] = { +static const struct hda_verb vt1718S_uniwill_init_verbs[] = { {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -4572,7 +4323,7 @@ static struct hda_verb vt1718S_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1718S_pcm_analog_playback = { +static const struct hda_pcm_stream vt1718S_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 10, @@ -4585,7 +4336,7 @@ static struct hda_pcm_stream vt1718S_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1718S_pcm_analog_capture = { +static const struct hda_pcm_stream vt1718S_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -4598,7 +4349,7 @@ static struct hda_pcm_stream vt1718S_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1718S_pcm_digital_playback = { +static const struct hda_pcm_stream vt1718S_pcm_digital_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -4611,7 +4362,7 @@ static struct hda_pcm_stream vt1718S_pcm_digital_playback = { }, }; -static struct hda_pcm_stream vt1718S_pcm_digital_capture = { +static const struct hda_pcm_stream vt1718S_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -4634,16 +4385,16 @@ static int vt1718S_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x8; + spec->private_dac_nids[i] = 0x8; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0xa; + spec->private_dac_nids[i] = 0xa; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x9; + spec->private_dac_nids[i] = 0x9; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0xb; + spec->private_dac_nids[i] = 0xb; break; } } @@ -4765,7 +4516,7 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -4816,7 +4567,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1718S_loopbacks[] = { +static const struct hda_amp_list vt1718S_loopbacks[] = { { 0x21, HDA_INPUT, 1 }, { 0x21, HDA_INPUT, 2 }, { 0x21, HDA_INPUT, 3 }, @@ -4825,6 +4576,72 @@ static struct hda_amp_list vt1718S_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1718S(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + /* MUX6 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x27, &parm); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW2 (26h), AOW2 (ah) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x2b, &parm); + snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW0 (24h), AOW0 (8h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + if (!spec->hp_independent_mode) /* check for redirected HP */ + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); + /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ + snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + + /* PW1 (25h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x2a, &parm); + snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm); + + if (spec->hp_independent_mode) { + /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0xc, 0, + AC_VERB_SET_POWER_STATE, parm); + } +} + static int patch_vt1718S(struct hda_codec *codec) { struct via_spec *spec; @@ -4886,6 +4703,8 @@ static int patch_vt1718S(struct hda_codec *codec) spec->loopback.amplist = vt1718S_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1718S; + return 0; } @@ -4925,13 +4744,12 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_CONNECT_SEL, index); spec->dmic_enabled = index; - set_jack_power_state(codec); - + set_widgets_power_state(codec); return 1; } /* capture mixer elements */ -static struct snd_kcontrol_new vt1716S_capture_mixer[] = { +static const struct snd_kcontrol_new vt1716S_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), @@ -4950,7 +4768,7 @@ static struct snd_kcontrol_new vt1716S_capture_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { +static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = { HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -4966,12 +4784,12 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { /* mono-out mixer elements */ -static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { +static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT), { } /* end */ }; -static struct hda_verb vt1716S_volume_init_verbs[] = { +static const struct hda_verb vt1716S_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -5020,7 +4838,7 @@ static struct hda_verb vt1716S_volume_init_verbs[] = { }; -static struct hda_verb vt1716S_uniwill_init_verbs[] = { +static const struct hda_verb vt1716S_uniwill_init_verbs[] = { {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, @@ -5033,7 +4851,7 @@ static struct hda_verb vt1716S_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1716S_pcm_analog_playback = { +static const struct hda_pcm_stream vt1716S_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 6, @@ -5046,7 +4864,7 @@ static struct hda_pcm_stream vt1716S_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1716S_pcm_analog_capture = { +static const struct hda_pcm_stream vt1716S_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5059,7 +4877,7 @@ static struct hda_pcm_stream vt1716S_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1716S_pcm_digital_playback = { +static const struct hda_pcm_stream vt1716S_pcm_digital_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5088,13 +4906,13 @@ static int vt1716S_auto_fill_dac_nids(struct via_spec *spec, /* config dac list */ switch (i) { case AUTO_SEQ_FRONT: - spec->multiout.dac_nids[i] = 0x10; + spec->private_dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x25; + spec->private_dac_nids[i] = 0x25; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x11; + spec->private_dac_nids[i] = 0x11; break; } } @@ -5229,7 +5047,7 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -5276,7 +5094,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1716S_loopbacks[] = { +static const struct hda_amp_list vt1716S_loopbacks[] = { { 0x16, HDA_INPUT, 1 }, { 0x16, HDA_INPUT, 2 }, { 0x16, HDA_INPUT, 3 }, @@ -5285,6 +5103,99 @@ static struct hda_amp_list vt1716S_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1716S(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + unsigned int mono_out, present; + /* SW0 (17h) = stereo mixer */ + imux_is_smixer = + (snd_hda_codec_read(codec, 0x17, 0, + AC_VERB_GET_CONNECT_SEL, 0x00) == 5); + /* inputs */ + /* PW 1/2/5 (1ah/1bh/1eh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1a, &parm); + set_pin_power_state(codec, 0x1b, &parm); + set_pin_power_state(codec, 0x1e, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* SW0 (17h), AIW0(13h) */ + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1e, &parm); + /* PW11 (22h) */ + if (spec->dmic_enabled) + set_pin_power_state(codec, 0x22, &parm); + else + snd_hda_codec_write(codec, 0x22, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + + /* SW2(26h), AIW1(14h) */ + snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW0 (19h), SW1 (18h), AOW1 (11h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x19, &parm); + /* Smart 5.1 PW2(1bh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1b, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW7 (23h), SW3 (27h), AOW3 (25h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x23, &parm); + /* Smart 5.1 PW1(1ah) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Smart 5.1 PW5(1eh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1e, &parm); + snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Mono out */ + /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ + present = snd_hda_jack_detect(codec, 0x1c); + + if (present) + mono_out = 0; + else { + present = snd_hda_jack_detect(codec, 0x1d); + if (!spec->hp_independent_mode && present) + mono_out = 0; + else + mono_out = 1; + } + parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; + snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW 3/4 (1ch/1dh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1c, &parm); + set_pin_power_state(codec, 0x1d, &parm); + /* HP Independent Mode, power on AOW3 */ + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + + /* force to D0 for internal Speaker */ + /* MW0 (16h), AOW0 (10h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + mono_out ? AC_PWRST_D0 : parm); +} + static int patch_vt1716S(struct hda_codec *codec) { struct via_spec *spec; @@ -5339,13 +5250,14 @@ static int patch_vt1716S(struct hda_codec *codec) spec->loopback.amplist = vt1716S_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1716S; return 0; } /* for vt2002P */ /* capture mixer elements */ -static struct snd_kcontrol_new vt2002P_capture_mixer[] = { +static const struct snd_kcontrol_new vt2002P_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), @@ -5368,7 +5280,11 @@ static struct snd_kcontrol_new vt2002P_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt2002P_volume_init_verbs[] = { +static const struct hda_verb vt2002P_volume_init_verbs[] = { + /* Class-D speaker related verbs */ + {0x1, 0xfe0, 0x4}, + {0x1, 0xfe9, 0x80}, + {0x1, 0xfe2, 0x22}, /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -5419,9 +5335,60 @@ static struct hda_verb vt2002P_volume_init_verbs[] = { {0x1, 0xfb8, 0x88}, { } }; +static const struct hda_verb vt1802_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + /* Enable Boost Volume backdoor */ + {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, -static struct hda_verb vt2002P_uniwill_init_verbs[] = { + /* set MUX0/1/4/8 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x38, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, + + /* set PW0 index=0 (MW0) */ + {0x24, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Enable AOW0 to MW9 */ + {0x1, 0xfb8, 0x88}, + { } +}; + + +static const struct hda_verb vt2002P_uniwill_init_verbs[] = { {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, @@ -5431,8 +5398,18 @@ static struct hda_verb vt2002P_uniwill_init_verbs[] = { {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, { } }; +static const struct hda_verb vt1802_uniwill_init_verbs[] = { + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; -static struct hda_pcm_stream vt2002P_pcm_analog_playback = { +static const struct hda_pcm_stream vt2002P_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5445,7 +5422,7 @@ static struct hda_pcm_stream vt2002P_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt2002P_pcm_analog_capture = { +static const struct hda_pcm_stream vt2002P_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5458,7 +5435,7 @@ static struct hda_pcm_stream vt2002P_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt2002P_pcm_digital_playback = { +static const struct hda_pcm_stream vt2002P_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -5478,7 +5455,7 @@ static int vt2002P_auto_fill_dac_nids(struct via_spec *spec, spec->multiout.num_dacs = 1; spec->multiout.dac_nids = spec->private_dac_nids; if (cfg->line_out_pins[0]) - spec->multiout.dac_nids[0] = 0x8; + spec->private_dac_nids[0] = 0x8; return 0; } @@ -5487,10 +5464,15 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { int err; + hda_nid_t sw_nid; if (!cfg->line_out_pins[0]) return -1; + if (spec->codec_type == VT1802) + sw_nid = 0x28; + else + sw_nid = 0x26; /* Line-Out: PortE */ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, @@ -5500,7 +5482,7 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, return err; err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, "Master Front Playback Switch", - HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT)); + HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -5540,7 +5522,7 @@ static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec, { struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; - static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff }; int err; err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, @@ -5601,7 +5583,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt2002P_loopbacks[] = { +static const struct hda_amp_list vt2002P_loopbacks[] = { { 0x21, HDA_INPUT, 0 }, { 0x21, HDA_INPUT, 1 }, { 0x21, HDA_INPUT, 2 }, @@ -5609,6 +5591,116 @@ static struct hda_amp_list vt2002P_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt2002P(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + unsigned int present; + /* MUX9 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + parm = AC_PWRST_D0; + /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* AOW0 (8h)*/ + snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); + + if (spec->codec_type == VT1802) { + /* PW4 (28h), MW4 (18h), MUX4(38h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x38, 0, + AC_VERB_SET_POWER_STATE, parm); + } else { + /* PW4 (26h), MW4 (1ch), MUX4(37h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x37, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + if (spec->codec_type == VT1802) { + /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x15, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); + } else { + /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x19, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* Class-D */ + /* PW0 (24h), MW0(18h/14h), MUX0(34h) */ + present = snd_hda_jack_detect(codec, 0x25); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + parm = present ? AC_PWRST_D3 : AC_PWRST_D0; + if (spec->codec_type == VT1802) + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, parm); + else + snd_hda_codec_write(codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Mono Out */ + present = snd_hda_jack_detect(codec, 0x26); + + parm = present ? AC_PWRST_D3 : AC_PWRST_D0; + if (spec->codec_type == VT1802) { + /* PW15 (33h), MW8(1ch), MUX8(3ch) */ + snd_hda_codec_write(codec, 0x33, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, parm); + } else { + /* PW15 (31h), MW8(17h), MUX8(3bh) */ + snd_hda_codec_write(codec, 0x31, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x17, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3b, 0, + AC_VERB_SET_POWER_STATE, parm); + } + /* MW9 (21h) */ + if (imux_is_smixer || !is_aa_path_mute(codec)) + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + else + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); +} /* patch for vt2002P */ static int patch_vt2002P(struct hda_codec *codec) @@ -5631,14 +5723,31 @@ static int patch_vt2002P(struct hda_codec *codec) "from BIOS. Using genenic mode...\n"); } - spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs; - spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs; + if (spec->codec_type == VT1802) + spec->init_verbs[spec->num_iverbs++] = + vt1802_volume_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt2002P_volume_init_verbs; + + if (spec->codec_type == VT1802) + spec->init_verbs[spec->num_iverbs++] = + vt1802_uniwill_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt2002P_uniwill_init_verbs; - spec->stream_name_analog = "VT2002P Analog"; + if (spec->codec_type == VT1802) + spec->stream_name_analog = "VT1802 Analog"; + else + spec->stream_name_analog = "VT2002P Analog"; spec->stream_analog_playback = &vt2002P_pcm_analog_playback; spec->stream_analog_capture = &vt2002P_pcm_analog_capture; - spec->stream_name_digital = "VT2002P Digital"; + if (spec->codec_type == VT1802) + spec->stream_name_digital = "VT1802 Digital"; + else + spec->stream_name_digital = "VT2002P Digital"; spec->stream_digital_playback = &vt2002P_pcm_digital_playback; if (!spec->adc_nids && spec->input_mux) { @@ -5660,13 +5769,14 @@ static int patch_vt2002P(struct hda_codec *codec) spec->loopback.amplist = vt2002P_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt2002P; return 0; } /* for vt1812 */ /* capture mixer elements */ -static struct snd_kcontrol_new vt1812_capture_mixer[] = { +static const struct snd_kcontrol_new vt1812_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), @@ -5688,7 +5798,7 @@ static struct snd_kcontrol_new vt1812_capture_mixer[] = { { } /* end */ }; -static struct hda_verb vt1812_volume_init_verbs[] = { +static const struct hda_verb vt1812_volume_init_verbs[] = { /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -5741,7 +5851,7 @@ static struct hda_verb vt1812_volume_init_verbs[] = { }; -static struct hda_verb vt1812_uniwill_init_verbs[] = { +static const struct hda_verb vt1812_uniwill_init_verbs[] = { {0x33, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT }, @@ -5753,7 +5863,7 @@ static struct hda_verb vt1812_uniwill_init_verbs[] = { { } }; -static struct hda_pcm_stream vt1812_pcm_analog_playback = { +static const struct hda_pcm_stream vt1812_pcm_analog_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5766,7 +5876,7 @@ static struct hda_pcm_stream vt1812_pcm_analog_playback = { }, }; -static struct hda_pcm_stream vt1812_pcm_analog_capture = { +static const struct hda_pcm_stream vt1812_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, @@ -5779,7 +5889,7 @@ static struct hda_pcm_stream vt1812_pcm_analog_capture = { }, }; -static struct hda_pcm_stream vt1812_pcm_digital_playback = { +static const struct hda_pcm_stream vt1812_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, @@ -5798,7 +5908,7 @@ static int vt1812_auto_fill_dac_nids(struct via_spec *spec, spec->multiout.num_dacs = 1; spec->multiout.dac_nids = spec->private_dac_nids; if (cfg->line_out_pins[0]) - spec->multiout.dac_nids[0] = 0x8; + spec->private_dac_nids[0] = 0x8; return 0; } @@ -5861,7 +5971,7 @@ static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec, { struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; - static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff }; + static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff }; int err; err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, @@ -5923,7 +6033,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec) } #ifdef CONFIG_SND_HDA_POWER_SAVE -static struct hda_amp_list vt1812_loopbacks[] = { +static const struct hda_amp_list vt1812_loopbacks[] = { { 0x21, HDA_INPUT, 0 }, { 0x21, HDA_INPUT, 1 }, { 0x21, HDA_INPUT, 2 }, @@ -5931,6 +6041,97 @@ static struct hda_amp_list vt1812_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1812(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer = + snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + unsigned int parm; + unsigned int present; + /* MUX10 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + parm = AC_PWRST_D0; + /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* AOW0 (8h)*/ + snd_hda_codec_write(codec, 0x8, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* PW4 (28h), MW4 (18h), MUX4(38h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm); + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* Internal Speaker */ + /* PW0 (24h), MW0(14h), MUX0(34h) */ + present = snd_hda_jack_detect(codec, 0x25); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + if (present) { + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } else { + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + } + + + /* Mono Out */ + /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ + present = snd_hda_jack_detect(codec, 0x28); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x31, &parm); + if (present) { + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } else { + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + } + + /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x33, &parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm); + +} /* patch for vt1812 */ static int patch_vt1812(struct hda_codec *codec) @@ -5984,13 +6185,14 @@ static int patch_vt1812(struct hda_codec *codec) spec->loopback.amplist = vt1812_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1812; return 0; } /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_via[] = { +static const struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708}, { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708}, { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708}, @@ -6035,7 +6237,7 @@ static struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1708S}, { .id = 0x11063397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11064397, .name = "VT1708S", + { .id = 0x11064397, .name = "VT1705", .patch = patch_vt1708S}, { .id = 0x11065397, .name = "VT1708S", .patch = patch_vt1708S}, @@ -6076,6 +6278,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812}, { .id = 0x11060440, .name = "VT1818S", .patch = patch_vt1708S}, + { .id = 0x11060446, .name = "VT1802", + .patch = patch_vt2002P}, + { .id = 0x11068446, .name = "VT1802", + .patch = patch_vt2002P}, {} /* terminator */ }; diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 2f6252266a02..3e4f8c12ffce 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -148,7 +148,7 @@ static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg, udelay(100); /* * send device address, command and value, - * skipping ack cycles inbetween + * skipping ack cycles in between */ for (j = 0; j < 3; j++) { switch (j) { @@ -2143,7 +2143,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) ice->num_total_adcs = 2; } - /* to remeber the register values of CS8415 */ + /* to remember the register values of CS8415 */ ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); if (!ice->akm) return -ENOMEM; diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 4fc6d8bc637e..f4594d76b6ea 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2755,7 +2755,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, return err; } if (c->mpu401_1_name) - /* Prefered name available in card_info */ + /* Preferred name available in card_info */ snprintf(ice->rmidi[0]->name, sizeof(ice->rmidi[0]->name), "%s %d", c->mpu401_1_name, card->number); @@ -2772,7 +2772,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, return err; } if (c->mpu401_2_name) - /* Prefered name available in card_info */ + /* Preferred name available in card_info */ snprintf(ice->rmidi[1]->name, sizeof(ice->rmidi[1]->name), "%s %d", c->mpu401_2_name, diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index cdb873f5da50..92c1160d7ab5 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -768,7 +768,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) ice->num_total_dacs = 2; ice->num_total_adcs = 2; - /* to remeber the register values */ + /* to remember the register values */ ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); if (! ice->akm) return -ENOMEM; diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 6a9fee3ee78f..764cc93dbca4 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -1046,7 +1046,7 @@ static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice) * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten */ ice->gpio.saved[0] = 0; - /* to remeber the register values */ + /* to remember the register values */ ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); if (! ice->akm) @@ -1128,7 +1128,7 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten */ ice->gpio.saved[0] = 0; - /* to remeber the register values */ + /* to remember the register values */ ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); if (! ice->akm) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 629a5494347a..6c896dbfd796 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -534,7 +534,7 @@ static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int code udelay(10); } while (time--); - /* access to some forbidden (non existant) ac97 registers will not + /* access to some forbidden (non existent) ac97 registers will not * reset the semaphore. So even if you don't get the semaphore, still * continue the access. We don't need the semaphore anyway. */ snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 2ae8d29500a8..f3353b49c785 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -235,8 +235,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = { { PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */ { PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */ { PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */ + { PCI_VDEVICE(AMD, 0x746e), DEVICE_INTEL }, /* AMD8111 */ #if 0 - { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL }, /* AMD8111 */ { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI }, /* Ali5455 */ #endif { 0, } @@ -331,7 +331,7 @@ static int snd_intel8x0m_codec_semaphore(struct intel8x0m *chip, unsigned int co udelay(10); } while (time--); - /* access to some forbidden (non existant) ac97 registers will not + /* access to some forbidden (non existent) ac97 registers will not * reset the semaphore. So even if you don't get the semaphore, still * continue the access. We don't need the semaphore anyway. */ snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", @@ -1261,9 +1261,9 @@ static struct shortname_table { { PCI_DEVICE_ID_NVIDIA_MCP2_MODEM, "NVidia nForce2" }, { PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM, "NVidia nForce2s" }, { PCI_DEVICE_ID_NVIDIA_MCP3_MODEM, "NVidia nForce3" }, + { 0x746e, "AMD AMD8111" }, #if 0 { 0x5455, "ALi M5455" }, - { 0x746d, "AMD AMD8111" }, #endif { 0 }, }; diff --git a/sound/pci/lola/Makefile b/sound/pci/lola/Makefile new file mode 100644 index 000000000000..8178a2a59d00 --- /dev/null +++ b/sound/pci/lola/Makefile @@ -0,0 +1,4 @@ +snd-lola-y := lola.o lola_pcm.o lola_clock.o lola_mixer.o +snd-lola-$(CONFIG_SND_DEBUG) += lola_proc.o + +obj-$(CONFIG_SND_LOLA) += snd-lola.o diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c new file mode 100644 index 000000000000..34b24286d279 --- /dev/null +++ b/sound/pci/lola/lola.c @@ -0,0 +1,791 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/moduleparam.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/initval.h> +#include "lola.h" + +/* Standard options */ +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for Digigram Lola driver."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for Digigram Lola driver."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable Digigram Lola driver."); + +/* Lola-specific options */ + +/* for instance use always max granularity which is compatible + * with all sample rates + */ +static int granularity[SNDRV_CARDS] = { + [0 ... (SNDRV_CARDS - 1)] = LOLA_GRANULARITY_MAX +}; + +/* below a sample_rate of 16kHz the analogue audio quality is NOT excellent */ +static int sample_rate_min[SNDRV_CARDS] = { + [0 ... (SNDRV_CARDS - 1) ] = 16000 +}; + +module_param_array(granularity, int, NULL, 0444); +MODULE_PARM_DESC(granularity, "Granularity value"); +module_param_array(sample_rate_min, int, NULL, 0444); +MODULE_PARM_DESC(sample_rate_min, "Minimal sample rate"); + +/* + */ + +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Digigram, Lola}}"); +MODULE_DESCRIPTION("Digigram Lola driver"); +MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); + +#ifdef CONFIG_SND_DEBUG_VERBOSE +static int debug; +module_param(debug, int, 0644); +#define verbose_debug(fmt, args...) \ + do { if (debug > 1) printk(KERN_DEBUG SFX fmt, ##args); } while (0) +#else +#define verbose_debug(fmt, args...) +#endif + +/* + * pseudo-codec read/write via CORB/RIRB + */ + +static int corb_send_verb(struct lola *chip, unsigned int nid, + unsigned int verb, unsigned int data, + unsigned int extdata) +{ + unsigned long flags; + int ret = -EIO; + + chip->last_cmd_nid = nid; + chip->last_verb = verb; + chip->last_data = data; + chip->last_extdata = extdata; + data |= (nid << 20) | (verb << 8); + + spin_lock_irqsave(&chip->reg_lock, flags); + if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) { + unsigned int wp = chip->corb.wp + 1; + wp %= LOLA_CORB_ENTRIES; + chip->corb.wp = wp; + chip->corb.buf[wp * 2] = cpu_to_le32(data); + chip->corb.buf[wp * 2 + 1] = cpu_to_le32(extdata); + lola_writew(chip, BAR0, CORBWP, wp); + chip->rirb.cmds++; + smp_wmb(); + ret = 0; + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + return ret; +} + +static void lola_queue_unsol_event(struct lola *chip, unsigned int res, + unsigned int res_ex) +{ + lola_update_ext_clock_freq(chip, res); +} + +/* retrieve RIRB entry - called from interrupt handler */ +static void lola_update_rirb(struct lola *chip) +{ + unsigned int rp, wp; + u32 res, res_ex; + + wp = lola_readw(chip, BAR0, RIRBWP); + if (wp == chip->rirb.wp) + return; + chip->rirb.wp = wp; + + while (chip->rirb.rp != wp) { + chip->rirb.rp++; + chip->rirb.rp %= LOLA_CORB_ENTRIES; + + rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ + res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); + res = le32_to_cpu(chip->rirb.buf[rp]); + if (res_ex & LOLA_RIRB_EX_UNSOL_EV) + lola_queue_unsol_event(chip, res, res_ex); + else if (chip->rirb.cmds) { + chip->res = res; + chip->res_ex = res_ex; + smp_wmb(); + chip->rirb.cmds--; + } + } +} + +static int rirb_get_response(struct lola *chip, unsigned int *val, + unsigned int *extval) +{ + unsigned long timeout; + + again: + timeout = jiffies + msecs_to_jiffies(1000); + for (;;) { + if (chip->polling_mode) { + spin_lock_irq(&chip->reg_lock); + lola_update_rirb(chip); + spin_unlock_irq(&chip->reg_lock); + } + if (!chip->rirb.cmds) { + *val = chip->res; + if (extval) + *extval = chip->res_ex; + verbose_debug("get_response: %x, %x\n", + chip->res, chip->res_ex); + if (chip->res_ex & LOLA_RIRB_EX_ERROR) { + printk(KERN_WARNING SFX "RIRB ERROR: " + "NID=%x, verb=%x, data=%x, ext=%x\n", + chip->last_cmd_nid, + chip->last_verb, chip->last_data, + chip->last_extdata); + return -EIO; + } + return 0; + } + if (time_after(jiffies, timeout)) + break; + udelay(20); + cond_resched(); + } + printk(KERN_WARNING SFX "RIRB response error\n"); + if (!chip->polling_mode) { + printk(KERN_WARNING SFX "switching to polling mode\n"); + chip->polling_mode = 1; + goto again; + } + return -EIO; +} + +/* aynchronous write of a codec verb with data */ +int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb, + unsigned int data, unsigned int extdata) +{ + verbose_debug("codec_write NID=%x, verb=%x, data=%x, ext=%x\n", + nid, verb, data, extdata); + return corb_send_verb(chip, nid, verb, data, extdata); +} + +/* write a codec verb with data and read the returned status */ +int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb, + unsigned int data, unsigned int extdata, + unsigned int *val, unsigned int *extval) +{ + int err; + + verbose_debug("codec_read NID=%x, verb=%x, data=%x, ext=%x\n", + nid, verb, data, extdata); + err = corb_send_verb(chip, nid, verb, data, extdata); + if (err < 0) + return err; + err = rirb_get_response(chip, val, extval); + return err; +} + +/* flush all pending codec writes */ +int lola_codec_flush(struct lola *chip) +{ + unsigned int tmp; + return rirb_get_response(chip, &tmp, NULL); +} + +/* + * interrupt handler + */ +static irqreturn_t lola_interrupt(int irq, void *dev_id) +{ + struct lola *chip = dev_id; + unsigned int notify_ins, notify_outs, error_ins, error_outs; + int handled = 0; + int i; + + notify_ins = notify_outs = error_ins = error_outs = 0; + spin_lock(&chip->reg_lock); + for (;;) { + unsigned int status, in_sts, out_sts; + unsigned int reg; + + status = lola_readl(chip, BAR1, DINTSTS); + if (!status || status == -1) + break; + + in_sts = lola_readl(chip, BAR1, DIINTSTS); + out_sts = lola_readl(chip, BAR1, DOINTSTS); + + /* clear Input Interrupts */ + for (i = 0; in_sts && i < chip->pcm[CAPT].num_streams; i++) { + if (!(in_sts & (1 << i))) + continue; + in_sts &= ~(1 << i); + reg = lola_dsd_read(chip, i, STS); + if (reg & LOLA_DSD_STS_DESE) /* error */ + error_ins |= (1 << i); + if (reg & LOLA_DSD_STS_BCIS) /* notify */ + notify_ins |= (1 << i); + /* clear */ + lola_dsd_write(chip, i, STS, reg); + } + + /* clear Output Interrupts */ + for (i = 0; out_sts && i < chip->pcm[PLAY].num_streams; i++) { + if (!(out_sts & (1 << i))) + continue; + out_sts &= ~(1 << i); + reg = lola_dsd_read(chip, i + MAX_STREAM_IN_COUNT, STS); + if (reg & LOLA_DSD_STS_DESE) /* error */ + error_outs |= (1 << i); + if (reg & LOLA_DSD_STS_BCIS) /* notify */ + notify_outs |= (1 << i); + lola_dsd_write(chip, i + MAX_STREAM_IN_COUNT, STS, reg); + } + + if (status & LOLA_DINT_CTRL) { + unsigned char rbsts; /* ring status is byte access */ + rbsts = lola_readb(chip, BAR0, RIRBSTS); + rbsts &= LOLA_RIRB_INT_MASK; + if (rbsts) + lola_writeb(chip, BAR0, RIRBSTS, rbsts); + rbsts = lola_readb(chip, BAR0, CORBSTS); + rbsts &= LOLA_CORB_INT_MASK; + if (rbsts) + lola_writeb(chip, BAR0, CORBSTS, rbsts); + + lola_update_rirb(chip); + } + + if (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)) { + /* clear global fifo error interrupt */ + lola_writel(chip, BAR1, DINTSTS, + (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR))); + } + handled = 1; + } + spin_unlock(&chip->reg_lock); + + lola_pcm_update(chip, &chip->pcm[CAPT], notify_ins); + lola_pcm_update(chip, &chip->pcm[PLAY], notify_outs); + + return IRQ_RETVAL(handled); +} + + +/* + * controller + */ +static int reset_controller(struct lola *chip) +{ + unsigned int gctl = lola_readl(chip, BAR0, GCTL); + unsigned long end_time; + + if (gctl) { + /* to be sure */ + lola_writel(chip, BAR1, BOARD_MODE, 0); + return 0; + } + + chip->cold_reset = 1; + lola_writel(chip, BAR0, GCTL, LOLA_GCTL_RESET); + end_time = jiffies + msecs_to_jiffies(200); + do { + msleep(1); + gctl = lola_readl(chip, BAR0, GCTL); + if (gctl) + break; + } while (time_before(jiffies, end_time)); + if (!gctl) { + printk(KERN_ERR SFX "cannot reset controller\n"); + return -EIO; + } + return 0; +} + +static void lola_irq_enable(struct lola *chip) +{ + unsigned int val; + + /* enalbe all I/O streams */ + val = (1 << chip->pcm[PLAY].num_streams) - 1; + lola_writel(chip, BAR1, DOINTCTL, val); + val = (1 << chip->pcm[CAPT].num_streams) - 1; + lola_writel(chip, BAR1, DIINTCTL, val); + + /* enable global irqs */ + val = LOLA_DINT_GLOBAL | LOLA_DINT_CTRL | LOLA_DINT_FIFOERR | + LOLA_DINT_MUERR; + lola_writel(chip, BAR1, DINTCTL, val); +} + +static void lola_irq_disable(struct lola *chip) +{ + lola_writel(chip, BAR1, DINTCTL, 0); + lola_writel(chip, BAR1, DIINTCTL, 0); + lola_writel(chip, BAR1, DOINTCTL, 0); +} + +static int setup_corb_rirb(struct lola *chip) +{ + int err; + unsigned char tmp; + unsigned long end_time; + + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + PAGE_SIZE, &chip->rb); + if (err < 0) + return err; + + chip->corb.addr = chip->rb.addr; + chip->corb.buf = (u32 *)chip->rb.area; + chip->rirb.addr = chip->rb.addr + 2048; + chip->rirb.buf = (u32 *)(chip->rb.area + 2048); + + /* disable ringbuffer DMAs */ + lola_writeb(chip, BAR0, RIRBCTL, 0); + lola_writeb(chip, BAR0, CORBCTL, 0); + + end_time = jiffies + msecs_to_jiffies(200); + do { + if (!lola_readb(chip, BAR0, RIRBCTL) && + !lola_readb(chip, BAR0, CORBCTL)) + break; + msleep(1); + } while (time_before(jiffies, end_time)); + + /* CORB set up */ + lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr); + lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr)); + /* set the corb size to 256 entries */ + lola_writeb(chip, BAR0, CORBSIZE, 0x02); + /* set the corb write pointer to 0 */ + lola_writew(chip, BAR0, CORBWP, 0); + /* reset the corb hw read pointer */ + lola_writew(chip, BAR0, CORBRP, LOLA_RBRWP_CLR); + /* enable corb dma */ + lola_writeb(chip, BAR0, CORBCTL, LOLA_RBCTL_DMA_EN); + /* clear flags if set */ + tmp = lola_readb(chip, BAR0, CORBSTS) & LOLA_CORB_INT_MASK; + if (tmp) + lola_writeb(chip, BAR0, CORBSTS, tmp); + chip->corb.wp = 0; + + /* RIRB set up */ + lola_writel(chip, BAR0, RIRBLBASE, (u32)chip->rirb.addr); + lola_writel(chip, BAR0, RIRBUBASE, upper_32_bits(chip->rirb.addr)); + /* set the rirb size to 256 entries */ + lola_writeb(chip, BAR0, RIRBSIZE, 0x02); + /* reset the rirb hw write pointer */ + lola_writew(chip, BAR0, RIRBWP, LOLA_RBRWP_CLR); + /* set N=1, get RIRB response interrupt for new entry */ + lola_writew(chip, BAR0, RINTCNT, 1); + /* enable rirb dma and response irq */ + lola_writeb(chip, BAR0, RIRBCTL, LOLA_RBCTL_DMA_EN | LOLA_RBCTL_IRQ_EN); + /* clear flags if set */ + tmp = lola_readb(chip, BAR0, RIRBSTS) & LOLA_RIRB_INT_MASK; + if (tmp) + lola_writeb(chip, BAR0, RIRBSTS, tmp); + chip->rirb.rp = chip->rirb.cmds = 0; + + return 0; +} + +static void stop_corb_rirb(struct lola *chip) +{ + /* disable ringbuffer DMAs */ + lola_writeb(chip, BAR0, RIRBCTL, 0); + lola_writeb(chip, BAR0, CORBCTL, 0); +} + +static void lola_reset_setups(struct lola *chip) +{ + /* update the granularity */ + lola_set_granularity(chip, chip->granularity, true); + /* update the sample clock */ + lola_set_clock_index(chip, chip->clock.cur_index); + /* enable unsolicited events of the clock widget */ + lola_enable_clock_events(chip); + /* update the analog gains */ + lola_setup_all_analog_gains(chip, CAPT, false); /* input, update */ + /* update SRC configuration if applicable */ + lola_set_src_config(chip, chip->input_src_mask, false); + /* update the analog outputs */ + lola_setup_all_analog_gains(chip, PLAY, false); /* output, update */ +} + +static int lola_parse_tree(struct lola *chip) +{ + unsigned int val; + int nid, err; + + err = lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read VENDOR_ID\n"); + return err; + } + val >>= 16; + if (val != 0x1369) { + printk(KERN_ERR SFX "Unknown codec vendor 0x%x\n", val); + return -EINVAL; + } + + err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read FUNCTION_TYPE for 0x%x\n", nid); + return err; + } + if (val != 1) { + printk(KERN_ERR SFX "Unknown function type %d\n", val); + return -EINVAL; + } + + err = lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read SPECCAPS\n"); + return err; + } + chip->lola_caps = val; + chip->pin[CAPT].num_pins = LOLA_AFG_INPUT_PIN_COUNT(chip->lola_caps); + chip->pin[PLAY].num_pins = LOLA_AFG_OUTPUT_PIN_COUNT(chip->lola_caps); + snd_printdd(SFX "speccaps=0x%x, pins in=%d, out=%d\n", + chip->lola_caps, + chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins); + + if (chip->pin[CAPT].num_pins > MAX_AUDIO_INOUT_COUNT || + chip->pin[PLAY].num_pins > MAX_AUDIO_INOUT_COUNT) { + printk(KERN_ERR SFX "Invalid Lola-spec caps 0x%x\n", val); + return -EINVAL; + } + + nid = 0x02; + err = lola_init_pcm(chip, CAPT, &nid); + if (err < 0) + return err; + err = lola_init_pcm(chip, PLAY, &nid); + if (err < 0) + return err; + + err = lola_init_pins(chip, CAPT, &nid); + if (err < 0) + return err; + err = lola_init_pins(chip, PLAY, &nid); + if (err < 0) + return err; + + if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) { + err = lola_init_clock_widget(chip, nid); + if (err < 0) + return err; + nid++; + } + if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) { + err = lola_init_mixer_widget(chip, nid); + if (err < 0) + return err; + nid++; + } + + /* enable unsolicited events of the clock widget */ + err = lola_enable_clock_events(chip); + if (err < 0) + return err; + + /* if last ResetController was not a ColdReset, we don't know + * the state of the card; initialize here again + */ + if (!chip->cold_reset) { + lola_reset_setups(chip); + chip->cold_reset = 1; + } else { + /* set the granularity if it is not the default */ + if (chip->granularity != LOLA_GRANULARITY_MIN) + lola_set_granularity(chip, chip->granularity, true); + } + + return 0; +} + +static void lola_stop_hw(struct lola *chip) +{ + stop_corb_rirb(chip); + lola_irq_disable(chip); +} + +static void lola_free(struct lola *chip) +{ + if (chip->initialized) + lola_stop_hw(chip); + lola_free_pcm(chip); + lola_free_mixer(chip); + if (chip->irq >= 0) + free_irq(chip->irq, (void *)chip); + if (chip->bar[0].remap_addr) + iounmap(chip->bar[0].remap_addr); + if (chip->bar[1].remap_addr) + iounmap(chip->bar[1].remap_addr); + if (chip->rb.area) + snd_dma_free_pages(&chip->rb); + pci_release_regions(chip->pci); + pci_disable_device(chip->pci); + kfree(chip); +} + +static int lola_dev_free(struct snd_device *device) +{ + lola_free(device->device_data); + return 0; +} + +static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, + int dev, struct lola **rchip) +{ + struct lola *chip; + int err; + unsigned int dever; + static struct snd_device_ops ops = { + .dev_free = lola_dev_free, + }; + + *rchip = NULL; + + err = pci_enable_device(pci); + if (err < 0) + return err; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { + snd_printk(KERN_ERR SFX "cannot allocate chip\n"); + pci_disable_device(pci); + return -ENOMEM; + } + + spin_lock_init(&chip->reg_lock); + mutex_init(&chip->open_mutex); + chip->card = card; + chip->pci = pci; + chip->irq = -1; + + chip->granularity = granularity[dev]; + switch (chip->granularity) { + case 8: + chip->sample_rate_max = 48000; + break; + case 16: + chip->sample_rate_max = 96000; + break; + case 32: + chip->sample_rate_max = 192000; + break; + default: + snd_printk(KERN_WARNING SFX + "Invalid granularity %d, reset to %d\n", + chip->granularity, LOLA_GRANULARITY_MAX); + chip->granularity = LOLA_GRANULARITY_MAX; + chip->sample_rate_max = 192000; + break; + } + chip->sample_rate_min = sample_rate_min[dev]; + if (chip->sample_rate_min > chip->sample_rate_max) { + snd_printk(KERN_WARNING SFX + "Invalid sample_rate_min %d, reset to 16000\n", + chip->sample_rate_min); + chip->sample_rate_min = 16000; + } + + err = pci_request_regions(pci, DRVNAME); + if (err < 0) { + kfree(chip); + pci_disable_device(pci); + return err; + } + + chip->bar[0].addr = pci_resource_start(pci, 0); + chip->bar[0].remap_addr = pci_ioremap_bar(pci, 0); + chip->bar[1].addr = pci_resource_start(pci, 2); + chip->bar[1].remap_addr = pci_ioremap_bar(pci, 2); + if (!chip->bar[0].remap_addr || !chip->bar[1].remap_addr) { + snd_printk(KERN_ERR SFX "ioremap error\n"); + err = -ENXIO; + goto errout; + } + + pci_set_master(pci); + + err = reset_controller(chip); + if (err < 0) + goto errout; + + if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED, + DRVNAME, chip)) { + printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); + err = -EBUSY; + goto errout; + } + chip->irq = pci->irq; + synchronize_irq(chip->irq); + + dever = lola_readl(chip, BAR1, DEVER); + chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff; + chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff; + chip->version = (dever >> 24) & 0xff; + snd_printdd(SFX "streams in=%d, out=%d, version=0x%x\n", + chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams, + chip->version); + + /* Test LOLA_BAR1_DEVER */ + if (chip->pcm[CAPT].num_streams > MAX_STREAM_IN_COUNT || + chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT || + (!chip->pcm[CAPT].num_streams && + !chip->pcm[PLAY].num_streams)) { + printk(KERN_ERR SFX "invalid DEVER = %x\n", dever); + err = -EINVAL; + goto errout; + } + + err = setup_corb_rirb(chip); + if (err < 0) + goto errout; + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); + goto errout; + } + + strcpy(card->driver, "Lola"); + strlcpy(card->shortname, "Digigram Lola", sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", + card->shortname, chip->bar[0].addr, chip->irq); + strcpy(card->mixername, card->shortname); + + lola_irq_enable(chip); + + chip->initialized = 1; + *rchip = chip; + return 0; + + errout: + lola_free(chip); + return err; +} + +static int __devinit lola_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + struct snd_card *card; + struct lola *chip; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + if (err < 0) { + snd_printk(KERN_ERR SFX "Error creating card!\n"); + return err; + } + + snd_card_set_dev(card, &pci->dev); + + err = lola_create(card, pci, dev, &chip); + if (err < 0) + goto out_free; + card->private_data = chip; + + err = lola_parse_tree(chip); + if (err < 0) + goto out_free; + + err = lola_create_pcm(chip); + if (err < 0) + goto out_free; + + err = lola_create_mixer(chip); + if (err < 0) + goto out_free; + + lola_proc_debug_new(chip); + + err = snd_card_register(card); + if (err < 0) + goto out_free; + + pci_set_drvdata(pci, card); + dev++; + return err; +out_free: + snd_card_free(card); + return err; +} + +static void __devexit lola_remove(struct pci_dev *pci) +{ + snd_card_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); +} + +/* PCI IDs */ +static DEFINE_PCI_DEVICE_TABLE(lola_ids) = { + { PCI_VDEVICE(DIGIGRAM, 0x0001) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, lola_ids); + +/* pci_driver definition */ +static struct pci_driver driver = { + .name = DRVNAME, + .id_table = lola_ids, + .probe = lola_probe, + .remove = __devexit_p(lola_remove), +}; + +static int __init alsa_card_lola_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_lola_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_lola_init) +module_exit(alsa_card_lola_exit) diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h new file mode 100644 index 000000000000..d5708e29b16d --- /dev/null +++ b/sound/pci/lola/lola.h @@ -0,0 +1,527 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _LOLA_H +#define _LOLA_H + +#define DRVNAME "snd-lola" +#define SFX DRVNAME ": " + +/* + * Lola HD Audio Registers BAR0 + */ +#define LOLA_BAR0_GCAP 0x00 +#define LOLA_BAR0_VMIN 0x02 +#define LOLA_BAR0_VMAJ 0x03 +#define LOLA_BAR0_OUTPAY 0x04 +#define LOLA_BAR0_INPAY 0x06 +#define LOLA_BAR0_GCTL 0x08 +#define LOLA_BAR0_WAKEEN 0x0c +#define LOLA_BAR0_STATESTS 0x0e +#define LOLA_BAR0_GSTS 0x10 +#define LOLA_BAR0_OUTSTRMPAY 0x18 +#define LOLA_BAR0_INSTRMPAY 0x1a +#define LOLA_BAR0_INTCTL 0x20 +#define LOLA_BAR0_INTSTS 0x24 +#define LOLA_BAR0_WALCLK 0x30 +#define LOLA_BAR0_SSYNC 0x38 + +#define LOLA_BAR0_CORBLBASE 0x40 +#define LOLA_BAR0_CORBUBASE 0x44 +#define LOLA_BAR0_CORBWP 0x48 /* no ULONG access */ +#define LOLA_BAR0_CORBRP 0x4a /* no ULONG access */ +#define LOLA_BAR0_CORBCTL 0x4c /* no ULONG access */ +#define LOLA_BAR0_CORBSTS 0x4d /* UCHAR access only */ +#define LOLA_BAR0_CORBSIZE 0x4e /* no ULONG access */ + +#define LOLA_BAR0_RIRBLBASE 0x50 +#define LOLA_BAR0_RIRBUBASE 0x54 +#define LOLA_BAR0_RIRBWP 0x58 +#define LOLA_BAR0_RINTCNT 0x5a /* no ULONG access */ +#define LOLA_BAR0_RIRBCTL 0x5c +#define LOLA_BAR0_RIRBSTS 0x5d /* UCHAR access only */ +#define LOLA_BAR0_RIRBSIZE 0x5e /* no ULONG access */ + +#define LOLA_BAR0_ICW 0x60 +#define LOLA_BAR0_IRR 0x64 +#define LOLA_BAR0_ICS 0x68 +#define LOLA_BAR0_DPLBASE 0x70 +#define LOLA_BAR0_DPUBASE 0x74 + +/* stream register offsets from stream base 0x80 */ +#define LOLA_BAR0_SD0_OFFSET 0x80 +#define LOLA_REG0_SD_CTL 0x00 +#define LOLA_REG0_SD_STS 0x03 +#define LOLA_REG0_SD_LPIB 0x04 +#define LOLA_REG0_SD_CBL 0x08 +#define LOLA_REG0_SD_LVI 0x0c +#define LOLA_REG0_SD_FIFOW 0x0e +#define LOLA_REG0_SD_FIFOSIZE 0x10 +#define LOLA_REG0_SD_FORMAT 0x12 +#define LOLA_REG0_SD_BDLPL 0x18 +#define LOLA_REG0_SD_BDLPU 0x1c + +/* + * Lola Digigram Registers BAR1 + */ +#define LOLA_BAR1_FPGAVER 0x00 +#define LOLA_BAR1_DEVER 0x04 +#define LOLA_BAR1_UCBMV 0x08 +#define LOLA_BAR1_JTAG 0x0c +#define LOLA_BAR1_UARTRX 0x10 +#define LOLA_BAR1_UARTTX 0x14 +#define LOLA_BAR1_UARTCR 0x18 +#define LOLA_BAR1_NVRAMVER 0x1c +#define LOLA_BAR1_CTRLSPI 0x20 +#define LOLA_BAR1_DSPI 0x24 +#define LOLA_BAR1_AISPI 0x28 +#define LOLA_BAR1_GRAN 0x2c + +#define LOLA_BAR1_DINTCTL 0x80 +#define LOLA_BAR1_DIINTCTL 0x84 +#define LOLA_BAR1_DOINTCTL 0x88 +#define LOLA_BAR1_LRC 0x90 +#define LOLA_BAR1_DINTSTS 0x94 +#define LOLA_BAR1_DIINTSTS 0x98 +#define LOLA_BAR1_DOINTSTS 0x9c + +#define LOLA_BAR1_DSD0_OFFSET 0xa0 +#define LOLA_BAR1_DSD_SIZE 0x18 + +#define LOLA_BAR1_DSDnSTS 0x00 +#define LOLA_BAR1_DSDnLPIB 0x04 +#define LOLA_BAR1_DSDnCTL 0x08 +#define LOLA_BAR1_DSDnLVI 0x0c +#define LOLA_BAR1_DSDnBDPL 0x10 +#define LOLA_BAR1_DSDnBDPU 0x14 + +#define LOLA_BAR1_SSYNC 0x03e8 + +#define LOLA_BAR1_BOARD_CTRL 0x0f00 +#define LOLA_BAR1_BOARD_MODE 0x0f02 + +#define LOLA_BAR1_SOURCE_GAIN_ENABLE 0x1000 +#define LOLA_BAR1_DEST00_MIX_GAIN_ENABLE 0x1004 +#define LOLA_BAR1_DEST31_MIX_GAIN_ENABLE 0x1080 +#define LOLA_BAR1_SOURCE00_01_GAIN 0x1084 +#define LOLA_BAR1_SOURCE30_31_GAIN 0x10c0 +#define LOLA_BAR1_SOURCE_GAIN(src) \ + (LOLA_BAR1_SOURCE00_01_GAIN + (src) * 2) +#define LOLA_BAR1_DEST00_MIX00_01_GAIN 0x10c4 +#define LOLA_BAR1_DEST00_MIX30_31_GAIN 0x1100 +#define LOLA_BAR1_DEST01_MIX00_01_GAIN 0x1104 +#define LOLA_BAR1_DEST01_MIX30_31_GAIN 0x1140 +#define LOLA_BAR1_DEST31_MIX00_01_GAIN 0x1884 +#define LOLA_BAR1_DEST31_MIX30_31_GAIN 0x18c0 +#define LOLA_BAR1_MIX_GAIN(dest, mix) \ + (LOLA_BAR1_DEST00_MIX00_01_GAIN + (dest) * 0x40 + (mix) * 2) +#define LOLA_BAR1_ANALOG_CLIP_IN 0x18c4 +#define LOLA_BAR1_PEAKMETERS_SOURCE00_01 0x18c8 +#define LOLA_BAR1_PEAKMETERS_SOURCE30_31 0x1904 +#define LOLA_BAR1_PEAKMETERS_SOURCE(src) \ + (LOLA_BAR1_PEAKMETERS_SOURCE00_01 + (src) * 2) +#define LOLA_BAR1_PEAKMETERS_DEST00_01 0x1908 +#define LOLA_BAR1_PEAKMETERS_DEST30_31 0x1944 +#define LOLA_BAR1_PEAKMETERS_DEST(dest) \ + (LOLA_BAR1_PEAKMETERS_DEST00_01 + (dest) * 2) +#define LOLA_BAR1_PEAKMETERS_AGC00_01 0x1948 +#define LOLA_BAR1_PEAKMETERS_AGC14_15 0x1964 +#define LOLA_BAR1_PEAKMETERS_AGC(x) \ + (LOLA_BAR1_PEAKMETERS_AGC00_01 + (x) * 2) + +/* GCTL reset bit */ +#define LOLA_GCTL_RESET (1 << 0) +/* GCTL unsolicited response enable bit */ +#define LOLA_GCTL_UREN (1 << 8) + +/* CORB/RIRB control, read/write pointer */ +#define LOLA_RBCTL_DMA_EN 0x02 /* enable DMA */ +#define LOLA_RBCTL_IRQ_EN 0x01 /* enable IRQ */ +#define LOLA_RBRWP_CLR 0x8000 /* read/write pointer clear */ + +#define LOLA_RIRB_EX_UNSOL_EV 0x40000000 +#define LOLA_RIRB_EX_ERROR 0x80000000 + +/* CORB int mask: CMEI[0] */ +#define LOLA_CORB_INT_CMEI 0x01 +#define LOLA_CORB_INT_MASK LOLA_CORB_INT_CMEI + +/* RIRB int mask: overrun[2], response[0] */ +#define LOLA_RIRB_INT_RESPONSE 0x01 +#define LOLA_RIRB_INT_OVERRUN 0x04 +#define LOLA_RIRB_INT_MASK (LOLA_RIRB_INT_RESPONSE | LOLA_RIRB_INT_OVERRUN) + +/* DINTCTL and DINTSTS */ +#define LOLA_DINT_GLOBAL 0x80000000 /* global interrupt enable bit */ +#define LOLA_DINT_CTRL 0x40000000 /* controller interrupt enable bit */ +#define LOLA_DINT_FIFOERR 0x20000000 /* global fifo error enable bit */ +#define LOLA_DINT_MUERR 0x10000000 /* global microcontroller underrun error */ + +/* DSDnCTL bits */ +#define LOLA_DSD_CTL_SRST 0x01 /* stream reset bit */ +#define LOLA_DSD_CTL_SRUN 0x02 /* stream DMA start bit */ +#define LOLA_DSD_CTL_IOCE 0x04 /* interrupt on completion enable */ +#define LOLA_DSD_CTL_DEIE 0x10 /* descriptor error interrupt enable */ +#define LOLA_DSD_CTL_VLRCV 0x20 /* valid LRCountValue information in bits 8..31 */ +#define LOLA_LRC_MASK 0xffffff00 + +/* DSDnSTS */ +#define LOLA_DSD_STS_BCIS 0x04 /* buffer completion interrupt status */ +#define LOLA_DSD_STS_DESE 0x10 /* descriptor error interrupt */ +#define LOLA_DSD_STS_FIFORDY 0x20 /* fifo ready */ + +#define LOLA_CORB_ENTRIES 256 + +#define MAX_STREAM_IN_COUNT 16 +#define MAX_STREAM_OUT_COUNT 16 +#define MAX_STREAM_COUNT 16 +#define MAX_PINS MAX_STREAM_COUNT +#define MAX_STREAM_BUFFER_COUNT 16 +#define MAX_AUDIO_INOUT_COUNT 16 + +#define LOLA_CLOCK_TYPE_INTERNAL 0 +#define LOLA_CLOCK_TYPE_AES 1 +#define LOLA_CLOCK_TYPE_AES_SYNC 2 +#define LOLA_CLOCK_TYPE_WORDCLOCK 3 +#define LOLA_CLOCK_TYPE_ETHERSOUND 4 +#define LOLA_CLOCK_TYPE_VIDEO 5 + +#define LOLA_CLOCK_FORMAT_NONE 0 +#define LOLA_CLOCK_FORMAT_NTSC 1 +#define LOLA_CLOCK_FORMAT_PAL 2 + +#define MAX_SAMPLE_CLOCK_COUNT 48 + +/* parameters used with mixer widget's mixer capabilities */ +#define LOLA_PEAK_METER_CAN_AGC_MASK 1 +#define LOLA_PEAK_METER_CAN_ANALOG_CLIP_MASK 2 + +struct lola_bar { + unsigned long addr; + void __iomem *remap_addr; +}; + +/* CORB/RIRB */ +struct lola_rb { + u32 *buf; /* CORB/RIRB buffer, 8 byte per each entry */ + dma_addr_t addr; /* physical address of CORB/RIRB buffer */ + unsigned short rp, wp; /* read/write pointers */ + int cmds; /* number of pending requests */ +}; + +/* Pin widget setup */ +struct lola_pin { + unsigned int nid; + bool is_analog; + unsigned int amp_mute; + unsigned int amp_step_size; + unsigned int amp_num_steps; + unsigned int amp_offset; + unsigned int max_level; + unsigned int config_default_reg; + unsigned int fixed_gain_list_len; + unsigned int cur_gain_step; +}; + +struct lola_pin_array { + unsigned int num_pins; + unsigned int num_analog_pins; + struct lola_pin pins[MAX_PINS]; +}; + +/* Clock widget setup */ +struct lola_sample_clock { + unsigned int type; + unsigned int format; + unsigned int freq; +}; + +struct lola_clock_widget { + unsigned int nid; + unsigned int items; + unsigned int cur_index; + unsigned int cur_freq; + bool cur_valid; + struct lola_sample_clock sample_clock[MAX_SAMPLE_CLOCK_COUNT]; + unsigned int idx_lookup[MAX_SAMPLE_CLOCK_COUNT]; +}; + +#define LOLA_MIXER_DIM 32 +struct lola_mixer_array { + u32 src_gain_enable; + u32 dest_mix_gain_enable[LOLA_MIXER_DIM]; + u16 src_gain[LOLA_MIXER_DIM]; + u16 dest_mix_gain[LOLA_MIXER_DIM][LOLA_MIXER_DIM]; +}; + +/* Mixer widget setup */ +struct lola_mixer_widget { + unsigned int nid; + unsigned int caps; + struct lola_mixer_array __user *array; + struct lola_mixer_array *array_saved; + unsigned int src_stream_outs; + unsigned int src_phys_ins; + unsigned int dest_stream_ins; + unsigned int dest_phys_outs; + unsigned int src_stream_out_ofs; + unsigned int dest_phys_out_ofs; + unsigned int src_mask; + unsigned int dest_mask; +}; + +/* Audio stream */ +struct lola_stream { + unsigned int nid; /* audio widget NID */ + unsigned int index; /* array index */ + unsigned int dsd; /* DSD index */ + bool can_float; + struct snd_pcm_substream *substream; /* assigned PCM substream */ + struct lola_stream *master; /* master stream (for multi-channel) */ + + /* buffer setup */ + unsigned int bufsize; + unsigned int period_bytes; + unsigned int frags; + + /* format + channel setup */ + unsigned int format_verb; + + /* flags */ + unsigned int opened:1; + unsigned int prepared:1; + unsigned int paused:1; + unsigned int running:1; +}; + +#define PLAY SNDRV_PCM_STREAM_PLAYBACK +#define CAPT SNDRV_PCM_STREAM_CAPTURE + +struct lola_pcm { + unsigned int num_streams; + struct snd_dma_buffer bdl; /* BDL buffer */ + struct lola_stream streams[MAX_STREAM_COUNT]; +}; + +/* card instance */ +struct lola { + struct snd_card *card; + struct pci_dev *pci; + + /* pci resources */ + struct lola_bar bar[2]; + int irq; + + /* locks */ + spinlock_t reg_lock; + struct mutex open_mutex; + + /* CORB/RIRB */ + struct lola_rb corb; + struct lola_rb rirb; + unsigned int res, res_ex; /* last read values */ + /* last command (for debugging) */ + unsigned int last_cmd_nid, last_verb, last_data, last_extdata; + + /* CORB/RIRB buffers */ + struct snd_dma_buffer rb; + + /* unsolicited events */ + unsigned int last_unsol_res; + + /* streams */ + struct lola_pcm pcm[2]; + + /* input src */ + unsigned int input_src_caps_mask; + unsigned int input_src_mask; + + /* pins */ + struct lola_pin_array pin[2]; + + /* clock */ + struct lola_clock_widget clock; + int ref_count_rate; + unsigned int sample_rate; + + /* mixer */ + struct lola_mixer_widget mixer; + + /* hw info */ + unsigned int version; + unsigned int lola_caps; + + /* parameters */ + unsigned int granularity; + unsigned int sample_rate_min; + unsigned int sample_rate_max; + + /* flags */ + unsigned int initialized:1; + unsigned int cold_reset:1; + unsigned int polling_mode:1; + + /* for debugging */ + unsigned int debug_res; + unsigned int debug_res_ex; +}; + +#define BAR0 0 +#define BAR1 1 + +/* Helper macros */ +#define lola_readl(chip, idx, name) \ + readl((chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_readw(chip, idx, name) \ + readw((chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_readb(chip, idx, name) \ + readb((chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_writel(chip, idx, name, val) \ + writel((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_writew(chip, idx, name, val) \ + writew((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name) +#define lola_writeb(chip, idx, name, val) \ + writeb((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name) + +#define lola_dsd_read(chip, dsd, name) \ + readl((chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \ + (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name) +#define lola_dsd_write(chip, dsd, name, val) \ + writel((val), (chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \ + (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name) + +/* GET verbs HDAudio */ +#define LOLA_VERB_GET_STREAM_FORMAT 0xa00 +#define LOLA_VERB_GET_AMP_GAIN_MUTE 0xb00 +#define LOLA_VERB_PARAMETERS 0xf00 +#define LOLA_VERB_GET_POWER_STATE 0xf05 +#define LOLA_VERB_GET_CONV 0xf06 +#define LOLA_VERB_GET_UNSOLICITED_RESPONSE 0xf08 +#define LOLA_VERB_GET_DIGI_CONVERT_1 0xf0d +#define LOLA_VERB_GET_CONFIG_DEFAULT 0xf1c +#define LOLA_VERB_GET_SUBSYSTEM_ID 0xf20 +/* GET verbs Digigram */ +#define LOLA_VERB_GET_FIXED_GAIN 0xfc0 +#define LOLA_VERB_GET_GAIN_SELECT 0xfc1 +#define LOLA_VERB_GET_MAX_LEVEL 0xfc2 +#define LOLA_VERB_GET_CLOCK_LIST 0xfc3 +#define LOLA_VERB_GET_CLOCK_SELECT 0xfc4 +#define LOLA_VERB_GET_CLOCK_STATUS 0xfc5 + +/* SET verbs HDAudio */ +#define LOLA_VERB_SET_STREAM_FORMAT 0x200 +#define LOLA_VERB_SET_AMP_GAIN_MUTE 0x300 +#define LOLA_VERB_SET_POWER_STATE 0x705 +#define LOLA_VERB_SET_CHANNEL_STREAMID 0x706 +#define LOLA_VERB_SET_UNSOLICITED_ENABLE 0x708 +#define LOLA_VERB_SET_DIGI_CONVERT_1 0x70d +/* SET verbs Digigram */ +#define LOLA_VERB_SET_GAIN_SELECT 0xf81 +#define LOLA_VERB_SET_CLOCK_SELECT 0xf84 +#define LOLA_VERB_SET_GRANULARITY_STEPS 0xf86 +#define LOLA_VERB_SET_SOURCE_GAIN 0xf87 +#define LOLA_VERB_SET_MIX_GAIN 0xf88 +#define LOLA_VERB_SET_DESTINATION_GAIN 0xf89 +#define LOLA_VERB_SET_SRC 0xf8a + +/* Parameter IDs used with LOLA_VERB_PARAMETERS */ +#define LOLA_PAR_VENDOR_ID 0x00 +#define LOLA_PAR_FUNCTION_TYPE 0x05 +#define LOLA_PAR_AUDIO_WIDGET_CAP 0x09 +#define LOLA_PAR_PCM 0x0a +#define LOLA_PAR_STREAM_FORMATS 0x0b +#define LOLA_PAR_PIN_CAP 0x0c +#define LOLA_PAR_AMP_IN_CAP 0x0d +#define LOLA_PAR_CONNLIST_LEN 0x0e +#define LOLA_PAR_POWER_STATE 0x0f +#define LOLA_PAR_GPIO_CAP 0x11 +#define LOLA_PAR_AMP_OUT_CAP 0x12 +#define LOLA_PAR_SPECIFIC_CAPS 0x80 +#define LOLA_PAR_FIXED_GAIN_LIST 0x81 + +/* extract results of LOLA_PAR_SPECIFIC_CAPS */ +#define LOLA_AFG_MIXER_WIDGET_PRESENT(res) ((res & (1 << 21)) != 0) +#define LOLA_AFG_CLOCK_WIDGET_PRESENT(res) ((res & (1 << 20)) != 0) +#define LOLA_AFG_INPUT_PIN_COUNT(res) ((res >> 10) & 0x2ff) +#define LOLA_AFG_OUTPUT_PIN_COUNT(res) ((res) & 0x2ff) + +/* extract results of LOLA_PAR_AMP_IN_CAP / LOLA_PAR_AMP_OUT_CAP */ +#define LOLA_AMP_MUTE_CAPABLE(res) ((res & (1 << 31)) != 0) +#define LOLA_AMP_STEP_SIZE(res) ((res >> 24) & 0x7f) +#define LOLA_AMP_NUM_STEPS(res) ((res >> 12) & 0x3ff) +#define LOLA_AMP_OFFSET(res) ((res) & 0x3ff) + +#define LOLA_GRANULARITY_MIN 8 +#define LOLA_GRANULARITY_MAX 32 +#define LOLA_GRANULARITY_STEP 8 + +/* parameters used with unsolicited command/response */ +#define LOLA_UNSOLICITED_TAG_MASK 0x3f +#define LOLA_UNSOLICITED_TAG 0x1a +#define LOLA_UNSOLICITED_ENABLE 0x80 +#define LOLA_UNSOL_RESP_TAG_OFFSET 26 + +/* count values in the Vendor Specific Mixer Widget's Audio Widget Capabilities */ +#define LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(res) ((res >> 2) & 0x1f) +#define LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(res) ((res >> 7) & 0x1f) + +int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb, + unsigned int data, unsigned int extdata); +int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb, + unsigned int data, unsigned int extdata, + unsigned int *val, unsigned int *extval); +int lola_codec_flush(struct lola *chip); +#define lola_read_param(chip, nid, param, val) \ + lola_codec_read(chip, nid, LOLA_VERB_PARAMETERS, param, 0, val, NULL) + +/* PCM */ +int lola_create_pcm(struct lola *chip); +void lola_free_pcm(struct lola *chip); +int lola_init_pcm(struct lola *chip, int dir, int *nidp); +void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits); + +/* clock */ +int lola_init_clock_widget(struct lola *chip, int nid); +int lola_set_granularity(struct lola *chip, unsigned int val, bool force); +int lola_enable_clock_events(struct lola *chip); +int lola_set_clock_index(struct lola *chip, unsigned int idx); +int lola_set_clock(struct lola *chip, int idx); +int lola_set_sample_rate(struct lola *chip, int rate); +bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val); +unsigned int lola_sample_rate_convert(unsigned int coded); + +/* mixer */ +int lola_init_pins(struct lola *chip, int dir, int *nidp); +int lola_init_mixer_widget(struct lola *chip, int nid); +void lola_free_mixer(struct lola *chip); +int lola_create_mixer(struct lola *chip); +int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute); +void lola_save_mixer(struct lola *chip); +void lola_restore_mixer(struct lola *chip); +int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update); + +/* proc */ +#ifdef CONFIG_SND_DEBUG +void lola_proc_debug_new(struct lola *chip); +#else +#define lola_proc_debug_new(chip) +#endif + +#endif /* _LOLA_H */ diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c new file mode 100644 index 000000000000..72f8ef0ac865 --- /dev/null +++ b/sound/pci/lola/lola_clock.c @@ -0,0 +1,323 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include "lola.h" + +unsigned int lola_sample_rate_convert(unsigned int coded) +{ + unsigned int freq; + + /* base frequency */ + switch (coded & 0x3) { + case 0: freq = 48000; break; + case 1: freq = 44100; break; + case 2: freq = 32000; break; + default: return 0; /* error */ + } + + /* multiplier / devisor */ + switch (coded & 0x1c) { + case (0 << 2): break; + case (4 << 2): break; + case (1 << 2): freq *= 2; break; + case (2 << 2): freq *= 4; break; + case (5 << 2): freq /= 2; break; + case (6 << 2): freq /= 4; break; + default: return 0; /* error */ + } + + /* ajustement */ + switch (coded & 0x60) { + case (0 << 5): break; + case (1 << 5): freq = (freq * 999) / 1000; break; + case (2 << 5): freq = (freq * 1001) / 1000; break; + default: return 0; /* error */ + } + return freq; +} + +/* + * Granualrity + */ + +#define LOLA_MAXFREQ_AT_GRANULARITY_MIN 48000 +#define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX 96000 + +static bool check_gran_clock_compatibility(struct lola *chip, + unsigned int val, + unsigned int freq) +{ + if (!chip->granularity) + return true; + + if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX || + (val % LOLA_GRANULARITY_STEP) != 0) + return false; + + if (val == LOLA_GRANULARITY_MIN) { + if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN) + return false; + } else if (val < LOLA_GRANULARITY_MAX) { + if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX) + return false; + } + return true; +} + +int lola_set_granularity(struct lola *chip, unsigned int val, bool force) +{ + int err; + + if (!force) { + if (val == chip->granularity) + return 0; +#if 0 + /* change Gran only if there are no streams allocated ! */ + if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask) + return -EBUSY; +#endif + if (!check_gran_clock_compatibility(chip, val, + chip->clock.cur_freq)) + return -EINVAL; + } + + chip->granularity = val; + val /= LOLA_GRANULARITY_STEP; + + /* audio function group */ + err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS, + val, 0); + if (err < 0) + return err; + /* this can be a very slow function !!! */ + usleep_range(400 * val, 20000); + return lola_codec_flush(chip); +} + +/* + * Clock widget handling + */ + +int __devinit lola_init_clock_widget(struct lola *chip, int nid) +{ + unsigned int val; + int i, j, nitems, nb_verbs, idx, idx_list; + int err; + + err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + return err; + } + + if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */ + snd_printdd("No valid clock widget\n"); + return 0; + } + + chip->clock.nid = nid; + chip->clock.items = val & 0xff; + snd_printdd("clock_list nid=%x, entries=%d\n", nid, + chip->clock.items); + if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) { + printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n", + chip->clock.items); + return -EINVAL; + } + + nitems = chip->clock.items; + nb_verbs = (nitems + 3) / 4; + idx = 0; + idx_list = 0; + for (i = 0; i < nb_verbs; i++) { + unsigned int res_ex; + unsigned short items[4]; + + err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST, + idx, 0, &val, &res_ex); + if (err < 0) { + printk(KERN_ERR SFX "Can't read CLOCK_LIST\n"); + return -EINVAL; + } + + items[0] = val & 0xfff; + items[1] = (val >> 16) & 0xfff; + items[2] = res_ex & 0xfff; + items[3] = (res_ex >> 16) & 0xfff; + + for (j = 0; j < 4; j++) { + unsigned char type = items[j] >> 8; + unsigned int freq = items[j] & 0xff; + int format = LOLA_CLOCK_FORMAT_NONE; + bool add_clock = true; + if (type == LOLA_CLOCK_TYPE_INTERNAL) { + freq = lola_sample_rate_convert(freq); + if (freq < chip->sample_rate_min) + add_clock = false; + else if (freq == 48000) { + chip->clock.cur_index = idx_list; + chip->clock.cur_freq = 48000; + chip->clock.cur_valid = true; + } + } else if (type == LOLA_CLOCK_TYPE_VIDEO) { + freq = lola_sample_rate_convert(freq); + if (freq < chip->sample_rate_min) + add_clock = false; + /* video clock has a format (0:NTSC, 1:PAL)*/ + if (items[j] & 0x80) + format = LOLA_CLOCK_FORMAT_NTSC; + else + format = LOLA_CLOCK_FORMAT_PAL; + } + if (add_clock) { + struct lola_sample_clock *sc; + sc = &chip->clock.sample_clock[idx_list]; + sc->type = type; + sc->format = format; + sc->freq = freq; + /* keep the index used with the board */ + chip->clock.idx_lookup[idx_list] = idx; + idx_list++; + } else { + chip->clock.items--; + } + if (++idx >= nitems) + break; + } + } + return 0; +} + +/* enable unsolicited events of the clock widget */ +int lola_enable_clock_events(struct lola *chip) +{ + unsigned int res; + int err; + + err = lola_codec_read(chip, chip->clock.nid, + LOLA_VERB_SET_UNSOLICITED_ENABLE, + LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG, + 0, &res, NULL); + if (err < 0) + return err; + if (res) { + printk(KERN_WARNING SFX "error in enable_clock_events %d\n", + res); + return -EINVAL; + } + return 0; +} + +int lola_set_clock_index(struct lola *chip, unsigned int idx) +{ + unsigned int res; + int err; + + err = lola_codec_read(chip, chip->clock.nid, + LOLA_VERB_SET_CLOCK_SELECT, + chip->clock.idx_lookup[idx], + 0, &res, NULL); + if (err < 0) + return err; + if (res) { + printk(KERN_WARNING SFX "error in set_clock %d\n", res); + return -EINVAL; + } + return 0; +} + +bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val) +{ + unsigned int tag; + + /* the current EXTERNAL clock information gets updated by interrupt + * with an unsolicited response + */ + if (!val) + return false; + tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK; + if (tag != LOLA_UNSOLICITED_TAG) + return false; + + /* only for current = external clocks */ + if (chip->clock.sample_clock[chip->clock.cur_index].type != + LOLA_CLOCK_TYPE_INTERNAL) { + chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f); + chip->clock.cur_valid = (val & 0x100) != 0; + } + return true; +} + +int lola_set_clock(struct lola *chip, int idx) +{ + int freq = 0; + bool valid = false; + + if (idx == chip->clock.cur_index) { + /* current clock is allowed */ + freq = chip->clock.cur_freq; + valid = chip->clock.cur_valid; + } else if (chip->clock.sample_clock[idx].type == + LOLA_CLOCK_TYPE_INTERNAL) { + /* internal clocks allowed */ + freq = chip->clock.sample_clock[idx].freq; + valid = true; + } + + if (!freq || !valid) + return -EINVAL; + + if (!check_gran_clock_compatibility(chip, chip->granularity, freq)) + return -EINVAL; + + if (idx != chip->clock.cur_index) { + int err = lola_set_clock_index(chip, idx); + if (err < 0) + return err; + /* update new settings */ + chip->clock.cur_index = idx; + chip->clock.cur_freq = freq; + chip->clock.cur_valid = true; + } + return 0; +} + +int lola_set_sample_rate(struct lola *chip, int rate) +{ + int i; + + if (chip->clock.cur_freq == rate && chip->clock.cur_valid) + return 0; + /* search for new dwClockIndex */ + for (i = 0; i < chip->clock.items; i++) { + if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL && + chip->clock.sample_clock[i].freq == rate) + break; + } + if (i >= chip->clock.items) + return -EINVAL; + return lola_set_clock(chip, i); +} + diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c new file mode 100644 index 000000000000..5d518f1a712c --- /dev/null +++ b/sound/pci/lola/lola_mixer.c @@ -0,0 +1,839 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/io.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/tlv.h> +#include "lola.h" + +static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, + int dir, int nid) +{ + unsigned int val; + int err; + + pin->nid = nid; + err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + return err; + } + val &= 0x00f00fff; /* test TYPE and bits 0..11 */ + if (val == 0x00400200) /* Type = 4, Digital = 1 */ + pin->is_analog = false; + else if (val == 0x0040000a && dir == CAPT) /* Dig=0, InAmp/ovrd */ + pin->is_analog = true; + else if (val == 0x0040000c && dir == PLAY) /* Dig=0, OutAmp/ovrd */ + pin->is_analog = true; + else { + printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", val, nid); + return -EINVAL; + } + + /* analog parameters only following, so continue in case of Digital pin + */ + if (!pin->is_analog) + return 0; + + if (dir == PLAY) + err = lola_read_param(chip, nid, LOLA_PAR_AMP_OUT_CAP, &val); + else + err = lola_read_param(chip, nid, LOLA_PAR_AMP_IN_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read AMP-caps for 0x%x\n", nid); + return err; + } + + pin->amp_mute = LOLA_AMP_MUTE_CAPABLE(val); + pin->amp_step_size = LOLA_AMP_STEP_SIZE(val); + pin->amp_num_steps = LOLA_AMP_NUM_STEPS(val); + if (pin->amp_num_steps) { + /* zero as mute state */ + pin->amp_num_steps++; + pin->amp_step_size++; + } + pin->amp_offset = LOLA_AMP_OFFSET(val); + + err = lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, + NULL); + if (err < 0) { + printk(KERN_ERR SFX "Can't get MAX_LEVEL 0x%x\n", nid); + return err; + } + pin->max_level = val & 0x3ff; /* 10 bits */ + + pin->config_default_reg = 0; + pin->fixed_gain_list_len = 0; + pin->cur_gain_step = 0; + + return 0; +} + +int __devinit lola_init_pins(struct lola *chip, int dir, int *nidp) +{ + int i, err, nid; + nid = *nidp; + for (i = 0; i < chip->pin[dir].num_pins; i++, nid++) { + err = lola_init_pin(chip, &chip->pin[dir].pins[i], dir, nid); + if (err < 0) + return err; + if (chip->pin[dir].pins[i].is_analog) + chip->pin[dir].num_analog_pins++; + } + *nidp = nid; + return 0; +} + +void lola_free_mixer(struct lola *chip) +{ + if (chip->mixer.array_saved) + vfree(chip->mixer.array_saved); +} + +int __devinit lola_init_mixer_widget(struct lola *chip, int nid) +{ + unsigned int val; + int err; + + err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + return err; + } + + if ((val & 0xfff00000) != 0x02f00000) { /* test SubType and Type */ + snd_printdd("No valid mixer widget\n"); + return 0; + } + + chip->mixer.nid = nid; + chip->mixer.caps = val; + chip->mixer.array = (struct lola_mixer_array __iomem *) + (chip->bar[BAR1].remap_addr + LOLA_BAR1_SOURCE_GAIN_ENABLE); + + /* reserve memory to copy mixer data for sleep mode transitions */ + chip->mixer.array_saved = vmalloc(sizeof(struct lola_mixer_array)); + + /* mixer matrix sources are physical input data and play streams */ + chip->mixer.src_stream_outs = chip->pcm[PLAY].num_streams; + chip->mixer.src_phys_ins = chip->pin[CAPT].num_pins; + + /* mixer matrix destinations are record streams and physical output */ + chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams; + chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins; + + /* mixer matrix can have unused areas between PhysIn and + * Play or Record and PhysOut zones + */ + chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins + + LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val); + chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins + + LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(val); + + /* example : MixerMatrix of LoLa881 + * 0-------8------16-------8------16 + * | | | | | + * | INPUT | | INPUT | | + * | -> |unused | -> |unused | + * | RECORD| | OUTPUT| | + * | | | | | + * 8-------------------------------- + * | | | | | + * | | | | | + * |unused |unused |unused |unused | + * | | | | | + * | | | | | + * 16------------------------------- + * | | | | | + * | PLAY | | PLAY | | + * | -> |unused | -> |unused | + * | RECORD| | OUTPUT| | + * | | | | | + * 8-------------------------------- + * | | | | | + * | | | | | + * |unused |unused |unused |unused | + * | | | | | + * | | | | | + * 16------------------------------- + */ + if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT || + chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) { + printk(KERN_ERR SFX "Invalid mixer widget size\n"); + return -EINVAL; + } + + chip->mixer.src_mask = ((1U << chip->mixer.src_phys_ins) - 1) | + (((1U << chip->mixer.src_stream_outs) - 1) + << chip->mixer.src_stream_out_ofs); + chip->mixer.dest_mask = ((1U << chip->mixer.dest_stream_ins) - 1) | + (((1U << chip->mixer.dest_phys_outs) - 1) + << chip->mixer.dest_phys_out_ofs); + + return 0; +} + +static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id, + unsigned short gain, bool on) +{ + unsigned int oldval, val; + + if (!(chip->mixer.src_mask & (1 << id))) + return -EINVAL; + writew(gain, &chip->mixer.array->src_gain[id]); + oldval = val = readl(&chip->mixer.array->src_gain_enable); + if (on) + val |= (1 << id); + else + val &= ~(1 << id); + writel(val, &chip->mixer.array->src_gain_enable); + lola_codec_flush(chip); + /* inform micro-controller about the new source gain */ + return lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, id, 0); +} + +#if 0 /* not used */ +static int lola_mixer_set_src_gains(struct lola *chip, unsigned int mask, + unsigned short *gains) +{ + int i; + + if ((chip->mixer.src_mask & mask) != mask) + return -EINVAL; + for (i = 0; i < LOLA_MIXER_DIM; i++) { + if (mask & (1 << i)) { + writew(*gains, &chip->mixer.array->src_gain[i]); + gains++; + } + } + writel(mask, &chip->mixer.array->src_gain_enable); + lola_codec_flush(chip); + if (chip->mixer.caps & LOLA_PEAK_METER_CAN_AGC_MASK) { + /* update for all srcs at once */ + return lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, 0x80, 0); + } + /* update manually */ + for (i = 0; i < LOLA_MIXER_DIM; i++) { + if (mask & (1 << i)) { + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, i, 0); + } + } + return 0; +} +#endif /* not used */ + +static int lola_mixer_set_mapping_gain(struct lola *chip, + unsigned int src, unsigned int dest, + unsigned short gain, bool on) +{ + unsigned int val; + + if (!(chip->mixer.src_mask & (1 << src)) || + !(chip->mixer.dest_mask & (1 << dest))) + return -EINVAL; + if (on) + writew(gain, &chip->mixer.array->dest_mix_gain[dest][src]); + val = readl(&chip->mixer.array->dest_mix_gain_enable[dest]); + if (on) + val |= (1 << src); + else + val &= ~(1 << src); + writel(val, &chip->mixer.array->dest_mix_gain_enable[dest]); + lola_codec_flush(chip); + return lola_codec_write(chip, chip->mixer.nid, LOLA_VERB_SET_MIX_GAIN, + src, dest); +} + +static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id, + unsigned int mask, unsigned short *gains) +{ + int i; + + if (!(chip->mixer.dest_mask & (1 << id)) || + (chip->mixer.src_mask & mask) != mask) + return -EINVAL; + for (i = 0; i < LOLA_MIXER_DIM; i++) { + if (mask & (1 << i)) { + writew(*gains, &chip->mixer.array->dest_mix_gain[id][i]); + gains++; + } + } + writel(mask, &chip->mixer.array->dest_mix_gain_enable[id]); + lola_codec_flush(chip); + /* update for all dests at once */ + return lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_DESTINATION_GAIN, id, 0); +} + +/* + */ + +static int set_analog_volume(struct lola *chip, int dir, + unsigned int idx, unsigned int val, + bool external_call); + +int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute) +{ + struct lola_pin *pin; + int idx, max_idx; + + pin = chip->pin[dir].pins; + max_idx = chip->pin[dir].num_pins; + for (idx = 0; idx < max_idx; idx++) { + if (pin[idx].is_analog) { + unsigned int val = mute ? 0 : pin[idx].cur_gain_step; + /* set volume and do not save the value */ + set_analog_volume(chip, dir, idx, val, false); + } + } + return lola_codec_flush(chip); +} + +void lola_save_mixer(struct lola *chip) +{ + /* mute analog output */ + if (chip->mixer.array_saved) { + /* store contents of mixer array */ + memcpy_fromio(chip->mixer.array_saved, chip->mixer.array, + sizeof(*chip->mixer.array)); + } + lola_setup_all_analog_gains(chip, PLAY, true); /* output mute */ +} + +void lola_restore_mixer(struct lola *chip) +{ + int i; + + /*lola_reset_setups(chip);*/ + if (chip->mixer.array_saved) { + /* restore contents of mixer array */ + memcpy_toio(chip->mixer.array, chip->mixer.array_saved, + sizeof(*chip->mixer.array)); + /* inform micro-controller about all restored values + * and ignore return values + */ + for (i = 0; i < chip->mixer.src_phys_ins; i++) + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, + i, 0); + for (i = 0; i < chip->mixer.src_stream_outs; i++) + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_SOURCE_GAIN, + chip->mixer.src_stream_out_ofs + i, 0); + for (i = 0; i < chip->mixer.dest_stream_ins; i++) + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_DESTINATION_GAIN, + i, 0); + for (i = 0; i < chip->mixer.dest_phys_outs; i++) + lola_codec_write(chip, chip->mixer.nid, + LOLA_VERB_SET_DESTINATION_GAIN, + chip->mixer.dest_phys_out_ofs + i, 0); + lola_codec_flush(chip); + } +} + +/* + */ + +static int set_analog_volume(struct lola *chip, int dir, + unsigned int idx, unsigned int val, + bool external_call) +{ + struct lola_pin *pin; + int err; + + if (idx >= chip->pin[dir].num_pins) + return -EINVAL; + pin = &chip->pin[dir].pins[idx]; + if (!pin->is_analog || pin->amp_num_steps <= val) + return -EINVAL; + if (external_call && pin->cur_gain_step == val) + return 0; + if (external_call) + lola_codec_flush(chip); + err = lola_codec_write(chip, pin->nid, + LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0); + if (err < 0) + return err; + if (external_call) + pin->cur_gain_step = val; + return 0; +} + +int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update) +{ + int ret = 0; + int success = 0; + int n, err; + + /* SRC can be activated and the dwInputSRCMask is valid? */ + if ((chip->input_src_caps_mask & src_mask) != src_mask) + return -EINVAL; + /* handle all even Inputs - SRC is a stereo setting !!! */ + for (n = 0; n < chip->pin[CAPT].num_pins; n += 2) { + unsigned int mask = 3U << n; /* handle the stereo case */ + unsigned int new_src, src_state; + if (!(chip->input_src_caps_mask & mask)) + continue; + /* if one IO needs SRC, both stereo IO will get SRC */ + new_src = (src_mask & mask) != 0; + if (update) { + src_state = (chip->input_src_mask & mask) != 0; + if (src_state == new_src) + continue; /* nothing to change for this IO */ + } + err = lola_codec_write(chip, chip->pcm[CAPT].streams[n].nid, + LOLA_VERB_SET_SRC, new_src, 0); + if (!err) + success++; + else + ret = err; + } + if (success) + ret = lola_codec_flush(chip); + if (!ret) + chip->input_src_mask = src_mask; + return ret; +} + +/* + */ +static int init_mixer_values(struct lola *chip) +{ + int i; + + /* all src on */ + lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false); + + /* clear all matrix */ + memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array)); + /* set src gain to 0dB */ + for (i = 0; i < chip->mixer.src_phys_ins; i++) + lola_mixer_set_src_gain(chip, i, 336, true); /* 0dB */ + for (i = 0; i < chip->mixer.src_stream_outs; i++) + lola_mixer_set_src_gain(chip, + i + chip->mixer.src_stream_out_ofs, + 336, true); /* 0dB */ + /* set 1:1 dest gain */ + for (i = 0; i < chip->mixer.dest_stream_ins; i++) { + int src = i % chip->mixer.src_phys_ins; + lola_mixer_set_mapping_gain(chip, src, i, 336, true); + } + for (i = 0; i < chip->mixer.src_stream_outs; i++) { + int src = chip->mixer.src_stream_out_ofs + i; + int dst = chip->mixer.dest_phys_out_ofs + + i % chip->mixer.dest_phys_outs; + lola_mixer_set_mapping_gain(chip, src, dst, 336, true); + } + return 0; +} + +/* + * analog mixer control element + */ +static int lola_analog_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int dir = kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chip->pin[dir].num_pins; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = chip->pin[dir].pins[0].amp_num_steps; + return 0; +} + +static int lola_analog_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int dir = kcontrol->private_value; + int i; + + for (i = 0; i < chip->pin[dir].num_pins; i++) + ucontrol->value.integer.value[i] = + chip->pin[dir].pins[i].cur_gain_step; + return 0; +} + +static int lola_analog_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int dir = kcontrol->private_value; + int i, err; + + for (i = 0; i < chip->pin[dir].num_pins; i++) { + err = set_analog_volume(chip, dir, i, + ucontrol->value.integer.value[i], + true); + if (err < 0) + return err; + } + return 0; +} + +static int lola_analog_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int dir = kcontrol->private_value; + unsigned int val1, val2; + struct lola_pin *pin; + + if (size < 4 * sizeof(unsigned int)) + return -ENOMEM; + pin = &chip->pin[dir].pins[0]; + + val2 = pin->amp_step_size * 25; + val1 = -1 * (int)pin->amp_offset * (int)val2; +#ifdef TLV_DB_SCALE_MUTE + val2 |= TLV_DB_SCALE_MUTE; +#endif + if (put_user(SNDRV_CTL_TLVT_DB_SCALE, tlv)) + return -EFAULT; + if (put_user(2 * sizeof(unsigned int), tlv + 1)) + return -EFAULT; + if (put_user(val1, tlv + 2)) + return -EFAULT; + if (put_user(val2, tlv + 3)) + return -EFAULT; + return 0; +} + +static struct snd_kcontrol_new lola_analog_mixer __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), + .info = lola_analog_vol_info, + .get = lola_analog_vol_get, + .put = lola_analog_vol_put, + .tlv.c = lola_analog_vol_tlv, +}; + +static int __devinit create_analog_mixer(struct lola *chip, int dir, char *name) +{ + if (!chip->pin[dir].num_pins) + return 0; + /* no analog volumes on digital only adapters */ + if (chip->pin[dir].num_pins != chip->pin[dir].num_analog_pins) + return 0; + lola_analog_mixer.name = name; + lola_analog_mixer.private_value = dir; + return snd_ctl_add(chip->card, + snd_ctl_new1(&lola_analog_mixer, chip)); +} + +/* + * Hardware sample rate converter on digital input + */ +static int lola_input_src_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = chip->pin[CAPT].num_pins; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int lola_input_src_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int i; + + for (i = 0; i < chip->pin[CAPT].num_pins; i++) + ucontrol->value.integer.value[i] = + !!(chip->input_src_mask & (1 << i)); + return 0; +} + +static int lola_input_src_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + int i; + unsigned int mask; + + mask = 0; + for (i = 0; i < chip->pin[CAPT].num_pins; i++) + if (ucontrol->value.integer.value[i]) + mask |= 1 << i; + return lola_set_src_config(chip, mask, true); +} + +static struct snd_kcontrol_new lola_input_src_mixer __devinitdata = { + .name = "Digital SRC Capture Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = lola_input_src_info, + .get = lola_input_src_get, + .put = lola_input_src_put, +}; + +/* + * Lola16161 or Lola881 can have Hardware sample rate converters + * on its digital input pins + */ +static int __devinit create_input_src_mixer(struct lola *chip) +{ + if (!chip->input_src_caps_mask) + return 0; + + return snd_ctl_add(chip->card, + snd_ctl_new1(&lola_input_src_mixer, chip)); +} + +/* + * src gain mixer + */ +static int lola_src_gain_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int count = (kcontrol->private_value >> 8) & 0xff; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 409; + return 0; +} + +static int lola_src_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + unsigned int ofs = kcontrol->private_value & 0xff; + unsigned int count = (kcontrol->private_value >> 8) & 0xff; + unsigned int mask, i; + + mask = readl(&chip->mixer.array->src_gain_enable); + for (i = 0; i < count; i++) { + unsigned int idx = ofs + i; + unsigned short val; + if (!(chip->mixer.src_mask & (1 << idx))) + return -EINVAL; + if (mask & (1 << idx)) + val = readw(&chip->mixer.array->src_gain[idx]) + 1; + else + val = 0; + ucontrol->value.integer.value[i] = val; + } + return 0; +} + +static int lola_src_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + unsigned int ofs = kcontrol->private_value & 0xff; + unsigned int count = (kcontrol->private_value >> 8) & 0xff; + int i, err; + + for (i = 0; i < count; i++) { + unsigned int idx = ofs + i; + unsigned short val = ucontrol->value.integer.value[i]; + if (val) + val--; + err = lola_mixer_set_src_gain(chip, idx, val, !!val); + if (err < 0) + return err; + } + return 0; +} + +/* raw value: 0 = -84dB, 336 = 0dB, 408=18dB, incremented 1 for mute */ +static const DECLARE_TLV_DB_SCALE(lola_src_gain_tlv, -8425, 25, 1); + +static struct snd_kcontrol_new lola_src_gain_mixer __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .info = lola_src_gain_info, + .get = lola_src_gain_get, + .put = lola_src_gain_put, + .tlv.p = lola_src_gain_tlv, +}; + +static int __devinit create_src_gain_mixer(struct lola *chip, + int num, int ofs, char *name) +{ + lola_src_gain_mixer.name = name; + lola_src_gain_mixer.private_value = ofs + (num << 8); + return snd_ctl_add(chip->card, + snd_ctl_new1(&lola_src_gain_mixer, chip)); +} + +/* + * destination gain (matrix-like) mixer + */ +static int lola_dest_gain_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int src_num = (kcontrol->private_value >> 8) & 0xff; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = src_num; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 433; + return 0; +} + +static int lola_dest_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + unsigned int src_ofs = kcontrol->private_value & 0xff; + unsigned int src_num = (kcontrol->private_value >> 8) & 0xff; + unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff; + unsigned int dst, mask, i; + + dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs; + mask = readl(&chip->mixer.array->dest_mix_gain_enable[dst]); + for (i = 0; i < src_num; i++) { + unsigned int src = src_ofs + i; + unsigned short val; + if (!(chip->mixer.src_mask & (1 << src))) + return -EINVAL; + if (mask & (1 << dst)) + val = readw(&chip->mixer.array->dest_mix_gain[dst][src]) + 1; + else + val = 0; + ucontrol->value.integer.value[i] = val; + } + return 0; +} + +static int lola_dest_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lola *chip = snd_kcontrol_chip(kcontrol); + unsigned int src_ofs = kcontrol->private_value & 0xff; + unsigned int src_num = (kcontrol->private_value >> 8) & 0xff; + unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff; + unsigned int dst, mask; + unsigned short gains[MAX_STREAM_COUNT]; + int i, num; + + mask = 0; + num = 0; + for (i = 0; i < src_num; i++) { + unsigned short val = ucontrol->value.integer.value[i]; + if (val) { + gains[num++] = val - 1; + mask |= 1 << i; + } + } + mask <<= src_ofs; + dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs; + return lola_mixer_set_dest_gains(chip, dst, mask, gains); +} + +static const DECLARE_TLV_DB_SCALE(lola_dest_gain_tlv, -8425, 25, 1); + +static struct snd_kcontrol_new lola_dest_gain_mixer __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .info = lola_dest_gain_info, + .get = lola_dest_gain_get, + .put = lola_dest_gain_put, + .tlv.p = lola_dest_gain_tlv, +}; + +static int __devinit create_dest_gain_mixer(struct lola *chip, + int src_num, int src_ofs, + int num, int ofs, char *name) +{ + lola_dest_gain_mixer.count = num; + lola_dest_gain_mixer.name = name; + lola_dest_gain_mixer.private_value = + src_ofs + (src_num << 8) + (ofs << 16) + (num << 24); + return snd_ctl_add(chip->card, + snd_ctl_new1(&lola_dest_gain_mixer, chip)); +} + +/* + */ +int __devinit lola_create_mixer(struct lola *chip) +{ + int err; + + err = create_analog_mixer(chip, PLAY, "Analog Playback Volume"); + if (err < 0) + return err; + err = create_analog_mixer(chip, CAPT, "Analog Capture Volume"); + if (err < 0) + return err; + err = create_input_src_mixer(chip); + if (err < 0) + return err; + err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0, + "Line Source Gain Volume"); + if (err < 0) + return err; + err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs, + chip->mixer.src_stream_out_ofs, + "Stream Source Gain Volume"); + if (err < 0) + return err; + err = create_dest_gain_mixer(chip, + chip->mixer.src_phys_ins, 0, + chip->mixer.dest_stream_ins, 0, + "Line Capture Volume"); + if (err < 0) + return err; + err = create_dest_gain_mixer(chip, + chip->mixer.src_stream_outs, + chip->mixer.src_stream_out_ofs, + chip->mixer.dest_stream_ins, 0, + "Stream-Loopback Capture Volume"); + if (err < 0) + return err; + err = create_dest_gain_mixer(chip, + chip->mixer.src_phys_ins, 0, + chip->mixer.dest_phys_outs, + chip->mixer.dest_phys_out_ofs, + "Line-Loopback Playback Volume"); + if (err < 0) + return err; + err = create_dest_gain_mixer(chip, + chip->mixer.src_stream_outs, + chip->mixer.src_stream_out_ofs, + chip->mixer.dest_phys_outs, + chip->mixer.dest_phys_out_ofs, + "Stream Playback Volume"); + if (err < 0) + return err; + + return init_mixer_values(chip); +} diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c new file mode 100644 index 000000000000..c44db68eecb5 --- /dev/null +++ b/sound/pci/lola/lola_pcm.c @@ -0,0 +1,706 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include "lola.h" + +#define LOLA_MAX_BDL_ENTRIES 8 +#define LOLA_MAX_BUF_SIZE (1024*1024*1024) +#define LOLA_BDL_ENTRY_SIZE (16 * 16) + +static struct lola_pcm *lola_get_pcm(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + return &chip->pcm[substream->stream]; +} + +static struct lola_stream *lola_get_stream(struct snd_pcm_substream *substream) +{ + struct lola_pcm *pcm = lola_get_pcm(substream); + unsigned int idx = substream->number; + return &pcm->streams[idx]; +} + +static unsigned int lola_get_lrc(struct lola *chip) +{ + return lola_readl(chip, BAR1, LRC); +} + +static unsigned int lola_get_tstamp(struct lola *chip, bool quick_no_sync) +{ + unsigned int tstamp = lola_get_lrc(chip) >> 8; + if (chip->granularity) { + unsigned int wait_banks = quick_no_sync ? 0 : 8; + tstamp += (wait_banks + 1) * chip->granularity - 1; + tstamp -= tstamp % chip->granularity; + } + return tstamp << 8; +} + +/* clear any pending interrupt status */ +static void lola_stream_clear_pending_irq(struct lola *chip, + struct lola_stream *str) +{ + unsigned int val = lola_dsd_read(chip, str->dsd, STS); + val &= LOLA_DSD_STS_DESE | LOLA_DSD_STS_BCIS; + if (val) + lola_dsd_write(chip, str->dsd, STS, val); +} + +static void lola_stream_start(struct lola *chip, struct lola_stream *str, + unsigned int tstamp) +{ + lola_stream_clear_pending_irq(chip, str); + lola_dsd_write(chip, str->dsd, CTL, + LOLA_DSD_CTL_SRUN | + LOLA_DSD_CTL_IOCE | + LOLA_DSD_CTL_DEIE | + LOLA_DSD_CTL_VLRCV | + tstamp); +} + +static void lola_stream_stop(struct lola *chip, struct lola_stream *str, + unsigned int tstamp) +{ + lola_dsd_write(chip, str->dsd, CTL, + LOLA_DSD_CTL_IOCE | + LOLA_DSD_CTL_DEIE | + LOLA_DSD_CTL_VLRCV | + tstamp); + lola_stream_clear_pending_irq(chip, str); +} + +static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) +{ + unsigned long end_time = jiffies + msecs_to_jiffies(200); + while (time_before(jiffies, end_time)) { + unsigned int val; + val = lola_dsd_read(chip, str->dsd, CTL); + if (!(val & LOLA_DSD_CTL_SRST)) + return; + msleep(1); + } + printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd); +} + +static int lola_stream_wait_for_fifo(struct lola *chip, + struct lola_stream *str, + bool ready) +{ + unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0; + unsigned long end_time = jiffies + msecs_to_jiffies(200); + while (time_before(jiffies, end_time)) { + unsigned int reg = lola_dsd_read(chip, str->dsd, STS); + if ((reg & LOLA_DSD_STS_FIFORDY) == val) + return 0; + msleep(1); + } + printk(KERN_WARNING SFX "FIFO not ready (stream %d)\n", str->dsd); + return -EIO; +} + +/* sync for FIFO ready/empty for all linked streams; + * clear paused flag when FIFO gets ready again + */ +static int lola_sync_wait_for_fifo(struct lola *chip, + struct snd_pcm_substream *substream, + bool ready) +{ + unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0; + unsigned long end_time = jiffies + msecs_to_jiffies(200); + struct snd_pcm_substream *s; + int pending = 0; + + while (time_before(jiffies, end_time)) { + pending = 0; + snd_pcm_group_for_each_entry(s, substream) { + struct lola_stream *str; + if (s->pcm->card != substream->pcm->card) + continue; + str = lola_get_stream(s); + if (str->prepared && str->paused) { + unsigned int reg; + reg = lola_dsd_read(chip, str->dsd, STS); + if ((reg & LOLA_DSD_STS_FIFORDY) != val) { + pending = str->dsd + 1; + break; + } + if (ready) + str->paused = 0; + } + } + if (!pending) + return 0; + msleep(1); + } + printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1); + return -EIO; +} + +/* finish pause - prepare for a new resume */ +static void lola_sync_pause(struct lola *chip, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_substream *s; + + lola_sync_wait_for_fifo(chip, substream, false); + snd_pcm_group_for_each_entry(s, substream) { + struct lola_stream *str; + if (s->pcm->card != substream->pcm->card) + continue; + str = lola_get_stream(s); + if (str->paused && str->prepared) + lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRUN | + LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE); + } + lola_sync_wait_for_fifo(chip, substream, true); +} + +static void lola_stream_reset(struct lola *chip, struct lola_stream *str) +{ + if (str->prepared) { + if (str->paused) + lola_sync_pause(chip, str->substream); + str->prepared = 0; + lola_dsd_write(chip, str->dsd, CTL, + LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE); + lola_stream_wait_for_fifo(chip, str, false); + lola_stream_clear_pending_irq(chip, str); + lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST); + lola_dsd_write(chip, str->dsd, LVI, 0); + lola_dsd_write(chip, str->dsd, BDPU, 0); + lola_dsd_write(chip, str->dsd, BDPL, 0); + wait_for_srst_clear(chip, str); + } +} + +static struct snd_pcm_hardware lola_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_FLOAT_LE), + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = LOLA_MAX_BUF_SIZE, + .period_bytes_min = 128, + .period_bytes_max = LOLA_MAX_BUF_SIZE / 2, + .periods_min = 2, + .periods_max = LOLA_MAX_BDL_ENTRIES, + .fifo_size = 0, +}; + +static int lola_pcm_open(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_pcm *pcm = lola_get_pcm(substream); + struct lola_stream *str = lola_get_stream(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + mutex_lock(&chip->open_mutex); + if (str->opened) { + mutex_unlock(&chip->open_mutex); + return -EBUSY; + } + str->substream = substream; + str->master = NULL; + str->opened = 1; + runtime->hw = lola_pcm_hw; + runtime->hw.channels_max = pcm->num_streams - str->index; + if (chip->sample_rate) { + /* sample rate is locked */ + runtime->hw.rate_min = chip->sample_rate; + runtime->hw.rate_max = chip->sample_rate; + } else { + runtime->hw.rate_min = chip->sample_rate_min; + runtime->hw.rate_max = chip->sample_rate_max; + } + chip->ref_count_rate++; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + /* period size = multiple of chip->granularity (8, 16 or 32 frames)*/ + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + chip->granularity); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + chip->granularity); + mutex_unlock(&chip->open_mutex); + return 0; +} + +static void lola_cleanup_slave_streams(struct lola_pcm *pcm, + struct lola_stream *str) +{ + int i; + for (i = str->index + 1; i < pcm->num_streams; i++) { + struct lola_stream *s = &pcm->streams[i]; + if (s->master != str) + break; + s->master = NULL; + s->opened = 0; + } +} + +static int lola_pcm_close(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_stream *str = lola_get_stream(substream); + + mutex_lock(&chip->open_mutex); + if (str->substream == substream) { + str->substream = NULL; + str->opened = 0; + } + if (--chip->ref_count_rate == 0) { + /* release sample rate */ + chip->sample_rate = 0; + } + mutex_unlock(&chip->open_mutex); + return 0; +} + +static int lola_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct lola_stream *str = lola_get_stream(substream); + + str->bufsize = 0; + str->period_bytes = 0; + str->format_verb = 0; + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +static int lola_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_pcm *pcm = lola_get_pcm(substream); + struct lola_stream *str = lola_get_stream(substream); + + mutex_lock(&chip->open_mutex); + lola_stream_reset(chip, str); + lola_cleanup_slave_streams(pcm, str); + mutex_unlock(&chip->open_mutex); + return snd_pcm_lib_free_pages(substream); +} + +/* + * set up a BDL entry + */ +static int setup_bdle(struct snd_pcm_substream *substream, + struct lola_stream *str, u32 **bdlp, + int ofs, int size) +{ + u32 *bdl = *bdlp; + + while (size > 0) { + dma_addr_t addr; + int chunk; + + if (str->frags >= LOLA_MAX_BDL_ENTRIES) + return -EINVAL; + + addr = snd_pcm_sgbuf_get_addr(substream, ofs); + /* program the address field of the BDL entry */ + bdl[0] = cpu_to_le32((u32)addr); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); + /* program the size field of the BDL entry */ + chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size); + bdl[2] = cpu_to_le32(chunk); + /* program the IOC to enable interrupt + * only when the whole fragment is processed + */ + size -= chunk; + bdl[3] = size ? 0 : cpu_to_le32(0x01); + bdl += 4; + str->frags++; + ofs += chunk; + } + *bdlp = bdl; + return ofs; +} + +/* + * set up BDL entries + */ +static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm, + struct snd_pcm_substream *substream, + struct lola_stream *str) +{ + u32 *bdl; + int i, ofs, periods, period_bytes; + + period_bytes = str->period_bytes; + periods = str->bufsize / period_bytes; + + /* program the initial BDL entries */ + bdl = (u32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index); + ofs = 0; + str->frags = 0; + for (i = 0; i < periods; i++) { + ofs = setup_bdle(substream, str, &bdl, ofs, period_bytes); + if (ofs < 0) + goto error; + } + return 0; + + error: + snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n", + str->bufsize, period_bytes); + return -EINVAL; +} + +static unsigned int lola_get_format_verb(struct snd_pcm_substream *substream) +{ + unsigned int verb; + + switch (substream->runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + verb = 0x00000000; + break; + case SNDRV_PCM_FORMAT_S24_LE: + verb = 0x00000200; + break; + case SNDRV_PCM_FORMAT_S32_LE: + verb = 0x00000300; + break; + case SNDRV_PCM_FORMAT_FLOAT_LE: + verb = 0x00001300; + break; + default: + return 0; + } + verb |= substream->runtime->channels; + return verb; +} + +static int lola_set_stream_config(struct lola *chip, + struct lola_stream *str, + int channels) +{ + int i, err; + unsigned int verb, val; + + /* set format info for all channels + * (with only one command for the first channel) + */ + err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT, + str->format_verb, 0, &val, NULL); + if (err < 0) { + printk(KERN_ERR SFX "Cannot set stream format 0x%x\n", + str->format_verb); + return err; + } + + /* update stream - channel config */ + for (i = 0; i < channels; i++) { + verb = (str->index << 6) | i; + err = lola_codec_read(chip, str[i].nid, + LOLA_VERB_SET_CHANNEL_STREAMID, 0, verb, + &val, NULL); + if (err < 0) { + printk(KERN_ERR SFX "Cannot set stream channel %d\n", i); + return err; + } + } + return 0; +} + +/* + * set up the SD for streaming + */ +static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm, + struct lola_stream *str) +{ + dma_addr_t bdl; + + if (str->prepared) + return -EINVAL; + + /* set up BDL */ + bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index; + lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl); + lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl)); + /* program the stream LVI (last valid index) of the BDL */ + lola_dsd_write(chip, str->dsd, LVI, str->frags - 1); + lola_stream_clear_pending_irq(chip, str); + + lola_dsd_write(chip, str->dsd, CTL, + LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_SRUN); + + str->prepared = 1; + + return lola_stream_wait_for_fifo(chip, str, true); +} + +static int lola_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_pcm *pcm = lola_get_pcm(substream); + struct lola_stream *str = lola_get_stream(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int bufsize, period_bytes, format_verb; + int i, err; + + mutex_lock(&chip->open_mutex); + lola_stream_reset(chip, str); + lola_cleanup_slave_streams(pcm, str); + if (str->index + runtime->channels > pcm->num_streams) { + mutex_unlock(&chip->open_mutex); + return -EINVAL; + } + for (i = 1; i < runtime->channels; i++) { + str[i].master = str; + str[i].opened = 1; + } + mutex_unlock(&chip->open_mutex); + + bufsize = snd_pcm_lib_buffer_bytes(substream); + period_bytes = snd_pcm_lib_period_bytes(substream); + format_verb = lola_get_format_verb(substream); + + str->bufsize = bufsize; + str->period_bytes = period_bytes; + str->format_verb = format_verb; + + err = lola_setup_periods(chip, pcm, substream, str); + if (err < 0) + return err; + + err = lola_set_sample_rate(chip, runtime->rate); + if (err < 0) + return err; + chip->sample_rate = runtime->rate; /* sample rate gets locked */ + + err = lola_set_stream_config(chip, str, runtime->channels); + if (err < 0) + return err; + + err = lola_setup_controller(chip, pcm, str); + if (err < 0) { + lola_stream_reset(chip, str); + return err; + } + + return 0; +} + +static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_stream *str; + struct snd_pcm_substream *s; + unsigned int start; + unsigned int tstamp; + bool sync_streams; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + start = 1; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + start = 0; + break; + default: + return -EINVAL; + } + + /* + * sample correct synchronization is only needed starting several + * streams. On stop or if only one stream do as quick as possible + */ + sync_streams = (start && snd_pcm_stream_linked(substream)); + tstamp = lola_get_tstamp(chip, !sync_streams); + spin_lock(&chip->reg_lock); + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + str = lola_get_stream(s); + if (start) + lola_stream_start(chip, str, tstamp); + else + lola_stream_stop(chip, str, tstamp); + str->running = start; + str->paused = !start; + snd_pcm_trigger_done(s, substream); + } + spin_unlock(&chip->reg_lock); + return 0; +} + +static snd_pcm_uframes_t lola_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct lola *chip = snd_pcm_substream_chip(substream); + struct lola_stream *str = lola_get_stream(substream); + unsigned int pos = lola_dsd_read(chip, str->dsd, LPIB); + + if (pos >= str->bufsize) + pos = 0; + return bytes_to_frames(substream->runtime, pos); +} + +void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits) +{ + int i; + + for (i = 0; bits && i < pcm->num_streams; i++) { + if (bits & (1 << i)) { + struct lola_stream *str = &pcm->streams[i]; + if (str->substream && str->running) + snd_pcm_period_elapsed(str->substream); + bits &= ~(1 << i); + } + } +} + +static struct snd_pcm_ops lola_pcm_ops = { + .open = lola_pcm_open, + .close = lola_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = lola_pcm_hw_params, + .hw_free = lola_pcm_hw_free, + .prepare = lola_pcm_prepare, + .trigger = lola_pcm_trigger, + .pointer = lola_pcm_pointer, + .page = snd_pcm_sgbuf_ops_page, +}; + +int __devinit lola_create_pcm(struct lola *chip) +{ + struct snd_pcm *pcm; + int i, err; + + for (i = 0; i < 2; i++) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + PAGE_SIZE, &chip->pcm[i].bdl); + if (err < 0) + return err; + } + + err = snd_pcm_new(chip->card, "Digigram Lola", 0, + chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams, + chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams, + &pcm); + if (err < 0) + return err; + strlcpy(pcm->name, "Digigram Lola", sizeof(pcm->name)); + pcm->private_data = chip; + for (i = 0; i < 2; i++) { + if (chip->pcm[i].num_streams) + snd_pcm_set_ops(pcm, i, &lola_pcm_ops); + } + /* buffer pre-allocation */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), + 1024 * 64, 32 * 1024 * 1024); + return 0; +} + +void lola_free_pcm(struct lola *chip) +{ + snd_dma_free_pages(&chip->pcm[0].bdl); + snd_dma_free_pages(&chip->pcm[1].bdl); +} + +/* + */ + +static int lola_init_stream(struct lola *chip, struct lola_stream *str, + int idx, int nid, int dir) +{ + unsigned int val; + int err; + + str->nid = nid; + str->index = idx; + str->dsd = idx; + if (dir == PLAY) + str->dsd += MAX_STREAM_IN_COUNT; + err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + return err; + } + if (dir == PLAY) { + /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */ + if ((val & 0x00f00dff) != 0x00000010) { + printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", + val, nid); + return -EINVAL; + } + } else { + /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) + * (bug : ignore bit8: Conn list = 0/1) + */ + if ((val & 0x00f00cff) != 0x00100010) { + printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", + val, nid); + return -EINVAL; + } + /* test bit9:DIGITAL and bit12:SRC_PRESENT*/ + if ((val & 0x00001200) == 0x00001200) + chip->input_src_caps_mask |= (1 << idx); + } + + err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val); + if (err < 0) { + printk(KERN_ERR SFX "Can't read FORMATS 0x%x\n", nid); + return err; + } + val &= 3; + if (val == 3) + str->can_float = true; + if (!(val & 1)) { + printk(KERN_ERR SFX "Invalid formats 0x%x for 0x%x", val, nid); + return -EINVAL; + } + return 0; +} + +int __devinit lola_init_pcm(struct lola *chip, int dir, int *nidp) +{ + struct lola_pcm *pcm = &chip->pcm[dir]; + int i, nid, err; + + nid = *nidp; + for (i = 0; i < pcm->num_streams; i++, nid++) { + err = lola_init_stream(chip, &pcm->streams[i], i, nid, dir); + if (err < 0) + return err; + } + *nidp = nid; + return 0; +} diff --git a/sound/pci/lola/lola_proc.c b/sound/pci/lola/lola_proc.c new file mode 100644 index 000000000000..9d7daf897c9d --- /dev/null +++ b/sound/pci/lola/lola_proc.c @@ -0,0 +1,222 @@ +/* + * Support for Digigram Lola PCI-e boards + * + * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <sound/core.h> +#include <sound/info.h> +#include <sound/pcm.h> +#include "lola.h" + +static void print_audio_widget(struct snd_info_buffer *buffer, + struct lola *chip, int nid, const char *name) +{ + unsigned int val; + + lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val); + lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val); + snd_iprintf(buffer, " Formats: 0x%x\n", val); +} + +static void print_pin_widget(struct snd_info_buffer *buffer, + struct lola *chip, int nid, unsigned int ampcap, + const char *name) +{ + unsigned int val; + + lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val); + if (val == 0x00400200) + return; + lola_read_param(chip, nid, ampcap, &val); + snd_iprintf(buffer, " Amp-Caps: 0x%x\n", val); + snd_iprintf(buffer, " mute=%d, step-size=%d, steps=%d, ofs=%d\n", + LOLA_AMP_MUTE_CAPABLE(val), + LOLA_AMP_STEP_SIZE(val), + LOLA_AMP_NUM_STEPS(val), + LOLA_AMP_OFFSET(val)); + lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, NULL); + snd_iprintf(buffer, " Max-level: 0x%x\n", val); +} + +static void print_clock_widget(struct snd_info_buffer *buffer, + struct lola *chip, int nid) +{ + int i, j, num_clocks; + unsigned int val; + + lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + snd_iprintf(buffer, "Node 0x%02x [Clock] wcaps 0x%x\n", nid, val); + num_clocks = val & 0xff; + for (i = 0; i < num_clocks; i += 4) { + unsigned int res_ex; + unsigned short items[4]; + const char *name; + + lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST, + i, 0, &val, &res_ex); + items[0] = val & 0xfff; + items[1] = (val >> 16) & 0xfff; + items[2] = res_ex & 0xfff; + items[3] = (res_ex >> 16) & 0xfff; + for (j = 0; j < 4; j++) { + unsigned char type = items[j] >> 8; + unsigned int freq = items[j] & 0xff; + if (i + j >= num_clocks) + break; + if (type == LOLA_CLOCK_TYPE_INTERNAL) { + name = "Internal"; + freq = lola_sample_rate_convert(freq); + } else if (type == LOLA_CLOCK_TYPE_VIDEO) { + name = "Video"; + freq = lola_sample_rate_convert(freq); + } else { + name = "Other"; + } + snd_iprintf(buffer, " Clock %d: Type %d:%s, freq=%d\n", + i + j, type, name, freq); + } + } +} + +static void print_mixer_widget(struct snd_info_buffer *buffer, + struct lola *chip, int nid) +{ + unsigned int val; + + lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); + snd_iprintf(buffer, "Node 0x%02x [Mixer] wcaps 0x%x\n", nid, val); +} + +static void lola_proc_codec_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct lola *chip = entry->private_data; + unsigned int val; + int i, nid; + + lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val); + snd_iprintf(buffer, "Vendor: 0x%08x\n", val); + lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val); + snd_iprintf(buffer, "Function Type: %d\n", val); + lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val); + snd_iprintf(buffer, "Specific-Caps: 0x%08x\n", val); + snd_iprintf(buffer, " Pins-In %d, Pins-Out %d\n", + chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins); + nid = 2; + for (i = 0; i < chip->pcm[CAPT].num_streams; i++, nid++) + print_audio_widget(buffer, chip, nid, "[Audio-In]"); + for (i = 0; i < chip->pcm[PLAY].num_streams; i++, nid++) + print_audio_widget(buffer, chip, nid, "[Audio-Out]"); + for (i = 0; i < chip->pin[CAPT].num_pins; i++, nid++) + print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_IN_CAP, + "[Pin-In]"); + for (i = 0; i < chip->pin[PLAY].num_pins; i++, nid++) + print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_OUT_CAP, + "[Pin-Out]"); + if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) { + print_clock_widget(buffer, chip, nid); + nid++; + } + if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) { + print_mixer_widget(buffer, chip, nid); + nid++; + } +} + +/* direct codec access for debugging */ +static void lola_proc_codec_rw_write(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct lola *chip = entry->private_data; + char line[64]; + unsigned int id, verb, data, extdata; + while (!snd_info_get_line(buffer, line, sizeof(line))) { + if (sscanf(line, "%i %i %i %i", &id, &verb, &data, &extdata) != 4) + continue; + lola_codec_read(chip, id, verb, data, extdata, + &chip->debug_res, + &chip->debug_res_ex); + } +} + +static void lola_proc_codec_rw_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct lola *chip = entry->private_data; + snd_iprintf(buffer, "0x%x 0x%x\n", chip->debug_res, chip->debug_res_ex); +} + +/* + * dump some registers + */ +static void lola_proc_regs_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct lola *chip = entry->private_data; + int i; + + for (i = 0; i < 0x40; i += 4) { + snd_iprintf(buffer, "BAR0 %02x: %08x\n", i, + readl(chip->bar[BAR0].remap_addr + i)); + } + snd_iprintf(buffer, "\n"); + for (i = 0; i < 0x30; i += 4) { + snd_iprintf(buffer, "BAR1 %02x: %08x\n", i, + readl(chip->bar[BAR1].remap_addr + i)); + } + snd_iprintf(buffer, "\n"); + for (i = 0x80; i < 0xa0; i += 4) { + snd_iprintf(buffer, "BAR1 %02x: %08x\n", i, + readl(chip->bar[BAR1].remap_addr + i)); + } + snd_iprintf(buffer, "\n"); + for (i = 0; i < 32; i++) { + snd_iprintf(buffer, "DSD %02x STS %08x\n", i, + lola_dsd_read(chip, i, STS)); + snd_iprintf(buffer, "DSD %02x LPIB %08x\n", i, + lola_dsd_read(chip, i, LPIB)); + snd_iprintf(buffer, "DSD %02x CTL %08x\n", i, + lola_dsd_read(chip, i, CTL)); + snd_iprintf(buffer, "DSD %02x LVIL %08x\n", i, + lola_dsd_read(chip, i, LVI)); + snd_iprintf(buffer, "DSD %02x BDPL %08x\n", i, + lola_dsd_read(chip, i, BDPL)); + snd_iprintf(buffer, "DSD %02x BDPU %08x\n", i, + lola_dsd_read(chip, i, BDPU)); + } +} + +void __devinit lola_proc_debug_new(struct lola *chip) +{ + struct snd_info_entry *entry; + + if (!snd_card_proc_new(chip->card, "codec", &entry)) + snd_info_set_text_ops(entry, chip, lola_proc_codec_read); + if (!snd_card_proc_new(chip->card, "codec_rw", &entry)) { + snd_info_set_text_ops(entry, chip, lola_proc_codec_rw_read); + entry->mode |= S_IWUSR; + entry->c.text.write = lola_proc_codec_rw_write; + } + if (!snd_card_proc_new(chip->card, "regs", &entry)) + snd_info_set_text_ops(entry, chip, lola_proc_regs_read); +} diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index d3350f383966..3df0f530f67c 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -265,7 +265,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int if (! timeout) { /* error - no ack */ mutex_unlock(&mgr->msg_mutex); - snd_printk(KERN_ERR "error: no reponse on msg %x\n", msg_frame); + snd_printk(KERN_ERR "error: no response on msg %x\n", msg_frame); return -EIO; } @@ -278,7 +278,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int err = get_msg(mgr, &resp, msg_frame); if( request->message_id != resp.message_id ) - snd_printk(KERN_ERR "REPONSE ERROR!\n"); + snd_printk(KERN_ERR "RESPONSE ERROR!\n"); mutex_unlock(&mgr->msg_mutex); return err; diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 833e7180ad2d..304411c1fe4b 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -1042,11 +1042,11 @@ void pcxhr_msg_tasklet(unsigned long arg) int i, j; if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE) - snd_printdd("TASKLET : PCXHR_IRQ_FREQ_CHANGE event occured\n"); + snd_printdd("TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n"); if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE) - snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occured\n"); + snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n"); if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY) - snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occured\n"); + snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occurred\n"); if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) { /* clear events FREQ_CHANGE and TIME_CODE */ pcxhr_init_rmh(prmh, CMD_TEST_IT); @@ -1055,7 +1055,7 @@ void pcxhr_msg_tasklet(unsigned long arg) err, prmh->stat[0]); } if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) { - snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occured\n"); + snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occurred\n"); pcxhr_init_rmh(prmh, CMD_ASYNC); prmh->cmd[0] |= 1; /* add SEL_ASYNC_EVENTS */ @@ -1233,7 +1233,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) reg = PCXHR_INPL(mgr, PCXHR_PLX_L2PCIDB); PCXHR_OUTPL(mgr, PCXHR_PLX_L2PCIDB, reg); - /* timer irq occured */ + /* timer irq occurred */ if (reg & PCXHR_IRQ_TIMER) { int timer_toggle = reg & PCXHR_IRQ_TIMER; /* is a 24 bit counter */ @@ -1288,7 +1288,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) if (reg & PCXHR_IRQ_MASK) { if (reg & PCXHR_IRQ_ASYNC) { /* as we didn't request any async notifications, - * some kind of xrun error will probably occured + * some kind of xrun error will probably occurred */ /* better resynchronize all streams next interrupt : */ mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index d5f5b440fc40..9ff247fc8871 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -150,7 +150,7 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard."); #define RME96_RCR_BITPOS_F1 28 #define RME96_RCR_BITPOS_F2 29 -/* Additonal register bits */ +/* Additional register bits */ #define RME96_AR_WSEL (1 << 0) #define RME96_AR_ANALOG (1 << 1) #define RME96_AR_FREQPAD_0 (1 << 2) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index a323eafb9e03..949691a876d3 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -391,7 +391,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); /* Status2 Register bits */ /* MADI ONLY */ -#define HDSPM_version0 (1<<0) /* not realy defined but I guess */ +#define HDSPM_version0 (1<<0) /* not really defined but I guess */ #define HDSPM_version1 (1<<1) /* in former cards it was ??? */ #define HDSPM_version2 (1<<2) @@ -936,7 +936,7 @@ struct hdspm { struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; /* but input to much, so not used */ struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; - /* full mixer accessable over mixer ioctl or hwdep-device */ + /* full mixer accessible over mixer ioctl or hwdep-device */ struct hdspm_mixer *mixer; struct hdspm_tco *tco; /* NULL if no TCO detected */ diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 1b8f6742b5fa..2b5c7a95ae1f 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -308,7 +308,7 @@ static irqreturn_t sis_interrupt(int irq, void *dev) u32 intr, status; /* We only use the DMA interrupts, and we don't enable any other - * source of interrupts. But, it is possible to see an interupt + * source of interrupts. But, it is possible to see an interrupt * status that didn't actually interrupt us, so eliminate anything * we're not expecting to avoid falsely claiming an IRQ, and an * ensuing endless loop. @@ -773,7 +773,7 @@ static void sis_prepare_timing_voice(struct voice *voice, vperiod = 0; } - /* The interrupt handler implements the timing syncronization, so + /* The interrupt handler implements the timing synchronization, so * setup its state. */ timing->flags |= VOICE_SYNC_TIMING; @@ -1139,7 +1139,7 @@ static int sis_chip_init(struct sis7019 *sis) */ outl(SIS_DMA_CSR_PCI_SETTINGS, io + SIS_DMA_CSR); - /* Reset the syncronization groups for all of the channels + /* Reset the synchronization groups for all of the channels * to be asyncronous. If we start doing SPDIF or 5.1 sound, etc. * we'll need to change how we handle these. Until then, we just * assign sub-mixer 0 to all playback channels, and avoid any diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 8cc4733698a0..ce33be0e4e98 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -278,7 +278,7 @@ static int pdacf_resume(struct pcmcia_device *link) /* * Module entry points */ -static struct pcmcia_device_id snd_pdacf_ids[] = { +static const struct pcmcia_device_id snd_pdacf_ids[] = { /* this is too general PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45), */ PCMCIA_DEVICE_PROD_ID12("Core Sound","PDAudio-CF",0x396d19d2,0x71717b49), PCMCIA_DEVICE_NULL diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 80000d631f88..d9ef21d8fa73 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -350,7 +350,7 @@ static void vxpocket_detach(struct pcmcia_device *link) * Module entry points */ -static struct pcmcia_device_id vxp_ids[] = { +static const struct pcmcia_device_id vxp_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100), PCMCIA_DEVICE_NULL }; diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index edce8a27e3ee..bc823a547550 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -358,7 +358,7 @@ static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) * filling dummy data, serial automatically start to * consume them and then will generate normal buffer * empty interrupts. - * If both buffer underflow and buffer empty are occured, + * If both buffer underflow and buffer empty are occurred, * it is better to do nomal data transfer than empty one */ snd_ps3_program_dma(card, diff --git a/sound/ppc/snd_ps3_reg.h b/sound/ppc/snd_ps3_reg.h index 03fdee4aaaf2..2e6302079566 100644 --- a/sound/ppc/snd_ps3_reg.h +++ b/sound/ppc/snd_ps3_reg.h @@ -125,7 +125,7 @@ transfers. Any interrupts associated with the canceled transfers will occur as if the transfer had finished. Since this bit is designed to recover from DMA related issues - which are caused by unpredictable situations, it is prefered to wait + which are caused by unpredictable situations, it is preferred to wait for normal DMA transfer end without using this bit. */ #define PS3_AUDIO_CONFIG_CLEAR (1 << 8) /* RWIVF */ @@ -316,13 +316,13 @@ DISABLED=Interrupt generation disabled. /* Audio Port Interrupt Status Register -Indicates Interrupt status, which interrupt has occured, and can clear +Indicates Interrupt status, which interrupt has occurred, and can clear each interrupt in this register. Writing 1b to a field containing 1b clears field and de-asserts interrupt. Writing 0b to a field has no effect. Field vaules are the following: -0 - Interrupt hasn't occured. -1 - Interrupt has occured. +0 - Interrupt hasn't occurred. +1 - Interrupt has occurred. 31 24 23 16 15 8 7 0 @@ -473,7 +473,7 @@ Channel N is out of action by setting 0 to asoen. /* Sampling Rate Specifies the divide ratio of the bit clock (clock output -from bclko) used by the 3-wire Audio Output Clock, whcih +from bclko) used by the 3-wire Audio Output Clock, which is applied to the master clock selected by mcksel. Data output is synchronized with this clock. */ @@ -756,7 +756,7 @@ The STATUS field can be used to monitor the progress of a DMA request. DONE indicates the previous request has completed. EVENT indicates that the DMA engine is waiting for the EVENT to occur. PENDING indicates that the DMA engine has not started processing this -request, but the EVENT has occured. +request, but the EVENT has occurred. DMA indicates that the data transfer is in progress. NOTIFY indicates that the notifier signalling end of transfer is being written. CLEAR indicated that the previous transfer was cleared. @@ -824,7 +824,7 @@ AUDIOFIFO = Audio WriteData FIFO, /* PS3_AUDIO_DMASIZE specifies the number of 128-byte blocks + 1 to transfer. -So a value of 0 means 128-bytes will get transfered. +So a value of 0 means 128-bytes will get transferred. 31 24 23 16 15 8 7 0 diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 961d98297695..9cea84c3e0c6 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -1000,7 +1000,7 @@ static void device_change_handler(struct work_struct *work) chip->lineout_sw_ctl); if (mix->anded_reset) msleep(10); - check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify, + check_mute(chip, &mix->amp_mute, !IS_G4DA, mix->auto_mute_notify, chip->speaker_sw_ctl); } else { /* unmute speaker, mute others */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 5d230cee3fa7..7fbfa051f6e1 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -672,7 +672,7 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) /* re-enable interrupts */ ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); - /* Re-enable recieve and transmit as appropriate */ + /* Re-enable receive and transmit as appropriate */ cr = 0; cr |= (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index af3c73053ee4..95572d290c27 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) "at91sam9g20ek_wm8731 " ": at91sam9g20ek_wm8731_init() called\n"); - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, + ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_MCLK, MCLK_RATE, SND_SOC_CLOCK_IN); if (ret < 0) { printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret); @@ -184,7 +184,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = { .codec_dai_name = "wm8731-hifi", .init = at91sam9g20ek_wm8731_init, .platform_name = "atmel-pcm-audio", - .codec_name = "wm8731-codec.0-001b", + .codec_name = "wm8731.0-001b", .ops = &at91sam9g20ek_ops, }; diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index cb99f04abe88..1d3e258c9ea8 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c @@ -77,7 +77,7 @@ static struct snd_soc_dai_link db1200_i2s_dai = { .codec_dai_name = "wm8731-hifi", .cpu_dai_name = "au1xpsc_i2s.1", .platform_name = "au1xpsc-pcm.1", - .codec_name = "wm8731-codec.0-001b", + .codec_name = "wm8731.0-001b", .ops = &db1200_i2s_wm8731_ops, }; diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 5a2fd8abaefa..98b44b316e78 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -243,6 +243,9 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) static int bf5xx_pcm_open(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); struct snd_pcm_runtime *runtime = substream->runtime; int ret; @@ -314,6 +317,9 @@ static struct snd_pcm_ops bf5xx_pcm_ac97_ops = { static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; size_t size = bf5xx_pcm_hardware.buffer_bytes_max @@ -377,6 +383,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) struct snd_dma_buffer *buf; int stream; #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); size_t size = bf5xx_pcm_hardware.buffer_bytes_max * sizeof(struct ac97_frame) / 4; #endif @@ -405,8 +414,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) } #endif } - if (sport_handle) - sport_done(sport_handle); } static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); @@ -458,7 +465,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev) static struct platform_driver bf5xx_pcm_driver = { .driver = { - .name = "bf5xx-pcm-audio", + .name = "bfin-ac97-pcm-audio", .owner = THIS_MODULE, }, diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index ffbac26b9bce..6d2162590889 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -41,48 +41,7 @@ * anomaly does not affect blackfin sound drivers. */ -static int *cmd_count; -static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; - -#define SPORT_REQ(x) \ - [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \ - P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0} -static u16 sport_req[][7] = { -#ifdef SPORT0_TCR1 - SPORT_REQ(0), -#endif -#ifdef SPORT1_TCR1 - SPORT_REQ(1), -#endif -#ifdef SPORT2_TCR1 - SPORT_REQ(2), -#endif -#ifdef SPORT3_TCR1 - SPORT_REQ(3), -#endif -}; - -#define SPORT_PARAMS(x) \ - [x] = { \ - .dma_rx_chan = CH_SPORT##x##_RX, \ - .dma_tx_chan = CH_SPORT##x##_TX, \ - .err_irq = IRQ_SPORT##x##_ERROR, \ - .regs = (struct sport_register *)SPORT##x##_TCR1, \ - } -static struct sport_param sport_params[4] = { -#ifdef SPORT0_TCR1 - SPORT_PARAMS(0), -#endif -#ifdef SPORT1_TCR1 - SPORT_PARAMS(1), -#endif -#ifdef SPORT2_TCR1 - SPORT_PARAMS(2), -#endif -#ifdef SPORT3_TCR1 - SPORT_PARAMS(3), -#endif -}; +static struct sport_device *ac97_sport_handle; void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, size_t count, unsigned int chan_mask) @@ -140,7 +99,8 @@ static unsigned int sport_tx_curr_frag(struct sport_device *sport) static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) { - struct sport_device *sport = sport_handle; + struct sport_device *sport = ac97_sport_handle; + int *cmd_count = sport->private_data; int nextfrag = sport_tx_curr_frag(sport); struct ac97_frame *nextwrite; @@ -161,6 +121,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { + struct sport_device *sport_handle = ac97_sport_handle; struct ac97_frame out_frame[2], in_frame[2]; pr_debug("%s enter 0x%x\n", __func__, reg); @@ -185,6 +146,8 @@ static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97, void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { + struct sport_device *sport_handle = ac97_sport_handle; + pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val); if (sport_handle->tx_run) { @@ -203,28 +166,19 @@ void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97) { -#if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || \ - (defined(BF537_FAMILY) && (CONFIG_SND_BF5XX_SPORT_NUM == 1)) - -#define CONCAT(a, b, c) a ## b ## c -#define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS) - - u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM); - u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM)); + struct sport_device *sport_handle = ac97_sport_handle; + u16 gpio = P_IDENT(sport_handle->pin_req[3]); pr_debug("%s enter\n", __func__); - peripheral_free(per); + peripheral_free_list(sport_handle->pin_req); gpio_request(gpio, "bf5xx-ac97"); gpio_direction_output(gpio, 1); udelay(2); gpio_set_value(gpio, 0); udelay(1); gpio_free(gpio); - peripheral_request(per, "soc-audio"); -#else - pr_info("%s: Not implemented\n", __func__); -#endif + peripheral_request_list(sport_handle->pin_req, "soc-audio"); } static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97) @@ -306,18 +260,32 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai) #define bf5xx_ac97_resume NULL #endif -static int bf5xx_ac97_probe(struct snd_soc_dai *dai) +static struct snd_soc_dai_driver bfin_ac97_dai = { + .ac97_control = 1, + .suspend = bf5xx_ac97_suspend, + .resume = bf5xx_ac97_resume, + .playback = { + .stream_name = "AC97 Playback", + .channels_min = 2, +#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) + .channels_max = 6, +#else + .channels_max = 2, +#endif + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, + .capture = { + .stream_name = "AC97 Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, +}; + +static int __devinit asoc_bfin_ac97_probe(struct platform_device *pdev) { - int ret = 0; - cmd_count = (int *)get_zeroed_page(GFP_KERNEL); - if (cmd_count == NULL) - return -ENOMEM; - - if (peripheral_request_list(sport_req[sport_num], "soc-audio")) { - pr_err("Requesting Peripherals failed\n"); - ret = -EFAULT; - goto peripheral_err; - } + struct sport_device *sport_handle; + int ret; #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET /* Request PB3 as reset pin */ @@ -329,12 +297,14 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai) } gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); #endif - sport_handle = sport_init(&sport_params[sport_num], 2, \ - sizeof(struct ac97_frame), NULL); + + sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame), + PAGE_SIZE); if (!sport_handle) { ret = -ENODEV; goto sport_err; } + /*SPORT works in TDM mode to simulate AC97 transfers*/ #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1); @@ -361,67 +331,37 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai) goto sport_config_err; } + ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai); + if (ret) { + pr_err("Failed to register DAI: %d\n", ret); + goto sport_config_err; + } + + ac97_sport_handle = sport_handle; + return 0; sport_config_err: - kfree(sport_handle); + sport_done(sport_handle); sport_err: #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); gpio_err: #endif - peripheral_free_list(sport_req[sport_num]); -peripheral_err: - free_page((unsigned long)cmd_count); - cmd_count = NULL; return ret; } -static int bf5xx_ac97_remove(struct snd_soc_dai *dai) +static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev) { - free_page((unsigned long)cmd_count); - cmd_count = NULL; - peripheral_free_list(sport_req[sport_num]); + struct sport_device *sport_handle = platform_get_drvdata(pdev); + + snd_soc_unregister_dai(&pdev->dev); + sport_done(sport_handle); #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); #endif - return 0; -} - -struct snd_soc_dai_driver bfin_ac97_dai = { - .ac97_control = 1, - .probe = bf5xx_ac97_probe, - .remove = bf5xx_ac97_remove, - .suspend = bf5xx_ac97_suspend, - .resume = bf5xx_ac97_resume, - .playback = { - .stream_name = "AC97 Playback", - .channels_min = 2, -#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) - .channels_max = 6, -#else - .channels_max = 2, -#endif - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .capture = { - .stream_name = "AC97 Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, }, -}; -EXPORT_SYMBOL_GPL(bfin_ac97_dai); - -static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev) -{ - return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai); -} -static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev) -{ - snd_soc_unregister_dai(&pdev->dev); return 0; } diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c index 83012da9dfc2..ea4951cf5526 100644 --- a/sound/soc/blackfin/bf5xx-ad1836.c +++ b/sound/soc/blackfin/bf5xx-ad1836.c @@ -29,22 +29,12 @@ #include <asm/portmux.h> #include "../codecs/ad1836.h" -#include "bf5xx-sport.h" #include "bf5xx-tdm-pcm.h" #include "bf5xx-tdm.h" static struct snd_soc_card bf5xx_ad1836; -static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - snd_soc_dai_set_drvdata(cpu_dai, sport_handle); - return 0; -} - static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -75,23 +65,33 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, } static struct snd_soc_ops bf5xx_ad1836_ops = { - .startup = bf5xx_ad1836_startup, .hw_params = bf5xx_ad1836_hw_params, }; -static struct snd_soc_dai_link bf5xx_ad1836_dai = { - .name = "ad1836", - .stream_name = "AD1836", - .cpu_dai_name = "bf5xx-tdm", - .codec_dai_name = "ad1836-hifi", - .platform_name = "bf5xx-tdm-pcm-audio", - .codec_name = "ad1836-codec.0", - .ops = &bf5xx_ad1836_ops, +static struct snd_soc_dai_link bf5xx_ad1836_dai[] = { + { + .name = "ad1836", + .stream_name = "AD1836", + .cpu_dai_name = "bfin-tdm.0", + .codec_dai_name = "ad1836-hifi", + .platform_name = "bfin-tdm-pcm-audio", + .codec_name = "ad1836.0", + .ops = &bf5xx_ad1836_ops, + }, + { + .name = "ad1836", + .stream_name = "AD1836", + .cpu_dai_name = "bfin-tdm.1", + .codec_dai_name = "ad1836-hifi", + .platform_name = "bfin-tdm-pcm-audio", + .codec_name = "ad1836.0", + .ops = &bf5xx_ad1836_ops, + }, }; static struct snd_soc_card bf5xx_ad1836 = { - .name = "bf5xx_ad1836", - .dai_link = &bf5xx_ad1836_dai, + .name = "bfin-ad1836", + .dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM], .num_links = 1, }; diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c index d3ccb926b5e4..d6651c033cb7 100644 --- a/sound/soc/blackfin/bf5xx-ad193x.c +++ b/sound/soc/blackfin/bf5xx-ad193x.c @@ -38,30 +38,28 @@ #include <asm/portmux.h> #include "../codecs/ad193x.h" -#include "bf5xx-sport.h" #include "bf5xx-tdm-pcm.h" #include "bf5xx-tdm.h" static struct snd_soc_card bf5xx_ad193x; -static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - snd_soc_dai_set_drvdata(cpu_dai, sport_handle); - return 0; -} - static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; + unsigned int clk = 0; unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7}; int ret = 0; + + switch (params_rate(params)) { + case 48000: + clk = 12288000; + break; + } + /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); @@ -74,6 +72,12 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; + /* set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + /* set codec DAI slots, 8 channels, all channels are enabled */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32); if (ret < 0) @@ -89,23 +93,33 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream, } static struct snd_soc_ops bf5xx_ad193x_ops = { - .startup = bf5xx_ad193x_startup, .hw_params = bf5xx_ad193x_hw_params, }; -static struct snd_soc_dai_link bf5xx_ad193x_dai = { - .name = "ad193x", - .stream_name = "AD193X", - .cpu_dai_name = "bf5xx-tdm", - .codec_dai_name ="ad193x-hifi", - .platform_name = "bf5xx-tdm-pcm-audio", - .codec_name = "ad193x-codec.5", - .ops = &bf5xx_ad193x_ops, +static struct snd_soc_dai_link bf5xx_ad193x_dai[] = { + { + .name = "ad193x", + .stream_name = "AD193X", + .cpu_dai_name = "bfin-tdm.0", + .codec_dai_name ="ad193x-hifi", + .platform_name = "bfin-tdm-pcm-audio", + .codec_name = "ad193x.5", + .ops = &bf5xx_ad193x_ops, + }, + { + .name = "ad193x", + .stream_name = "AD193X", + .cpu_dai_name = "bfin-tdm.1", + .codec_dai_name ="ad193x-hifi", + .platform_name = "bfin-tdm-pcm-audio", + .codec_name = "ad193x.5", + .ops = &bf5xx_ad193x_ops, + }, }; static struct snd_soc_card bf5xx_ad193x = { - .name = "bf5xx_ad193x", - .dai_link = &bf5xx_ad193x_dai, + .name = "bfin-ad193x", + .dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM], .num_links = 1, }; diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index d57c9c9c9883..06a84b211b52 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c @@ -47,39 +47,34 @@ #include <asm/portmux.h> #include "../codecs/ad1980.h" -#include "bf5xx-sport.h" + #include "bf5xx-ac97-pcm.h" #include "bf5xx-ac97.h" static struct snd_soc_card bf5xx_board; -static int bf5xx_board_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - pr_debug("%s enter\n", __func__); - snd_soc_dai_set_drvdata(cpu_dai, sport_handle); - return 0; -} - -static struct snd_soc_ops bf5xx_board_ops = { - .startup = bf5xx_board_startup, -}; - -static struct snd_soc_dai_link bf5xx_board_dai = { - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai_name = "bfin-ac97", - .codec_dai_name = "ad1980-hifi", - .platform_name = "bfin-pcm-audio", - .codec_name = "ad1980-codec", - .ops = &bf5xx_board_ops, +static struct snd_soc_dai_link bf5xx_board_dai[] = { + { + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai_name = "bfin-ac97.0", + .codec_dai_name = "ad1980-hifi", + .platform_name = "bfin-ac97-pcm-audio", + .codec_name = "ad1980", + }, + { + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai_name = "bfin-ac97.1", + .codec_dai_name = "ad1980-hifi", + .platform_name = "bfin-ac97-pcm-audio", + .codec_name = "ad1980", + }, }; static struct snd_soc_card bf5xx_board = { - .name = "bf5xx-board", - .dai_link = &bf5xx_board_dai, + .name = "bfin-ad1980", + .dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM], .num_links = 1, }; diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 732fb8bad076..732a247f2527 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -145,16 +145,6 @@ static int bf5xx_probe(struct platform_device *pdev) return 0; } -static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - pr_debug("%s enter\n", __func__); - snd_soc_dai_set_drvdata(cpu_dai, sport_handle); - return 0; -} - static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -176,24 +166,34 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream, static struct snd_soc_ops bf5xx_ad73311_ops = { - .startup = bf5xx_ad73311_startup, .hw_params = bf5xx_ad73311_hw_params, }; -static struct snd_soc_dai_link bf5xx_ad73311_dai = { - .name = "ad73311", - .stream_name = "AD73311", - .cpu_dai_name = "bf5xx-i2s", - .codec_dai_name = "ad73311-hifi", - .platform_name = "bfin-pcm-audio", - .codec_name = "ad73311-codec", - .ops = &bf5xx_ad73311_ops, +static struct snd_soc_dai_link bf5xx_ad73311_dai[] = { + { + .name = "ad73311", + .stream_name = "AD73311", + .cpu_dai_name = "bfin-i2s.0", + .codec_dai_name = "ad73311-hifi", + .platform_name = "bfin-i2s-pcm-audio", + .codec_name = "ad73311", + .ops = &bf5xx_ad73311_ops, + }, + { + .name = "ad73311", + .stream_name = "AD73311", + .cpu_dai_name = "bfin-i2s.1", + .codec_dai_name = "ad73311-hifi", + .platform_name = "bfin-i2s-pcm-audio", + .codec_name = "ad73311", + .ops = &bf5xx_ad73311_ops, + }, }; static struct snd_soc_card bf5xx_ad73311 = { - .name = "bf5xx_ad73311", + .name = "bfin-ad73311", .probe = bf5xx_probe, - .dai_link = &bf5xx_ad73311_dai, + .dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM], .num_links = 1, }; diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 890a0dccf902..b5101efd1c87 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -148,10 +148,15 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) static int bf5xx_pcm_open(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dma_buffer *buf = &substream->dma_buffer; int ret; pr_debug("%s enter\n", __func__); + snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); ret = snd_pcm_hw_constraint_integer(runtime, \ @@ -159,9 +164,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) if (ret < 0) goto out; - if (sport_handle != NULL) + if (sport_handle != NULL) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sport_handle->tx_buf = buf->area; + else + sport_handle->rx_buf = buf->area; + runtime->private_data = sport_handle; - else { + } else { pr_err("sport_handle is NULL\n"); return -1; } @@ -214,11 +224,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) pr_debug("%s, area:%p, size:0x%08lx\n", __func__, buf->area, buf->bytes); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - sport_handle->tx_buf = buf->area; - else - sport_handle->rx_buf = buf->area; - return 0; } @@ -239,8 +244,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) dma_free_coherent(NULL, buf->bytes, buf->area, 0); buf->area = NULL; } - if (sport_handle) - sport_done(sport_handle); } static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); @@ -292,7 +295,7 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev) static struct platform_driver bfin_i2s_pcm_driver = { .driver = { - .name = "bfin-pcm-audio", + .name = "bfin-i2s-pcm-audio", .owner = THIS_MODULE, }, diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index d453b1e9d607..00cc3e00b2fe 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -51,59 +51,24 @@ struct bf5xx_i2s_port { int configured; }; -static struct bf5xx_i2s_port bf5xx_i2s; -static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; - -static struct sport_param sport_params[2] = { - { - .dma_rx_chan = CH_SPORT0_RX, - .dma_tx_chan = CH_SPORT0_TX, - .err_irq = IRQ_SPORT0_ERROR, - .regs = (struct sport_register *)SPORT0_TCR1, - }, - { - .dma_rx_chan = CH_SPORT1_RX, - .dma_tx_chan = CH_SPORT1_TX, - .err_irq = IRQ_SPORT1_ERROR, - .regs = (struct sport_register *)SPORT1_TCR1, - } -}; - -/* - * Setting the TFS pin selector for SPORT 0 based on whether the selected - * port id F or G. If the port is F then no conflict should exist for the - * TFS. When Port G is selected and EMAC then there is a conflict between - * the PHY interrupt line and TFS. Current settings prevent the conflict - * by ignoring the TFS pin when Port G is selected. This allows both - * codecs and EMAC using Port G concurrently. - */ -#ifdef CONFIG_BF527_SPORT0_PORTG -#define LOCAL_SPORT0_TFS (0) -#else -#define LOCAL_SPORT0_TFS (P_SPORT0_TFS) -#endif - -static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, - P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0}, - {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI, - P_SPORT1_RSCLK, P_SPORT1_TFS, 0} }; - static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); + struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; int ret = 0; /* interface format:support I2S,slave mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - bf5xx_i2s.tcr1 |= TFSR | TCKFE; - bf5xx_i2s.rcr1 |= RFSR | RCKFE; - bf5xx_i2s.tcr2 |= TSFSE; - bf5xx_i2s.rcr2 |= RSFSE; + bf5xx_i2s->tcr1 |= TFSR | TCKFE; + bf5xx_i2s->rcr1 |= RFSR | RCKFE; + bf5xx_i2s->tcr2 |= TSFSE; + bf5xx_i2s->rcr2 |= RSFSE; break; case SND_SOC_DAIFMT_DSP_A: - bf5xx_i2s.tcr1 |= TFSR; - bf5xx_i2s.rcr1 |= RFSR; + bf5xx_i2s->tcr1 |= TFSR; + bf5xx_i2s->rcr1 |= RFSR; break; case SND_SOC_DAIFMT_LEFT_J: ret = -EINVAL; @@ -135,29 +100,35 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); + struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; int ret = 0; - bf5xx_i2s.tcr2 &= ~0x1f; - bf5xx_i2s.rcr2 &= ~0x1f; + bf5xx_i2s->tcr2 &= ~0x1f; + bf5xx_i2s->rcr2 &= ~0x1f; switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + bf5xx_i2s->tcr2 |= 7; + bf5xx_i2s->rcr2 |= 7; + sport_handle->wdsize = 1; case SNDRV_PCM_FORMAT_S16_LE: - bf5xx_i2s.tcr2 |= 15; - bf5xx_i2s.rcr2 |= 15; + bf5xx_i2s->tcr2 |= 15; + bf5xx_i2s->rcr2 |= 15; sport_handle->wdsize = 2; break; case SNDRV_PCM_FORMAT_S24_LE: - bf5xx_i2s.tcr2 |= 23; - bf5xx_i2s.rcr2 |= 23; + bf5xx_i2s->tcr2 |= 23; + bf5xx_i2s->rcr2 |= 23; sport_handle->wdsize = 3; break; case SNDRV_PCM_FORMAT_S32_LE: - bf5xx_i2s.tcr2 |= 31; - bf5xx_i2s.rcr2 |= 31; + bf5xx_i2s->tcr2 |= 31; + bf5xx_i2s->rcr2 |= 31; sport_handle->wdsize = 4; break; } - if (!bf5xx_i2s.configured) { + if (!bf5xx_i2s->configured) { /* * TX and RX are not independent,they are enabled at the * same time, even if only one side is running. So, we @@ -166,16 +137,16 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, * * CPU DAI:slave mode. */ - bf5xx_i2s.configured = 1; - ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, - bf5xx_i2s.rcr2, 0, 0); + bf5xx_i2s->configured = 1; + ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1, + bf5xx_i2s->rcr2, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, - bf5xx_i2s.tcr2, 0, 0); + ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1, + bf5xx_i2s->tcr2, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; @@ -188,41 +159,19 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); + struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; + pr_debug("%s enter\n", __func__); /* No active stream, SPORT is allowed to be configured again. */ if (!dai->active) - bf5xx_i2s.configured = 0; -} - -static int bf5xx_i2s_probe(struct snd_soc_dai *dai) -{ - pr_debug("%s enter\n", __func__); - if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { - pr_err("Requesting Peripherals failed\n"); - return -EFAULT; - } - - /* request DMA for SPORT */ - sport_handle = sport_init(&sport_params[sport_num], 4, \ - 2 * sizeof(u32), NULL); - if (!sport_handle) { - peripheral_free_list(&sport_req[sport_num][0]); - return -ENODEV; - } - - return 0; -} - -static int bf5xx_i2s_remove(struct snd_soc_dai *dai) -{ - pr_debug("%s enter\n", __func__); - peripheral_free_list(&sport_req[sport_num][0]); - return 0; + bf5xx_i2s->configured = 0; } #ifdef CONFIG_PM static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) { + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); pr_debug("%s : sport %d\n", __func__, dai->id); @@ -235,19 +184,21 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) static int bf5xx_i2s_resume(struct snd_soc_dai *dai) { + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); + struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; int ret; pr_debug("%s : sport %d\n", __func__, dai->id); - ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, - bf5xx_i2s.rcr2, 0, 0); + ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1, + bf5xx_i2s->rcr2, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, - bf5xx_i2s.tcr2, 0, 0); + ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1, + bf5xx_i2s->tcr2, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; @@ -266,8 +217,11 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai) SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ SNDRV_PCM_RATE_96000) -#define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ - SNDRV_PCM_FMTBIT_S32_LE) +#define BF5XX_I2S_FORMATS \ + (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { .shutdown = bf5xx_i2s_shutdown, @@ -276,8 +230,6 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { }; static struct snd_soc_dai_driver bf5xx_i2s_dai = { - .probe = bf5xx_i2s_probe, - .remove = bf5xx_i2s_remove, .suspend = bf5xx_i2s_suspend, .resume = bf5xx_i2s_resume, .playback = { @@ -293,23 +245,45 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = { .ops = &bf5xx_i2s_dai_ops, }; -static int bfin_i2s_drv_probe(struct platform_device *pdev) +static int __devinit bf5xx_i2s_probe(struct platform_device *pdev) { - return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai); + struct sport_device *sport_handle; + int ret; + + /* configure SPORT for I2S */ + sport_handle = sport_init(pdev, 4, 2 * sizeof(u32), + sizeof(struct bf5xx_i2s_port)); + if (!sport_handle) + return -ENODEV; + + /* register with the ASoC layers */ + ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai); + if (ret) { + pr_err("Failed to register DAI: %d\n", ret); + sport_done(sport_handle); + return ret; + } + + return 0; } -static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev) +static int __devexit bf5xx_i2s_remove(struct platform_device *pdev) { + struct sport_device *sport_handle = platform_get_drvdata(pdev); + + pr_debug("%s enter\n", __func__); + snd_soc_unregister_dai(&pdev->dev); + sport_done(sport_handle); + return 0; } static struct platform_driver bfin_i2s_driver = { - .probe = bfin_i2s_drv_probe, - .remove = __devexit_p(bfin_i2s_drv_remove), - + .probe = bf5xx_i2s_probe, + .remove = __devexit_p(bf5xx_i2s_remove), .driver = { - .name = "bf5xx-i2s", + .name = "bfin-i2s", .owner = THIS_MODULE, }, }; diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c index 99051ff0954e..a2d40349fcc4 100644 --- a/sound/soc/blackfin/bf5xx-sport.c +++ b/sound/soc/blackfin/bf5xx-sport.c @@ -42,8 +42,6 @@ /* delay between frame sync pulse and first data bit in multichannel mode */ #define FRAME_DELAY (1<<12) -struct sport_device *sport_handle; -EXPORT_SYMBOL(sport_handle); /* note: multichannel is in units of 8 channels, * tdm_count is # channels NOT / 8 ! */ int sport_set_multichannel(struct sport_device *sport, @@ -798,86 +796,164 @@ int sport_set_err_callback(struct sport_device *sport, } EXPORT_SYMBOL(sport_set_err_callback); -struct sport_device *sport_init(struct sport_param *param, unsigned wdsize, - unsigned dummy_count, void *private_data) +static int sport_config_pdev(struct platform_device *pdev, struct sport_param *param) { - int ret; + /* Extract settings from platform data */ + struct device *dev = &pdev->dev; + struct bfin_snd_platform_data *pdata = dev->platform_data; + struct resource *res; + + param->num = pdev->id; + + if (!pdata) { + dev_err(dev, "no platform_data\n"); + return -ENODEV; + } + param->pin_req = pdata->pin_req; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no MEM resource\n"); + return -ENODEV; + } + param->regs = (struct sport_register *)res->start; + + /* first RX, then TX */ + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!res) { + dev_err(dev, "no rx DMA resource\n"); + return -ENODEV; + } + param->dma_rx_chan = res->start; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!res) { + dev_err(dev, "no tx DMA resource\n"); + return -ENODEV; + } + param->dma_tx_chan = res->start; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "no irq resource\n"); + return -ENODEV; + } + param->err_irq = res->start; + + return 0; +} + +struct sport_device *sport_init(struct platform_device *pdev, + unsigned int wdsize, unsigned int dummy_count, size_t priv_size) +{ + struct device *dev = &pdev->dev; + struct sport_param param; struct sport_device *sport; - pr_debug("%s enter\n", __func__); - BUG_ON(param == NULL); - BUG_ON(wdsize == 0 || dummy_count == 0); - sport = kmalloc(sizeof(struct sport_device), GFP_KERNEL); - if (!sport) { - pr_err("Failed to allocate for sport device\n"); + int ret; + + dev_dbg(dev, "%s enter\n", __func__); + + param.wdsize = wdsize; + param.dummy_count = dummy_count; + BUG_ON(param.wdsize == 0 || param.dummy_count == 0); + + ret = sport_config_pdev(pdev, ¶m); + if (ret) + return NULL; + + if (peripheral_request_list(param.pin_req, "soc-audio")) { + dev_err(dev, "requesting Peripherals failed\n"); return NULL; } - memset(sport, 0, sizeof(struct sport_device)); - sport->dma_rx_chan = param->dma_rx_chan; - sport->dma_tx_chan = param->dma_tx_chan; - sport->err_irq = param->err_irq; - sport->regs = param->regs; - sport->private_data = private_data; + sport = kzalloc(sizeof(*sport), GFP_KERNEL); + if (!sport) { + dev_err(dev, "failed to allocate for sport device\n"); + goto __init_err0; + } + + sport->num = param.num; + sport->dma_rx_chan = param.dma_rx_chan; + sport->dma_tx_chan = param.dma_tx_chan; + sport->err_irq = param.err_irq; + sport->regs = param.regs; + sport->pin_req = param.pin_req; if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) { - pr_err("Failed to request RX dma %d\n", \ - sport->dma_rx_chan); + dev_err(dev, "failed to request RX dma %d\n", sport->dma_rx_chan); goto __init_err1; } if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) { - pr_err("Failed to request RX irq %d\n", \ - sport->dma_rx_chan); + dev_err(dev, "failed to request RX irq %d\n", sport->dma_rx_chan); goto __init_err2; } if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) { - pr_err("Failed to request TX dma %d\n", \ - sport->dma_tx_chan); + dev_err(dev, "failed to request TX dma %d\n", sport->dma_tx_chan); goto __init_err2; } if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) { - pr_err("Failed to request TX irq %d\n", \ - sport->dma_tx_chan); + dev_err(dev, "failed to request TX irq %d\n", sport->dma_tx_chan); goto __init_err3; } if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err", sport) < 0) { - pr_err("Failed to request err irq:%d\n", \ - sport->err_irq); + dev_err(dev, "failed to request err irq %d\n", sport->err_irq); goto __init_err3; } - pr_err("dma rx:%d tx:%d, err irq:%d, regs:%p\n", + dev_info(dev, "dma rx:%d tx:%d, err irq:%d, regs:%p\n", sport->dma_rx_chan, sport->dma_tx_chan, sport->err_irq, sport->regs); - sport->wdsize = wdsize; - sport->dummy_count = dummy_count; + sport->wdsize = param.wdsize; + sport->dummy_count = param.dummy_count; + + sport->private_data = kzalloc(priv_size, GFP_KERNEL); + if (!sport->private_data) { + dev_err(dev, "could not alloc priv data %zu bytes\n", priv_size); + goto __init_err4; + } if (L1_DATA_A_LENGTH) - sport->dummy_buf = l1_data_sram_zalloc(dummy_count * 2); + sport->dummy_buf = l1_data_sram_zalloc(param.dummy_count * 2); else - sport->dummy_buf = kzalloc(dummy_count * 2, GFP_KERNEL); + sport->dummy_buf = kzalloc(param.dummy_count * 2, GFP_KERNEL); if (sport->dummy_buf == NULL) { - pr_err("Failed to allocate dummy buffer\n"); - goto __error; + dev_err(dev, "failed to allocate dummy buffer\n"); + goto __error1; } ret = sport_config_rx_dummy(sport); if (ret) { - pr_err("Failed to config rx dummy ring\n"); - goto __error; + dev_err(dev, "failed to config rx dummy ring\n"); + goto __error2; } ret = sport_config_tx_dummy(sport); if (ret) { - pr_err("Failed to config tx dummy ring\n"); - goto __error; + dev_err(dev, "failed to config tx dummy ring\n"); + goto __error3; } + platform_set_drvdata(pdev, sport); + return sport; -__error: +__error3: + if (L1_DATA_A_LENGTH) + l1_data_sram_free(sport->dummy_rx_desc); + else + dma_free_coherent(NULL, 2*sizeof(struct dmasg), + sport->dummy_rx_desc, 0); +__error2: + if (L1_DATA_A_LENGTH) + l1_data_sram_free(sport->dummy_buf); + else + kfree(sport->dummy_buf); +__error1: + kfree(sport->private_data); +__init_err4: free_irq(sport->err_irq, sport); __init_err3: free_dma(sport->dma_tx_chan); @@ -885,6 +961,8 @@ __init_err2: free_dma(sport->dma_rx_chan); __init_err1: kfree(sport); +__init_err0: + peripheral_free_list(param.pin_req); return NULL; } EXPORT_SYMBOL(sport_init); @@ -917,8 +995,9 @@ void sport_done(struct sport_device *sport) free_dma(sport->dma_tx_chan); free_irq(sport->err_irq, sport); + kfree(sport->private_data); + peripheral_free_list(sport->pin_req); kfree(sport); - sport = NULL; } EXPORT_SYMBOL(sport_done); diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h index a86e8cc0b2d3..5ab60bd613ea 100644 --- a/sound/soc/blackfin/bf5xx-sport.h +++ b/sound/soc/blackfin/bf5xx-sport.h @@ -1,5 +1,5 @@ /* - * File: bf5xx_ac97_sport.h + * File: bf5xx_sport.h * Based on: * Author: Roy Huang <roy.huang@analog.com> * @@ -33,15 +33,18 @@ #include <linux/types.h> #include <linux/wait.h> #include <linux/workqueue.h> +#include <linux/platform_device.h> #include <asm/dma.h> #include <asm/bfin_sport.h> #define DESC_ELEMENT_COUNT 9 struct sport_device { + int num; int dma_rx_chan; int dma_tx_chan; int err_irq; + const unsigned short *pin_req; struct sport_register *regs; unsigned char *rx_buf; @@ -103,17 +106,20 @@ struct sport_device { void *private_data; }; -extern struct sport_device *sport_handle; - struct sport_param { + int num; int dma_rx_chan; int dma_tx_chan; int err_irq; + const unsigned short *pin_req; struct sport_register *regs; + unsigned int wdsize; + unsigned int dummy_count; + void *private_data; }; -struct sport_device *sport_init(struct sport_param *param, unsigned wdsize, - unsigned dummy_count, void *private_data); +struct sport_device *sport_init(struct platform_device *pdev, + unsigned int wdsize, unsigned int dummy_count, size_t priv_size); void sport_done(struct sport_device *sport); diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index ad28663f5bbd..767e772a815d 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -44,16 +44,6 @@ static struct snd_soc_card bf5xx_ssm2602; -static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - pr_debug("%s enter\n", __func__); - snd_soc_dai_set_drvdata(cpu_dai, sport_handle); - return 0; -} - static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -109,23 +99,33 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream, } static struct snd_soc_ops bf5xx_ssm2602_ops = { - .startup = bf5xx_ssm2602_startup, .hw_params = bf5xx_ssm2602_hw_params, }; -static struct snd_soc_dai_link bf5xx_ssm2602_dai = { - .name = "ssm2602", - .stream_name = "SSM2602", - .cpu_dai_name = "bf5xx-i2s", - .codec_dai_name = "ssm2602-hifi", - .platform_name = "bf5xx-pcm-audio", - .codec_name = "ssm2602-codec.0-001b", - .ops = &bf5xx_ssm2602_ops, +static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = { + { + .name = "ssm2602", + .stream_name = "SSM2602", + .cpu_dai_name = "bfin-i2s.0", + .codec_dai_name = "ssm2602-hifi", + .platform_name = "bfin-i2s-pcm-audio", + .codec_name = "ssm2602.0-001b", + .ops = &bf5xx_ssm2602_ops, + }, + { + .name = "ssm2602", + .stream_name = "SSM2602", + .cpu_dai_name = "bfin-i2s.1", + .codec_dai_name = "ssm2602-hifi", + .platform_name = "bfin-i2s-pcm-audio", + .codec_name = "ssm2602.0-001b", + .ops = &bf5xx_ssm2602_ops, + }, }; static struct snd_soc_card bf5xx_ssm2602 = { - .name = "bf5xx_ssm2602", - .dai_link = &bf5xx_ssm2602_dai, + .name = "bfin-ssm2602", + .dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM], .num_links = 1, }; diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index 74cf759b78a6..07cfc7a9e49a 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c @@ -154,7 +154,12 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) static int bf5xx_pcm_open(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dma_buffer *buf = &substream->dma_buffer; + int ret = 0; snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); @@ -164,9 +169,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) if (ret < 0) goto out; - if (sport_handle != NULL) + if (sport_handle != NULL) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sport_handle->tx_buf = buf->area; + else + sport_handle->rx_buf = buf->area; + runtime->private_data = sport_handle; - else { + } else { pr_err("sport_handle is NULL\n"); ret = -ENODEV; } @@ -249,11 +259,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) } buf->bytes = size; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - sport_handle->tx_buf = buf->area; - else - sport_handle->rx_buf = buf->area; - return 0; } @@ -274,8 +279,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) dma_free_coherent(NULL, buf->bytes, buf->area, 0); buf->area = NULL; } - if (sport_handle) - sport_done(sport_handle); } static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); @@ -326,7 +329,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev) static struct platform_driver bfin_tdm_driver = { .driver = { - .name = "bf5xx-tdm-pcm-audio", + .name = "bfin-tdm-pcm-audio", .owner = THIS_MODULE, }, diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c index 5515ac9e05c7..a822d1ee1380 100644 --- a/sound/soc/blackfin/bf5xx-tdm.c +++ b/sound/soc/blackfin/bf5xx-tdm.c @@ -46,43 +46,6 @@ #include "bf5xx-sport.h" #include "bf5xx-tdm.h" -static struct bf5xx_tdm_port bf5xx_tdm; -static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; - -static struct sport_param sport_params[2] = { - { - .dma_rx_chan = CH_SPORT0_RX, - .dma_tx_chan = CH_SPORT0_TX, - .err_irq = IRQ_SPORT0_ERROR, - .regs = (struct sport_register *)SPORT0_TCR1, - }, - { - .dma_rx_chan = CH_SPORT1_RX, - .dma_tx_chan = CH_SPORT1_TX, - .err_irq = IRQ_SPORT1_ERROR, - .regs = (struct sport_register *)SPORT1_TCR1, - } -}; - -/* - * Setting the TFS pin selector for SPORT 0 based on whether the selected - * port id F or G. If the port is F then no conflict should exist for the - * TFS. When Port G is selected and EMAC then there is a conflict between - * the PHY interrupt line and TFS. Current settings prevent the conflict - * by ignoring the TFS pin when Port G is selected. This allows both - * codecs and EMAC using Port G concurrently. - */ -#ifdef CONFIG_BF527_SPORT0_PORTG -#define LOCAL_SPORT0_TFS (0) -#else -#define LOCAL_SPORT0_TFS (P_SPORT0_TFS) -#endif - -static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, - P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0}, - {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI, - P_SPORT1_RSCLK, P_SPORT1_TFS, 0} }; - static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { @@ -119,14 +82,16 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); + struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data; int ret = 0; - bf5xx_tdm.tcr2 &= ~0x1f; - bf5xx_tdm.rcr2 &= ~0x1f; + bf5xx_tdm->tcr2 &= ~0x1f; + bf5xx_tdm->rcr2 &= ~0x1f; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S32_LE: - bf5xx_tdm.tcr2 |= 31; - bf5xx_tdm.rcr2 |= 31; + bf5xx_tdm->tcr2 |= 31; + bf5xx_tdm->rcr2 |= 31; sport_handle->wdsize = 4; break; /* at present, we only support 32bit transfer */ @@ -136,7 +101,7 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream, break; } - if (!bf5xx_tdm.configured) { + if (!bf5xx_tdm->configured) { /* * TX and RX are not independent,they are enabled at the * same time, even if only one side is running. So, we @@ -145,21 +110,21 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream, * * CPU DAI:slave mode. */ - ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1, - bf5xx_tdm.rcr2, 0, 0); + ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1, + bf5xx_tdm->rcr2, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1, - bf5xx_tdm.tcr2, 0, 0); + ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1, + bf5xx_tdm->tcr2, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - bf5xx_tdm.configured = 1; + bf5xx_tdm->configured = 1; } return 0; @@ -168,15 +133,20 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream, static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); + struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data; + /* No active stream, SPORT is allowed to be configured again. */ if (!dai->active) - bf5xx_tdm.configured = 0; + bf5xx_tdm->configured = 0; } static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, unsigned int *tx_slot, unsigned int rx_num, unsigned int *rx_slot) { + struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); + struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data; int i; unsigned int slot; unsigned int tx_mapped = 0, rx_mapped = 0; @@ -189,7 +159,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, slot = tx_slot[i]; if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && (!(tx_mapped & (1 << slot)))) { - bf5xx_tdm.tx_map[i] = slot; + bf5xx_tdm->tx_map[i] = slot; tx_mapped |= 1 << slot; } else return -EINVAL; @@ -198,7 +168,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, slot = rx_slot[i]; if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && (!(rx_mapped & (1 << slot)))) { - bf5xx_tdm.rx_map[i] = slot; + bf5xx_tdm->rx_map[i] = slot; rx_mapped |= 1 << slot; } else return -EINVAL; @@ -212,12 +182,14 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) { struct sport_device *sport = snd_soc_dai_get_drvdata(dai); - if (!dai->active) - return 0; - if (dai->capture_active) - sport_rx_stop(sport); if (dai->playback_active) sport_tx_stop(sport); + if (dai->capture_active) + sport_rx_stop(sport); + + /* isolate sync/clock pins from codec while sports resume */ + peripheral_free_list(sport->pin_req); + return 0; } @@ -226,9 +198,6 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai) int ret; struct sport_device *sport = snd_soc_dai_get_drvdata(dai); - if (!dai->active) - return 0; - ret = sport_set_multichannel(sport, 8, 0xFF, 1); if (ret) { pr_err("SPORT is busy!\n"); @@ -247,6 +216,8 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai) ret = -EBUSY; } + peripheral_request_list(sport->pin_req, "soc-audio"); + return 0; } @@ -280,20 +251,14 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = { static int __devinit bfin_tdm_probe(struct platform_device *pdev) { - int ret = 0; - - if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { - pr_err("Requesting Peripherals failed\n"); - return -EFAULT; - } + struct sport_device *sport_handle; + int ret; - /* request DMA for SPORT */ - sport_handle = sport_init(&sport_params[sport_num], 4, \ - 8 * sizeof(u32), NULL); - if (!sport_handle) { - peripheral_free_list(&sport_req[sport_num][0]); + /* configure SPORT for TDM */ + sport_handle = sport_init(pdev, 4, 8 * sizeof(u32), + sizeof(struct bf5xx_tdm_port)); + if (!sport_handle) return -ENODEV; - } /* SPORT works in TDM mode */ ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1); @@ -323,18 +288,19 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev) goto sport_config_err; } - sport_handle->private_data = &bf5xx_tdm; return 0; sport_config_err: - peripheral_free_list(&sport_req[sport_num][0]); + sport_done(sport_handle); return ret; } static int __devexit bfin_tdm_remove(struct platform_device *pdev) { - peripheral_free_list(&sport_req[sport_num][0]); + struct sport_device *sport_handle = platform_get_drvdata(pdev); + snd_soc_unregister_dai(&pdev->dev); + sport_done(sport_handle); return 0; } diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 06b6981b8d6d..19241576b6b5 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -120,7 +120,7 @@ */ #define PM860X_DAPM_OUTPUT(wname, wevent) \ { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ - .shift = 0, .invert = 0, .kcontrols = NULL, \ + .shift = 0, .invert = 0, .kcontrol_news = NULL, \ .num_kcontrols = 0, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, } diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6943e24a74a1..98175a096df2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -16,10 +16,11 @@ config SND_SOC_ALL_CODECS select SND_SOC_AD1836 if SPI_MASTER select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI select SND_SOC_AD1980 if SND_SOC_AC97_BUS + select SND_SOC_AD73311 select SND_SOC_ADS117X - select SND_SOC_AD73311 if I2C select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C + select SND_SOC_AK4641 if I2C select SND_SOC_AK4642 if I2C select SND_SOC_AK4671 if I2C select SND_SOC_ALC5623 if I2C @@ -33,13 +34,14 @@ config SND_SOC_ALL_CODECS select SND_SOC_JZ4740_CODEC if SOC_JZ4740 select SND_SOC_LM4857 if I2C select SND_SOC_MAX98088 if I2C + select SND_SOC_MAX98095 if I2C select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9877 if I2C select SND_SOC_PCM3008 select SND_SOC_SGTL5000 if I2C select SND_SOC_SN95031 if INTEL_SCU_IPC select SND_SOC_SPDIF - select SND_SOC_SSM2602 if I2C + select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER @@ -52,6 +54,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C select SND_SOC_WL1273 if MFD_WL1273_CORE + select SND_SOC_WM1250_EV1 if I2C select SND_SOC_WM2000 if I2C select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8400 if MFD_WM8400 @@ -72,6 +75,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C select SND_SOC_WM8904 if I2C + select SND_SOC_WM8915 if I2C select SND_SOC_WM8940 if I2C select SND_SOC_WM8955 if I2C select SND_SOC_WM8960 if I2C @@ -136,6 +140,9 @@ config SND_SOC_AK4104 config SND_SOC_AK4535 tristate +config SND_SOC_AK4641 + tristate + config SND_SOC_AK4642 tristate @@ -187,6 +194,9 @@ config SND_SOC_DMIC config SND_SOC_MAX98088 tristate +config SND_SOC_MAX98095 + tristate + config SND_SOC_MAX9850 tristate @@ -241,6 +251,9 @@ config SND_SOC_UDA1380 config SND_SOC_WL1273 tristate +config SND_SOC_WM1250_EV1 + tristate + config SND_SOC_WM8350 tristate @@ -298,6 +311,9 @@ config SND_SOC_WM8903 config SND_SOC_WM8904 tristate +config SND_SOC_WM8915 + tristate + config SND_SOC_WM8940 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 379bc55f0723..fd8558406ef0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -7,6 +7,7 @@ snd-soc-ad73311-objs := ad73311.o snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o +snd-soc-ak4641-objs := ak4641.o snd-soc-ak4642-objs := ak4642.o snd-soc-ak4671-objs := ak4671.o snd-soc-cq93vc-objs := cq93vc.o @@ -19,6 +20,7 @@ snd-soc-dfbmcs320-objs := dfbmcs320.o snd-soc-dmic-objs := dmic.o snd-soc-l3-objs := l3.o snd-soc-max98088-objs := max98088.o +snd-soc-max98095-objs := max98095.o snd-soc-max9850-objs := max9850.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-sgtl5000-objs := sgtl5000.o @@ -37,6 +39,7 @@ snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wl1273-objs := wl1273.o +snd-soc-wm1250-ev1-objs := wm1250-ev1.o snd-soc-wm8350-objs := wm8350.o snd-soc-wm8400-objs := wm8400.o snd-soc-wm8510-objs := wm8510.o @@ -56,6 +59,7 @@ snd-soc-wm8804-objs := wm8804.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o snd-soc-wm8904-objs := wm8904.o +snd-soc-wm8915-objs := wm8915.o snd-soc-wm8940-objs := wm8940.o snd-soc-wm8955-objs := wm8955.o snd-soc-wm8960-objs := wm8960.o @@ -69,7 +73,7 @@ snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o snd-soc-wm8991-objs := wm8991.o snd-soc-wm8993-objs := wm8993.o -snd-soc-wm8994-objs := wm8994.o wm8994-tables.o +snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o snd-soc-wm8995-objs := wm8995.o snd-soc-wm9081-objs := wm9081.o snd-soc-wm9705-objs := wm9705.o @@ -94,6 +98,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o +obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o @@ -108,6 +113,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o +obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o @@ -125,6 +131,7 @@ obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o +obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o @@ -144,6 +151,7 @@ obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o +obj-$(CONFIG_SND_SOC_WM8915) += snd-soc-wm8915.o obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index da46479bfcfa..2374ca5ffe68 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -23,8 +23,7 @@ /* codec private data */ struct ad193x_priv { - enum snd_soc_control_type bus_type; - void *control_data; + enum snd_soc_control_type control_type; int sysclk; }; @@ -354,14 +353,12 @@ static int ad193x_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = &codec->dapm; int ret; - codec->control_data = ad193x->control_data; - if (ad193x->bus_type == SND_SOC_I2C) - ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type); + if (ad193x->control_type == SND_SOC_I2C) + ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type); else - ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type); + ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type); if (ret < 0) { - dev_err(codec->dev, "failed to set cache I/O: %d\n", - ret); + dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); return ret; } @@ -408,8 +405,7 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi) return -ENOMEM; spi_set_drvdata(spi, ad193x); - ad193x->control_data = spi; - ad193x->bus_type = SND_SOC_SPI; + ad193x->control_type = SND_SOC_SPI; ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x, &ad193x_dai, 1); @@ -427,7 +423,7 @@ static int __devexit ad193x_spi_remove(struct spi_device *spi) static struct spi_driver ad193x_spi_driver = { .driver = { - .name = "ad193x-codec", + .name = "ad193x", .owner = THIS_MODULE, }, .probe = ad193x_spi_probe, @@ -454,8 +450,7 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, ad193x); - ad193x->control_data = client; - ad193x->bus_type = SND_SOC_I2C; + ad193x->control_type = SND_SOC_I2C; ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x, &ad193x_dai, 1); @@ -473,7 +468,7 @@ static int __devexit ad193x_i2c_remove(struct i2c_client *client) static struct i2c_driver ad193x_i2c_driver = { .driver = { - .name = "ad193x-codec", + .name = "ad193x", }, .probe = ad193x_i2c_probe, .remove = __devexit_p(ad193x_i2c_remove), diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 34cb51ef2156..923b364a3e41 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -266,7 +266,7 @@ static int __devexit ad1980_remove(struct platform_device *pdev) static struct platform_driver ad1980_codec_driver = { .driver = { - .name = "ad1980-codec", + .name = "ad1980", .owner = THIS_MODULE, }, diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index de799cd1ba72..8d793e993e9a 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -55,7 +55,7 @@ static int __devexit ad73311_remove(struct platform_device *pdev) static struct platform_driver ad73311_codec_driver = { .driver = { - .name = "ad73311-codec", + .name = "ad73311", .owner = THIS_MODULE, }, diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 8b38739c88f8..e1a214ee757f 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -230,7 +230,7 @@ static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = { SND_SOC_DAPM_INPUT("AIN"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route ak4535_audio_map[] = { /*stereo mixer */ {"Stereo Mixer", "Playback Switch", "DAC"}, {"Stereo Mixer", "Mic Sidetone Switch", "Mic"}, @@ -287,17 +287,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Input Mixer", "Aux Capture Switch", "Aux In"}, }; -static int ak4535_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, ak4535_dapm_widgets, - ARRAY_SIZE(ak4535_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - return 0; -} - static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { @@ -457,8 +446,6 @@ static int ak4535_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, ak4535_snd_controls, ARRAY_SIZE(ak4535_snd_controls)); - ak4535_add_widgets(codec); - return 0; } @@ -480,6 +467,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { .reg_cache_size = ARRAY_SIZE(ak4535_reg), .reg_word_size = sizeof(u8), .reg_cache_default = ak4535_reg, + .dapm_widgets = ak4535_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), + .dapm_routes = ak4535_audio_map, + .num_dapm_routes = ARRAY_SIZE(ak4535_audio_map), }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c new file mode 100644 index 000000000000..ed96f247c2da --- /dev/null +++ b/sound/soc/codecs/ak4641.c @@ -0,0 +1,664 @@ +/* + * ak4641.c -- AK4641 ALSA Soc Audio driver + * + * Copyright (C) 2008 Harald Welte <laforge@gnufiish.org> + * Copyright (C) 2011 Dmitry Artamonow <mad_soft@inbox.ru> + * + * Based on ak4535.c by Richard Purdie + * + * 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/init.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/ak4641.h> + +#include "ak4641.h" + +/* codec private data */ +struct ak4641_priv { + struct snd_soc_codec *codec; + unsigned int sysclk; + int deemph; + int playback_fs; +}; + +/* + * ak4641 register cache + */ +static const u8 ak4641_reg[AK4641_CACHEREGNUM] = { + 0x00, 0x80, 0x00, 0x80, + 0x02, 0x00, 0x11, 0x05, + 0x00, 0x00, 0x36, 0x10, + 0x00, 0x00, 0x57, 0x00, + 0x88, 0x88, 0x08, 0x08 +}; + +static const int deemph_settings[] = {44100, 0, 48000, 32000}; + +static int ak4641_set_deemph(struct snd_soc_codec *codec) +{ + struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); + int i, best = 0; + + for (i = 0 ; i < ARRAY_SIZE(deemph_settings); i++) { + /* if deemphasis is on, select the nearest available rate */ + if (ak4641->deemph && deemph_settings[i] != 0 && + abs(deemph_settings[i] - ak4641->playback_fs) < + abs(deemph_settings[best] - ak4641->playback_fs)) + best = i; + + if (!ak4641->deemph && deemph_settings[i] == 0) + best = i; + } + + dev_dbg(codec->dev, "Set deemphasis %d\n", best); + + return snd_soc_update_bits(codec, AK4641_DAC, 0x3, best); +} + +static int ak4641_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); + int deemph = ucontrol->value.enumerated.item[0]; + + if (deemph > 1) + return -EINVAL; + + ak4641->deemph = deemph; + + return ak4641_set_deemph(codec); +} + +static int ak4641_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = ak4641->deemph; + return 0; +}; + +static const char *ak4641_mono_out[] = {"(L + R)/2", "Hi-Z"}; +static const char *ak4641_hp_out[] = {"Stereo", "Mono"}; +static const char *ak4641_mic_select[] = {"Internal", "External"}; +static const char *ak4641_mic_or_dac[] = {"Microphone", "Voice DAC"}; + + +static const DECLARE_TLV_DB_SCALE(mono_gain_tlv, -1700, 2300, 0); +static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 2000, 0); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1050, 150, 0); +static const DECLARE_TLV_DB_SCALE(master_tlv, -12750, 50, 0); +static const DECLARE_TLV_DB_SCALE(mic_stereo_sidetone_tlv, -2700, 300, 0); +static const DECLARE_TLV_DB_SCALE(mic_mono_sidetone_tlv, -400, 400, 0); +static const DECLARE_TLV_DB_SCALE(capture_tlv, -800, 50, 0); +static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0); +static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0); + + +static const struct soc_enum ak4641_mono_out_enum = + SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out); +static const struct soc_enum ak4641_hp_out_enum = + SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out); +static const struct soc_enum ak4641_mic_select_enum = + SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select); +static const struct soc_enum ak4641_mic_or_dac_enum = + SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac); + +static const struct snd_kcontrol_new ak4641_snd_controls[] = { + SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum), + SOC_SINGLE_TLV("Mono 1 Gain Volume", AK4641_SIG1, 7, 1, 1, + mono_gain_tlv), + SOC_ENUM("Headphone Output", ak4641_hp_out_enum), + SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0, + ak4641_get_deemph, ak4641_put_deemph), + + SOC_SINGLE_TLV("Mic Boost Volume", AK4641_MIC, 0, 1, 0, mic_boost_tlv), + + SOC_SINGLE("ALC Operation Time", AK4641_TIMER, 0, 3, 0), + SOC_SINGLE("ALC Recovery Time", AK4641_TIMER, 2, 3, 0), + SOC_SINGLE("ALC ZC Time", AK4641_TIMER, 4, 3, 0), + + SOC_SINGLE("ALC 1 Switch", AK4641_ALC1, 5, 1, 0), + + SOC_SINGLE_TLV("ALC Volume", AK4641_ALC2, 0, 71, 0, alc_tlv), + SOC_SINGLE("Left Out Enable Switch", AK4641_SIG2, 1, 1, 0), + SOC_SINGLE("Right Out Enable Switch", AK4641_SIG2, 0, 1, 0), + + SOC_SINGLE_TLV("Capture Volume", AK4641_PGA, 0, 71, 0, capture_tlv), + + SOC_DOUBLE_R_TLV("Master Playback Volume", AK4641_LATT, + AK4641_RATT, 0, 255, 1, master_tlv), + + SOC_SINGLE_TLV("AUX In Volume", AK4641_VOL, 0, 15, 0, aux_in_tlv), + + SOC_SINGLE("Equalizer Switch", AK4641_DAC, 2, 1, 0), + SOC_SINGLE_TLV("EQ1 100 Hz Volume", AK4641_EQLO, 0, 15, 1, eq_tlv), + SOC_SINGLE_TLV("EQ2 250 Hz Volume", AK4641_EQLO, 4, 15, 1, eq_tlv), + SOC_SINGLE_TLV("EQ3 1 kHz Volume", AK4641_EQMID, 0, 15, 1, eq_tlv), + SOC_SINGLE_TLV("EQ4 3.5 kHz Volume", AK4641_EQMID, 4, 15, 1, eq_tlv), + SOC_SINGLE_TLV("EQ5 10 kHz Volume", AK4641_EQHI, 0, 15, 1, eq_tlv), +}; + +/* Mono 1 Mixer */ +static const struct snd_kcontrol_new ak4641_mono1_mixer_controls[] = { + SOC_DAPM_SINGLE_TLV("Mic Mono Sidetone Volume", AK4641_VOL, 7, 1, 0, + mic_mono_sidetone_tlv), + SOC_DAPM_SINGLE("Mic Mono Sidetone Switch", AK4641_SIG1, 4, 1, 0), + SOC_DAPM_SINGLE("Mono Playback Switch", AK4641_SIG1, 5, 1, 0), +}; + +/* Stereo Mixer */ +static const struct snd_kcontrol_new ak4641_stereo_mixer_controls[] = { + SOC_DAPM_SINGLE_TLV("Mic Sidetone Volume", AK4641_VOL, 4, 7, 0, + mic_stereo_sidetone_tlv), + SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4641_SIG2, 4, 1, 0), + SOC_DAPM_SINGLE("Playback Switch", AK4641_SIG2, 7, 1, 0), + SOC_DAPM_SINGLE("Aux Bypass Switch", AK4641_SIG2, 5, 1, 0), +}; + +/* Input Mixer */ +static const struct snd_kcontrol_new ak4641_input_mixer_controls[] = { + SOC_DAPM_SINGLE("Mic Capture Switch", AK4641_MIC, 2, 1, 0), + SOC_DAPM_SINGLE("Aux Capture Switch", AK4641_MIC, 5, 1, 0), +}; + +/* Mic mux */ +static const struct snd_kcontrol_new ak4641_mic_mux_control = + SOC_DAPM_ENUM("Mic Select", ak4641_mic_select_enum); + +/* Input mux */ +static const struct snd_kcontrol_new ak4641_input_mux_control = + SOC_DAPM_ENUM("Input Select", ak4641_mic_or_dac_enum); + +/* mono 2 switch */ +static const struct snd_kcontrol_new ak4641_mono2_control = + SOC_DAPM_SINGLE("Switch", AK4641_SIG1, 0, 1, 0); + +/* ak4641 dapm widgets */ +static const struct snd_soc_dapm_widget ak4641_dapm_widgets[] = { + SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0, + &ak4641_stereo_mixer_controls[0], + ARRAY_SIZE(ak4641_stereo_mixer_controls)), + SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0, + &ak4641_mono1_mixer_controls[0], + ARRAY_SIZE(ak4641_mono1_mixer_controls)), + SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, + &ak4641_input_mixer_controls[0], + ARRAY_SIZE(ak4641_input_mixer_controls)), + SND_SOC_DAPM_MUX("Mic Mux", SND_SOC_NOPM, 0, 0, + &ak4641_mic_mux_control), + SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, + &ak4641_input_mux_control), + SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0, + &ak4641_mono2_control), + + SND_SOC_DAPM_OUTPUT("LOUT"), + SND_SOC_DAPM_OUTPUT("ROUT"), + SND_SOC_DAPM_OUTPUT("MOUT1"), + SND_SOC_DAPM_OUTPUT("MOUT2"), + SND_SOC_DAPM_OUTPUT("MICOUT"), + + SND_SOC_DAPM_ADC("ADC", "HiFi Capture", AK4641_PM1, 0, 0), + SND_SOC_DAPM_PGA("Mic", AK4641_PM1, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA("AUX In", AK4641_PM1, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mono Out", AK4641_PM1, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Line Out", AK4641_PM1, 4, 0, NULL, 0), + + SND_SOC_DAPM_DAC("DAC", "HiFi Playback", AK4641_PM2, 0, 0), + SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0), + + SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0), + SND_SOC_DAPM_ADC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0), + + SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0), + SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0), + + SND_SOC_DAPM_INPUT("MICIN"), + SND_SOC_DAPM_INPUT("MICEXT"), + SND_SOC_DAPM_INPUT("AUX"), + SND_SOC_DAPM_INPUT("AIN"), +}; + +static const struct snd_soc_dapm_route ak4641_audio_map[] = { + /* Stereo Mixer */ + {"Stereo Mixer", "Playback Switch", "DAC"}, + {"Stereo Mixer", "Mic Sidetone Switch", "Input Mux"}, + {"Stereo Mixer", "Aux Bypass Switch", "AUX In"}, + + /* Mono 1 Mixer */ + {"Mono1 Mixer", "Mic Mono Sidetone Switch", "Input Mux"}, + {"Mono1 Mixer", "Mono Playback Switch", "DAC"}, + + /* Mic */ + {"Mic", NULL, "AIN"}, + {"Mic Mux", "Internal", "Mic Int Bias"}, + {"Mic Mux", "External", "Mic Ext Bias"}, + {"Mic Int Bias", NULL, "MICIN"}, + {"Mic Ext Bias", NULL, "MICEXT"}, + {"MICOUT", NULL, "Mic Mux"}, + + /* Input Mux */ + {"Input Mux", "Microphone", "Mic"}, + {"Input Mux", "Voice DAC", "Voice DAC"}, + + /* Line Out */ + {"LOUT", NULL, "Line Out"}, + {"ROUT", NULL, "Line Out"}, + {"Line Out", NULL, "Stereo Mixer"}, + + /* Mono 1 Out */ + {"MOUT1", NULL, "Mono Out"}, + {"Mono Out", NULL, "Mono1 Mixer"}, + + /* Mono 2 Out */ + {"MOUT2", NULL, "Mono 2 Enable"}, + {"Mono 2 Enable", "Switch", "Mono Out 2"}, + {"Mono Out 2", NULL, "Stereo Mixer"}, + + {"Voice ADC", NULL, "Mono 2 Enable"}, + + /* Aux In */ + {"AUX In", NULL, "AUX"}, + + /* ADC */ + {"ADC", NULL, "Input Mixer"}, + {"Input Mixer", "Mic Capture Switch", "Mic"}, + {"Input Mixer", "Aux Capture Switch", "AUX In"}, +}; + +static int ak4641_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); + + ak4641->sysclk = freq; + return 0; +} + +static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); + int rate = params_rate(params), fs = 256; + u8 mode2; + + if (rate) + fs = ak4641->sysclk / rate; + else + return -EINVAL; + + /* set fs */ + switch (fs) { + case 1024: + mode2 = (0x2 << 5); + break; + case 512: + mode2 = (0x1 << 5); + break; + case 256: + mode2 = (0x0 << 5); + break; + default: + dev_err(codec->dev, "Error: unsupported fs=%d\n", fs); + return -EINVAL; + } + + snd_soc_update_bits(codec, AK4641_MODE2, (0x3 << 5), mode2); + + /* Update de-emphasis filter for the new rate */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ak4641->playback_fs = rate; + ak4641_set_deemph(codec); + }; + + return 0; +} + +static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 btif; + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + btif = (0x3 << 5); + break; + case SND_SOC_DAIFMT_LEFT_J: + btif = (0x2 << 5); + break; + case SND_SOC_DAIFMT_DSP_A: /* MSB after FRM */ + btif = (0x0 << 5); + break; + case SND_SOC_DAIFMT_DSP_B: /* MSB during FRM */ + btif = (0x1 << 5); + break; + default: + return -EINVAL; + } + + return snd_soc_update_bits(codec, AK4641_BTIF, (0x3 << 5), btif); +} + +static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 mode1 = 0; + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + mode1 = 0x02; + break; + case SND_SOC_DAIFMT_LEFT_J: + mode1 = 0x01; + break; + default: + return -EINVAL; + } + + return snd_soc_write(codec, AK4641_MODE1, mode1); +} + +static int ak4641_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + + return snd_soc_update_bits(codec, AK4641_DAC, 0x20, mute ? 0x20 : 0); +} + +static int ak4641_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct ak4641_platform_data *pdata = codec->dev->platform_data; + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + /* unmute */ + snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0); + break; + case SND_SOC_BIAS_PREPARE: + /* mute */ + snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20); + break; + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + if (pdata && gpio_is_valid(pdata->gpio_power)) + gpio_set_value(pdata->gpio_power, 1); + mdelay(1); + if (pdata && gpio_is_valid(pdata->gpio_npdn)) + gpio_set_value(pdata->gpio_npdn, 1); + mdelay(1); + + ret = snd_soc_cache_sync(codec); + if (ret) { + dev_err(codec->dev, + "Failed to sync cache: %d\n", ret); + return ret; + } + } + snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0x80); + snd_soc_update_bits(codec, AK4641_PM2, 0x80, 0); + break; + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0); + if (pdata && gpio_is_valid(pdata->gpio_npdn)) + gpio_set_value(pdata->gpio_npdn, 0); + if (pdata && gpio_is_valid(pdata->gpio_power)) + gpio_set_value(pdata->gpio_power, 0); + codec->cache_sync = 1; + break; + } + codec->dapm.bias_level = level; + return 0; +} + +#define AK4641_RATES (SNDRV_PCM_RATE_8000_48000) +#define AK4641_RATES_BT (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000) +#define AK4641_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +static struct snd_soc_dai_ops ak4641_i2s_dai_ops = { + .hw_params = ak4641_i2s_hw_params, + .set_fmt = ak4641_i2s_set_dai_fmt, + .digital_mute = ak4641_mute, + .set_sysclk = ak4641_set_dai_sysclk, +}; + +static struct snd_soc_dai_ops ak4641_pcm_dai_ops = { + .hw_params = NULL, /* rates are controlled by BT chip */ + .set_fmt = ak4641_pcm_set_dai_fmt, + .digital_mute = ak4641_mute, + .set_sysclk = ak4641_set_dai_sysclk, +}; + +struct snd_soc_dai_driver ak4641_dai[] = { +{ + .name = "ak4641-hifi", + .id = 1, + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AK4641_RATES, + .formats = AK4641_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AK4641_RATES, + .formats = AK4641_FORMATS, + }, + .ops = &ak4641_i2s_dai_ops, + .symmetric_rates = 1, +}, +{ + .name = "ak4641-voice", + .id = 1, + .playback = { + .stream_name = "Voice Playback", + .channels_min = 1, + .channels_max = 1, + .rates = AK4641_RATES_BT, + .formats = AK4641_FORMATS, + }, + .capture = { + .stream_name = "Voice Capture", + .channels_min = 1, + .channels_max = 1, + .rates = AK4641_RATES_BT, + .formats = AK4641_FORMATS, + }, + .ops = &ak4641_pcm_dai_ops, + .symmetric_rates = 1, +}, +}; + +static int ak4641_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int ak4641_resume(struct snd_soc_codec *codec) +{ + ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; +} + +static int ak4641_probe(struct snd_soc_codec *codec) +{ + struct ak4641_platform_data *pdata = codec->dev->platform_data; + int ret; + + + if (pdata) { + if (gpio_is_valid(pdata->gpio_power)) { + ret = gpio_request_one(pdata->gpio_power, + GPIOF_OUT_INIT_LOW, "ak4641 power"); + if (ret) + goto err_out; + } + if (gpio_is_valid(pdata->gpio_npdn)) { + ret = gpio_request_one(pdata->gpio_npdn, + GPIOF_OUT_INIT_LOW, "ak4641 npdn"); + if (ret) + goto err_gpio; + + udelay(1); /* > 150 ns */ + gpio_set_value(pdata->gpio_npdn, 1); + } + } + + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err_register; + } + + /* power on device */ + ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; + +err_register: + if (pdata) { + if (gpio_is_valid(pdata->gpio_power)) + gpio_set_value(pdata->gpio_power, 0); + if (gpio_is_valid(pdata->gpio_npdn)) + gpio_free(pdata->gpio_npdn); + } +err_gpio: + if (pdata && gpio_is_valid(pdata->gpio_power)) + gpio_free(pdata->gpio_power); +err_out: + return ret; +} + +static int ak4641_remove(struct snd_soc_codec *codec) +{ + struct ak4641_platform_data *pdata = codec->dev->platform_data; + + ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); + + if (pdata) { + if (gpio_is_valid(pdata->gpio_power)) { + gpio_set_value(pdata->gpio_power, 0); + gpio_free(pdata->gpio_power); + } + if (gpio_is_valid(pdata->gpio_npdn)) + gpio_free(pdata->gpio_npdn); + } + return 0; +} + + +static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { + .probe = ak4641_probe, + .remove = ak4641_remove, + .suspend = ak4641_suspend, + .resume = ak4641_resume, + .controls = ak4641_snd_controls, + .num_controls = ARRAY_SIZE(ak4641_snd_controls), + .dapm_widgets = ak4641_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4641_dapm_widgets), + .dapm_routes = ak4641_audio_map, + .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), + .set_bias_level = ak4641_set_bias_level, + .reg_cache_size = ARRAY_SIZE(ak4641_reg), + .reg_word_size = sizeof(u8), + .reg_cache_default = ak4641_reg, + .reg_cache_step = 1, +}; + + +static int __devinit ak4641_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct ak4641_priv *ak4641; + int ret; + + ak4641 = kzalloc(sizeof(struct ak4641_priv), GFP_KERNEL); + if (!ak4641) + return -ENOMEM; + + i2c_set_clientdata(i2c, ak4641); + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641, + ak4641_dai, ARRAY_SIZE(ak4641_dai)); + if (ret < 0) + kfree(ak4641); + + return ret; +} + +static int __devexit ak4641_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + kfree(i2c_get_clientdata(i2c)); + return 0; +} + +static const struct i2c_device_id ak4641_i2c_id[] = { + { "ak4641", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id); + +static struct i2c_driver ak4641_i2c_driver = { + .driver = { + .name = "ak4641", + .owner = THIS_MODULE, + }, + .probe = ak4641_i2c_probe, + .remove = __devexit_p(ak4641_i2c_remove), + .id_table = ak4641_i2c_id, +}; + +static int __init ak4641_modinit(void) +{ + int ret; + + ret = i2c_add_driver(&ak4641_i2c_driver); + if (ret != 0) + pr_err("Failed to register AK4641 I2C driver: %d\n", ret); + + return ret; +} +module_init(ak4641_modinit); + +static void __exit ak4641_exit(void) +{ + i2c_del_driver(&ak4641_i2c_driver); +} +module_exit(ak4641_exit); + +MODULE_DESCRIPTION("SoC AK4641 driver"); +MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h new file mode 100644 index 000000000000..4a263248efea --- /dev/null +++ b/sound/soc/codecs/ak4641.h @@ -0,0 +1,47 @@ +/* + * ak4641.h -- AK4641 SoC Audio driver + * + * Copyright 2008 Harald Welte <laforge@gnufiish.org> + * + * Based on ak4535.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _AK4641_H +#define _AK4641_H + +/* AK4641 register space */ + +#define AK4641_PM1 0x00 +#define AK4641_PM2 0x01 +#define AK4641_SIG1 0x02 +#define AK4641_SIG2 0x03 +#define AK4641_MODE1 0x04 +#define AK4641_MODE2 0x05 +#define AK4641_DAC 0x06 +#define AK4641_MIC 0x07 +#define AK4641_TIMER 0x08 +#define AK4641_ALC1 0x09 +#define AK4641_ALC2 0x0a +#define AK4641_PGA 0x0b +#define AK4641_LATT 0x0c +#define AK4641_RATT 0x0d +#define AK4641_VOL 0x0e +#define AK4641_STATUS 0x0f +#define AK4641_EQLO 0x10 +#define AK4641_EQMID 0x11 +#define AK4641_EQHI 0x12 +#define AK4641_BTIF 0x13 + +#define AK4641_CACHEREGNUM 0x14 + + + +#define AK4641_DAI_HIFI 0 +#define AK4641_DAI_VOICE 1 + + +#endif diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 2ec75abfa3e9..88b29f8c748b 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -352,7 +352,7 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0), }; -static const struct snd_soc_dapm_route intercon[] = { +static const struct snd_soc_dapm_route ak4671_intercon[] = { {"DAC Left", "NULL", "PMPLL"}, {"DAC Right", "NULL", "PMPLL"}, {"ADC Left", "NULL", "PMPLL"}, @@ -433,17 +433,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"}, }; -static int ak4671_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, ak4671_dapm_widgets, - ARRAY_SIZE(ak4671_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - - return 0; -} - static int ak4671_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -650,7 +639,6 @@ static int ak4671_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, ak4671_snd_controls, ARRAY_SIZE(ak4671_snd_controls)); - ak4671_add_widgets(codec); ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -670,6 +658,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { .reg_cache_size = AK4671_CACHEREGNUM, .reg_word_size = sizeof(u8), .reg_cache_default = ak4671_reg, + .dapm_widgets = ak4671_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets), + .dapm_routes = ak4671_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), }; static int __devinit ak4671_i2c_probe(struct i2c_client *client, diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 4f377c9e868d..eecffb548947 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -481,7 +481,7 @@ struct _pll_div { }; /* Note : pll code from original alc5623 driver. Not sure of how good it is */ -/* usefull only for master mode */ +/* useful only for master mode */ static const struct _pll_div codec_master_pll_div[] = { { 2048000, 8192000, 0x0ea0}, diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index b8066ef10bb0..46dbfd067f79 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -153,8 +153,7 @@ static int cq93vc_resume(struct snd_soc_codec *codec) static int cq93vc_probe(struct snd_soc_codec *codec) { - struct davinci_vc *davinci_vc = - mfd_get_data(to_platform_device(codec->dev)); + struct davinci_vc *davinci_vc = codec->dev->platform_data; davinci_vc->cq93vc.codec = codec; codec->control_data = davinci_vc; diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 0bb424af956f..f8c663dcff02 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -86,18 +86,6 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = { {"ADC", NULL, "Input Mixer"}, }; -static int cx20442_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, cx20442_dapm_widgets, - ARRAY_SIZE(cx20442_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, cx20442_audio_map, - ARRAY_SIZE(cx20442_audio_map)); - - return 0; -} - static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { @@ -274,14 +262,14 @@ static int v253_hangup(struct tty_struct *tty) } /* Line discipline .receive_buf() */ -static void v253_receive(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) +static unsigned int v253_receive(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) { struct snd_soc_codec *codec = tty->disc_data; struct cx20442_priv *cx20442; if (!codec) - return; + return count; cx20442 = snd_soc_codec_get_drvdata(codec); @@ -293,6 +281,8 @@ static void v253_receive(struct tty_struct *tty, codec->hw_write = (hw_write_t)tty->ops->write; codec->card->pop_time = 1; } + + return count; } /* Line discipline .write_wakeup() */ @@ -344,8 +334,6 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec) return -ENOMEM; snd_soc_codec_set_drvdata(codec, cx20442); - cx20442_add_widgets(codec); - cx20442->control_data = NULL; codec->hw_write = NULL; codec->card->pop_time = 0; @@ -377,6 +365,10 @@ static struct snd_soc_codec_driver cx20442_codec_dev = { .reg_word_size = sizeof(u8), .read = cx20442_read_reg_cache, .write = cx20442_write, + .dapm_widgets = cx20442_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets), + .dapm_routes = cx20442_audio_map, + .num_dapm_routes = ARRAY_SIZE(cx20442_audio_map), }; static int cx20442_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 57e9dac88d38..f9a87737ec16 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -39,7 +39,31 @@ static struct snd_soc_dai_driver dmic_dai = { }, }; -static struct snd_soc_codec_driver soc_dmic = {}; +static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = { + SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("DMic"), +}; + +static const struct snd_soc_dapm_route intercon[] = { + {"DMIC AIF", NULL, "DMic"}, +}; + +static int dmic_probe(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = &codec->dapm; + + snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets, + ARRAY_SIZE(dmic_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); + snd_soc_dapm_new_widgets(dapm); + + return 0; +} + +static struct snd_soc_codec_driver soc_dmic = { + .probe = dmic_probe, +}; static int __devinit dmic_dev_probe(struct platform_device *pdev) { diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index f7cd346fd727..e373f8f06907 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -294,22 +294,9 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, static int jz4740_codec_dev_probe(struct snd_soc_codec *codec) { - struct snd_soc_dapm_context *dapm = &codec->dapm; - snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE); - snd_soc_add_controls(codec, jz4740_codec_controls, - ARRAY_SIZE(jz4740_codec_controls)); - - snd_soc_dapm_new_controls(dapm, jz4740_codec_dapm_widgets, - ARRAY_SIZE(jz4740_codec_dapm_widgets)); - - snd_soc_dapm_add_routes(dapm, jz4740_codec_dapm_routes, - ARRAY_SIZE(jz4740_codec_dapm_routes)); - - snd_soc_dapm_new_widgets(codec); - jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; @@ -350,6 +337,13 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { .reg_cache_default = jz4740_codec_regs, .reg_word_size = sizeof(u32), .reg_cache_size = 2, + + .controls = jz4740_codec_controls, + .num_controls = ARRAY_SIZE(jz4740_codec_controls), + .dapm_widgets = jz4740_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(jz4740_codec_dapm_widgets), + .dapm_routes = jz4740_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes), }; static int __devinit jz4740_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 72de47e5d040..2c2a681da0d7 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -161,7 +161,7 @@ static const struct snd_kcontrol_new lm4857_controls[] = { lm4857_get_mode, lm4857_set_mode), }; -/* There is a demux inbetween the the input signal and the output signals. +/* There is a demux between the input signal and the output signals. * Currently there is no easy way to model it in ASoC and since it does not make * much of a difference in practice simply connect the input direclty to the * outputs. */ diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index bd0517cb7980..4173b67c94d1 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -656,8 +656,6 @@ static const struct soc_enum max98088_exmode_enum = ARRAY_SIZE(max98088_exmode_texts), max98088_exmode_texts, max98088_exmode_values); -static const struct snd_kcontrol_new max98088_exmode_controls = - SOC_DAPM_VALUE_ENUM("Route", max98088_exmode_enum); static const char *max98088_ex_thresh[] = { /* volts PP */ "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"}; @@ -783,6 +781,7 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = { SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0), SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0), + SOC_ENUM("EX Limiter Mode", max98088_exmode_enum), SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum), SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum), @@ -808,10 +807,10 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = { /* Left speaker mixer switch */ static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0), @@ -836,10 +835,10 @@ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = { /* Left headphone mixer switch */ static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0), @@ -864,10 +863,10 @@ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = { /* Left earpiece/receiver mixer switch */ static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0), @@ -1094,9 +1093,6 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = { SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0), - SND_SOC_DAPM_MUX("EX Limiter Mode", SND_SOC_NOPM, 0, 0, - &max98088_exmode_controls), - SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), SND_SOC_DAPM_OUTPUT("SPKL"), @@ -1112,7 +1108,7 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = { SND_SOC_DAPM_INPUT("INB2"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route max98088_audio_map[] = { /* Left headphone output mixer */ {"Left HP Mixer", "Left DAC1 Switch", "DACL1"}, {"Left HP Mixer", "Left DAC2 Switch", "DACL2"}, @@ -1226,22 +1222,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"MIC2 Input", NULL, "MIC2"}, }; -static int max98088_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, max98088_dapm_widgets, - ARRAY_SIZE(max98088_dapm_widgets)); - - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - snd_soc_add_controls(codec, max98088_snd_controls, - ARRAY_SIZE(max98088_snd_controls)); - - snd_soc_dapm_new_widgets(dapm); - return 0; -} - /* codec mclk clock divider coefficients */ static const struct { u32 rate; @@ -1586,6 +1566,36 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai, return 0; } +static int max98088_dai1_digital_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int reg; + + if (mute) + reg = M98088_DAI_MUTE; + else + reg = 0; + + snd_soc_update_bits(codec, M98088_REG_2F_LVL_DAI1_PLAY, + M98088_DAI_MUTE_MASK, reg); + return 0; +} + +static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int reg; + + if (mute) + reg = M98088_DAI_MUTE; + else + reg = 0; + + snd_soc_update_bits(codec, M98088_REG_31_LVL_DAI2_PLAY, + M98088_DAI_MUTE_MASK, reg); + return 0; +} + static void max98088_sync_cache(struct snd_soc_codec *codec) { u16 *reg_cache = codec->reg_cache; @@ -1647,12 +1657,14 @@ static struct snd_soc_dai_ops max98088_dai1_ops = { .set_sysclk = max98088_dai_set_sysclk, .set_fmt = max98088_dai1_set_fmt, .hw_params = max98088_dai1_hw_params, + .digital_mute = max98088_dai1_digital_mute, }; static struct snd_soc_dai_ops max98088_dai2_ops = { .set_sysclk = max98088_dai_set_sysclk, .set_fmt = max98088_dai2_set_fmt, .hw_params = max98088_dai2_hw_params, + .digital_mute = max98088_dai2_digital_mute, }; static struct snd_soc_dai_driver max98088_dai[] = { @@ -2010,7 +2022,8 @@ static int max98088_probe(struct snd_soc_codec *codec) max98088_handle_pdata(codec); - max98088_add_widgets(codec); + snd_soc_add_controls(codec, max98088_snd_controls, + ARRAY_SIZE(max98088_snd_controls)); err_access: return ret; @@ -2036,6 +2049,10 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = { .reg_word_size = sizeof(u8), .reg_cache_default = max98088_reg, .volatile_register = max98088_volatile_register, + .dapm_widgets = max98088_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets), + .dapm_routes = max98088_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98088_audio_map), }; static int max98088_i2c_probe(struct i2c_client *i2c, diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h index 56554c797fef..be89a4f4aab8 100644 --- a/sound/soc/codecs/max98088.h +++ b/sound/soc/codecs/max98088.h @@ -133,6 +133,19 @@ #define M98088_REC_LINEMODE (1<<7) #define M98088_REC_LINEMODE_MASK (1<<7) +/* M98088_REG_2D_MIX_SPK_CNTL */ + #define M98088_MIX_SPKR_GAIN_MASK (3<<2) + #define M98088_MIX_SPKR_GAIN_SHIFT 2 + #define M98088_MIX_SPKL_GAIN_MASK (3<<0) + #define M98088_MIX_SPKL_GAIN_SHIFT 0 + +/* M98088_REG_2F_LVL_DAI1_PLAY, M98088_REG_31_LVL_DAI2_PLAY */ + #define M98088_DAI_MUTE (1<<7) + #define M98088_DAI_MUTE_MASK (1<<7) + #define M98088_DAI_VOICE_GAIN_MASK (3<<4) + #define M98088_DAI_ATTENUATION_MASK (0xF<<0) + #define M98088_DAI_ATTENUATION_SHIFT 0 + /* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */ #define M98088_MICPRE_MASK (3<<5) #define M98088_MICPRE_SHIFT 5 diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c new file mode 100644 index 000000000000..e1d282d477da --- /dev/null +++ b/sound/soc/codecs/max98095.c @@ -0,0 +1,2396 @@ +/* + * max98095.c -- MAX98095 ALSA SoC Audio driver + * + * Copyright 2011 Maxim Integrated Products + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.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/initval.h> +#include <sound/tlv.h> +#include <linux/slab.h> +#include <asm/div64.h> +#include <sound/max98095.h> +#include "max98095.h" + +enum max98095_type { + MAX98095, +}; + +struct max98095_cdata { + unsigned int rate; + unsigned int fmt; + int eq_sel; + int bq_sel; +}; + +struct max98095_priv { + enum max98095_type devtype; + void *control_data; + struct max98095_pdata *pdata; + unsigned int sysclk; + struct max98095_cdata dai[3]; + const char **eq_texts; + const char **bq_texts; + struct soc_enum eq_enum; + struct soc_enum bq_enum; + int eq_textcnt; + int bq_textcnt; + u8 lin_state; + unsigned int mic1pre; + unsigned int mic2pre; +}; + +static const u8 max98095_reg_def[M98095_REG_CNT] = { + 0x00, /* 00 */ + 0x00, /* 01 */ + 0x00, /* 02 */ + 0x00, /* 03 */ + 0x00, /* 04 */ + 0x00, /* 05 */ + 0x00, /* 06 */ + 0x00, /* 07 */ + 0x00, /* 08 */ + 0x00, /* 09 */ + 0x00, /* 0A */ + 0x00, /* 0B */ + 0x00, /* 0C */ + 0x00, /* 0D */ + 0x00, /* 0E */ + 0x00, /* 0F */ + 0x00, /* 10 */ + 0x00, /* 11 */ + 0x00, /* 12 */ + 0x00, /* 13 */ + 0x00, /* 14 */ + 0x00, /* 15 */ + 0x00, /* 16 */ + 0x00, /* 17 */ + 0x00, /* 18 */ + 0x00, /* 19 */ + 0x00, /* 1A */ + 0x00, /* 1B */ + 0x00, /* 1C */ + 0x00, /* 1D */ + 0x00, /* 1E */ + 0x00, /* 1F */ + 0x00, /* 20 */ + 0x00, /* 21 */ + 0x00, /* 22 */ + 0x00, /* 23 */ + 0x00, /* 24 */ + 0x00, /* 25 */ + 0x00, /* 26 */ + 0x00, /* 27 */ + 0x00, /* 28 */ + 0x00, /* 29 */ + 0x00, /* 2A */ + 0x00, /* 2B */ + 0x00, /* 2C */ + 0x00, /* 2D */ + 0x00, /* 2E */ + 0x00, /* 2F */ + 0x00, /* 30 */ + 0x00, /* 31 */ + 0x00, /* 32 */ + 0x00, /* 33 */ + 0x00, /* 34 */ + 0x00, /* 35 */ + 0x00, /* 36 */ + 0x00, /* 37 */ + 0x00, /* 38 */ + 0x00, /* 39 */ + 0x00, /* 3A */ + 0x00, /* 3B */ + 0x00, /* 3C */ + 0x00, /* 3D */ + 0x00, /* 3E */ + 0x00, /* 3F */ + 0x00, /* 40 */ + 0x00, /* 41 */ + 0x00, /* 42 */ + 0x00, /* 43 */ + 0x00, /* 44 */ + 0x00, /* 45 */ + 0x00, /* 46 */ + 0x00, /* 47 */ + 0x00, /* 48 */ + 0x00, /* 49 */ + 0x00, /* 4A */ + 0x00, /* 4B */ + 0x00, /* 4C */ + 0x00, /* 4D */ + 0x00, /* 4E */ + 0x00, /* 4F */ + 0x00, /* 50 */ + 0x00, /* 51 */ + 0x00, /* 52 */ + 0x00, /* 53 */ + 0x00, /* 54 */ + 0x00, /* 55 */ + 0x00, /* 56 */ + 0x00, /* 57 */ + 0x00, /* 58 */ + 0x00, /* 59 */ + 0x00, /* 5A */ + 0x00, /* 5B */ + 0x00, /* 5C */ + 0x00, /* 5D */ + 0x00, /* 5E */ + 0x00, /* 5F */ + 0x00, /* 60 */ + 0x00, /* 61 */ + 0x00, /* 62 */ + 0x00, /* 63 */ + 0x00, /* 64 */ + 0x00, /* 65 */ + 0x00, /* 66 */ + 0x00, /* 67 */ + 0x00, /* 68 */ + 0x00, /* 69 */ + 0x00, /* 6A */ + 0x00, /* 6B */ + 0x00, /* 6C */ + 0x00, /* 6D */ + 0x00, /* 6E */ + 0x00, /* 6F */ + 0x00, /* 70 */ + 0x00, /* 71 */ + 0x00, /* 72 */ + 0x00, /* 73 */ + 0x00, /* 74 */ + 0x00, /* 75 */ + 0x00, /* 76 */ + 0x00, /* 77 */ + 0x00, /* 78 */ + 0x00, /* 79 */ + 0x00, /* 7A */ + 0x00, /* 7B */ + 0x00, /* 7C */ + 0x00, /* 7D */ + 0x00, /* 7E */ + 0x00, /* 7F */ + 0x00, /* 80 */ + 0x00, /* 81 */ + 0x00, /* 82 */ + 0x00, /* 83 */ + 0x00, /* 84 */ + 0x00, /* 85 */ + 0x00, /* 86 */ + 0x00, /* 87 */ + 0x00, /* 88 */ + 0x00, /* 89 */ + 0x00, /* 8A */ + 0x00, /* 8B */ + 0x00, /* 8C */ + 0x00, /* 8D */ + 0x00, /* 8E */ + 0x00, /* 8F */ + 0x00, /* 90 */ + 0x00, /* 91 */ + 0x30, /* 92 */ + 0xF0, /* 93 */ + 0x00, /* 94 */ + 0x00, /* 95 */ + 0x3F, /* 96 */ + 0x00, /* 97 */ + 0x00, /* 98 */ + 0x00, /* 99 */ + 0x00, /* 9A */ + 0x00, /* 9B */ + 0x00, /* 9C */ + 0x00, /* 9D */ + 0x00, /* 9E */ + 0x00, /* 9F */ + 0x00, /* A0 */ + 0x00, /* A1 */ + 0x00, /* A2 */ + 0x00, /* A3 */ + 0x00, /* A4 */ + 0x00, /* A5 */ + 0x00, /* A6 */ + 0x00, /* A7 */ + 0x00, /* A8 */ + 0x00, /* A9 */ + 0x00, /* AA */ + 0x00, /* AB */ + 0x00, /* AC */ + 0x00, /* AD */ + 0x00, /* AE */ + 0x00, /* AF */ + 0x00, /* B0 */ + 0x00, /* B1 */ + 0x00, /* B2 */ + 0x00, /* B3 */ + 0x00, /* B4 */ + 0x00, /* B5 */ + 0x00, /* B6 */ + 0x00, /* B7 */ + 0x00, /* B8 */ + 0x00, /* B9 */ + 0x00, /* BA */ + 0x00, /* BB */ + 0x00, /* BC */ + 0x00, /* BD */ + 0x00, /* BE */ + 0x00, /* BF */ + 0x00, /* C0 */ + 0x00, /* C1 */ + 0x00, /* C2 */ + 0x00, /* C3 */ + 0x00, /* C4 */ + 0x00, /* C5 */ + 0x00, /* C6 */ + 0x00, /* C7 */ + 0x00, /* C8 */ + 0x00, /* C9 */ + 0x00, /* CA */ + 0x00, /* CB */ + 0x00, /* CC */ + 0x00, /* CD */ + 0x00, /* CE */ + 0x00, /* CF */ + 0x00, /* D0 */ + 0x00, /* D1 */ + 0x00, /* D2 */ + 0x00, /* D3 */ + 0x00, /* D4 */ + 0x00, /* D5 */ + 0x00, /* D6 */ + 0x00, /* D7 */ + 0x00, /* D8 */ + 0x00, /* D9 */ + 0x00, /* DA */ + 0x00, /* DB */ + 0x00, /* DC */ + 0x00, /* DD */ + 0x00, /* DE */ + 0x00, /* DF */ + 0x00, /* E0 */ + 0x00, /* E1 */ + 0x00, /* E2 */ + 0x00, /* E3 */ + 0x00, /* E4 */ + 0x00, /* E5 */ + 0x00, /* E6 */ + 0x00, /* E7 */ + 0x00, /* E8 */ + 0x00, /* E9 */ + 0x00, /* EA */ + 0x00, /* EB */ + 0x00, /* EC */ + 0x00, /* ED */ + 0x00, /* EE */ + 0x00, /* EF */ + 0x00, /* F0 */ + 0x00, /* F1 */ + 0x00, /* F2 */ + 0x00, /* F3 */ + 0x00, /* F4 */ + 0x00, /* F5 */ + 0x00, /* F6 */ + 0x00, /* F7 */ + 0x00, /* F8 */ + 0x00, /* F9 */ + 0x00, /* FA */ + 0x00, /* FB */ + 0x00, /* FC */ + 0x00, /* FD */ + 0x00, /* FE */ + 0x00, /* FF */ +}; + +static struct { + int readable; + int writable; +} max98095_access[M98095_REG_CNT] = { + { 0x00, 0x00 }, /* 00 */ + { 0xFF, 0x00 }, /* 01 */ + { 0xFF, 0x00 }, /* 02 */ + { 0xFF, 0x00 }, /* 03 */ + { 0xFF, 0x00 }, /* 04 */ + { 0xFF, 0x00 }, /* 05 */ + { 0xFF, 0x00 }, /* 06 */ + { 0xFF, 0x00 }, /* 07 */ + { 0xFF, 0x00 }, /* 08 */ + { 0xFF, 0x00 }, /* 09 */ + { 0xFF, 0x00 }, /* 0A */ + { 0xFF, 0x00 }, /* 0B */ + { 0xFF, 0x00 }, /* 0C */ + { 0xFF, 0x00 }, /* 0D */ + { 0xFF, 0x00 }, /* 0E */ + { 0xFF, 0x9F }, /* 0F */ + { 0xFF, 0xFF }, /* 10 */ + { 0xFF, 0xFF }, /* 11 */ + { 0xFF, 0xFF }, /* 12 */ + { 0xFF, 0xFF }, /* 13 */ + { 0xFF, 0xFF }, /* 14 */ + { 0xFF, 0xFF }, /* 15 */ + { 0xFF, 0xFF }, /* 16 */ + { 0xFF, 0xFF }, /* 17 */ + { 0xFF, 0xFF }, /* 18 */ + { 0xFF, 0xFF }, /* 19 */ + { 0xFF, 0xFF }, /* 1A */ + { 0xFF, 0xFF }, /* 1B */ + { 0xFF, 0xFF }, /* 1C */ + { 0xFF, 0xFF }, /* 1D */ + { 0xFF, 0x77 }, /* 1E */ + { 0xFF, 0x77 }, /* 1F */ + { 0xFF, 0x77 }, /* 20 */ + { 0xFF, 0x77 }, /* 21 */ + { 0xFF, 0x77 }, /* 22 */ + { 0xFF, 0x77 }, /* 23 */ + { 0xFF, 0xFF }, /* 24 */ + { 0xFF, 0x7F }, /* 25 */ + { 0xFF, 0x31 }, /* 26 */ + { 0xFF, 0xFF }, /* 27 */ + { 0xFF, 0xFF }, /* 28 */ + { 0xFF, 0xFF }, /* 29 */ + { 0xFF, 0xF7 }, /* 2A */ + { 0xFF, 0x2F }, /* 2B */ + { 0xFF, 0xEF }, /* 2C */ + { 0xFF, 0xFF }, /* 2D */ + { 0xFF, 0xFF }, /* 2E */ + { 0xFF, 0xFF }, /* 2F */ + { 0xFF, 0xFF }, /* 30 */ + { 0xFF, 0xFF }, /* 31 */ + { 0xFF, 0xFF }, /* 32 */ + { 0xFF, 0xFF }, /* 33 */ + { 0xFF, 0xF7 }, /* 34 */ + { 0xFF, 0x2F }, /* 35 */ + { 0xFF, 0xCF }, /* 36 */ + { 0xFF, 0xFF }, /* 37 */ + { 0xFF, 0xFF }, /* 38 */ + { 0xFF, 0xFF }, /* 39 */ + { 0xFF, 0xFF }, /* 3A */ + { 0xFF, 0xFF }, /* 3B */ + { 0xFF, 0xFF }, /* 3C */ + { 0xFF, 0xFF }, /* 3D */ + { 0xFF, 0xF7 }, /* 3E */ + { 0xFF, 0x2F }, /* 3F */ + { 0xFF, 0xCF }, /* 40 */ + { 0xFF, 0xFF }, /* 41 */ + { 0xFF, 0x77 }, /* 42 */ + { 0xFF, 0xFF }, /* 43 */ + { 0xFF, 0xFF }, /* 44 */ + { 0xFF, 0xFF }, /* 45 */ + { 0xFF, 0xFF }, /* 46 */ + { 0xFF, 0xFF }, /* 47 */ + { 0xFF, 0xFF }, /* 48 */ + { 0xFF, 0x0F }, /* 49 */ + { 0xFF, 0xFF }, /* 4A */ + { 0xFF, 0xFF }, /* 4B */ + { 0xFF, 0x3F }, /* 4C */ + { 0xFF, 0x3F }, /* 4D */ + { 0xFF, 0x3F }, /* 4E */ + { 0xFF, 0xFF }, /* 4F */ + { 0xFF, 0x7F }, /* 50 */ + { 0xFF, 0x7F }, /* 51 */ + { 0xFF, 0x0F }, /* 52 */ + { 0xFF, 0x3F }, /* 53 */ + { 0xFF, 0x3F }, /* 54 */ + { 0xFF, 0x3F }, /* 55 */ + { 0xFF, 0xFF }, /* 56 */ + { 0xFF, 0xFF }, /* 57 */ + { 0xFF, 0xBF }, /* 58 */ + { 0xFF, 0x1F }, /* 59 */ + { 0xFF, 0xBF }, /* 5A */ + { 0xFF, 0x1F }, /* 5B */ + { 0xFF, 0xBF }, /* 5C */ + { 0xFF, 0x3F }, /* 5D */ + { 0xFF, 0x3F }, /* 5E */ + { 0xFF, 0x7F }, /* 5F */ + { 0xFF, 0x7F }, /* 60 */ + { 0xFF, 0x47 }, /* 61 */ + { 0xFF, 0x9F }, /* 62 */ + { 0xFF, 0x9F }, /* 63 */ + { 0xFF, 0x9F }, /* 64 */ + { 0xFF, 0x9F }, /* 65 */ + { 0xFF, 0x9F }, /* 66 */ + { 0xFF, 0xBF }, /* 67 */ + { 0xFF, 0xBF }, /* 68 */ + { 0xFF, 0xFF }, /* 69 */ + { 0xFF, 0xFF }, /* 6A */ + { 0xFF, 0x7F }, /* 6B */ + { 0xFF, 0xF7 }, /* 6C */ + { 0xFF, 0xFF }, /* 6D */ + { 0xFF, 0xFF }, /* 6E */ + { 0xFF, 0x1F }, /* 6F */ + { 0xFF, 0xF7 }, /* 70 */ + { 0xFF, 0xFF }, /* 71 */ + { 0xFF, 0xFF }, /* 72 */ + { 0xFF, 0x1F }, /* 73 */ + { 0xFF, 0xF7 }, /* 74 */ + { 0xFF, 0xFF }, /* 75 */ + { 0xFF, 0xFF }, /* 76 */ + { 0xFF, 0x1F }, /* 77 */ + { 0xFF, 0xF7 }, /* 78 */ + { 0xFF, 0xFF }, /* 79 */ + { 0xFF, 0xFF }, /* 7A */ + { 0xFF, 0x1F }, /* 7B */ + { 0xFF, 0xF7 }, /* 7C */ + { 0xFF, 0xFF }, /* 7D */ + { 0xFF, 0xFF }, /* 7E */ + { 0xFF, 0x1F }, /* 7F */ + { 0xFF, 0xF7 }, /* 80 */ + { 0xFF, 0xFF }, /* 81 */ + { 0xFF, 0xFF }, /* 82 */ + { 0xFF, 0x1F }, /* 83 */ + { 0xFF, 0x7F }, /* 84 */ + { 0xFF, 0x0F }, /* 85 */ + { 0xFF, 0xD8 }, /* 86 */ + { 0xFF, 0xFF }, /* 87 */ + { 0xFF, 0xEF }, /* 88 */ + { 0xFF, 0xFE }, /* 89 */ + { 0xFF, 0xFE }, /* 8A */ + { 0xFF, 0xFF }, /* 8B */ + { 0xFF, 0xFF }, /* 8C */ + { 0xFF, 0x3F }, /* 8D */ + { 0xFF, 0xFF }, /* 8E */ + { 0xFF, 0x3F }, /* 8F */ + { 0xFF, 0x8F }, /* 90 */ + { 0xFF, 0xFF }, /* 91 */ + { 0xFF, 0x3F }, /* 92 */ + { 0xFF, 0xFF }, /* 93 */ + { 0xFF, 0xFF }, /* 94 */ + { 0xFF, 0x0F }, /* 95 */ + { 0xFF, 0x3F }, /* 96 */ + { 0xFF, 0x8C }, /* 97 */ + { 0x00, 0x00 }, /* 98 */ + { 0x00, 0x00 }, /* 99 */ + { 0x00, 0x00 }, /* 9A */ + { 0x00, 0x00 }, /* 9B */ + { 0x00, 0x00 }, /* 9C */ + { 0x00, 0x00 }, /* 9D */ + { 0x00, 0x00 }, /* 9E */ + { 0x00, 0x00 }, /* 9F */ + { 0x00, 0x00 }, /* A0 */ + { 0x00, 0x00 }, /* A1 */ + { 0x00, 0x00 }, /* A2 */ + { 0x00, 0x00 }, /* A3 */ + { 0x00, 0x00 }, /* A4 */ + { 0x00, 0x00 }, /* A5 */ + { 0x00, 0x00 }, /* A6 */ + { 0x00, 0x00 }, /* A7 */ + { 0x00, 0x00 }, /* A8 */ + { 0x00, 0x00 }, /* A9 */ + { 0x00, 0x00 }, /* AA */ + { 0x00, 0x00 }, /* AB */ + { 0x00, 0x00 }, /* AC */ + { 0x00, 0x00 }, /* AD */ + { 0x00, 0x00 }, /* AE */ + { 0x00, 0x00 }, /* AF */ + { 0x00, 0x00 }, /* B0 */ + { 0x00, 0x00 }, /* B1 */ + { 0x00, 0x00 }, /* B2 */ + { 0x00, 0x00 }, /* B3 */ + { 0x00, 0x00 }, /* B4 */ + { 0x00, 0x00 }, /* B5 */ + { 0x00, 0x00 }, /* B6 */ + { 0x00, 0x00 }, /* B7 */ + { 0x00, 0x00 }, /* B8 */ + { 0x00, 0x00 }, /* B9 */ + { 0x00, 0x00 }, /* BA */ + { 0x00, 0x00 }, /* BB */ + { 0x00, 0x00 }, /* BC */ + { 0x00, 0x00 }, /* BD */ + { 0x00, 0x00 }, /* BE */ + { 0x00, 0x00 }, /* BF */ + { 0x00, 0x00 }, /* C0 */ + { 0x00, 0x00 }, /* C1 */ + { 0x00, 0x00 }, /* C2 */ + { 0x00, 0x00 }, /* C3 */ + { 0x00, 0x00 }, /* C4 */ + { 0x00, 0x00 }, /* C5 */ + { 0x00, 0x00 }, /* C6 */ + { 0x00, 0x00 }, /* C7 */ + { 0x00, 0x00 }, /* C8 */ + { 0x00, 0x00 }, /* C9 */ + { 0x00, 0x00 }, /* CA */ + { 0x00, 0x00 }, /* CB */ + { 0x00, 0x00 }, /* CC */ + { 0x00, 0x00 }, /* CD */ + { 0x00, 0x00 }, /* CE */ + { 0x00, 0x00 }, /* CF */ + { 0x00, 0x00 }, /* D0 */ + { 0x00, 0x00 }, /* D1 */ + { 0x00, 0x00 }, /* D2 */ + { 0x00, 0x00 }, /* D3 */ + { 0x00, 0x00 }, /* D4 */ + { 0x00, 0x00 }, /* D5 */ + { 0x00, 0x00 }, /* D6 */ + { 0x00, 0x00 }, /* D7 */ + { 0x00, 0x00 }, /* D8 */ + { 0x00, 0x00 }, /* D9 */ + { 0x00, 0x00 }, /* DA */ + { 0x00, 0x00 }, /* DB */ + { 0x00, 0x00 }, /* DC */ + { 0x00, 0x00 }, /* DD */ + { 0x00, 0x00 }, /* DE */ + { 0x00, 0x00 }, /* DF */ + { 0x00, 0x00 }, /* E0 */ + { 0x00, 0x00 }, /* E1 */ + { 0x00, 0x00 }, /* E2 */ + { 0x00, 0x00 }, /* E3 */ + { 0x00, 0x00 }, /* E4 */ + { 0x00, 0x00 }, /* E5 */ + { 0x00, 0x00 }, /* E6 */ + { 0x00, 0x00 }, /* E7 */ + { 0x00, 0x00 }, /* E8 */ + { 0x00, 0x00 }, /* E9 */ + { 0x00, 0x00 }, /* EA */ + { 0x00, 0x00 }, /* EB */ + { 0x00, 0x00 }, /* EC */ + { 0x00, 0x00 }, /* ED */ + { 0x00, 0x00 }, /* EE */ + { 0x00, 0x00 }, /* EF */ + { 0x00, 0x00 }, /* F0 */ + { 0x00, 0x00 }, /* F1 */ + { 0x00, 0x00 }, /* F2 */ + { 0x00, 0x00 }, /* F3 */ + { 0x00, 0x00 }, /* F4 */ + { 0x00, 0x00 }, /* F5 */ + { 0x00, 0x00 }, /* F6 */ + { 0x00, 0x00 }, /* F7 */ + { 0x00, 0x00 }, /* F8 */ + { 0x00, 0x00 }, /* F9 */ + { 0x00, 0x00 }, /* FA */ + { 0x00, 0x00 }, /* FB */ + { 0x00, 0x00 }, /* FC */ + { 0x00, 0x00 }, /* FD */ + { 0x00, 0x00 }, /* FE */ + { 0xFF, 0x00 }, /* FF */ +}; + +static int max98095_readable(struct snd_soc_codec *codec, unsigned int reg) +{ + if (reg >= M98095_REG_CNT) + return 0; + return max98095_access[reg].readable != 0; +} + +static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg) +{ + if (reg > M98095_REG_MAX_CACHED) + return 1; + + switch (reg) { + case M98095_000_HOST_DATA: + case M98095_001_HOST_INT_STS: + case M98095_002_HOST_RSP_STS: + case M98095_003_HOST_CMD_STS: + case M98095_004_CODEC_STS: + case M98095_005_DAI1_ALC_STS: + case M98095_006_DAI2_ALC_STS: + case M98095_007_JACK_AUTO_STS: + case M98095_008_JACK_MANUAL_STS: + case M98095_009_JACK_VBAT_STS: + case M98095_00A_ACC_ADC_STS: + case M98095_00B_MIC_NG_AGC_STS: + case M98095_00C_SPK_L_VOLT_STS: + case M98095_00D_SPK_R_VOLT_STS: + case M98095_00E_TEMP_SENSOR_STS: + return 1; + } + + return 0; +} + +/* + * Filter coefficients are in a separate register segment + * and they share the address space of the normal registers. + * The coefficient registers do not need or share the cache. + */ +static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + data[0] = reg; + data[1] = value; + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +/* + * Load equalizer DSP coefficient configurations registers + */ +static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai, + unsigned int band, u16 *coefs) +{ + unsigned int eq_reg; + unsigned int i; + + BUG_ON(band > 4); + BUG_ON(dai > 1); + + /* Load the base register address */ + eq_reg = dai ? M98095_142_DAI2_EQ_BASE : M98095_110_DAI1_EQ_BASE; + + /* Add the band address offset, note adjustment for word address */ + eq_reg += band * (M98095_COEFS_PER_BAND << 1); + + /* Step through the registers and coefs */ + for (i = 0; i < M98095_COEFS_PER_BAND; i++) { + max98095_hw_write(codec, eq_reg++, M98095_BYTE1(coefs[i])); + max98095_hw_write(codec, eq_reg++, M98095_BYTE0(coefs[i])); + } +} + +/* + * Load biquad filter coefficient configurations registers + */ +static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai, + unsigned int band, u16 *coefs) +{ + unsigned int bq_reg; + unsigned int i; + + BUG_ON(band > 1); + BUG_ON(dai > 1); + + /* Load the base register address */ + bq_reg = dai ? M98095_17E_DAI2_BQ_BASE : M98095_174_DAI1_BQ_BASE; + + /* Add the band address offset, note adjustment for word address */ + bq_reg += band * (M98095_COEFS_PER_BAND << 1); + + /* Step through the registers and coefs */ + for (i = 0; i < M98095_COEFS_PER_BAND; i++) { + max98095_hw_write(codec, bq_reg++, M98095_BYTE1(coefs[i])); + max98095_hw_write(codec, bq_reg++, M98095_BYTE0(coefs[i])); + } +} + +static const char * const max98095_fltr_mode[] = { "Voice", "Music" }; +static const struct soc_enum max98095_dai1_filter_mode_enum[] = { + SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 7, 2, max98095_fltr_mode), +}; +static const struct soc_enum max98095_dai2_filter_mode_enum[] = { + SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 7, 2, max98095_fltr_mode), +}; + +static const char * const max98095_extmic_text[] = { "None", "MIC1", "MIC2" }; + +static const struct soc_enum max98095_extmic_enum = + SOC_ENUM_SINGLE(M98095_087_CFG_MIC, 0, 3, max98095_extmic_text); + +static const struct snd_kcontrol_new max98095_extmic_mux = + SOC_DAPM_ENUM("External MIC Mux", max98095_extmic_enum); + +static const char * const max98095_linein_text[] = { "INA", "INB" }; + +static const struct soc_enum max98095_linein_enum = + SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 6, 2, max98095_linein_text); + +static const struct snd_kcontrol_new max98095_linein_mux = + SOC_DAPM_ENUM("Linein Input Mux", max98095_linein_enum); + +static const char * const max98095_line_mode_text[] = { + "Stereo", "Differential"}; + +static const struct soc_enum max98095_linein_mode_enum = + SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 7, 2, max98095_line_mode_text); + +static const struct soc_enum max98095_lineout_mode_enum = + SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 4, 2, max98095_line_mode_text); + +static const char * const max98095_dai_fltr[] = { + "Off", "Elliptical-HPF-16k", "Butterworth-HPF-16k", + "Elliptical-HPF-8k", "Butterworth-HPF-8k", "Butterworth-HPF-Fs/240"}; +static const struct soc_enum max98095_dai1_dac_filter_enum[] = { + SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 0, 6, max98095_dai_fltr), +}; +static const struct soc_enum max98095_dai2_dac_filter_enum[] = { + SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 0, 6, max98095_dai_fltr), +}; +static const struct soc_enum max98095_dai3_dac_filter_enum[] = { + SOC_ENUM_SINGLE(M98095_042_DAI3_FILTERS, 0, 6, max98095_dai_fltr), +}; + +static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + + max98095->mic1pre = sel; + snd_soc_update_bits(codec, M98095_05F_LVL_MIC1, M98095_MICPRE_MASK, + (1+sel)<<M98095_MICPRE_SHIFT); + + return 0; +} + +static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = max98095->mic1pre; + return 0; +} + +static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + + max98095->mic2pre = sel; + snd_soc_update_bits(codec, M98095_060_LVL_MIC2, M98095_MICPRE_MASK, + (1+sel)<<M98095_MICPRE_SHIFT); + + return 0; +} + +static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = max98095->mic2pre; + return 0; +} + +static const unsigned int max98095_micboost_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), + 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), +}; + +static const DECLARE_TLV_DB_SCALE(max98095_mic_tlv, 0, 100, 0); +static const DECLARE_TLV_DB_SCALE(max98095_adc_tlv, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(max98095_adcboost_tlv, 0, 600, 0); + +static const unsigned int max98095_hp_tlv[] = { + TLV_DB_RANGE_HEAD(5), + 0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0), + 7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0), + 15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0), + 22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0), + 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0), +}; + +static const unsigned int max98095_spk_tlv[] = { + TLV_DB_RANGE_HEAD(4), + 0, 10, TLV_DB_SCALE_ITEM(-5900, 400, 0), + 11, 18, TLV_DB_SCALE_ITEM(-1700, 200, 0), + 19, 27, TLV_DB_SCALE_ITEM(-200, 100, 0), + 28, 39, TLV_DB_SCALE_ITEM(650, 50, 0), +}; + +static const unsigned int max98095_rcv_lout_tlv[] = { + TLV_DB_RANGE_HEAD(5), + 0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0), + 7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0), + 15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0), + 22, 27, TLV_DB_SCALE_ITEM(100, 100, 0), + 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0), +}; + +static const unsigned int max98095_lin_tlv[] = { + TLV_DB_RANGE_HEAD(3), + 0, 2, TLV_DB_SCALE_ITEM(-600, 300, 0), + 3, 3, TLV_DB_SCALE_ITEM(300, 1100, 0), + 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0), +}; + +static const struct snd_kcontrol_new max98095_snd_controls[] = { + + SOC_DOUBLE_R_TLV("Headphone Volume", M98095_064_LVL_HP_L, + M98095_065_LVL_HP_R, 0, 31, 0, max98095_hp_tlv), + + SOC_DOUBLE_R_TLV("Speaker Volume", M98095_067_LVL_SPK_L, + M98095_068_LVL_SPK_R, 0, 39, 0, max98095_spk_tlv), + + SOC_SINGLE_TLV("Receiver Volume", M98095_066_LVL_RCV, + 0, 31, 0, max98095_rcv_lout_tlv), + + SOC_DOUBLE_R_TLV("Lineout Volume", M98095_062_LVL_LINEOUT1, + M98095_063_LVL_LINEOUT2, 0, 31, 0, max98095_rcv_lout_tlv), + + SOC_DOUBLE_R("Headphone Switch", M98095_064_LVL_HP_L, + M98095_065_LVL_HP_R, 7, 1, 1), + + SOC_DOUBLE_R("Speaker Switch", M98095_067_LVL_SPK_L, + M98095_068_LVL_SPK_R, 7, 1, 1), + + SOC_SINGLE("Receiver Switch", M98095_066_LVL_RCV, 7, 1, 1), + + SOC_DOUBLE_R("Lineout Switch", M98095_062_LVL_LINEOUT1, + M98095_063_LVL_LINEOUT2, 7, 1, 1), + + SOC_SINGLE_TLV("MIC1 Volume", M98095_05F_LVL_MIC1, 0, 20, 1, + max98095_mic_tlv), + + SOC_SINGLE_TLV("MIC2 Volume", M98095_060_LVL_MIC2, 0, 20, 1, + max98095_mic_tlv), + + SOC_SINGLE_EXT_TLV("MIC1 Boost Volume", + M98095_05F_LVL_MIC1, 5, 2, 0, + max98095_mic1pre_get, max98095_mic1pre_set, + max98095_micboost_tlv), + SOC_SINGLE_EXT_TLV("MIC2 Boost Volume", + M98095_060_LVL_MIC2, 5, 2, 0, + max98095_mic2pre_get, max98095_mic2pre_set, + max98095_micboost_tlv), + + SOC_SINGLE_TLV("Linein Volume", M98095_061_LVL_LINEIN, 0, 5, 1, + max98095_lin_tlv), + + SOC_SINGLE_TLV("ADCL Volume", M98095_05D_LVL_ADC_L, 0, 15, 1, + max98095_adc_tlv), + SOC_SINGLE_TLV("ADCR Volume", M98095_05E_LVL_ADC_R, 0, 15, 1, + max98095_adc_tlv), + + SOC_SINGLE_TLV("ADCL Boost Volume", M98095_05D_LVL_ADC_L, 4, 3, 0, + max98095_adcboost_tlv), + SOC_SINGLE_TLV("ADCR Boost Volume", M98095_05E_LVL_ADC_R, 4, 3, 0, + max98095_adcboost_tlv), + + SOC_SINGLE("EQ1 Switch", M98095_088_CFG_LEVEL, 0, 1, 0), + SOC_SINGLE("EQ2 Switch", M98095_088_CFG_LEVEL, 1, 1, 0), + + SOC_SINGLE("Biquad1 Switch", M98095_088_CFG_LEVEL, 2, 1, 0), + SOC_SINGLE("Biquad2 Switch", M98095_088_CFG_LEVEL, 3, 1, 0), + + SOC_ENUM("DAI1 Filter Mode", max98095_dai1_filter_mode_enum), + SOC_ENUM("DAI2 Filter Mode", max98095_dai2_filter_mode_enum), + SOC_ENUM("DAI1 DAC Filter", max98095_dai1_dac_filter_enum), + SOC_ENUM("DAI2 DAC Filter", max98095_dai2_dac_filter_enum), + SOC_ENUM("DAI3 DAC Filter", max98095_dai3_dac_filter_enum), + + SOC_ENUM("Linein Mode", max98095_linein_mode_enum), + SOC_ENUM("Lineout Mode", max98095_lineout_mode_enum), +}; + +/* Left speaker mixer switch */ +static const struct snd_kcontrol_new max98095_left_speaker_mixer_controls[] = { + SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_050_MIX_SPK_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_050_MIX_SPK_LEFT, 6, 1, 0), + SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0), + SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0), + SOC_DAPM_SINGLE("MIC1 Switch", M98095_050_MIX_SPK_LEFT, 4, 1, 0), + SOC_DAPM_SINGLE("MIC2 Switch", M98095_050_MIX_SPK_LEFT, 5, 1, 0), + SOC_DAPM_SINGLE("IN1 Switch", M98095_050_MIX_SPK_LEFT, 1, 1, 0), + SOC_DAPM_SINGLE("IN2 Switch", M98095_050_MIX_SPK_LEFT, 2, 1, 0), +}; + +/* Right speaker mixer switch */ +static const struct snd_kcontrol_new max98095_right_speaker_mixer_controls[] = { + SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 6, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 0, 1, 0), + SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0), + SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0), + SOC_DAPM_SINGLE("MIC1 Switch", M98095_051_MIX_SPK_RIGHT, 5, 1, 0), + SOC_DAPM_SINGLE("MIC2 Switch", M98095_051_MIX_SPK_RIGHT, 4, 1, 0), + SOC_DAPM_SINGLE("IN1 Switch", M98095_051_MIX_SPK_RIGHT, 1, 1, 0), + SOC_DAPM_SINGLE("IN2 Switch", M98095_051_MIX_SPK_RIGHT, 2, 1, 0), +}; + +/* Left headphone mixer switch */ +static const struct snd_kcontrol_new max98095_left_hp_mixer_controls[] = { + SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04C_MIX_HP_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04C_MIX_HP_LEFT, 5, 1, 0), + SOC_DAPM_SINGLE("MIC1 Switch", M98095_04C_MIX_HP_LEFT, 3, 1, 0), + SOC_DAPM_SINGLE("MIC2 Switch", M98095_04C_MIX_HP_LEFT, 4, 1, 0), + SOC_DAPM_SINGLE("IN1 Switch", M98095_04C_MIX_HP_LEFT, 1, 1, 0), + SOC_DAPM_SINGLE("IN2 Switch", M98095_04C_MIX_HP_LEFT, 2, 1, 0), +}; + +/* Right headphone mixer switch */ +static const struct snd_kcontrol_new max98095_right_hp_mixer_controls[] = { + SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 5, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 0, 1, 0), + SOC_DAPM_SINGLE("MIC1 Switch", M98095_04D_MIX_HP_RIGHT, 3, 1, 0), + SOC_DAPM_SINGLE("MIC2 Switch", M98095_04D_MIX_HP_RIGHT, 4, 1, 0), + SOC_DAPM_SINGLE("IN1 Switch", M98095_04D_MIX_HP_RIGHT, 1, 1, 0), + SOC_DAPM_SINGLE("IN2 Switch", M98095_04D_MIX_HP_RIGHT, 2, 1, 0), +}; + +/* Receiver earpiece mixer switch */ +static const struct snd_kcontrol_new max98095_mono_rcv_mixer_controls[] = { + SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04F_MIX_RCV, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04F_MIX_RCV, 5, 1, 0), + SOC_DAPM_SINGLE("MIC1 Switch", M98095_04F_MIX_RCV, 3, 1, 0), + SOC_DAPM_SINGLE("MIC2 Switch", M98095_04F_MIX_RCV, 4, 1, 0), + SOC_DAPM_SINGLE("IN1 Switch", M98095_04F_MIX_RCV, 1, 1, 0), + SOC_DAPM_SINGLE("IN2 Switch", M98095_04F_MIX_RCV, 2, 1, 0), +}; + +/* Left lineout mixer switch */ +static const struct snd_kcontrol_new max98095_left_lineout_mixer_controls[] = { + SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_053_MIX_LINEOUT1, 5, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_053_MIX_LINEOUT1, 0, 1, 0), + SOC_DAPM_SINGLE("MIC1 Switch", M98095_053_MIX_LINEOUT1, 3, 1, 0), + SOC_DAPM_SINGLE("MIC2 Switch", M98095_053_MIX_LINEOUT1, 4, 1, 0), + SOC_DAPM_SINGLE("IN1 Switch", M98095_053_MIX_LINEOUT1, 1, 1, 0), + SOC_DAPM_SINGLE("IN2 Switch", M98095_053_MIX_LINEOUT1, 2, 1, 0), +}; + +/* Right lineout mixer switch */ +static const struct snd_kcontrol_new max98095_right_lineout_mixer_controls[] = { + SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_054_MIX_LINEOUT2, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_054_MIX_LINEOUT2, 5, 1, 0), + SOC_DAPM_SINGLE("MIC1 Switch", M98095_054_MIX_LINEOUT2, 3, 1, 0), + SOC_DAPM_SINGLE("MIC2 Switch", M98095_054_MIX_LINEOUT2, 4, 1, 0), + SOC_DAPM_SINGLE("IN1 Switch", M98095_054_MIX_LINEOUT2, 1, 1, 0), + SOC_DAPM_SINGLE("IN2 Switch", M98095_054_MIX_LINEOUT2, 2, 1, 0), +}; + +/* Left ADC mixer switch */ +static const struct snd_kcontrol_new max98095_left_ADC_mixer_controls[] = { + SOC_DAPM_SINGLE("MIC1 Switch", M98095_04A_MIX_ADC_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("MIC2 Switch", M98095_04A_MIX_ADC_LEFT, 6, 1, 0), + SOC_DAPM_SINGLE("IN1 Switch", M98095_04A_MIX_ADC_LEFT, 3, 1, 0), + SOC_DAPM_SINGLE("IN2 Switch", M98095_04A_MIX_ADC_LEFT, 2, 1, 0), +}; + +/* Right ADC mixer switch */ +static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = { + SOC_DAPM_SINGLE("MIC1 Switch", M98095_04B_MIX_ADC_RIGHT, 7, 1, 0), + SOC_DAPM_SINGLE("MIC2 Switch", M98095_04B_MIX_ADC_RIGHT, 6, 1, 0), + SOC_DAPM_SINGLE("IN1 Switch", M98095_04B_MIX_ADC_RIGHT, 3, 1, 0), + SOC_DAPM_SINGLE("IN2 Switch", M98095_04B_MIX_ADC_RIGHT, 2, 1, 0), +}; + +static int max98095_mic_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (w->reg == M98095_05F_LVL_MIC1) { + snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK, + (1+max98095->mic1pre)<<M98095_MICPRE_SHIFT); + } else { + snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK, + (1+max98095->mic2pre)<<M98095_MICPRE_SHIFT); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * The line inputs are stereo inputs with the left and right + * channels sharing a common PGA power control signal. + */ +static int max98095_line_pga(struct snd_soc_dapm_widget *w, + int event, u8 channel) +{ + struct snd_soc_codec *codec = w->codec; + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + u8 *state; + + BUG_ON(!((channel == 1) || (channel == 2))); + + state = &max98095->lin_state; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + *state |= channel; + snd_soc_update_bits(codec, w->reg, + (1 << w->shift), (1 << w->shift)); + break; + case SND_SOC_DAPM_POST_PMD: + *state &= ~channel; + if (*state == 0) { + snd_soc_update_bits(codec, w->reg, + (1 << w->shift), 0); + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int max98095_pga_in1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + return max98095_line_pga(w, event, 1); +} + +static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + return max98095_line_pga(w, event, 2); +} + +/* + * The stereo line out mixer outputs to two stereo line outs. + * The 2nd pair has a separate set of enables. + */ +static int max98095_lineout_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, w->reg, + (1 << (w->shift+2)), (1 << (w->shift+2))); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, w->reg, + (1 << (w->shift+2)), 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dapm_widget max98095_dapm_widgets[] = { + + SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98095_090_PWR_EN_IN, 0, 0), + SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98095_090_PWR_EN_IN, 1, 0), + + SND_SOC_DAPM_DAC("DACL1", "HiFi Playback", + M98095_091_PWR_EN_OUT, 0, 0), + SND_SOC_DAPM_DAC("DACR1", "HiFi Playback", + M98095_091_PWR_EN_OUT, 1, 0), + SND_SOC_DAPM_DAC("DACM2", "Aux Playback", + M98095_091_PWR_EN_OUT, 2, 0), + SND_SOC_DAPM_DAC("DACM3", "Voice Playback", + M98095_091_PWR_EN_OUT, 2, 0), + + SND_SOC_DAPM_PGA("HP Left Out", M98095_091_PWR_EN_OUT, + 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("HP Right Out", M98095_091_PWR_EN_OUT, + 7, 0, NULL, 0), + + SND_SOC_DAPM_PGA("SPK Left Out", M98095_091_PWR_EN_OUT, + 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("SPK Right Out", M98095_091_PWR_EN_OUT, + 5, 0, NULL, 0), + + SND_SOC_DAPM_PGA("RCV Mono Out", M98095_091_PWR_EN_OUT, + 3, 0, NULL, 0), + + SND_SOC_DAPM_PGA_E("LINE Left Out", M98095_092_PWR_EN_OUT, + 0, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("LINE Right Out", M98095_092_PWR_EN_OUT, + 1, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0, + &max98095_extmic_mux), + + SND_SOC_DAPM_MUX("Linein Mux", SND_SOC_NOPM, 0, 0, + &max98095_linein_mux), + + SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0, + &max98095_left_hp_mixer_controls[0], + ARRAY_SIZE(max98095_left_hp_mixer_controls)), + + SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0, + &max98095_right_hp_mixer_controls[0], + ARRAY_SIZE(max98095_right_hp_mixer_controls)), + + SND_SOC_DAPM_MIXER("Left Speaker Mixer", SND_SOC_NOPM, 0, 0, + &max98095_left_speaker_mixer_controls[0], + ARRAY_SIZE(max98095_left_speaker_mixer_controls)), + + SND_SOC_DAPM_MIXER("Right Speaker Mixer", SND_SOC_NOPM, 0, 0, + &max98095_right_speaker_mixer_controls[0], + ARRAY_SIZE(max98095_right_speaker_mixer_controls)), + + SND_SOC_DAPM_MIXER("Receiver Mixer", SND_SOC_NOPM, 0, 0, + &max98095_mono_rcv_mixer_controls[0], + ARRAY_SIZE(max98095_mono_rcv_mixer_controls)), + + SND_SOC_DAPM_MIXER("Left Lineout Mixer", SND_SOC_NOPM, 0, 0, + &max98095_left_lineout_mixer_controls[0], + ARRAY_SIZE(max98095_left_lineout_mixer_controls)), + + SND_SOC_DAPM_MIXER("Right Lineout Mixer", SND_SOC_NOPM, 0, 0, + &max98095_right_lineout_mixer_controls[0], + ARRAY_SIZE(max98095_right_lineout_mixer_controls)), + + SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0, + &max98095_left_ADC_mixer_controls[0], + ARRAY_SIZE(max98095_left_ADC_mixer_controls)), + + SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0, + &max98095_right_ADC_mixer_controls[0], + ARRAY_SIZE(max98095_right_ADC_mixer_controls)), + + SND_SOC_DAPM_PGA_E("MIC1 Input", M98095_05F_LVL_MIC1, + 5, 0, NULL, 0, max98095_mic_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_PGA_E("MIC2 Input", M98095_060_LVL_MIC2, + 5, 0, NULL, 0, max98095_mic_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_PGA_E("IN1 Input", M98095_090_PWR_EN_IN, + 7, 0, NULL, 0, max98095_pga_in1_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_PGA_E("IN2 Input", M98095_090_PWR_EN_IN, + 7, 0, NULL, 0, max98095_pga_in2_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MICBIAS("MICBIAS1", M98095_090_PWR_EN_IN, 2, 0), + SND_SOC_DAPM_MICBIAS("MICBIAS2", M98095_090_PWR_EN_IN, 3, 0), + + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), + SND_SOC_DAPM_OUTPUT("SPKL"), + SND_SOC_DAPM_OUTPUT("SPKR"), + SND_SOC_DAPM_OUTPUT("RCV"), + SND_SOC_DAPM_OUTPUT("OUT1"), + SND_SOC_DAPM_OUTPUT("OUT2"), + SND_SOC_DAPM_OUTPUT("OUT3"), + SND_SOC_DAPM_OUTPUT("OUT4"), + + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("INA1"), + SND_SOC_DAPM_INPUT("INA2"), + SND_SOC_DAPM_INPUT("INB1"), + SND_SOC_DAPM_INPUT("INB2"), +}; + +static const struct snd_soc_dapm_route max98095_audio_map[] = { + /* Left headphone output mixer */ + {"Left Headphone Mixer", "Left DAC1 Switch", "DACL1"}, + {"Left Headphone Mixer", "Right DAC1 Switch", "DACR1"}, + {"Left Headphone Mixer", "MIC1 Switch", "MIC1 Input"}, + {"Left Headphone Mixer", "MIC2 Switch", "MIC2 Input"}, + {"Left Headphone Mixer", "IN1 Switch", "IN1 Input"}, + {"Left Headphone Mixer", "IN2 Switch", "IN2 Input"}, + + /* Right headphone output mixer */ + {"Right Headphone Mixer", "Left DAC1 Switch", "DACL1"}, + {"Right Headphone Mixer", "Right DAC1 Switch", "DACR1"}, + {"Right Headphone Mixer", "MIC1 Switch", "MIC1 Input"}, + {"Right Headphone Mixer", "MIC2 Switch", "MIC2 Input"}, + {"Right Headphone Mixer", "IN1 Switch", "IN1 Input"}, + {"Right Headphone Mixer", "IN2 Switch", "IN2 Input"}, + + /* Left speaker output mixer */ + {"Left Speaker Mixer", "Left DAC1 Switch", "DACL1"}, + {"Left Speaker Mixer", "Right DAC1 Switch", "DACR1"}, + {"Left Speaker Mixer", "Mono DAC2 Switch", "DACM2"}, + {"Left Speaker Mixer", "Mono DAC3 Switch", "DACM3"}, + {"Left Speaker Mixer", "MIC1 Switch", "MIC1 Input"}, + {"Left Speaker Mixer", "MIC2 Switch", "MIC2 Input"}, + {"Left Speaker Mixer", "IN1 Switch", "IN1 Input"}, + {"Left Speaker Mixer", "IN2 Switch", "IN2 Input"}, + + /* Right speaker output mixer */ + {"Right Speaker Mixer", "Left DAC1 Switch", "DACL1"}, + {"Right Speaker Mixer", "Right DAC1 Switch", "DACR1"}, + {"Right Speaker Mixer", "Mono DAC2 Switch", "DACM2"}, + {"Right Speaker Mixer", "Mono DAC3 Switch", "DACM3"}, + {"Right Speaker Mixer", "MIC1 Switch", "MIC1 Input"}, + {"Right Speaker Mixer", "MIC2 Switch", "MIC2 Input"}, + {"Right Speaker Mixer", "IN1 Switch", "IN1 Input"}, + {"Right Speaker Mixer", "IN2 Switch", "IN2 Input"}, + + /* Earpiece/Receiver output mixer */ + {"Receiver Mixer", "Left DAC1 Switch", "DACL1"}, + {"Receiver Mixer", "Right DAC1 Switch", "DACR1"}, + {"Receiver Mixer", "MIC1 Switch", "MIC1 Input"}, + {"Receiver Mixer", "MIC2 Switch", "MIC2 Input"}, + {"Receiver Mixer", "IN1 Switch", "IN1 Input"}, + {"Receiver Mixer", "IN2 Switch", "IN2 Input"}, + + /* Left Lineout output mixer */ + {"Left Lineout Mixer", "Left DAC1 Switch", "DACL1"}, + {"Left Lineout Mixer", "Right DAC1 Switch", "DACR1"}, + {"Left Lineout Mixer", "MIC1 Switch", "MIC1 Input"}, + {"Left Lineout Mixer", "MIC2 Switch", "MIC2 Input"}, + {"Left Lineout Mixer", "IN1 Switch", "IN1 Input"}, + {"Left Lineout Mixer", "IN2 Switch", "IN2 Input"}, + + /* Right lineout output mixer */ + {"Right Lineout Mixer", "Left DAC1 Switch", "DACL1"}, + {"Right Lineout Mixer", "Right DAC1 Switch", "DACR1"}, + {"Right Lineout Mixer", "MIC1 Switch", "MIC1 Input"}, + {"Right Lineout Mixer", "MIC2 Switch", "MIC2 Input"}, + {"Right Lineout Mixer", "IN1 Switch", "IN1 Input"}, + {"Right Lineout Mixer", "IN2 Switch", "IN2 Input"}, + + {"HP Left Out", NULL, "Left Headphone Mixer"}, + {"HP Right Out", NULL, "Right Headphone Mixer"}, + {"SPK Left Out", NULL, "Left Speaker Mixer"}, + {"SPK Right Out", NULL, "Right Speaker Mixer"}, + {"RCV Mono Out", NULL, "Receiver Mixer"}, + {"LINE Left Out", NULL, "Left Lineout Mixer"}, + {"LINE Right Out", NULL, "Right Lineout Mixer"}, + + {"HPL", NULL, "HP Left Out"}, + {"HPR", NULL, "HP Right Out"}, + {"SPKL", NULL, "SPK Left Out"}, + {"SPKR", NULL, "SPK Right Out"}, + {"RCV", NULL, "RCV Mono Out"}, + {"OUT1", NULL, "LINE Left Out"}, + {"OUT2", NULL, "LINE Right Out"}, + {"OUT3", NULL, "LINE Left Out"}, + {"OUT4", NULL, "LINE Right Out"}, + + /* Left ADC input mixer */ + {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"}, + {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"}, + {"Left ADC Mixer", "IN1 Switch", "IN1 Input"}, + {"Left ADC Mixer", "IN2 Switch", "IN2 Input"}, + + /* Right ADC input mixer */ + {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"}, + {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"}, + {"Right ADC Mixer", "IN1 Switch", "IN1 Input"}, + {"Right ADC Mixer", "IN2 Switch", "IN2 Input"}, + + /* Inputs */ + {"ADCL", NULL, "Left ADC Mixer"}, + {"ADCR", NULL, "Right ADC Mixer"}, + + {"IN1 Input", NULL, "INA1"}, + {"IN2 Input", NULL, "INA2"}, + + {"MIC1 Input", NULL, "MIC1"}, + {"MIC2 Input", NULL, "MIC2"}, +}; + +static int max98095_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_add_controls(codec, max98095_snd_controls, + ARRAY_SIZE(max98095_snd_controls)); + + return 0; +} + +/* codec mclk clock divider coefficients */ +static const struct { + u32 rate; + u8 sr; +} rate_table[] = { + {8000, 0x01}, + {11025, 0x02}, + {16000, 0x03}, + {22050, 0x04}, + {24000, 0x05}, + {32000, 0x06}, + {44100, 0x07}, + {48000, 0x08}, + {88200, 0x09}, + {96000, 0x0A}, +}; + +static int rate_value(int rate, u8 *value) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rate_table); i++) { + if (rate_table[i].rate >= rate) { + *value = rate_table[i].sr; + return 0; + } + } + *value = rate_table[0].sr; + return -EINVAL; +} + +static int max98095_dai1_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 max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_cdata *cdata; + unsigned long long ni; + unsigned int rate; + u8 regval; + + cdata = &max98095->dai[0]; + + rate = params_rate(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT, + M98095_DAI_WS, 0); + break; + case SNDRV_PCM_FORMAT_S24_LE: + snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT, + M98095_DAI_WS, M98095_DAI_WS); + break; + default: + return -EINVAL; + } + + if (rate_value(rate, ®val)) + return -EINVAL; + + snd_soc_update_bits(codec, M98095_027_DAI1_CLKMODE, + M98095_CLKMODE_MASK, regval); + cdata->rate = rate; + + /* Configure NI when operating as master */ + if (snd_soc_read(codec, M98095_02A_DAI1_FORMAT) & M98095_DAI_MAS) { + if (max98095->sysclk == 0) { + dev_err(codec->dev, "Invalid system clock frequency\n"); + return -EINVAL; + } + ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL) + * (unsigned long long int)rate; + do_div(ni, (unsigned long long int)max98095->sysclk); + snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI, + (ni >> 8) & 0x7F); + snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO, + ni & 0xFF); + } + + /* Update sample rate mode */ + if (rate < 50000) + snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS, + M98095_DAI_DHF, 0); + else + snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS, + M98095_DAI_DHF, M98095_DAI_DHF); + + return 0; +} + +static int max98095_dai2_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 max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_cdata *cdata; + unsigned long long ni; + unsigned int rate; + u8 regval; + + cdata = &max98095->dai[1]; + + rate = params_rate(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT, + M98095_DAI_WS, 0); + break; + case SNDRV_PCM_FORMAT_S24_LE: + snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT, + M98095_DAI_WS, M98095_DAI_WS); + break; + default: + return -EINVAL; + } + + if (rate_value(rate, ®val)) + return -EINVAL; + + snd_soc_update_bits(codec, M98095_031_DAI2_CLKMODE, + M98095_CLKMODE_MASK, regval); + cdata->rate = rate; + + /* Configure NI when operating as master */ + if (snd_soc_read(codec, M98095_034_DAI2_FORMAT) & M98095_DAI_MAS) { + if (max98095->sysclk == 0) { + dev_err(codec->dev, "Invalid system clock frequency\n"); + return -EINVAL; + } + ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL) + * (unsigned long long int)rate; + do_div(ni, (unsigned long long int)max98095->sysclk); + snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI, + (ni >> 8) & 0x7F); + snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO, + ni & 0xFF); + } + + /* Update sample rate mode */ + if (rate < 50000) + snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS, + M98095_DAI_DHF, 0); + else + snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS, + M98095_DAI_DHF, M98095_DAI_DHF); + + return 0; +} + +static int max98095_dai3_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 max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_cdata *cdata; + unsigned long long ni; + unsigned int rate; + u8 regval; + + cdata = &max98095->dai[2]; + + rate = params_rate(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT, + M98095_DAI_WS, 0); + break; + case SNDRV_PCM_FORMAT_S24_LE: + snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT, + M98095_DAI_WS, M98095_DAI_WS); + break; + default: + return -EINVAL; + } + + if (rate_value(rate, ®val)) + return -EINVAL; + + snd_soc_update_bits(codec, M98095_03B_DAI3_CLKMODE, + M98095_CLKMODE_MASK, regval); + cdata->rate = rate; + + /* Configure NI when operating as master */ + if (snd_soc_read(codec, M98095_03E_DAI3_FORMAT) & M98095_DAI_MAS) { + if (max98095->sysclk == 0) { + dev_err(codec->dev, "Invalid system clock frequency\n"); + return -EINVAL; + } + ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL) + * (unsigned long long int)rate; + do_div(ni, (unsigned long long int)max98095->sysclk); + snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI, + (ni >> 8) & 0x7F); + snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO, + ni & 0xFF); + } + + /* Update sample rate mode */ + if (rate < 50000) + snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS, + M98095_DAI_DHF, 0); + else + snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS, + M98095_DAI_DHF, M98095_DAI_DHF); + + return 0; +} + +static int max98095_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + + /* Requested clock frequency is already setup */ + if (freq == max98095->sysclk) + return 0; + + max98095->sysclk = freq; /* remember current sysclk */ + + /* Setup clocks for slave mode, and using the PLL + * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) + * 0x02 (when master clk is 20MHz to 40MHz).. + * 0x03 (when master clk is 40MHz to 60MHz).. + */ + if ((freq >= 10000000) && (freq < 20000000)) { + snd_soc_write(codec, M98095_026_SYS_CLK, 0x10); + } else if ((freq >= 20000000) && (freq < 40000000)) { + snd_soc_write(codec, M98095_026_SYS_CLK, 0x20); + } else if ((freq >= 40000000) && (freq < 60000000)) { + snd_soc_write(codec, M98095_026_SYS_CLK, 0x30); + } else { + dev_err(codec->dev, "Invalid master clock frequency\n"); + return -EINVAL; + } + + dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq); + + max98095->sysclk = freq; + return 0; +} + +static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_cdata *cdata; + u8 regval = 0; + + cdata = &max98095->dai[0]; + + if (fmt != cdata->fmt) { + cdata->fmt = fmt; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* Slave mode PLL */ + snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI, + 0x80); + snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO, + 0x00); + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* Set to master mode */ + regval |= M98095_DAI_MAS; + break; + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + default: + dev_err(codec->dev, "Clock mode unsupported"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + regval |= M98095_DAI_DLY; + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + regval |= M98095_DAI_WCI; + break; + case SND_SOC_DAIFMT_IB_NF: + regval |= M98095_DAI_BCI; + break; + case SND_SOC_DAIFMT_IB_IF: + regval |= M98095_DAI_BCI|M98095_DAI_WCI; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT, + M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI | + M98095_DAI_WCI, regval); + + snd_soc_write(codec, M98095_02B_DAI1_CLOCK, M98095_DAI_BSEL64); + } + + return 0; +} + +static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_cdata *cdata; + u8 regval = 0; + + cdata = &max98095->dai[1]; + + if (fmt != cdata->fmt) { + cdata->fmt = fmt; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* Slave mode PLL */ + snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI, + 0x80); + snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO, + 0x00); + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* Set to master mode */ + regval |= M98095_DAI_MAS; + break; + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + default: + dev_err(codec->dev, "Clock mode unsupported"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + regval |= M98095_DAI_DLY; + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + regval |= M98095_DAI_WCI; + break; + case SND_SOC_DAIFMT_IB_NF: + regval |= M98095_DAI_BCI; + break; + case SND_SOC_DAIFMT_IB_IF: + regval |= M98095_DAI_BCI|M98095_DAI_WCI; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT, + M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI | + M98095_DAI_WCI, regval); + + snd_soc_write(codec, M98095_035_DAI2_CLOCK, + M98095_DAI_BSEL64); + } + + return 0; +} + +static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_cdata *cdata; + u8 regval = 0; + + cdata = &max98095->dai[2]; + + if (fmt != cdata->fmt) { + cdata->fmt = fmt; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* Slave mode PLL */ + snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI, + 0x80); + snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO, + 0x00); + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* Set to master mode */ + regval |= M98095_DAI_MAS; + break; + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + default: + dev_err(codec->dev, "Clock mode unsupported"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + regval |= M98095_DAI_DLY; + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + regval |= M98095_DAI_WCI; + break; + case SND_SOC_DAIFMT_IB_NF: + regval |= M98095_DAI_BCI; + break; + case SND_SOC_DAIFMT_IB_IF: + regval |= M98095_DAI_BCI|M98095_DAI_WCI; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT, + M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI | + M98095_DAI_WCI, regval); + + snd_soc_write(codec, M98095_03F_DAI3_CLOCK, + M98095_DAI_BSEL64); + } + + return 0; +} + +static int max98095_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + ret = snd_soc_cache_sync(codec); + + if (ret != 0) { + dev_err(codec->dev, "Failed to sync cache: %d\n", ret); + return ret; + } + } + + snd_soc_update_bits(codec, M98095_090_PWR_EN_IN, + M98095_MBEN, M98095_MBEN); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, M98095_090_PWR_EN_IN, + M98095_MBEN, 0); + codec->cache_sync = 1; + break; + } + codec->dapm.bias_level = level; + return 0; +} + +#define MAX98095_RATES SNDRV_PCM_RATE_8000_96000 +#define MAX98095_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops max98095_dai1_ops = { + .set_sysclk = max98095_dai_set_sysclk, + .set_fmt = max98095_dai1_set_fmt, + .hw_params = max98095_dai1_hw_params, +}; + +static struct snd_soc_dai_ops max98095_dai2_ops = { + .set_sysclk = max98095_dai_set_sysclk, + .set_fmt = max98095_dai2_set_fmt, + .hw_params = max98095_dai2_hw_params, +}; + +static struct snd_soc_dai_ops max98095_dai3_ops = { + .set_sysclk = max98095_dai_set_sysclk, + .set_fmt = max98095_dai3_set_fmt, + .hw_params = max98095_dai3_hw_params, +}; + +static struct snd_soc_dai_driver max98095_dai[] = { +{ + .name = "HiFi", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98095_RATES, + .formats = MAX98095_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98095_RATES, + .formats = MAX98095_FORMATS, + }, + .ops = &max98095_dai1_ops, +}, +{ + .name = "Aux", + .playback = { + .stream_name = "Aux Playback", + .channels_min = 1, + .channels_max = 1, + .rates = MAX98095_RATES, + .formats = MAX98095_FORMATS, + }, + .ops = &max98095_dai2_ops, +}, +{ + .name = "Voice", + .playback = { + .stream_name = "Voice Playback", + .channels_min = 1, + .channels_max = 1, + .rates = MAX98095_RATES, + .formats = MAX98095_FORMATS, + }, + .ops = &max98095_dai3_ops, +} + +}; + +static int max98095_get_eq_channel(const char *name) +{ + if (strcmp(name, "EQ1 Mode") == 0) + return 0; + if (strcmp(name, "EQ2 Mode") == 0) + return 1; + return -EINVAL; +} + +static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_pdata *pdata = max98095->pdata; + int channel = max98095_get_eq_channel(kcontrol->id.name); + struct max98095_cdata *cdata; + int sel = ucontrol->value.integer.value[0]; + struct max98095_eq_cfg *coef_set; + int fs, best, best_val, i; + int regmask, regsave; + + BUG_ON(channel > 1); + + if (!pdata || !max98095->eq_textcnt) + return 0; + + if (sel >= pdata->eq_cfgcnt) + return -EINVAL; + + cdata = &max98095->dai[channel]; + cdata->eq_sel = sel; + fs = cdata->rate; + + /* Find the selected configuration with nearest sample rate */ + best = 0; + best_val = INT_MAX; + for (i = 0; i < pdata->eq_cfgcnt; i++) { + if (strcmp(pdata->eq_cfg[i].name, max98095->eq_texts[sel]) == 0 && + abs(pdata->eq_cfg[i].rate - fs) < best_val) { + best = i; + best_val = abs(pdata->eq_cfg[i].rate - fs); + } + } + + dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n", + pdata->eq_cfg[best].name, + pdata->eq_cfg[best].rate, fs); + + coef_set = &pdata->eq_cfg[best]; + + regmask = (channel == 0) ? M98095_EQ1EN : M98095_EQ2EN; + + /* Disable filter while configuring, and save current on/off state */ + regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); + snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); + + mutex_lock(&codec->mutex); + snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); + m98095_eq_band(codec, channel, 0, coef_set->band1); + m98095_eq_band(codec, channel, 1, coef_set->band2); + m98095_eq_band(codec, channel, 2, coef_set->band3); + m98095_eq_band(codec, channel, 3, coef_set->band4); + m98095_eq_band(codec, channel, 4, coef_set->band5); + snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); + mutex_unlock(&codec->mutex); + + /* Restore the original on/off state */ + snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); + return 0; +} + +static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + int channel = max98095_get_eq_channel(kcontrol->id.name); + struct max98095_cdata *cdata; + + cdata = &max98095->dai[channel]; + ucontrol->value.enumerated.item[0] = cdata->eq_sel; + + return 0; +} + +static void max98095_handle_eq_pdata(struct snd_soc_codec *codec) +{ + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_pdata *pdata = max98095->pdata; + struct max98095_eq_cfg *cfg; + unsigned int cfgcnt; + int i, j; + const char **t; + int ret; + + struct snd_kcontrol_new controls[] = { + SOC_ENUM_EXT("EQ1 Mode", + max98095->eq_enum, + max98095_get_eq_enum, + max98095_put_eq_enum), + SOC_ENUM_EXT("EQ2 Mode", + max98095->eq_enum, + max98095_get_eq_enum, + max98095_put_eq_enum), + }; + + cfg = pdata->eq_cfg; + cfgcnt = pdata->eq_cfgcnt; + + /* Setup an array of texts for the equalizer enum. + * This is based on Mark Brown's equalizer driver code. + */ + max98095->eq_textcnt = 0; + max98095->eq_texts = NULL; + for (i = 0; i < cfgcnt; i++) { + for (j = 0; j < max98095->eq_textcnt; j++) { + if (strcmp(cfg[i].name, max98095->eq_texts[j]) == 0) + break; + } + + if (j != max98095->eq_textcnt) + continue; + + /* Expand the array */ + t = krealloc(max98095->eq_texts, + sizeof(char *) * (max98095->eq_textcnt + 1), + GFP_KERNEL); + if (t == NULL) + continue; + + /* Store the new entry */ + t[max98095->eq_textcnt] = cfg[i].name; + max98095->eq_textcnt++; + max98095->eq_texts = t; + } + + /* Now point the soc_enum to .texts array items */ + max98095->eq_enum.texts = max98095->eq_texts; + max98095->eq_enum.max = max98095->eq_textcnt; + + ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls)); + if (ret != 0) + dev_err(codec->dev, "Failed to add EQ control: %d\n", ret); +} + +static int max98095_get_bq_channel(const char *name) +{ + if (strcmp(name, "Biquad1 Mode") == 0) + return 0; + if (strcmp(name, "Biquad2 Mode") == 0) + return 1; + return -EINVAL; +} + +static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_pdata *pdata = max98095->pdata; + int channel = max98095_get_bq_channel(kcontrol->id.name); + struct max98095_cdata *cdata; + int sel = ucontrol->value.integer.value[0]; + struct max98095_biquad_cfg *coef_set; + int fs, best, best_val, i; + int regmask, regsave; + + BUG_ON(channel > 1); + + if (!pdata || !max98095->bq_textcnt) + return 0; + + if (sel >= pdata->bq_cfgcnt) + return -EINVAL; + + cdata = &max98095->dai[channel]; + cdata->bq_sel = sel; + fs = cdata->rate; + + /* Find the selected configuration with nearest sample rate */ + best = 0; + best_val = INT_MAX; + for (i = 0; i < pdata->bq_cfgcnt; i++) { + if (strcmp(pdata->bq_cfg[i].name, max98095->bq_texts[sel]) == 0 && + abs(pdata->bq_cfg[i].rate - fs) < best_val) { + best = i; + best_val = abs(pdata->bq_cfg[i].rate - fs); + } + } + + dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n", + pdata->bq_cfg[best].name, + pdata->bq_cfg[best].rate, fs); + + coef_set = &pdata->bq_cfg[best]; + + regmask = (channel == 0) ? M98095_BQ1EN : M98095_BQ2EN; + + /* Disable filter while configuring, and save current on/off state */ + regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); + snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); + + mutex_lock(&codec->mutex); + snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); + m98095_biquad_band(codec, channel, 0, coef_set->band1); + m98095_biquad_band(codec, channel, 1, coef_set->band2); + snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); + mutex_unlock(&codec->mutex); + + /* Restore the original on/off state */ + snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); + return 0; +} + +static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + int channel = max98095_get_bq_channel(kcontrol->id.name); + struct max98095_cdata *cdata; + + cdata = &max98095->dai[channel]; + ucontrol->value.enumerated.item[0] = cdata->bq_sel; + + return 0; +} + +static void max98095_handle_bq_pdata(struct snd_soc_codec *codec) +{ + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_pdata *pdata = max98095->pdata; + struct max98095_biquad_cfg *cfg; + unsigned int cfgcnt; + int i, j; + const char **t; + int ret; + + struct snd_kcontrol_new controls[] = { + SOC_ENUM_EXT("Biquad1 Mode", + max98095->bq_enum, + max98095_get_bq_enum, + max98095_put_bq_enum), + SOC_ENUM_EXT("Biquad2 Mode", + max98095->bq_enum, + max98095_get_bq_enum, + max98095_put_bq_enum), + }; + + cfg = pdata->bq_cfg; + cfgcnt = pdata->bq_cfgcnt; + + /* Setup an array of texts for the biquad enum. + * This is based on Mark Brown's equalizer driver code. + */ + max98095->bq_textcnt = 0; + max98095->bq_texts = NULL; + for (i = 0; i < cfgcnt; i++) { + for (j = 0; j < max98095->bq_textcnt; j++) { + if (strcmp(cfg[i].name, max98095->bq_texts[j]) == 0) + break; + } + + if (j != max98095->bq_textcnt) + continue; + + /* Expand the array */ + t = krealloc(max98095->bq_texts, + sizeof(char *) * (max98095->bq_textcnt + 1), + GFP_KERNEL); + if (t == NULL) + continue; + + /* Store the new entry */ + t[max98095->bq_textcnt] = cfg[i].name; + max98095->bq_textcnt++; + max98095->bq_texts = t; + } + + /* Now point the soc_enum to .texts array items */ + max98095->bq_enum.texts = max98095->bq_texts; + max98095->bq_enum.max = max98095->bq_textcnt; + + ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls)); + if (ret != 0) + dev_err(codec->dev, "Failed to add Biquad control: %d\n", ret); +} + +static void max98095_handle_pdata(struct snd_soc_codec *codec) +{ + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_pdata *pdata = max98095->pdata; + u8 regval = 0; + + if (!pdata) { + dev_dbg(codec->dev, "No platform data\n"); + return; + } + + /* Configure mic for analog/digital mic mode */ + if (pdata->digmic_left_mode) + regval |= M98095_DIGMIC_L; + + if (pdata->digmic_right_mode) + regval |= M98095_DIGMIC_R; + + snd_soc_write(codec, M98095_087_CFG_MIC, regval); + + /* Configure equalizers */ + if (pdata->eq_cfgcnt) + max98095_handle_eq_pdata(codec); + + /* Configure bi-quad filters */ + if (pdata->bq_cfgcnt) + max98095_handle_bq_pdata(codec); +} + +#ifdef CONFIG_PM +static int max98095_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int max98095_resume(struct snd_soc_codec *codec) +{ + max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +#else +#define max98095_suspend NULL +#define max98095_resume NULL +#endif + +static int max98095_reset(struct snd_soc_codec *codec) +{ + int i, ret; + + /* Gracefully reset the DSP core and the codec hardware + * in a proper sequence */ + ret = snd_soc_write(codec, M98095_00F_HOST_CFG, 0); + if (ret < 0) { + dev_err(codec->dev, "Failed to reset DSP: %d\n", ret); + return ret; + } + + ret = snd_soc_write(codec, M98095_097_PWR_SYS, 0); + if (ret < 0) { + dev_err(codec->dev, "Failed to reset codec: %d\n", ret); + return ret; + } + + /* Reset to hardware default for registers, as there is not + * a soft reset hardware control register */ + for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) { + ret = snd_soc_write(codec, i, max98095_reg_def[i]); + if (ret < 0) { + dev_err(codec->dev, "Failed to reset: %d\n", ret); + return ret; + } + } + + return ret; +} + +static int max98095_probe(struct snd_soc_codec *codec) +{ + struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); + struct max98095_cdata *cdata; + int ret = 0; + + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + /* reset the codec, the DSP core, and disable all interrupts */ + max98095_reset(codec); + + /* initialize private data */ + + max98095->sysclk = (unsigned)-1; + max98095->eq_textcnt = 0; + max98095->bq_textcnt = 0; + + cdata = &max98095->dai[0]; + cdata->rate = (unsigned)-1; + cdata->fmt = (unsigned)-1; + cdata->eq_sel = 0; + cdata->bq_sel = 0; + + cdata = &max98095->dai[1]; + cdata->rate = (unsigned)-1; + cdata->fmt = (unsigned)-1; + cdata->eq_sel = 0; + cdata->bq_sel = 0; + + cdata = &max98095->dai[2]; + cdata->rate = (unsigned)-1; + cdata->fmt = (unsigned)-1; + cdata->eq_sel = 0; + cdata->bq_sel = 0; + + max98095->lin_state = 0; + max98095->mic1pre = 0; + max98095->mic2pre = 0; + + ret = snd_soc_read(codec, M98095_0FF_REV_ID); + if (ret < 0) { + dev_err(codec->dev, "Failed to read device revision: %d\n", + ret); + goto err_access; + } + dev_info(codec->dev, "revision %c\n", ret + 'A'); + + snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); + + /* initialize registers cache to hardware default */ + max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + snd_soc_write(codec, M98095_048_MIX_DAC_LR, + M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR); + + snd_soc_write(codec, M98095_049_MIX_DAC_M, + M98095_DAI2M_TO_DACM|M98095_DAI3M_TO_DACM); + + snd_soc_write(codec, M98095_092_PWR_EN_OUT, M98095_SPK_SPREADSPECTRUM); + snd_soc_write(codec, M98095_045_CFG_DSP, M98095_DSPNORMAL); + snd_soc_write(codec, M98095_04E_CFG_HP, M98095_HPNORMAL); + + snd_soc_write(codec, M98095_02C_DAI1_IOCFG, + M98095_S1NORMAL|M98095_SDATA); + + snd_soc_write(codec, M98095_036_DAI2_IOCFG, + M98095_S2NORMAL|M98095_SDATA); + + snd_soc_write(codec, M98095_040_DAI3_IOCFG, + M98095_S3NORMAL|M98095_SDATA); + + max98095_handle_pdata(codec); + + /* take the codec out of the shut down */ + snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN, + M98095_SHDNRUN); + + max98095_add_widgets(codec); + +err_access: + return ret; +} + +static int max98095_remove(struct snd_soc_codec *codec) +{ + max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_max98095 = { + .probe = max98095_probe, + .remove = max98095_remove, + .suspend = max98095_suspend, + .resume = max98095_resume, + .set_bias_level = max98095_set_bias_level, + .reg_cache_size = ARRAY_SIZE(max98095_reg_def), + .reg_word_size = sizeof(u8), + .reg_cache_default = max98095_reg_def, + .readable_register = max98095_readable, + .volatile_register = max98095_volatile, + .dapm_widgets = max98095_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets), + .dapm_routes = max98095_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98095_audio_map), +}; + +static int max98095_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max98095_priv *max98095; + int ret; + + max98095 = kzalloc(sizeof(struct max98095_priv), GFP_KERNEL); + if (max98095 == NULL) + return -ENOMEM; + + max98095->devtype = id->driver_data; + i2c_set_clientdata(i2c, max98095); + max98095->control_data = i2c; + max98095->pdata = i2c->dev.platform_data; + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_max98095, &max98095_dai[0], 3); + if (ret < 0) + kfree(max98095); + return ret; +} + +static int __devexit max98095_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static const struct i2c_device_id max98095_i2c_id[] = { + { "max98095", MAX98095 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98095_i2c_id); + +static struct i2c_driver max98095_i2c_driver = { + .driver = { + .name = "max98095", + .owner = THIS_MODULE, + }, + .probe = max98095_i2c_probe, + .remove = __devexit_p(max98095_i2c_remove), + .id_table = max98095_i2c_id, +}; + +static int __init max98095_init(void) +{ + int ret; + + ret = i2c_add_driver(&max98095_i2c_driver); + if (ret) + pr_err("Failed to register max98095 I2C driver: %d\n", ret); + + return ret; +} +module_init(max98095_init); + +static void __exit max98095_exit(void) +{ + i2c_del_driver(&max98095_i2c_driver); +} +module_exit(max98095_exit); + +MODULE_DESCRIPTION("ALSA SoC MAX98095 driver"); +MODULE_AUTHOR("Peter Hsiang"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98095.h b/sound/soc/codecs/max98095.h new file mode 100644 index 000000000000..891584a0eb03 --- /dev/null +++ b/sound/soc/codecs/max98095.h @@ -0,0 +1,299 @@ +/* + * max98095.h -- MAX98095 ALSA SoC Audio driver + * + * Copyright 2011 Maxim Integrated Products + * + * 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 _MAX98095_H +#define _MAX98095_H + +/* + * MAX98095 Registers Definition + */ + +#define M98095_000_HOST_DATA 0x00 +#define M98095_001_HOST_INT_STS 0x01 +#define M98095_002_HOST_RSP_STS 0x02 +#define M98095_003_HOST_CMD_STS 0x03 +#define M98095_004_CODEC_STS 0x04 +#define M98095_005_DAI1_ALC_STS 0x05 +#define M98095_006_DAI2_ALC_STS 0x06 +#define M98095_007_JACK_AUTO_STS 0x07 +#define M98095_008_JACK_MANUAL_STS 0x08 +#define M98095_009_JACK_VBAT_STS 0x09 +#define M98095_00A_ACC_ADC_STS 0x0A +#define M98095_00B_MIC_NG_AGC_STS 0x0B +#define M98095_00C_SPK_L_VOLT_STS 0x0C +#define M98095_00D_SPK_R_VOLT_STS 0x0D +#define M98095_00E_TEMP_SENSOR_STS 0x0E +#define M98095_00F_HOST_CFG 0x0F +#define M98095_010_HOST_INT_CFG 0x10 +#define M98095_011_HOST_INT_EN 0x11 +#define M98095_012_CODEC_INT_EN 0x12 +#define M98095_013_JACK_INT_EN 0x13 +#define M98095_014_JACK_INT_EN 0x14 +#define M98095_015_DEC 0x15 +#define M98095_016_RESERVED 0x16 +#define M98095_017_RESERVED 0x17 +#define M98095_018_KEYCODE3 0x18 +#define M98095_019_KEYCODE2 0x19 +#define M98095_01A_KEYCODE1 0x1A +#define M98095_01B_KEYCODE0 0x1B +#define M98095_01C_OEMCODE1 0x1C +#define M98095_01D_OEMCODE0 0x1D +#define M98095_01E_XCFG1 0x1E +#define M98095_01F_XCFG2 0x1F +#define M98095_020_XCFG3 0x20 +#define M98095_021_XCFG4 0x21 +#define M98095_022_XCFG5 0x22 +#define M98095_023_XCFG6 0x23 +#define M98095_024_XGPIO 0x24 +#define M98095_025_XCLKCFG 0x25 +#define M98095_026_SYS_CLK 0x26 +#define M98095_027_DAI1_CLKMODE 0x27 +#define M98095_028_DAI1_CLKCFG_HI 0x28 +#define M98095_029_DAI1_CLKCFG_LO 0x29 +#define M98095_02A_DAI1_FORMAT 0x2A +#define M98095_02B_DAI1_CLOCK 0x2B +#define M98095_02C_DAI1_IOCFG 0x2C +#define M98095_02D_DAI1_TDM 0x2D +#define M98095_02E_DAI1_FILTERS 0x2E +#define M98095_02F_DAI1_LVL1 0x2F +#define M98095_030_DAI1_LVL2 0x30 +#define M98095_031_DAI2_CLKMODE 0x31 +#define M98095_032_DAI2_CLKCFG_HI 0x32 +#define M98095_033_DAI2_CLKCFG_LO 0x33 +#define M98095_034_DAI2_FORMAT 0x34 +#define M98095_035_DAI2_CLOCK 0x35 +#define M98095_036_DAI2_IOCFG 0x36 +#define M98095_037_DAI2_TDM 0x37 +#define M98095_038_DAI2_FILTERS 0x38 +#define M98095_039_DAI2_LVL1 0x39 +#define M98095_03A_DAI2_LVL2 0x3A +#define M98095_03B_DAI3_CLKMODE 0x3B +#define M98095_03C_DAI3_CLKCFG_HI 0x3C +#define M98095_03D_DAI3_CLKCFG_LO 0x3D +#define M98095_03E_DAI3_FORMAT 0x3E +#define M98095_03F_DAI3_CLOCK 0x3F +#define M98095_040_DAI3_IOCFG 0x40 +#define M98095_041_DAI3_TDM 0x41 +#define M98095_042_DAI3_FILTERS 0x42 +#define M98095_043_DAI3_LVL1 0x43 +#define M98095_044_DAI3_LVL2 0x44 +#define M98095_045_CFG_DSP 0x45 +#define M98095_046_DAC_CTRL1 0x46 +#define M98095_047_DAC_CTRL2 0x47 +#define M98095_048_MIX_DAC_LR 0x48 +#define M98095_049_MIX_DAC_M 0x49 +#define M98095_04A_MIX_ADC_LEFT 0x4A +#define M98095_04B_MIX_ADC_RIGHT 0x4B +#define M98095_04C_MIX_HP_LEFT 0x4C +#define M98095_04D_MIX_HP_RIGHT 0x4D +#define M98095_04E_CFG_HP 0x4E +#define M98095_04F_MIX_RCV 0x4F +#define M98095_050_MIX_SPK_LEFT 0x50 +#define M98095_051_MIX_SPK_RIGHT 0x51 +#define M98095_052_MIX_SPK_CFG 0x52 +#define M98095_053_MIX_LINEOUT1 0x53 +#define M98095_054_MIX_LINEOUT2 0x54 +#define M98095_055_MIX_LINEOUT_CFG 0x55 +#define M98095_056_LVL_SIDETONE_DAI12 0x56 +#define M98095_057_LVL_SIDETONE_DAI3 0x57 +#define M98095_058_LVL_DAI1_PLAY 0x58 +#define M98095_059_LVL_DAI1_EQ 0x59 +#define M98095_05A_LVL_DAI2_PLAY 0x5A +#define M98095_05B_LVL_DAI2_EQ 0x5B +#define M98095_05C_LVL_DAI3_PLAY 0x5C +#define M98095_05D_LVL_ADC_L 0x5D +#define M98095_05E_LVL_ADC_R 0x5E +#define M98095_05F_LVL_MIC1 0x5F +#define M98095_060_LVL_MIC2 0x60 +#define M98095_061_LVL_LINEIN 0x61 +#define M98095_062_LVL_LINEOUT1 0x62 +#define M98095_063_LVL_LINEOUT2 0x63 +#define M98095_064_LVL_HP_L 0x64 +#define M98095_065_LVL_HP_R 0x65 +#define M98095_066_LVL_RCV 0x66 +#define M98095_067_LVL_SPK_L 0x67 +#define M98095_068_LVL_SPK_R 0x68 +#define M98095_069_MICAGC_CFG 0x69 +#define M98095_06A_MICAGC_THRESH 0x6A +#define M98095_06B_SPK_NOISEGATE 0x6B +#define M98095_06C_DAI1_ALC1_TIME 0x6C +#define M98095_06D_DAI1_ALC1_COMP 0x6D +#define M98095_06E_DAI1_ALC1_EXPN 0x6E +#define M98095_06F_DAI1_ALC1_GAIN 0x6F +#define M98095_070_DAI1_ALC2_TIME 0x70 +#define M98095_071_DAI1_ALC2_COMP 0x71 +#define M98095_072_DAI1_ALC2_EXPN 0x72 +#define M98095_073_DAI1_ALC2_GAIN 0x73 +#define M98095_074_DAI1_ALC3_TIME 0x74 +#define M98095_075_DAI1_ALC3_COMP 0x75 +#define M98095_076_DAI1_ALC3_EXPN 0x76 +#define M98095_077_DAI1_ALC3_GAIN 0x77 +#define M98095_078_DAI2_ALC1_TIME 0x78 +#define M98095_079_DAI2_ALC1_COMP 0x79 +#define M98095_07A_DAI2_ALC1_EXPN 0x7A +#define M98095_07B_DAI2_ALC1_GAIN 0x7B +#define M98095_07C_DAI2_ALC2_TIME 0x7C +#define M98095_07D_DAI2_ALC2_COMP 0x7D +#define M98095_07E_DAI2_ALC2_EXPN 0x7E +#define M98095_07F_DAI2_ALC2_GAIN 0x7F +#define M98095_080_DAI2_ALC3_TIME 0x80 +#define M98095_081_DAI2_ALC3_COMP 0x81 +#define M98095_082_DAI2_ALC3_EXPN 0x82 +#define M98095_083_DAI2_ALC3_GAIN 0x83 +#define M98095_084_HP_NOISE_GATE 0x84 +#define M98095_085_AUX_ADC 0x85 +#define M98095_086_CFG_LINE 0x86 +#define M98095_087_CFG_MIC 0x87 +#define M98095_088_CFG_LEVEL 0x88 +#define M98095_089_JACK_DET_AUTO 0x89 +#define M98095_08A_JACK_DET_MANUAL 0x8A +#define M98095_08B_JACK_KEYSCAN_DBC 0x8B +#define M98095_08C_JACK_KEYSCAN_DLY 0x8C +#define M98095_08D_JACK_KEY_THRESH 0x8D +#define M98095_08E_JACK_DC_SLEW 0x8E +#define M98095_08F_JACK_TEST_CFG 0x8F +#define M98095_090_PWR_EN_IN 0x90 +#define M98095_091_PWR_EN_OUT 0x91 +#define M98095_092_PWR_EN_OUT 0x92 +#define M98095_093_BIAS_CTRL 0x93 +#define M98095_094_PWR_DAC_21 0x94 +#define M98095_095_PWR_DAC_03 0x95 +#define M98095_096_PWR_DAC_CK 0x96 +#define M98095_097_PWR_SYS 0x97 + +#define M98095_0FF_REV_ID 0xFF + +#define M98095_REG_CNT (0xFF+1) +#define M98095_REG_MAX_CACHED 0X97 + +/* MAX98095 Registers Bit Fields */ + +/* M98095_00F_HOST_CFG */ + #define M98095_SEG (1<<0) + #define M98095_XTEN (1<<1) + #define M98095_MDLLEN (1<<2) + +/* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */ + #define M98095_CLKMODE_MASK 0xFF + +/* M98095_02A_DAI1_FORMAT, M98095_034_DAI2_FORMAT, M98095_03E_DAI3_FORMAT */ + #define M98095_DAI_MAS (1<<7) + #define M98095_DAI_WCI (1<<6) + #define M98095_DAI_BCI (1<<5) + #define M98095_DAI_DLY (1<<4) + #define M98095_DAI_TDM (1<<2) + #define M98095_DAI_FSW (1<<1) + #define M98095_DAI_WS (1<<0) + +/* M98095_02B_DAI1_CLOCK, M98095_035_DAI2_CLOCK, M98095_03F_DAI3_CLOCK */ + #define M98095_DAI_BSEL64 (1<<0) + #define M98095_DAI_DOSR_DIV2 (0<<5) + #define M98095_DAI_DOSR_DIV4 (1<<5) + +/* M98095_02C_DAI1_IOCFG, M98095_036_DAI2_IOCFG, M98095_040_DAI3_IOCFG */ + #define M98095_S1NORMAL (1<<6) + #define M98095_S2NORMAL (2<<6) + #define M98095_S3NORMAL (3<<6) + #define M98095_SDATA (3<<0) + +/* M98095_02E_DAI1_FILTERS, M98095_038_DAI2_FILTERS, M98095_042_DAI3_FILTERS */ + #define M98095_DAI_DHF (1<<3) + +/* M98095_045_DSP_CFG */ + #define M98095_DSPNORMAL (5<<4) + +/* M98095_048_MIX_DAC_LR */ + #define M98095_DAI1L_TO_DACR (1<<7) + #define M98095_DAI1R_TO_DACR (1<<6) + #define M98095_DAI2M_TO_DACR (1<<5) + #define M98095_DAI1L_TO_DACL (1<<3) + #define M98095_DAI1R_TO_DACL (1<<2) + #define M98095_DAI2M_TO_DACL (1<<1) + #define M98095_DAI3M_TO_DACL (1<<0) + +/* M98095_049_MIX_DAC_M */ + #define M98095_DAI1L_TO_DACM (1<<3) + #define M98095_DAI1R_TO_DACM (1<<2) + #define M98095_DAI2M_TO_DACM (1<<1) + #define M98095_DAI3M_TO_DACM (1<<0) + +/* M98095_04E_MIX_HP_CFG */ + #define M98095_HPNORMAL (3<<4) + +/* M98095_05F_LVL_MIC1, M98095_060_LVL_MIC2 */ + #define M98095_MICPRE_MASK (3<<5) + #define M98095_MICPRE_SHIFT 5 + +/* M98095_064_LVL_HP_L, M98095_065_LVL_HP_R */ + #define M98095_HP_MUTE (1<<7) + +/* M98095_066_LVL_RCV */ + #define M98095_REC_MUTE (1<<7) + +/* M98095_067_LVL_SPK_L, M98095_068_LVL_SPK_R */ + #define M98095_SP_MUTE (1<<7) + +/* M98095_087_CFG_MIC */ + #define M98095_MICSEL_MASK (3<<0) + #define M98095_DIGMIC_L (1<<2) + #define M98095_DIGMIC_R (1<<3) + #define M98095_DIGMIC2L (1<<4) + #define M98095_DIGMIC2R (1<<5) + +/* M98095_088_CFG_LEVEL */ + #define M98095_VSEN (1<<6) + #define M98095_ZDEN (1<<5) + #define M98095_BQ2EN (1<<3) + #define M98095_BQ1EN (1<<2) + #define M98095_EQ2EN (1<<1) + #define M98095_EQ1EN (1<<0) + +/* M98095_090_PWR_EN_IN */ + #define M98095_INEN (1<<7) + #define M98095_MB2EN (1<<3) + #define M98095_MB1EN (1<<2) + #define M98095_MBEN (3<<2) + #define M98095_ADREN (1<<1) + #define M98095_ADLEN (1<<0) + +/* M98095_091_PWR_EN_OUT */ + #define M98095_HPLEN (1<<7) + #define M98095_HPREN (1<<6) + #define M98095_SPLEN (1<<5) + #define M98095_SPREN (1<<4) + #define M98095_RECEN (1<<3) + #define M98095_DALEN (1<<1) + #define M98095_DAREN (1<<0) + +/* M98095_092_PWR_EN_OUT */ + #define M98095_SPK_FIXEDSPECTRUM (0<<4) + #define M98095_SPK_SPREADSPECTRUM (1<<4) + +/* M98095_097_PWR_SYS */ + #define M98095_SHDNRUN (1<<7) + #define M98095_PERFMODE (1<<3) + #define M98095_HPPLYBACK (1<<2) + #define M98095_PWRSV8K (1<<1) + #define M98095_PWRSV (1<<0) + +#define M98095_COEFS_PER_BAND 5 + +#define M98095_BYTE1(w) ((w >> 8) & 0xff) +#define M98095_BYTE0(w) (w & 0xff) + +/* Equalizer filter coefficients */ +#define M98095_110_DAI1_EQ_BASE 0x10 +#define M98095_142_DAI2_EQ_BASE 0x42 + +/* Biquad filter coefficients */ +#define M98095_174_DAI1_BQ_BASE 0x74 +#define M98095_17E_DAI2_BQ_BASE 0x7E + +#endif diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 2a30eae1881c..84ffdebb8a8b 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -26,7 +26,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/platform_device.h> +#include <linux/delay.h> #include <linux/slab.h> + #include <asm/intel_scu_ipc.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -825,8 +827,6 @@ EXPORT_SYMBOL_GPL(sn95031_jack_detection); /* codec registration */ static int sn95031_codec_probe(struct snd_soc_codec *codec) { - int ret; - pr_debug("codec_probe called\n"); codec->dapm.bias_level = SND_SOC_BIAS_OFF; @@ -877,16 +877,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, sn95031_snd_controls, ARRAY_SIZE(sn95031_snd_controls)); - ret = snd_soc_dapm_new_controls(&codec->dapm, sn95031_dapm_widgets, - ARRAY_SIZE(sn95031_dapm_widgets)); - if (ret) - pr_err("soc_dapm_new_control failed %d", ret); - ret = snd_soc_dapm_add_routes(&codec->dapm, sn95031_audio_map, - ARRAY_SIZE(sn95031_audio_map)); - if (ret) - pr_err("soc_dapm_add_routes failed %d", ret); - - return ret; + return 0; } static int sn95031_codec_remove(struct snd_soc_codec *codec) @@ -903,6 +894,10 @@ struct snd_soc_codec_driver sn95031_codec = { .read = sn95031_read, .write = sn95031_write, .set_bias_level = sn95031_set_vaud_bias, + .dapm_widgets = sn95031_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), + .dapm_routes = sn95031_audio_map, + .num_dapm_routes = ARRAY_SIZE(sn95031_audio_map), }; static int __devinit sn95031_device_probe(struct platform_device *pdev) @@ -925,7 +920,7 @@ static struct platform_driver sn95031_codec_driver = { .owner = THIS_MODULE, }, .probe = sn95031_device_probe, - .remove = sn95031_device_remove, + .remove = __devexit_p(sn95031_device_remove), }; static int __init sn95031_init(void) diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c index 4c32b54913ad..6a1a7e705cd7 100644 --- a/sound/soc/codecs/spdif_transciever.c +++ b/sound/soc/codecs/spdif_transciever.c @@ -21,7 +21,7 @@ #include <sound/pcm.h> #include <sound/initval.h> -MODULE_LICENSE("GPL"); +#define DRV_NAME "spdif-dit" #define STUB_RATES SNDRV_PCM_RATE_8000_96000 #define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE @@ -56,7 +56,7 @@ static struct platform_driver spdif_dit_driver = { .probe = spdif_dit_probe, .remove = spdif_dit_remove, .driver = { - .name = "spdif-dit", + .name = DRV_NAME, .owner = THIS_MODULE, }, }; @@ -74,3 +74,7 @@ static void __exit dit_exit(void) module_init(dit_modinit); module_exit(dit_exit); +MODULE_AUTHOR("Steve Chen <schen@mvista.com>"); +MODULE_DESCRIPTION("SPDIF dummy codec driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 2727befd158e..84f4ad568556 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -32,6 +32,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/spi/spi.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <sound/core.h> @@ -39,18 +40,25 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/initval.h> +#include <sound/tlv.h> #include "ssm2602.h" #define SSM2602_VERSION "0.1" +enum ssm2602_type { + SSM2602, + SSM2604, +}; + /* codec private data */ struct ssm2602_priv { unsigned int sysclk; enum snd_soc_control_type control_type; - void *control_data; struct snd_pcm_substream *master_substream; struct snd_pcm_substream *slave_substream; + + enum ssm2602_type type; }; /* @@ -60,60 +68,12 @@ struct ssm2602_priv { * There is no point in caching the reset register */ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { - 0x0017, 0x0017, 0x0079, 0x0079, - 0x0000, 0x0000, 0x0000, 0x000a, + 0x0097, 0x0097, 0x0079, 0x0079, + 0x000a, 0x0008, 0x009f, 0x000a, 0x0000, 0x0000 }; -/* - * read ssm2602 register cache - */ -static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg == SSM2602_RESET) - return 0; - if (reg >= SSM2602_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write ssm2602 register cache - */ -static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= SSM2602_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the ssm2602 register space - */ -static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 ssm2602 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - ssm2602_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define ssm2602_reset(c) ssm2602_write(c, SSM2602_RESET, 0) +#define ssm2602_reset(c) snd_soc_write(c, SSM2602_RESET, 0) /*Appending several "None"s just for OSS mixer use*/ static const char *ssm2602_input_select[] = { @@ -128,174 +88,187 @@ static const struct soc_enum ssm2602_enum[] = { SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph), }; -static const struct snd_kcontrol_new ssm2602_snd_controls[] = { +static const unsigned int ssm260x_outmix_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), + 48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0), +}; -SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V, - 0, 127, 0), -SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V, - 7, 1, 0), +static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0); -SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0), +static const struct snd_kcontrol_new ssm260x_snd_controls[] = { +SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0, + ssm260x_inpga_tlv), SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1), -SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), -SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0), -SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), - -SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1), - SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1), SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0), -SOC_ENUM("Capture Source", ssm2602_enum[0]), - SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), }; +static const struct snd_kcontrol_new ssm2602_snd_controls[] = { +SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V, + 0, 127, 0, ssm260x_outmix_tlv), +SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V, + 7, 1, 0), +SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1, + ssm260x_sidetone_tlv), + +SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), +SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0), +SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), +}; + /* Output Mixer */ -static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { +static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = { SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), -SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), +SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), }; /* Input mux */ static const struct snd_kcontrol_new ssm2602_input_mux_controls = SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); -static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = { -SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, - &ssm2602_output_mixer_controls[0], - ARRAY_SIZE(ssm2602_output_mixer_controls)), +static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), +SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), +SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0), + +SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("LOUT"), -SND_SOC_DAPM_OUTPUT("LHPOUT"), SND_SOC_DAPM_OUTPUT("ROUT"), -SND_SOC_DAPM_OUTPUT("RHPOUT"), -SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), +SND_SOC_DAPM_INPUT("RLINEIN"), +SND_SOC_DAPM_INPUT("LLINEIN"), +}; + +static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = { +SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, + ssm260x_output_mixer_controls, + ARRAY_SIZE(ssm260x_output_mixer_controls)), + SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), -SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0), SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), + +SND_SOC_DAPM_OUTPUT("LHPOUT"), +SND_SOC_DAPM_OUTPUT("RHPOUT"), SND_SOC_DAPM_INPUT("MICIN"), -SND_SOC_DAPM_INPUT("RLINEIN"), -SND_SOC_DAPM_INPUT("LLINEIN"), }; -static const struct snd_soc_dapm_route audio_conn[] = { - /* output mixer */ +static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = { +SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, + ssm260x_output_mixer_controls, + ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */ +}; + +static const struct snd_soc_dapm_route ssm260x_routes[] = { + {"DAC", NULL, "Digital Core Power"}, + {"ADC", NULL, "Digital Core Power"}, + {"Output Mixer", "Line Bypass Switch", "Line Input"}, {"Output Mixer", "HiFi Playback Switch", "DAC"}, + + {"ROUT", NULL, "Output Mixer"}, + {"LOUT", NULL, "Output Mixer"}, + + {"Line Input", NULL, "LLINEIN"}, + {"Line Input", NULL, "RLINEIN"}, +}; + +static const struct snd_soc_dapm_route ssm2602_routes[] = { {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, - /* outputs */ {"RHPOUT", NULL, "Output Mixer"}, - {"ROUT", NULL, "Output Mixer"}, {"LHPOUT", NULL, "Output Mixer"}, - {"LOUT", NULL, "Output Mixer"}, - /* input mux */ {"Input Mux", "Line", "Line Input"}, {"Input Mux", "Mic", "Mic Bias"}, {"ADC", NULL, "Input Mux"}, - /* inputs */ - {"Line Input", NULL, "LLINEIN"}, - {"Line Input", NULL, "RLINEIN"}, {"Mic Bias", NULL, "MICIN"}, }; -static int ssm2602_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets, - ARRAY_SIZE(ssm2602_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn)); - - return 0; -} +static const struct snd_soc_dapm_route ssm2604_routes[] = { + {"ADC", NULL, "Line Input"}, +}; -struct _coeff_div { +struct ssm2602_coeff { u32 mclk; u32 rate; - u16 fs; - u8 sr:4; - u8 bosr:1; - u8 usb:1; + u8 srate; }; -/* codec mclk clock divider coefficients */ -static const struct _coeff_div coeff_div[] = { +#define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb)) + +/* codec mclk clock coefficients */ +static const struct ssm2602_coeff ssm2602_coeff_table[] = { /* 48k */ - {12288000, 48000, 256, 0x0, 0x0, 0x0}, - {18432000, 48000, 384, 0x0, 0x1, 0x0}, - {12000000, 48000, 250, 0x0, 0x0, 0x1}, + {12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)}, + {18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)}, + {12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)}, /* 32k */ - {12288000, 32000, 384, 0x6, 0x0, 0x0}, - {18432000, 32000, 576, 0x6, 0x1, 0x0}, - {12000000, 32000, 375, 0x6, 0x0, 0x1}, + {12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)}, + {18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)}, + {12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)}, /* 8k */ - {12288000, 8000, 1536, 0x3, 0x0, 0x0}, - {18432000, 8000, 2304, 0x3, 0x1, 0x0}, - {11289600, 8000, 1408, 0xb, 0x0, 0x0}, - {16934400, 8000, 2112, 0xb, 0x1, 0x0}, - {12000000, 8000, 1500, 0x3, 0x0, 0x1}, + {12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)}, + {18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)}, + {11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)}, + {16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)}, + {12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)}, /* 96k */ - {12288000, 96000, 128, 0x7, 0x0, 0x0}, - {18432000, 96000, 192, 0x7, 0x1, 0x0}, - {12000000, 96000, 125, 0x7, 0x0, 0x1}, + {12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)}, + {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)}, + {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)}, /* 44.1k */ - {11289600, 44100, 256, 0x8, 0x0, 0x0}, - {16934400, 44100, 384, 0x8, 0x1, 0x0}, - {12000000, 44100, 272, 0x8, 0x1, 0x1}, + {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)}, + {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)}, + {12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)}, /* 88.2k */ - {11289600, 88200, 128, 0xf, 0x0, 0x0}, - {16934400, 88200, 192, 0xf, 0x1, 0x0}, - {12000000, 88200, 136, 0xf, 0x1, 0x1}, + {11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)}, + {16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)}, + {12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)}, }; -static inline int get_coeff(int mclk, int rate) +static inline int ssm2602_get_coeff(int mclk, int rate) { int i; - for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { - if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) - return i; + for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) { + if (ssm2602_coeff_table[i].rate == rate && + ssm2602_coeff_table[i].mclk == mclk) + return ssm2602_coeff_table[i].srate; } - return i; + return -EINVAL; } static int ssm2602_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - u16 srate; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); - struct i2c_client *i2c = codec->control_data; - u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; - int i = get_coeff(ssm2602->sysclk, params_rate(params)); + u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3; + int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params)); if (substream == ssm2602->slave_substream) { - dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); + dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n"); return 0; } - /*no match is found*/ - if (i == ARRAY_SIZE(coeff_div)) - return -EINVAL; - - srate = (coeff_div[i].sr << 2) | - (coeff_div[i].bosr << 1) | coeff_div[i].usb; + if (srate < 0) + return srate; - ssm2602_write(codec, SSM2602_ACTIVE, 0); - ssm2602_write(codec, SSM2602_SRATE, srate); + snd_soc_write(codec, SSM2602_SRATE, srate); /* bit size */ switch (params_format(params)) { @@ -311,8 +284,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, iface |= 0x000c; break; } - ssm2602_write(codec, SSM2602_IFACE, iface); - ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); + snd_soc_write(codec, SSM2602_IFACE, iface); return 0; } @@ -354,17 +326,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, return 0; } -static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; - /* set active */ - ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); - - return 0; -} - static void ssm2602_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -372,25 +333,22 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); - /* deactivate */ - if (!codec->active) - ssm2602_write(codec, SSM2602_ACTIVE, 0); - if (ssm2602->master_substream == substream) ssm2602->master_substream = ssm2602->slave_substream; ssm2602->slave_substream = NULL; } + static int ssm2602_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE; + u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE; if (mute) - ssm2602_write(codec, SSM2602_APDIGI, + snd_soc_write(codec, SSM2602_APDIGI, mute_reg | APDIGI_ENABLE_DAC_MUTE); else - ssm2602_write(codec, SSM2602_APDIGI, mute_reg); + snd_soc_write(codec, SSM2602_APDIGI, mute_reg); return 0; } @@ -466,30 +424,29 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, } /* set iface */ - ssm2602_write(codec, SSM2602_IFACE, iface); + snd_soc_write(codec, SSM2602_IFACE, iface); return 0; } static int ssm2602_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f; + u16 reg = snd_soc_read(codec, SSM2602_PWR) & 0xff7f; switch (level) { case SND_SOC_BIAS_ON: /* vref/mid, osc on, dac unmute */ - ssm2602_write(codec, SSM2602_PWR, reg); + snd_soc_write(codec, SSM2602_PWR, reg); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: /* everything off except vref/vmid, */ - ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); + snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); break; case SND_SOC_BIAS_OFF: /* everything off, dac mute, inactive */ - ssm2602_write(codec, SSM2602_ACTIVE, 0); - ssm2602_write(codec, SSM2602_PWR, 0xffff); + snd_soc_write(codec, SSM2602_PWR, 0xffff); break; } @@ -506,7 +463,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, static struct snd_soc_dai_ops ssm2602_dai_ops = { .startup = ssm2602_startup, - .prepare = ssm2602_pcm_prepare, .hw_params = ssm2602_hw_params, .shutdown = ssm2602_shutdown, .digital_mute = ssm2602_mute, @@ -539,50 +495,87 @@ static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state) static int ssm2602_resume(struct snd_soc_codec *codec) { - int i; - u8 data[2]; - u16 *cache = codec->reg_cache; - - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) { - data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); - data[1] = cache[i] & 0x00ff; - codec->hw_write(codec->control_data, data, 2); - } + snd_soc_cache_sync(codec); + ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; } static int ssm2602_probe(struct snd_soc_codec *codec) { + struct snd_soc_dapm_context *dapm = &codec->dapm; + int ret, reg; + + reg = snd_soc_read(codec, SSM2602_LOUT1V); + snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); + reg = snd_soc_read(codec, SSM2602_ROUT1V); + snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); + + ret = snd_soc_add_controls(codec, ssm2602_snd_controls, + ARRAY_SIZE(ssm2602_snd_controls)); + if (ret) + return ret; + + ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets, + ARRAY_SIZE(ssm2602_dapm_widgets)); + if (ret) + return ret; + + return snd_soc_dapm_add_routes(dapm, ssm2602_routes, + ARRAY_SIZE(ssm2602_routes)); +} + +static int ssm2604_probe(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = &codec->dapm; + int ret; + + ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets, + ARRAY_SIZE(ssm2604_dapm_widgets)); + if (ret) + return ret; + + return snd_soc_dapm_add_routes(dapm, ssm2604_routes, + ARRAY_SIZE(ssm2604_routes)); +} + +static int ssm260x_probe(struct snd_soc_codec *codec) +{ struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); - int ret = 0, reg; + int ret, reg; pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); - codec->control_data = ssm2602->control_data; + ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } - ssm2602_reset(codec); + ret = ssm2602_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset: %d\n", ret); + return ret; + } - /*power on device*/ - ssm2602_write(codec, SSM2602_ACTIVE, 0); /* set the update bits */ - reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL); - ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); - reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL); - ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); - reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V); - ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); - reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V); - ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); + reg = snd_soc_read(codec, SSM2602_LINVOL); + snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); + reg = snd_soc_read(codec, SSM2602_RINVOL); + snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); /*select Line in as default input*/ - ssm2602_write(codec, SSM2602_APANA, APANA_SELECT_DAC | + snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC | APANA_ENABLE_MIC_BOOST); - ssm2602_write(codec, SSM2602_PWR, 0); - snd_soc_add_controls(codec, ssm2602_snd_controls, - ARRAY_SIZE(ssm2602_snd_controls)); - ssm2602_add_widgets(codec); + switch (ssm2602->type) { + case SSM2602: + ret = ssm2602_probe(codec); + break; + case SSM2604: + ret = ssm2604_probe(codec); + break; + } return ret; } @@ -595,18 +588,61 @@ static int ssm2602_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { - .probe = ssm2602_probe, + .probe = ssm260x_probe, .remove = ssm2602_remove, .suspend = ssm2602_suspend, .resume = ssm2602_resume, - .read = ssm2602_read_reg_cache, - .write = ssm2602_write, .set_bias_level = ssm2602_set_bias_level, - .reg_cache_size = sizeof(ssm2602_reg), + .reg_cache_size = ARRAY_SIZE(ssm2602_reg), .reg_word_size = sizeof(u16), .reg_cache_default = ssm2602_reg, + + .controls = ssm260x_snd_controls, + .num_controls = ARRAY_SIZE(ssm260x_snd_controls), + .dapm_widgets = ssm260x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets), + .dapm_routes = ssm260x_routes, + .num_dapm_routes = ARRAY_SIZE(ssm260x_routes), }; +#if defined(CONFIG_SPI_MASTER) +static int __devinit ssm2602_spi_probe(struct spi_device *spi) +{ + struct ssm2602_priv *ssm2602; + int ret; + + ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL); + if (ssm2602 == NULL) + return -ENOMEM; + + spi_set_drvdata(spi, ssm2602); + ssm2602->control_type = SND_SOC_SPI; + ssm2602->type = SSM2602; + + ret = snd_soc_register_codec(&spi->dev, + &soc_codec_dev_ssm2602, &ssm2602_dai, 1); + if (ret < 0) + kfree(ssm2602); + return ret; +} + +static int __devexit ssm2602_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + kfree(spi_get_drvdata(spi)); + return 0; +} + +static struct spi_driver ssm2602_spi_driver = { + .driver = { + .name = "ssm2602", + .owner = THIS_MODULE, + }, + .probe = ssm2602_spi_probe, + .remove = __devexit_p(ssm2602_spi_remove), +}; +#endif + #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /* * ssm2602 2 wire address is determined by GPIO5 @@ -614,7 +650,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { * low = 0x1a * high = 0x1b */ -static int ssm2602_i2c_probe(struct i2c_client *i2c, +static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct ssm2602_priv *ssm2602; @@ -625,8 +661,8 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c, return -ENOMEM; i2c_set_clientdata(i2c, ssm2602); - ssm2602->control_data = i2c; ssm2602->control_type = SND_SOC_I2C; + ssm2602->type = id->driver_data; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ssm2602, &ssm2602_dai, 1); @@ -635,7 +671,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c, return ret; } -static int ssm2602_i2c_remove(struct i2c_client *client) +static int __devexit ssm2602_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); kfree(i2c_get_clientdata(client)); @@ -643,7 +679,9 @@ static int ssm2602_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id ssm2602_i2c_id[] = { - { "ssm2602", 0 }, + { "ssm2602", SSM2602 }, + { "ssm2603", SSM2602 }, + { "ssm2604", SSM2604 }, { } }; MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); @@ -651,11 +689,11 @@ MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); /* corgi i2c codec control layer */ static struct i2c_driver ssm2602_i2c_driver = { .driver = { - .name = "ssm2602-codec", + .name = "ssm2602", .owner = THIS_MODULE, }, .probe = ssm2602_i2c_probe, - .remove = ssm2602_i2c_remove, + .remove = __devexit_p(ssm2602_i2c_remove), .id_table = ssm2602_i2c_id, }; #endif @@ -664,25 +702,35 @@ static struct i2c_driver ssm2602_i2c_driver = { static int __init ssm2602_modinit(void) { int ret = 0; + +#if defined(CONFIG_SPI_MASTER) + ret = spi_register_driver(&ssm2602_spi_driver); + if (ret) + return ret; +#endif + #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ret = i2c_add_driver(&ssm2602_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n", - ret); - } + if (ret) + return ret; #endif + return ret; } module_init(ssm2602_modinit); static void __exit ssm2602_exit(void) { +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&ssm2602_spi_driver); +#endif + #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&ssm2602_i2c_driver); #endif } module_exit(ssm2602_exit); -MODULE_DESCRIPTION("ASoC ssm2602 driver"); +MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver"); MODULE_AUTHOR("Cliff Cai"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h index 42a47d0f8e25..b98c69168036 100644 --- a/sound/soc/codecs/ssm2602.h +++ b/sound/soc/codecs/ssm2602.h @@ -117,11 +117,5 @@ #define SSM2602_CACHEREGNUM 10 #define SSM2602_SYSCLK 0 -#define SSM2602_DAI 0 - -struct ssm2602_setup_data { - int i2c_bus; - unsigned short i2c_address; -}; #endif diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 54a30ef0ec8b..33bb52f3f683 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { SND_SOC_DAPM_INPUT("MICIN"), }; -static const struct snd_soc_dapm_route intercon[] = { +static const struct snd_soc_dapm_route tlv320aic23_intercon[] = { /* Output Mixer */ {"Output Mixer", "Line Bypass Switch", "Line Input"}, {"Output Mixer", "Playback Switch", "DAC"}, @@ -388,18 +388,6 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, return 0; } -static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets, - ARRAY_SIZE(tlv320aic23_dapm_widgets)); - /* set up audio path interconnects */ - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - - return 0; -} - static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -676,7 +664,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, tlv320aic23_snd_controls, ARRAY_SIZE(tlv320aic23_snd_controls)); - tlv320aic23_add_widgets(codec); return 0; } @@ -698,6 +685,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { .read = tlv320aic23_read_reg_cache, .write = tlv320aic23_write, .set_bias_level = tlv320aic23_set_bias_level, + .dapm_widgets = tlv320aic23_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), + .dapm_routes = tlv320aic23_intercon, + .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h index 62b1f2261429..67f19c3bebe6 100644 --- a/sound/soc/codecs/tlv320aic26.h +++ b/sound/soc/codecs/tlv320aic26.h @@ -14,14 +14,14 @@ #define AIC26_PAGE_ADDR(page, offset) ((page << 6) | offset) #define AIC26_NUM_REGS AIC26_PAGE_ADDR(3, 0) -/* Page 0: Auxillary data registers */ +/* Page 0: Auxiliary data registers */ #define AIC26_REG_BAT1 AIC26_PAGE_ADDR(0, 0x05) #define AIC26_REG_BAT2 AIC26_PAGE_ADDR(0, 0x06) #define AIC26_REG_AUX AIC26_PAGE_ADDR(0, 0x07) #define AIC26_REG_TEMP1 AIC26_PAGE_ADDR(0, 0x09) #define AIC26_REG_TEMP2 AIC26_PAGE_ADDR(0, 0x0A) -/* Page 1: Auxillary control registers */ +/* Page 1: Auxiliary control registers */ #define AIC26_REG_AUX_ADC AIC26_PAGE_ADDR(1, 0x00) #define AIC26_REG_STATUS AIC26_PAGE_ADDR(1, 0x01) #define AIC26_REG_REFERENCE AIC26_PAGE_ADDR(1, 0x03) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 3bedab26892f..c3d96fc8c267 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -157,7 +157,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int reg = mc->reg; @@ -884,7 +885,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, if (bypass_pll) return 0; - /* Use PLL, compute apropriate setup for j, d, r and p, the closest + /* Use PLL, compute appropriate setup for j, d, r and p, the closest * one wins the game. Try with d==0 first, next with d!=0. * Constraints for j are according to the datasheet. * The sysclk is divided by 1000 to prevent integer overflows. diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 00b6d87e7bdb..faa5e9fb1471 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1,7 +1,7 @@ /* * ALSA SoC Texas Instruments TLV320DAC33 codec driver * - * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com> + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> * * Copyright: (C) 2009 Nokia Corporation * @@ -324,6 +324,10 @@ static void dac33_init_chip(struct snd_soc_codec *codec) dac33_write(codec, DAC33_OUT_AMP_CTRL, dac33_read_reg_cache(codec, DAC33_OUT_AMP_CTRL)); + dac33_write(codec, DAC33_LDAC_PWR_CTRL, + dac33_read_reg_cache(codec, DAC33_LDAC_PWR_CTRL)); + dac33_write(codec, DAC33_RDAC_PWR_CTRL, + dac33_read_reg_cache(codec, DAC33_RDAC_PWR_CTRL)); } static inline int dac33_read_id(struct snd_soc_codec *codec) @@ -583,6 +587,9 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("Right DAC Power", DAC33_RDAC_PWR_CTRL, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Codec Power", + DAC33_PWR_CTRL, 4, 0, NULL, 0), + SND_SOC_DAPM_PRE("Pre Playback", dac33_playback_event), SND_SOC_DAPM_POST("Post Playback", dac33_playback_event), }; @@ -615,6 +622,9 @@ static const struct snd_soc_dapm_route audio_map[] = { /* output */ {"LEFT_LO", NULL, "Output Left Amplifier"}, {"RIGHT_LO", NULL, "Output Right Amplifier"}, + + {"LEFT_LO", NULL, "Codec Power"}, + {"RIGHT_LO", NULL, "Codec Power"}, }; static int dac33_add_widgets(struct snd_soc_codec *codec) @@ -632,13 +642,10 @@ static int dac33_add_widgets(struct snd_soc_codec *codec) static int dac33_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); int ret; switch (level) { case SND_SOC_BIAS_ON: - if (!dac33->substream) - dac33_soft_power(codec, 1); break; case SND_SOC_BIAS_PREPARE: break; @@ -670,6 +677,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) { struct snd_soc_codec *codec = dac33->codec; unsigned int delay; + unsigned long flags; switch (dac33->fifo_mode) { case DAC33_FIFO_MODE1: @@ -677,10 +685,10 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) DAC33_THRREG(dac33->nsample)); /* Take the timestamps */ - spin_lock_irq(&dac33->lock); + spin_lock_irqsave(&dac33->lock, flags); dac33->t_stamp2 = ktime_to_us(ktime_get()); dac33->t_stamp1 = dac33->t_stamp2; - spin_unlock_irq(&dac33->lock); + spin_unlock_irqrestore(&dac33->lock, flags); dac33_write16(codec, DAC33_PREFILL_MSB, DAC33_THRREG(dac33->alarm_threshold)); @@ -692,11 +700,11 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) break; case DAC33_FIFO_MODE7: /* Take the timestamp */ - spin_lock_irq(&dac33->lock); + spin_lock_irqsave(&dac33->lock, flags); dac33->t_stamp1 = ktime_to_us(ktime_get()); /* Move back the timestamp with drain time */ dac33->t_stamp1 -= dac33->mode7_us_to_lthr; - spin_unlock_irq(&dac33->lock); + spin_unlock_irqrestore(&dac33->lock, flags); dac33_write16(codec, DAC33_PREFILL_MSB, DAC33_THRREG(DAC33_MODE7_MARGIN)); @@ -714,13 +722,14 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33) { struct snd_soc_codec *codec = dac33->codec; + unsigned long flags; switch (dac33->fifo_mode) { case DAC33_FIFO_MODE1: /* Take the timestamp */ - spin_lock_irq(&dac33->lock); + spin_lock_irqsave(&dac33->lock, flags); dac33->t_stamp2 = ktime_to_us(ktime_get()); - spin_unlock_irq(&dac33->lock); + spin_unlock_irqrestore(&dac33->lock, flags); dac33_write16(codec, DAC33_NSAMPLE_MSB, DAC33_THRREG(dac33->nsample)); @@ -773,10 +782,11 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev) { struct snd_soc_codec *codec = dev; struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); + unsigned long flags; - spin_lock(&dac33->lock); + spin_lock_irqsave(&dac33->lock, flags); dac33->t_stamp1 = ktime_to_us(ktime_get()); - spin_unlock(&dac33->lock); + spin_unlock_irqrestore(&dac33->lock, flags); /* Do not schedule the workqueue in Mode7 */ if (dac33->fifo_mode != DAC33_FIFO_MODE7) @@ -936,8 +946,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) /* Write registers 0x08 and 0x09 (MSB, LSB) */ dac33_write16(codec, DAC33_INT_OSC_FREQ_RAT_A, oscset); - /* calib time: 128 is a nice number ;) */ - dac33_write(codec, DAC33_CALIB_TIME, 128); + /* OSC calibration time */ + dac33_write(codec, DAC33_CALIB_TIME, 96); /* adjustment treshold & step */ dac33_write(codec, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) | @@ -1020,7 +1030,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) /* * For FIFO bypass mode: * Enable the FIFO bypass (Disable the FIFO use) - * Set the BCLK as continous + * Set the BCLK as continuous */ fifoctrl_a |= DAC33_FBYPAS; aictrl_b |= DAC33_BCLKON; @@ -1173,15 +1183,16 @@ static snd_pcm_sframes_t dac33_dai_delay( unsigned int time_delta, uthr; int samples_out, samples_in, samples; snd_pcm_sframes_t delay = 0; + unsigned long flags; switch (dac33->fifo_mode) { case DAC33_FIFO_BYPASS: break; case DAC33_FIFO_MODE1: - spin_lock(&dac33->lock); + spin_lock_irqsave(&dac33->lock, flags); t0 = dac33->t_stamp1; t1 = dac33->t_stamp2; - spin_unlock(&dac33->lock); + spin_unlock_irqrestore(&dac33->lock, flags); t_now = ktime_to_us(ktime_get()); /* We have not started to fill the FIFO yet, delay is 0 */ @@ -1246,10 +1257,10 @@ static snd_pcm_sframes_t dac33_dai_delay( } break; case DAC33_FIFO_MODE7: - spin_lock(&dac33->lock); + spin_lock_irqsave(&dac33->lock, flags); t0 = dac33->t_stamp1; uthr = dac33->uthr; - spin_unlock(&dac33->lock); + spin_unlock_irqrestore(&dac33->lock, flags); t_now = ktime_to_us(ktime_get()); /* We have not started to fill the FIFO yet, delay is 0 */ @@ -1647,5 +1658,5 @@ module_exit(dac33_module_exit); MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver"); -MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>"); +MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320dac33.h b/sound/soc/codecs/tlv320dac33.h index 7c318b5da437..ed69670747bf 100644 --- a/sound/soc/codecs/tlv320dac33.h +++ b/sound/soc/codecs/tlv320dac33.h @@ -1,7 +1,7 @@ /* * ALSA SoC Texas Instruments TLV320DAC33 codec driver * - * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com> + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> * * Copyright: (C) 2009 Nokia Corporation * diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 1f1ac8110bef..239e0c461068 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -3,7 +3,7 @@ * * Copyright (C) Nokia Corporation * - * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com> + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -495,7 +495,7 @@ static void __exit tpa6130a2_exit(void) i2c_del_driver(&tpa6130a2_i2c_driver); } -MODULE_AUTHOR("Peter Ujfalusi"); +MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tpa6130a2.h b/sound/soc/codecs/tpa6130a2.h index 5df49c8756b2..417444020ba6 100644 --- a/sound/soc/codecs/tpa6130a2.h +++ b/sound/soc/codecs/tpa6130a2.h @@ -3,7 +3,7 @@ * * Copyright (C) Nokia Corporation * - * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com> + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 8512800f6326..bec788b12613 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -26,7 +26,6 @@ #include <linux/pm.h> #include <linux/i2c.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/i2c/twl.h> #include <linux/slab.h> #include <sound/core.h> @@ -281,7 +280,7 @@ static inline void twl4030_check_defaults(struct snd_soc_codec *codec) i, val, twl4030_reg[i]); } } - dev_dbg(codec->dev, "Found %d non maching registers. %s\n", + dev_dbg(codec->dev, "Found %d non-matching registers. %s\n", difference, difference ? "Not OK" : "OK"); } @@ -733,8 +732,7 @@ static int aif_event(struct snd_soc_dapm_widget *w, static void headset_ramp(struct snd_soc_codec *codec, int ramp) { - struct twl4030_codec_audio_data *pdata = - mfd_get_data(to_platform_device(codec->dev)); + struct twl4030_codec_audio_data *pdata = codec->dev->platform_data; unsigned char hs_gain, hs_pop; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); /* Base values for ramp delay calculation: 2^19 - 2^26 */ @@ -2018,7 +2016,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream, u8 mode; /* If the system master clock is not 26MHz, the voice PCM interface is - * not avilable. + * not available. */ if (twl4030->sysclk != 26000) { dev_err(codec->dev, "The board is configured for %u Hz, while" @@ -2028,7 +2026,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream, } /* If the codec mode is not option2, the voice PCM interface is not - * avilable. + * available. */ mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) & TWL4030_OPT_MODE; @@ -2299,7 +2297,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { static int __devinit twl4030_codec_probe(struct platform_device *pdev) { - struct twl4030_codec_audio_data *pdata = mfd_get_data(pdev); + struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "platform_data is missing\n"); diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 482fcdb59bfa..4c336636d4f5 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -960,9 +960,9 @@ static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0); /* * AFMGAIN volume control: - * from 18 to 24 dB in 6 dB steps + * from -18 to 24 dB in 6 dB steps */ -static DECLARE_TLV_DB_SCALE(afm_amp_tlv, 1800, 600, 0); +static DECLARE_TLV_DB_SCALE(afm_amp_tlv, -1800, 600, 0); /* * HSGAIN volume control: @@ -1049,7 +1049,7 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = { /* AFM gains */ SOC_DOUBLE_TLV("Aux FM Volume", - TWL6040_REG_LINEGAIN, 0, 4, 0xF, 0, afm_amp_tlv), + TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv), /* Playback gains */ SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume", @@ -1629,8 +1629,10 @@ static int twl6040_probe(struct snd_soc_codec *codec) priv->naudint = naudint; priv->workqueue = create_singlethread_workqueue("twl6040-codec"); - if (!priv->workqueue) + if (!priv->workqueue) { + ret = -ENOMEM; goto work_err; + } INIT_DELAYED_WORK(&priv->delayed_work, twl6040_accessory_work); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 48ffd406a71d..a7b8f301bad3 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -601,9 +601,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .reg_cache_step = 1, .read = uda134x_read_reg_cache, .write = uda134x_write, -#ifdef POWER_OFF_ON_STANDBY .set_bias_level = uda134x_set_bias_level, -#endif }; static int __devinit uda134x_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index c8a874d0d4ca..5836201834d9 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -441,8 +441,7 @@ EXPORT_SYMBOL_GPL(wl1273_get_format); static int wl1273_probe(struct snd_soc_codec *codec) { - struct wl1273_core **core = - mfd_get_data(to_platform_device(codec->dev)); + struct wl1273_core **core = codec->dev->platform_data; struct wl1273_priv *wl1273; int r; diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c new file mode 100644 index 000000000000..bcc208967917 --- /dev/null +++ b/sound/soc/codecs/wm1250-ev1.c @@ -0,0 +1,108 @@ +/* + * Driver for the 1250-EV1 audio I/O module + * + * Copyright 2011 Wolfson Microelectronics plc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/i2c.h> + +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +static const struct snd_soc_dapm_widget wm1250_ev1_dapm_widgets[] = { +SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_DAC("DAC", "wm1250-ev1 Playback", SND_SOC_NOPM, 0, 0), + +SND_SOC_DAPM_INPUT("WM1250 Input"), +SND_SOC_DAPM_OUTPUT("WM1250 Output"), +}; + +static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = { + { "ADC", NULL, "WM1250 Input" }, + { "WM1250 Output", NULL, "DAC" }, +}; + +static struct snd_soc_dai_driver wm1250_ev1_dai = { + .name = "wm1250-ev1", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = { + .dapm_widgets = wm1250_ev1_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets), + .dapm_routes = wm1250_ev1_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes), +}; + +static int __devinit wm1250_ev1_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1, + &wm1250_ev1_dai, 1); +} + +static int __devexit wm1250_ev1_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static const struct i2c_device_id wm1250_ev1_i2c_id[] = { + { "wm1250-ev1", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id); + +static struct i2c_driver wm1250_ev1_i2c_driver = { + .driver = { + .name = "wm1250-ev1", + .owner = THIS_MODULE, + }, + .probe = wm1250_ev1_probe, + .remove = __devexit_p(wm1250_ev1_remove), + .id_table = wm1250_ev1_i2c_id, +}; + +static int __init wm1250_ev1_modinit(void) +{ + int ret = 0; + + ret = i2c_add_driver(&wm1250_ev1_i2c_driver); + if (ret != 0) + pr_err("Failed to register WM1250-EV1 I2C driver: %d\n", ret); + + return ret; +} +module_init(wm1250_ev1_modinit); + +static void __exit wm1250_ev1_exit(void) +{ + i2c_del_driver(&wm1250_ev1_i2c_driver); +} +module_exit(wm1250_ev1_exit); + +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_DESCRIPTION("WM1250-EV1 audio I/O module driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 736b785e3756..fbee556cbf35 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1378,7 +1378,7 @@ static void wm8400_probe_deferred(struct work_struct *work) static int wm8400_codec_probe(struct snd_soc_codec *codec) { - struct wm8400 *wm8400 = mfd_get_data(to_platform_device(codec->dev)); + struct wm8400 *wm8400 = dev_get_platdata(codec->dev); struct wm8400_priv *priv; int ret; u16 reg; diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 8f6b5ee6645b..4bbc0a79f01e 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -772,7 +772,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); snd_soc_write(codec, WM8580_PWRDN1, reg); - /* Make VMID high impedence */ + /* Make VMID high impedance */ reg = snd_soc_read(codec, WM8580_ADC_CONTROL1); reg &= ~0x100; snd_soc_write(codec, WM8580_ADC_CONTROL1, reg); diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 97c30382d3ff..a537e4af6ae7 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -77,7 +77,7 @@ SND_SOC_DAPM_OUTPUT("ROUT"), SND_SOC_DAPM_OUTPUT("RHPOUT"), }; -static const struct snd_soc_dapm_route intercon[] = { +static const struct snd_soc_dapm_route wm8711_intercon[] = { /* output mixer */ {"Output Mixer", "Line Bypass Switch", "Line Input"}, {"Output Mixer", "HiFi Playback Switch", "DAC"}, @@ -89,17 +89,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"LOUT", NULL, "Output Mixer"}, }; -static int wm8711_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8711_dapm_widgets, - ARRAY_SIZE(wm8711_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - - return 0; -} - struct _coeff_div { u32 mclk; u32 rate; @@ -398,7 +387,6 @@ static int wm8711_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, wm8711_snd_controls, ARRAY_SIZE(wm8711_snd_controls)); - wm8711_add_widgets(codec); return ret; @@ -420,6 +408,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = { .reg_cache_size = ARRAY_SIZE(wm8711_reg), .reg_word_size = sizeof(u16), .reg_cache_default = wm8711_reg, + .dapm_widgets = wm8711_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8711_dapm_widgets), + .dapm_routes = wm8711_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8711_intercon), }; #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 736b0352d0a7..86d4718d3a76 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -65,22 +65,11 @@ SND_SOC_DAPM_OUTPUT("VOUTL"), SND_SOC_DAPM_OUTPUT("VOUTR"), }; -static const struct snd_soc_dapm_route intercon[] = { +static const struct snd_soc_dapm_route wm8728_intercon[] = { {"VOUTL", NULL, "DAC"}, {"VOUTR", NULL, "DAC"}, }; -static int wm8728_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8728_dapm_widgets, - ARRAY_SIZE(wm8728_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - - return 0; -} - static int wm8728_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; @@ -255,7 +244,6 @@ static int wm8728_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, wm8728_snd_controls, ARRAY_SIZE(wm8728_snd_controls)); - wm8728_add_widgets(codec); return ret; } @@ -275,6 +263,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = { .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults), .reg_word_size = sizeof(u16), .reg_cache_default = wm8728_reg_defaults, + .dapm_widgets = wm8728_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets), + .dapm_routes = wm8728_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8728_intercon), }; #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 0a67c31b2663..2dc964b55e4f 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -198,10 +198,10 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source, { struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec); - return wm8731->sysclk_type == WM8731_SYSCLK_MCLK; + return wm8731->sysclk_type == WM8731_SYSCLK_XTAL; } -static const struct snd_soc_dapm_route intercon[] = { +static const struct snd_soc_dapm_route wm8731_intercon[] = { {"DAC", NULL, "OSC", wm8731_check_osc}, {"ADC", NULL, "OSC", wm8731_check_osc}, @@ -227,17 +227,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"Mic Bias", NULL, "MICIN"}, }; -static int wm8731_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets, - ARRAY_SIZE(wm8731_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - - return 0; -} - struct _coeff_div { u32 mclk; u32 rate; @@ -599,7 +588,6 @@ static int wm8731_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, wm8731_snd_controls, ARRAY_SIZE(wm8731_snd_controls)); - wm8731_add_widgets(codec); /* Regulators will have been enabled by bias management */ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); @@ -636,6 +624,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { .reg_cache_size = ARRAY_SIZE(wm8731_reg), .reg_word_size = sizeof(u16), .reg_cache_default = wm8731_reg, + .dapm_widgets = wm8731_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), + .dapm_routes = wm8731_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8731_intercon), }; #if defined(CONFIG_SPI_MASTER) @@ -667,7 +659,7 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi) static struct spi_driver wm8731_spi_driver = { .driver = { - .name = "wm8731-codec", + .name = "wm8731", .owner = THIS_MODULE, }, .probe = wm8731_spi_probe, @@ -711,7 +703,7 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); static struct i2c_driver wm8731_i2c_driver = { .driver = { - .name = "wm8731-codec", + .name = "wm8731", .owner = THIS_MODULE, }, .probe = wm8731_i2c_probe, diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 3f09deea8d9d..ffa2ffe5ec11 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1312,7 +1312,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_FMTBIT_S24_LE) /* - * The WM8753 supports upto 4 different and mutually exclusive DAI + * The WM8753 supports up to 4 different and mutually exclusive DAI * configurations. This gives 2 PCM's available for use, hifi and voice. * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI * is connected between the wm8753 and a BT codec or GSM modem. diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index ae1cadfae84c..43e3d760766f 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -247,8 +247,6 @@ static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int re case WM8903_REVISION_NUMBER: case WM8903_INTERRUPT_STATUS_1: case WM8903_WRITE_SEQUENCER_4: - case WM8903_POWER_MANAGEMENT_3: - case WM8903_POWER_MANAGEMENT_2: case WM8903_DC_SERVO_READBACK_1: case WM8903_DC_SERVO_READBACK_2: case WM8903_DC_SERVO_READBACK_3: @@ -384,7 +382,8 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm, static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct snd_soc_codec *codec = widget->codec; struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); u16 reg; @@ -636,6 +635,13 @@ static const struct soc_enum lsidetone_enum = static const struct soc_enum rsidetone_enum = SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text); +static const char *adcinput_text[] = { + "ADC", "DMIC" +}; + +static const struct soc_enum adcinput_enum = + SOC_ENUM_SINGLE(WM8903_CLOCK_RATE_TEST_4, 9, 2, adcinput_text); + static const char *aif_text[] = { "Left", "Right" }; @@ -694,7 +700,7 @@ SOC_ENUM("DRC Smoothing Threshold", drc_smoothing), SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup), SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT, - WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv), + WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv), SOC_ENUM("ADC Companding Mode", adc_companding), SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0), @@ -769,6 +775,9 @@ static const struct snd_kcontrol_new lsidetone_mux = static const struct snd_kcontrol_new rsidetone_mux = SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum); +static const struct snd_kcontrol_new adcinput_mux = + SOC_DAPM_ENUM("ADC Input", adcinput_enum); + static const struct snd_kcontrol_new lcapture_mux = SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum); @@ -819,6 +828,7 @@ SND_SOC_DAPM_INPUT("IN2L"), SND_SOC_DAPM_INPUT("IN2R"), SND_SOC_DAPM_INPUT("IN3L"), SND_SOC_DAPM_INPUT("IN3R"), +SND_SOC_DAPM_INPUT("DMICDAT"), SND_SOC_DAPM_OUTPUT("HPOUTL"), SND_SOC_DAPM_OUTPUT("HPOUTR"), @@ -844,6 +854,9 @@ SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux), SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0), SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0), +SND_SOC_DAPM_MUX("Left ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux), +SND_SOC_DAPM_MUX("Right ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux), + SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0), SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0), @@ -875,34 +888,40 @@ SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0, SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0, right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), -SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0, - 4, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0, +SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2, + 1, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2, 0, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 4, 0, +SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 1, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 0, 0, +SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 0, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPL_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 7, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPL_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPL_ENA", 1, WM8903_ANALOGUE_HP_0, 4, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPR_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 3, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPR_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 2, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPR_ENA", 1, WM8903_ANALOGUE_HP_0, 0, 0, NULL, 0), SND_SOC_DAPM_PGA_S("LINEOUTL_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 7, 0, NULL, 0), SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 5, 0, +SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 5, 0, + NULL, 0), +SND_SOC_DAPM_PGA_S("LINEOUTL_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 4, 0, NULL, 0), SND_SOC_DAPM_PGA_S("LINEOUTR_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 3, 0, NULL, 0), SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 2, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 1, 0, +SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 1, 0, + NULL, 0), +SND_SOC_DAPM_PGA_S("LINEOUTR_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DCS Master", WM8903_DC_SERVO_0, 4, 0, NULL, 0), @@ -926,7 +945,7 @@ SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0), }; -static const struct snd_soc_dapm_route intercon[] = { +static const struct snd_soc_dapm_route wm8903_intercon[] = { { "CLK_DSP", NULL, "CLK_SYS" }, { "Mic Bias", NULL, "CLK_SYS" }, @@ -975,6 +994,11 @@ static const struct snd_soc_dapm_route intercon[] = { { "Left Input PGA", NULL, "Left Input Mode Mux" }, { "Right Input PGA", NULL, "Right Input Mode Mux" }, + { "Left ADC Input", "ADC", "Left Input PGA" }, + { "Left ADC Input", "DMIC", "DMICDAT" }, + { "Right ADC Input", "ADC", "Right Input PGA" }, + { "Right ADC Input", "DMIC", "DMICDAT" }, + { "Left Capture Mux", "Left", "ADCL" }, { "Left Capture Mux", "Right", "ADCR" }, @@ -984,9 +1008,9 @@ static const struct snd_soc_dapm_route intercon[] = { { "AIFTXL", NULL, "Left Capture Mux" }, { "AIFTXR", NULL, "Right Capture Mux" }, - { "ADCL", NULL, "Left Input PGA" }, + { "ADCL", NULL, "Left ADC Input" }, { "ADCL", NULL, "CLK_DSP" }, - { "ADCR", NULL, "Right Input PGA" }, + { "ADCR", NULL, "Right ADC Input" }, { "ADCR", NULL, "CLK_DSP" }, { "Left Playback Mux", "Left", "AIFRXL" }, @@ -1037,10 +1061,14 @@ static const struct snd_soc_dapm_route intercon[] = { { "Left Speaker PGA", NULL, "Left Speaker Mixer" }, { "Right Speaker PGA", NULL, "Right Speaker Mixer" }, - { "HPL_ENA_DLY", NULL, "Left Headphone Output PGA" }, - { "HPR_ENA_DLY", NULL, "Right Headphone Output PGA" }, - { "LINEOUTL_ENA_DLY", NULL, "Left Line Output PGA" }, - { "LINEOUTR_ENA_DLY", NULL, "Right Line Output PGA" }, + { "HPL_ENA", NULL, "Left Headphone Output PGA" }, + { "HPR_ENA", NULL, "Right Headphone Output PGA" }, + { "HPL_ENA_DLY", NULL, "HPL_ENA" }, + { "HPR_ENA_DLY", NULL, "HPR_ENA" }, + { "LINEOUTL_ENA", NULL, "Left Line Output PGA" }, + { "LINEOUTR_ENA", NULL, "Right Line Output PGA" }, + { "LINEOUTL_ENA_DLY", NULL, "LINEOUTL_ENA" }, + { "LINEOUTR_ENA_DLY", NULL, "LINEOUTR_ENA" }, { "HPL_DCS", NULL, "DCS Master" }, { "HPR_DCS", NULL, "DCS Master" }, @@ -1079,17 +1107,6 @@ static const struct snd_soc_dapm_route intercon[] = { { "Right Line Output PGA", NULL, "Charge Pump" }, }; -static int wm8903_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8903_dapm_widgets, - ARRAY_SIZE(wm8903_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - - return 0; -} - static int wm8903_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -2020,7 +2037,6 @@ static int wm8903_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, wm8903_snd_controls, ARRAY_SIZE(wm8903_snd_controls)); - wm8903_add_widgets(codec); wm8903_init_gpio(codec); @@ -2046,6 +2062,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8903 = { .reg_cache_default = wm8903_reg_defaults, .volatile_register = wm8903_volatile_register, .seq_notifier = wm8903_seq_notifier, + .dapm_widgets = wm8903_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets), + .dapm_routes = wm8903_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8903_intercon), }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 443ae580445c..9b3bba4df5b3 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1895,7 +1895,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, pr_debug("Fvco=%dHz\n", target); - /* Find an appropraite FLL_FRATIO and factor it out of the target */ + /* Find an appropriate FLL_FRATIO and factor it out of the target */ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { fll_div->fll_fratio = fll_fratios[i].fll_fratio; diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c new file mode 100644 index 000000000000..a0b1a7278284 --- /dev/null +++ b/sound/soc/codecs/wm8915.c @@ -0,0 +1,2930 @@ +/* + * wm8915.c - WM8915 audio codec interface + * + * Copyright 2011 Wolfson Microelectronics PLC. + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/gcd.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <trace/events/asoc.h> + +#include <sound/wm8915.h> +#include "wm8915.h" + +#define WM8915_AIFS 2 + +#define HPOUT1L 1 +#define HPOUT1R 2 +#define HPOUT2L 4 +#define HPOUT2R 8 + +#define WM8915_NUM_SUPPLIES 6 +static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = { + "DCVDD", + "DBVDD", + "AVDD1", + "AVDD2", + "CPVDD", + "MICVDD", +}; + +struct wm8915_priv { + struct snd_soc_codec *codec; + + int ldo1ena; + + int sysclk; + + int fll_src; + int fll_fref; + int fll_fout; + + struct completion fll_lock; + + u16 dcs_pending; + struct completion dcs_done; + + u16 hpout_ena; + u16 hpout_pending; + + struct regulator_bulk_data supplies[WM8915_NUM_SUPPLIES]; + struct notifier_block disable_nb[WM8915_NUM_SUPPLIES]; + + struct wm8915_pdata pdata; + + int rx_rate[WM8915_AIFS]; + + /* Platform dependant ReTune mobile configuration */ + int num_retune_mobile_texts; + const char **retune_mobile_texts; + int retune_mobile_cfg[2]; + struct soc_enum retune_mobile_enum; + + struct snd_soc_jack *jack; + bool detecting; + bool jack_mic; + wm8915_polarity_fn polarity_cb; + +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio_chip; +#endif +}; + +/* We can't use the same notifier block for more than one supply and + * there's no way I can see to get from a callback to the caller + * except container_of(). + */ +#define WM8915_REGULATOR_EVENT(n) \ +static int wm8915_regulator_event_##n(struct notifier_block *nb, \ + unsigned long event, void *data) \ +{ \ + struct wm8915_priv *wm8915 = container_of(nb, struct wm8915_priv, \ + disable_nb[n]); \ + if (event & REGULATOR_EVENT_DISABLE) { \ + wm8915->codec->cache_sync = 1; \ + } \ + return 0; \ +} + +WM8915_REGULATOR_EVENT(0) +WM8915_REGULATOR_EVENT(1) +WM8915_REGULATOR_EVENT(2) +WM8915_REGULATOR_EVENT(3) +WM8915_REGULATOR_EVENT(4) +WM8915_REGULATOR_EVENT(5) + +static const u16 wm8915_reg[WM8915_MAX_REGISTER] = { + [WM8915_SOFTWARE_RESET] = 0x8915, + [WM8915_POWER_MANAGEMENT_7] = 0x10, + [WM8915_DAC1_HPOUT1_VOLUME] = 0x88, + [WM8915_DAC2_HPOUT2_VOLUME] = 0x88, + [WM8915_DAC1_LEFT_VOLUME] = 0x2c0, + [WM8915_DAC1_RIGHT_VOLUME] = 0x2c0, + [WM8915_DAC2_LEFT_VOLUME] = 0x2c0, + [WM8915_DAC2_RIGHT_VOLUME] = 0x2c0, + [WM8915_OUTPUT1_LEFT_VOLUME] = 0x80, + [WM8915_OUTPUT1_RIGHT_VOLUME] = 0x80, + [WM8915_OUTPUT2_LEFT_VOLUME] = 0x80, + [WM8915_OUTPUT2_RIGHT_VOLUME] = 0x80, + [WM8915_MICBIAS_1] = 0x39, + [WM8915_MICBIAS_2] = 0x39, + [WM8915_LDO_1] = 0x3, + [WM8915_LDO_2] = 0x13, + [WM8915_ACCESSORY_DETECT_MODE_1] = 0x4, + [WM8915_HEADPHONE_DETECT_1] = 0x20, + [WM8915_MIC_DETECT_1] = 0x7600, + [WM8915_MIC_DETECT_2] = 0xbf, + [WM8915_CHARGE_PUMP_1] = 0x1f25, + [WM8915_CHARGE_PUMP_2] = 0xab19, + [WM8915_DC_SERVO_5] = 0x2a2a, + [WM8915_CONTROL_INTERFACE_1] = 0x8004, + [WM8915_CLOCKING_1] = 0x10, + [WM8915_AIF_RATE] = 0x83, + [WM8915_FLL_CONTROL_4] = 0x5dc0, + [WM8915_FLL_CONTROL_5] = 0xc84, + [WM8915_FLL_EFS_2] = 0x2, + [WM8915_AIF1_TX_LRCLK_1] = 0x80, + [WM8915_AIF1_TX_LRCLK_2] = 0x8, + [WM8915_AIF1_RX_LRCLK_1] = 0x80, + [WM8915_AIF1TX_DATA_CONFIGURATION_1] = 0x1818, + [WM8915_AIF1RX_DATA_CONFIGURATION] = 0x1818, + [WM8915_AIF1TX_TEST] = 0x7, + [WM8915_AIF2_TX_LRCLK_1] = 0x80, + [WM8915_AIF2_TX_LRCLK_2] = 0x8, + [WM8915_AIF2_RX_LRCLK_1] = 0x80, + [WM8915_AIF2TX_DATA_CONFIGURATION_1] = 0x1818, + [WM8915_AIF2RX_DATA_CONFIGURATION] = 0x1818, + [WM8915_AIF2TX_TEST] = 0x1, + [WM8915_DSP1_TX_LEFT_VOLUME] = 0xc0, + [WM8915_DSP1_TX_RIGHT_VOLUME] = 0xc0, + [WM8915_DSP1_RX_LEFT_VOLUME] = 0xc0, + [WM8915_DSP1_RX_RIGHT_VOLUME] = 0xc0, + [WM8915_DSP1_TX_FILTERS] = 0x2000, + [WM8915_DSP1_RX_FILTERS_1] = 0x200, + [WM8915_DSP1_RX_FILTERS_2] = 0x10, + [WM8915_DSP1_DRC_1] = 0x98, + [WM8915_DSP1_DRC_2] = 0x845, + [WM8915_DSP1_RX_EQ_GAINS_1] = 0x6318, + [WM8915_DSP1_RX_EQ_GAINS_2] = 0x6300, + [WM8915_DSP1_RX_EQ_BAND_1_A] = 0xfca, + [WM8915_DSP1_RX_EQ_BAND_1_B] = 0x400, + [WM8915_DSP1_RX_EQ_BAND_1_PG] = 0xd8, + [WM8915_DSP1_RX_EQ_BAND_2_A] = 0x1eb5, + [WM8915_DSP1_RX_EQ_BAND_2_B] = 0xf145, + [WM8915_DSP1_RX_EQ_BAND_2_C] = 0xb75, + [WM8915_DSP1_RX_EQ_BAND_2_PG] = 0x1c5, + [WM8915_DSP1_RX_EQ_BAND_3_A] = 0x1c58, + [WM8915_DSP1_RX_EQ_BAND_3_B] = 0xf373, + [WM8915_DSP1_RX_EQ_BAND_3_C] = 0xa54, + [WM8915_DSP1_RX_EQ_BAND_3_PG] = 0x558, + [WM8915_DSP1_RX_EQ_BAND_4_A] = 0x168e, + [WM8915_DSP1_RX_EQ_BAND_4_B] = 0xf829, + [WM8915_DSP1_RX_EQ_BAND_4_C] = 0x7ad, + [WM8915_DSP1_RX_EQ_BAND_4_PG] = 0x1103, + [WM8915_DSP1_RX_EQ_BAND_5_A] = 0x564, + [WM8915_DSP1_RX_EQ_BAND_5_B] = 0x559, + [WM8915_DSP1_RX_EQ_BAND_5_PG] = 0x4000, + [WM8915_DSP2_TX_LEFT_VOLUME] = 0xc0, + [WM8915_DSP2_TX_RIGHT_VOLUME] = 0xc0, + [WM8915_DSP2_RX_LEFT_VOLUME] = 0xc0, + [WM8915_DSP2_RX_RIGHT_VOLUME] = 0xc0, + [WM8915_DSP2_TX_FILTERS] = 0x2000, + [WM8915_DSP2_RX_FILTERS_1] = 0x200, + [WM8915_DSP2_RX_FILTERS_2] = 0x10, + [WM8915_DSP2_DRC_1] = 0x98, + [WM8915_DSP2_DRC_2] = 0x845, + [WM8915_DSP2_RX_EQ_GAINS_1] = 0x6318, + [WM8915_DSP2_RX_EQ_GAINS_2] = 0x6300, + [WM8915_DSP2_RX_EQ_BAND_1_A] = 0xfca, + [WM8915_DSP2_RX_EQ_BAND_1_B] = 0x400, + [WM8915_DSP2_RX_EQ_BAND_1_PG] = 0xd8, + [WM8915_DSP2_RX_EQ_BAND_2_A] = 0x1eb5, + [WM8915_DSP2_RX_EQ_BAND_2_B] = 0xf145, + [WM8915_DSP2_RX_EQ_BAND_2_C] = 0xb75, + [WM8915_DSP2_RX_EQ_BAND_2_PG] = 0x1c5, + [WM8915_DSP2_RX_EQ_BAND_3_A] = 0x1c58, + [WM8915_DSP2_RX_EQ_BAND_3_B] = 0xf373, + [WM8915_DSP2_RX_EQ_BAND_3_C] = 0xa54, + [WM8915_DSP2_RX_EQ_BAND_3_PG] = 0x558, + [WM8915_DSP2_RX_EQ_BAND_4_A] = 0x168e, + [WM8915_DSP2_RX_EQ_BAND_4_B] = 0xf829, + [WM8915_DSP2_RX_EQ_BAND_4_C] = 0x7ad, + [WM8915_DSP2_RX_EQ_BAND_4_PG] = 0x1103, + [WM8915_DSP2_RX_EQ_BAND_5_A] = 0x564, + [WM8915_DSP2_RX_EQ_BAND_5_B] = 0x559, + [WM8915_DSP2_RX_EQ_BAND_5_PG] = 0x4000, + [WM8915_OVERSAMPLING] = 0xd, + [WM8915_SIDETONE] = 0x1040, + [WM8915_GPIO_1] = 0xa101, + [WM8915_GPIO_2] = 0xa101, + [WM8915_GPIO_3] = 0xa101, + [WM8915_GPIO_4] = 0xa101, + [WM8915_GPIO_5] = 0xa101, + [WM8915_PULL_CONTROL_2] = 0x140, + [WM8915_INTERRUPT_STATUS_1_MASK] = 0x1f, + [WM8915_INTERRUPT_STATUS_2_MASK] = 0x1ecf, + [WM8915_RIGHT_PDM_SPEAKER] = 0x1, + [WM8915_PDM_SPEAKER_MUTE_SEQUENCE] = 0x69, + [WM8915_PDM_SPEAKER_VOLUME] = 0x66, + [WM8915_WRITE_SEQUENCER_0] = 0x1, + [WM8915_WRITE_SEQUENCER_1] = 0x1, + [WM8915_WRITE_SEQUENCER_3] = 0x6, + [WM8915_WRITE_SEQUENCER_4] = 0x40, + [WM8915_WRITE_SEQUENCER_5] = 0x1, + [WM8915_WRITE_SEQUENCER_6] = 0xf, + [WM8915_WRITE_SEQUENCER_7] = 0x6, + [WM8915_WRITE_SEQUENCER_8] = 0x1, + [WM8915_WRITE_SEQUENCER_9] = 0x3, + [WM8915_WRITE_SEQUENCER_10] = 0x104, + [WM8915_WRITE_SEQUENCER_12] = 0x60, + [WM8915_WRITE_SEQUENCER_13] = 0x11, + [WM8915_WRITE_SEQUENCER_14] = 0x401, + [WM8915_WRITE_SEQUENCER_16] = 0x50, + [WM8915_WRITE_SEQUENCER_17] = 0x3, + [WM8915_WRITE_SEQUENCER_18] = 0x100, + [WM8915_WRITE_SEQUENCER_20] = 0x51, + [WM8915_WRITE_SEQUENCER_21] = 0x3, + [WM8915_WRITE_SEQUENCER_22] = 0x104, + [WM8915_WRITE_SEQUENCER_23] = 0xa, + [WM8915_WRITE_SEQUENCER_24] = 0x60, + [WM8915_WRITE_SEQUENCER_25] = 0x3b, + [WM8915_WRITE_SEQUENCER_26] = 0x502, + [WM8915_WRITE_SEQUENCER_27] = 0x100, + [WM8915_WRITE_SEQUENCER_28] = 0x2fff, + [WM8915_WRITE_SEQUENCER_32] = 0x2fff, + [WM8915_WRITE_SEQUENCER_36] = 0x2fff, + [WM8915_WRITE_SEQUENCER_40] = 0x2fff, + [WM8915_WRITE_SEQUENCER_44] = 0x2fff, + [WM8915_WRITE_SEQUENCER_48] = 0x2fff, + [WM8915_WRITE_SEQUENCER_52] = 0x2fff, + [WM8915_WRITE_SEQUENCER_56] = 0x2fff, + [WM8915_WRITE_SEQUENCER_60] = 0x2fff, + [WM8915_WRITE_SEQUENCER_64] = 0x1, + [WM8915_WRITE_SEQUENCER_65] = 0x1, + [WM8915_WRITE_SEQUENCER_67] = 0x6, + [WM8915_WRITE_SEQUENCER_68] = 0x40, + [WM8915_WRITE_SEQUENCER_69] = 0x1, + [WM8915_WRITE_SEQUENCER_70] = 0xf, + [WM8915_WRITE_SEQUENCER_71] = 0x6, + [WM8915_WRITE_SEQUENCER_72] = 0x1, + [WM8915_WRITE_SEQUENCER_73] = 0x3, + [WM8915_WRITE_SEQUENCER_74] = 0x104, + [WM8915_WRITE_SEQUENCER_76] = 0x60, + [WM8915_WRITE_SEQUENCER_77] = 0x11, + [WM8915_WRITE_SEQUENCER_78] = 0x401, + [WM8915_WRITE_SEQUENCER_80] = 0x50, + [WM8915_WRITE_SEQUENCER_81] = 0x3, + [WM8915_WRITE_SEQUENCER_82] = 0x100, + [WM8915_WRITE_SEQUENCER_84] = 0x60, + [WM8915_WRITE_SEQUENCER_85] = 0x3b, + [WM8915_WRITE_SEQUENCER_86] = 0x502, + [WM8915_WRITE_SEQUENCER_87] = 0x100, + [WM8915_WRITE_SEQUENCER_88] = 0x2fff, + [WM8915_WRITE_SEQUENCER_92] = 0x2fff, + [WM8915_WRITE_SEQUENCER_96] = 0x2fff, + [WM8915_WRITE_SEQUENCER_100] = 0x2fff, + [WM8915_WRITE_SEQUENCER_104] = 0x2fff, + [WM8915_WRITE_SEQUENCER_108] = 0x2fff, + [WM8915_WRITE_SEQUENCER_112] = 0x2fff, + [WM8915_WRITE_SEQUENCER_116] = 0x2fff, + [WM8915_WRITE_SEQUENCER_120] = 0x2fff, + [WM8915_WRITE_SEQUENCER_124] = 0x2fff, + [WM8915_WRITE_SEQUENCER_128] = 0x1, + [WM8915_WRITE_SEQUENCER_129] = 0x1, + [WM8915_WRITE_SEQUENCER_131] = 0x6, + [WM8915_WRITE_SEQUENCER_132] = 0x40, + [WM8915_WRITE_SEQUENCER_133] = 0x1, + [WM8915_WRITE_SEQUENCER_134] = 0xf, + [WM8915_WRITE_SEQUENCER_135] = 0x6, + [WM8915_WRITE_SEQUENCER_136] = 0x1, + [WM8915_WRITE_SEQUENCER_137] = 0x3, + [WM8915_WRITE_SEQUENCER_138] = 0x106, + [WM8915_WRITE_SEQUENCER_140] = 0x61, + [WM8915_WRITE_SEQUENCER_141] = 0x11, + [WM8915_WRITE_SEQUENCER_142] = 0x401, + [WM8915_WRITE_SEQUENCER_144] = 0x50, + [WM8915_WRITE_SEQUENCER_145] = 0x3, + [WM8915_WRITE_SEQUENCER_146] = 0x102, + [WM8915_WRITE_SEQUENCER_148] = 0x51, + [WM8915_WRITE_SEQUENCER_149] = 0x3, + [WM8915_WRITE_SEQUENCER_150] = 0x106, + [WM8915_WRITE_SEQUENCER_151] = 0xa, + [WM8915_WRITE_SEQUENCER_152] = 0x61, + [WM8915_WRITE_SEQUENCER_153] = 0x3b, + [WM8915_WRITE_SEQUENCER_154] = 0x502, + [WM8915_WRITE_SEQUENCER_155] = 0x100, + [WM8915_WRITE_SEQUENCER_156] = 0x2fff, + [WM8915_WRITE_SEQUENCER_160] = 0x2fff, + [WM8915_WRITE_SEQUENCER_164] = 0x2fff, + [WM8915_WRITE_SEQUENCER_168] = 0x2fff, + [WM8915_WRITE_SEQUENCER_172] = 0x2fff, + [WM8915_WRITE_SEQUENCER_176] = 0x2fff, + [WM8915_WRITE_SEQUENCER_180] = 0x2fff, + [WM8915_WRITE_SEQUENCER_184] = 0x2fff, + [WM8915_WRITE_SEQUENCER_188] = 0x2fff, + [WM8915_WRITE_SEQUENCER_192] = 0x1, + [WM8915_WRITE_SEQUENCER_193] = 0x1, + [WM8915_WRITE_SEQUENCER_195] = 0x6, + [WM8915_WRITE_SEQUENCER_196] = 0x40, + [WM8915_WRITE_SEQUENCER_197] = 0x1, + [WM8915_WRITE_SEQUENCER_198] = 0xf, + [WM8915_WRITE_SEQUENCER_199] = 0x6, + [WM8915_WRITE_SEQUENCER_200] = 0x1, + [WM8915_WRITE_SEQUENCER_201] = 0x3, + [WM8915_WRITE_SEQUENCER_202] = 0x106, + [WM8915_WRITE_SEQUENCER_204] = 0x61, + [WM8915_WRITE_SEQUENCER_205] = 0x11, + [WM8915_WRITE_SEQUENCER_206] = 0x401, + [WM8915_WRITE_SEQUENCER_208] = 0x50, + [WM8915_WRITE_SEQUENCER_209] = 0x3, + [WM8915_WRITE_SEQUENCER_210] = 0x102, + [WM8915_WRITE_SEQUENCER_212] = 0x61, + [WM8915_WRITE_SEQUENCER_213] = 0x3b, + [WM8915_WRITE_SEQUENCER_214] = 0x502, + [WM8915_WRITE_SEQUENCER_215] = 0x100, + [WM8915_WRITE_SEQUENCER_216] = 0x2fff, + [WM8915_WRITE_SEQUENCER_220] = 0x2fff, + [WM8915_WRITE_SEQUENCER_224] = 0x2fff, + [WM8915_WRITE_SEQUENCER_228] = 0x2fff, + [WM8915_WRITE_SEQUENCER_232] = 0x2fff, + [WM8915_WRITE_SEQUENCER_236] = 0x2fff, + [WM8915_WRITE_SEQUENCER_240] = 0x2fff, + [WM8915_WRITE_SEQUENCER_244] = 0x2fff, + [WM8915_WRITE_SEQUENCER_248] = 0x2fff, + [WM8915_WRITE_SEQUENCER_252] = 0x2fff, + [WM8915_WRITE_SEQUENCER_256] = 0x60, + [WM8915_WRITE_SEQUENCER_258] = 0x601, + [WM8915_WRITE_SEQUENCER_260] = 0x50, + [WM8915_WRITE_SEQUENCER_262] = 0x100, + [WM8915_WRITE_SEQUENCER_264] = 0x1, + [WM8915_WRITE_SEQUENCER_266] = 0x104, + [WM8915_WRITE_SEQUENCER_267] = 0x100, + [WM8915_WRITE_SEQUENCER_268] = 0x2fff, + [WM8915_WRITE_SEQUENCER_272] = 0x2fff, + [WM8915_WRITE_SEQUENCER_276] = 0x2fff, + [WM8915_WRITE_SEQUENCER_280] = 0x2fff, + [WM8915_WRITE_SEQUENCER_284] = 0x2fff, + [WM8915_WRITE_SEQUENCER_288] = 0x2fff, + [WM8915_WRITE_SEQUENCER_292] = 0x2fff, + [WM8915_WRITE_SEQUENCER_296] = 0x2fff, + [WM8915_WRITE_SEQUENCER_300] = 0x2fff, + [WM8915_WRITE_SEQUENCER_304] = 0x2fff, + [WM8915_WRITE_SEQUENCER_308] = 0x2fff, + [WM8915_WRITE_SEQUENCER_312] = 0x2fff, + [WM8915_WRITE_SEQUENCER_316] = 0x2fff, + [WM8915_WRITE_SEQUENCER_320] = 0x61, + [WM8915_WRITE_SEQUENCER_322] = 0x601, + [WM8915_WRITE_SEQUENCER_324] = 0x50, + [WM8915_WRITE_SEQUENCER_326] = 0x102, + [WM8915_WRITE_SEQUENCER_328] = 0x1, + [WM8915_WRITE_SEQUENCER_330] = 0x106, + [WM8915_WRITE_SEQUENCER_331] = 0x100, + [WM8915_WRITE_SEQUENCER_332] = 0x2fff, + [WM8915_WRITE_SEQUENCER_336] = 0x2fff, + [WM8915_WRITE_SEQUENCER_340] = 0x2fff, + [WM8915_WRITE_SEQUENCER_344] = 0x2fff, + [WM8915_WRITE_SEQUENCER_348] = 0x2fff, + [WM8915_WRITE_SEQUENCER_352] = 0x2fff, + [WM8915_WRITE_SEQUENCER_356] = 0x2fff, + [WM8915_WRITE_SEQUENCER_360] = 0x2fff, + [WM8915_WRITE_SEQUENCER_364] = 0x2fff, + [WM8915_WRITE_SEQUENCER_368] = 0x2fff, + [WM8915_WRITE_SEQUENCER_372] = 0x2fff, + [WM8915_WRITE_SEQUENCER_376] = 0x2fff, + [WM8915_WRITE_SEQUENCER_380] = 0x2fff, + [WM8915_WRITE_SEQUENCER_384] = 0x60, + [WM8915_WRITE_SEQUENCER_386] = 0x601, + [WM8915_WRITE_SEQUENCER_388] = 0x61, + [WM8915_WRITE_SEQUENCER_390] = 0x601, + [WM8915_WRITE_SEQUENCER_392] = 0x50, + [WM8915_WRITE_SEQUENCER_394] = 0x300, + [WM8915_WRITE_SEQUENCER_396] = 0x1, + [WM8915_WRITE_SEQUENCER_398] = 0x304, + [WM8915_WRITE_SEQUENCER_400] = 0x40, + [WM8915_WRITE_SEQUENCER_402] = 0xf, + [WM8915_WRITE_SEQUENCER_404] = 0x1, + [WM8915_WRITE_SEQUENCER_407] = 0x100, +}; + +static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0); +static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0); +static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); +static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0); +static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0); +static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); + +static const char *sidetone_hpf_text[] = { + "2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz" +}; + +static const struct soc_enum sidetone_hpf = + SOC_ENUM_SINGLE(WM8915_SIDETONE, 7, 6, sidetone_hpf_text); + +static const char *hpf_mode_text[] = { + "HiFi", "Custom", "Voice" +}; + +static const struct soc_enum dsp1tx_hpf_mode = + SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 3, 3, hpf_mode_text); + +static const struct soc_enum dsp2tx_hpf_mode = + SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 3, 3, hpf_mode_text); + +static const char *hpf_cutoff_text[] = { + "50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" +}; + +static const struct soc_enum dsp1tx_hpf_cutoff = + SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text); + +static const struct soc_enum dsp2tx_hpf_cutoff = + SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text); + +static void wm8915_set_retune_mobile(struct snd_soc_codec *codec, int block) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + struct wm8915_pdata *pdata = &wm8915->pdata; + int base, best, best_val, save, i, cfg, iface; + + if (!wm8915->num_retune_mobile_texts) + return; + + switch (block) { + case 0: + base = WM8915_DSP1_RX_EQ_GAINS_1; + if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) & + WM8915_DSP1RX_SRC) + iface = 1; + else + iface = 0; + break; + case 1: + base = WM8915_DSP1_RX_EQ_GAINS_2; + if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) & + WM8915_DSP2RX_SRC) + iface = 1; + else + iface = 0; + break; + default: + return; + } + + /* Find the version of the currently selected configuration + * with the nearest sample rate. */ + cfg = wm8915->retune_mobile_cfg[block]; + best = 0; + best_val = INT_MAX; + for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { + if (strcmp(pdata->retune_mobile_cfgs[i].name, + wm8915->retune_mobile_texts[cfg]) == 0 && + abs(pdata->retune_mobile_cfgs[i].rate + - wm8915->rx_rate[iface]) < best_val) { + best = i; + best_val = abs(pdata->retune_mobile_cfgs[i].rate + - wm8915->rx_rate[iface]); + } + } + + dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n", + block, + pdata->retune_mobile_cfgs[best].name, + pdata->retune_mobile_cfgs[best].rate, + wm8915->rx_rate[iface]); + + /* The EQ will be disabled while reconfiguring it, remember the + * current configuration. + */ + save = snd_soc_read(codec, base); + save &= WM8915_DSP1RX_EQ_ENA; + + for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++) + snd_soc_update_bits(codec, base + i, 0xffff, + pdata->retune_mobile_cfgs[best].regs[i]); + + snd_soc_update_bits(codec, base, WM8915_DSP1RX_EQ_ENA, save); +} + +/* Icky as hell but saves code duplication */ +static int wm8915_get_retune_mobile_block(const char *name) +{ + if (strcmp(name, "DSP1 EQ Mode") == 0) + return 0; + if (strcmp(name, "DSP2 EQ Mode") == 0) + return 1; + return -EINVAL; +} + +static int wm8915_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + struct wm8915_pdata *pdata = &wm8915->pdata; + int block = wm8915_get_retune_mobile_block(kcontrol->id.name); + int value = ucontrol->value.integer.value[0]; + + if (block < 0) + return block; + + if (value >= pdata->num_retune_mobile_cfgs) + return -EINVAL; + + wm8915->retune_mobile_cfg[block] = value; + + wm8915_set_retune_mobile(codec, block); + + return 0; +} + +static int wm8915_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + int block = wm8915_get_retune_mobile_block(kcontrol->id.name); + + ucontrol->value.enumerated.item[0] = wm8915->retune_mobile_cfg[block]; + + return 0; +} + +static const struct snd_kcontrol_new wm8915_snd_controls[] = { +SOC_DOUBLE_R_TLV("Capture Volume", WM8915_LEFT_LINE_INPUT_VOLUME, + WM8915_RIGHT_LINE_INPUT_VOLUME, 0, 31, 0, inpga_tlv), +SOC_DOUBLE_R("Capture ZC Switch", WM8915_LEFT_LINE_INPUT_VOLUME, + WM8915_RIGHT_LINE_INPUT_VOLUME, 5, 1, 0), + +SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8915_DAC1_MIXER_VOLUMES, + 0, 5, 24, 0, sidetone_tlv), +SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8915_DAC2_MIXER_VOLUMES, + 0, 5, 24, 0, sidetone_tlv), +SOC_SINGLE("Sidetone LPF Switch", WM8915_SIDETONE, 12, 1, 0), +SOC_ENUM("Sidetone HPF Cut-off", sidetone_hpf), +SOC_SINGLE("Sidetone HPF Switch", WM8915_SIDETONE, 6, 1, 0), + +SOC_DOUBLE_R_TLV("DSP1 Capture Volume", WM8915_DSP1_TX_LEFT_VOLUME, + WM8915_DSP1_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv), +SOC_DOUBLE_R_TLV("DSP2 Capture Volume", WM8915_DSP2_TX_LEFT_VOLUME, + WM8915_DSP2_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv), + +SOC_SINGLE("DSP1 Capture Notch Filter Switch", WM8915_DSP1_TX_FILTERS, + 13, 1, 0), +SOC_DOUBLE("DSP1 Capture HPF Switch", WM8915_DSP1_TX_FILTERS, 12, 11, 1, 0), +SOC_ENUM("DSP1 Capture HPF Mode", dsp1tx_hpf_mode), +SOC_ENUM("DSP1 Capture HPF Cutoff", dsp1tx_hpf_cutoff), + +SOC_SINGLE("DSP2 Capture Notch Filter Switch", WM8915_DSP2_TX_FILTERS, + 13, 1, 0), +SOC_DOUBLE("DSP2 Capture HPF Switch", WM8915_DSP2_TX_FILTERS, 12, 11, 1, 0), +SOC_ENUM("DSP2 Capture HPF Mode", dsp2tx_hpf_mode), +SOC_ENUM("DSP2 Capture HPF Cutoff", dsp2tx_hpf_cutoff), + +SOC_DOUBLE_R_TLV("DSP1 Playback Volume", WM8915_DSP1_RX_LEFT_VOLUME, + WM8915_DSP1_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv), +SOC_SINGLE("DSP1 Playback Switch", WM8915_DSP1_RX_FILTERS_1, 9, 1, 1), + +SOC_DOUBLE_R_TLV("DSP2 Playback Volume", WM8915_DSP2_RX_LEFT_VOLUME, + WM8915_DSP2_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv), +SOC_SINGLE("DSP2 Playback Switch", WM8915_DSP2_RX_FILTERS_1, 9, 1, 1), + +SOC_DOUBLE_R_TLV("DAC1 Volume", WM8915_DAC1_LEFT_VOLUME, + WM8915_DAC1_RIGHT_VOLUME, 1, 112, 0, digital_tlv), +SOC_DOUBLE_R("DAC1 Switch", WM8915_DAC1_LEFT_VOLUME, + WM8915_DAC1_RIGHT_VOLUME, 9, 1, 1), + +SOC_DOUBLE_R_TLV("DAC2 Volume", WM8915_DAC2_LEFT_VOLUME, + WM8915_DAC2_RIGHT_VOLUME, 1, 112, 0, digital_tlv), +SOC_DOUBLE_R("DAC2 Switch", WM8915_DAC2_LEFT_VOLUME, + WM8915_DAC2_RIGHT_VOLUME, 9, 1, 1), + +SOC_SINGLE("Speaker High Performance Switch", WM8915_OVERSAMPLING, 3, 1, 0), +SOC_SINGLE("DMIC High Performance Switch", WM8915_OVERSAMPLING, 2, 1, 0), +SOC_SINGLE("ADC High Performance Switch", WM8915_OVERSAMPLING, 1, 1, 0), +SOC_SINGLE("DAC High Performance Switch", WM8915_OVERSAMPLING, 0, 1, 0), + +SOC_SINGLE("DAC Soft Mute Switch", WM8915_DAC_SOFTMUTE, 1, 1, 0), +SOC_SINGLE("DAC Slow Soft Mute Switch", WM8915_DAC_SOFTMUTE, 0, 1, 0), + +SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8915_DAC1_HPOUT1_VOLUME, 0, 4, + 8, 0, out_digital_tlv), +SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8915_DAC2_HPOUT2_VOLUME, 0, 4, + 8, 0, out_digital_tlv), + +SOC_DOUBLE_R_TLV("Output 1 Volume", WM8915_OUTPUT1_LEFT_VOLUME, + WM8915_OUTPUT1_RIGHT_VOLUME, 0, 12, 0, out_tlv), +SOC_DOUBLE_R("Output 1 ZC Switch", WM8915_OUTPUT1_LEFT_VOLUME, + WM8915_OUTPUT1_RIGHT_VOLUME, 7, 1, 0), + +SOC_DOUBLE_R_TLV("Output 2 Volume", WM8915_OUTPUT2_LEFT_VOLUME, + WM8915_OUTPUT2_RIGHT_VOLUME, 0, 12, 0, out_tlv), +SOC_DOUBLE_R("Output 2 ZC Switch", WM8915_OUTPUT2_LEFT_VOLUME, + WM8915_OUTPUT2_RIGHT_VOLUME, 7, 1, 0), + +SOC_DOUBLE_TLV("Speaker Volume", WM8915_PDM_SPEAKER_VOLUME, 0, 4, 8, 0, + spk_tlv), +SOC_DOUBLE_R("Speaker Switch", WM8915_LEFT_PDM_SPEAKER, + WM8915_RIGHT_PDM_SPEAKER, 3, 1, 1), +SOC_DOUBLE_R("Speaker ZC Switch", WM8915_LEFT_PDM_SPEAKER, + WM8915_RIGHT_PDM_SPEAKER, 2, 1, 0), + +SOC_SINGLE("DSP1 EQ Switch", WM8915_DSP1_RX_EQ_GAINS_1, 0, 1, 0), +SOC_SINGLE("DSP2 EQ Switch", WM8915_DSP2_RX_EQ_GAINS_1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new wm8915_eq_controls[] = { +SOC_SINGLE_TLV("DSP1 EQ B1 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("DSP1 EQ B2 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 6, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("DSP1 EQ B3 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 1, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("DSP1 EQ B4 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("DSP1 EQ B5 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 6, 31, 0, + eq_tlv), + +SOC_SINGLE_TLV("DSP2 EQ B1 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("DSP2 EQ B2 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 6, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("DSP2 EQ B3 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 1, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("DSP2 EQ B4 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 11, 31, 0, + eq_tlv), +SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 6, 31, 0, + eq_tlv), +}; + +static int cp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msleep(5); + break; + default: + BUG(); + return -EINVAL; + } + + return 0; +} + +static int rmv_short_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec); + + /* Record which outputs we enabled */ + switch (event) { + case SND_SOC_DAPM_PRE_PMD: + wm8915->hpout_pending &= ~w->shift; + break; + case SND_SOC_DAPM_PRE_PMU: + wm8915->hpout_pending |= w->shift; + break; + default: + BUG(); + return -EINVAL; + } + + return 0; +} + +static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask) +{ + struct i2c_client *i2c = to_i2c_client(codec->dev); + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + int i, ret; + unsigned long timeout = 200; + + snd_soc_write(codec, WM8915_DC_SERVO_2, mask); + + /* Use the interrupt if possible */ + do { + if (i2c->irq) { + timeout = wait_for_completion_timeout(&wm8915->dcs_done, + msecs_to_jiffies(200)); + if (timeout == 0) + dev_err(codec->dev, "DC servo timed out\n"); + + } else { + msleep(1); + if (--i) { + timeout = 0; + break; + } + } + + ret = snd_soc_read(codec, WM8915_DC_SERVO_2); + dev_dbg(codec->dev, "DC servo state: %x\n", ret); + } while (ret & mask); + + if (timeout == 0) + dev_err(codec->dev, "DC servo timed out for %x\n", mask); + else + dev_dbg(codec->dev, "DC servo complete for %x\n", mask); +} + +static void wm8915_seq_notifier(struct snd_soc_dapm_context *dapm, + enum snd_soc_dapm_type event, int subseq) +{ + struct snd_soc_codec *codec = container_of(dapm, + struct snd_soc_codec, dapm); + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + u16 val, mask; + + /* Complete any pending DC servo starts */ + if (wm8915->dcs_pending) { + dev_dbg(codec->dev, "Starting DC servo for %x\n", + wm8915->dcs_pending); + + /* Trigger a startup sequence */ + wait_for_dc_servo(codec, wm8915->dcs_pending + << WM8915_DCS_TRIG_STARTUP_0_SHIFT); + + wm8915->dcs_pending = 0; + } + + if (wm8915->hpout_pending != wm8915->hpout_ena) { + dev_dbg(codec->dev, "Applying RMV_SHORTs %x->%x\n", + wm8915->hpout_ena, wm8915->hpout_pending); + + val = 0; + mask = 0; + if (wm8915->hpout_pending & HPOUT1L) { + val |= WM8915_HPOUT1L_RMV_SHORT; + mask |= WM8915_HPOUT1L_RMV_SHORT; + } else { + mask |= WM8915_HPOUT1L_RMV_SHORT | + WM8915_HPOUT1L_OUTP | + WM8915_HPOUT1L_DLY; + } + + if (wm8915->hpout_pending & HPOUT1R) { + val |= WM8915_HPOUT1R_RMV_SHORT; + mask |= WM8915_HPOUT1R_RMV_SHORT; + } else { + mask |= WM8915_HPOUT1R_RMV_SHORT | + WM8915_HPOUT1R_OUTP | + WM8915_HPOUT1R_DLY; + } + + snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_1, mask, val); + + val = 0; + mask = 0; + if (wm8915->hpout_pending & HPOUT2L) { + val |= WM8915_HPOUT2L_RMV_SHORT; + mask |= WM8915_HPOUT2L_RMV_SHORT; + } else { + mask |= WM8915_HPOUT2L_RMV_SHORT | + WM8915_HPOUT2L_OUTP | + WM8915_HPOUT2L_DLY; + } + + if (wm8915->hpout_pending & HPOUT2R) { + val |= WM8915_HPOUT2R_RMV_SHORT; + mask |= WM8915_HPOUT2R_RMV_SHORT; + } else { + mask |= WM8915_HPOUT2R_RMV_SHORT | + WM8915_HPOUT2R_OUTP | + WM8915_HPOUT2R_DLY; + } + + snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_2, mask, val); + + wm8915->hpout_ena = wm8915->hpout_pending; + } +} + +static int dcs_start(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + wm8915->dcs_pending |= 1 << w->shift; + break; + default: + BUG(); + return -EINVAL; + } + + return 0; +} + +static const char *sidetone_text[] = { + "IN1", "IN2", +}; + +static const struct soc_enum left_sidetone_enum = + SOC_ENUM_SINGLE(WM8915_SIDETONE, 0, 2, sidetone_text); + +static const struct snd_kcontrol_new left_sidetone = + SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum); + +static const struct soc_enum right_sidetone_enum = + SOC_ENUM_SINGLE(WM8915_SIDETONE, 1, 2, sidetone_text); + +static const struct snd_kcontrol_new right_sidetone = + SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum); + +static const char *spk_text[] = { + "DAC1L", "DAC1R", "DAC2L", "DAC2R" +}; + +static const struct soc_enum spkl_enum = + SOC_ENUM_SINGLE(WM8915_LEFT_PDM_SPEAKER, 0, 4, spk_text); + +static const struct snd_kcontrol_new spkl_mux = + SOC_DAPM_ENUM("SPKL", spkl_enum); + +static const struct soc_enum spkr_enum = + SOC_ENUM_SINGLE(WM8915_RIGHT_PDM_SPEAKER, 0, 4, spk_text); + +static const struct snd_kcontrol_new spkr_mux = + SOC_DAPM_ENUM("SPKR", spkr_enum); + +static const char *dsp1rx_text[] = { + "AIF1", "AIF2" +}; + +static const struct soc_enum dsp1rx_enum = + SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text); + +static const struct snd_kcontrol_new dsp1rx = + SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum); + +static const char *dsp2rx_text[] = { + "AIF2", "AIF1" +}; + +static const struct soc_enum dsp2rx_enum = + SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text); + +static const struct snd_kcontrol_new dsp2rx = + SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum); + +static const char *aif2tx_text[] = { + "DSP2", "DSP1", "AIF1" +}; + +static const struct soc_enum aif2tx_enum = + SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 6, 3, aif2tx_text); + +static const struct snd_kcontrol_new aif2tx = + SOC_DAPM_ENUM("AIF2TX", aif2tx_enum); + +static const char *inmux_text[] = { + "ADC", "DMIC1", "DMIC2" +}; + +static const struct soc_enum in1_enum = + SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 0, 3, inmux_text); + +static const struct snd_kcontrol_new in1_mux = + SOC_DAPM_ENUM("IN1 Mux", in1_enum); + +static const struct soc_enum in2_enum = + SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 4, 3, inmux_text); + +static const struct snd_kcontrol_new in2_mux = + SOC_DAPM_ENUM("IN2 Mux", in2_enum); + +static const struct snd_kcontrol_new dac2r_mix[] = { +SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, + 5, 1, 0), +SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, + 4, 1, 0), +SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0), +SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0), +}; + +static const struct snd_kcontrol_new dac2l_mix[] = { +SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, + 5, 1, 0), +SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, + 4, 1, 0), +SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 1, 1, 0), +SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 0, 1, 0), +}; + +static const struct snd_kcontrol_new dac1r_mix[] = { +SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, + 5, 1, 0), +SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, + 4, 1, 0), +SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 1, 1, 0), +SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 0, 1, 0), +}; + +static const struct snd_kcontrol_new dac1l_mix[] = { +SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, + 5, 1, 0), +SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, + 4, 1, 0), +SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 1, 1, 0), +SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 0, 1, 0), +}; + +static const struct snd_kcontrol_new dsp1txl[] = { +SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING, + 1, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING, + 0, 1, 0), +}; + +static const struct snd_kcontrol_new dsp1txr[] = { +SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING, + 1, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING, + 0, 1, 0), +}; + +static const struct snd_kcontrol_new dsp2txl[] = { +SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING, + 1, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING, + 0, 1, 0), +}; + +static const struct snd_kcontrol_new dsp2txr[] = { +SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING, + 1, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING, + 0, 1, 0), +}; + + +static const struct snd_soc_dapm_widget wm8915_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN1LN"), +SND_SOC_DAPM_INPUT("IN1LP"), +SND_SOC_DAPM_INPUT("IN1RN"), +SND_SOC_DAPM_INPUT("IN1RP"), + +SND_SOC_DAPM_INPUT("IN2LN"), +SND_SOC_DAPM_INPUT("IN2LP"), +SND_SOC_DAPM_INPUT("IN2RN"), +SND_SOC_DAPM_INPUT("IN2RP"), + +SND_SOC_DAPM_INPUT("DMIC1DAT"), +SND_SOC_DAPM_INPUT("DMIC2DAT"), + +SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8915_AIF_CLOCKING_1, 0, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8915_CLOCKING_1, 1, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8915_CLOCKING_1, 2, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8915_CHARGE_PUMP_1, 15, 0, cp_event, + SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_SUPPLY("LDO2", WM8915_POWER_MANAGEMENT_2, 1, 0, NULL, 0), +SND_SOC_DAPM_MICBIAS("MICB2", WM8915_POWER_MANAGEMENT_1, 9, 0), +SND_SOC_DAPM_MICBIAS("MICB1", WM8915_POWER_MANAGEMENT_1, 8, 0), + +SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0), + +SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux), +SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux), +SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux), +SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux), + +SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0), +SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0), +SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0), + +SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8915_POWER_MANAGEMENT_3, 5, 0), +SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8915_POWER_MANAGEMENT_3, 4, 0), +SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8915_POWER_MANAGEMENT_3, 3, 0), +SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8915_POWER_MANAGEMENT_3, 2, 0), + +SND_SOC_DAPM_ADC("ADCL", NULL, WM8915_POWER_MANAGEMENT_3, 1, 0), +SND_SOC_DAPM_ADC("ADCR", NULL, WM8915_POWER_MANAGEMENT_3, 0, 0), + +SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &left_sidetone), +SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &right_sidetone), + +SND_SOC_DAPM_AIF_IN("DSP2RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 11, 0), +SND_SOC_DAPM_AIF_IN("DSP2RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 10, 0), +SND_SOC_DAPM_AIF_IN("DSP1RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 9, 0), +SND_SOC_DAPM_AIF_IN("DSP1RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 8, 0), + +SND_SOC_DAPM_MIXER("DSP2TXL", WM8915_POWER_MANAGEMENT_5, 11, 0, + dsp2txl, ARRAY_SIZE(dsp2txl)), +SND_SOC_DAPM_MIXER("DSP2TXR", WM8915_POWER_MANAGEMENT_5, 10, 0, + dsp2txr, ARRAY_SIZE(dsp2txr)), +SND_SOC_DAPM_MIXER("DSP1TXL", WM8915_POWER_MANAGEMENT_5, 9, 0, + dsp1txl, ARRAY_SIZE(dsp1txl)), +SND_SOC_DAPM_MIXER("DSP1TXR", WM8915_POWER_MANAGEMENT_5, 8, 0, + dsp1txr, ARRAY_SIZE(dsp1txr)), + +SND_SOC_DAPM_MIXER("DAC2L Mixer", SND_SOC_NOPM, 0, 0, + dac2l_mix, ARRAY_SIZE(dac2l_mix)), +SND_SOC_DAPM_MIXER("DAC2R Mixer", SND_SOC_NOPM, 0, 0, + dac2r_mix, ARRAY_SIZE(dac2r_mix)), +SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0, + dac1l_mix, ARRAY_SIZE(dac1l_mix)), +SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0, + dac1r_mix, ARRAY_SIZE(dac1r_mix)), + +SND_SOC_DAPM_DAC("DAC2L", NULL, WM8915_POWER_MANAGEMENT_5, 3, 0), +SND_SOC_DAPM_DAC("DAC2R", NULL, WM8915_POWER_MANAGEMENT_5, 2, 0), +SND_SOC_DAPM_DAC("DAC1L", NULL, WM8915_POWER_MANAGEMENT_5, 1, 0), +SND_SOC_DAPM_DAC("DAC1R", NULL, WM8915_POWER_MANAGEMENT_5, 0, 0), + +SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 1, + WM8915_POWER_MANAGEMENT_4, 9, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 2, + WM8915_POWER_MANAGEMENT_4, 8, 0), + +SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 1, + WM8915_POWER_MANAGEMENT_6, 9, 0), +SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 2, + WM8915_POWER_MANAGEMENT_6, 8, 0), + +SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5, + WM8915_POWER_MANAGEMENT_4, 5, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4, + WM8915_POWER_MANAGEMENT_4, 4, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3, + WM8915_POWER_MANAGEMENT_4, 3, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2, + WM8915_POWER_MANAGEMENT_4, 2, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1, + WM8915_POWER_MANAGEMENT_4, 1, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0, + WM8915_POWER_MANAGEMENT_4, 0, 0), + +SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5, + WM8915_POWER_MANAGEMENT_6, 5, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4, + WM8915_POWER_MANAGEMENT_6, 4, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3, + WM8915_POWER_MANAGEMENT_6, 3, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2, + WM8915_POWER_MANAGEMENT_6, 2, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1, + WM8915_POWER_MANAGEMENT_6, 1, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0, + WM8915_POWER_MANAGEMENT_6, 0, 0), + +/* We route as stereo pairs so define some dummy widgets to squash + * things down for now. RXA = 0,1, RXB = 2,3 and so on */ +SND_SOC_DAPM_PGA("AIF1RXA", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("AIF1RXB", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("AIF1RXC", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("AIF2RX", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("DSP2TX", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_MUX("DSP1RX", SND_SOC_NOPM, 0, 0, &dsp1rx), +SND_SOC_DAPM_MUX("DSP2RX", SND_SOC_NOPM, 0, 0, &dsp2rx), +SND_SOC_DAPM_MUX("AIF2TX", SND_SOC_NOPM, 0, 0, &aif2tx), + +SND_SOC_DAPM_MUX("SPKL", SND_SOC_NOPM, 0, 0, &spkl_mux), +SND_SOC_DAPM_MUX("SPKR", SND_SOC_NOPM, 0, 0, &spkr_mux), +SND_SOC_DAPM_PGA("SPKL PGA", WM8915_LEFT_PDM_SPEAKER, 4, 0, NULL, 0), +SND_SOC_DAPM_PGA("SPKR PGA", WM8915_RIGHT_PDM_SPEAKER, 4, 0, NULL, 0), + +SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8915_POWER_MANAGEMENT_1, 7, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8915_ANALOGUE_HP_2, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8915_DC_SERVO_1, 2, 0, dcs_start, + SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8915_ANALOGUE_HP_2, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0, + rmv_short_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8915_POWER_MANAGEMENT_1, 6, 0,NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8915_ANALOGUE_HP_2, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8915_DC_SERVO_1, 3, 0, dcs_start, + SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8915_ANALOGUE_HP_2, 2, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0, + rmv_short_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8915_POWER_MANAGEMENT_1, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8915_ANALOGUE_HP_1, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8915_DC_SERVO_1, 0, 0, dcs_start, + SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8915_ANALOGUE_HP_1, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0, + rmv_short_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8915_POWER_MANAGEMENT_1, 4, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8915_ANALOGUE_HP_1, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8915_DC_SERVO_1, 1, 0, dcs_start, + SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8915_ANALOGUE_HP_1, 2, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0, + rmv_short_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_OUTPUT("HPOUT1L"), +SND_SOC_DAPM_OUTPUT("HPOUT1R"), +SND_SOC_DAPM_OUTPUT("HPOUT2L"), +SND_SOC_DAPM_OUTPUT("HPOUT2R"), +SND_SOC_DAPM_OUTPUT("SPKDAT"), +}; + +static const struct snd_soc_dapm_route wm8915_dapm_routes[] = { + { "AIFCLK", NULL, "SYSCLK" }, + { "SYSDSPCLK", NULL, "SYSCLK" }, + { "Charge Pump", NULL, "SYSCLK" }, + + { "MICB1", NULL, "LDO2" }, + { "MICB2", NULL, "LDO2" }, + + { "IN1L PGA", NULL, "IN2LN" }, + { "IN1L PGA", NULL, "IN2LP" }, + { "IN1L PGA", NULL, "IN1LN" }, + { "IN1L PGA", NULL, "IN1LP" }, + + { "IN1R PGA", NULL, "IN2RN" }, + { "IN1R PGA", NULL, "IN2RP" }, + { "IN1R PGA", NULL, "IN1RN" }, + { "IN1R PGA", NULL, "IN1RP" }, + + { "ADCL", NULL, "IN1L PGA" }, + + { "ADCR", NULL, "IN1R PGA" }, + + { "DMIC1L", NULL, "DMIC1DAT" }, + { "DMIC1R", NULL, "DMIC1DAT" }, + { "DMIC2L", NULL, "DMIC2DAT" }, + { "DMIC2R", NULL, "DMIC2DAT" }, + + { "DMIC2L", NULL, "DMIC2" }, + { "DMIC2R", NULL, "DMIC2" }, + { "DMIC1L", NULL, "DMIC1" }, + { "DMIC1R", NULL, "DMIC1" }, + + { "IN1L Mux", "ADC", "ADCL" }, + { "IN1L Mux", "DMIC1", "DMIC1L" }, + { "IN1L Mux", "DMIC2", "DMIC2L" }, + + { "IN1R Mux", "ADC", "ADCR" }, + { "IN1R Mux", "DMIC1", "DMIC1R" }, + { "IN1R Mux", "DMIC2", "DMIC2R" }, + + { "IN2L Mux", "ADC", "ADCL" }, + { "IN2L Mux", "DMIC1", "DMIC1L" }, + { "IN2L Mux", "DMIC2", "DMIC2L" }, + + { "IN2R Mux", "ADC", "ADCR" }, + { "IN2R Mux", "DMIC1", "DMIC1R" }, + { "IN2R Mux", "DMIC2", "DMIC2R" }, + + { "Left Sidetone", "IN1", "IN1L Mux" }, + { "Left Sidetone", "IN2", "IN2L Mux" }, + + { "Right Sidetone", "IN1", "IN1R Mux" }, + { "Right Sidetone", "IN2", "IN2R Mux" }, + + { "DSP1TXL", "IN1 Switch", "IN1L Mux" }, + { "DSP1TXR", "IN1 Switch", "IN1R Mux" }, + + { "DSP2TXL", "IN1 Switch", "IN2L Mux" }, + { "DSP2TXR", "IN1 Switch", "IN2R Mux" }, + + { "AIF1TX0", NULL, "DSP1TXL" }, + { "AIF1TX1", NULL, "DSP1TXR" }, + { "AIF1TX2", NULL, "DSP2TXL" }, + { "AIF1TX3", NULL, "DSP2TXR" }, + { "AIF1TX4", NULL, "AIF2RX0" }, + { "AIF1TX5", NULL, "AIF2RX1" }, + + { "AIF1RX0", NULL, "AIFCLK" }, + { "AIF1RX1", NULL, "AIFCLK" }, + { "AIF1RX2", NULL, "AIFCLK" }, + { "AIF1RX3", NULL, "AIFCLK" }, + { "AIF1RX4", NULL, "AIFCLK" }, + { "AIF1RX5", NULL, "AIFCLK" }, + + { "AIF2RX0", NULL, "AIFCLK" }, + { "AIF2RX1", NULL, "AIFCLK" }, + + { "DSP1RXL", NULL, "SYSDSPCLK" }, + { "DSP1RXR", NULL, "SYSDSPCLK" }, + { "DSP2RXL", NULL, "SYSDSPCLK" }, + { "DSP2RXR", NULL, "SYSDSPCLK" }, + { "DSP1TXL", NULL, "SYSDSPCLK" }, + { "DSP1TXR", NULL, "SYSDSPCLK" }, + { "DSP2TXL", NULL, "SYSDSPCLK" }, + { "DSP2TXR", NULL, "SYSDSPCLK" }, + + { "AIF1RXA", NULL, "AIF1RX0" }, + { "AIF1RXA", NULL, "AIF1RX1" }, + { "AIF1RXB", NULL, "AIF1RX2" }, + { "AIF1RXB", NULL, "AIF1RX3" }, + { "AIF1RXC", NULL, "AIF1RX4" }, + { "AIF1RXC", NULL, "AIF1RX5" }, + + { "AIF2RX", NULL, "AIF2RX0" }, + { "AIF2RX", NULL, "AIF2RX1" }, + + { "AIF2TX", "DSP2", "DSP2TX" }, + { "AIF2TX", "DSP1", "DSP1RX" }, + { "AIF2TX", "AIF1", "AIF1RXC" }, + + { "DSP1RXL", NULL, "DSP1RX" }, + { "DSP1RXR", NULL, "DSP1RX" }, + { "DSP2RXL", NULL, "DSP2RX" }, + { "DSP2RXR", NULL, "DSP2RX" }, + + { "DSP2TX", NULL, "DSP2TXL" }, + { "DSP2TX", NULL, "DSP2TXR" }, + + { "DSP1RX", "AIF1", "AIF1RXA" }, + { "DSP1RX", "AIF2", "AIF2RX" }, + + { "DSP2RX", "AIF1", "AIF1RXB" }, + { "DSP2RX", "AIF2", "AIF2RX" }, + + { "DAC2L Mixer", "DSP2 Switch", "DSP2RXL" }, + { "DAC2L Mixer", "DSP1 Switch", "DSP1RXL" }, + { "DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" }, + { "DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" }, + + { "DAC2R Mixer", "DSP2 Switch", "DSP2RXR" }, + { "DAC2R Mixer", "DSP1 Switch", "DSP1RXR" }, + { "DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" }, + { "DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" }, + + { "DAC1L Mixer", "DSP2 Switch", "DSP2RXL" }, + { "DAC1L Mixer", "DSP1 Switch", "DSP1RXL" }, + { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" }, + { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" }, + + { "DAC1R Mixer", "DSP2 Switch", "DSP2RXR" }, + { "DAC1R Mixer", "DSP1 Switch", "DSP1RXR" }, + { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" }, + { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" }, + + { "DAC1L", NULL, "DAC1L Mixer" }, + { "DAC1R", NULL, "DAC1R Mixer" }, + { "DAC2L", NULL, "DAC2L Mixer" }, + { "DAC2R", NULL, "DAC2R Mixer" }, + + { "HPOUT2L PGA", NULL, "Charge Pump" }, + { "HPOUT2L PGA", NULL, "DAC2L" }, + { "HPOUT2L_DLY", NULL, "HPOUT2L PGA" }, + { "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" }, + { "HPOUT2L_OUTP", NULL, "HPOUT2L_DCS" }, + { "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" }, + + { "HPOUT2R PGA", NULL, "Charge Pump" }, + { "HPOUT2R PGA", NULL, "DAC2R" }, + { "HPOUT2R_DLY", NULL, "HPOUT2R PGA" }, + { "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" }, + { "HPOUT2R_OUTP", NULL, "HPOUT2R_DCS" }, + { "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" }, + + { "HPOUT1L PGA", NULL, "Charge Pump" }, + { "HPOUT1L PGA", NULL, "DAC1L" }, + { "HPOUT1L_DLY", NULL, "HPOUT1L PGA" }, + { "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" }, + { "HPOUT1L_OUTP", NULL, "HPOUT1L_DCS" }, + { "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" }, + + { "HPOUT1R PGA", NULL, "Charge Pump" }, + { "HPOUT1R PGA", NULL, "DAC1R" }, + { "HPOUT1R_DLY", NULL, "HPOUT1R PGA" }, + { "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" }, + { "HPOUT1R_OUTP", NULL, "HPOUT1R_DCS" }, + { "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_OUTP" }, + + { "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" }, + { "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" }, + { "HPOUT1L", NULL, "HPOUT1L_RMV_SHORT" }, + { "HPOUT1R", NULL, "HPOUT1R_RMV_SHORT" }, + + { "SPKL", "DAC1L", "DAC1L" }, + { "SPKL", "DAC1R", "DAC1R" }, + { "SPKL", "DAC2L", "DAC2L" }, + { "SPKL", "DAC2R", "DAC2R" }, + + { "SPKR", "DAC1L", "DAC1L" }, + { "SPKR", "DAC1R", "DAC1R" }, + { "SPKR", "DAC2L", "DAC2L" }, + { "SPKR", "DAC2R", "DAC2R" }, + + { "SPKL PGA", NULL, "SPKL" }, + { "SPKR PGA", NULL, "SPKR" }, + + { "SPKDAT", NULL, "SPKL PGA" }, + { "SPKDAT", NULL, "SPKR PGA" }, +}; + +static int wm8915_readable_register(struct snd_soc_codec *codec, + unsigned int reg) +{ + /* Due to the sparseness of the register map the compiler + * output from an explicit switch statement ends up being much + * more efficient than a table. + */ + switch (reg) { + case WM8915_SOFTWARE_RESET: + case WM8915_POWER_MANAGEMENT_1: + case WM8915_POWER_MANAGEMENT_2: + case WM8915_POWER_MANAGEMENT_3: + case WM8915_POWER_MANAGEMENT_4: + case WM8915_POWER_MANAGEMENT_5: + case WM8915_POWER_MANAGEMENT_6: + case WM8915_POWER_MANAGEMENT_7: + case WM8915_POWER_MANAGEMENT_8: + case WM8915_LEFT_LINE_INPUT_VOLUME: + case WM8915_RIGHT_LINE_INPUT_VOLUME: + case WM8915_LINE_INPUT_CONTROL: + case WM8915_DAC1_HPOUT1_VOLUME: + case WM8915_DAC2_HPOUT2_VOLUME: + case WM8915_DAC1_LEFT_VOLUME: + case WM8915_DAC1_RIGHT_VOLUME: + case WM8915_DAC2_LEFT_VOLUME: + case WM8915_DAC2_RIGHT_VOLUME: + case WM8915_OUTPUT1_LEFT_VOLUME: + case WM8915_OUTPUT1_RIGHT_VOLUME: + case WM8915_OUTPUT2_LEFT_VOLUME: + case WM8915_OUTPUT2_RIGHT_VOLUME: + case WM8915_MICBIAS_1: + case WM8915_MICBIAS_2: + case WM8915_LDO_1: + case WM8915_LDO_2: + case WM8915_ACCESSORY_DETECT_MODE_1: + case WM8915_ACCESSORY_DETECT_MODE_2: + case WM8915_HEADPHONE_DETECT_1: + case WM8915_HEADPHONE_DETECT_2: + case WM8915_MIC_DETECT_1: + case WM8915_MIC_DETECT_2: + case WM8915_MIC_DETECT_3: + case WM8915_CHARGE_PUMP_1: + case WM8915_CHARGE_PUMP_2: + case WM8915_DC_SERVO_1: + case WM8915_DC_SERVO_2: + case WM8915_DC_SERVO_3: + case WM8915_DC_SERVO_5: + case WM8915_DC_SERVO_6: + case WM8915_DC_SERVO_7: + case WM8915_DC_SERVO_READBACK_0: + case WM8915_ANALOGUE_HP_1: + case WM8915_ANALOGUE_HP_2: + case WM8915_CHIP_REVISION: + case WM8915_CONTROL_INTERFACE_1: + case WM8915_WRITE_SEQUENCER_CTRL_1: + case WM8915_WRITE_SEQUENCER_CTRL_2: + case WM8915_AIF_CLOCKING_1: + case WM8915_AIF_CLOCKING_2: + case WM8915_CLOCKING_1: + case WM8915_CLOCKING_2: + case WM8915_AIF_RATE: + case WM8915_FLL_CONTROL_1: + case WM8915_FLL_CONTROL_2: + case WM8915_FLL_CONTROL_3: + case WM8915_FLL_CONTROL_4: + case WM8915_FLL_CONTROL_5: + case WM8915_FLL_CONTROL_6: + case WM8915_FLL_EFS_1: + case WM8915_FLL_EFS_2: + case WM8915_AIF1_CONTROL: + case WM8915_AIF1_BCLK: + case WM8915_AIF1_TX_LRCLK_1: + case WM8915_AIF1_TX_LRCLK_2: + case WM8915_AIF1_RX_LRCLK_1: + case WM8915_AIF1_RX_LRCLK_2: + case WM8915_AIF1TX_DATA_CONFIGURATION_1: + case WM8915_AIF1TX_DATA_CONFIGURATION_2: + case WM8915_AIF1RX_DATA_CONFIGURATION: + case WM8915_AIF1TX_CHANNEL_0_CONFIGURATION: + case WM8915_AIF1TX_CHANNEL_1_CONFIGURATION: + case WM8915_AIF1TX_CHANNEL_2_CONFIGURATION: + case WM8915_AIF1TX_CHANNEL_3_CONFIGURATION: + case WM8915_AIF1TX_CHANNEL_4_CONFIGURATION: + case WM8915_AIF1TX_CHANNEL_5_CONFIGURATION: + case WM8915_AIF1RX_CHANNEL_0_CONFIGURATION: + case WM8915_AIF1RX_CHANNEL_1_CONFIGURATION: + case WM8915_AIF1RX_CHANNEL_2_CONFIGURATION: + case WM8915_AIF1RX_CHANNEL_3_CONFIGURATION: + case WM8915_AIF1RX_CHANNEL_4_CONFIGURATION: + case WM8915_AIF1RX_CHANNEL_5_CONFIGURATION: + case WM8915_AIF1RX_MONO_CONFIGURATION: + case WM8915_AIF1TX_TEST: + case WM8915_AIF2_CONTROL: + case WM8915_AIF2_BCLK: + case WM8915_AIF2_TX_LRCLK_1: + case WM8915_AIF2_TX_LRCLK_2: + case WM8915_AIF2_RX_LRCLK_1: + case WM8915_AIF2_RX_LRCLK_2: + case WM8915_AIF2TX_DATA_CONFIGURATION_1: + case WM8915_AIF2TX_DATA_CONFIGURATION_2: + case WM8915_AIF2RX_DATA_CONFIGURATION: + case WM8915_AIF2TX_CHANNEL_0_CONFIGURATION: + case WM8915_AIF2TX_CHANNEL_1_CONFIGURATION: + case WM8915_AIF2RX_CHANNEL_0_CONFIGURATION: + case WM8915_AIF2RX_CHANNEL_1_CONFIGURATION: + case WM8915_AIF2RX_MONO_CONFIGURATION: + case WM8915_AIF2TX_TEST: + case WM8915_DSP1_TX_LEFT_VOLUME: + case WM8915_DSP1_TX_RIGHT_VOLUME: + case WM8915_DSP1_RX_LEFT_VOLUME: + case WM8915_DSP1_RX_RIGHT_VOLUME: + case WM8915_DSP1_TX_FILTERS: + case WM8915_DSP1_RX_FILTERS_1: + case WM8915_DSP1_RX_FILTERS_2: + case WM8915_DSP1_DRC_1: + case WM8915_DSP1_DRC_2: + case WM8915_DSP1_DRC_3: + case WM8915_DSP1_DRC_4: + case WM8915_DSP1_DRC_5: + case WM8915_DSP1_RX_EQ_GAINS_1: + case WM8915_DSP1_RX_EQ_GAINS_2: + case WM8915_DSP1_RX_EQ_BAND_1_A: + case WM8915_DSP1_RX_EQ_BAND_1_B: + case WM8915_DSP1_RX_EQ_BAND_1_PG: + case WM8915_DSP1_RX_EQ_BAND_2_A: + case WM8915_DSP1_RX_EQ_BAND_2_B: + case WM8915_DSP1_RX_EQ_BAND_2_C: + case WM8915_DSP1_RX_EQ_BAND_2_PG: + case WM8915_DSP1_RX_EQ_BAND_3_A: + case WM8915_DSP1_RX_EQ_BAND_3_B: + case WM8915_DSP1_RX_EQ_BAND_3_C: + case WM8915_DSP1_RX_EQ_BAND_3_PG: + case WM8915_DSP1_RX_EQ_BAND_4_A: + case WM8915_DSP1_RX_EQ_BAND_4_B: + case WM8915_DSP1_RX_EQ_BAND_4_C: + case WM8915_DSP1_RX_EQ_BAND_4_PG: + case WM8915_DSP1_RX_EQ_BAND_5_A: + case WM8915_DSP1_RX_EQ_BAND_5_B: + case WM8915_DSP1_RX_EQ_BAND_5_PG: + case WM8915_DSP2_TX_LEFT_VOLUME: + case WM8915_DSP2_TX_RIGHT_VOLUME: + case WM8915_DSP2_RX_LEFT_VOLUME: + case WM8915_DSP2_RX_RIGHT_VOLUME: + case WM8915_DSP2_TX_FILTERS: + case WM8915_DSP2_RX_FILTERS_1: + case WM8915_DSP2_RX_FILTERS_2: + case WM8915_DSP2_DRC_1: + case WM8915_DSP2_DRC_2: + case WM8915_DSP2_DRC_3: + case WM8915_DSP2_DRC_4: + case WM8915_DSP2_DRC_5: + case WM8915_DSP2_RX_EQ_GAINS_1: + case WM8915_DSP2_RX_EQ_GAINS_2: + case WM8915_DSP2_RX_EQ_BAND_1_A: + case WM8915_DSP2_RX_EQ_BAND_1_B: + case WM8915_DSP2_RX_EQ_BAND_1_PG: + case WM8915_DSP2_RX_EQ_BAND_2_A: + case WM8915_DSP2_RX_EQ_BAND_2_B: + case WM8915_DSP2_RX_EQ_BAND_2_C: + case WM8915_DSP2_RX_EQ_BAND_2_PG: + case WM8915_DSP2_RX_EQ_BAND_3_A: + case WM8915_DSP2_RX_EQ_BAND_3_B: + case WM8915_DSP2_RX_EQ_BAND_3_C: + case WM8915_DSP2_RX_EQ_BAND_3_PG: + case WM8915_DSP2_RX_EQ_BAND_4_A: + case WM8915_DSP2_RX_EQ_BAND_4_B: + case WM8915_DSP2_RX_EQ_BAND_4_C: + case WM8915_DSP2_RX_EQ_BAND_4_PG: + case WM8915_DSP2_RX_EQ_BAND_5_A: + case WM8915_DSP2_RX_EQ_BAND_5_B: + case WM8915_DSP2_RX_EQ_BAND_5_PG: + case WM8915_DAC1_MIXER_VOLUMES: + case WM8915_DAC1_LEFT_MIXER_ROUTING: + case WM8915_DAC1_RIGHT_MIXER_ROUTING: + case WM8915_DAC2_MIXER_VOLUMES: + case WM8915_DAC2_LEFT_MIXER_ROUTING: + case WM8915_DAC2_RIGHT_MIXER_ROUTING: + case WM8915_DSP1_TX_LEFT_MIXER_ROUTING: + case WM8915_DSP1_TX_RIGHT_MIXER_ROUTING: + case WM8915_DSP2_TX_LEFT_MIXER_ROUTING: + case WM8915_DSP2_TX_RIGHT_MIXER_ROUTING: + case WM8915_DSP_TX_MIXER_SELECT: + case WM8915_DAC_SOFTMUTE: + case WM8915_OVERSAMPLING: + case WM8915_SIDETONE: + case WM8915_GPIO_1: + case WM8915_GPIO_2: + case WM8915_GPIO_3: + case WM8915_GPIO_4: + case WM8915_GPIO_5: + case WM8915_PULL_CONTROL_1: + case WM8915_PULL_CONTROL_2: + case WM8915_INTERRUPT_STATUS_1: + case WM8915_INTERRUPT_STATUS_2: + case WM8915_INTERRUPT_RAW_STATUS_2: + case WM8915_INTERRUPT_STATUS_1_MASK: + case WM8915_INTERRUPT_STATUS_2_MASK: + case WM8915_INTERRUPT_CONTROL: + case WM8915_LEFT_PDM_SPEAKER: + case WM8915_RIGHT_PDM_SPEAKER: + case WM8915_PDM_SPEAKER_MUTE_SEQUENCE: + case WM8915_PDM_SPEAKER_VOLUME: + return 1; + default: + return 0; + } +} + +static int wm8915_volatile_register(struct snd_soc_codec *codec, + unsigned int reg) +{ + switch (reg) { + case WM8915_SOFTWARE_RESET: + case WM8915_CHIP_REVISION: + case WM8915_LDO_1: + case WM8915_LDO_2: + case WM8915_INTERRUPT_STATUS_1: + case WM8915_INTERRUPT_STATUS_2: + case WM8915_INTERRUPT_RAW_STATUS_2: + case WM8915_DC_SERVO_READBACK_0: + case WM8915_DC_SERVO_2: + case WM8915_DC_SERVO_6: + case WM8915_DC_SERVO_7: + case WM8915_FLL_CONTROL_6: + case WM8915_MIC_DETECT_3: + case WM8915_HEADPHONE_DETECT_1: + case WM8915_HEADPHONE_DETECT_2: + return 1; + default: + return 0; + } +} + +static int wm8915_reset(struct snd_soc_codec *codec) +{ + return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915); +} + +static int wm8915_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { + snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1, + WM8915_BG_ENA, WM8915_BG_ENA); + msleep(2); + } + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies), + wm8915->supplies); + if (ret != 0) { + dev_err(codec->dev, + "Failed to enable supplies: %d\n", + ret); + return ret; + } + + if (wm8915->pdata.ldo_ena >= 0) { + gpio_set_value_cansleep(wm8915->pdata.ldo_ena, + 1); + msleep(5); + } + + codec->cache_only = false; + snd_soc_cache_sync(codec); + } + + snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1, + WM8915_BG_ENA, 0); + break; + + case SND_SOC_BIAS_OFF: + codec->cache_only = true; + if (wm8915->pdata.ldo_ena >= 0) + gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0); + regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), + wm8915->supplies); + break; + } + + codec->dapm.bias_level = level; + + return 0; +} + +static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + int aifctrl = 0; + int bclk = 0; + int lrclk_tx = 0; + int lrclk_rx = 0; + int aifctrl_reg, bclk_reg, lrclk_tx_reg, lrclk_rx_reg; + + switch (dai->id) { + case 0: + aifctrl_reg = WM8915_AIF1_CONTROL; + bclk_reg = WM8915_AIF1_BCLK; + lrclk_tx_reg = WM8915_AIF1_TX_LRCLK_2; + lrclk_rx_reg = WM8915_AIF1_RX_LRCLK_2; + break; + case 1: + aifctrl_reg = WM8915_AIF2_CONTROL; + bclk_reg = WM8915_AIF2_BCLK; + lrclk_tx_reg = WM8915_AIF2_TX_LRCLK_2; + lrclk_rx_reg = WM8915_AIF2_RX_LRCLK_2; + break; + default: + BUG(); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + bclk |= WM8915_AIF1_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + lrclk_tx |= WM8915_AIF1TX_LRCLK_INV; + lrclk_rx |= WM8915_AIF1RX_LRCLK_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + bclk |= WM8915_AIF1_BCLK_INV; + lrclk_tx |= WM8915_AIF1TX_LRCLK_INV; + lrclk_rx |= WM8915_AIF1RX_LRCLK_INV; + break; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + case SND_SOC_DAIFMT_CBS_CFM: + lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR; + lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + bclk |= WM8915_AIF1_BCLK_MSTR; + break; + case SND_SOC_DAIFMT_CBM_CFM: + bclk |= WM8915_AIF1_BCLK_MSTR; + lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR; + lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + break; + case SND_SOC_DAIFMT_DSP_B: + aifctrl |= 1; + break; + case SND_SOC_DAIFMT_I2S: + aifctrl |= 2; + break; + case SND_SOC_DAIFMT_LEFT_J: + aifctrl |= 3; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, aifctrl_reg, WM8915_AIF1_FMT_MASK, aifctrl); + snd_soc_update_bits(codec, bclk_reg, + WM8915_AIF1_BCLK_INV | WM8915_AIF1_BCLK_MSTR, + bclk); + snd_soc_update_bits(codec, lrclk_tx_reg, + WM8915_AIF1TX_LRCLK_INV | + WM8915_AIF1TX_LRCLK_MSTR, + lrclk_tx); + snd_soc_update_bits(codec, lrclk_rx_reg, + WM8915_AIF1RX_LRCLK_INV | + WM8915_AIF1RX_LRCLK_MSTR, + lrclk_rx); + + return 0; +} + +static const int bclk_divs[] = { + 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 +}; + +static const int dsp_divs[] = { + 48000, 32000, 16000, 8000 +}; + +static int wm8915_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 wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + int bits, i, bclk_rate, best, cur_val; + int aifdata = 0; + int bclk = 0; + int lrclk = 0; + int dsp = 0; + int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift; + + if (!wm8915->sysclk) { + dev_err(codec->dev, "SYSCLK not configured\n"); + return -EINVAL; + } + + switch (dai->id) { + case 0: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || + (snd_soc_read(codec, WM8915_GPIO_1)) & WM8915_GP1_FN_MASK) { + aifdata_reg = WM8915_AIF1RX_DATA_CONFIGURATION; + lrclk_reg = WM8915_AIF1_RX_LRCLK_1; + } else { + aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1; + lrclk_reg = WM8915_AIF1_TX_LRCLK_1; + } + bclk_reg = WM8915_AIF1_BCLK; + dsp_shift = 0; + break; + case 1: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || + (snd_soc_read(codec, WM8915_GPIO_2)) & WM8915_GP2_FN_MASK) { + aifdata_reg = WM8915_AIF2RX_DATA_CONFIGURATION; + lrclk_reg = WM8915_AIF2_RX_LRCLK_1; + } else { + aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1; + lrclk_reg = WM8915_AIF2_TX_LRCLK_1; + } + bclk_reg = WM8915_AIF2_BCLK; + dsp_shift = WM8915_DSP2_DIV_SHIFT; + break; + default: + BUG(); + return -EINVAL; + } + + bclk_rate = snd_soc_params_to_bclk(params); + if (bclk_rate < 0) { + dev_err(codec->dev, "Unsupported BCLK rate: %d\n", bclk_rate); + return bclk_rate; + } + + /* Needs looking at for TDM */ + bits = snd_pcm_format_width(params_format(params)); + if (bits < 0) + return bits; + aifdata |= (bits << WM8915_AIF1TX_WL_SHIFT) | bits; + + for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) { + if (dsp_divs[i] == params_rate(params)) + break; + } + if (i == ARRAY_SIZE(dsp_divs)) { + dev_err(codec->dev, "Unsupported sample rate %dHz\n", + params_rate(params)); + return -EINVAL; + } + dsp |= i << dsp_shift; + + /* Pick a divisor for BCLK as close as we can get to ideal */ + best = 0; + for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { + cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate; + if (cur_val < 0) /* BCLK table is sorted */ + break; + best = i; + } + bclk_rate = wm8915->sysclk / bclk_divs[best]; + dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", + bclk_divs[best], bclk_rate); + bclk |= best; + + lrclk = bclk_rate / params_rate(params); + dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n", + lrclk, bclk_rate / lrclk); + + snd_soc_update_bits(codec, aifdata_reg, + WM8915_AIF1TX_WL_MASK | + WM8915_AIF1TX_SLOT_LEN_MASK, + aifdata); + snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk); + snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK, + lrclk); + snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2, + WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp); + + wm8915->rx_rate[dai->id] = params_rate(params); + + return 0; +} + +static int wm8915_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + int lfclk = 0; + int ratediv = 0; + int src; + int old; + + /* Disable SYSCLK while we reconfigure */ + old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1); + snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, + WM8915_SYSCLK_ENA, 0); + + switch (clk_id) { + case WM8915_SYSCLK_MCLK1: + wm8915->sysclk = freq; + src = 0; + break; + case WM8915_SYSCLK_MCLK2: + wm8915->sysclk = freq; + src = 1; + break; + case WM8915_SYSCLK_FLL: + wm8915->sysclk = freq; + src = 2; + break; + default: + dev_err(codec->dev, "Unsupported clock source %d\n", clk_id); + return -EINVAL; + } + + switch (wm8915->sysclk) { + case 6144000: + snd_soc_update_bits(codec, WM8915_AIF_RATE, + WM8915_SYSCLK_RATE, 0); + break; + case 24576000: + ratediv = WM8915_SYSCLK_DIV; + case 12288000: + snd_soc_update_bits(codec, WM8915_AIF_RATE, + WM8915_SYSCLK_RATE, WM8915_SYSCLK_RATE); + break; + case 32000: + case 32768: + lfclk = WM8915_LFCLK_ENA; + break; + default: + dev_warn(codec->dev, "Unsupported clock rate %dHz\n", + wm8915->sysclk); + return -EINVAL; + } + + snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, + WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK, + src << WM8915_SYSCLK_SRC_SHIFT | ratediv); + snd_soc_update_bits(codec, WM8915_CLOCKING_1, WM8915_LFCLK_ENA, lfclk); + snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, + WM8915_SYSCLK_ENA, old); + + return 0; +} + +struct _fll_div { + u16 fll_fratio; + u16 fll_outdiv; + u16 fll_refclk_div; + u16 fll_loop_gain; + u16 fll_ref_freq; + u16 n; + u16 theta; + u16 lambda; +}; + +static struct { + unsigned int min; + unsigned int max; + u16 fll_fratio; + int ratio; +} fll_fratios[] = { + { 0, 64000, 4, 16 }, + { 64000, 128000, 3, 8 }, + { 128000, 256000, 2, 4 }, + { 256000, 1000000, 1, 2 }, + { 1000000, 13500000, 0, 1 }, +}; + +static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, + unsigned int Fout) +{ + unsigned int target; + unsigned int div; + unsigned int fratio, gcd_fll; + int i; + + /* Fref must be <=13.5MHz */ + div = 1; + fll_div->fll_refclk_div = 0; + while ((Fref / div) > 13500000) { + div *= 2; + fll_div->fll_refclk_div++; + + if (div > 8) { + pr_err("Can't scale %dMHz input down to <=13.5MHz\n", + Fref); + return -EINVAL; + } + } + + pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout); + + /* Apply the division for our remaining calculations */ + Fref /= div; + + if (Fref >= 3000000) + fll_div->fll_loop_gain = 5; + else + fll_div->fll_loop_gain = 0; + + if (Fref >= 48000) + fll_div->fll_ref_freq = 0; + else + fll_div->fll_ref_freq = 1; + + /* Fvco should be 90-100MHz; don't check the upper bound */ + div = 2; + while (Fout * div < 90000000) { + div++; + if (div > 64) { + pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n", + Fout); + return -EINVAL; + } + } + target = Fout * div; + fll_div->fll_outdiv = div - 1; + + pr_debug("FLL Fvco=%dHz\n", target); + + /* Find an appropraite FLL_FRATIO and factor it out of the target */ + for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { + if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { + fll_div->fll_fratio = fll_fratios[i].fll_fratio; + fratio = fll_fratios[i].ratio; + break; + } + } + if (i == ARRAY_SIZE(fll_fratios)) { + pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref); + return -EINVAL; + } + + fll_div->n = target / (fratio * Fref); + + if (target % Fref == 0) { + fll_div->theta = 0; + fll_div->lambda = 0; + } else { + gcd_fll = gcd(target, fratio * Fref); + + fll_div->theta = (target - (fll_div->n * fratio * Fref)) + / gcd_fll; + fll_div->lambda = (fratio * Fref) / gcd_fll; + } + + pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n", + fll_div->n, fll_div->theta, fll_div->lambda); + pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n", + fll_div->fll_fratio, fll_div->fll_outdiv, + fll_div->fll_refclk_div); + + return 0; +} + +static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, + unsigned int Fref, unsigned int Fout) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + struct _fll_div fll_div; + unsigned long timeout; + int ret, reg; + + /* Any change? */ + if (source == wm8915->fll_src && Fref == wm8915->fll_fref && + Fout == wm8915->fll_fout) + return 0; + + if (Fout == 0) { + dev_dbg(codec->dev, "FLL disabled\n"); + + wm8915->fll_fref = 0; + wm8915->fll_fout = 0; + + snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1, + WM8915_FLL_ENA, 0); + + return 0; + } + + ret = fll_factors(&fll_div, Fref, Fout); + if (ret != 0) + return ret; + + switch (source) { + case WM8915_FLL_MCLK1: + reg = 0; + break; + case WM8915_FLL_MCLK2: + reg = 1; + case WM8915_FLL_DACLRCLK1: + reg = 2; + break; + case WM8915_FLL_BCLK1: + reg = 3; + break; + default: + dev_err(codec->dev, "Unknown FLL source %d\n", ret); + return -EINVAL; + } + + reg |= fll_div.fll_refclk_div << WM8915_FLL_REFCLK_DIV_SHIFT; + reg |= fll_div.fll_ref_freq << WM8915_FLL_REF_FREQ_SHIFT; + + snd_soc_update_bits(codec, WM8915_FLL_CONTROL_5, + WM8915_FLL_REFCLK_DIV_MASK | WM8915_FLL_REF_FREQ | + WM8915_FLL_REFCLK_SRC_MASK, reg); + + reg = 0; + if (fll_div.theta || fll_div.lambda) + reg |= WM8915_FLL_EFS_ENA | (3 << WM8915_FLL_LFSR_SEL_SHIFT); + else + reg |= 1 << WM8915_FLL_LFSR_SEL_SHIFT; + snd_soc_write(codec, WM8915_FLL_EFS_2, reg); + + snd_soc_update_bits(codec, WM8915_FLL_CONTROL_2, + WM8915_FLL_OUTDIV_MASK | + WM8915_FLL_FRATIO_MASK, + (fll_div.fll_outdiv << WM8915_FLL_OUTDIV_SHIFT) | + (fll_div.fll_fratio)); + + snd_soc_write(codec, WM8915_FLL_CONTROL_3, fll_div.theta); + + snd_soc_update_bits(codec, WM8915_FLL_CONTROL_4, + WM8915_FLL_N_MASK | WM8915_FLL_LOOP_GAIN_MASK, + (fll_div.n << WM8915_FLL_N_SHIFT) | + fll_div.fll_loop_gain); + + snd_soc_write(codec, WM8915_FLL_EFS_1, fll_div.lambda); + + snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1, + WM8915_FLL_ENA, WM8915_FLL_ENA); + + /* The FLL supports live reconfiguration - kick that in case we were + * already enabled. + */ + snd_soc_write(codec, WM8915_FLL_CONTROL_6, WM8915_FLL_SWITCH_CLK); + + /* Wait for the FLL to lock, using the interrupt if possible */ + if (Fref > 1000000) + timeout = usecs_to_jiffies(300); + else + timeout = msecs_to_jiffies(2); + + wait_for_completion_timeout(&wm8915->fll_lock, timeout); + + dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); + + wm8915->fll_fref = Fref; + wm8915->fll_fout = Fout; + wm8915->fll_src = source; + + return 0; +} + +#ifdef CONFIG_GPIOLIB +static inline struct wm8915_priv *gpio_to_wm8915(struct gpio_chip *chip) +{ + return container_of(chip, struct wm8915_priv, gpio_chip); +} + +static void wm8915_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct wm8915_priv *wm8915 = gpio_to_wm8915(chip); + struct snd_soc_codec *codec = wm8915->codec; + + snd_soc_update_bits(codec, WM8915_GPIO_1 + offset, + WM8915_GP1_LVL, !!value << WM8915_GP1_LVL_SHIFT); +} + +static int wm8915_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct wm8915_priv *wm8915 = gpio_to_wm8915(chip); + struct snd_soc_codec *codec = wm8915->codec; + int val; + + val = (1 << WM8915_GP1_FN_SHIFT) | (!!value << WM8915_GP1_LVL_SHIFT); + + return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset, + WM8915_GP1_FN_MASK | WM8915_GP1_DIR | + WM8915_GP1_LVL, val); +} + +static int wm8915_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct wm8915_priv *wm8915 = gpio_to_wm8915(chip); + struct snd_soc_codec *codec = wm8915->codec; + int ret; + + ret = snd_soc_read(codec, WM8915_GPIO_1 + offset); + if (ret < 0) + return ret; + + return (ret & WM8915_GP1_LVL) != 0; +} + +static int wm8915_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct wm8915_priv *wm8915 = gpio_to_wm8915(chip); + struct snd_soc_codec *codec = wm8915->codec; + + return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset, + WM8915_GP1_FN_MASK | WM8915_GP1_DIR, + (1 << WM8915_GP1_FN_SHIFT) | + (1 << WM8915_GP1_DIR_SHIFT)); +} + +static struct gpio_chip wm8915_template_chip = { + .label = "wm8915", + .owner = THIS_MODULE, + .direction_output = wm8915_gpio_direction_out, + .set = wm8915_gpio_set, + .direction_input = wm8915_gpio_direction_in, + .get = wm8915_gpio_get, + .can_sleep = 1, +}; + +static void wm8915_init_gpio(struct snd_soc_codec *codec) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + int ret; + + wm8915->gpio_chip = wm8915_template_chip; + wm8915->gpio_chip.ngpio = 5; + wm8915->gpio_chip.dev = codec->dev; + + if (wm8915->pdata.gpio_base) + wm8915->gpio_chip.base = wm8915->pdata.gpio_base; + else + wm8915->gpio_chip.base = -1; + + ret = gpiochip_add(&wm8915->gpio_chip); + if (ret != 0) + dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); +} + +static void wm8915_free_gpio(struct snd_soc_codec *codec) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = gpiochip_remove(&wm8915->gpio_chip); + if (ret != 0) + dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); +} +#else +static void wm8915_init_gpio(struct snd_soc_codec *codec) +{ +} + +static void wm8915_free_gpio(struct snd_soc_codec *codec) +{ +} +#endif + +/** + * wm8915_detect - Enable default WM8915 jack detection + * + * The WM8915 has advanced accessory detection support for headsets. + * This function provides a default implementation which integrates + * the majority of this functionality with minimal user configuration. + * + * This will detect headset, headphone and short circuit button and + * will also detect inverted microphone ground connections and update + * the polarity of the connections. + */ +int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, + wm8915_polarity_fn polarity_cb) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + + wm8915->jack = jack; + wm8915->detecting = true; + wm8915->polarity_cb = polarity_cb; + + if (wm8915->polarity_cb) + wm8915->polarity_cb(codec, 0); + + /* Clear discarge to avoid noise during detection */ + snd_soc_update_bits(codec, WM8915_MICBIAS_1, + WM8915_MICB1_DISCH, 0); + snd_soc_update_bits(codec, WM8915_MICBIAS_2, + WM8915_MICB2_DISCH, 0); + + /* LDO2 powers the microphones, SYSCLK clocks detection */ + snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); + snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); + + /* We start off just enabling microphone detection - even a + * plain headphone will trigger detection. + */ + snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, + WM8915_MICD_ENA, WM8915_MICD_ENA); + + /* Slowest detection rate, gives debounce for initial detection */ + snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, + WM8915_MICD_RATE_MASK, + WM8915_MICD_RATE_MASK); + + /* Enable interrupts and we're off */ + snd_soc_update_bits(codec, WM8915_INTERRUPT_STATUS_2_MASK, + WM8915_IM_MICD_EINT, 0); + + return 0; +} +EXPORT_SYMBOL_GPL(wm8915_detect); + +static void wm8915_micd(struct snd_soc_codec *codec) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + int val, reg; + + val = snd_soc_read(codec, WM8915_MIC_DETECT_3); + + dev_dbg(codec->dev, "Microphone event: %x\n", val); + + if (!(val & WM8915_MICD_VALID)) { + dev_warn(codec->dev, "Microphone detection state invalid\n"); + return; + } + + /* No accessory, reset everything and report removal */ + if (!(val & WM8915_MICD_STS)) { + dev_dbg(codec->dev, "Jack removal detected\n"); + wm8915->jack_mic = false; + wm8915->detecting = true; + snd_soc_jack_report(wm8915->jack, 0, + SND_JACK_HEADSET | SND_JACK_BTN_0); + snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, + WM8915_MICD_RATE_MASK, + WM8915_MICD_RATE_MASK); + return; + } + + /* If the measurement is very high we've got a microphone but + * do a little debounce to account for mechanical issues. + */ + if (val & 0x400) { + dev_dbg(codec->dev, "Microphone detected\n"); + snd_soc_jack_report(wm8915->jack, SND_JACK_HEADSET, + SND_JACK_HEADSET | SND_JACK_BTN_0); + wm8915->jack_mic = true; + wm8915->detecting = false; + } + + /* If we detected a lower impedence during initial startup + * then we probably have the wrong polarity, flip it. Don't + * do this for the lowest impedences to speed up detection of + * plain headphones. + */ + if (wm8915->detecting && (val & 0x3f0)) { + reg = snd_soc_read(codec, WM8915_ACCESSORY_DETECT_MODE_2); + reg ^= WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC | + WM8915_MICD_BIAS_SRC; + snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2, + WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC | + WM8915_MICD_BIAS_SRC, reg); + + if (wm8915->polarity_cb) + wm8915->polarity_cb(codec, + (reg & WM8915_MICD_SRC) != 0); + + dev_dbg(codec->dev, "Set microphone polarity to %d\n", + (reg & WM8915_MICD_SRC) != 0); + + return; + } + + /* Don't distinguish between buttons, just report any low + * impedence as BTN_0. + */ + if (val & 0x3fc) { + if (wm8915->jack_mic) { + dev_dbg(codec->dev, "Mic button detected\n"); + snd_soc_jack_report(wm8915->jack, + SND_JACK_HEADSET | SND_JACK_BTN_0, + SND_JACK_HEADSET | SND_JACK_BTN_0); + } else { + dev_dbg(codec->dev, "Headphone detected\n"); + snd_soc_jack_report(wm8915->jack, + SND_JACK_HEADPHONE, + SND_JACK_HEADSET | + SND_JACK_BTN_0); + wm8915->detecting = false; + } + } + + /* Increase poll rate to give better responsiveness for buttons */ + if (!wm8915->detecting) + snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, + WM8915_MICD_RATE_MASK, + 5 << WM8915_MICD_RATE_SHIFT); +} + +static irqreturn_t wm8915_irq(int irq, void *data) +{ + struct snd_soc_codec *codec = data; + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + int irq_val; + + irq_val = snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2); + if (irq_val < 0) { + dev_err(codec->dev, "Failed to read IRQ status: %d\n", + irq_val); + return IRQ_NONE; + } + irq_val &= ~snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2_MASK); + + if (irq_val & (WM8915_DCS_DONE_01_EINT | WM8915_DCS_DONE_23_EINT)) { + dev_dbg(codec->dev, "DC servo IRQ\n"); + complete(&wm8915->dcs_done); + } + + if (irq_val & WM8915_FIFOS_ERR_EINT) + dev_err(codec->dev, "Digital core FIFO error\n"); + + if (irq_val & WM8915_FLL_LOCK_EINT) { + dev_dbg(codec->dev, "FLL locked\n"); + complete(&wm8915->fll_lock); + } + + if (irq_val & WM8915_MICD_EINT) + wm8915_micd(codec); + + if (irq_val) { + snd_soc_write(codec, WM8915_INTERRUPT_STATUS_2, irq_val); + + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } +} + +static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + struct wm8915_pdata *pdata = &wm8915->pdata; + + struct snd_kcontrol_new controls[] = { + SOC_ENUM_EXT("DSP1 EQ Mode", + wm8915->retune_mobile_enum, + wm8915_get_retune_mobile_enum, + wm8915_put_retune_mobile_enum), + SOC_ENUM_EXT("DSP2 EQ Mode", + wm8915->retune_mobile_enum, + wm8915_get_retune_mobile_enum, + wm8915_put_retune_mobile_enum), + }; + int ret, i, j; + const char **t; + + /* We need an array of texts for the enum API but the number + * of texts is likely to be less than the number of + * configurations due to the sample rate dependency of the + * configurations. */ + wm8915->num_retune_mobile_texts = 0; + wm8915->retune_mobile_texts = NULL; + for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) { + for (j = 0; j < wm8915->num_retune_mobile_texts; j++) { + if (strcmp(pdata->retune_mobile_cfgs[i].name, + wm8915->retune_mobile_texts[j]) == 0) + break; + } + + if (j != wm8915->num_retune_mobile_texts) + continue; + + /* Expand the array... */ + t = krealloc(wm8915->retune_mobile_texts, + sizeof(char *) * + (wm8915->num_retune_mobile_texts + 1), + GFP_KERNEL); + if (t == NULL) + continue; + + /* ...store the new entry... */ + t[wm8915->num_retune_mobile_texts] = + pdata->retune_mobile_cfgs[i].name; + + /* ...and remember the new version. */ + wm8915->num_retune_mobile_texts++; + wm8915->retune_mobile_texts = t; + } + + dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", + wm8915->num_retune_mobile_texts); + + wm8915->retune_mobile_enum.max = wm8915->num_retune_mobile_texts; + wm8915->retune_mobile_enum.texts = wm8915->retune_mobile_texts; + + ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls)); + if (ret != 0) + dev_err(codec->dev, + "Failed to add ReTune Mobile controls: %d\n", ret); +} + +static int wm8915_probe(struct snd_soc_codec *codec) +{ + int ret; + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + struct i2c_client *i2c = to_i2c_client(codec->dev); + struct snd_soc_dapm_context *dapm = &codec->dapm; + int i, irq_flags; + + wm8915->codec = codec; + + init_completion(&wm8915->dcs_done); + init_completion(&wm8915->fll_lock); + + dapm->idle_bias_off = true; + dapm->bias_level = SND_SOC_BIAS_OFF; + + ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + + for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) + wm8915->supplies[i].supply = wm8915_supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8915->supplies), + wm8915->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + goto err; + } + + wm8915->disable_nb[0].notifier_call = wm8915_regulator_event_0; + wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1; + wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2; + wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3; + wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4; + wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5; + + /* This should really be moved into the regulator core */ + for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) { + ret = regulator_register_notifier(wm8915->supplies[i].consumer, + &wm8915->disable_nb[i]); + if (ret != 0) { + dev_err(codec->dev, + "Failed to register regulator notifier: %d\n", + ret); + } + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies), + wm8915->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + goto err_get; + } + + if (wm8915->pdata.ldo_ena >= 0) { + gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 1); + msleep(5); + } + + ret = snd_soc_read(codec, WM8915_SOFTWARE_RESET); + if (ret < 0) { + dev_err(codec->dev, "Failed to read ID register: %d\n", ret); + goto err_enable; + } + if (ret != 0x8915) { + dev_err(codec->dev, "Device is not a WM8915, ID %x\n", ret); + ret = -EINVAL; + goto err_enable; + } + + ret = snd_soc_read(codec, WM8915_CHIP_REVISION); + if (ret < 0) { + dev_err(codec->dev, "Failed to read device revision: %d\n", + ret); + goto err_enable; + } + + dev_info(codec->dev, "revision %c\n", + (ret & WM8915_CHIP_REV_MASK) + 'A'); + + if (wm8915->pdata.ldo_ena >= 0) { + gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0); + } else { + ret = wm8915_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + goto err_enable; + } + } + + codec->cache_only = true; + + /* Apply platform data settings */ + snd_soc_update_bits(codec, WM8915_LINE_INPUT_CONTROL, + WM8915_INL_MODE_MASK | WM8915_INR_MODE_MASK, + wm8915->pdata.inl_mode << WM8915_INL_MODE_SHIFT | + wm8915->pdata.inr_mode); + + for (i = 0; i < ARRAY_SIZE(wm8915->pdata.gpio_default); i++) { + if (!wm8915->pdata.gpio_default[i]) + continue; + + snd_soc_write(codec, WM8915_GPIO_1 + i, + wm8915->pdata.gpio_default[i] & 0xffff); + } + + if (wm8915->pdata.spkmute_seq) + snd_soc_update_bits(codec, WM8915_PDM_SPEAKER_MUTE_SEQUENCE, + WM8915_SPK_MUTE_ENDIAN | + WM8915_SPK_MUTE_SEQ1_MASK, + wm8915->pdata.spkmute_seq); + + snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2, + WM8915_MICD_BIAS_SRC | WM8915_HPOUT1FB_SRC | + WM8915_MICD_SRC, wm8915->pdata.micdet_def); + + /* Latch volume update bits */ + snd_soc_update_bits(codec, WM8915_LEFT_LINE_INPUT_VOLUME, + WM8915_IN1_VU, WM8915_IN1_VU); + snd_soc_update_bits(codec, WM8915_RIGHT_LINE_INPUT_VOLUME, + WM8915_IN1_VU, WM8915_IN1_VU); + + snd_soc_update_bits(codec, WM8915_DAC1_LEFT_VOLUME, + WM8915_DAC1_VU, WM8915_DAC1_VU); + snd_soc_update_bits(codec, WM8915_DAC1_RIGHT_VOLUME, + WM8915_DAC1_VU, WM8915_DAC1_VU); + snd_soc_update_bits(codec, WM8915_DAC2_LEFT_VOLUME, + WM8915_DAC2_VU, WM8915_DAC2_VU); + snd_soc_update_bits(codec, WM8915_DAC2_RIGHT_VOLUME, + WM8915_DAC2_VU, WM8915_DAC2_VU); + + snd_soc_update_bits(codec, WM8915_OUTPUT1_LEFT_VOLUME, + WM8915_DAC1_VU, WM8915_DAC1_VU); + snd_soc_update_bits(codec, WM8915_OUTPUT1_RIGHT_VOLUME, + WM8915_DAC1_VU, WM8915_DAC1_VU); + snd_soc_update_bits(codec, WM8915_OUTPUT2_LEFT_VOLUME, + WM8915_DAC2_VU, WM8915_DAC2_VU); + snd_soc_update_bits(codec, WM8915_OUTPUT2_RIGHT_VOLUME, + WM8915_DAC2_VU, WM8915_DAC2_VU); + + snd_soc_update_bits(codec, WM8915_DSP1_TX_LEFT_VOLUME, + WM8915_DSP1TX_VU, WM8915_DSP1TX_VU); + snd_soc_update_bits(codec, WM8915_DSP1_TX_RIGHT_VOLUME, + WM8915_DSP1TX_VU, WM8915_DSP1TX_VU); + snd_soc_update_bits(codec, WM8915_DSP2_TX_LEFT_VOLUME, + WM8915_DSP2TX_VU, WM8915_DSP2TX_VU); + snd_soc_update_bits(codec, WM8915_DSP2_TX_RIGHT_VOLUME, + WM8915_DSP2TX_VU, WM8915_DSP2TX_VU); + + snd_soc_update_bits(codec, WM8915_DSP1_RX_LEFT_VOLUME, + WM8915_DSP1RX_VU, WM8915_DSP1RX_VU); + snd_soc_update_bits(codec, WM8915_DSP1_RX_RIGHT_VOLUME, + WM8915_DSP1RX_VU, WM8915_DSP1RX_VU); + snd_soc_update_bits(codec, WM8915_DSP2_RX_LEFT_VOLUME, + WM8915_DSP2RX_VU, WM8915_DSP2RX_VU); + snd_soc_update_bits(codec, WM8915_DSP2_RX_RIGHT_VOLUME, + WM8915_DSP2RX_VU, WM8915_DSP2RX_VU); + + /* No support currently for the underclocked TDM modes and + * pick a default TDM layout with each channel pair working with + * slots 0 and 1. */ + snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_0_CONFIGURATION, + WM8915_AIF1RX_CHAN0_SLOTS_MASK | + WM8915_AIF1RX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1RX_CHAN0_SLOTS_SHIFT | 0); + snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_1_CONFIGURATION, + WM8915_AIF1RX_CHAN1_SLOTS_MASK | + WM8915_AIF1RX_CHAN1_START_SLOT_MASK, + 1 << WM8915_AIF1RX_CHAN1_SLOTS_SHIFT | 1); + snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_2_CONFIGURATION, + WM8915_AIF1RX_CHAN2_SLOTS_MASK | + WM8915_AIF1RX_CHAN2_START_SLOT_MASK, + 1 << WM8915_AIF1RX_CHAN2_SLOTS_SHIFT | 0); + snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_3_CONFIGURATION, + WM8915_AIF1RX_CHAN3_SLOTS_MASK | + WM8915_AIF1RX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1RX_CHAN3_SLOTS_SHIFT | 1); + snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_4_CONFIGURATION, + WM8915_AIF1RX_CHAN4_SLOTS_MASK | + WM8915_AIF1RX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1RX_CHAN4_SLOTS_SHIFT | 0); + snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_5_CONFIGURATION, + WM8915_AIF1RX_CHAN5_SLOTS_MASK | + WM8915_AIF1RX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1RX_CHAN5_SLOTS_SHIFT | 1); + + snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_0_CONFIGURATION, + WM8915_AIF2RX_CHAN0_SLOTS_MASK | + WM8915_AIF2RX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF2RX_CHAN0_SLOTS_SHIFT | 0); + snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_1_CONFIGURATION, + WM8915_AIF2RX_CHAN1_SLOTS_MASK | + WM8915_AIF2RX_CHAN1_START_SLOT_MASK, + 1 << WM8915_AIF2RX_CHAN1_SLOTS_SHIFT | 1); + + snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_0_CONFIGURATION, + WM8915_AIF1TX_CHAN0_SLOTS_MASK | + WM8915_AIF1TX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1TX_CHAN0_SLOTS_SHIFT | 0); + snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION, + WM8915_AIF1TX_CHAN1_SLOTS_MASK | + WM8915_AIF1TX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1); + snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_2_CONFIGURATION, + WM8915_AIF1TX_CHAN2_SLOTS_MASK | + WM8915_AIF1TX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1TX_CHAN2_SLOTS_SHIFT | 0); + snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_3_CONFIGURATION, + WM8915_AIF1TX_CHAN3_SLOTS_MASK | + WM8915_AIF1TX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1TX_CHAN3_SLOTS_SHIFT | 1); + snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_4_CONFIGURATION, + WM8915_AIF1TX_CHAN4_SLOTS_MASK | + WM8915_AIF1TX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1TX_CHAN4_SLOTS_SHIFT | 0); + snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_5_CONFIGURATION, + WM8915_AIF1TX_CHAN5_SLOTS_MASK | + WM8915_AIF1TX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF1TX_CHAN5_SLOTS_SHIFT | 1); + + snd_soc_update_bits(codec, WM8915_AIF2TX_CHANNEL_0_CONFIGURATION, + WM8915_AIF2TX_CHAN0_SLOTS_MASK | + WM8915_AIF2TX_CHAN0_START_SLOT_MASK, + 1 << WM8915_AIF2TX_CHAN0_SLOTS_SHIFT | 0); + snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION, + WM8915_AIF2TX_CHAN1_SLOTS_MASK | + WM8915_AIF2TX_CHAN1_START_SLOT_MASK, + 1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1); + + if (wm8915->pdata.num_retune_mobile_cfgs) + wm8915_retune_mobile_pdata(codec); + else + snd_soc_add_controls(codec, wm8915_eq_controls, + ARRAY_SIZE(wm8915_eq_controls)); + + /* If the TX LRCLK pins are not in LRCLK mode configure the + * AIFs to source their clocks from the RX LRCLKs. + */ + if ((snd_soc_read(codec, WM8915_GPIO_1))) + snd_soc_update_bits(codec, WM8915_AIF1_TX_LRCLK_2, + WM8915_AIF1TX_LRCLK_MODE, + WM8915_AIF1TX_LRCLK_MODE); + + if ((snd_soc_read(codec, WM8915_GPIO_2))) + snd_soc_update_bits(codec, WM8915_AIF2_TX_LRCLK_2, + WM8915_AIF2TX_LRCLK_MODE, + WM8915_AIF2TX_LRCLK_MODE); + + regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies); + + wm8915_init_gpio(codec); + + if (i2c->irq) { + if (wm8915->pdata.irq_flags) + irq_flags = wm8915->pdata.irq_flags; + else + irq_flags = IRQF_TRIGGER_LOW; + + irq_flags |= IRQF_ONESHOT; + + ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq, + irq_flags, "wm8915", codec); + if (ret == 0) { + /* Unmask the interrupt */ + snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL, + WM8915_IM_IRQ, 0); + + /* Enable error reporting and DC servo status */ + snd_soc_update_bits(codec, + WM8915_INTERRUPT_STATUS_2_MASK, + WM8915_IM_DCS_DONE_23_EINT | + WM8915_IM_DCS_DONE_01_EINT | + WM8915_IM_FLL_LOCK_EINT | + WM8915_IM_FIFOS_ERR_EINT, + 0); + } else { + dev_err(codec->dev, "Failed to request IRQ: %d\n", + ret); + } + } + + return 0; + +err_enable: + if (wm8915->pdata.ldo_ena >= 0) + gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0); + + regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies); +err_get: + regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies); +err: + return ret; +} + +static int wm8915_remove(struct snd_soc_codec *codec) +{ + struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); + struct i2c_client *i2c = to_i2c_client(codec->dev); + int i; + + snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL, + WM8915_IM_IRQ, WM8915_IM_IRQ); + + if (i2c->irq) + free_irq(i2c->irq, codec); + + wm8915_free_gpio(codec); + + for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) + regulator_unregister_notifier(wm8915->supplies[i].consumer, + &wm8915->disable_nb[i]); + regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies); + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_wm8915 = { + .probe = wm8915_probe, + .remove = wm8915_remove, + .set_bias_level = wm8915_set_bias_level, + .seq_notifier = wm8915_seq_notifier, + .reg_cache_size = WM8915_MAX_REGISTER + 1, + .reg_word_size = sizeof(u16), + .reg_cache_default = wm8915_reg, + .volatile_register = wm8915_volatile_register, + .readable_register = wm8915_readable_register, + .compress_type = SND_SOC_RBTREE_COMPRESSION, + .controls = wm8915_snd_controls, + .num_controls = ARRAY_SIZE(wm8915_snd_controls), + .dapm_widgets = wm8915_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8915_dapm_widgets), + .dapm_routes = wm8915_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8915_dapm_routes), + .set_pll = wm8915_set_fll, +}; + +#define WM8915_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000) +#define WM8915_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops wm8915_dai_ops = { + .set_fmt = wm8915_set_fmt, + .hw_params = wm8915_hw_params, + .set_sysclk = wm8915_set_sysclk, +}; + +static struct snd_soc_dai_driver wm8915_dai[] = { + { + .name = "wm8915-aif1", + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 6, + .rates = WM8915_RATES, + .formats = WM8915_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 6, + .rates = WM8915_RATES, + .formats = WM8915_FORMATS, + }, + .ops = &wm8915_dai_ops, + }, + { + .name = "wm8915-aif2", + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8915_RATES, + .formats = WM8915_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8915_RATES, + .formats = WM8915_FORMATS, + }, + .ops = &wm8915_dai_ops, + }, +}; + +static __devinit int wm8915_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8915_priv *wm8915; + int ret; + + wm8915 = kzalloc(sizeof(struct wm8915_priv), GFP_KERNEL); + if (wm8915 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, wm8915); + + if (dev_get_platdata(&i2c->dev)) + memcpy(&wm8915->pdata, dev_get_platdata(&i2c->dev), + sizeof(wm8915->pdata)); + + if (wm8915->pdata.ldo_ena > 0) { + ret = gpio_request_one(wm8915->pdata.ldo_ena, + GPIOF_OUT_INIT_LOW, "WM8915 ENA"); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n", + wm8915->pdata.ldo_ena, ret); + goto err; + } + } + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_wm8915, wm8915_dai, + ARRAY_SIZE(wm8915_dai)); + if (ret < 0) + goto err_gpio; + + return ret; + +err_gpio: + if (wm8915->pdata.ldo_ena > 0) + gpio_free(wm8915->pdata.ldo_ena); +err: + kfree(wm8915); + + return ret; +} + +static __devexit int wm8915_i2c_remove(struct i2c_client *client) +{ + struct wm8915_priv *wm8915 = i2c_get_clientdata(client); + + snd_soc_unregister_codec(&client->dev); + if (wm8915->pdata.ldo_ena > 0) + gpio_free(wm8915->pdata.ldo_ena); + kfree(i2c_get_clientdata(client)); + return 0; +} + +static const struct i2c_device_id wm8915_i2c_id[] = { + { "wm8915", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8915_i2c_id); + +static struct i2c_driver wm8915_i2c_driver = { + .driver = { + .name = "wm8915", + .owner = THIS_MODULE, + }, + .probe = wm8915_i2c_probe, + .remove = __devexit_p(wm8915_i2c_remove), + .id_table = wm8915_i2c_id, +}; + +static int __init wm8915_modinit(void) +{ + int ret; + + ret = i2c_add_driver(&wm8915_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8915 I2C driver: %d\n", + ret); + } + + return ret; +} +module_init(wm8915_modinit); + +static void __exit wm8915_exit(void) +{ + i2c_del_driver(&wm8915_i2c_driver); +} +module_exit(wm8915_exit); + +MODULE_DESCRIPTION("ASoC WM8915 driver"); +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8915.h b/sound/soc/codecs/wm8915.h new file mode 100644 index 000000000000..200ffd7bf953 --- /dev/null +++ b/sound/soc/codecs/wm8915.h @@ -0,0 +1,3717 @@ +/* + * wm8915.h - WM8915 audio codec interface + * + * Copyright 2011 Wolfson Microelectronics PLC. + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _WM8915_H +#define _WM8915_H + +#define WM8915_SYSCLK_MCLK1 1 +#define WM8915_SYSCLK_MCLK2 2 +#define WM8915_SYSCLK_FLL 3 + +#define WM8915_FLL_MCLK1 1 +#define WM8915_FLL_MCLK2 2 +#define WM8915_FLL_DACLRCLK1 3 +#define WM8915_FLL_BCLK1 4 + +typedef void (*wm8915_polarity_fn)(struct snd_soc_codec *codec, int polarity); + +int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, + wm8915_polarity_fn polarity_cb); + +/* + * Register values. + */ +#define WM8915_SOFTWARE_RESET 0x00 +#define WM8915_POWER_MANAGEMENT_1 0x01 +#define WM8915_POWER_MANAGEMENT_2 0x02 +#define WM8915_POWER_MANAGEMENT_3 0x03 +#define WM8915_POWER_MANAGEMENT_4 0x04 +#define WM8915_POWER_MANAGEMENT_5 0x05 +#define WM8915_POWER_MANAGEMENT_6 0x06 +#define WM8915_POWER_MANAGEMENT_7 0x07 +#define WM8915_POWER_MANAGEMENT_8 0x08 +#define WM8915_LEFT_LINE_INPUT_VOLUME 0x10 +#define WM8915_RIGHT_LINE_INPUT_VOLUME 0x11 +#define WM8915_LINE_INPUT_CONTROL 0x12 +#define WM8915_DAC1_HPOUT1_VOLUME 0x15 +#define WM8915_DAC2_HPOUT2_VOLUME 0x16 +#define WM8915_DAC1_LEFT_VOLUME 0x18 +#define WM8915_DAC1_RIGHT_VOLUME 0x19 +#define WM8915_DAC2_LEFT_VOLUME 0x1A +#define WM8915_DAC2_RIGHT_VOLUME 0x1B +#define WM8915_OUTPUT1_LEFT_VOLUME 0x1C +#define WM8915_OUTPUT1_RIGHT_VOLUME 0x1D +#define WM8915_OUTPUT2_LEFT_VOLUME 0x1E +#define WM8915_OUTPUT2_RIGHT_VOLUME 0x1F +#define WM8915_MICBIAS_1 0x20 +#define WM8915_MICBIAS_2 0x21 +#define WM8915_LDO_1 0x28 +#define WM8915_LDO_2 0x29 +#define WM8915_ACCESSORY_DETECT_MODE_1 0x30 +#define WM8915_ACCESSORY_DETECT_MODE_2 0x31 +#define WM8915_HEADPHONE_DETECT_1 0x34 +#define WM8915_HEADPHONE_DETECT_2 0x35 +#define WM8915_MIC_DETECT_1 0x38 +#define WM8915_MIC_DETECT_2 0x39 +#define WM8915_MIC_DETECT_3 0x3A +#define WM8915_CHARGE_PUMP_1 0x40 +#define WM8915_CHARGE_PUMP_2 0x41 +#define WM8915_DC_SERVO_1 0x50 +#define WM8915_DC_SERVO_2 0x51 +#define WM8915_DC_SERVO_3 0x52 +#define WM8915_DC_SERVO_5 0x54 +#define WM8915_DC_SERVO_6 0x55 +#define WM8915_DC_SERVO_7 0x56 +#define WM8915_DC_SERVO_READBACK_0 0x57 +#define WM8915_ANALOGUE_HP_1 0x60 +#define WM8915_ANALOGUE_HP_2 0x61 +#define WM8915_CHIP_REVISION 0x100 +#define WM8915_CONTROL_INTERFACE_1 0x101 +#define WM8915_WRITE_SEQUENCER_CTRL_1 0x110 +#define WM8915_WRITE_SEQUENCER_CTRL_2 0x111 +#define WM8915_AIF_CLOCKING_1 0x200 +#define WM8915_AIF_CLOCKING_2 0x201 +#define WM8915_CLOCKING_1 0x208 +#define WM8915_CLOCKING_2 0x209 +#define WM8915_AIF_RATE 0x210 +#define WM8915_FLL_CONTROL_1 0x220 +#define WM8915_FLL_CONTROL_2 0x221 +#define WM8915_FLL_CONTROL_3 0x222 +#define WM8915_FLL_CONTROL_4 0x223 +#define WM8915_FLL_CONTROL_5 0x224 +#define WM8915_FLL_CONTROL_6 0x225 +#define WM8915_FLL_EFS_1 0x226 +#define WM8915_FLL_EFS_2 0x227 +#define WM8915_AIF1_CONTROL 0x300 +#define WM8915_AIF1_BCLK 0x301 +#define WM8915_AIF1_TX_LRCLK_1 0x302 +#define WM8915_AIF1_TX_LRCLK_2 0x303 +#define WM8915_AIF1_RX_LRCLK_1 0x304 +#define WM8915_AIF1_RX_LRCLK_2 0x305 +#define WM8915_AIF1TX_DATA_CONFIGURATION_1 0x306 +#define WM8915_AIF1TX_DATA_CONFIGURATION_2 0x307 +#define WM8915_AIF1RX_DATA_CONFIGURATION 0x308 +#define WM8915_AIF1TX_CHANNEL_0_CONFIGURATION 0x309 +#define WM8915_AIF1TX_CHANNEL_1_CONFIGURATION 0x30A +#define WM8915_AIF1TX_CHANNEL_2_CONFIGURATION 0x30B +#define WM8915_AIF1TX_CHANNEL_3_CONFIGURATION 0x30C +#define WM8915_AIF1TX_CHANNEL_4_CONFIGURATION 0x30D +#define WM8915_AIF1TX_CHANNEL_5_CONFIGURATION 0x30E +#define WM8915_AIF1RX_CHANNEL_0_CONFIGURATION 0x30F +#define WM8915_AIF1RX_CHANNEL_1_CONFIGURATION 0x310 +#define WM8915_AIF1RX_CHANNEL_2_CONFIGURATION 0x311 +#define WM8915_AIF1RX_CHANNEL_3_CONFIGURATION 0x312 +#define WM8915_AIF1RX_CHANNEL_4_CONFIGURATION 0x313 +#define WM8915_AIF1RX_CHANNEL_5_CONFIGURATION 0x314 +#define WM8915_AIF1RX_MONO_CONFIGURATION 0x315 +#define WM8915_AIF1TX_TEST 0x31A +#define WM8915_AIF2_CONTROL 0x320 +#define WM8915_AIF2_BCLK 0x321 +#define WM8915_AIF2_TX_LRCLK_1 0x322 +#define WM8915_AIF2_TX_LRCLK_2 0x323 +#define WM8915_AIF2_RX_LRCLK_1 0x324 +#define WM8915_AIF2_RX_LRCLK_2 0x325 +#define WM8915_AIF2TX_DATA_CONFIGURATION_1 0x326 +#define WM8915_AIF2TX_DATA_CONFIGURATION_2 0x327 +#define WM8915_AIF2RX_DATA_CONFIGURATION 0x328 +#define WM8915_AIF2TX_CHANNEL_0_CONFIGURATION 0x329 +#define WM8915_AIF2TX_CHANNEL_1_CONFIGURATION 0x32A +#define WM8915_AIF2RX_CHANNEL_0_CONFIGURATION 0x32B +#define WM8915_AIF2RX_CHANNEL_1_CONFIGURATION 0x32C +#define WM8915_AIF2RX_MONO_CONFIGURATION 0x32D +#define WM8915_AIF2TX_TEST 0x32F +#define WM8915_DSP1_TX_LEFT_VOLUME 0x400 +#define WM8915_DSP1_TX_RIGHT_VOLUME 0x401 +#define WM8915_DSP1_RX_LEFT_VOLUME 0x402 +#define WM8915_DSP1_RX_RIGHT_VOLUME 0x403 +#define WM8915_DSP1_TX_FILTERS 0x410 +#define WM8915_DSP1_RX_FILTERS_1 0x420 +#define WM8915_DSP1_RX_FILTERS_2 0x421 +#define WM8915_DSP1_DRC_1 0x440 +#define WM8915_DSP1_DRC_2 0x441 +#define WM8915_DSP1_DRC_3 0x442 +#define WM8915_DSP1_DRC_4 0x443 +#define WM8915_DSP1_DRC_5 0x444 +#define WM8915_DSP1_RX_EQ_GAINS_1 0x480 +#define WM8915_DSP1_RX_EQ_GAINS_2 0x481 +#define WM8915_DSP1_RX_EQ_BAND_1_A 0x482 +#define WM8915_DSP1_RX_EQ_BAND_1_B 0x483 +#define WM8915_DSP1_RX_EQ_BAND_1_PG 0x484 +#define WM8915_DSP1_RX_EQ_BAND_2_A 0x485 +#define WM8915_DSP1_RX_EQ_BAND_2_B 0x486 +#define WM8915_DSP1_RX_EQ_BAND_2_C 0x487 +#define WM8915_DSP1_RX_EQ_BAND_2_PG 0x488 +#define WM8915_DSP1_RX_EQ_BAND_3_A 0x489 +#define WM8915_DSP1_RX_EQ_BAND_3_B 0x48A +#define WM8915_DSP1_RX_EQ_BAND_3_C 0x48B +#define WM8915_DSP1_RX_EQ_BAND_3_PG 0x48C +#define WM8915_DSP1_RX_EQ_BAND_4_A 0x48D +#define WM8915_DSP1_RX_EQ_BAND_4_B 0x48E +#define WM8915_DSP1_RX_EQ_BAND_4_C 0x48F +#define WM8915_DSP1_RX_EQ_BAND_4_PG 0x490 +#define WM8915_DSP1_RX_EQ_BAND_5_A 0x491 +#define WM8915_DSP1_RX_EQ_BAND_5_B 0x492 +#define WM8915_DSP1_RX_EQ_BAND_5_PG 0x493 +#define WM8915_DSP2_TX_LEFT_VOLUME 0x500 +#define WM8915_DSP2_TX_RIGHT_VOLUME 0x501 +#define WM8915_DSP2_RX_LEFT_VOLUME 0x502 +#define WM8915_DSP2_RX_RIGHT_VOLUME 0x503 +#define WM8915_DSP2_TX_FILTERS 0x510 +#define WM8915_DSP2_RX_FILTERS_1 0x520 +#define WM8915_DSP2_RX_FILTERS_2 0x521 +#define WM8915_DSP2_DRC_1 0x540 +#define WM8915_DSP2_DRC_2 0x541 +#define WM8915_DSP2_DRC_3 0x542 +#define WM8915_DSP2_DRC_4 0x543 +#define WM8915_DSP2_DRC_5 0x544 +#define WM8915_DSP2_RX_EQ_GAINS_1 0x580 +#define WM8915_DSP2_RX_EQ_GAINS_2 0x581 +#define WM8915_DSP2_RX_EQ_BAND_1_A 0x582 +#define WM8915_DSP2_RX_EQ_BAND_1_B 0x583 +#define WM8915_DSP2_RX_EQ_BAND_1_PG 0x584 +#define WM8915_DSP2_RX_EQ_BAND_2_A 0x585 +#define WM8915_DSP2_RX_EQ_BAND_2_B 0x586 +#define WM8915_DSP2_RX_EQ_BAND_2_C 0x587 +#define WM8915_DSP2_RX_EQ_BAND_2_PG 0x588 +#define WM8915_DSP2_RX_EQ_BAND_3_A 0x589 +#define WM8915_DSP2_RX_EQ_BAND_3_B 0x58A +#define WM8915_DSP2_RX_EQ_BAND_3_C 0x58B +#define WM8915_DSP2_RX_EQ_BAND_3_PG 0x58C +#define WM8915_DSP2_RX_EQ_BAND_4_A 0x58D +#define WM8915_DSP2_RX_EQ_BAND_4_B 0x58E +#define WM8915_DSP2_RX_EQ_BAND_4_C 0x58F +#define WM8915_DSP2_RX_EQ_BAND_4_PG 0x590 +#define WM8915_DSP2_RX_EQ_BAND_5_A 0x591 +#define WM8915_DSP2_RX_EQ_BAND_5_B 0x592 +#define WM8915_DSP2_RX_EQ_BAND_5_PG 0x593 +#define WM8915_DAC1_MIXER_VOLUMES 0x600 +#define WM8915_DAC1_LEFT_MIXER_ROUTING 0x601 +#define WM8915_DAC1_RIGHT_MIXER_ROUTING 0x602 +#define WM8915_DAC2_MIXER_VOLUMES 0x603 +#define WM8915_DAC2_LEFT_MIXER_ROUTING 0x604 +#define WM8915_DAC2_RIGHT_MIXER_ROUTING 0x605 +#define WM8915_DSP1_TX_LEFT_MIXER_ROUTING 0x606 +#define WM8915_DSP1_TX_RIGHT_MIXER_ROUTING 0x607 +#define WM8915_DSP2_TX_LEFT_MIXER_ROUTING 0x608 +#define WM8915_DSP2_TX_RIGHT_MIXER_ROUTING 0x609 +#define WM8915_DSP_TX_MIXER_SELECT 0x60A +#define WM8915_DAC_SOFTMUTE 0x610 +#define WM8915_OVERSAMPLING 0x620 +#define WM8915_SIDETONE 0x621 +#define WM8915_GPIO_1 0x700 +#define WM8915_GPIO_2 0x701 +#define WM8915_GPIO_3 0x702 +#define WM8915_GPIO_4 0x703 +#define WM8915_GPIO_5 0x704 +#define WM8915_PULL_CONTROL_1 0x720 +#define WM8915_PULL_CONTROL_2 0x721 +#define WM8915_INTERRUPT_STATUS_1 0x730 +#define WM8915_INTERRUPT_STATUS_2 0x731 +#define WM8915_INTERRUPT_RAW_STATUS_2 0x732 +#define WM8915_INTERRUPT_STATUS_1_MASK 0x738 +#define WM8915_INTERRUPT_STATUS_2_MASK 0x739 +#define WM8915_INTERRUPT_CONTROL 0x740 +#define WM8915_LEFT_PDM_SPEAKER 0x800 +#define WM8915_RIGHT_PDM_SPEAKER 0x801 +#define WM8915_PDM_SPEAKER_MUTE_SEQUENCE 0x802 +#define WM8915_PDM_SPEAKER_VOLUME 0x803 +#define WM8915_WRITE_SEQUENCER_0 0x3000 +#define WM8915_WRITE_SEQUENCER_1 0x3001 +#define WM8915_WRITE_SEQUENCER_2 0x3002 +#define WM8915_WRITE_SEQUENCER_3 0x3003 +#define WM8915_WRITE_SEQUENCER_4 0x3004 +#define WM8915_WRITE_SEQUENCER_5 0x3005 +#define WM8915_WRITE_SEQUENCER_6 0x3006 +#define WM8915_WRITE_SEQUENCER_7 0x3007 +#define WM8915_WRITE_SEQUENCER_8 0x3008 +#define WM8915_WRITE_SEQUENCER_9 0x3009 +#define WM8915_WRITE_SEQUENCER_10 0x300A +#define WM8915_WRITE_SEQUENCER_11 0x300B +#define WM8915_WRITE_SEQUENCER_12 0x300C +#define WM8915_WRITE_SEQUENCER_13 0x300D +#define WM8915_WRITE_SEQUENCER_14 0x300E +#define WM8915_WRITE_SEQUENCER_15 0x300F +#define WM8915_WRITE_SEQUENCER_16 0x3010 +#define WM8915_WRITE_SEQUENCER_17 0x3011 +#define WM8915_WRITE_SEQUENCER_18 0x3012 +#define WM8915_WRITE_SEQUENCER_19 0x3013 +#define WM8915_WRITE_SEQUENCER_20 0x3014 +#define WM8915_WRITE_SEQUENCER_21 0x3015 +#define WM8915_WRITE_SEQUENCER_22 0x3016 +#define WM8915_WRITE_SEQUENCER_23 0x3017 +#define WM8915_WRITE_SEQUENCER_24 0x3018 +#define WM8915_WRITE_SEQUENCER_25 0x3019 +#define WM8915_WRITE_SEQUENCER_26 0x301A +#define WM8915_WRITE_SEQUENCER_27 0x301B +#define WM8915_WRITE_SEQUENCER_28 0x301C +#define WM8915_WRITE_SEQUENCER_29 0x301D +#define WM8915_WRITE_SEQUENCER_30 0x301E +#define WM8915_WRITE_SEQUENCER_31 0x301F +#define WM8915_WRITE_SEQUENCER_32 0x3020 +#define WM8915_WRITE_SEQUENCER_33 0x3021 +#define WM8915_WRITE_SEQUENCER_34 0x3022 +#define WM8915_WRITE_SEQUENCER_35 0x3023 +#define WM8915_WRITE_SEQUENCER_36 0x3024 +#define WM8915_WRITE_SEQUENCER_37 0x3025 +#define WM8915_WRITE_SEQUENCER_38 0x3026 +#define WM8915_WRITE_SEQUENCER_39 0x3027 +#define WM8915_WRITE_SEQUENCER_40 0x3028 +#define WM8915_WRITE_SEQUENCER_41 0x3029 +#define WM8915_WRITE_SEQUENCER_42 0x302A +#define WM8915_WRITE_SEQUENCER_43 0x302B +#define WM8915_WRITE_SEQUENCER_44 0x302C +#define WM8915_WRITE_SEQUENCER_45 0x302D +#define WM8915_WRITE_SEQUENCER_46 0x302E +#define WM8915_WRITE_SEQUENCER_47 0x302F +#define WM8915_WRITE_SEQUENCER_48 0x3030 +#define WM8915_WRITE_SEQUENCER_49 0x3031 +#define WM8915_WRITE_SEQUENCER_50 0x3032 +#define WM8915_WRITE_SEQUENCER_51 0x3033 +#define WM8915_WRITE_SEQUENCER_52 0x3034 +#define WM8915_WRITE_SEQUENCER_53 0x3035 +#define WM8915_WRITE_SEQUENCER_54 0x3036 +#define WM8915_WRITE_SEQUENCER_55 0x3037 +#define WM8915_WRITE_SEQUENCER_56 0x3038 +#define WM8915_WRITE_SEQUENCER_57 0x3039 +#define WM8915_WRITE_SEQUENCER_58 0x303A +#define WM8915_WRITE_SEQUENCER_59 0x303B +#define WM8915_WRITE_SEQUENCER_60 0x303C +#define WM8915_WRITE_SEQUENCER_61 0x303D +#define WM8915_WRITE_SEQUENCER_62 0x303E +#define WM8915_WRITE_SEQUENCER_63 0x303F +#define WM8915_WRITE_SEQUENCER_64 0x3040 +#define WM8915_WRITE_SEQUENCER_65 0x3041 +#define WM8915_WRITE_SEQUENCER_66 0x3042 +#define WM8915_WRITE_SEQUENCER_67 0x3043 +#define WM8915_WRITE_SEQUENCER_68 0x3044 +#define WM8915_WRITE_SEQUENCER_69 0x3045 +#define WM8915_WRITE_SEQUENCER_70 0x3046 +#define WM8915_WRITE_SEQUENCER_71 0x3047 +#define WM8915_WRITE_SEQUENCER_72 0x3048 +#define WM8915_WRITE_SEQUENCER_73 0x3049 +#define WM8915_WRITE_SEQUENCER_74 0x304A +#define WM8915_WRITE_SEQUENCER_75 0x304B +#define WM8915_WRITE_SEQUENCER_76 0x304C +#define WM8915_WRITE_SEQUENCER_77 0x304D +#define WM8915_WRITE_SEQUENCER_78 0x304E +#define WM8915_WRITE_SEQUENCER_79 0x304F +#define WM8915_WRITE_SEQUENCER_80 0x3050 +#define WM8915_WRITE_SEQUENCER_81 0x3051 +#define WM8915_WRITE_SEQUENCER_82 0x3052 +#define WM8915_WRITE_SEQUENCER_83 0x3053 +#define WM8915_WRITE_SEQUENCER_84 0x3054 +#define WM8915_WRITE_SEQUENCER_85 0x3055 +#define WM8915_WRITE_SEQUENCER_86 0x3056 +#define WM8915_WRITE_SEQUENCER_87 0x3057 +#define WM8915_WRITE_SEQUENCER_88 0x3058 +#define WM8915_WRITE_SEQUENCER_89 0x3059 +#define WM8915_WRITE_SEQUENCER_90 0x305A +#define WM8915_WRITE_SEQUENCER_91 0x305B +#define WM8915_WRITE_SEQUENCER_92 0x305C +#define WM8915_WRITE_SEQUENCER_93 0x305D +#define WM8915_WRITE_SEQUENCER_94 0x305E +#define WM8915_WRITE_SEQUENCER_95 0x305F +#define WM8915_WRITE_SEQUENCER_96 0x3060 +#define WM8915_WRITE_SEQUENCER_97 0x3061 +#define WM8915_WRITE_SEQUENCER_98 0x3062 +#define WM8915_WRITE_SEQUENCER_99 0x3063 +#define WM8915_WRITE_SEQUENCER_100 0x3064 +#define WM8915_WRITE_SEQUENCER_101 0x3065 +#define WM8915_WRITE_SEQUENCER_102 0x3066 +#define WM8915_WRITE_SEQUENCER_103 0x3067 +#define WM8915_WRITE_SEQUENCER_104 0x3068 +#define WM8915_WRITE_SEQUENCER_105 0x3069 +#define WM8915_WRITE_SEQUENCER_106 0x306A +#define WM8915_WRITE_SEQUENCER_107 0x306B +#define WM8915_WRITE_SEQUENCER_108 0x306C +#define WM8915_WRITE_SEQUENCER_109 0x306D +#define WM8915_WRITE_SEQUENCER_110 0x306E +#define WM8915_WRITE_SEQUENCER_111 0x306F +#define WM8915_WRITE_SEQUENCER_112 0x3070 +#define WM8915_WRITE_SEQUENCER_113 0x3071 +#define WM8915_WRITE_SEQUENCER_114 0x3072 +#define WM8915_WRITE_SEQUENCER_115 0x3073 +#define WM8915_WRITE_SEQUENCER_116 0x3074 +#define WM8915_WRITE_SEQUENCER_117 0x3075 +#define WM8915_WRITE_SEQUENCER_118 0x3076 +#define WM8915_WRITE_SEQUENCER_119 0x3077 +#define WM8915_WRITE_SEQUENCER_120 0x3078 +#define WM8915_WRITE_SEQUENCER_121 0x3079 +#define WM8915_WRITE_SEQUENCER_122 0x307A +#define WM8915_WRITE_SEQUENCER_123 0x307B +#define WM8915_WRITE_SEQUENCER_124 0x307C +#define WM8915_WRITE_SEQUENCER_125 0x307D +#define WM8915_WRITE_SEQUENCER_126 0x307E +#define WM8915_WRITE_SEQUENCER_127 0x307F +#define WM8915_WRITE_SEQUENCER_128 0x3080 +#define WM8915_WRITE_SEQUENCER_129 0x3081 +#define WM8915_WRITE_SEQUENCER_130 0x3082 +#define WM8915_WRITE_SEQUENCER_131 0x3083 +#define WM8915_WRITE_SEQUENCER_132 0x3084 +#define WM8915_WRITE_SEQUENCER_133 0x3085 +#define WM8915_WRITE_SEQUENCER_134 0x3086 +#define WM8915_WRITE_SEQUENCER_135 0x3087 +#define WM8915_WRITE_SEQUENCER_136 0x3088 +#define WM8915_WRITE_SEQUENCER_137 0x3089 +#define WM8915_WRITE_SEQUENCER_138 0x308A +#define WM8915_WRITE_SEQUENCER_139 0x308B +#define WM8915_WRITE_SEQUENCER_140 0x308C +#define WM8915_WRITE_SEQUENCER_141 0x308D +#define WM8915_WRITE_SEQUENCER_142 0x308E +#define WM8915_WRITE_SEQUENCER_143 0x308F +#define WM8915_WRITE_SEQUENCER_144 0x3090 +#define WM8915_WRITE_SEQUENCER_145 0x3091 +#define WM8915_WRITE_SEQUENCER_146 0x3092 +#define WM8915_WRITE_SEQUENCER_147 0x3093 +#define WM8915_WRITE_SEQUENCER_148 0x3094 +#define WM8915_WRITE_SEQUENCER_149 0x3095 +#define WM8915_WRITE_SEQUENCER_150 0x3096 +#define WM8915_WRITE_SEQUENCER_151 0x3097 +#define WM8915_WRITE_SEQUENCER_152 0x3098 +#define WM8915_WRITE_SEQUENCER_153 0x3099 +#define WM8915_WRITE_SEQUENCER_154 0x309A +#define WM8915_WRITE_SEQUENCER_155 0x309B +#define WM8915_WRITE_SEQUENCER_156 0x309C +#define WM8915_WRITE_SEQUENCER_157 0x309D +#define WM8915_WRITE_SEQUENCER_158 0x309E +#define WM8915_WRITE_SEQUENCER_159 0x309F +#define WM8915_WRITE_SEQUENCER_160 0x30A0 +#define WM8915_WRITE_SEQUENCER_161 0x30A1 +#define WM8915_WRITE_SEQUENCER_162 0x30A2 +#define WM8915_WRITE_SEQUENCER_163 0x30A3 +#define WM8915_WRITE_SEQUENCER_164 0x30A4 +#define WM8915_WRITE_SEQUENCER_165 0x30A5 +#define WM8915_WRITE_SEQUENCER_166 0x30A6 +#define WM8915_WRITE_SEQUENCER_167 0x30A7 +#define WM8915_WRITE_SEQUENCER_168 0x30A8 +#define WM8915_WRITE_SEQUENCER_169 0x30A9 +#define WM8915_WRITE_SEQUENCER_170 0x30AA +#define WM8915_WRITE_SEQUENCER_171 0x30AB +#define WM8915_WRITE_SEQUENCER_172 0x30AC +#define WM8915_WRITE_SEQUENCER_173 0x30AD +#define WM8915_WRITE_SEQUENCER_174 0x30AE +#define WM8915_WRITE_SEQUENCER_175 0x30AF +#define WM8915_WRITE_SEQUENCER_176 0x30B0 +#define WM8915_WRITE_SEQUENCER_177 0x30B1 +#define WM8915_WRITE_SEQUENCER_178 0x30B2 +#define WM8915_WRITE_SEQUENCER_179 0x30B3 +#define WM8915_WRITE_SEQUENCER_180 0x30B4 +#define WM8915_WRITE_SEQUENCER_181 0x30B5 +#define WM8915_WRITE_SEQUENCER_182 0x30B6 +#define WM8915_WRITE_SEQUENCER_183 0x30B7 +#define WM8915_WRITE_SEQUENCER_184 0x30B8 +#define WM8915_WRITE_SEQUENCER_185 0x30B9 +#define WM8915_WRITE_SEQUENCER_186 0x30BA +#define WM8915_WRITE_SEQUENCER_187 0x30BB +#define WM8915_WRITE_SEQUENCER_188 0x30BC +#define WM8915_WRITE_SEQUENCER_189 0x30BD +#define WM8915_WRITE_SEQUENCER_190 0x30BE +#define WM8915_WRITE_SEQUENCER_191 0x30BF +#define WM8915_WRITE_SEQUENCER_192 0x30C0 +#define WM8915_WRITE_SEQUENCER_193 0x30C1 +#define WM8915_WRITE_SEQUENCER_194 0x30C2 +#define WM8915_WRITE_SEQUENCER_195 0x30C3 +#define WM8915_WRITE_SEQUENCER_196 0x30C4 +#define WM8915_WRITE_SEQUENCER_197 0x30C5 +#define WM8915_WRITE_SEQUENCER_198 0x30C6 +#define WM8915_WRITE_SEQUENCER_199 0x30C7 +#define WM8915_WRITE_SEQUENCER_200 0x30C8 +#define WM8915_WRITE_SEQUENCER_201 0x30C9 +#define WM8915_WRITE_SEQUENCER_202 0x30CA +#define WM8915_WRITE_SEQUENCER_203 0x30CB +#define WM8915_WRITE_SEQUENCER_204 0x30CC +#define WM8915_WRITE_SEQUENCER_205 0x30CD +#define WM8915_WRITE_SEQUENCER_206 0x30CE +#define WM8915_WRITE_SEQUENCER_207 0x30CF +#define WM8915_WRITE_SEQUENCER_208 0x30D0 +#define WM8915_WRITE_SEQUENCER_209 0x30D1 +#define WM8915_WRITE_SEQUENCER_210 0x30D2 +#define WM8915_WRITE_SEQUENCER_211 0x30D3 +#define WM8915_WRITE_SEQUENCER_212 0x30D4 +#define WM8915_WRITE_SEQUENCER_213 0x30D5 +#define WM8915_WRITE_SEQUENCER_214 0x30D6 +#define WM8915_WRITE_SEQUENCER_215 0x30D7 +#define WM8915_WRITE_SEQUENCER_216 0x30D8 +#define WM8915_WRITE_SEQUENCER_217 0x30D9 +#define WM8915_WRITE_SEQUENCER_218 0x30DA +#define WM8915_WRITE_SEQUENCER_219 0x30DB +#define WM8915_WRITE_SEQUENCER_220 0x30DC +#define WM8915_WRITE_SEQUENCER_221 0x30DD +#define WM8915_WRITE_SEQUENCER_222 0x30DE +#define WM8915_WRITE_SEQUENCER_223 0x30DF +#define WM8915_WRITE_SEQUENCER_224 0x30E0 +#define WM8915_WRITE_SEQUENCER_225 0x30E1 +#define WM8915_WRITE_SEQUENCER_226 0x30E2 +#define WM8915_WRITE_SEQUENCER_227 0x30E3 +#define WM8915_WRITE_SEQUENCER_228 0x30E4 +#define WM8915_WRITE_SEQUENCER_229 0x30E5 +#define WM8915_WRITE_SEQUENCER_230 0x30E6 +#define WM8915_WRITE_SEQUENCER_231 0x30E7 +#define WM8915_WRITE_SEQUENCER_232 0x30E8 +#define WM8915_WRITE_SEQUENCER_233 0x30E9 +#define WM8915_WRITE_SEQUENCER_234 0x30EA +#define WM8915_WRITE_SEQUENCER_235 0x30EB +#define WM8915_WRITE_SEQUENCER_236 0x30EC +#define WM8915_WRITE_SEQUENCER_237 0x30ED +#define WM8915_WRITE_SEQUENCER_238 0x30EE +#define WM8915_WRITE_SEQUENCER_239 0x30EF +#define WM8915_WRITE_SEQUENCER_240 0x30F0 +#define WM8915_WRITE_SEQUENCER_241 0x30F1 +#define WM8915_WRITE_SEQUENCER_242 0x30F2 +#define WM8915_WRITE_SEQUENCER_243 0x30F3 +#define WM8915_WRITE_SEQUENCER_244 0x30F4 +#define WM8915_WRITE_SEQUENCER_245 0x30F5 +#define WM8915_WRITE_SEQUENCER_246 0x30F6 +#define WM8915_WRITE_SEQUENCER_247 0x30F7 +#define WM8915_WRITE_SEQUENCER_248 0x30F8 +#define WM8915_WRITE_SEQUENCER_249 0x30F9 +#define WM8915_WRITE_SEQUENCER_250 0x30FA +#define WM8915_WRITE_SEQUENCER_251 0x30FB +#define WM8915_WRITE_SEQUENCER_252 0x30FC +#define WM8915_WRITE_SEQUENCER_253 0x30FD +#define WM8915_WRITE_SEQUENCER_254 0x30FE +#define WM8915_WRITE_SEQUENCER_255 0x30FF +#define WM8915_WRITE_SEQUENCER_256 0x3100 +#define WM8915_WRITE_SEQUENCER_257 0x3101 +#define WM8915_WRITE_SEQUENCER_258 0x3102 +#define WM8915_WRITE_SEQUENCER_259 0x3103 +#define WM8915_WRITE_SEQUENCER_260 0x3104 +#define WM8915_WRITE_SEQUENCER_261 0x3105 +#define WM8915_WRITE_SEQUENCER_262 0x3106 +#define WM8915_WRITE_SEQUENCER_263 0x3107 +#define WM8915_WRITE_SEQUENCER_264 0x3108 +#define WM8915_WRITE_SEQUENCER_265 0x3109 +#define WM8915_WRITE_SEQUENCER_266 0x310A +#define WM8915_WRITE_SEQUENCER_267 0x310B +#define WM8915_WRITE_SEQUENCER_268 0x310C +#define WM8915_WRITE_SEQUENCER_269 0x310D +#define WM8915_WRITE_SEQUENCER_270 0x310E +#define WM8915_WRITE_SEQUENCER_271 0x310F +#define WM8915_WRITE_SEQUENCER_272 0x3110 +#define WM8915_WRITE_SEQUENCER_273 0x3111 +#define WM8915_WRITE_SEQUENCER_274 0x3112 +#define WM8915_WRITE_SEQUENCER_275 0x3113 +#define WM8915_WRITE_SEQUENCER_276 0x3114 +#define WM8915_WRITE_SEQUENCER_277 0x3115 +#define WM8915_WRITE_SEQUENCER_278 0x3116 +#define WM8915_WRITE_SEQUENCER_279 0x3117 +#define WM8915_WRITE_SEQUENCER_280 0x3118 +#define WM8915_WRITE_SEQUENCER_281 0x3119 +#define WM8915_WRITE_SEQUENCER_282 0x311A +#define WM8915_WRITE_SEQUENCER_283 0x311B +#define WM8915_WRITE_SEQUENCER_284 0x311C +#define WM8915_WRITE_SEQUENCER_285 0x311D +#define WM8915_WRITE_SEQUENCER_286 0x311E +#define WM8915_WRITE_SEQUENCER_287 0x311F +#define WM8915_WRITE_SEQUENCER_288 0x3120 +#define WM8915_WRITE_SEQUENCER_289 0x3121 +#define WM8915_WRITE_SEQUENCER_290 0x3122 +#define WM8915_WRITE_SEQUENCER_291 0x3123 +#define WM8915_WRITE_SEQUENCER_292 0x3124 +#define WM8915_WRITE_SEQUENCER_293 0x3125 +#define WM8915_WRITE_SEQUENCER_294 0x3126 +#define WM8915_WRITE_SEQUENCER_295 0x3127 +#define WM8915_WRITE_SEQUENCER_296 0x3128 +#define WM8915_WRITE_SEQUENCER_297 0x3129 +#define WM8915_WRITE_SEQUENCER_298 0x312A +#define WM8915_WRITE_SEQUENCER_299 0x312B +#define WM8915_WRITE_SEQUENCER_300 0x312C +#define WM8915_WRITE_SEQUENCER_301 0x312D +#define WM8915_WRITE_SEQUENCER_302 0x312E +#define WM8915_WRITE_SEQUENCER_303 0x312F +#define WM8915_WRITE_SEQUENCER_304 0x3130 +#define WM8915_WRITE_SEQUENCER_305 0x3131 +#define WM8915_WRITE_SEQUENCER_306 0x3132 +#define WM8915_WRITE_SEQUENCER_307 0x3133 +#define WM8915_WRITE_SEQUENCER_308 0x3134 +#define WM8915_WRITE_SEQUENCER_309 0x3135 +#define WM8915_WRITE_SEQUENCER_310 0x3136 +#define WM8915_WRITE_SEQUENCER_311 0x3137 +#define WM8915_WRITE_SEQUENCER_312 0x3138 +#define WM8915_WRITE_SEQUENCER_313 0x3139 +#define WM8915_WRITE_SEQUENCER_314 0x313A +#define WM8915_WRITE_SEQUENCER_315 0x313B +#define WM8915_WRITE_SEQUENCER_316 0x313C +#define WM8915_WRITE_SEQUENCER_317 0x313D +#define WM8915_WRITE_SEQUENCER_318 0x313E +#define WM8915_WRITE_SEQUENCER_319 0x313F +#define WM8915_WRITE_SEQUENCER_320 0x3140 +#define WM8915_WRITE_SEQUENCER_321 0x3141 +#define WM8915_WRITE_SEQUENCER_322 0x3142 +#define WM8915_WRITE_SEQUENCER_323 0x3143 +#define WM8915_WRITE_SEQUENCER_324 0x3144 +#define WM8915_WRITE_SEQUENCER_325 0x3145 +#define WM8915_WRITE_SEQUENCER_326 0x3146 +#define WM8915_WRITE_SEQUENCER_327 0x3147 +#define WM8915_WRITE_SEQUENCER_328 0x3148 +#define WM8915_WRITE_SEQUENCER_329 0x3149 +#define WM8915_WRITE_SEQUENCER_330 0x314A +#define WM8915_WRITE_SEQUENCER_331 0x314B +#define WM8915_WRITE_SEQUENCER_332 0x314C +#define WM8915_WRITE_SEQUENCER_333 0x314D +#define WM8915_WRITE_SEQUENCER_334 0x314E +#define WM8915_WRITE_SEQUENCER_335 0x314F +#define WM8915_WRITE_SEQUENCER_336 0x3150 +#define WM8915_WRITE_SEQUENCER_337 0x3151 +#define WM8915_WRITE_SEQUENCER_338 0x3152 +#define WM8915_WRITE_SEQUENCER_339 0x3153 +#define WM8915_WRITE_SEQUENCER_340 0x3154 +#define WM8915_WRITE_SEQUENCER_341 0x3155 +#define WM8915_WRITE_SEQUENCER_342 0x3156 +#define WM8915_WRITE_SEQUENCER_343 0x3157 +#define WM8915_WRITE_SEQUENCER_344 0x3158 +#define WM8915_WRITE_SEQUENCER_345 0x3159 +#define WM8915_WRITE_SEQUENCER_346 0x315A +#define WM8915_WRITE_SEQUENCER_347 0x315B +#define WM8915_WRITE_SEQUENCER_348 0x315C +#define WM8915_WRITE_SEQUENCER_349 0x315D +#define WM8915_WRITE_SEQUENCER_350 0x315E +#define WM8915_WRITE_SEQUENCER_351 0x315F +#define WM8915_WRITE_SEQUENCER_352 0x3160 +#define WM8915_WRITE_SEQUENCER_353 0x3161 +#define WM8915_WRITE_SEQUENCER_354 0x3162 +#define WM8915_WRITE_SEQUENCER_355 0x3163 +#define WM8915_WRITE_SEQUENCER_356 0x3164 +#define WM8915_WRITE_SEQUENCER_357 0x3165 +#define WM8915_WRITE_SEQUENCER_358 0x3166 +#define WM8915_WRITE_SEQUENCER_359 0x3167 +#define WM8915_WRITE_SEQUENCER_360 0x3168 +#define WM8915_WRITE_SEQUENCER_361 0x3169 +#define WM8915_WRITE_SEQUENCER_362 0x316A +#define WM8915_WRITE_SEQUENCER_363 0x316B +#define WM8915_WRITE_SEQUENCER_364 0x316C +#define WM8915_WRITE_SEQUENCER_365 0x316D +#define WM8915_WRITE_SEQUENCER_366 0x316E +#define WM8915_WRITE_SEQUENCER_367 0x316F +#define WM8915_WRITE_SEQUENCER_368 0x3170 +#define WM8915_WRITE_SEQUENCER_369 0x3171 +#define WM8915_WRITE_SEQUENCER_370 0x3172 +#define WM8915_WRITE_SEQUENCER_371 0x3173 +#define WM8915_WRITE_SEQUENCER_372 0x3174 +#define WM8915_WRITE_SEQUENCER_373 0x3175 +#define WM8915_WRITE_SEQUENCER_374 0x3176 +#define WM8915_WRITE_SEQUENCER_375 0x3177 +#define WM8915_WRITE_SEQUENCER_376 0x3178 +#define WM8915_WRITE_SEQUENCER_377 0x3179 +#define WM8915_WRITE_SEQUENCER_378 0x317A +#define WM8915_WRITE_SEQUENCER_379 0x317B +#define WM8915_WRITE_SEQUENCER_380 0x317C +#define WM8915_WRITE_SEQUENCER_381 0x317D +#define WM8915_WRITE_SEQUENCER_382 0x317E +#define WM8915_WRITE_SEQUENCER_383 0x317F +#define WM8915_WRITE_SEQUENCER_384 0x3180 +#define WM8915_WRITE_SEQUENCER_385 0x3181 +#define WM8915_WRITE_SEQUENCER_386 0x3182 +#define WM8915_WRITE_SEQUENCER_387 0x3183 +#define WM8915_WRITE_SEQUENCER_388 0x3184 +#define WM8915_WRITE_SEQUENCER_389 0x3185 +#define WM8915_WRITE_SEQUENCER_390 0x3186 +#define WM8915_WRITE_SEQUENCER_391 0x3187 +#define WM8915_WRITE_SEQUENCER_392 0x3188 +#define WM8915_WRITE_SEQUENCER_393 0x3189 +#define WM8915_WRITE_SEQUENCER_394 0x318A +#define WM8915_WRITE_SEQUENCER_395 0x318B +#define WM8915_WRITE_SEQUENCER_396 0x318C +#define WM8915_WRITE_SEQUENCER_397 0x318D +#define WM8915_WRITE_SEQUENCER_398 0x318E +#define WM8915_WRITE_SEQUENCER_399 0x318F +#define WM8915_WRITE_SEQUENCER_400 0x3190 +#define WM8915_WRITE_SEQUENCER_401 0x3191 +#define WM8915_WRITE_SEQUENCER_402 0x3192 +#define WM8915_WRITE_SEQUENCER_403 0x3193 +#define WM8915_WRITE_SEQUENCER_404 0x3194 +#define WM8915_WRITE_SEQUENCER_405 0x3195 +#define WM8915_WRITE_SEQUENCER_406 0x3196 +#define WM8915_WRITE_SEQUENCER_407 0x3197 +#define WM8915_WRITE_SEQUENCER_408 0x3198 +#define WM8915_WRITE_SEQUENCER_409 0x3199 +#define WM8915_WRITE_SEQUENCER_410 0x319A +#define WM8915_WRITE_SEQUENCER_411 0x319B +#define WM8915_WRITE_SEQUENCER_412 0x319C +#define WM8915_WRITE_SEQUENCER_413 0x319D +#define WM8915_WRITE_SEQUENCER_414 0x319E +#define WM8915_WRITE_SEQUENCER_415 0x319F +#define WM8915_WRITE_SEQUENCER_416 0x31A0 +#define WM8915_WRITE_SEQUENCER_417 0x31A1 +#define WM8915_WRITE_SEQUENCER_418 0x31A2 +#define WM8915_WRITE_SEQUENCER_419 0x31A3 +#define WM8915_WRITE_SEQUENCER_420 0x31A4 +#define WM8915_WRITE_SEQUENCER_421 0x31A5 +#define WM8915_WRITE_SEQUENCER_422 0x31A6 +#define WM8915_WRITE_SEQUENCER_423 0x31A7 +#define WM8915_WRITE_SEQUENCER_424 0x31A8 +#define WM8915_WRITE_SEQUENCER_425 0x31A9 +#define WM8915_WRITE_SEQUENCER_426 0x31AA +#define WM8915_WRITE_SEQUENCER_427 0x31AB +#define WM8915_WRITE_SEQUENCER_428 0x31AC +#define WM8915_WRITE_SEQUENCER_429 0x31AD +#define WM8915_WRITE_SEQUENCER_430 0x31AE +#define WM8915_WRITE_SEQUENCER_431 0x31AF +#define WM8915_WRITE_SEQUENCER_432 0x31B0 +#define WM8915_WRITE_SEQUENCER_433 0x31B1 +#define WM8915_WRITE_SEQUENCER_434 0x31B2 +#define WM8915_WRITE_SEQUENCER_435 0x31B3 +#define WM8915_WRITE_SEQUENCER_436 0x31B4 +#define WM8915_WRITE_SEQUENCER_437 0x31B5 +#define WM8915_WRITE_SEQUENCER_438 0x31B6 +#define WM8915_WRITE_SEQUENCER_439 0x31B7 +#define WM8915_WRITE_SEQUENCER_440 0x31B8 +#define WM8915_WRITE_SEQUENCER_441 0x31B9 +#define WM8915_WRITE_SEQUENCER_442 0x31BA +#define WM8915_WRITE_SEQUENCER_443 0x31BB +#define WM8915_WRITE_SEQUENCER_444 0x31BC +#define WM8915_WRITE_SEQUENCER_445 0x31BD +#define WM8915_WRITE_SEQUENCER_446 0x31BE +#define WM8915_WRITE_SEQUENCER_447 0x31BF +#define WM8915_WRITE_SEQUENCER_448 0x31C0 +#define WM8915_WRITE_SEQUENCER_449 0x31C1 +#define WM8915_WRITE_SEQUENCER_450 0x31C2 +#define WM8915_WRITE_SEQUENCER_451 0x31C3 +#define WM8915_WRITE_SEQUENCER_452 0x31C4 +#define WM8915_WRITE_SEQUENCER_453 0x31C5 +#define WM8915_WRITE_SEQUENCER_454 0x31C6 +#define WM8915_WRITE_SEQUENCER_455 0x31C7 +#define WM8915_WRITE_SEQUENCER_456 0x31C8 +#define WM8915_WRITE_SEQUENCER_457 0x31C9 +#define WM8915_WRITE_SEQUENCER_458 0x31CA +#define WM8915_WRITE_SEQUENCER_459 0x31CB +#define WM8915_WRITE_SEQUENCER_460 0x31CC +#define WM8915_WRITE_SEQUENCER_461 0x31CD +#define WM8915_WRITE_SEQUENCER_462 0x31CE +#define WM8915_WRITE_SEQUENCER_463 0x31CF +#define WM8915_WRITE_SEQUENCER_464 0x31D0 +#define WM8915_WRITE_SEQUENCER_465 0x31D1 +#define WM8915_WRITE_SEQUENCER_466 0x31D2 +#define WM8915_WRITE_SEQUENCER_467 0x31D3 +#define WM8915_WRITE_SEQUENCER_468 0x31D4 +#define WM8915_WRITE_SEQUENCER_469 0x31D5 +#define WM8915_WRITE_SEQUENCER_470 0x31D6 +#define WM8915_WRITE_SEQUENCER_471 0x31D7 +#define WM8915_WRITE_SEQUENCER_472 0x31D8 +#define WM8915_WRITE_SEQUENCER_473 0x31D9 +#define WM8915_WRITE_SEQUENCER_474 0x31DA +#define WM8915_WRITE_SEQUENCER_475 0x31DB +#define WM8915_WRITE_SEQUENCER_476 0x31DC +#define WM8915_WRITE_SEQUENCER_477 0x31DD +#define WM8915_WRITE_SEQUENCER_478 0x31DE +#define WM8915_WRITE_SEQUENCER_479 0x31DF +#define WM8915_WRITE_SEQUENCER_480 0x31E0 +#define WM8915_WRITE_SEQUENCER_481 0x31E1 +#define WM8915_WRITE_SEQUENCER_482 0x31E2 +#define WM8915_WRITE_SEQUENCER_483 0x31E3 +#define WM8915_WRITE_SEQUENCER_484 0x31E4 +#define WM8915_WRITE_SEQUENCER_485 0x31E5 +#define WM8915_WRITE_SEQUENCER_486 0x31E6 +#define WM8915_WRITE_SEQUENCER_487 0x31E7 +#define WM8915_WRITE_SEQUENCER_488 0x31E8 +#define WM8915_WRITE_SEQUENCER_489 0x31E9 +#define WM8915_WRITE_SEQUENCER_490 0x31EA +#define WM8915_WRITE_SEQUENCER_491 0x31EB +#define WM8915_WRITE_SEQUENCER_492 0x31EC +#define WM8915_WRITE_SEQUENCER_493 0x31ED +#define WM8915_WRITE_SEQUENCER_494 0x31EE +#define WM8915_WRITE_SEQUENCER_495 0x31EF +#define WM8915_WRITE_SEQUENCER_496 0x31F0 +#define WM8915_WRITE_SEQUENCER_497 0x31F1 +#define WM8915_WRITE_SEQUENCER_498 0x31F2 +#define WM8915_WRITE_SEQUENCER_499 0x31F3 +#define WM8915_WRITE_SEQUENCER_500 0x31F4 +#define WM8915_WRITE_SEQUENCER_501 0x31F5 +#define WM8915_WRITE_SEQUENCER_502 0x31F6 +#define WM8915_WRITE_SEQUENCER_503 0x31F7 +#define WM8915_WRITE_SEQUENCER_504 0x31F8 +#define WM8915_WRITE_SEQUENCER_505 0x31F9 +#define WM8915_WRITE_SEQUENCER_506 0x31FA +#define WM8915_WRITE_SEQUENCER_507 0x31FB +#define WM8915_WRITE_SEQUENCER_508 0x31FC +#define WM8915_WRITE_SEQUENCER_509 0x31FD +#define WM8915_WRITE_SEQUENCER_510 0x31FE +#define WM8915_WRITE_SEQUENCER_511 0x31FF + +#define WM8915_REGISTER_COUNT 706 +#define WM8915_MAX_REGISTER 0x31FF + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - Software Reset + */ +#define WM8915_SW_RESET_MASK 0xFFFF /* SW_RESET - [15:0] */ +#define WM8915_SW_RESET_SHIFT 0 /* SW_RESET - [15:0] */ +#define WM8915_SW_RESET_WIDTH 16 /* SW_RESET - [15:0] */ + +/* + * R1 (0x01) - Power Management (1) + */ +#define WM8915_MICB2_ENA 0x0200 /* MICB2_ENA */ +#define WM8915_MICB2_ENA_MASK 0x0200 /* MICB2_ENA */ +#define WM8915_MICB2_ENA_SHIFT 9 /* MICB2_ENA */ +#define WM8915_MICB2_ENA_WIDTH 1 /* MICB2_ENA */ +#define WM8915_MICB1_ENA 0x0100 /* MICB1_ENA */ +#define WM8915_MICB1_ENA_MASK 0x0100 /* MICB1_ENA */ +#define WM8915_MICB1_ENA_SHIFT 8 /* MICB1_ENA */ +#define WM8915_MICB1_ENA_WIDTH 1 /* MICB1_ENA */ +#define WM8915_HPOUT2L_ENA 0x0080 /* HPOUT2L_ENA */ +#define WM8915_HPOUT2L_ENA_MASK 0x0080 /* HPOUT2L_ENA */ +#define WM8915_HPOUT2L_ENA_SHIFT 7 /* HPOUT2L_ENA */ +#define WM8915_HPOUT2L_ENA_WIDTH 1 /* HPOUT2L_ENA */ +#define WM8915_HPOUT2R_ENA 0x0040 /* HPOUT2R_ENA */ +#define WM8915_HPOUT2R_ENA_MASK 0x0040 /* HPOUT2R_ENA */ +#define WM8915_HPOUT2R_ENA_SHIFT 6 /* HPOUT2R_ENA */ +#define WM8915_HPOUT2R_ENA_WIDTH 1 /* HPOUT2R_ENA */ +#define WM8915_HPOUT1L_ENA 0x0020 /* HPOUT1L_ENA */ +#define WM8915_HPOUT1L_ENA_MASK 0x0020 /* HPOUT1L_ENA */ +#define WM8915_HPOUT1L_ENA_SHIFT 5 /* HPOUT1L_ENA */ +#define WM8915_HPOUT1L_ENA_WIDTH 1 /* HPOUT1L_ENA */ +#define WM8915_HPOUT1R_ENA 0x0010 /* HPOUT1R_ENA */ +#define WM8915_HPOUT1R_ENA_MASK 0x0010 /* HPOUT1R_ENA */ +#define WM8915_HPOUT1R_ENA_SHIFT 4 /* HPOUT1R_ENA */ +#define WM8915_HPOUT1R_ENA_WIDTH 1 /* HPOUT1R_ENA */ +#define WM8915_BG_ENA 0x0001 /* BG_ENA */ +#define WM8915_BG_ENA_MASK 0x0001 /* BG_ENA */ +#define WM8915_BG_ENA_SHIFT 0 /* BG_ENA */ +#define WM8915_BG_ENA_WIDTH 1 /* BG_ENA */ + +/* + * R2 (0x02) - Power Management (2) + */ +#define WM8915_OPCLK_ENA 0x0800 /* OPCLK_ENA */ +#define WM8915_OPCLK_ENA_MASK 0x0800 /* OPCLK_ENA */ +#define WM8915_OPCLK_ENA_SHIFT 11 /* OPCLK_ENA */ +#define WM8915_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */ +#define WM8915_INL_ENA 0x0020 /* INL_ENA */ +#define WM8915_INL_ENA_MASK 0x0020 /* INL_ENA */ +#define WM8915_INL_ENA_SHIFT 5 /* INL_ENA */ +#define WM8915_INL_ENA_WIDTH 1 /* INL_ENA */ +#define WM8915_INR_ENA 0x0010 /* INR_ENA */ +#define WM8915_INR_ENA_MASK 0x0010 /* INR_ENA */ +#define WM8915_INR_ENA_SHIFT 4 /* INR_ENA */ +#define WM8915_INR_ENA_WIDTH 1 /* INR_ENA */ +#define WM8915_LDO2_ENA 0x0002 /* LDO2_ENA */ +#define WM8915_LDO2_ENA_MASK 0x0002 /* LDO2_ENA */ +#define WM8915_LDO2_ENA_SHIFT 1 /* LDO2_ENA */ +#define WM8915_LDO2_ENA_WIDTH 1 /* LDO2_ENA */ + +/* + * R3 (0x03) - Power Management (3) + */ +#define WM8915_DSP2RXL_ENA 0x0800 /* DSP2RXL_ENA */ +#define WM8915_DSP2RXL_ENA_MASK 0x0800 /* DSP2RXL_ENA */ +#define WM8915_DSP2RXL_ENA_SHIFT 11 /* DSP2RXL_ENA */ +#define WM8915_DSP2RXL_ENA_WIDTH 1 /* DSP2RXL_ENA */ +#define WM8915_DSP2RXR_ENA 0x0400 /* DSP2RXR_ENA */ +#define WM8915_DSP2RXR_ENA_MASK 0x0400 /* DSP2RXR_ENA */ +#define WM8915_DSP2RXR_ENA_SHIFT 10 /* DSP2RXR_ENA */ +#define WM8915_DSP2RXR_ENA_WIDTH 1 /* DSP2RXR_ENA */ +#define WM8915_DSP1RXL_ENA 0x0200 /* DSP1RXL_ENA */ +#define WM8915_DSP1RXL_ENA_MASK 0x0200 /* DSP1RXL_ENA */ +#define WM8915_DSP1RXL_ENA_SHIFT 9 /* DSP1RXL_ENA */ +#define WM8915_DSP1RXL_ENA_WIDTH 1 /* DSP1RXL_ENA */ +#define WM8915_DSP1RXR_ENA 0x0100 /* DSP1RXR_ENA */ +#define WM8915_DSP1RXR_ENA_MASK 0x0100 /* DSP1RXR_ENA */ +#define WM8915_DSP1RXR_ENA_SHIFT 8 /* DSP1RXR_ENA */ +#define WM8915_DSP1RXR_ENA_WIDTH 1 /* DSP1RXR_ENA */ +#define WM8915_DMIC2L_ENA 0x0020 /* DMIC2L_ENA */ +#define WM8915_DMIC2L_ENA_MASK 0x0020 /* DMIC2L_ENA */ +#define WM8915_DMIC2L_ENA_SHIFT 5 /* DMIC2L_ENA */ +#define WM8915_DMIC2L_ENA_WIDTH 1 /* DMIC2L_ENA */ +#define WM8915_DMIC2R_ENA 0x0010 /* DMIC2R_ENA */ +#define WM8915_DMIC2R_ENA_MASK 0x0010 /* DMIC2R_ENA */ +#define WM8915_DMIC2R_ENA_SHIFT 4 /* DMIC2R_ENA */ +#define WM8915_DMIC2R_ENA_WIDTH 1 /* DMIC2R_ENA */ +#define WM8915_DMIC1L_ENA 0x0008 /* DMIC1L_ENA */ +#define WM8915_DMIC1L_ENA_MASK 0x0008 /* DMIC1L_ENA */ +#define WM8915_DMIC1L_ENA_SHIFT 3 /* DMIC1L_ENA */ +#define WM8915_DMIC1L_ENA_WIDTH 1 /* DMIC1L_ENA */ +#define WM8915_DMIC1R_ENA 0x0004 /* DMIC1R_ENA */ +#define WM8915_DMIC1R_ENA_MASK 0x0004 /* DMIC1R_ENA */ +#define WM8915_DMIC1R_ENA_SHIFT 2 /* DMIC1R_ENA */ +#define WM8915_DMIC1R_ENA_WIDTH 1 /* DMIC1R_ENA */ +#define WM8915_ADCL_ENA 0x0002 /* ADCL_ENA */ +#define WM8915_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */ +#define WM8915_ADCL_ENA_SHIFT 1 /* ADCL_ENA */ +#define WM8915_ADCL_ENA_WIDTH 1 /* ADCL_ENA */ +#define WM8915_ADCR_ENA 0x0001 /* ADCR_ENA */ +#define WM8915_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */ +#define WM8915_ADCR_ENA_SHIFT 0 /* ADCR_ENA */ +#define WM8915_ADCR_ENA_WIDTH 1 /* ADCR_ENA */ + +/* + * R4 (0x04) - Power Management (4) + */ +#define WM8915_AIF2RX_CHAN1_ENA 0x0200 /* AIF2RX_CHAN1_ENA */ +#define WM8915_AIF2RX_CHAN1_ENA_MASK 0x0200 /* AIF2RX_CHAN1_ENA */ +#define WM8915_AIF2RX_CHAN1_ENA_SHIFT 9 /* AIF2RX_CHAN1_ENA */ +#define WM8915_AIF2RX_CHAN1_ENA_WIDTH 1 /* AIF2RX_CHAN1_ENA */ +#define WM8915_AIF2RX_CHAN0_ENA 0x0100 /* AIF2RX_CHAN0_ENA */ +#define WM8915_AIF2RX_CHAN0_ENA_MASK 0x0100 /* AIF2RX_CHAN0_ENA */ +#define WM8915_AIF2RX_CHAN0_ENA_SHIFT 8 /* AIF2RX_CHAN0_ENA */ +#define WM8915_AIF2RX_CHAN0_ENA_WIDTH 1 /* AIF2RX_CHAN0_ENA */ +#define WM8915_AIF1RX_CHAN5_ENA 0x0020 /* AIF1RX_CHAN5_ENA */ +#define WM8915_AIF1RX_CHAN5_ENA_MASK 0x0020 /* AIF1RX_CHAN5_ENA */ +#define WM8915_AIF1RX_CHAN5_ENA_SHIFT 5 /* AIF1RX_CHAN5_ENA */ +#define WM8915_AIF1RX_CHAN5_ENA_WIDTH 1 /* AIF1RX_CHAN5_ENA */ +#define WM8915_AIF1RX_CHAN4_ENA 0x0010 /* AIF1RX_CHAN4_ENA */ +#define WM8915_AIF1RX_CHAN4_ENA_MASK 0x0010 /* AIF1RX_CHAN4_ENA */ +#define WM8915_AIF1RX_CHAN4_ENA_SHIFT 4 /* AIF1RX_CHAN4_ENA */ +#define WM8915_AIF1RX_CHAN4_ENA_WIDTH 1 /* AIF1RX_CHAN4_ENA */ +#define WM8915_AIF1RX_CHAN3_ENA 0x0008 /* AIF1RX_CHAN3_ENA */ +#define WM8915_AIF1RX_CHAN3_ENA_MASK 0x0008 /* AIF1RX_CHAN3_ENA */ +#define WM8915_AIF1RX_CHAN3_ENA_SHIFT 3 /* AIF1RX_CHAN3_ENA */ +#define WM8915_AIF1RX_CHAN3_ENA_WIDTH 1 /* AIF1RX_CHAN3_ENA */ +#define WM8915_AIF1RX_CHAN2_ENA 0x0004 /* AIF1RX_CHAN2_ENA */ +#define WM8915_AIF1RX_CHAN2_ENA_MASK 0x0004 /* AIF1RX_CHAN2_ENA */ +#define WM8915_AIF1RX_CHAN2_ENA_SHIFT 2 /* AIF1RX_CHAN2_ENA */ +#define WM8915_AIF1RX_CHAN2_ENA_WIDTH 1 /* AIF1RX_CHAN2_ENA */ +#define WM8915_AIF1RX_CHAN1_ENA 0x0002 /* AIF1RX_CHAN1_ENA */ +#define WM8915_AIF1RX_CHAN1_ENA_MASK 0x0002 /* AIF1RX_CHAN1_ENA */ +#define WM8915_AIF1RX_CHAN1_ENA_SHIFT 1 /* AIF1RX_CHAN1_ENA */ +#define WM8915_AIF1RX_CHAN1_ENA_WIDTH 1 /* AIF1RX_CHAN1_ENA */ +#define WM8915_AIF1RX_CHAN0_ENA 0x0001 /* AIF1RX_CHAN0_ENA */ +#define WM8915_AIF1RX_CHAN0_ENA_MASK 0x0001 /* AIF1RX_CHAN0_ENA */ +#define WM8915_AIF1RX_CHAN0_ENA_SHIFT 0 /* AIF1RX_CHAN0_ENA */ +#define WM8915_AIF1RX_CHAN0_ENA_WIDTH 1 /* AIF1RX_CHAN0_ENA */ + +/* + * R5 (0x05) - Power Management (5) + */ +#define WM8915_DSP2TXL_ENA 0x0800 /* DSP2TXL_ENA */ +#define WM8915_DSP2TXL_ENA_MASK 0x0800 /* DSP2TXL_ENA */ +#define WM8915_DSP2TXL_ENA_SHIFT 11 /* DSP2TXL_ENA */ +#define WM8915_DSP2TXL_ENA_WIDTH 1 /* DSP2TXL_ENA */ +#define WM8915_DSP2TXR_ENA 0x0400 /* DSP2TXR_ENA */ +#define WM8915_DSP2TXR_ENA_MASK 0x0400 /* DSP2TXR_ENA */ +#define WM8915_DSP2TXR_ENA_SHIFT 10 /* DSP2TXR_ENA */ +#define WM8915_DSP2TXR_ENA_WIDTH 1 /* DSP2TXR_ENA */ +#define WM8915_DSP1TXL_ENA 0x0200 /* DSP1TXL_ENA */ +#define WM8915_DSP1TXL_ENA_MASK 0x0200 /* DSP1TXL_ENA */ +#define WM8915_DSP1TXL_ENA_SHIFT 9 /* DSP1TXL_ENA */ +#define WM8915_DSP1TXL_ENA_WIDTH 1 /* DSP1TXL_ENA */ +#define WM8915_DSP1TXR_ENA 0x0100 /* DSP1TXR_ENA */ +#define WM8915_DSP1TXR_ENA_MASK 0x0100 /* DSP1TXR_ENA */ +#define WM8915_DSP1TXR_ENA_SHIFT 8 /* DSP1TXR_ENA */ +#define WM8915_DSP1TXR_ENA_WIDTH 1 /* DSP1TXR_ENA */ +#define WM8915_DAC2L_ENA 0x0008 /* DAC2L_ENA */ +#define WM8915_DAC2L_ENA_MASK 0x0008 /* DAC2L_ENA */ +#define WM8915_DAC2L_ENA_SHIFT 3 /* DAC2L_ENA */ +#define WM8915_DAC2L_ENA_WIDTH 1 /* DAC2L_ENA */ +#define WM8915_DAC2R_ENA 0x0004 /* DAC2R_ENA */ +#define WM8915_DAC2R_ENA_MASK 0x0004 /* DAC2R_ENA */ +#define WM8915_DAC2R_ENA_SHIFT 2 /* DAC2R_ENA */ +#define WM8915_DAC2R_ENA_WIDTH 1 /* DAC2R_ENA */ +#define WM8915_DAC1L_ENA 0x0002 /* DAC1L_ENA */ +#define WM8915_DAC1L_ENA_MASK 0x0002 /* DAC1L_ENA */ +#define WM8915_DAC1L_ENA_SHIFT 1 /* DAC1L_ENA */ +#define WM8915_DAC1L_ENA_WIDTH 1 /* DAC1L_ENA */ +#define WM8915_DAC1R_ENA 0x0001 /* DAC1R_ENA */ +#define WM8915_DAC1R_ENA_MASK 0x0001 /* DAC1R_ENA */ +#define WM8915_DAC1R_ENA_SHIFT 0 /* DAC1R_ENA */ +#define WM8915_DAC1R_ENA_WIDTH 1 /* DAC1R_ENA */ + +/* + * R6 (0x06) - Power Management (6) + */ +#define WM8915_AIF2TX_CHAN1_ENA 0x0200 /* AIF2TX_CHAN1_ENA */ +#define WM8915_AIF2TX_CHAN1_ENA_MASK 0x0200 /* AIF2TX_CHAN1_ENA */ +#define WM8915_AIF2TX_CHAN1_ENA_SHIFT 9 /* AIF2TX_CHAN1_ENA */ +#define WM8915_AIF2TX_CHAN1_ENA_WIDTH 1 /* AIF2TX_CHAN1_ENA */ +#define WM8915_AIF2TX_CHAN0_ENA 0x0100 /* AIF2TX_CHAN0_ENA */ +#define WM8915_AIF2TX_CHAN0_ENA_MASK 0x0100 /* AIF2TX_CHAN0_ENA */ +#define WM8915_AIF2TX_CHAN0_ENA_SHIFT 8 /* AIF2TX_CHAN0_ENA */ +#define WM8915_AIF2TX_CHAN0_ENA_WIDTH 1 /* AIF2TX_CHAN0_ENA */ +#define WM8915_AIF1TX_CHAN5_ENA 0x0020 /* AIF1TX_CHAN5_ENA */ +#define WM8915_AIF1TX_CHAN5_ENA_MASK 0x0020 /* AIF1TX_CHAN5_ENA */ +#define WM8915_AIF1TX_CHAN5_ENA_SHIFT 5 /* AIF1TX_CHAN5_ENA */ +#define WM8915_AIF1TX_CHAN5_ENA_WIDTH 1 /* AIF1TX_CHAN5_ENA */ +#define WM8915_AIF1TX_CHAN4_ENA 0x0010 /* AIF1TX_CHAN4_ENA */ +#define WM8915_AIF1TX_CHAN4_ENA_MASK 0x0010 /* AIF1TX_CHAN4_ENA */ +#define WM8915_AIF1TX_CHAN4_ENA_SHIFT 4 /* AIF1TX_CHAN4_ENA */ +#define WM8915_AIF1TX_CHAN4_ENA_WIDTH 1 /* AIF1TX_CHAN4_ENA */ +#define WM8915_AIF1TX_CHAN3_ENA 0x0008 /* AIF1TX_CHAN3_ENA */ +#define WM8915_AIF1TX_CHAN3_ENA_MASK 0x0008 /* AIF1TX_CHAN3_ENA */ +#define WM8915_AIF1TX_CHAN3_ENA_SHIFT 3 /* AIF1TX_CHAN3_ENA */ +#define WM8915_AIF1TX_CHAN3_ENA_WIDTH 1 /* AIF1TX_CHAN3_ENA */ +#define WM8915_AIF1TX_CHAN2_ENA 0x0004 /* AIF1TX_CHAN2_ENA */ +#define WM8915_AIF1TX_CHAN2_ENA_MASK 0x0004 /* AIF1TX_CHAN2_ENA */ +#define WM8915_AIF1TX_CHAN2_ENA_SHIFT 2 /* AIF1TX_CHAN2_ENA */ +#define WM8915_AIF1TX_CHAN2_ENA_WIDTH 1 /* AIF1TX_CHAN2_ENA */ +#define WM8915_AIF1TX_CHAN1_ENA 0x0002 /* AIF1TX_CHAN1_ENA */ +#define WM8915_AIF1TX_CHAN1_ENA_MASK 0x0002 /* AIF1TX_CHAN1_ENA */ +#define WM8915_AIF1TX_CHAN1_ENA_SHIFT 1 /* AIF1TX_CHAN1_ENA */ +#define WM8915_AIF1TX_CHAN1_ENA_WIDTH 1 /* AIF1TX_CHAN1_ENA */ +#define WM8915_AIF1TX_CHAN0_ENA 0x0001 /* AIF1TX_CHAN0_ENA */ +#define WM8915_AIF1TX_CHAN0_ENA_MASK 0x0001 /* AIF1TX_CHAN0_ENA */ +#define WM8915_AIF1TX_CHAN0_ENA_SHIFT 0 /* AIF1TX_CHAN0_ENA */ +#define WM8915_AIF1TX_CHAN0_ENA_WIDTH 1 /* AIF1TX_CHAN0_ENA */ + +/* + * R7 (0x07) - Power Management (7) + */ +#define WM8915_DMIC2_FN 0x0200 /* DMIC2_FN */ +#define WM8915_DMIC2_FN_MASK 0x0200 /* DMIC2_FN */ +#define WM8915_DMIC2_FN_SHIFT 9 /* DMIC2_FN */ +#define WM8915_DMIC2_FN_WIDTH 1 /* DMIC2_FN */ +#define WM8915_DMIC1_FN 0x0100 /* DMIC1_FN */ +#define WM8915_DMIC1_FN_MASK 0x0100 /* DMIC1_FN */ +#define WM8915_DMIC1_FN_SHIFT 8 /* DMIC1_FN */ +#define WM8915_DMIC1_FN_WIDTH 1 /* DMIC1_FN */ +#define WM8915_ADC_DMIC_DSP2R_ENA 0x0080 /* ADC_DMIC_DSP2R_ENA */ +#define WM8915_ADC_DMIC_DSP2R_ENA_MASK 0x0080 /* ADC_DMIC_DSP2R_ENA */ +#define WM8915_ADC_DMIC_DSP2R_ENA_SHIFT 7 /* ADC_DMIC_DSP2R_ENA */ +#define WM8915_ADC_DMIC_DSP2R_ENA_WIDTH 1 /* ADC_DMIC_DSP2R_ENA */ +#define WM8915_ADC_DMIC_DSP2L_ENA 0x0040 /* ADC_DMIC_DSP2L_ENA */ +#define WM8915_ADC_DMIC_DSP2L_ENA_MASK 0x0040 /* ADC_DMIC_DSP2L_ENA */ +#define WM8915_ADC_DMIC_DSP2L_ENA_SHIFT 6 /* ADC_DMIC_DSP2L_ENA */ +#define WM8915_ADC_DMIC_DSP2L_ENA_WIDTH 1 /* ADC_DMIC_DSP2L_ENA */ +#define WM8915_ADC_DMIC_SRC2_MASK 0x0030 /* ADC_DMIC_SRC2 - [5:4] */ +#define WM8915_ADC_DMIC_SRC2_SHIFT 4 /* ADC_DMIC_SRC2 - [5:4] */ +#define WM8915_ADC_DMIC_SRC2_WIDTH 2 /* ADC_DMIC_SRC2 - [5:4] */ +#define WM8915_ADC_DMIC_DSP1R_ENA 0x0008 /* ADC_DMIC_DSP1R_ENA */ +#define WM8915_ADC_DMIC_DSP1R_ENA_MASK 0x0008 /* ADC_DMIC_DSP1R_ENA */ +#define WM8915_ADC_DMIC_DSP1R_ENA_SHIFT 3 /* ADC_DMIC_DSP1R_ENA */ +#define WM8915_ADC_DMIC_DSP1R_ENA_WIDTH 1 /* ADC_DMIC_DSP1R_ENA */ +#define WM8915_ADC_DMIC_DSP1L_ENA 0x0004 /* ADC_DMIC_DSP1L_ENA */ +#define WM8915_ADC_DMIC_DSP1L_ENA_MASK 0x0004 /* ADC_DMIC_DSP1L_ENA */ +#define WM8915_ADC_DMIC_DSP1L_ENA_SHIFT 2 /* ADC_DMIC_DSP1L_ENA */ +#define WM8915_ADC_DMIC_DSP1L_ENA_WIDTH 1 /* ADC_DMIC_DSP1L_ENA */ +#define WM8915_ADC_DMIC_SRC1_MASK 0x0003 /* ADC_DMIC_SRC1 - [1:0] */ +#define WM8915_ADC_DMIC_SRC1_SHIFT 0 /* ADC_DMIC_SRC1 - [1:0] */ +#define WM8915_ADC_DMIC_SRC1_WIDTH 2 /* ADC_DMIC_SRC1 - [1:0] */ + +/* + * R8 (0x08) - Power Management (8) + */ +#define WM8915_AIF2TX_SRC_MASK 0x00C0 /* AIF2TX_SRC - [7:6] */ +#define WM8915_AIF2TX_SRC_SHIFT 6 /* AIF2TX_SRC - [7:6] */ +#define WM8915_AIF2TX_SRC_WIDTH 2 /* AIF2TX_SRC - [7:6] */ +#define WM8915_DSP2RX_SRC 0x0010 /* DSP2RX_SRC */ +#define WM8915_DSP2RX_SRC_MASK 0x0010 /* DSP2RX_SRC */ +#define WM8915_DSP2RX_SRC_SHIFT 4 /* DSP2RX_SRC */ +#define WM8915_DSP2RX_SRC_WIDTH 1 /* DSP2RX_SRC */ +#define WM8915_DSP1RX_SRC 0x0001 /* DSP1RX_SRC */ +#define WM8915_DSP1RX_SRC_MASK 0x0001 /* DSP1RX_SRC */ +#define WM8915_DSP1RX_SRC_SHIFT 0 /* DSP1RX_SRC */ +#define WM8915_DSP1RX_SRC_WIDTH 1 /* DSP1RX_SRC */ + +/* + * R16 (0x10) - Left Line Input Volume + */ +#define WM8915_IN1_VU 0x0080 /* IN1_VU */ +#define WM8915_IN1_VU_MASK 0x0080 /* IN1_VU */ +#define WM8915_IN1_VU_SHIFT 7 /* IN1_VU */ +#define WM8915_IN1_VU_WIDTH 1 /* IN1_VU */ +#define WM8915_IN1L_ZC 0x0020 /* IN1L_ZC */ +#define WM8915_IN1L_ZC_MASK 0x0020 /* IN1L_ZC */ +#define WM8915_IN1L_ZC_SHIFT 5 /* IN1L_ZC */ +#define WM8915_IN1L_ZC_WIDTH 1 /* IN1L_ZC */ +#define WM8915_IN1L_VOL_MASK 0x001F /* IN1L_VOL - [4:0] */ +#define WM8915_IN1L_VOL_SHIFT 0 /* IN1L_VOL - [4:0] */ +#define WM8915_IN1L_VOL_WIDTH 5 /* IN1L_VOL - [4:0] */ + +/* + * R17 (0x11) - Right Line Input Volume + */ +#define WM8915_IN1_VU 0x0080 /* IN1_VU */ +#define WM8915_IN1_VU_MASK 0x0080 /* IN1_VU */ +#define WM8915_IN1_VU_SHIFT 7 /* IN1_VU */ +#define WM8915_IN1_VU_WIDTH 1 /* IN1_VU */ +#define WM8915_IN1R_ZC 0x0020 /* IN1R_ZC */ +#define WM8915_IN1R_ZC_MASK 0x0020 /* IN1R_ZC */ +#define WM8915_IN1R_ZC_SHIFT 5 /* IN1R_ZC */ +#define WM8915_IN1R_ZC_WIDTH 1 /* IN1R_ZC */ +#define WM8915_IN1R_VOL_MASK 0x001F /* IN1R_VOL - [4:0] */ +#define WM8915_IN1R_VOL_SHIFT 0 /* IN1R_VOL - [4:0] */ +#define WM8915_IN1R_VOL_WIDTH 5 /* IN1R_VOL - [4:0] */ + +/* + * R18 (0x12) - Line Input Control + */ +#define WM8915_INL_MODE_MASK 0x000C /* INL_MODE - [3:2] */ +#define WM8915_INL_MODE_SHIFT 2 /* INL_MODE - [3:2] */ +#define WM8915_INL_MODE_WIDTH 2 /* INL_MODE - [3:2] */ +#define WM8915_INR_MODE_MASK 0x0003 /* INR_MODE - [1:0] */ +#define WM8915_INR_MODE_SHIFT 0 /* INR_MODE - [1:0] */ +#define WM8915_INR_MODE_WIDTH 2 /* INR_MODE - [1:0] */ + +/* + * R21 (0x15) - DAC1 HPOUT1 Volume + */ +#define WM8915_DAC1R_HPOUT1R_VOL_MASK 0x00F0 /* DAC1R_HPOUT1R_VOL - [7:4] */ +#define WM8915_DAC1R_HPOUT1R_VOL_SHIFT 4 /* DAC1R_HPOUT1R_VOL - [7:4] */ +#define WM8915_DAC1R_HPOUT1R_VOL_WIDTH 4 /* DAC1R_HPOUT1R_VOL - [7:4] */ +#define WM8915_DAC1L_HPOUT1L_VOL_MASK 0x000F /* DAC1L_HPOUT1L_VOL - [3:0] */ +#define WM8915_DAC1L_HPOUT1L_VOL_SHIFT 0 /* DAC1L_HPOUT1L_VOL - [3:0] */ +#define WM8915_DAC1L_HPOUT1L_VOL_WIDTH 4 /* DAC1L_HPOUT1L_VOL - [3:0] */ + +/* + * R22 (0x16) - DAC2 HPOUT2 Volume + */ +#define WM8915_DAC2R_HPOUT2R_VOL_MASK 0x00F0 /* DAC2R_HPOUT2R_VOL - [7:4] */ +#define WM8915_DAC2R_HPOUT2R_VOL_SHIFT 4 /* DAC2R_HPOUT2R_VOL - [7:4] */ +#define WM8915_DAC2R_HPOUT2R_VOL_WIDTH 4 /* DAC2R_HPOUT2R_VOL - [7:4] */ +#define WM8915_DAC2L_HPOUT2L_VOL_MASK 0x000F /* DAC2L_HPOUT2L_VOL - [3:0] */ +#define WM8915_DAC2L_HPOUT2L_VOL_SHIFT 0 /* DAC2L_HPOUT2L_VOL - [3:0] */ +#define WM8915_DAC2L_HPOUT2L_VOL_WIDTH 4 /* DAC2L_HPOUT2L_VOL - [3:0] */ + +/* + * R24 (0x18) - DAC1 Left Volume + */ +#define WM8915_DAC1L_MUTE 0x0200 /* DAC1L_MUTE */ +#define WM8915_DAC1L_MUTE_MASK 0x0200 /* DAC1L_MUTE */ +#define WM8915_DAC1L_MUTE_SHIFT 9 /* DAC1L_MUTE */ +#define WM8915_DAC1L_MUTE_WIDTH 1 /* DAC1L_MUTE */ +#define WM8915_DAC1_VU 0x0100 /* DAC1_VU */ +#define WM8915_DAC1_VU_MASK 0x0100 /* DAC1_VU */ +#define WM8915_DAC1_VU_SHIFT 8 /* DAC1_VU */ +#define WM8915_DAC1_VU_WIDTH 1 /* DAC1_VU */ +#define WM8915_DAC1L_VOL_MASK 0x00FF /* DAC1L_VOL - [7:0] */ +#define WM8915_DAC1L_VOL_SHIFT 0 /* DAC1L_VOL - [7:0] */ +#define WM8915_DAC1L_VOL_WIDTH 8 /* DAC1L_VOL - [7:0] */ + +/* + * R25 (0x19) - DAC1 Right Volume + */ +#define WM8915_DAC1R_MUTE 0x0200 /* DAC1R_MUTE */ +#define WM8915_DAC1R_MUTE_MASK 0x0200 /* DAC1R_MUTE */ +#define WM8915_DAC1R_MUTE_SHIFT 9 /* DAC1R_MUTE */ +#define WM8915_DAC1R_MUTE_WIDTH 1 /* DAC1R_MUTE */ +#define WM8915_DAC1_VU 0x0100 /* DAC1_VU */ +#define WM8915_DAC1_VU_MASK 0x0100 /* DAC1_VU */ +#define WM8915_DAC1_VU_SHIFT 8 /* DAC1_VU */ +#define WM8915_DAC1_VU_WIDTH 1 /* DAC1_VU */ +#define WM8915_DAC1R_VOL_MASK 0x00FF /* DAC1R_VOL - [7:0] */ +#define WM8915_DAC1R_VOL_SHIFT 0 /* DAC1R_VOL - [7:0] */ +#define WM8915_DAC1R_VOL_WIDTH 8 /* DAC1R_VOL - [7:0] */ + +/* + * R26 (0x1A) - DAC2 Left Volume + */ +#define WM8915_DAC2L_MUTE 0x0200 /* DAC2L_MUTE */ +#define WM8915_DAC2L_MUTE_MASK 0x0200 /* DAC2L_MUTE */ +#define WM8915_DAC2L_MUTE_SHIFT 9 /* DAC2L_MUTE */ +#define WM8915_DAC2L_MUTE_WIDTH 1 /* DAC2L_MUTE */ +#define WM8915_DAC2_VU 0x0100 /* DAC2_VU */ +#define WM8915_DAC2_VU_MASK 0x0100 /* DAC2_VU */ +#define WM8915_DAC2_VU_SHIFT 8 /* DAC2_VU */ +#define WM8915_DAC2_VU_WIDTH 1 /* DAC2_VU */ +#define WM8915_DAC2L_VOL_MASK 0x00FF /* DAC2L_VOL - [7:0] */ +#define WM8915_DAC2L_VOL_SHIFT 0 /* DAC2L_VOL - [7:0] */ +#define WM8915_DAC2L_VOL_WIDTH 8 /* DAC2L_VOL - [7:0] */ + +/* + * R27 (0x1B) - DAC2 Right Volume + */ +#define WM8915_DAC2R_MUTE 0x0200 /* DAC2R_MUTE */ +#define WM8915_DAC2R_MUTE_MASK 0x0200 /* DAC2R_MUTE */ +#define WM8915_DAC2R_MUTE_SHIFT 9 /* DAC2R_MUTE */ +#define WM8915_DAC2R_MUTE_WIDTH 1 /* DAC2R_MUTE */ +#define WM8915_DAC2_VU 0x0100 /* DAC2_VU */ +#define WM8915_DAC2_VU_MASK 0x0100 /* DAC2_VU */ +#define WM8915_DAC2_VU_SHIFT 8 /* DAC2_VU */ +#define WM8915_DAC2_VU_WIDTH 1 /* DAC2_VU */ +#define WM8915_DAC2R_VOL_MASK 0x00FF /* DAC2R_VOL - [7:0] */ +#define WM8915_DAC2R_VOL_SHIFT 0 /* DAC2R_VOL - [7:0] */ +#define WM8915_DAC2R_VOL_WIDTH 8 /* DAC2R_VOL - [7:0] */ + +/* + * R28 (0x1C) - Output1 Left Volume + */ +#define WM8915_DAC1_VU 0x0100 /* DAC1_VU */ +#define WM8915_DAC1_VU_MASK 0x0100 /* DAC1_VU */ +#define WM8915_DAC1_VU_SHIFT 8 /* DAC1_VU */ +#define WM8915_DAC1_VU_WIDTH 1 /* DAC1_VU */ +#define WM8915_HPOUT1L_ZC 0x0080 /* HPOUT1L_ZC */ +#define WM8915_HPOUT1L_ZC_MASK 0x0080 /* HPOUT1L_ZC */ +#define WM8915_HPOUT1L_ZC_SHIFT 7 /* HPOUT1L_ZC */ +#define WM8915_HPOUT1L_ZC_WIDTH 1 /* HPOUT1L_ZC */ +#define WM8915_HPOUT1L_VOL_MASK 0x000F /* HPOUT1L_VOL - [3:0] */ +#define WM8915_HPOUT1L_VOL_SHIFT 0 /* HPOUT1L_VOL - [3:0] */ +#define WM8915_HPOUT1L_VOL_WIDTH 4 /* HPOUT1L_VOL - [3:0] */ + +/* + * R29 (0x1D) - Output1 Right Volume + */ +#define WM8915_DAC1_VU 0x0100 /* DAC1_VU */ +#define WM8915_DAC1_VU_MASK 0x0100 /* DAC1_VU */ +#define WM8915_DAC1_VU_SHIFT 8 /* DAC1_VU */ +#define WM8915_DAC1_VU_WIDTH 1 /* DAC1_VU */ +#define WM8915_HPOUT1R_ZC 0x0080 /* HPOUT1R_ZC */ +#define WM8915_HPOUT1R_ZC_MASK 0x0080 /* HPOUT1R_ZC */ +#define WM8915_HPOUT1R_ZC_SHIFT 7 /* HPOUT1R_ZC */ +#define WM8915_HPOUT1R_ZC_WIDTH 1 /* HPOUT1R_ZC */ +#define WM8915_HPOUT1R_VOL_MASK 0x000F /* HPOUT1R_VOL - [3:0] */ +#define WM8915_HPOUT1R_VOL_SHIFT 0 /* HPOUT1R_VOL - [3:0] */ +#define WM8915_HPOUT1R_VOL_WIDTH 4 /* HPOUT1R_VOL - [3:0] */ + +/* + * R30 (0x1E) - Output2 Left Volume + */ +#define WM8915_DAC2_VU 0x0100 /* DAC2_VU */ +#define WM8915_DAC2_VU_MASK 0x0100 /* DAC2_VU */ +#define WM8915_DAC2_VU_SHIFT 8 /* DAC2_VU */ +#define WM8915_DAC2_VU_WIDTH 1 /* DAC2_VU */ +#define WM8915_HPOUT2L_ZC 0x0080 /* HPOUT2L_ZC */ +#define WM8915_HPOUT2L_ZC_MASK 0x0080 /* HPOUT2L_ZC */ +#define WM8915_HPOUT2L_ZC_SHIFT 7 /* HPOUT2L_ZC */ +#define WM8915_HPOUT2L_ZC_WIDTH 1 /* HPOUT2L_ZC */ +#define WM8915_HPOUT2L_VOL_MASK 0x000F /* HPOUT2L_VOL - [3:0] */ +#define WM8915_HPOUT2L_VOL_SHIFT 0 /* HPOUT2L_VOL - [3:0] */ +#define WM8915_HPOUT2L_VOL_WIDTH 4 /* HPOUT2L_VOL - [3:0] */ + +/* + * R31 (0x1F) - Output2 Right Volume + */ +#define WM8915_DAC2_VU 0x0100 /* DAC2_VU */ +#define WM8915_DAC2_VU_MASK 0x0100 /* DAC2_VU */ +#define WM8915_DAC2_VU_SHIFT 8 /* DAC2_VU */ +#define WM8915_DAC2_VU_WIDTH 1 /* DAC2_VU */ +#define WM8915_HPOUT2R_ZC 0x0080 /* HPOUT2R_ZC */ +#define WM8915_HPOUT2R_ZC_MASK 0x0080 /* HPOUT2R_ZC */ +#define WM8915_HPOUT2R_ZC_SHIFT 7 /* HPOUT2R_ZC */ +#define WM8915_HPOUT2R_ZC_WIDTH 1 /* HPOUT2R_ZC */ +#define WM8915_HPOUT2R_VOL_MASK 0x000F /* HPOUT2R_VOL - [3:0] */ +#define WM8915_HPOUT2R_VOL_SHIFT 0 /* HPOUT2R_VOL - [3:0] */ +#define WM8915_HPOUT2R_VOL_WIDTH 4 /* HPOUT2R_VOL - [3:0] */ + +/* + * R32 (0x20) - MICBIAS (1) + */ +#define WM8915_MICB1_RATE 0x0020 /* MICB1_RATE */ +#define WM8915_MICB1_RATE_MASK 0x0020 /* MICB1_RATE */ +#define WM8915_MICB1_RATE_SHIFT 5 /* MICB1_RATE */ +#define WM8915_MICB1_RATE_WIDTH 1 /* MICB1_RATE */ +#define WM8915_MICB1_MODE 0x0010 /* MICB1_MODE */ +#define WM8915_MICB1_MODE_MASK 0x0010 /* MICB1_MODE */ +#define WM8915_MICB1_MODE_SHIFT 4 /* MICB1_MODE */ +#define WM8915_MICB1_MODE_WIDTH 1 /* MICB1_MODE */ +#define WM8915_MICB1_LVL_MASK 0x000E /* MICB1_LVL - [3:1] */ +#define WM8915_MICB1_LVL_SHIFT 1 /* MICB1_LVL - [3:1] */ +#define WM8915_MICB1_LVL_WIDTH 3 /* MICB1_LVL - [3:1] */ +#define WM8915_MICB1_DISCH 0x0001 /* MICB1_DISCH */ +#define WM8915_MICB1_DISCH_MASK 0x0001 /* MICB1_DISCH */ +#define WM8915_MICB1_DISCH_SHIFT 0 /* MICB1_DISCH */ +#define WM8915_MICB1_DISCH_WIDTH 1 /* MICB1_DISCH */ + +/* + * R33 (0x21) - MICBIAS (2) + */ +#define WM8915_MICB2_RATE 0x0020 /* MICB2_RATE */ +#define WM8915_MICB2_RATE_MASK 0x0020 /* MICB2_RATE */ +#define WM8915_MICB2_RATE_SHIFT 5 /* MICB2_RATE */ +#define WM8915_MICB2_RATE_WIDTH 1 /* MICB2_RATE */ +#define WM8915_MICB2_MODE 0x0010 /* MICB2_MODE */ +#define WM8915_MICB2_MODE_MASK 0x0010 /* MICB2_MODE */ +#define WM8915_MICB2_MODE_SHIFT 4 /* MICB2_MODE */ +#define WM8915_MICB2_MODE_WIDTH 1 /* MICB2_MODE */ +#define WM8915_MICB2_LVL_MASK 0x000E /* MICB2_LVL - [3:1] */ +#define WM8915_MICB2_LVL_SHIFT 1 /* MICB2_LVL - [3:1] */ +#define WM8915_MICB2_LVL_WIDTH 3 /* MICB2_LVL - [3:1] */ +#define WM8915_MICB2_DISCH 0x0001 /* MICB2_DISCH */ +#define WM8915_MICB2_DISCH_MASK 0x0001 /* MICB2_DISCH */ +#define WM8915_MICB2_DISCH_SHIFT 0 /* MICB2_DISCH */ +#define WM8915_MICB2_DISCH_WIDTH 1 /* MICB2_DISCH */ + +/* + * R40 (0x28) - LDO 1 + */ +#define WM8915_LDO1_MODE 0x0020 /* LDO1_MODE */ +#define WM8915_LDO1_MODE_MASK 0x0020 /* LDO1_MODE */ +#define WM8915_LDO1_MODE_SHIFT 5 /* LDO1_MODE */ +#define WM8915_LDO1_MODE_WIDTH 1 /* LDO1_MODE */ +#define WM8915_LDO1_VSEL_MASK 0x0006 /* LDO1_VSEL - [2:1] */ +#define WM8915_LDO1_VSEL_SHIFT 1 /* LDO1_VSEL - [2:1] */ +#define WM8915_LDO1_VSEL_WIDTH 2 /* LDO1_VSEL - [2:1] */ +#define WM8915_LDO1_DISCH 0x0001 /* LDO1_DISCH */ +#define WM8915_LDO1_DISCH_MASK 0x0001 /* LDO1_DISCH */ +#define WM8915_LDO1_DISCH_SHIFT 0 /* LDO1_DISCH */ +#define WM8915_LDO1_DISCH_WIDTH 1 /* LDO1_DISCH */ + +/* + * R41 (0x29) - LDO 2 + */ +#define WM8915_LDO2_MODE 0x0020 /* LDO2_MODE */ +#define WM8915_LDO2_MODE_MASK 0x0020 /* LDO2_MODE */ +#define WM8915_LDO2_MODE_SHIFT 5 /* LDO2_MODE */ +#define WM8915_LDO2_MODE_WIDTH 1 /* LDO2_MODE */ +#define WM8915_LDO2_VSEL_MASK 0x001E /* LDO2_VSEL - [4:1] */ +#define WM8915_LDO2_VSEL_SHIFT 1 /* LDO2_VSEL - [4:1] */ +#define WM8915_LDO2_VSEL_WIDTH 4 /* LDO2_VSEL - [4:1] */ +#define WM8915_LDO2_DISCH 0x0001 /* LDO2_DISCH */ +#define WM8915_LDO2_DISCH_MASK 0x0001 /* LDO2_DISCH */ +#define WM8915_LDO2_DISCH_SHIFT 0 /* LDO2_DISCH */ +#define WM8915_LDO2_DISCH_WIDTH 1 /* LDO2_DISCH */ + +/* + * R48 (0x30) - Accessory Detect Mode 1 + */ +#define WM8915_JD_MODE_MASK 0x0003 /* JD_MODE - [1:0] */ +#define WM8915_JD_MODE_SHIFT 0 /* JD_MODE - [1:0] */ +#define WM8915_JD_MODE_WIDTH 2 /* JD_MODE - [1:0] */ + +/* + * R49 (0x31) - Accessory Detect Mode 2 + */ +#define WM8915_HPOUT1FB_SRC 0x0004 /* HPOUT1FB_SRC */ +#define WM8915_HPOUT1FB_SRC_MASK 0x0004 /* HPOUT1FB_SRC */ +#define WM8915_HPOUT1FB_SRC_SHIFT 2 /* HPOUT1FB_SRC */ +#define WM8915_HPOUT1FB_SRC_WIDTH 1 /* HPOUT1FB_SRC */ +#define WM8915_MICD_SRC 0x0002 /* MICD_SRC */ +#define WM8915_MICD_SRC_MASK 0x0002 /* MICD_SRC */ +#define WM8915_MICD_SRC_SHIFT 1 /* MICD_SRC */ +#define WM8915_MICD_SRC_WIDTH 1 /* MICD_SRC */ +#define WM8915_MICD_BIAS_SRC 0x0001 /* MICD_BIAS_SRC */ +#define WM8915_MICD_BIAS_SRC_MASK 0x0001 /* MICD_BIAS_SRC */ +#define WM8915_MICD_BIAS_SRC_SHIFT 0 /* MICD_BIAS_SRC */ +#define WM8915_MICD_BIAS_SRC_WIDTH 1 /* MICD_BIAS_SRC */ + +/* + * R52 (0x34) - Headphone Detect 1 + */ +#define WM8915_HP_HOLDTIME_MASK 0x00E0 /* HP_HOLDTIME - [7:5] */ +#define WM8915_HP_HOLDTIME_SHIFT 5 /* HP_HOLDTIME - [7:5] */ +#define WM8915_HP_HOLDTIME_WIDTH 3 /* HP_HOLDTIME - [7:5] */ +#define WM8915_HP_CLK_DIV_MASK 0x0018 /* HP_CLK_DIV - [4:3] */ +#define WM8915_HP_CLK_DIV_SHIFT 3 /* HP_CLK_DIV - [4:3] */ +#define WM8915_HP_CLK_DIV_WIDTH 2 /* HP_CLK_DIV - [4:3] */ +#define WM8915_HP_STEP_SIZE 0x0002 /* HP_STEP_SIZE */ +#define WM8915_HP_STEP_SIZE_MASK 0x0002 /* HP_STEP_SIZE */ +#define WM8915_HP_STEP_SIZE_SHIFT 1 /* HP_STEP_SIZE */ +#define WM8915_HP_STEP_SIZE_WIDTH 1 /* HP_STEP_SIZE */ +#define WM8915_HP_POLL 0x0001 /* HP_POLL */ +#define WM8915_HP_POLL_MASK 0x0001 /* HP_POLL */ +#define WM8915_HP_POLL_SHIFT 0 /* HP_POLL */ +#define WM8915_HP_POLL_WIDTH 1 /* HP_POLL */ + +/* + * R53 (0x35) - Headphone Detect 2 + */ +#define WM8915_HP_DONE 0x0080 /* HP_DONE */ +#define WM8915_HP_DONE_MASK 0x0080 /* HP_DONE */ +#define WM8915_HP_DONE_SHIFT 7 /* HP_DONE */ +#define WM8915_HP_DONE_WIDTH 1 /* HP_DONE */ +#define WM8915_HP_LVL_MASK 0x007F /* HP_LVL - [6:0] */ +#define WM8915_HP_LVL_SHIFT 0 /* HP_LVL - [6:0] */ +#define WM8915_HP_LVL_WIDTH 7 /* HP_LVL - [6:0] */ + +/* + * R56 (0x38) - Mic Detect 1 + */ +#define WM8915_MICD_BIAS_STARTTIME_MASK 0xF000 /* MICD_BIAS_STARTTIME - [15:12] */ +#define WM8915_MICD_BIAS_STARTTIME_SHIFT 12 /* MICD_BIAS_STARTTIME - [15:12] */ +#define WM8915_MICD_BIAS_STARTTIME_WIDTH 4 /* MICD_BIAS_STARTTIME - [15:12] */ +#define WM8915_MICD_RATE_MASK 0x0F00 /* MICD_RATE - [11:8] */ +#define WM8915_MICD_RATE_SHIFT 8 /* MICD_RATE - [11:8] */ +#define WM8915_MICD_RATE_WIDTH 4 /* MICD_RATE - [11:8] */ +#define WM8915_MICD_DBTIME 0x0002 /* MICD_DBTIME */ +#define WM8915_MICD_DBTIME_MASK 0x0002 /* MICD_DBTIME */ +#define WM8915_MICD_DBTIME_SHIFT 1 /* MICD_DBTIME */ +#define WM8915_MICD_DBTIME_WIDTH 1 /* MICD_DBTIME */ +#define WM8915_MICD_ENA 0x0001 /* MICD_ENA */ +#define WM8915_MICD_ENA_MASK 0x0001 /* MICD_ENA */ +#define WM8915_MICD_ENA_SHIFT 0 /* MICD_ENA */ +#define WM8915_MICD_ENA_WIDTH 1 /* MICD_ENA */ + +/* + * R57 (0x39) - Mic Detect 2 + */ +#define WM8915_MICD_LVL_SEL_MASK 0x00FF /* MICD_LVL_SEL - [7:0] */ +#define WM8915_MICD_LVL_SEL_SHIFT 0 /* MICD_LVL_SEL - [7:0] */ +#define WM8915_MICD_LVL_SEL_WIDTH 8 /* MICD_LVL_SEL - [7:0] */ + +/* + * R58 (0x3A) - Mic Detect 3 + */ +#define WM8915_MICD_LVL_MASK 0x07FC /* MICD_LVL - [10:2] */ +#define WM8915_MICD_LVL_SHIFT 2 /* MICD_LVL - [10:2] */ +#define WM8915_MICD_LVL_WIDTH 9 /* MICD_LVL - [10:2] */ +#define WM8915_MICD_VALID 0x0002 /* MICD_VALID */ +#define WM8915_MICD_VALID_MASK 0x0002 /* MICD_VALID */ +#define WM8915_MICD_VALID_SHIFT 1 /* MICD_VALID */ +#define WM8915_MICD_VALID_WIDTH 1 /* MICD_VALID */ +#define WM8915_MICD_STS 0x0001 /* MICD_STS */ +#define WM8915_MICD_STS_MASK 0x0001 /* MICD_STS */ +#define WM8915_MICD_STS_SHIFT 0 /* MICD_STS */ +#define WM8915_MICD_STS_WIDTH 1 /* MICD_STS */ + +/* + * R64 (0x40) - Charge Pump (1) + */ +#define WM8915_CP_ENA 0x8000 /* CP_ENA */ +#define WM8915_CP_ENA_MASK 0x8000 /* CP_ENA */ +#define WM8915_CP_ENA_SHIFT 15 /* CP_ENA */ +#define WM8915_CP_ENA_WIDTH 1 /* CP_ENA */ + +/* + * R65 (0x41) - Charge Pump (2) + */ +#define WM8915_CP_DISCH 0x8000 /* CP_DISCH */ +#define WM8915_CP_DISCH_MASK 0x8000 /* CP_DISCH */ +#define WM8915_CP_DISCH_SHIFT 15 /* CP_DISCH */ +#define WM8915_CP_DISCH_WIDTH 1 /* CP_DISCH */ + +/* + * R80 (0x50) - DC Servo (1) + */ +#define WM8915_DCS_ENA_CHAN_3 0x0008 /* DCS_ENA_CHAN_3 */ +#define WM8915_DCS_ENA_CHAN_3_MASK 0x0008 /* DCS_ENA_CHAN_3 */ +#define WM8915_DCS_ENA_CHAN_3_SHIFT 3 /* DCS_ENA_CHAN_3 */ +#define WM8915_DCS_ENA_CHAN_3_WIDTH 1 /* DCS_ENA_CHAN_3 */ +#define WM8915_DCS_ENA_CHAN_2 0x0004 /* DCS_ENA_CHAN_2 */ +#define WM8915_DCS_ENA_CHAN_2_MASK 0x0004 /* DCS_ENA_CHAN_2 */ +#define WM8915_DCS_ENA_CHAN_2_SHIFT 2 /* DCS_ENA_CHAN_2 */ +#define WM8915_DCS_ENA_CHAN_2_WIDTH 1 /* DCS_ENA_CHAN_2 */ +#define WM8915_DCS_ENA_CHAN_1 0x0002 /* DCS_ENA_CHAN_1 */ +#define WM8915_DCS_ENA_CHAN_1_MASK 0x0002 /* DCS_ENA_CHAN_1 */ +#define WM8915_DCS_ENA_CHAN_1_SHIFT 1 /* DCS_ENA_CHAN_1 */ +#define WM8915_DCS_ENA_CHAN_1_WIDTH 1 /* DCS_ENA_CHAN_1 */ +#define WM8915_DCS_ENA_CHAN_0 0x0001 /* DCS_ENA_CHAN_0 */ +#define WM8915_DCS_ENA_CHAN_0_MASK 0x0001 /* DCS_ENA_CHAN_0 */ +#define WM8915_DCS_ENA_CHAN_0_SHIFT 0 /* DCS_ENA_CHAN_0 */ +#define WM8915_DCS_ENA_CHAN_0_WIDTH 1 /* DCS_ENA_CHAN_0 */ + +/* + * R81 (0x51) - DC Servo (2) + */ +#define WM8915_DCS_TRIG_SINGLE_3 0x8000 /* DCS_TRIG_SINGLE_3 */ +#define WM8915_DCS_TRIG_SINGLE_3_MASK 0x8000 /* DCS_TRIG_SINGLE_3 */ +#define WM8915_DCS_TRIG_SINGLE_3_SHIFT 15 /* DCS_TRIG_SINGLE_3 */ +#define WM8915_DCS_TRIG_SINGLE_3_WIDTH 1 /* DCS_TRIG_SINGLE_3 */ +#define WM8915_DCS_TRIG_SINGLE_2 0x4000 /* DCS_TRIG_SINGLE_2 */ +#define WM8915_DCS_TRIG_SINGLE_2_MASK 0x4000 /* DCS_TRIG_SINGLE_2 */ +#define WM8915_DCS_TRIG_SINGLE_2_SHIFT 14 /* DCS_TRIG_SINGLE_2 */ +#define WM8915_DCS_TRIG_SINGLE_2_WIDTH 1 /* DCS_TRIG_SINGLE_2 */ +#define WM8915_DCS_TRIG_SINGLE_1 0x2000 /* DCS_TRIG_SINGLE_1 */ +#define WM8915_DCS_TRIG_SINGLE_1_MASK 0x2000 /* DCS_TRIG_SINGLE_1 */ +#define WM8915_DCS_TRIG_SINGLE_1_SHIFT 13 /* DCS_TRIG_SINGLE_1 */ +#define WM8915_DCS_TRIG_SINGLE_1_WIDTH 1 /* DCS_TRIG_SINGLE_1 */ +#define WM8915_DCS_TRIG_SINGLE_0 0x1000 /* DCS_TRIG_SINGLE_0 */ +#define WM8915_DCS_TRIG_SINGLE_0_MASK 0x1000 /* DCS_TRIG_SINGLE_0 */ +#define WM8915_DCS_TRIG_SINGLE_0_SHIFT 12 /* DCS_TRIG_SINGLE_0 */ +#define WM8915_DCS_TRIG_SINGLE_0_WIDTH 1 /* DCS_TRIG_SINGLE_0 */ +#define WM8915_DCS_TRIG_SERIES_3 0x0800 /* DCS_TRIG_SERIES_3 */ +#define WM8915_DCS_TRIG_SERIES_3_MASK 0x0800 /* DCS_TRIG_SERIES_3 */ +#define WM8915_DCS_TRIG_SERIES_3_SHIFT 11 /* DCS_TRIG_SERIES_3 */ +#define WM8915_DCS_TRIG_SERIES_3_WIDTH 1 /* DCS_TRIG_SERIES_3 */ +#define WM8915_DCS_TRIG_SERIES_2 0x0400 /* DCS_TRIG_SERIES_2 */ +#define WM8915_DCS_TRIG_SERIES_2_MASK 0x0400 /* DCS_TRIG_SERIES_2 */ +#define WM8915_DCS_TRIG_SERIES_2_SHIFT 10 /* DCS_TRIG_SERIES_2 */ +#define WM8915_DCS_TRIG_SERIES_2_WIDTH 1 /* DCS_TRIG_SERIES_2 */ +#define WM8915_DCS_TRIG_SERIES_1 0x0200 /* DCS_TRIG_SERIES_1 */ +#define WM8915_DCS_TRIG_SERIES_1_MASK 0x0200 /* DCS_TRIG_SERIES_1 */ +#define WM8915_DCS_TRIG_SERIES_1_SHIFT 9 /* DCS_TRIG_SERIES_1 */ +#define WM8915_DCS_TRIG_SERIES_1_WIDTH 1 /* DCS_TRIG_SERIES_1 */ +#define WM8915_DCS_TRIG_SERIES_0 0x0100 /* DCS_TRIG_SERIES_0 */ +#define WM8915_DCS_TRIG_SERIES_0_MASK 0x0100 /* DCS_TRIG_SERIES_0 */ +#define WM8915_DCS_TRIG_SERIES_0_SHIFT 8 /* DCS_TRIG_SERIES_0 */ +#define WM8915_DCS_TRIG_SERIES_0_WIDTH 1 /* DCS_TRIG_SERIES_0 */ +#define WM8915_DCS_TRIG_STARTUP_3 0x0080 /* DCS_TRIG_STARTUP_3 */ +#define WM8915_DCS_TRIG_STARTUP_3_MASK 0x0080 /* DCS_TRIG_STARTUP_3 */ +#define WM8915_DCS_TRIG_STARTUP_3_SHIFT 7 /* DCS_TRIG_STARTUP_3 */ +#define WM8915_DCS_TRIG_STARTUP_3_WIDTH 1 /* DCS_TRIG_STARTUP_3 */ +#define WM8915_DCS_TRIG_STARTUP_2 0x0040 /* DCS_TRIG_STARTUP_2 */ +#define WM8915_DCS_TRIG_STARTUP_2_MASK 0x0040 /* DCS_TRIG_STARTUP_2 */ +#define WM8915_DCS_TRIG_STARTUP_2_SHIFT 6 /* DCS_TRIG_STARTUP_2 */ +#define WM8915_DCS_TRIG_STARTUP_2_WIDTH 1 /* DCS_TRIG_STARTUP_2 */ +#define WM8915_DCS_TRIG_STARTUP_1 0x0020 /* DCS_TRIG_STARTUP_1 */ +#define WM8915_DCS_TRIG_STARTUP_1_MASK 0x0020 /* DCS_TRIG_STARTUP_1 */ +#define WM8915_DCS_TRIG_STARTUP_1_SHIFT 5 /* DCS_TRIG_STARTUP_1 */ +#define WM8915_DCS_TRIG_STARTUP_1_WIDTH 1 /* DCS_TRIG_STARTUP_1 */ +#define WM8915_DCS_TRIG_STARTUP_0 0x0010 /* DCS_TRIG_STARTUP_0 */ +#define WM8915_DCS_TRIG_STARTUP_0_MASK 0x0010 /* DCS_TRIG_STARTUP_0 */ +#define WM8915_DCS_TRIG_STARTUP_0_SHIFT 4 /* DCS_TRIG_STARTUP_0 */ +#define WM8915_DCS_TRIG_STARTUP_0_WIDTH 1 /* DCS_TRIG_STARTUP_0 */ +#define WM8915_DCS_TRIG_DAC_WR_3 0x0008 /* DCS_TRIG_DAC_WR_3 */ +#define WM8915_DCS_TRIG_DAC_WR_3_MASK 0x0008 /* DCS_TRIG_DAC_WR_3 */ +#define WM8915_DCS_TRIG_DAC_WR_3_SHIFT 3 /* DCS_TRIG_DAC_WR_3 */ +#define WM8915_DCS_TRIG_DAC_WR_3_WIDTH 1 /* DCS_TRIG_DAC_WR_3 */ +#define WM8915_DCS_TRIG_DAC_WR_2 0x0004 /* DCS_TRIG_DAC_WR_2 */ +#define WM8915_DCS_TRIG_DAC_WR_2_MASK 0x0004 /* DCS_TRIG_DAC_WR_2 */ +#define WM8915_DCS_TRIG_DAC_WR_2_SHIFT 2 /* DCS_TRIG_DAC_WR_2 */ +#define WM8915_DCS_TRIG_DAC_WR_2_WIDTH 1 /* DCS_TRIG_DAC_WR_2 */ +#define WM8915_DCS_TRIG_DAC_WR_1 0x0002 /* DCS_TRIG_DAC_WR_1 */ +#define WM8915_DCS_TRIG_DAC_WR_1_MASK 0x0002 /* DCS_TRIG_DAC_WR_1 */ +#define WM8915_DCS_TRIG_DAC_WR_1_SHIFT 1 /* DCS_TRIG_DAC_WR_1 */ +#define WM8915_DCS_TRIG_DAC_WR_1_WIDTH 1 /* DCS_TRIG_DAC_WR_1 */ +#define WM8915_DCS_TRIG_DAC_WR_0 0x0001 /* DCS_TRIG_DAC_WR_0 */ +#define WM8915_DCS_TRIG_DAC_WR_0_MASK 0x0001 /* DCS_TRIG_DAC_WR_0 */ +#define WM8915_DCS_TRIG_DAC_WR_0_SHIFT 0 /* DCS_TRIG_DAC_WR_0 */ +#define WM8915_DCS_TRIG_DAC_WR_0_WIDTH 1 /* DCS_TRIG_DAC_WR_0 */ + +/* + * R82 (0x52) - DC Servo (3) + */ +#define WM8915_DCS_TIMER_PERIOD_23_MASK 0x0F00 /* DCS_TIMER_PERIOD_23 - [11:8] */ +#define WM8915_DCS_TIMER_PERIOD_23_SHIFT 8 /* DCS_TIMER_PERIOD_23 - [11:8] */ +#define WM8915_DCS_TIMER_PERIOD_23_WIDTH 4 /* DCS_TIMER_PERIOD_23 - [11:8] */ +#define WM8915_DCS_TIMER_PERIOD_01_MASK 0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */ +#define WM8915_DCS_TIMER_PERIOD_01_SHIFT 0 /* DCS_TIMER_PERIOD_01 - [3:0] */ +#define WM8915_DCS_TIMER_PERIOD_01_WIDTH 4 /* DCS_TIMER_PERIOD_01 - [3:0] */ + +/* + * R84 (0x54) - DC Servo (5) + */ +#define WM8915_DCS_SERIES_NO_23_MASK 0x7F00 /* DCS_SERIES_NO_23 - [14:8] */ +#define WM8915_DCS_SERIES_NO_23_SHIFT 8 /* DCS_SERIES_NO_23 - [14:8] */ +#define WM8915_DCS_SERIES_NO_23_WIDTH 7 /* DCS_SERIES_NO_23 - [14:8] */ +#define WM8915_DCS_SERIES_NO_01_MASK 0x007F /* DCS_SERIES_NO_01 - [6:0] */ +#define WM8915_DCS_SERIES_NO_01_SHIFT 0 /* DCS_SERIES_NO_01 - [6:0] */ +#define WM8915_DCS_SERIES_NO_01_WIDTH 7 /* DCS_SERIES_NO_01 - [6:0] */ + +/* + * R85 (0x55) - DC Servo (6) + */ +#define WM8915_DCS_DAC_WR_VAL_3_MASK 0xFF00 /* DCS_DAC_WR_VAL_3 - [15:8] */ +#define WM8915_DCS_DAC_WR_VAL_3_SHIFT 8 /* DCS_DAC_WR_VAL_3 - [15:8] */ +#define WM8915_DCS_DAC_WR_VAL_3_WIDTH 8 /* DCS_DAC_WR_VAL_3 - [15:8] */ +#define WM8915_DCS_DAC_WR_VAL_2_MASK 0x00FF /* DCS_DAC_WR_VAL_2 - [7:0] */ +#define WM8915_DCS_DAC_WR_VAL_2_SHIFT 0 /* DCS_DAC_WR_VAL_2 - [7:0] */ +#define WM8915_DCS_DAC_WR_VAL_2_WIDTH 8 /* DCS_DAC_WR_VAL_2 - [7:0] */ + +/* + * R86 (0x56) - DC Servo (7) + */ +#define WM8915_DCS_DAC_WR_VAL_1_MASK 0xFF00 /* DCS_DAC_WR_VAL_1 - [15:8] */ +#define WM8915_DCS_DAC_WR_VAL_1_SHIFT 8 /* DCS_DAC_WR_VAL_1 - [15:8] */ +#define WM8915_DCS_DAC_WR_VAL_1_WIDTH 8 /* DCS_DAC_WR_VAL_1 - [15:8] */ +#define WM8915_DCS_DAC_WR_VAL_0_MASK 0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */ +#define WM8915_DCS_DAC_WR_VAL_0_SHIFT 0 /* DCS_DAC_WR_VAL_0 - [7:0] */ +#define WM8915_DCS_DAC_WR_VAL_0_WIDTH 8 /* DCS_DAC_WR_VAL_0 - [7:0] */ + +/* + * R87 (0x57) - DC Servo Readback 0 + */ +#define WM8915_DCS_CAL_COMPLETE_MASK 0x0F00 /* DCS_CAL_COMPLETE - [11:8] */ +#define WM8915_DCS_CAL_COMPLETE_SHIFT 8 /* DCS_CAL_COMPLETE - [11:8] */ +#define WM8915_DCS_CAL_COMPLETE_WIDTH 4 /* DCS_CAL_COMPLETE - [11:8] */ +#define WM8915_DCS_DAC_WR_COMPLETE_MASK 0x00F0 /* DCS_DAC_WR_COMPLETE - [7:4] */ +#define WM8915_DCS_DAC_WR_COMPLETE_SHIFT 4 /* DCS_DAC_WR_COMPLETE - [7:4] */ +#define WM8915_DCS_DAC_WR_COMPLETE_WIDTH 4 /* DCS_DAC_WR_COMPLETE - [7:4] */ +#define WM8915_DCS_STARTUP_COMPLETE_MASK 0x000F /* DCS_STARTUP_COMPLETE - [3:0] */ +#define WM8915_DCS_STARTUP_COMPLETE_SHIFT 0 /* DCS_STARTUP_COMPLETE - [3:0] */ +#define WM8915_DCS_STARTUP_COMPLETE_WIDTH 4 /* DCS_STARTUP_COMPLETE - [3:0] */ + +/* + * R96 (0x60) - Analogue HP (1) + */ +#define WM8915_HPOUT1L_RMV_SHORT 0x0080 /* HPOUT1L_RMV_SHORT */ +#define WM8915_HPOUT1L_RMV_SHORT_MASK 0x0080 /* HPOUT1L_RMV_SHORT */ +#define WM8915_HPOUT1L_RMV_SHORT_SHIFT 7 /* HPOUT1L_RMV_SHORT */ +#define WM8915_HPOUT1L_RMV_SHORT_WIDTH 1 /* HPOUT1L_RMV_SHORT */ +#define WM8915_HPOUT1L_OUTP 0x0040 /* HPOUT1L_OUTP */ +#define WM8915_HPOUT1L_OUTP_MASK 0x0040 /* HPOUT1L_OUTP */ +#define WM8915_HPOUT1L_OUTP_SHIFT 6 /* HPOUT1L_OUTP */ +#define WM8915_HPOUT1L_OUTP_WIDTH 1 /* HPOUT1L_OUTP */ +#define WM8915_HPOUT1L_DLY 0x0020 /* HPOUT1L_DLY */ +#define WM8915_HPOUT1L_DLY_MASK 0x0020 /* HPOUT1L_DLY */ +#define WM8915_HPOUT1L_DLY_SHIFT 5 /* HPOUT1L_DLY */ +#define WM8915_HPOUT1L_DLY_WIDTH 1 /* HPOUT1L_DLY */ +#define WM8915_HPOUT1R_RMV_SHORT 0x0008 /* HPOUT1R_RMV_SHORT */ +#define WM8915_HPOUT1R_RMV_SHORT_MASK 0x0008 /* HPOUT1R_RMV_SHORT */ +#define WM8915_HPOUT1R_RMV_SHORT_SHIFT 3 /* HPOUT1R_RMV_SHORT */ +#define WM8915_HPOUT1R_RMV_SHORT_WIDTH 1 /* HPOUT1R_RMV_SHORT */ +#define WM8915_HPOUT1R_OUTP 0x0004 /* HPOUT1R_OUTP */ +#define WM8915_HPOUT1R_OUTP_MASK 0x0004 /* HPOUT1R_OUTP */ +#define WM8915_HPOUT1R_OUTP_SHIFT 2 /* HPOUT1R_OUTP */ +#define WM8915_HPOUT1R_OUTP_WIDTH 1 /* HPOUT1R_OUTP */ +#define WM8915_HPOUT1R_DLY 0x0002 /* HPOUT1R_DLY */ +#define WM8915_HPOUT1R_DLY_MASK 0x0002 /* HPOUT1R_DLY */ +#define WM8915_HPOUT1R_DLY_SHIFT 1 /* HPOUT1R_DLY */ +#define WM8915_HPOUT1R_DLY_WIDTH 1 /* HPOUT1R_DLY */ + +/* + * R97 (0x61) - Analogue HP (2) + */ +#define WM8915_HPOUT2L_RMV_SHORT 0x0080 /* HPOUT2L_RMV_SHORT */ +#define WM8915_HPOUT2L_RMV_SHORT_MASK 0x0080 /* HPOUT2L_RMV_SHORT */ +#define WM8915_HPOUT2L_RMV_SHORT_SHIFT 7 /* HPOUT2L_RMV_SHORT */ +#define WM8915_HPOUT2L_RMV_SHORT_WIDTH 1 /* HPOUT2L_RMV_SHORT */ +#define WM8915_HPOUT2L_OUTP 0x0040 /* HPOUT2L_OUTP */ +#define WM8915_HPOUT2L_OUTP_MASK 0x0040 /* HPOUT2L_OUTP */ +#define WM8915_HPOUT2L_OUTP_SHIFT 6 /* HPOUT2L_OUTP */ +#define WM8915_HPOUT2L_OUTP_WIDTH 1 /* HPOUT2L_OUTP */ +#define WM8915_HPOUT2L_DLY 0x0020 /* HPOUT2L_DLY */ +#define WM8915_HPOUT2L_DLY_MASK 0x0020 /* HPOUT2L_DLY */ +#define WM8915_HPOUT2L_DLY_SHIFT 5 /* HPOUT2L_DLY */ +#define WM8915_HPOUT2L_DLY_WIDTH 1 /* HPOUT2L_DLY */ +#define WM8915_HPOUT2R_RMV_SHORT 0x0008 /* HPOUT2R_RMV_SHORT */ +#define WM8915_HPOUT2R_RMV_SHORT_MASK 0x0008 /* HPOUT2R_RMV_SHORT */ +#define WM8915_HPOUT2R_RMV_SHORT_SHIFT 3 /* HPOUT2R_RMV_SHORT */ +#define WM8915_HPOUT2R_RMV_SHORT_WIDTH 1 /* HPOUT2R_RMV_SHORT */ +#define WM8915_HPOUT2R_OUTP 0x0004 /* HPOUT2R_OUTP */ +#define WM8915_HPOUT2R_OUTP_MASK 0x0004 /* HPOUT2R_OUTP */ +#define WM8915_HPOUT2R_OUTP_SHIFT 2 /* HPOUT2R_OUTP */ +#define WM8915_HPOUT2R_OUTP_WIDTH 1 /* HPOUT2R_OUTP */ +#define WM8915_HPOUT2R_DLY 0x0002 /* HPOUT2R_DLY */ +#define WM8915_HPOUT2R_DLY_MASK 0x0002 /* HPOUT2R_DLY */ +#define WM8915_HPOUT2R_DLY_SHIFT 1 /* HPOUT2R_DLY */ +#define WM8915_HPOUT2R_DLY_WIDTH 1 /* HPOUT2R_DLY */ + +/* + * R256 (0x100) - Chip Revision + */ +#define WM8915_CHIP_REV_MASK 0x000F /* CHIP_REV - [3:0] */ +#define WM8915_CHIP_REV_SHIFT 0 /* CHIP_REV - [3:0] */ +#define WM8915_CHIP_REV_WIDTH 4 /* CHIP_REV - [3:0] */ + +/* + * R257 (0x101) - Control Interface (1) + */ +#define WM8915_AUTO_INC 0x0004 /* AUTO_INC */ +#define WM8915_AUTO_INC_MASK 0x0004 /* AUTO_INC */ +#define WM8915_AUTO_INC_SHIFT 2 /* AUTO_INC */ +#define WM8915_AUTO_INC_WIDTH 1 /* AUTO_INC */ + +/* + * R272 (0x110) - Write Sequencer Ctrl (1) + */ +#define WM8915_WSEQ_ENA 0x8000 /* WSEQ_ENA */ +#define WM8915_WSEQ_ENA_MASK 0x8000 /* WSEQ_ENA */ +#define WM8915_WSEQ_ENA_SHIFT 15 /* WSEQ_ENA */ +#define WM8915_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ +#define WM8915_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */ +#define WM8915_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */ +#define WM8915_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */ +#define WM8915_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ +#define WM8915_WSEQ_START 0x0100 /* WSEQ_START */ +#define WM8915_WSEQ_START_MASK 0x0100 /* WSEQ_START */ +#define WM8915_WSEQ_START_SHIFT 8 /* WSEQ_START */ +#define WM8915_WSEQ_START_WIDTH 1 /* WSEQ_START */ +#define WM8915_WSEQ_START_INDEX_MASK 0x007F /* WSEQ_START_INDEX - [6:0] */ +#define WM8915_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [6:0] */ +#define WM8915_WSEQ_START_INDEX_WIDTH 7 /* WSEQ_START_INDEX - [6:0] */ + +/* + * R273 (0x111) - Write Sequencer Ctrl (2) + */ +#define WM8915_WSEQ_BUSY 0x0100 /* WSEQ_BUSY */ +#define WM8915_WSEQ_BUSY_MASK 0x0100 /* WSEQ_BUSY */ +#define WM8915_WSEQ_BUSY_SHIFT 8 /* WSEQ_BUSY */ +#define WM8915_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ +#define WM8915_WSEQ_CURRENT_INDEX_MASK 0x007F /* WSEQ_CURRENT_INDEX - [6:0] */ +#define WM8915_WSEQ_CURRENT_INDEX_SHIFT 0 /* WSEQ_CURRENT_INDEX - [6:0] */ +#define WM8915_WSEQ_CURRENT_INDEX_WIDTH 7 /* WSEQ_CURRENT_INDEX - [6:0] */ + +/* + * R512 (0x200) - AIF Clocking (1) + */ +#define WM8915_SYSCLK_SRC_MASK 0x0018 /* SYSCLK_SRC - [4:3] */ +#define WM8915_SYSCLK_SRC_SHIFT 3 /* SYSCLK_SRC - [4:3] */ +#define WM8915_SYSCLK_SRC_WIDTH 2 /* SYSCLK_SRC - [4:3] */ +#define WM8915_SYSCLK_INV 0x0004 /* SYSCLK_INV */ +#define WM8915_SYSCLK_INV_MASK 0x0004 /* SYSCLK_INV */ +#define WM8915_SYSCLK_INV_SHIFT 2 /* SYSCLK_INV */ +#define WM8915_SYSCLK_INV_WIDTH 1 /* SYSCLK_INV */ +#define WM8915_SYSCLK_DIV 0x0002 /* SYSCLK_DIV */ +#define WM8915_SYSCLK_DIV_MASK 0x0002 /* SYSCLK_DIV */ +#define WM8915_SYSCLK_DIV_SHIFT 1 /* SYSCLK_DIV */ +#define WM8915_SYSCLK_DIV_WIDTH 1 /* SYSCLK_DIV */ +#define WM8915_SYSCLK_ENA 0x0001 /* SYSCLK_ENA */ +#define WM8915_SYSCLK_ENA_MASK 0x0001 /* SYSCLK_ENA */ +#define WM8915_SYSCLK_ENA_SHIFT 0 /* SYSCLK_ENA */ +#define WM8915_SYSCLK_ENA_WIDTH 1 /* SYSCLK_ENA */ + +/* + * R513 (0x201) - AIF Clocking (2) + */ +#define WM8915_DSP2_DIV_MASK 0x0018 /* DSP2_DIV - [4:3] */ +#define WM8915_DSP2_DIV_SHIFT 3 /* DSP2_DIV - [4:3] */ +#define WM8915_DSP2_DIV_WIDTH 2 /* DSP2_DIV - [4:3] */ +#define WM8915_DSP1_DIV_MASK 0x0003 /* DSP1_DIV - [1:0] */ +#define WM8915_DSP1_DIV_SHIFT 0 /* DSP1_DIV - [1:0] */ +#define WM8915_DSP1_DIV_WIDTH 2 /* DSP1_DIV - [1:0] */ + +/* + * R520 (0x208) - Clocking (1) + */ +#define WM8915_LFCLK_ENA 0x0020 /* LFCLK_ENA */ +#define WM8915_LFCLK_ENA_MASK 0x0020 /* LFCLK_ENA */ +#define WM8915_LFCLK_ENA_SHIFT 5 /* LFCLK_ENA */ +#define WM8915_LFCLK_ENA_WIDTH 1 /* LFCLK_ENA */ +#define WM8915_TOCLK_ENA 0x0010 /* TOCLK_ENA */ +#define WM8915_TOCLK_ENA_MASK 0x0010 /* TOCLK_ENA */ +#define WM8915_TOCLK_ENA_SHIFT 4 /* TOCLK_ENA */ +#define WM8915_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */ +#define WM8915_AIFCLK_ENA 0x0004 /* AIFCLK_ENA */ +#define WM8915_AIFCLK_ENA_MASK 0x0004 /* AIFCLK_ENA */ +#define WM8915_AIFCLK_ENA_SHIFT 2 /* AIFCLK_ENA */ +#define WM8915_AIFCLK_ENA_WIDTH 1 /* AIFCLK_ENA */ +#define WM8915_SYSDSPCLK_ENA 0x0002 /* SYSDSPCLK_ENA */ +#define WM8915_SYSDSPCLK_ENA_MASK 0x0002 /* SYSDSPCLK_ENA */ +#define WM8915_SYSDSPCLK_ENA_SHIFT 1 /* SYSDSPCLK_ENA */ +#define WM8915_SYSDSPCLK_ENA_WIDTH 1 /* SYSDSPCLK_ENA */ + +/* + * R521 (0x209) - Clocking (2) + */ +#define WM8915_TOCLK_DIV_MASK 0x0700 /* TOCLK_DIV - [10:8] */ +#define WM8915_TOCLK_DIV_SHIFT 8 /* TOCLK_DIV - [10:8] */ +#define WM8915_TOCLK_DIV_WIDTH 3 /* TOCLK_DIV - [10:8] */ +#define WM8915_DBCLK_DIV_MASK 0x00F0 /* DBCLK_DIV - [7:4] */ +#define WM8915_DBCLK_DIV_SHIFT 4 /* DBCLK_DIV - [7:4] */ +#define WM8915_DBCLK_DIV_WIDTH 4 /* DBCLK_DIV - [7:4] */ +#define WM8915_OPCLK_DIV_MASK 0x0007 /* OPCLK_DIV - [2:0] */ +#define WM8915_OPCLK_DIV_SHIFT 0 /* OPCLK_DIV - [2:0] */ +#define WM8915_OPCLK_DIV_WIDTH 3 /* OPCLK_DIV - [2:0] */ + +/* + * R528 (0x210) - AIF Rate + */ +#define WM8915_SYSCLK_RATE 0x0001 /* SYSCLK_RATE */ +#define WM8915_SYSCLK_RATE_MASK 0x0001 /* SYSCLK_RATE */ +#define WM8915_SYSCLK_RATE_SHIFT 0 /* SYSCLK_RATE */ +#define WM8915_SYSCLK_RATE_WIDTH 1 /* SYSCLK_RATE */ + +/* + * R544 (0x220) - FLL Control (1) + */ +#define WM8915_FLL_OSC_ENA 0x0002 /* FLL_OSC_ENA */ +#define WM8915_FLL_OSC_ENA_MASK 0x0002 /* FLL_OSC_ENA */ +#define WM8915_FLL_OSC_ENA_SHIFT 1 /* FLL_OSC_ENA */ +#define WM8915_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */ +#define WM8915_FLL_ENA 0x0001 /* FLL_ENA */ +#define WM8915_FLL_ENA_MASK 0x0001 /* FLL_ENA */ +#define WM8915_FLL_ENA_SHIFT 0 /* FLL_ENA */ +#define WM8915_FLL_ENA_WIDTH 1 /* FLL_ENA */ + +/* + * R545 (0x221) - FLL Control (2) + */ +#define WM8915_FLL_OUTDIV_MASK 0x3F00 /* FLL_OUTDIV - [13:8] */ +#define WM8915_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [13:8] */ +#define WM8915_FLL_OUTDIV_WIDTH 6 /* FLL_OUTDIV - [13:8] */ +#define WM8915_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */ +#define WM8915_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */ +#define WM8915_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */ + +/* + * R546 (0x222) - FLL Control (3) + */ +#define WM8915_FLL_THETA_MASK 0xFFFF /* FLL_THETA - [15:0] */ +#define WM8915_FLL_THETA_SHIFT 0 /* FLL_THETA - [15:0] */ +#define WM8915_FLL_THETA_WIDTH 16 /* FLL_THETA - [15:0] */ + +/* + * R547 (0x223) - FLL Control (4) + */ +#define WM8915_FLL_N_MASK 0x7FE0 /* FLL_N - [14:5] */ +#define WM8915_FLL_N_SHIFT 5 /* FLL_N - [14:5] */ +#define WM8915_FLL_N_WIDTH 10 /* FLL_N - [14:5] */ +#define WM8915_FLL_LOOP_GAIN_MASK 0x000F /* FLL_LOOP_GAIN - [3:0] */ +#define WM8915_FLL_LOOP_GAIN_SHIFT 0 /* FLL_LOOP_GAIN - [3:0] */ +#define WM8915_FLL_LOOP_GAIN_WIDTH 4 /* FLL_LOOP_GAIN - [3:0] */ + +/* + * R548 (0x224) - FLL Control (5) + */ +#define WM8915_FLL_FRC_NCO_VAL_MASK 0x1F80 /* FLL_FRC_NCO_VAL - [12:7] */ +#define WM8915_FLL_FRC_NCO_VAL_SHIFT 7 /* FLL_FRC_NCO_VAL - [12:7] */ +#define WM8915_FLL_FRC_NCO_VAL_WIDTH 6 /* FLL_FRC_NCO_VAL - [12:7] */ +#define WM8915_FLL_FRC_NCO 0x0040 /* FLL_FRC_NCO */ +#define WM8915_FLL_FRC_NCO_MASK 0x0040 /* FLL_FRC_NCO */ +#define WM8915_FLL_FRC_NCO_SHIFT 6 /* FLL_FRC_NCO */ +#define WM8915_FLL_FRC_NCO_WIDTH 1 /* FLL_FRC_NCO */ +#define WM8915_FLL_REFCLK_DIV_MASK 0x0018 /* FLL_REFCLK_DIV - [4:3] */ +#define WM8915_FLL_REFCLK_DIV_SHIFT 3 /* FLL_REFCLK_DIV - [4:3] */ +#define WM8915_FLL_REFCLK_DIV_WIDTH 2 /* FLL_REFCLK_DIV - [4:3] */ +#define WM8915_FLL_REF_FREQ 0x0004 /* FLL_REF_FREQ */ +#define WM8915_FLL_REF_FREQ_MASK 0x0004 /* FLL_REF_FREQ */ +#define WM8915_FLL_REF_FREQ_SHIFT 2 /* FLL_REF_FREQ */ +#define WM8915_FLL_REF_FREQ_WIDTH 1 /* FLL_REF_FREQ */ +#define WM8915_FLL_REFCLK_SRC_MASK 0x0003 /* FLL_REFCLK_SRC - [1:0] */ +#define WM8915_FLL_REFCLK_SRC_SHIFT 0 /* FLL_REFCLK_SRC - [1:0] */ +#define WM8915_FLL_REFCLK_SRC_WIDTH 2 /* FLL_REFCLK_SRC - [1:0] */ + +/* + * R549 (0x225) - FLL Control (6) + */ +#define WM8915_FLL_REFCLK_SRC_STS_MASK 0x000C /* FLL_REFCLK_SRC_STS - [3:2] */ +#define WM8915_FLL_REFCLK_SRC_STS_SHIFT 2 /* FLL_REFCLK_SRC_STS - [3:2] */ +#define WM8915_FLL_REFCLK_SRC_STS_WIDTH 2 /* FLL_REFCLK_SRC_STS - [3:2] */ +#define WM8915_FLL_SWITCH_CLK 0x0001 /* FLL_SWITCH_CLK */ +#define WM8915_FLL_SWITCH_CLK_MASK 0x0001 /* FLL_SWITCH_CLK */ +#define WM8915_FLL_SWITCH_CLK_SHIFT 0 /* FLL_SWITCH_CLK */ +#define WM8915_FLL_SWITCH_CLK_WIDTH 1 /* FLL_SWITCH_CLK */ + +/* + * R550 (0x226) - FLL EFS 1 + */ +#define WM8915_FLL_LAMBDA_MASK 0xFFFF /* FLL_LAMBDA - [15:0] */ +#define WM8915_FLL_LAMBDA_SHIFT 0 /* FLL_LAMBDA - [15:0] */ +#define WM8915_FLL_LAMBDA_WIDTH 16 /* FLL_LAMBDA - [15:0] */ + +/* + * R551 (0x227) - FLL EFS 2 + */ +#define WM8915_FLL_LFSR_SEL_MASK 0x0006 /* FLL_LFSR_SEL - [2:1] */ +#define WM8915_FLL_LFSR_SEL_SHIFT 1 /* FLL_LFSR_SEL - [2:1] */ +#define WM8915_FLL_LFSR_SEL_WIDTH 2 /* FLL_LFSR_SEL - [2:1] */ +#define WM8915_FLL_EFS_ENA 0x0001 /* FLL_EFS_ENA */ +#define WM8915_FLL_EFS_ENA_MASK 0x0001 /* FLL_EFS_ENA */ +#define WM8915_FLL_EFS_ENA_SHIFT 0 /* FLL_EFS_ENA */ +#define WM8915_FLL_EFS_ENA_WIDTH 1 /* FLL_EFS_ENA */ + +/* + * R768 (0x300) - AIF1 Control + */ +#define WM8915_AIF1_TRI 0x0004 /* AIF1_TRI */ +#define WM8915_AIF1_TRI_MASK 0x0004 /* AIF1_TRI */ +#define WM8915_AIF1_TRI_SHIFT 2 /* AIF1_TRI */ +#define WM8915_AIF1_TRI_WIDTH 1 /* AIF1_TRI */ +#define WM8915_AIF1_FMT_MASK 0x0003 /* AIF1_FMT - [1:0] */ +#define WM8915_AIF1_FMT_SHIFT 0 /* AIF1_FMT - [1:0] */ +#define WM8915_AIF1_FMT_WIDTH 2 /* AIF1_FMT - [1:0] */ + +/* + * R769 (0x301) - AIF1 BCLK + */ +#define WM8915_AIF1_BCLK_INV 0x0400 /* AIF1_BCLK_INV */ +#define WM8915_AIF1_BCLK_INV_MASK 0x0400 /* AIF1_BCLK_INV */ +#define WM8915_AIF1_BCLK_INV_SHIFT 10 /* AIF1_BCLK_INV */ +#define WM8915_AIF1_BCLK_INV_WIDTH 1 /* AIF1_BCLK_INV */ +#define WM8915_AIF1_BCLK_FRC 0x0200 /* AIF1_BCLK_FRC */ +#define WM8915_AIF1_BCLK_FRC_MASK 0x0200 /* AIF1_BCLK_FRC */ +#define WM8915_AIF1_BCLK_FRC_SHIFT 9 /* AIF1_BCLK_FRC */ +#define WM8915_AIF1_BCLK_FRC_WIDTH 1 /* AIF1_BCLK_FRC */ +#define WM8915_AIF1_BCLK_MSTR 0x0100 /* AIF1_BCLK_MSTR */ +#define WM8915_AIF1_BCLK_MSTR_MASK 0x0100 /* AIF1_BCLK_MSTR */ +#define WM8915_AIF1_BCLK_MSTR_SHIFT 8 /* AIF1_BCLK_MSTR */ +#define WM8915_AIF1_BCLK_MSTR_WIDTH 1 /* AIF1_BCLK_MSTR */ +#define WM8915_AIF1_BCLK_DIV_MASK 0x000F /* AIF1_BCLK_DIV - [3:0] */ +#define WM8915_AIF1_BCLK_DIV_SHIFT 0 /* AIF1_BCLK_DIV - [3:0] */ +#define WM8915_AIF1_BCLK_DIV_WIDTH 4 /* AIF1_BCLK_DIV - [3:0] */ + +/* + * R770 (0x302) - AIF1 TX LRCLK(1) + */ +#define WM8915_AIF1TX_RATE_MASK 0x07FF /* AIF1TX_RATE - [10:0] */ +#define WM8915_AIF1TX_RATE_SHIFT 0 /* AIF1TX_RATE - [10:0] */ +#define WM8915_AIF1TX_RATE_WIDTH 11 /* AIF1TX_RATE - [10:0] */ + +/* + * R771 (0x303) - AIF1 TX LRCLK(2) + */ +#define WM8915_AIF1TX_LRCLK_MODE 0x0008 /* AIF1TX_LRCLK_MODE */ +#define WM8915_AIF1TX_LRCLK_MODE_MASK 0x0008 /* AIF1TX_LRCLK_MODE */ +#define WM8915_AIF1TX_LRCLK_MODE_SHIFT 3 /* AIF1TX_LRCLK_MODE */ +#define WM8915_AIF1TX_LRCLK_MODE_WIDTH 1 /* AIF1TX_LRCLK_MODE */ +#define WM8915_AIF1TX_LRCLK_INV 0x0004 /* AIF1TX_LRCLK_INV */ +#define WM8915_AIF1TX_LRCLK_INV_MASK 0x0004 /* AIF1TX_LRCLK_INV */ +#define WM8915_AIF1TX_LRCLK_INV_SHIFT 2 /* AIF1TX_LRCLK_INV */ +#define WM8915_AIF1TX_LRCLK_INV_WIDTH 1 /* AIF1TX_LRCLK_INV */ +#define WM8915_AIF1TX_LRCLK_FRC 0x0002 /* AIF1TX_LRCLK_FRC */ +#define WM8915_AIF1TX_LRCLK_FRC_MASK 0x0002 /* AIF1TX_LRCLK_FRC */ +#define WM8915_AIF1TX_LRCLK_FRC_SHIFT 1 /* AIF1TX_LRCLK_FRC */ +#define WM8915_AIF1TX_LRCLK_FRC_WIDTH 1 /* AIF1TX_LRCLK_FRC */ +#define WM8915_AIF1TX_LRCLK_MSTR 0x0001 /* AIF1TX_LRCLK_MSTR */ +#define WM8915_AIF1TX_LRCLK_MSTR_MASK 0x0001 /* AIF1TX_LRCLK_MSTR */ +#define WM8915_AIF1TX_LRCLK_MSTR_SHIFT 0 /* AIF1TX_LRCLK_MSTR */ +#define WM8915_AIF1TX_LRCLK_MSTR_WIDTH 1 /* AIF1TX_LRCLK_MSTR */ + +/* + * R772 (0x304) - AIF1 RX LRCLK(1) + */ +#define WM8915_AIF1RX_RATE_MASK 0x07FF /* AIF1RX_RATE - [10:0] */ +#define WM8915_AIF1RX_RATE_SHIFT 0 /* AIF1RX_RATE - [10:0] */ +#define WM8915_AIF1RX_RATE_WIDTH 11 /* AIF1RX_RATE - [10:0] */ + +/* + * R773 (0x305) - AIF1 RX LRCLK(2) + */ +#define WM8915_AIF1RX_LRCLK_INV 0x0004 /* AIF1RX_LRCLK_INV */ +#define WM8915_AIF1RX_LRCLK_INV_MASK 0x0004 /* AIF1RX_LRCLK_INV */ +#define WM8915_AIF1RX_LRCLK_INV_SHIFT 2 /* AIF1RX_LRCLK_INV */ +#define WM8915_AIF1RX_LRCLK_INV_WIDTH 1 /* AIF1RX_LRCLK_INV */ +#define WM8915_AIF1RX_LRCLK_FRC 0x0002 /* AIF1RX_LRCLK_FRC */ +#define WM8915_AIF1RX_LRCLK_FRC_MASK 0x0002 /* AIF1RX_LRCLK_FRC */ +#define WM8915_AIF1RX_LRCLK_FRC_SHIFT 1 /* AIF1RX_LRCLK_FRC */ +#define WM8915_AIF1RX_LRCLK_FRC_WIDTH 1 /* AIF1RX_LRCLK_FRC */ +#define WM8915_AIF1RX_LRCLK_MSTR 0x0001 /* AIF1RX_LRCLK_MSTR */ +#define WM8915_AIF1RX_LRCLK_MSTR_MASK 0x0001 /* AIF1RX_LRCLK_MSTR */ +#define WM8915_AIF1RX_LRCLK_MSTR_SHIFT 0 /* AIF1RX_LRCLK_MSTR */ +#define WM8915_AIF1RX_LRCLK_MSTR_WIDTH 1 /* AIF1RX_LRCLK_MSTR */ + +/* + * R774 (0x306) - AIF1TX Data Configuration (1) + */ +#define WM8915_AIF1TX_WL_MASK 0xFF00 /* AIF1TX_WL - [15:8] */ +#define WM8915_AIF1TX_WL_SHIFT 8 /* AIF1TX_WL - [15:8] */ +#define WM8915_AIF1TX_WL_WIDTH 8 /* AIF1TX_WL - [15:8] */ +#define WM8915_AIF1TX_SLOT_LEN_MASK 0x00FF /* AIF1TX_SLOT_LEN - [7:0] */ +#define WM8915_AIF1TX_SLOT_LEN_SHIFT 0 /* AIF1TX_SLOT_LEN - [7:0] */ +#define WM8915_AIF1TX_SLOT_LEN_WIDTH 8 /* AIF1TX_SLOT_LEN - [7:0] */ + +/* + * R775 (0x307) - AIF1TX Data Configuration (2) + */ +#define WM8915_AIF1TX_DAT_TRI 0x0001 /* AIF1TX_DAT_TRI */ +#define WM8915_AIF1TX_DAT_TRI_MASK 0x0001 /* AIF1TX_DAT_TRI */ +#define WM8915_AIF1TX_DAT_TRI_SHIFT 0 /* AIF1TX_DAT_TRI */ +#define WM8915_AIF1TX_DAT_TRI_WIDTH 1 /* AIF1TX_DAT_TRI */ + +/* + * R776 (0x308) - AIF1RX Data Configuration + */ +#define WM8915_AIF1RX_WL_MASK 0xFF00 /* AIF1RX_WL - [15:8] */ +#define WM8915_AIF1RX_WL_SHIFT 8 /* AIF1RX_WL - [15:8] */ +#define WM8915_AIF1RX_WL_WIDTH 8 /* AIF1RX_WL - [15:8] */ +#define WM8915_AIF1RX_SLOT_LEN_MASK 0x00FF /* AIF1RX_SLOT_LEN - [7:0] */ +#define WM8915_AIF1RX_SLOT_LEN_SHIFT 0 /* AIF1RX_SLOT_LEN - [7:0] */ +#define WM8915_AIF1RX_SLOT_LEN_WIDTH 8 /* AIF1RX_SLOT_LEN - [7:0] */ + +/* + * R777 (0x309) - AIF1TX Channel 0 Configuration + */ +#define WM8915_AIF1TX_CHAN0_DAT_INV 0x8000 /* AIF1TX_CHAN0_DAT_INV */ +#define WM8915_AIF1TX_CHAN0_DAT_INV_MASK 0x8000 /* AIF1TX_CHAN0_DAT_INV */ +#define WM8915_AIF1TX_CHAN0_DAT_INV_SHIFT 15 /* AIF1TX_CHAN0_DAT_INV */ +#define WM8915_AIF1TX_CHAN0_DAT_INV_WIDTH 1 /* AIF1TX_CHAN0_DAT_INV */ +#define WM8915_AIF1TX_CHAN0_SPACING_MASK 0x7E00 /* AIF1TX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN0_SPACING_SHIFT 9 /* AIF1TX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN0_SPACING_WIDTH 6 /* AIF1TX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN0_SLOTS_MASK 0x01C0 /* AIF1TX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN0_SLOTS_SHIFT 6 /* AIF1TX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN0_SLOTS_WIDTH 3 /* AIF1TX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN0_START_SLOT_MASK 0x003F /* AIF1TX_CHAN0_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN0_START_SLOT_SHIFT 0 /* AIF1TX_CHAN0_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN0_START_SLOT_WIDTH 6 /* AIF1TX_CHAN0_START_SLOT - [5:0] */ + +/* + * R778 (0x30A) - AIF1TX Channel 1 Configuration + */ +#define WM8915_AIF1TX_CHAN1_DAT_INV 0x8000 /* AIF1TX_CHAN1_DAT_INV */ +#define WM8915_AIF1TX_CHAN1_DAT_INV_MASK 0x8000 /* AIF1TX_CHAN1_DAT_INV */ +#define WM8915_AIF1TX_CHAN1_DAT_INV_SHIFT 15 /* AIF1TX_CHAN1_DAT_INV */ +#define WM8915_AIF1TX_CHAN1_DAT_INV_WIDTH 1 /* AIF1TX_CHAN1_DAT_INV */ +#define WM8915_AIF1TX_CHAN1_SPACING_MASK 0x7E00 /* AIF1TX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN1_SPACING_SHIFT 9 /* AIF1TX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN1_SPACING_WIDTH 6 /* AIF1TX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN1_SLOTS_MASK 0x01C0 /* AIF1TX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN1_SLOTS_SHIFT 6 /* AIF1TX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN1_SLOTS_WIDTH 3 /* AIF1TX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN1_START_SLOT_MASK 0x003F /* AIF1TX_CHAN1_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN1_START_SLOT_SHIFT 0 /* AIF1TX_CHAN1_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN1_START_SLOT_WIDTH 6 /* AIF1TX_CHAN1_START_SLOT - [5:0] */ + +/* + * R779 (0x30B) - AIF1TX Channel 2 Configuration + */ +#define WM8915_AIF1TX_CHAN2_DAT_INV 0x8000 /* AIF1TX_CHAN2_DAT_INV */ +#define WM8915_AIF1TX_CHAN2_DAT_INV_MASK 0x8000 /* AIF1TX_CHAN2_DAT_INV */ +#define WM8915_AIF1TX_CHAN2_DAT_INV_SHIFT 15 /* AIF1TX_CHAN2_DAT_INV */ +#define WM8915_AIF1TX_CHAN2_DAT_INV_WIDTH 1 /* AIF1TX_CHAN2_DAT_INV */ +#define WM8915_AIF1TX_CHAN2_SPACING_MASK 0x7E00 /* AIF1TX_CHAN2_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN2_SPACING_SHIFT 9 /* AIF1TX_CHAN2_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN2_SPACING_WIDTH 6 /* AIF1TX_CHAN2_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN2_SLOTS_MASK 0x01C0 /* AIF1TX_CHAN2_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN2_SLOTS_SHIFT 6 /* AIF1TX_CHAN2_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN2_SLOTS_WIDTH 3 /* AIF1TX_CHAN2_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN2_START_SLOT_MASK 0x003F /* AIF1TX_CHAN2_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN2_START_SLOT_SHIFT 0 /* AIF1TX_CHAN2_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN2_START_SLOT_WIDTH 6 /* AIF1TX_CHAN2_START_SLOT - [5:0] */ + +/* + * R780 (0x30C) - AIF1TX Channel 3 Configuration + */ +#define WM8915_AIF1TX_CHAN3_DAT_INV 0x8000 /* AIF1TX_CHAN3_DAT_INV */ +#define WM8915_AIF1TX_CHAN3_DAT_INV_MASK 0x8000 /* AIF1TX_CHAN3_DAT_INV */ +#define WM8915_AIF1TX_CHAN3_DAT_INV_SHIFT 15 /* AIF1TX_CHAN3_DAT_INV */ +#define WM8915_AIF1TX_CHAN3_DAT_INV_WIDTH 1 /* AIF1TX_CHAN3_DAT_INV */ +#define WM8915_AIF1TX_CHAN3_SPACING_MASK 0x7E00 /* AIF1TX_CHAN3_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN3_SPACING_SHIFT 9 /* AIF1TX_CHAN3_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN3_SPACING_WIDTH 6 /* AIF1TX_CHAN3_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN3_SLOTS_MASK 0x01C0 /* AIF1TX_CHAN3_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN3_SLOTS_SHIFT 6 /* AIF1TX_CHAN3_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN3_SLOTS_WIDTH 3 /* AIF1TX_CHAN3_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN3_START_SLOT_MASK 0x003F /* AIF1TX_CHAN3_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN3_START_SLOT_SHIFT 0 /* AIF1TX_CHAN3_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN3_START_SLOT_WIDTH 6 /* AIF1TX_CHAN3_START_SLOT - [5:0] */ + +/* + * R781 (0x30D) - AIF1TX Channel 4 Configuration + */ +#define WM8915_AIF1TX_CHAN4_DAT_INV 0x8000 /* AIF1TX_CHAN4_DAT_INV */ +#define WM8915_AIF1TX_CHAN4_DAT_INV_MASK 0x8000 /* AIF1TX_CHAN4_DAT_INV */ +#define WM8915_AIF1TX_CHAN4_DAT_INV_SHIFT 15 /* AIF1TX_CHAN4_DAT_INV */ +#define WM8915_AIF1TX_CHAN4_DAT_INV_WIDTH 1 /* AIF1TX_CHAN4_DAT_INV */ +#define WM8915_AIF1TX_CHAN4_SPACING_MASK 0x7E00 /* AIF1TX_CHAN4_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN4_SPACING_SHIFT 9 /* AIF1TX_CHAN4_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN4_SPACING_WIDTH 6 /* AIF1TX_CHAN4_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN4_SLOTS_MASK 0x01C0 /* AIF1TX_CHAN4_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN4_SLOTS_SHIFT 6 /* AIF1TX_CHAN4_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN4_SLOTS_WIDTH 3 /* AIF1TX_CHAN4_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN4_START_SLOT_MASK 0x003F /* AIF1TX_CHAN4_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN4_START_SLOT_SHIFT 0 /* AIF1TX_CHAN4_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN4_START_SLOT_WIDTH 6 /* AIF1TX_CHAN4_START_SLOT - [5:0] */ + +/* + * R782 (0x30E) - AIF1TX Channel 5 Configuration + */ +#define WM8915_AIF1TX_CHAN5_DAT_INV 0x8000 /* AIF1TX_CHAN5_DAT_INV */ +#define WM8915_AIF1TX_CHAN5_DAT_INV_MASK 0x8000 /* AIF1TX_CHAN5_DAT_INV */ +#define WM8915_AIF1TX_CHAN5_DAT_INV_SHIFT 15 /* AIF1TX_CHAN5_DAT_INV */ +#define WM8915_AIF1TX_CHAN5_DAT_INV_WIDTH 1 /* AIF1TX_CHAN5_DAT_INV */ +#define WM8915_AIF1TX_CHAN5_SPACING_MASK 0x7E00 /* AIF1TX_CHAN5_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN5_SPACING_SHIFT 9 /* AIF1TX_CHAN5_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN5_SPACING_WIDTH 6 /* AIF1TX_CHAN5_SPACING - [14:9] */ +#define WM8915_AIF1TX_CHAN5_SLOTS_MASK 0x01C0 /* AIF1TX_CHAN5_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN5_SLOTS_SHIFT 6 /* AIF1TX_CHAN5_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN5_SLOTS_WIDTH 3 /* AIF1TX_CHAN5_SLOTS - [8:6] */ +#define WM8915_AIF1TX_CHAN5_START_SLOT_MASK 0x003F /* AIF1TX_CHAN5_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN5_START_SLOT_SHIFT 0 /* AIF1TX_CHAN5_START_SLOT - [5:0] */ +#define WM8915_AIF1TX_CHAN5_START_SLOT_WIDTH 6 /* AIF1TX_CHAN5_START_SLOT - [5:0] */ + +/* + * R783 (0x30F) - AIF1RX Channel 0 Configuration + */ +#define WM8915_AIF1RX_CHAN0_DAT_INV 0x8000 /* AIF1RX_CHAN0_DAT_INV */ +#define WM8915_AIF1RX_CHAN0_DAT_INV_MASK 0x8000 /* AIF1RX_CHAN0_DAT_INV */ +#define WM8915_AIF1RX_CHAN0_DAT_INV_SHIFT 15 /* AIF1RX_CHAN0_DAT_INV */ +#define WM8915_AIF1RX_CHAN0_DAT_INV_WIDTH 1 /* AIF1RX_CHAN0_DAT_INV */ +#define WM8915_AIF1RX_CHAN0_SPACING_MASK 0x7E00 /* AIF1RX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN0_SPACING_SHIFT 9 /* AIF1RX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN0_SPACING_WIDTH 6 /* AIF1RX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN0_SLOTS_MASK 0x01C0 /* AIF1RX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN0_SLOTS_SHIFT 6 /* AIF1RX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN0_SLOTS_WIDTH 3 /* AIF1RX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN0_START_SLOT_MASK 0x003F /* AIF1RX_CHAN0_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN0_START_SLOT_SHIFT 0 /* AIF1RX_CHAN0_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN0_START_SLOT_WIDTH 6 /* AIF1RX_CHAN0_START_SLOT - [5:0] */ + +/* + * R784 (0x310) - AIF1RX Channel 1 Configuration + */ +#define WM8915_AIF1RX_CHAN1_DAT_INV 0x8000 /* AIF1RX_CHAN1_DAT_INV */ +#define WM8915_AIF1RX_CHAN1_DAT_INV_MASK 0x8000 /* AIF1RX_CHAN1_DAT_INV */ +#define WM8915_AIF1RX_CHAN1_DAT_INV_SHIFT 15 /* AIF1RX_CHAN1_DAT_INV */ +#define WM8915_AIF1RX_CHAN1_DAT_INV_WIDTH 1 /* AIF1RX_CHAN1_DAT_INV */ +#define WM8915_AIF1RX_CHAN1_SPACING_MASK 0x7E00 /* AIF1RX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN1_SPACING_SHIFT 9 /* AIF1RX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN1_SPACING_WIDTH 6 /* AIF1RX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN1_SLOTS_MASK 0x01C0 /* AIF1RX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN1_SLOTS_SHIFT 6 /* AIF1RX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN1_SLOTS_WIDTH 3 /* AIF1RX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN1_START_SLOT_MASK 0x003F /* AIF1RX_CHAN1_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN1_START_SLOT_SHIFT 0 /* AIF1RX_CHAN1_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN1_START_SLOT_WIDTH 6 /* AIF1RX_CHAN1_START_SLOT - [5:0] */ + +/* + * R785 (0x311) - AIF1RX Channel 2 Configuration + */ +#define WM8915_AIF1RX_CHAN2_DAT_INV 0x8000 /* AIF1RX_CHAN2_DAT_INV */ +#define WM8915_AIF1RX_CHAN2_DAT_INV_MASK 0x8000 /* AIF1RX_CHAN2_DAT_INV */ +#define WM8915_AIF1RX_CHAN2_DAT_INV_SHIFT 15 /* AIF1RX_CHAN2_DAT_INV */ +#define WM8915_AIF1RX_CHAN2_DAT_INV_WIDTH 1 /* AIF1RX_CHAN2_DAT_INV */ +#define WM8915_AIF1RX_CHAN2_SPACING_MASK 0x7E00 /* AIF1RX_CHAN2_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN2_SPACING_SHIFT 9 /* AIF1RX_CHAN2_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN2_SPACING_WIDTH 6 /* AIF1RX_CHAN2_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN2_SLOTS_MASK 0x01C0 /* AIF1RX_CHAN2_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN2_SLOTS_SHIFT 6 /* AIF1RX_CHAN2_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN2_SLOTS_WIDTH 3 /* AIF1RX_CHAN2_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN2_START_SLOT_MASK 0x003F /* AIF1RX_CHAN2_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN2_START_SLOT_SHIFT 0 /* AIF1RX_CHAN2_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN2_START_SLOT_WIDTH 6 /* AIF1RX_CHAN2_START_SLOT - [5:0] */ + +/* + * R786 (0x312) - AIF1RX Channel 3 Configuration + */ +#define WM8915_AIF1RX_CHAN3_DAT_INV 0x8000 /* AIF1RX_CHAN3_DAT_INV */ +#define WM8915_AIF1RX_CHAN3_DAT_INV_MASK 0x8000 /* AIF1RX_CHAN3_DAT_INV */ +#define WM8915_AIF1RX_CHAN3_DAT_INV_SHIFT 15 /* AIF1RX_CHAN3_DAT_INV */ +#define WM8915_AIF1RX_CHAN3_DAT_INV_WIDTH 1 /* AIF1RX_CHAN3_DAT_INV */ +#define WM8915_AIF1RX_CHAN3_SPACING_MASK 0x7E00 /* AIF1RX_CHAN3_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN3_SPACING_SHIFT 9 /* AIF1RX_CHAN3_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN3_SPACING_WIDTH 6 /* AIF1RX_CHAN3_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN3_SLOTS_MASK 0x01C0 /* AIF1RX_CHAN3_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN3_SLOTS_SHIFT 6 /* AIF1RX_CHAN3_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN3_SLOTS_WIDTH 3 /* AIF1RX_CHAN3_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN3_START_SLOT_MASK 0x003F /* AIF1RX_CHAN3_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN3_START_SLOT_SHIFT 0 /* AIF1RX_CHAN3_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN3_START_SLOT_WIDTH 6 /* AIF1RX_CHAN3_START_SLOT - [5:0] */ + +/* + * R787 (0x313) - AIF1RX Channel 4 Configuration + */ +#define WM8915_AIF1RX_CHAN4_DAT_INV 0x8000 /* AIF1RX_CHAN4_DAT_INV */ +#define WM8915_AIF1RX_CHAN4_DAT_INV_MASK 0x8000 /* AIF1RX_CHAN4_DAT_INV */ +#define WM8915_AIF1RX_CHAN4_DAT_INV_SHIFT 15 /* AIF1RX_CHAN4_DAT_INV */ +#define WM8915_AIF1RX_CHAN4_DAT_INV_WIDTH 1 /* AIF1RX_CHAN4_DAT_INV */ +#define WM8915_AIF1RX_CHAN4_SPACING_MASK 0x7E00 /* AIF1RX_CHAN4_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN4_SPACING_SHIFT 9 /* AIF1RX_CHAN4_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN4_SPACING_WIDTH 6 /* AIF1RX_CHAN4_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN4_SLOTS_MASK 0x01C0 /* AIF1RX_CHAN4_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN4_SLOTS_SHIFT 6 /* AIF1RX_CHAN4_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN4_SLOTS_WIDTH 3 /* AIF1RX_CHAN4_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN4_START_SLOT_MASK 0x003F /* AIF1RX_CHAN4_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN4_START_SLOT_SHIFT 0 /* AIF1RX_CHAN4_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN4_START_SLOT_WIDTH 6 /* AIF1RX_CHAN4_START_SLOT - [5:0] */ + +/* + * R788 (0x314) - AIF1RX Channel 5 Configuration + */ +#define WM8915_AIF1RX_CHAN5_DAT_INV 0x8000 /* AIF1RX_CHAN5_DAT_INV */ +#define WM8915_AIF1RX_CHAN5_DAT_INV_MASK 0x8000 /* AIF1RX_CHAN5_DAT_INV */ +#define WM8915_AIF1RX_CHAN5_DAT_INV_SHIFT 15 /* AIF1RX_CHAN5_DAT_INV */ +#define WM8915_AIF1RX_CHAN5_DAT_INV_WIDTH 1 /* AIF1RX_CHAN5_DAT_INV */ +#define WM8915_AIF1RX_CHAN5_SPACING_MASK 0x7E00 /* AIF1RX_CHAN5_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN5_SPACING_SHIFT 9 /* AIF1RX_CHAN5_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN5_SPACING_WIDTH 6 /* AIF1RX_CHAN5_SPACING - [14:9] */ +#define WM8915_AIF1RX_CHAN5_SLOTS_MASK 0x01C0 /* AIF1RX_CHAN5_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN5_SLOTS_SHIFT 6 /* AIF1RX_CHAN5_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN5_SLOTS_WIDTH 3 /* AIF1RX_CHAN5_SLOTS - [8:6] */ +#define WM8915_AIF1RX_CHAN5_START_SLOT_MASK 0x003F /* AIF1RX_CHAN5_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN5_START_SLOT_SHIFT 0 /* AIF1RX_CHAN5_START_SLOT - [5:0] */ +#define WM8915_AIF1RX_CHAN5_START_SLOT_WIDTH 6 /* AIF1RX_CHAN5_START_SLOT - [5:0] */ + +/* + * R789 (0x315) - AIF1RX Mono Configuration + */ +#define WM8915_AIF1RX_CHAN4_MONO_MODE 0x0004 /* AIF1RX_CHAN4_MONO_MODE */ +#define WM8915_AIF1RX_CHAN4_MONO_MODE_MASK 0x0004 /* AIF1RX_CHAN4_MONO_MODE */ +#define WM8915_AIF1RX_CHAN4_MONO_MODE_SHIFT 2 /* AIF1RX_CHAN4_MONO_MODE */ +#define WM8915_AIF1RX_CHAN4_MONO_MODE_WIDTH 1 /* AIF1RX_CHAN4_MONO_MODE */ +#define WM8915_AIF1RX_CHAN2_MONO_MODE 0x0002 /* AIF1RX_CHAN2_MONO_MODE */ +#define WM8915_AIF1RX_CHAN2_MONO_MODE_MASK 0x0002 /* AIF1RX_CHAN2_MONO_MODE */ +#define WM8915_AIF1RX_CHAN2_MONO_MODE_SHIFT 1 /* AIF1RX_CHAN2_MONO_MODE */ +#define WM8915_AIF1RX_CHAN2_MONO_MODE_WIDTH 1 /* AIF1RX_CHAN2_MONO_MODE */ +#define WM8915_AIF1RX_CHAN0_MONO_MODE 0x0001 /* AIF1RX_CHAN0_MONO_MODE */ +#define WM8915_AIF1RX_CHAN0_MONO_MODE_MASK 0x0001 /* AIF1RX_CHAN0_MONO_MODE */ +#define WM8915_AIF1RX_CHAN0_MONO_MODE_SHIFT 0 /* AIF1RX_CHAN0_MONO_MODE */ +#define WM8915_AIF1RX_CHAN0_MONO_MODE_WIDTH 1 /* AIF1RX_CHAN0_MONO_MODE */ + +/* + * R794 (0x31A) - AIF1TX Test + */ +#define WM8915_AIF1TX45_DITHER_ENA 0x0004 /* AIF1TX45_DITHER_ENA */ +#define WM8915_AIF1TX45_DITHER_ENA_MASK 0x0004 /* AIF1TX45_DITHER_ENA */ +#define WM8915_AIF1TX45_DITHER_ENA_SHIFT 2 /* AIF1TX45_DITHER_ENA */ +#define WM8915_AIF1TX45_DITHER_ENA_WIDTH 1 /* AIF1TX45_DITHER_ENA */ +#define WM8915_AIF1TX23_DITHER_ENA 0x0002 /* AIF1TX23_DITHER_ENA */ +#define WM8915_AIF1TX23_DITHER_ENA_MASK 0x0002 /* AIF1TX23_DITHER_ENA */ +#define WM8915_AIF1TX23_DITHER_ENA_SHIFT 1 /* AIF1TX23_DITHER_ENA */ +#define WM8915_AIF1TX23_DITHER_ENA_WIDTH 1 /* AIF1TX23_DITHER_ENA */ +#define WM8915_AIF1TX01_DITHER_ENA 0x0001 /* AIF1TX01_DITHER_ENA */ +#define WM8915_AIF1TX01_DITHER_ENA_MASK 0x0001 /* AIF1TX01_DITHER_ENA */ +#define WM8915_AIF1TX01_DITHER_ENA_SHIFT 0 /* AIF1TX01_DITHER_ENA */ +#define WM8915_AIF1TX01_DITHER_ENA_WIDTH 1 /* AIF1TX01_DITHER_ENA */ + +/* + * R800 (0x320) - AIF2 Control + */ +#define WM8915_AIF2_TRI 0x0004 /* AIF2_TRI */ +#define WM8915_AIF2_TRI_MASK 0x0004 /* AIF2_TRI */ +#define WM8915_AIF2_TRI_SHIFT 2 /* AIF2_TRI */ +#define WM8915_AIF2_TRI_WIDTH 1 /* AIF2_TRI */ +#define WM8915_AIF2_FMT_MASK 0x0003 /* AIF2_FMT - [1:0] */ +#define WM8915_AIF2_FMT_SHIFT 0 /* AIF2_FMT - [1:0] */ +#define WM8915_AIF2_FMT_WIDTH 2 /* AIF2_FMT - [1:0] */ + +/* + * R801 (0x321) - AIF2 BCLK + */ +#define WM8915_AIF2_BCLK_INV 0x0400 /* AIF2_BCLK_INV */ +#define WM8915_AIF2_BCLK_INV_MASK 0x0400 /* AIF2_BCLK_INV */ +#define WM8915_AIF2_BCLK_INV_SHIFT 10 /* AIF2_BCLK_INV */ +#define WM8915_AIF2_BCLK_INV_WIDTH 1 /* AIF2_BCLK_INV */ +#define WM8915_AIF2_BCLK_FRC 0x0200 /* AIF2_BCLK_FRC */ +#define WM8915_AIF2_BCLK_FRC_MASK 0x0200 /* AIF2_BCLK_FRC */ +#define WM8915_AIF2_BCLK_FRC_SHIFT 9 /* AIF2_BCLK_FRC */ +#define WM8915_AIF2_BCLK_FRC_WIDTH 1 /* AIF2_BCLK_FRC */ +#define WM8915_AIF2_BCLK_MSTR 0x0100 /* AIF2_BCLK_MSTR */ +#define WM8915_AIF2_BCLK_MSTR_MASK 0x0100 /* AIF2_BCLK_MSTR */ +#define WM8915_AIF2_BCLK_MSTR_SHIFT 8 /* AIF2_BCLK_MSTR */ +#define WM8915_AIF2_BCLK_MSTR_WIDTH 1 /* AIF2_BCLK_MSTR */ +#define WM8915_AIF2_BCLK_DIV_MASK 0x000F /* AIF2_BCLK_DIV - [3:0] */ +#define WM8915_AIF2_BCLK_DIV_SHIFT 0 /* AIF2_BCLK_DIV - [3:0] */ +#define WM8915_AIF2_BCLK_DIV_WIDTH 4 /* AIF2_BCLK_DIV - [3:0] */ + +/* + * R802 (0x322) - AIF2 TX LRCLK(1) + */ +#define WM8915_AIF2TX_RATE_MASK 0x07FF /* AIF2TX_RATE - [10:0] */ +#define WM8915_AIF2TX_RATE_SHIFT 0 /* AIF2TX_RATE - [10:0] */ +#define WM8915_AIF2TX_RATE_WIDTH 11 /* AIF2TX_RATE - [10:0] */ + +/* + * R803 (0x323) - AIF2 TX LRCLK(2) + */ +#define WM8915_AIF2TX_LRCLK_MODE 0x0008 /* AIF2TX_LRCLK_MODE */ +#define WM8915_AIF2TX_LRCLK_MODE_MASK 0x0008 /* AIF2TX_LRCLK_MODE */ +#define WM8915_AIF2TX_LRCLK_MODE_SHIFT 3 /* AIF2TX_LRCLK_MODE */ +#define WM8915_AIF2TX_LRCLK_MODE_WIDTH 1 /* AIF2TX_LRCLK_MODE */ +#define WM8915_AIF2TX_LRCLK_INV 0x0004 /* AIF2TX_LRCLK_INV */ +#define WM8915_AIF2TX_LRCLK_INV_MASK 0x0004 /* AIF2TX_LRCLK_INV */ +#define WM8915_AIF2TX_LRCLK_INV_SHIFT 2 /* AIF2TX_LRCLK_INV */ +#define WM8915_AIF2TX_LRCLK_INV_WIDTH 1 /* AIF2TX_LRCLK_INV */ +#define WM8915_AIF2TX_LRCLK_FRC 0x0002 /* AIF2TX_LRCLK_FRC */ +#define WM8915_AIF2TX_LRCLK_FRC_MASK 0x0002 /* AIF2TX_LRCLK_FRC */ +#define WM8915_AIF2TX_LRCLK_FRC_SHIFT 1 /* AIF2TX_LRCLK_FRC */ +#define WM8915_AIF2TX_LRCLK_FRC_WIDTH 1 /* AIF2TX_LRCLK_FRC */ +#define WM8915_AIF2TX_LRCLK_MSTR 0x0001 /* AIF2TX_LRCLK_MSTR */ +#define WM8915_AIF2TX_LRCLK_MSTR_MASK 0x0001 /* AIF2TX_LRCLK_MSTR */ +#define WM8915_AIF2TX_LRCLK_MSTR_SHIFT 0 /* AIF2TX_LRCLK_MSTR */ +#define WM8915_AIF2TX_LRCLK_MSTR_WIDTH 1 /* AIF2TX_LRCLK_MSTR */ + +/* + * R804 (0x324) - AIF2 RX LRCLK(1) + */ +#define WM8915_AIF2RX_RATE_MASK 0x07FF /* AIF2RX_RATE - [10:0] */ +#define WM8915_AIF2RX_RATE_SHIFT 0 /* AIF2RX_RATE - [10:0] */ +#define WM8915_AIF2RX_RATE_WIDTH 11 /* AIF2RX_RATE - [10:0] */ + +/* + * R805 (0x325) - AIF2 RX LRCLK(2) + */ +#define WM8915_AIF2RX_LRCLK_INV 0x0004 /* AIF2RX_LRCLK_INV */ +#define WM8915_AIF2RX_LRCLK_INV_MASK 0x0004 /* AIF2RX_LRCLK_INV */ +#define WM8915_AIF2RX_LRCLK_INV_SHIFT 2 /* AIF2RX_LRCLK_INV */ +#define WM8915_AIF2RX_LRCLK_INV_WIDTH 1 /* AIF2RX_LRCLK_INV */ +#define WM8915_AIF2RX_LRCLK_FRC 0x0002 /* AIF2RX_LRCLK_FRC */ +#define WM8915_AIF2RX_LRCLK_FRC_MASK 0x0002 /* AIF2RX_LRCLK_FRC */ +#define WM8915_AIF2RX_LRCLK_FRC_SHIFT 1 /* AIF2RX_LRCLK_FRC */ +#define WM8915_AIF2RX_LRCLK_FRC_WIDTH 1 /* AIF2RX_LRCLK_FRC */ +#define WM8915_AIF2RX_LRCLK_MSTR 0x0001 /* AIF2RX_LRCLK_MSTR */ +#define WM8915_AIF2RX_LRCLK_MSTR_MASK 0x0001 /* AIF2RX_LRCLK_MSTR */ +#define WM8915_AIF2RX_LRCLK_MSTR_SHIFT 0 /* AIF2RX_LRCLK_MSTR */ +#define WM8915_AIF2RX_LRCLK_MSTR_WIDTH 1 /* AIF2RX_LRCLK_MSTR */ + +/* + * R806 (0x326) - AIF2TX Data Configuration (1) + */ +#define WM8915_AIF2TX_WL_MASK 0xFF00 /* AIF2TX_WL - [15:8] */ +#define WM8915_AIF2TX_WL_SHIFT 8 /* AIF2TX_WL - [15:8] */ +#define WM8915_AIF2TX_WL_WIDTH 8 /* AIF2TX_WL - [15:8] */ +#define WM8915_AIF2TX_SLOT_LEN_MASK 0x00FF /* AIF2TX_SLOT_LEN - [7:0] */ +#define WM8915_AIF2TX_SLOT_LEN_SHIFT 0 /* AIF2TX_SLOT_LEN - [7:0] */ +#define WM8915_AIF2TX_SLOT_LEN_WIDTH 8 /* AIF2TX_SLOT_LEN - [7:0] */ + +/* + * R807 (0x327) - AIF2TX Data Configuration (2) + */ +#define WM8915_AIF2TX_DAT_TRI 0x0001 /* AIF2TX_DAT_TRI */ +#define WM8915_AIF2TX_DAT_TRI_MASK 0x0001 /* AIF2TX_DAT_TRI */ +#define WM8915_AIF2TX_DAT_TRI_SHIFT 0 /* AIF2TX_DAT_TRI */ +#define WM8915_AIF2TX_DAT_TRI_WIDTH 1 /* AIF2TX_DAT_TRI */ + +/* + * R808 (0x328) - AIF2RX Data Configuration + */ +#define WM8915_AIF2RX_WL_MASK 0xFF00 /* AIF2RX_WL - [15:8] */ +#define WM8915_AIF2RX_WL_SHIFT 8 /* AIF2RX_WL - [15:8] */ +#define WM8915_AIF2RX_WL_WIDTH 8 /* AIF2RX_WL - [15:8] */ +#define WM8915_AIF2RX_SLOT_LEN_MASK 0x00FF /* AIF2RX_SLOT_LEN - [7:0] */ +#define WM8915_AIF2RX_SLOT_LEN_SHIFT 0 /* AIF2RX_SLOT_LEN - [7:0] */ +#define WM8915_AIF2RX_SLOT_LEN_WIDTH 8 /* AIF2RX_SLOT_LEN - [7:0] */ + +/* + * R809 (0x329) - AIF2TX Channel 0 Configuration + */ +#define WM8915_AIF2TX_CHAN0_DAT_INV 0x8000 /* AIF2TX_CHAN0_DAT_INV */ +#define WM8915_AIF2TX_CHAN0_DAT_INV_MASK 0x8000 /* AIF2TX_CHAN0_DAT_INV */ +#define WM8915_AIF2TX_CHAN0_DAT_INV_SHIFT 15 /* AIF2TX_CHAN0_DAT_INV */ +#define WM8915_AIF2TX_CHAN0_DAT_INV_WIDTH 1 /* AIF2TX_CHAN0_DAT_INV */ +#define WM8915_AIF2TX_CHAN0_SPACING_MASK 0x7E00 /* AIF2TX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF2TX_CHAN0_SPACING_SHIFT 9 /* AIF2TX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF2TX_CHAN0_SPACING_WIDTH 6 /* AIF2TX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF2TX_CHAN0_SLOTS_MASK 0x01C0 /* AIF2TX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF2TX_CHAN0_SLOTS_SHIFT 6 /* AIF2TX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF2TX_CHAN0_SLOTS_WIDTH 3 /* AIF2TX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF2TX_CHAN0_START_SLOT_MASK 0x003F /* AIF2TX_CHAN0_START_SLOT - [5:0] */ +#define WM8915_AIF2TX_CHAN0_START_SLOT_SHIFT 0 /* AIF2TX_CHAN0_START_SLOT - [5:0] */ +#define WM8915_AIF2TX_CHAN0_START_SLOT_WIDTH 6 /* AIF2TX_CHAN0_START_SLOT - [5:0] */ + +/* + * R810 (0x32A) - AIF2TX Channel 1 Configuration + */ +#define WM8915_AIF2TX_CHAN1_DAT_INV 0x8000 /* AIF2TX_CHAN1_DAT_INV */ +#define WM8915_AIF2TX_CHAN1_DAT_INV_MASK 0x8000 /* AIF2TX_CHAN1_DAT_INV */ +#define WM8915_AIF2TX_CHAN1_DAT_INV_SHIFT 15 /* AIF2TX_CHAN1_DAT_INV */ +#define WM8915_AIF2TX_CHAN1_DAT_INV_WIDTH 1 /* AIF2TX_CHAN1_DAT_INV */ +#define WM8915_AIF2TX_CHAN1_SPACING_MASK 0x7E00 /* AIF2TX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF2TX_CHAN1_SPACING_SHIFT 9 /* AIF2TX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF2TX_CHAN1_SPACING_WIDTH 6 /* AIF2TX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF2TX_CHAN1_SLOTS_MASK 0x01C0 /* AIF2TX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF2TX_CHAN1_SLOTS_SHIFT 6 /* AIF2TX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF2TX_CHAN1_SLOTS_WIDTH 3 /* AIF2TX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF2TX_CHAN1_START_SLOT_MASK 0x003F /* AIF2TX_CHAN1_START_SLOT - [5:0] */ +#define WM8915_AIF2TX_CHAN1_START_SLOT_SHIFT 0 /* AIF2TX_CHAN1_START_SLOT - [5:0] */ +#define WM8915_AIF2TX_CHAN1_START_SLOT_WIDTH 6 /* AIF2TX_CHAN1_START_SLOT - [5:0] */ + +/* + * R811 (0x32B) - AIF2RX Channel 0 Configuration + */ +#define WM8915_AIF2RX_CHAN0_DAT_INV 0x8000 /* AIF2RX_CHAN0_DAT_INV */ +#define WM8915_AIF2RX_CHAN0_DAT_INV_MASK 0x8000 /* AIF2RX_CHAN0_DAT_INV */ +#define WM8915_AIF2RX_CHAN0_DAT_INV_SHIFT 15 /* AIF2RX_CHAN0_DAT_INV */ +#define WM8915_AIF2RX_CHAN0_DAT_INV_WIDTH 1 /* AIF2RX_CHAN0_DAT_INV */ +#define WM8915_AIF2RX_CHAN0_SPACING_MASK 0x7E00 /* AIF2RX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF2RX_CHAN0_SPACING_SHIFT 9 /* AIF2RX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF2RX_CHAN0_SPACING_WIDTH 6 /* AIF2RX_CHAN0_SPACING - [14:9] */ +#define WM8915_AIF2RX_CHAN0_SLOTS_MASK 0x01C0 /* AIF2RX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF2RX_CHAN0_SLOTS_SHIFT 6 /* AIF2RX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF2RX_CHAN0_SLOTS_WIDTH 3 /* AIF2RX_CHAN0_SLOTS - [8:6] */ +#define WM8915_AIF2RX_CHAN0_START_SLOT_MASK 0x003F /* AIF2RX_CHAN0_START_SLOT - [5:0] */ +#define WM8915_AIF2RX_CHAN0_START_SLOT_SHIFT 0 /* AIF2RX_CHAN0_START_SLOT - [5:0] */ +#define WM8915_AIF2RX_CHAN0_START_SLOT_WIDTH 6 /* AIF2RX_CHAN0_START_SLOT - [5:0] */ + +/* + * R812 (0x32C) - AIF2RX Channel 1 Configuration + */ +#define WM8915_AIF2RX_CHAN1_DAT_INV 0x8000 /* AIF2RX_CHAN1_DAT_INV */ +#define WM8915_AIF2RX_CHAN1_DAT_INV_MASK 0x8000 /* AIF2RX_CHAN1_DAT_INV */ +#define WM8915_AIF2RX_CHAN1_DAT_INV_SHIFT 15 /* AIF2RX_CHAN1_DAT_INV */ +#define WM8915_AIF2RX_CHAN1_DAT_INV_WIDTH 1 /* AIF2RX_CHAN1_DAT_INV */ +#define WM8915_AIF2RX_CHAN1_SPACING_MASK 0x7E00 /* AIF2RX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF2RX_CHAN1_SPACING_SHIFT 9 /* AIF2RX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF2RX_CHAN1_SPACING_WIDTH 6 /* AIF2RX_CHAN1_SPACING - [14:9] */ +#define WM8915_AIF2RX_CHAN1_SLOTS_MASK 0x01C0 /* AIF2RX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF2RX_CHAN1_SLOTS_SHIFT 6 /* AIF2RX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF2RX_CHAN1_SLOTS_WIDTH 3 /* AIF2RX_CHAN1_SLOTS - [8:6] */ +#define WM8915_AIF2RX_CHAN1_START_SLOT_MASK 0x003F /* AIF2RX_CHAN1_START_SLOT - [5:0] */ +#define WM8915_AIF2RX_CHAN1_START_SLOT_SHIFT 0 /* AIF2RX_CHAN1_START_SLOT - [5:0] */ +#define WM8915_AIF2RX_CHAN1_START_SLOT_WIDTH 6 /* AIF2RX_CHAN1_START_SLOT - [5:0] */ + +/* + * R813 (0x32D) - AIF2RX Mono Configuration + */ +#define WM8915_AIF2RX_CHAN0_MONO_MODE 0x0001 /* AIF2RX_CHAN0_MONO_MODE */ +#define WM8915_AIF2RX_CHAN0_MONO_MODE_MASK 0x0001 /* AIF2RX_CHAN0_MONO_MODE */ +#define WM8915_AIF2RX_CHAN0_MONO_MODE_SHIFT 0 /* AIF2RX_CHAN0_MONO_MODE */ +#define WM8915_AIF2RX_CHAN0_MONO_MODE_WIDTH 1 /* AIF2RX_CHAN0_MONO_MODE */ + +/* + * R815 (0x32F) - AIF2TX Test + */ +#define WM8915_AIF2TX_DITHER_ENA 0x0001 /* AIF2TX_DITHER_ENA */ +#define WM8915_AIF2TX_DITHER_ENA_MASK 0x0001 /* AIF2TX_DITHER_ENA */ +#define WM8915_AIF2TX_DITHER_ENA_SHIFT 0 /* AIF2TX_DITHER_ENA */ +#define WM8915_AIF2TX_DITHER_ENA_WIDTH 1 /* AIF2TX_DITHER_ENA */ + +/* + * R1024 (0x400) - DSP1 TX Left Volume + */ +#define WM8915_DSP1TX_VU 0x0100 /* DSP1TX_VU */ +#define WM8915_DSP1TX_VU_MASK 0x0100 /* DSP1TX_VU */ +#define WM8915_DSP1TX_VU_SHIFT 8 /* DSP1TX_VU */ +#define WM8915_DSP1TX_VU_WIDTH 1 /* DSP1TX_VU */ +#define WM8915_DSP1TXL_VOL_MASK 0x00FF /* DSP1TXL_VOL - [7:0] */ +#define WM8915_DSP1TXL_VOL_SHIFT 0 /* DSP1TXL_VOL - [7:0] */ +#define WM8915_DSP1TXL_VOL_WIDTH 8 /* DSP1TXL_VOL - [7:0] */ + +/* + * R1025 (0x401) - DSP1 TX Right Volume + */ +#define WM8915_DSP1TX_VU 0x0100 /* DSP1TX_VU */ +#define WM8915_DSP1TX_VU_MASK 0x0100 /* DSP1TX_VU */ +#define WM8915_DSP1TX_VU_SHIFT 8 /* DSP1TX_VU */ +#define WM8915_DSP1TX_VU_WIDTH 1 /* DSP1TX_VU */ +#define WM8915_DSP1TXR_VOL_MASK 0x00FF /* DSP1TXR_VOL - [7:0] */ +#define WM8915_DSP1TXR_VOL_SHIFT 0 /* DSP1TXR_VOL - [7:0] */ +#define WM8915_DSP1TXR_VOL_WIDTH 8 /* DSP1TXR_VOL - [7:0] */ + +/* + * R1026 (0x402) - DSP1 RX Left Volume + */ +#define WM8915_DSP1RX_VU 0x0100 /* DSP1RX_VU */ +#define WM8915_DSP1RX_VU_MASK 0x0100 /* DSP1RX_VU */ +#define WM8915_DSP1RX_VU_SHIFT 8 /* DSP1RX_VU */ +#define WM8915_DSP1RX_VU_WIDTH 1 /* DSP1RX_VU */ +#define WM8915_DSP1RXL_VOL_MASK 0x00FF /* DSP1RXL_VOL - [7:0] */ +#define WM8915_DSP1RXL_VOL_SHIFT 0 /* DSP1RXL_VOL - [7:0] */ +#define WM8915_DSP1RXL_VOL_WIDTH 8 /* DSP1RXL_VOL - [7:0] */ + +/* + * R1027 (0x403) - DSP1 RX Right Volume + */ +#define WM8915_DSP1RX_VU 0x0100 /* DSP1RX_VU */ +#define WM8915_DSP1RX_VU_MASK 0x0100 /* DSP1RX_VU */ +#define WM8915_DSP1RX_VU_SHIFT 8 /* DSP1RX_VU */ +#define WM8915_DSP1RX_VU_WIDTH 1 /* DSP1RX_VU */ +#define WM8915_DSP1RXR_VOL_MASK 0x00FF /* DSP1RXR_VOL - [7:0] */ +#define WM8915_DSP1RXR_VOL_SHIFT 0 /* DSP1RXR_VOL - [7:0] */ +#define WM8915_DSP1RXR_VOL_WIDTH 8 /* DSP1RXR_VOL - [7:0] */ + +/* + * R1040 (0x410) - DSP1 TX Filters + */ +#define WM8915_DSP1TX_NF 0x2000 /* DSP1TX_NF */ +#define WM8915_DSP1TX_NF_MASK 0x2000 /* DSP1TX_NF */ +#define WM8915_DSP1TX_NF_SHIFT 13 /* DSP1TX_NF */ +#define WM8915_DSP1TX_NF_WIDTH 1 /* DSP1TX_NF */ +#define WM8915_DSP1TXL_HPF 0x1000 /* DSP1TXL_HPF */ +#define WM8915_DSP1TXL_HPF_MASK 0x1000 /* DSP1TXL_HPF */ +#define WM8915_DSP1TXL_HPF_SHIFT 12 /* DSP1TXL_HPF */ +#define WM8915_DSP1TXL_HPF_WIDTH 1 /* DSP1TXL_HPF */ +#define WM8915_DSP1TXR_HPF 0x0800 /* DSP1TXR_HPF */ +#define WM8915_DSP1TXR_HPF_MASK 0x0800 /* DSP1TXR_HPF */ +#define WM8915_DSP1TXR_HPF_SHIFT 11 /* DSP1TXR_HPF */ +#define WM8915_DSP1TXR_HPF_WIDTH 1 /* DSP1TXR_HPF */ +#define WM8915_DSP1TX_HPF_MODE_MASK 0x0018 /* DSP1TX_HPF_MODE - [4:3] */ +#define WM8915_DSP1TX_HPF_MODE_SHIFT 3 /* DSP1TX_HPF_MODE - [4:3] */ +#define WM8915_DSP1TX_HPF_MODE_WIDTH 2 /* DSP1TX_HPF_MODE - [4:3] */ +#define WM8915_DSP1TX_HPF_CUT_MASK 0x0007 /* DSP1TX_HPF_CUT - [2:0] */ +#define WM8915_DSP1TX_HPF_CUT_SHIFT 0 /* DSP1TX_HPF_CUT - [2:0] */ +#define WM8915_DSP1TX_HPF_CUT_WIDTH 3 /* DSP1TX_HPF_CUT - [2:0] */ + +/* + * R1056 (0x420) - DSP1 RX Filters (1) + */ +#define WM8915_DSP1RX_MUTE 0x0200 /* DSP1RX_MUTE */ +#define WM8915_DSP1RX_MUTE_MASK 0x0200 /* DSP1RX_MUTE */ +#define WM8915_DSP1RX_MUTE_SHIFT 9 /* DSP1RX_MUTE */ +#define WM8915_DSP1RX_MUTE_WIDTH 1 /* DSP1RX_MUTE */ +#define WM8915_DSP1RX_MONO 0x0080 /* DSP1RX_MONO */ +#define WM8915_DSP1RX_MONO_MASK 0x0080 /* DSP1RX_MONO */ +#define WM8915_DSP1RX_MONO_SHIFT 7 /* DSP1RX_MONO */ +#define WM8915_DSP1RX_MONO_WIDTH 1 /* DSP1RX_MONO */ +#define WM8915_DSP1RX_MUTERATE 0x0020 /* DSP1RX_MUTERATE */ +#define WM8915_DSP1RX_MUTERATE_MASK 0x0020 /* DSP1RX_MUTERATE */ +#define WM8915_DSP1RX_MUTERATE_SHIFT 5 /* DSP1RX_MUTERATE */ +#define WM8915_DSP1RX_MUTERATE_WIDTH 1 /* DSP1RX_MUTERATE */ +#define WM8915_DSP1RX_UNMUTE_RAMP 0x0010 /* DSP1RX_UNMUTE_RAMP */ +#define WM8915_DSP1RX_UNMUTE_RAMP_MASK 0x0010 /* DSP1RX_UNMUTE_RAMP */ +#define WM8915_DSP1RX_UNMUTE_RAMP_SHIFT 4 /* DSP1RX_UNMUTE_RAMP */ +#define WM8915_DSP1RX_UNMUTE_RAMP_WIDTH 1 /* DSP1RX_UNMUTE_RAMP */ + +/* + * R1057 (0x421) - DSP1 RX Filters (2) + */ +#define WM8915_DSP1RX_3D_GAIN_MASK 0x3E00 /* DSP1RX_3D_GAIN - [13:9] */ +#define WM8915_DSP1RX_3D_GAIN_SHIFT 9 /* DSP1RX_3D_GAIN - [13:9] */ +#define WM8915_DSP1RX_3D_GAIN_WIDTH 5 /* DSP1RX_3D_GAIN - [13:9] */ +#define WM8915_DSP1RX_3D_ENA 0x0100 /* DSP1RX_3D_ENA */ +#define WM8915_DSP1RX_3D_ENA_MASK 0x0100 /* DSP1RX_3D_ENA */ +#define WM8915_DSP1RX_3D_ENA_SHIFT 8 /* DSP1RX_3D_ENA */ +#define WM8915_DSP1RX_3D_ENA_WIDTH 1 /* DSP1RX_3D_ENA */ + +/* + * R1088 (0x440) - DSP1 DRC (1) + */ +#define WM8915_DSP1DRC_SIG_DET_RMS_MASK 0xF800 /* DSP1DRC_SIG_DET_RMS - [15:11] */ +#define WM8915_DSP1DRC_SIG_DET_RMS_SHIFT 11 /* DSP1DRC_SIG_DET_RMS - [15:11] */ +#define WM8915_DSP1DRC_SIG_DET_RMS_WIDTH 5 /* DSP1DRC_SIG_DET_RMS - [15:11] */ +#define WM8915_DSP1DRC_SIG_DET_PK_MASK 0x0600 /* DSP1DRC_SIG_DET_PK - [10:9] */ +#define WM8915_DSP1DRC_SIG_DET_PK_SHIFT 9 /* DSP1DRC_SIG_DET_PK - [10:9] */ +#define WM8915_DSP1DRC_SIG_DET_PK_WIDTH 2 /* DSP1DRC_SIG_DET_PK - [10:9] */ +#define WM8915_DSP1DRC_NG_ENA 0x0100 /* DSP1DRC_NG_ENA */ +#define WM8915_DSP1DRC_NG_ENA_MASK 0x0100 /* DSP1DRC_NG_ENA */ +#define WM8915_DSP1DRC_NG_ENA_SHIFT 8 /* DSP1DRC_NG_ENA */ +#define WM8915_DSP1DRC_NG_ENA_WIDTH 1 /* DSP1DRC_NG_ENA */ +#define WM8915_DSP1DRC_SIG_DET_MODE 0x0080 /* DSP1DRC_SIG_DET_MODE */ +#define WM8915_DSP1DRC_SIG_DET_MODE_MASK 0x0080 /* DSP1DRC_SIG_DET_MODE */ +#define WM8915_DSP1DRC_SIG_DET_MODE_SHIFT 7 /* DSP1DRC_SIG_DET_MODE */ +#define WM8915_DSP1DRC_SIG_DET_MODE_WIDTH 1 /* DSP1DRC_SIG_DET_MODE */ +#define WM8915_DSP1DRC_SIG_DET 0x0040 /* DSP1DRC_SIG_DET */ +#define WM8915_DSP1DRC_SIG_DET_MASK 0x0040 /* DSP1DRC_SIG_DET */ +#define WM8915_DSP1DRC_SIG_DET_SHIFT 6 /* DSP1DRC_SIG_DET */ +#define WM8915_DSP1DRC_SIG_DET_WIDTH 1 /* DSP1DRC_SIG_DET */ +#define WM8915_DSP1DRC_KNEE2_OP_ENA 0x0020 /* DSP1DRC_KNEE2_OP_ENA */ +#define WM8915_DSP1DRC_KNEE2_OP_ENA_MASK 0x0020 /* DSP1DRC_KNEE2_OP_ENA */ +#define WM8915_DSP1DRC_KNEE2_OP_ENA_SHIFT 5 /* DSP1DRC_KNEE2_OP_ENA */ +#define WM8915_DSP1DRC_KNEE2_OP_ENA_WIDTH 1 /* DSP1DRC_KNEE2_OP_ENA */ +#define WM8915_DSP1DRC_QR 0x0010 /* DSP1DRC_QR */ +#define WM8915_DSP1DRC_QR_MASK 0x0010 /* DSP1DRC_QR */ +#define WM8915_DSP1DRC_QR_SHIFT 4 /* DSP1DRC_QR */ +#define WM8915_DSP1DRC_QR_WIDTH 1 /* DSP1DRC_QR */ +#define WM8915_DSP1DRC_ANTICLIP 0x0008 /* DSP1DRC_ANTICLIP */ +#define WM8915_DSP1DRC_ANTICLIP_MASK 0x0008 /* DSP1DRC_ANTICLIP */ +#define WM8915_DSP1DRC_ANTICLIP_SHIFT 3 /* DSP1DRC_ANTICLIP */ +#define WM8915_DSP1DRC_ANTICLIP_WIDTH 1 /* DSP1DRC_ANTICLIP */ +#define WM8915_DSP1RX_DRC_ENA 0x0004 /* DSP1RX_DRC_ENA */ +#define WM8915_DSP1RX_DRC_ENA_MASK 0x0004 /* DSP1RX_DRC_ENA */ +#define WM8915_DSP1RX_DRC_ENA_SHIFT 2 /* DSP1RX_DRC_ENA */ +#define WM8915_DSP1RX_DRC_ENA_WIDTH 1 /* DSP1RX_DRC_ENA */ +#define WM8915_DSP1TXL_DRC_ENA 0x0002 /* DSP1TXL_DRC_ENA */ +#define WM8915_DSP1TXL_DRC_ENA_MASK 0x0002 /* DSP1TXL_DRC_ENA */ +#define WM8915_DSP1TXL_DRC_ENA_SHIFT 1 /* DSP1TXL_DRC_ENA */ +#define WM8915_DSP1TXL_DRC_ENA_WIDTH 1 /* DSP1TXL_DRC_ENA */ +#define WM8915_DSP1TXR_DRC_ENA 0x0001 /* DSP1TXR_DRC_ENA */ +#define WM8915_DSP1TXR_DRC_ENA_MASK 0x0001 /* DSP1TXR_DRC_ENA */ +#define WM8915_DSP1TXR_DRC_ENA_SHIFT 0 /* DSP1TXR_DRC_ENA */ +#define WM8915_DSP1TXR_DRC_ENA_WIDTH 1 /* DSP1TXR_DRC_ENA */ + +/* + * R1089 (0x441) - DSP1 DRC (2) + */ +#define WM8915_DSP1DRC_ATK_MASK 0x1E00 /* DSP1DRC_ATK - [12:9] */ +#define WM8915_DSP1DRC_ATK_SHIFT 9 /* DSP1DRC_ATK - [12:9] */ +#define WM8915_DSP1DRC_ATK_WIDTH 4 /* DSP1DRC_ATK - [12:9] */ +#define WM8915_DSP1DRC_DCY_MASK 0x01E0 /* DSP1DRC_DCY - [8:5] */ +#define WM8915_DSP1DRC_DCY_SHIFT 5 /* DSP1DRC_DCY - [8:5] */ +#define WM8915_DSP1DRC_DCY_WIDTH 4 /* DSP1DRC_DCY - [8:5] */ +#define WM8915_DSP1DRC_MINGAIN_MASK 0x001C /* DSP1DRC_MINGAIN - [4:2] */ +#define WM8915_DSP1DRC_MINGAIN_SHIFT 2 /* DSP1DRC_MINGAIN - [4:2] */ +#define WM8915_DSP1DRC_MINGAIN_WIDTH 3 /* DSP1DRC_MINGAIN - [4:2] */ +#define WM8915_DSP1DRC_MAXGAIN_MASK 0x0003 /* DSP1DRC_MAXGAIN - [1:0] */ +#define WM8915_DSP1DRC_MAXGAIN_SHIFT 0 /* DSP1DRC_MAXGAIN - [1:0] */ +#define WM8915_DSP1DRC_MAXGAIN_WIDTH 2 /* DSP1DRC_MAXGAIN - [1:0] */ + +/* + * R1090 (0x442) - DSP1 DRC (3) + */ +#define WM8915_DSP1DRC_NG_MINGAIN_MASK 0xF000 /* DSP1DRC_NG_MINGAIN - [15:12] */ +#define WM8915_DSP1DRC_NG_MINGAIN_SHIFT 12 /* DSP1DRC_NG_MINGAIN - [15:12] */ +#define WM8915_DSP1DRC_NG_MINGAIN_WIDTH 4 /* DSP1DRC_NG_MINGAIN - [15:12] */ +#define WM8915_DSP1DRC_NG_EXP_MASK 0x0C00 /* DSP1DRC_NG_EXP - [11:10] */ +#define WM8915_DSP1DRC_NG_EXP_SHIFT 10 /* DSP1DRC_NG_EXP - [11:10] */ +#define WM8915_DSP1DRC_NG_EXP_WIDTH 2 /* DSP1DRC_NG_EXP - [11:10] */ +#define WM8915_DSP1DRC_QR_THR_MASK 0x0300 /* DSP1DRC_QR_THR - [9:8] */ +#define WM8915_DSP1DRC_QR_THR_SHIFT 8 /* DSP1DRC_QR_THR - [9:8] */ +#define WM8915_DSP1DRC_QR_THR_WIDTH 2 /* DSP1DRC_QR_THR - [9:8] */ +#define WM8915_DSP1DRC_QR_DCY_MASK 0x00C0 /* DSP1DRC_QR_DCY - [7:6] */ +#define WM8915_DSP1DRC_QR_DCY_SHIFT 6 /* DSP1DRC_QR_DCY - [7:6] */ +#define WM8915_DSP1DRC_QR_DCY_WIDTH 2 /* DSP1DRC_QR_DCY - [7:6] */ +#define WM8915_DSP1DRC_HI_COMP_MASK 0x0038 /* DSP1DRC_HI_COMP - [5:3] */ +#define WM8915_DSP1DRC_HI_COMP_SHIFT 3 /* DSP1DRC_HI_COMP - [5:3] */ +#define WM8915_DSP1DRC_HI_COMP_WIDTH 3 /* DSP1DRC_HI_COMP - [5:3] */ +#define WM8915_DSP1DRC_LO_COMP_MASK 0x0007 /* DSP1DRC_LO_COMP - [2:0] */ +#define WM8915_DSP1DRC_LO_COMP_SHIFT 0 /* DSP1DRC_LO_COMP - [2:0] */ +#define WM8915_DSP1DRC_LO_COMP_WIDTH 3 /* DSP1DRC_LO_COMP - [2:0] */ + +/* + * R1091 (0x443) - DSP1 DRC (4) + */ +#define WM8915_DSP1DRC_KNEE_IP_MASK 0x07E0 /* DSP1DRC_KNEE_IP - [10:5] */ +#define WM8915_DSP1DRC_KNEE_IP_SHIFT 5 /* DSP1DRC_KNEE_IP - [10:5] */ +#define WM8915_DSP1DRC_KNEE_IP_WIDTH 6 /* DSP1DRC_KNEE_IP - [10:5] */ +#define WM8915_DSP1DRC_KNEE_OP_MASK 0x001F /* DSP1DRC_KNEE_OP - [4:0] */ +#define WM8915_DSP1DRC_KNEE_OP_SHIFT 0 /* DSP1DRC_KNEE_OP - [4:0] */ +#define WM8915_DSP1DRC_KNEE_OP_WIDTH 5 /* DSP1DRC_KNEE_OP - [4:0] */ + +/* + * R1092 (0x444) - DSP1 DRC (5) + */ +#define WM8915_DSP1DRC_KNEE2_IP_MASK 0x03E0 /* DSP1DRC_KNEE2_IP - [9:5] */ +#define WM8915_DSP1DRC_KNEE2_IP_SHIFT 5 /* DSP1DRC_KNEE2_IP - [9:5] */ +#define WM8915_DSP1DRC_KNEE2_IP_WIDTH 5 /* DSP1DRC_KNEE2_IP - [9:5] */ +#define WM8915_DSP1DRC_KNEE2_OP_MASK 0x001F /* DSP1DRC_KNEE2_OP - [4:0] */ +#define WM8915_DSP1DRC_KNEE2_OP_SHIFT 0 /* DSP1DRC_KNEE2_OP - [4:0] */ +#define WM8915_DSP1DRC_KNEE2_OP_WIDTH 5 /* DSP1DRC_KNEE2_OP - [4:0] */ + +/* + * R1152 (0x480) - DSP1 RX EQ Gains (1) + */ +#define WM8915_DSP1RX_EQ_B1_GAIN_MASK 0xF800 /* DSP1RX_EQ_B1_GAIN - [15:11] */ +#define WM8915_DSP1RX_EQ_B1_GAIN_SHIFT 11 /* DSP1RX_EQ_B1_GAIN - [15:11] */ +#define WM8915_DSP1RX_EQ_B1_GAIN_WIDTH 5 /* DSP1RX_EQ_B1_GAIN - [15:11] */ +#define WM8915_DSP1RX_EQ_B2_GAIN_MASK 0x07C0 /* DSP1RX_EQ_B2_GAIN - [10:6] */ +#define WM8915_DSP1RX_EQ_B2_GAIN_SHIFT 6 /* DSP1RX_EQ_B2_GAIN - [10:6] */ +#define WM8915_DSP1RX_EQ_B2_GAIN_WIDTH 5 /* DSP1RX_EQ_B2_GAIN - [10:6] */ +#define WM8915_DSP1RX_EQ_B3_GAIN_MASK 0x003E /* DSP1RX_EQ_B3_GAIN - [5:1] */ +#define WM8915_DSP1RX_EQ_B3_GAIN_SHIFT 1 /* DSP1RX_EQ_B3_GAIN - [5:1] */ +#define WM8915_DSP1RX_EQ_B3_GAIN_WIDTH 5 /* DSP1RX_EQ_B3_GAIN - [5:1] */ +#define WM8915_DSP1RX_EQ_ENA 0x0001 /* DSP1RX_EQ_ENA */ +#define WM8915_DSP1RX_EQ_ENA_MASK 0x0001 /* DSP1RX_EQ_ENA */ +#define WM8915_DSP1RX_EQ_ENA_SHIFT 0 /* DSP1RX_EQ_ENA */ +#define WM8915_DSP1RX_EQ_ENA_WIDTH 1 /* DSP1RX_EQ_ENA */ + +/* + * R1153 (0x481) - DSP1 RX EQ Gains (2) + */ +#define WM8915_DSP1RX_EQ_B4_GAIN_MASK 0xF800 /* DSP1RX_EQ_B4_GAIN - [15:11] */ +#define WM8915_DSP1RX_EQ_B4_GAIN_SHIFT 11 /* DSP1RX_EQ_B4_GAIN - [15:11] */ +#define WM8915_DSP1RX_EQ_B4_GAIN_WIDTH 5 /* DSP1RX_EQ_B4_GAIN - [15:11] */ +#define WM8915_DSP1RX_EQ_B5_GAIN_MASK 0x07C0 /* DSP1RX_EQ_B5_GAIN - [10:6] */ +#define WM8915_DSP1RX_EQ_B5_GAIN_SHIFT 6 /* DSP1RX_EQ_B5_GAIN - [10:6] */ +#define WM8915_DSP1RX_EQ_B5_GAIN_WIDTH 5 /* DSP1RX_EQ_B5_GAIN - [10:6] */ + +/* + * R1154 (0x482) - DSP1 RX EQ Band 1 A + */ +#define WM8915_DSP1RX_EQ_B1_A_MASK 0xFFFF /* DSP1RX_EQ_B1_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B1_A_SHIFT 0 /* DSP1RX_EQ_B1_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B1_A_WIDTH 16 /* DSP1RX_EQ_B1_A - [15:0] */ + +/* + * R1155 (0x483) - DSP1 RX EQ Band 1 B + */ +#define WM8915_DSP1RX_EQ_B1_B_MASK 0xFFFF /* DSP1RX_EQ_B1_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B1_B_SHIFT 0 /* DSP1RX_EQ_B1_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B1_B_WIDTH 16 /* DSP1RX_EQ_B1_B - [15:0] */ + +/* + * R1156 (0x484) - DSP1 RX EQ Band 1 PG + */ +#define WM8915_DSP1RX_EQ_B1_PG_MASK 0xFFFF /* DSP1RX_EQ_B1_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B1_PG_SHIFT 0 /* DSP1RX_EQ_B1_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B1_PG_WIDTH 16 /* DSP1RX_EQ_B1_PG - [15:0] */ + +/* + * R1157 (0x485) - DSP1 RX EQ Band 2 A + */ +#define WM8915_DSP1RX_EQ_B2_A_MASK 0xFFFF /* DSP1RX_EQ_B2_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B2_A_SHIFT 0 /* DSP1RX_EQ_B2_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B2_A_WIDTH 16 /* DSP1RX_EQ_B2_A - [15:0] */ + +/* + * R1158 (0x486) - DSP1 RX EQ Band 2 B + */ +#define WM8915_DSP1RX_EQ_B2_B_MASK 0xFFFF /* DSP1RX_EQ_B2_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B2_B_SHIFT 0 /* DSP1RX_EQ_B2_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B2_B_WIDTH 16 /* DSP1RX_EQ_B2_B - [15:0] */ + +/* + * R1159 (0x487) - DSP1 RX EQ Band 2 C + */ +#define WM8915_DSP1RX_EQ_B2_C_MASK 0xFFFF /* DSP1RX_EQ_B2_C - [15:0] */ +#define WM8915_DSP1RX_EQ_B2_C_SHIFT 0 /* DSP1RX_EQ_B2_C - [15:0] */ +#define WM8915_DSP1RX_EQ_B2_C_WIDTH 16 /* DSP1RX_EQ_B2_C - [15:0] */ + +/* + * R1160 (0x488) - DSP1 RX EQ Band 2 PG + */ +#define WM8915_DSP1RX_EQ_B2_PG_MASK 0xFFFF /* DSP1RX_EQ_B2_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B2_PG_SHIFT 0 /* DSP1RX_EQ_B2_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B2_PG_WIDTH 16 /* DSP1RX_EQ_B2_PG - [15:0] */ + +/* + * R1161 (0x489) - DSP1 RX EQ Band 3 A + */ +#define WM8915_DSP1RX_EQ_B3_A_MASK 0xFFFF /* DSP1RX_EQ_B3_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B3_A_SHIFT 0 /* DSP1RX_EQ_B3_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B3_A_WIDTH 16 /* DSP1RX_EQ_B3_A - [15:0] */ + +/* + * R1162 (0x48A) - DSP1 RX EQ Band 3 B + */ +#define WM8915_DSP1RX_EQ_B3_B_MASK 0xFFFF /* DSP1RX_EQ_B3_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B3_B_SHIFT 0 /* DSP1RX_EQ_B3_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B3_B_WIDTH 16 /* DSP1RX_EQ_B3_B - [15:0] */ + +/* + * R1163 (0x48B) - DSP1 RX EQ Band 3 C + */ +#define WM8915_DSP1RX_EQ_B3_C_MASK 0xFFFF /* DSP1RX_EQ_B3_C - [15:0] */ +#define WM8915_DSP1RX_EQ_B3_C_SHIFT 0 /* DSP1RX_EQ_B3_C - [15:0] */ +#define WM8915_DSP1RX_EQ_B3_C_WIDTH 16 /* DSP1RX_EQ_B3_C - [15:0] */ + +/* + * R1164 (0x48C) - DSP1 RX EQ Band 3 PG + */ +#define WM8915_DSP1RX_EQ_B3_PG_MASK 0xFFFF /* DSP1RX_EQ_B3_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B3_PG_SHIFT 0 /* DSP1RX_EQ_B3_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B3_PG_WIDTH 16 /* DSP1RX_EQ_B3_PG - [15:0] */ + +/* + * R1165 (0x48D) - DSP1 RX EQ Band 4 A + */ +#define WM8915_DSP1RX_EQ_B4_A_MASK 0xFFFF /* DSP1RX_EQ_B4_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B4_A_SHIFT 0 /* DSP1RX_EQ_B4_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B4_A_WIDTH 16 /* DSP1RX_EQ_B4_A - [15:0] */ + +/* + * R1166 (0x48E) - DSP1 RX EQ Band 4 B + */ +#define WM8915_DSP1RX_EQ_B4_B_MASK 0xFFFF /* DSP1RX_EQ_B4_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B4_B_SHIFT 0 /* DSP1RX_EQ_B4_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B4_B_WIDTH 16 /* DSP1RX_EQ_B4_B - [15:0] */ + +/* + * R1167 (0x48F) - DSP1 RX EQ Band 4 C + */ +#define WM8915_DSP1RX_EQ_B4_C_MASK 0xFFFF /* DSP1RX_EQ_B4_C - [15:0] */ +#define WM8915_DSP1RX_EQ_B4_C_SHIFT 0 /* DSP1RX_EQ_B4_C - [15:0] */ +#define WM8915_DSP1RX_EQ_B4_C_WIDTH 16 /* DSP1RX_EQ_B4_C - [15:0] */ + +/* + * R1168 (0x490) - DSP1 RX EQ Band 4 PG + */ +#define WM8915_DSP1RX_EQ_B4_PG_MASK 0xFFFF /* DSP1RX_EQ_B4_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B4_PG_SHIFT 0 /* DSP1RX_EQ_B4_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B4_PG_WIDTH 16 /* DSP1RX_EQ_B4_PG - [15:0] */ + +/* + * R1169 (0x491) - DSP1 RX EQ Band 5 A + */ +#define WM8915_DSP1RX_EQ_B5_A_MASK 0xFFFF /* DSP1RX_EQ_B5_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B5_A_SHIFT 0 /* DSP1RX_EQ_B5_A - [15:0] */ +#define WM8915_DSP1RX_EQ_B5_A_WIDTH 16 /* DSP1RX_EQ_B5_A - [15:0] */ + +/* + * R1170 (0x492) - DSP1 RX EQ Band 5 B + */ +#define WM8915_DSP1RX_EQ_B5_B_MASK 0xFFFF /* DSP1RX_EQ_B5_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B5_B_SHIFT 0 /* DSP1RX_EQ_B5_B - [15:0] */ +#define WM8915_DSP1RX_EQ_B5_B_WIDTH 16 /* DSP1RX_EQ_B5_B - [15:0] */ + +/* + * R1171 (0x493) - DSP1 RX EQ Band 5 PG + */ +#define WM8915_DSP1RX_EQ_B5_PG_MASK 0xFFFF /* DSP1RX_EQ_B5_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B5_PG_SHIFT 0 /* DSP1RX_EQ_B5_PG - [15:0] */ +#define WM8915_DSP1RX_EQ_B5_PG_WIDTH 16 /* DSP1RX_EQ_B5_PG - [15:0] */ + +/* + * R1280 (0x500) - DSP2 TX Left Volume + */ +#define WM8915_DSP2TX_VU 0x0100 /* DSP2TX_VU */ +#define WM8915_DSP2TX_VU_MASK 0x0100 /* DSP2TX_VU */ +#define WM8915_DSP2TX_VU_SHIFT 8 /* DSP2TX_VU */ +#define WM8915_DSP2TX_VU_WIDTH 1 /* DSP2TX_VU */ +#define WM8915_DSP2TXL_VOL_MASK 0x00FF /* DSP2TXL_VOL - [7:0] */ +#define WM8915_DSP2TXL_VOL_SHIFT 0 /* DSP2TXL_VOL - [7:0] */ +#define WM8915_DSP2TXL_VOL_WIDTH 8 /* DSP2TXL_VOL - [7:0] */ + +/* + * R1281 (0x501) - DSP2 TX Right Volume + */ +#define WM8915_DSP2TX_VU 0x0100 /* DSP2TX_VU */ +#define WM8915_DSP2TX_VU_MASK 0x0100 /* DSP2TX_VU */ +#define WM8915_DSP2TX_VU_SHIFT 8 /* DSP2TX_VU */ +#define WM8915_DSP2TX_VU_WIDTH 1 /* DSP2TX_VU */ +#define WM8915_DSP2TXR_VOL_MASK 0x00FF /* DSP2TXR_VOL - [7:0] */ +#define WM8915_DSP2TXR_VOL_SHIFT 0 /* DSP2TXR_VOL - [7:0] */ +#define WM8915_DSP2TXR_VOL_WIDTH 8 /* DSP2TXR_VOL - [7:0] */ + +/* + * R1282 (0x502) - DSP2 RX Left Volume + */ +#define WM8915_DSP2RX_VU 0x0100 /* DSP2RX_VU */ +#define WM8915_DSP2RX_VU_MASK 0x0100 /* DSP2RX_VU */ +#define WM8915_DSP2RX_VU_SHIFT 8 /* DSP2RX_VU */ +#define WM8915_DSP2RX_VU_WIDTH 1 /* DSP2RX_VU */ +#define WM8915_DSP2RXL_VOL_MASK 0x00FF /* DSP2RXL_VOL - [7:0] */ +#define WM8915_DSP2RXL_VOL_SHIFT 0 /* DSP2RXL_VOL - [7:0] */ +#define WM8915_DSP2RXL_VOL_WIDTH 8 /* DSP2RXL_VOL - [7:0] */ + +/* + * R1283 (0x503) - DSP2 RX Right Volume + */ +#define WM8915_DSP2RX_VU 0x0100 /* DSP2RX_VU */ +#define WM8915_DSP2RX_VU_MASK 0x0100 /* DSP2RX_VU */ +#define WM8915_DSP2RX_VU_SHIFT 8 /* DSP2RX_VU */ +#define WM8915_DSP2RX_VU_WIDTH 1 /* DSP2RX_VU */ +#define WM8915_DSP2RXR_VOL_MASK 0x00FF /* DSP2RXR_VOL - [7:0] */ +#define WM8915_DSP2RXR_VOL_SHIFT 0 /* DSP2RXR_VOL - [7:0] */ +#define WM8915_DSP2RXR_VOL_WIDTH 8 /* DSP2RXR_VOL - [7:0] */ + +/* + * R1296 (0x510) - DSP2 TX Filters + */ +#define WM8915_DSP2TX_NF 0x2000 /* DSP2TX_NF */ +#define WM8915_DSP2TX_NF_MASK 0x2000 /* DSP2TX_NF */ +#define WM8915_DSP2TX_NF_SHIFT 13 /* DSP2TX_NF */ +#define WM8915_DSP2TX_NF_WIDTH 1 /* DSP2TX_NF */ +#define WM8915_DSP2TXL_HPF 0x1000 /* DSP2TXL_HPF */ +#define WM8915_DSP2TXL_HPF_MASK 0x1000 /* DSP2TXL_HPF */ +#define WM8915_DSP2TXL_HPF_SHIFT 12 /* DSP2TXL_HPF */ +#define WM8915_DSP2TXL_HPF_WIDTH 1 /* DSP2TXL_HPF */ +#define WM8915_DSP2TXR_HPF 0x0800 /* DSP2TXR_HPF */ +#define WM8915_DSP2TXR_HPF_MASK 0x0800 /* DSP2TXR_HPF */ +#define WM8915_DSP2TXR_HPF_SHIFT 11 /* DSP2TXR_HPF */ +#define WM8915_DSP2TXR_HPF_WIDTH 1 /* DSP2TXR_HPF */ +#define WM8915_DSP2TX_HPF_MODE_MASK 0x0018 /* DSP2TX_HPF_MODE - [4:3] */ +#define WM8915_DSP2TX_HPF_MODE_SHIFT 3 /* DSP2TX_HPF_MODE - [4:3] */ +#define WM8915_DSP2TX_HPF_MODE_WIDTH 2 /* DSP2TX_HPF_MODE - [4:3] */ +#define WM8915_DSP2TX_HPF_CUT_MASK 0x0007 /* DSP2TX_HPF_CUT - [2:0] */ +#define WM8915_DSP2TX_HPF_CUT_SHIFT 0 /* DSP2TX_HPF_CUT - [2:0] */ +#define WM8915_DSP2TX_HPF_CUT_WIDTH 3 /* DSP2TX_HPF_CUT - [2:0] */ + +/* + * R1312 (0x520) - DSP2 RX Filters (1) + */ +#define WM8915_DSP2RX_MUTE 0x0200 /* DSP2RX_MUTE */ +#define WM8915_DSP2RX_MUTE_MASK 0x0200 /* DSP2RX_MUTE */ +#define WM8915_DSP2RX_MUTE_SHIFT 9 /* DSP2RX_MUTE */ +#define WM8915_DSP2RX_MUTE_WIDTH 1 /* DSP2RX_MUTE */ +#define WM8915_DSP2RX_MONO 0x0080 /* DSP2RX_MONO */ +#define WM8915_DSP2RX_MONO_MASK 0x0080 /* DSP2RX_MONO */ +#define WM8915_DSP2RX_MONO_SHIFT 7 /* DSP2RX_MONO */ +#define WM8915_DSP2RX_MONO_WIDTH 1 /* DSP2RX_MONO */ +#define WM8915_DSP2RX_MUTERATE 0x0020 /* DSP2RX_MUTERATE */ +#define WM8915_DSP2RX_MUTERATE_MASK 0x0020 /* DSP2RX_MUTERATE */ +#define WM8915_DSP2RX_MUTERATE_SHIFT 5 /* DSP2RX_MUTERATE */ +#define WM8915_DSP2RX_MUTERATE_WIDTH 1 /* DSP2RX_MUTERATE */ +#define WM8915_DSP2RX_UNMUTE_RAMP 0x0010 /* DSP2RX_UNMUTE_RAMP */ +#define WM8915_DSP2RX_UNMUTE_RAMP_MASK 0x0010 /* DSP2RX_UNMUTE_RAMP */ +#define WM8915_DSP2RX_UNMUTE_RAMP_SHIFT 4 /* DSP2RX_UNMUTE_RAMP */ +#define WM8915_DSP2RX_UNMUTE_RAMP_WIDTH 1 /* DSP2RX_UNMUTE_RAMP */ + +/* + * R1313 (0x521) - DSP2 RX Filters (2) + */ +#define WM8915_DSP2RX_3D_GAIN_MASK 0x3E00 /* DSP2RX_3D_GAIN - [13:9] */ +#define WM8915_DSP2RX_3D_GAIN_SHIFT 9 /* DSP2RX_3D_GAIN - [13:9] */ +#define WM8915_DSP2RX_3D_GAIN_WIDTH 5 /* DSP2RX_3D_GAIN - [13:9] */ +#define WM8915_DSP2RX_3D_ENA 0x0100 /* DSP2RX_3D_ENA */ +#define WM8915_DSP2RX_3D_ENA_MASK 0x0100 /* DSP2RX_3D_ENA */ +#define WM8915_DSP2RX_3D_ENA_SHIFT 8 /* DSP2RX_3D_ENA */ +#define WM8915_DSP2RX_3D_ENA_WIDTH 1 /* DSP2RX_3D_ENA */ + +/* + * R1344 (0x540) - DSP2 DRC (1) + */ +#define WM8915_DSP2DRC_SIG_DET_RMS_MASK 0xF800 /* DSP2DRC_SIG_DET_RMS - [15:11] */ +#define WM8915_DSP2DRC_SIG_DET_RMS_SHIFT 11 /* DSP2DRC_SIG_DET_RMS - [15:11] */ +#define WM8915_DSP2DRC_SIG_DET_RMS_WIDTH 5 /* DSP2DRC_SIG_DET_RMS - [15:11] */ +#define WM8915_DSP2DRC_SIG_DET_PK_MASK 0x0600 /* DSP2DRC_SIG_DET_PK - [10:9] */ +#define WM8915_DSP2DRC_SIG_DET_PK_SHIFT 9 /* DSP2DRC_SIG_DET_PK - [10:9] */ +#define WM8915_DSP2DRC_SIG_DET_PK_WIDTH 2 /* DSP2DRC_SIG_DET_PK - [10:9] */ +#define WM8915_DSP2DRC_NG_ENA 0x0100 /* DSP2DRC_NG_ENA */ +#define WM8915_DSP2DRC_NG_ENA_MASK 0x0100 /* DSP2DRC_NG_ENA */ +#define WM8915_DSP2DRC_NG_ENA_SHIFT 8 /* DSP2DRC_NG_ENA */ +#define WM8915_DSP2DRC_NG_ENA_WIDTH 1 /* DSP2DRC_NG_ENA */ +#define WM8915_DSP2DRC_SIG_DET_MODE 0x0080 /* DSP2DRC_SIG_DET_MODE */ +#define WM8915_DSP2DRC_SIG_DET_MODE_MASK 0x0080 /* DSP2DRC_SIG_DET_MODE */ +#define WM8915_DSP2DRC_SIG_DET_MODE_SHIFT 7 /* DSP2DRC_SIG_DET_MODE */ +#define WM8915_DSP2DRC_SIG_DET_MODE_WIDTH 1 /* DSP2DRC_SIG_DET_MODE */ +#define WM8915_DSP2DRC_SIG_DET 0x0040 /* DSP2DRC_SIG_DET */ +#define WM8915_DSP2DRC_SIG_DET_MASK 0x0040 /* DSP2DRC_SIG_DET */ +#define WM8915_DSP2DRC_SIG_DET_SHIFT 6 /* DSP2DRC_SIG_DET */ +#define WM8915_DSP2DRC_SIG_DET_WIDTH 1 /* DSP2DRC_SIG_DET */ +#define WM8915_DSP2DRC_KNEE2_OP_ENA 0x0020 /* DSP2DRC_KNEE2_OP_ENA */ +#define WM8915_DSP2DRC_KNEE2_OP_ENA_MASK 0x0020 /* DSP2DRC_KNEE2_OP_ENA */ +#define WM8915_DSP2DRC_KNEE2_OP_ENA_SHIFT 5 /* DSP2DRC_KNEE2_OP_ENA */ +#define WM8915_DSP2DRC_KNEE2_OP_ENA_WIDTH 1 /* DSP2DRC_KNEE2_OP_ENA */ +#define WM8915_DSP2DRC_QR 0x0010 /* DSP2DRC_QR */ +#define WM8915_DSP2DRC_QR_MASK 0x0010 /* DSP2DRC_QR */ +#define WM8915_DSP2DRC_QR_SHIFT 4 /* DSP2DRC_QR */ +#define WM8915_DSP2DRC_QR_WIDTH 1 /* DSP2DRC_QR */ +#define WM8915_DSP2DRC_ANTICLIP 0x0008 /* DSP2DRC_ANTICLIP */ +#define WM8915_DSP2DRC_ANTICLIP_MASK 0x0008 /* DSP2DRC_ANTICLIP */ +#define WM8915_DSP2DRC_ANTICLIP_SHIFT 3 /* DSP2DRC_ANTICLIP */ +#define WM8915_DSP2DRC_ANTICLIP_WIDTH 1 /* DSP2DRC_ANTICLIP */ +#define WM8915_DSP2RX_DRC_ENA 0x0004 /* DSP2RX_DRC_ENA */ +#define WM8915_DSP2RX_DRC_ENA_MASK 0x0004 /* DSP2RX_DRC_ENA */ +#define WM8915_DSP2RX_DRC_ENA_SHIFT 2 /* DSP2RX_DRC_ENA */ +#define WM8915_DSP2RX_DRC_ENA_WIDTH 1 /* DSP2RX_DRC_ENA */ +#define WM8915_DSP2TXL_DRC_ENA 0x0002 /* DSP2TXL_DRC_ENA */ +#define WM8915_DSP2TXL_DRC_ENA_MASK 0x0002 /* DSP2TXL_DRC_ENA */ +#define WM8915_DSP2TXL_DRC_ENA_SHIFT 1 /* DSP2TXL_DRC_ENA */ +#define WM8915_DSP2TXL_DRC_ENA_WIDTH 1 /* DSP2TXL_DRC_ENA */ +#define WM8915_DSP2TXR_DRC_ENA 0x0001 /* DSP2TXR_DRC_ENA */ +#define WM8915_DSP2TXR_DRC_ENA_MASK 0x0001 /* DSP2TXR_DRC_ENA */ +#define WM8915_DSP2TXR_DRC_ENA_SHIFT 0 /* DSP2TXR_DRC_ENA */ +#define WM8915_DSP2TXR_DRC_ENA_WIDTH 1 /* DSP2TXR_DRC_ENA */ + +/* + * R1345 (0x541) - DSP2 DRC (2) + */ +#define WM8915_DSP2DRC_ATK_MASK 0x1E00 /* DSP2DRC_ATK - [12:9] */ +#define WM8915_DSP2DRC_ATK_SHIFT 9 /* DSP2DRC_ATK - [12:9] */ +#define WM8915_DSP2DRC_ATK_WIDTH 4 /* DSP2DRC_ATK - [12:9] */ +#define WM8915_DSP2DRC_DCY_MASK 0x01E0 /* DSP2DRC_DCY - [8:5] */ +#define WM8915_DSP2DRC_DCY_SHIFT 5 /* DSP2DRC_DCY - [8:5] */ +#define WM8915_DSP2DRC_DCY_WIDTH 4 /* DSP2DRC_DCY - [8:5] */ +#define WM8915_DSP2DRC_MINGAIN_MASK 0x001C /* DSP2DRC_MINGAIN - [4:2] */ +#define WM8915_DSP2DRC_MINGAIN_SHIFT 2 /* DSP2DRC_MINGAIN - [4:2] */ +#define WM8915_DSP2DRC_MINGAIN_WIDTH 3 /* DSP2DRC_MINGAIN - [4:2] */ +#define WM8915_DSP2DRC_MAXGAIN_MASK 0x0003 /* DSP2DRC_MAXGAIN - [1:0] */ +#define WM8915_DSP2DRC_MAXGAIN_SHIFT 0 /* DSP2DRC_MAXGAIN - [1:0] */ +#define WM8915_DSP2DRC_MAXGAIN_WIDTH 2 /* DSP2DRC_MAXGAIN - [1:0] */ + +/* + * R1346 (0x542) - DSP2 DRC (3) + */ +#define WM8915_DSP2DRC_NG_MINGAIN_MASK 0xF000 /* DSP2DRC_NG_MINGAIN - [15:12] */ +#define WM8915_DSP2DRC_NG_MINGAIN_SHIFT 12 /* DSP2DRC_NG_MINGAIN - [15:12] */ +#define WM8915_DSP2DRC_NG_MINGAIN_WIDTH 4 /* DSP2DRC_NG_MINGAIN - [15:12] */ +#define WM8915_DSP2DRC_NG_EXP_MASK 0x0C00 /* DSP2DRC_NG_EXP - [11:10] */ +#define WM8915_DSP2DRC_NG_EXP_SHIFT 10 /* DSP2DRC_NG_EXP - [11:10] */ +#define WM8915_DSP2DRC_NG_EXP_WIDTH 2 /* DSP2DRC_NG_EXP - [11:10] */ +#define WM8915_DSP2DRC_QR_THR_MASK 0x0300 /* DSP2DRC_QR_THR - [9:8] */ +#define WM8915_DSP2DRC_QR_THR_SHIFT 8 /* DSP2DRC_QR_THR - [9:8] */ +#define WM8915_DSP2DRC_QR_THR_WIDTH 2 /* DSP2DRC_QR_THR - [9:8] */ +#define WM8915_DSP2DRC_QR_DCY_MASK 0x00C0 /* DSP2DRC_QR_DCY - [7:6] */ +#define WM8915_DSP2DRC_QR_DCY_SHIFT 6 /* DSP2DRC_QR_DCY - [7:6] */ +#define WM8915_DSP2DRC_QR_DCY_WIDTH 2 /* DSP2DRC_QR_DCY - [7:6] */ +#define WM8915_DSP2DRC_HI_COMP_MASK 0x0038 /* DSP2DRC_HI_COMP - [5:3] */ +#define WM8915_DSP2DRC_HI_COMP_SHIFT 3 /* DSP2DRC_HI_COMP - [5:3] */ +#define WM8915_DSP2DRC_HI_COMP_WIDTH 3 /* DSP2DRC_HI_COMP - [5:3] */ +#define WM8915_DSP2DRC_LO_COMP_MASK 0x0007 /* DSP2DRC_LO_COMP - [2:0] */ +#define WM8915_DSP2DRC_LO_COMP_SHIFT 0 /* DSP2DRC_LO_COMP - [2:0] */ +#define WM8915_DSP2DRC_LO_COMP_WIDTH 3 /* DSP2DRC_LO_COMP - [2:0] */ + +/* + * R1347 (0x543) - DSP2 DRC (4) + */ +#define WM8915_DSP2DRC_KNEE_IP_MASK 0x07E0 /* DSP2DRC_KNEE_IP - [10:5] */ +#define WM8915_DSP2DRC_KNEE_IP_SHIFT 5 /* DSP2DRC_KNEE_IP - [10:5] */ +#define WM8915_DSP2DRC_KNEE_IP_WIDTH 6 /* DSP2DRC_KNEE_IP - [10:5] */ +#define WM8915_DSP2DRC_KNEE_OP_MASK 0x001F /* DSP2DRC_KNEE_OP - [4:0] */ +#define WM8915_DSP2DRC_KNEE_OP_SHIFT 0 /* DSP2DRC_KNEE_OP - [4:0] */ +#define WM8915_DSP2DRC_KNEE_OP_WIDTH 5 /* DSP2DRC_KNEE_OP - [4:0] */ + +/* + * R1348 (0x544) - DSP2 DRC (5) + */ +#define WM8915_DSP2DRC_KNEE2_IP_MASK 0x03E0 /* DSP2DRC_KNEE2_IP - [9:5] */ +#define WM8915_DSP2DRC_KNEE2_IP_SHIFT 5 /* DSP2DRC_KNEE2_IP - [9:5] */ +#define WM8915_DSP2DRC_KNEE2_IP_WIDTH 5 /* DSP2DRC_KNEE2_IP - [9:5] */ +#define WM8915_DSP2DRC_KNEE2_OP_MASK 0x001F /* DSP2DRC_KNEE2_OP - [4:0] */ +#define WM8915_DSP2DRC_KNEE2_OP_SHIFT 0 /* DSP2DRC_KNEE2_OP - [4:0] */ +#define WM8915_DSP2DRC_KNEE2_OP_WIDTH 5 /* DSP2DRC_KNEE2_OP - [4:0] */ + +/* + * R1408 (0x580) - DSP2 RX EQ Gains (1) + */ +#define WM8915_DSP2RX_EQ_B1_GAIN_MASK 0xF800 /* DSP2RX_EQ_B1_GAIN - [15:11] */ +#define WM8915_DSP2RX_EQ_B1_GAIN_SHIFT 11 /* DSP2RX_EQ_B1_GAIN - [15:11] */ +#define WM8915_DSP2RX_EQ_B1_GAIN_WIDTH 5 /* DSP2RX_EQ_B1_GAIN - [15:11] */ +#define WM8915_DSP2RX_EQ_B2_GAIN_MASK 0x07C0 /* DSP2RX_EQ_B2_GAIN - [10:6] */ +#define WM8915_DSP2RX_EQ_B2_GAIN_SHIFT 6 /* DSP2RX_EQ_B2_GAIN - [10:6] */ +#define WM8915_DSP2RX_EQ_B2_GAIN_WIDTH 5 /* DSP2RX_EQ_B2_GAIN - [10:6] */ +#define WM8915_DSP2RX_EQ_B3_GAIN_MASK 0x003E /* DSP2RX_EQ_B3_GAIN - [5:1] */ +#define WM8915_DSP2RX_EQ_B3_GAIN_SHIFT 1 /* DSP2RX_EQ_B3_GAIN - [5:1] */ +#define WM8915_DSP2RX_EQ_B3_GAIN_WIDTH 5 /* DSP2RX_EQ_B3_GAIN - [5:1] */ +#define WM8915_DSP2RX_EQ_ENA 0x0001 /* DSP2RX_EQ_ENA */ +#define WM8915_DSP2RX_EQ_ENA_MASK 0x0001 /* DSP2RX_EQ_ENA */ +#define WM8915_DSP2RX_EQ_ENA_SHIFT 0 /* DSP2RX_EQ_ENA */ +#define WM8915_DSP2RX_EQ_ENA_WIDTH 1 /* DSP2RX_EQ_ENA */ + +/* + * R1409 (0x581) - DSP2 RX EQ Gains (2) + */ +#define WM8915_DSP2RX_EQ_B4_GAIN_MASK 0xF800 /* DSP2RX_EQ_B4_GAIN - [15:11] */ +#define WM8915_DSP2RX_EQ_B4_GAIN_SHIFT 11 /* DSP2RX_EQ_B4_GAIN - [15:11] */ +#define WM8915_DSP2RX_EQ_B4_GAIN_WIDTH 5 /* DSP2RX_EQ_B4_GAIN - [15:11] */ +#define WM8915_DSP2RX_EQ_B5_GAIN_MASK 0x07C0 /* DSP2RX_EQ_B5_GAIN - [10:6] */ +#define WM8915_DSP2RX_EQ_B5_GAIN_SHIFT 6 /* DSP2RX_EQ_B5_GAIN - [10:6] */ +#define WM8915_DSP2RX_EQ_B5_GAIN_WIDTH 5 /* DSP2RX_EQ_B5_GAIN - [10:6] */ + +/* + * R1410 (0x582) - DSP2 RX EQ Band 1 A + */ +#define WM8915_DSP2RX_EQ_B1_A_MASK 0xFFFF /* DSP2RX_EQ_B1_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B1_A_SHIFT 0 /* DSP2RX_EQ_B1_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B1_A_WIDTH 16 /* DSP2RX_EQ_B1_A - [15:0] */ + +/* + * R1411 (0x583) - DSP2 RX EQ Band 1 B + */ +#define WM8915_DSP2RX_EQ_B1_B_MASK 0xFFFF /* DSP2RX_EQ_B1_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B1_B_SHIFT 0 /* DSP2RX_EQ_B1_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B1_B_WIDTH 16 /* DSP2RX_EQ_B1_B - [15:0] */ + +/* + * R1412 (0x584) - DSP2 RX EQ Band 1 PG + */ +#define WM8915_DSP2RX_EQ_B1_PG_MASK 0xFFFF /* DSP2RX_EQ_B1_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B1_PG_SHIFT 0 /* DSP2RX_EQ_B1_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B1_PG_WIDTH 16 /* DSP2RX_EQ_B1_PG - [15:0] */ + +/* + * R1413 (0x585) - DSP2 RX EQ Band 2 A + */ +#define WM8915_DSP2RX_EQ_B2_A_MASK 0xFFFF /* DSP2RX_EQ_B2_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B2_A_SHIFT 0 /* DSP2RX_EQ_B2_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B2_A_WIDTH 16 /* DSP2RX_EQ_B2_A - [15:0] */ + +/* + * R1414 (0x586) - DSP2 RX EQ Band 2 B + */ +#define WM8915_DSP2RX_EQ_B2_B_MASK 0xFFFF /* DSP2RX_EQ_B2_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B2_B_SHIFT 0 /* DSP2RX_EQ_B2_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B2_B_WIDTH 16 /* DSP2RX_EQ_B2_B - [15:0] */ + +/* + * R1415 (0x587) - DSP2 RX EQ Band 2 C + */ +#define WM8915_DSP2RX_EQ_B2_C_MASK 0xFFFF /* DSP2RX_EQ_B2_C - [15:0] */ +#define WM8915_DSP2RX_EQ_B2_C_SHIFT 0 /* DSP2RX_EQ_B2_C - [15:0] */ +#define WM8915_DSP2RX_EQ_B2_C_WIDTH 16 /* DSP2RX_EQ_B2_C - [15:0] */ + +/* + * R1416 (0x588) - DSP2 RX EQ Band 2 PG + */ +#define WM8915_DSP2RX_EQ_B2_PG_MASK 0xFFFF /* DSP2RX_EQ_B2_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B2_PG_SHIFT 0 /* DSP2RX_EQ_B2_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B2_PG_WIDTH 16 /* DSP2RX_EQ_B2_PG - [15:0] */ + +/* + * R1417 (0x589) - DSP2 RX EQ Band 3 A + */ +#define WM8915_DSP2RX_EQ_B3_A_MASK 0xFFFF /* DSP2RX_EQ_B3_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B3_A_SHIFT 0 /* DSP2RX_EQ_B3_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B3_A_WIDTH 16 /* DSP2RX_EQ_B3_A - [15:0] */ + +/* + * R1418 (0x58A) - DSP2 RX EQ Band 3 B + */ +#define WM8915_DSP2RX_EQ_B3_B_MASK 0xFFFF /* DSP2RX_EQ_B3_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B3_B_SHIFT 0 /* DSP2RX_EQ_B3_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B3_B_WIDTH 16 /* DSP2RX_EQ_B3_B - [15:0] */ + +/* + * R1419 (0x58B) - DSP2 RX EQ Band 3 C + */ +#define WM8915_DSP2RX_EQ_B3_C_MASK 0xFFFF /* DSP2RX_EQ_B3_C - [15:0] */ +#define WM8915_DSP2RX_EQ_B3_C_SHIFT 0 /* DSP2RX_EQ_B3_C - [15:0] */ +#define WM8915_DSP2RX_EQ_B3_C_WIDTH 16 /* DSP2RX_EQ_B3_C - [15:0] */ + +/* + * R1420 (0x58C) - DSP2 RX EQ Band 3 PG + */ +#define WM8915_DSP2RX_EQ_B3_PG_MASK 0xFFFF /* DSP2RX_EQ_B3_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B3_PG_SHIFT 0 /* DSP2RX_EQ_B3_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B3_PG_WIDTH 16 /* DSP2RX_EQ_B3_PG - [15:0] */ + +/* + * R1421 (0x58D) - DSP2 RX EQ Band 4 A + */ +#define WM8915_DSP2RX_EQ_B4_A_MASK 0xFFFF /* DSP2RX_EQ_B4_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B4_A_SHIFT 0 /* DSP2RX_EQ_B4_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B4_A_WIDTH 16 /* DSP2RX_EQ_B4_A - [15:0] */ + +/* + * R1422 (0x58E) - DSP2 RX EQ Band 4 B + */ +#define WM8915_DSP2RX_EQ_B4_B_MASK 0xFFFF /* DSP2RX_EQ_B4_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B4_B_SHIFT 0 /* DSP2RX_EQ_B4_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B4_B_WIDTH 16 /* DSP2RX_EQ_B4_B - [15:0] */ + +/* + * R1423 (0x58F) - DSP2 RX EQ Band 4 C + */ +#define WM8915_DSP2RX_EQ_B4_C_MASK 0xFFFF /* DSP2RX_EQ_B4_C - [15:0] */ +#define WM8915_DSP2RX_EQ_B4_C_SHIFT 0 /* DSP2RX_EQ_B4_C - [15:0] */ +#define WM8915_DSP2RX_EQ_B4_C_WIDTH 16 /* DSP2RX_EQ_B4_C - [15:0] */ + +/* + * R1424 (0x590) - DSP2 RX EQ Band 4 PG + */ +#define WM8915_DSP2RX_EQ_B4_PG_MASK 0xFFFF /* DSP2RX_EQ_B4_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B4_PG_SHIFT 0 /* DSP2RX_EQ_B4_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B4_PG_WIDTH 16 /* DSP2RX_EQ_B4_PG - [15:0] */ + +/* + * R1425 (0x591) - DSP2 RX EQ Band 5 A + */ +#define WM8915_DSP2RX_EQ_B5_A_MASK 0xFFFF /* DSP2RX_EQ_B5_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B5_A_SHIFT 0 /* DSP2RX_EQ_B5_A - [15:0] */ +#define WM8915_DSP2RX_EQ_B5_A_WIDTH 16 /* DSP2RX_EQ_B5_A - [15:0] */ + +/* + * R1426 (0x592) - DSP2 RX EQ Band 5 B + */ +#define WM8915_DSP2RX_EQ_B5_B_MASK 0xFFFF /* DSP2RX_EQ_B5_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B5_B_SHIFT 0 /* DSP2RX_EQ_B5_B - [15:0] */ +#define WM8915_DSP2RX_EQ_B5_B_WIDTH 16 /* DSP2RX_EQ_B5_B - [15:0] */ + +/* + * R1427 (0x593) - DSP2 RX EQ Band 5 PG + */ +#define WM8915_DSP2RX_EQ_B5_PG_MASK 0xFFFF /* DSP2RX_EQ_B5_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B5_PG_SHIFT 0 /* DSP2RX_EQ_B5_PG - [15:0] */ +#define WM8915_DSP2RX_EQ_B5_PG_WIDTH 16 /* DSP2RX_EQ_B5_PG - [15:0] */ + +/* + * R1536 (0x600) - DAC1 Mixer Volumes + */ +#define WM8915_ADCR_DAC1_VOL_MASK 0x03E0 /* ADCR_DAC1_VOL - [9:5] */ +#define WM8915_ADCR_DAC1_VOL_SHIFT 5 /* ADCR_DAC1_VOL - [9:5] */ +#define WM8915_ADCR_DAC1_VOL_WIDTH 5 /* ADCR_DAC1_VOL - [9:5] */ +#define WM8915_ADCL_DAC1_VOL_MASK 0x001F /* ADCL_DAC1_VOL - [4:0] */ +#define WM8915_ADCL_DAC1_VOL_SHIFT 0 /* ADCL_DAC1_VOL - [4:0] */ +#define WM8915_ADCL_DAC1_VOL_WIDTH 5 /* ADCL_DAC1_VOL - [4:0] */ + +/* + * R1537 (0x601) - DAC1 Left Mixer Routing + */ +#define WM8915_ADCR_TO_DAC1L 0x0020 /* ADCR_TO_DAC1L */ +#define WM8915_ADCR_TO_DAC1L_MASK 0x0020 /* ADCR_TO_DAC1L */ +#define WM8915_ADCR_TO_DAC1L_SHIFT 5 /* ADCR_TO_DAC1L */ +#define WM8915_ADCR_TO_DAC1L_WIDTH 1 /* ADCR_TO_DAC1L */ +#define WM8915_ADCL_TO_DAC1L 0x0010 /* ADCL_TO_DAC1L */ +#define WM8915_ADCL_TO_DAC1L_MASK 0x0010 /* ADCL_TO_DAC1L */ +#define WM8915_ADCL_TO_DAC1L_SHIFT 4 /* ADCL_TO_DAC1L */ +#define WM8915_ADCL_TO_DAC1L_WIDTH 1 /* ADCL_TO_DAC1L */ +#define WM8915_DSP2RXL_TO_DAC1L 0x0002 /* DSP2RXL_TO_DAC1L */ +#define WM8915_DSP2RXL_TO_DAC1L_MASK 0x0002 /* DSP2RXL_TO_DAC1L */ +#define WM8915_DSP2RXL_TO_DAC1L_SHIFT 1 /* DSP2RXL_TO_DAC1L */ +#define WM8915_DSP2RXL_TO_DAC1L_WIDTH 1 /* DSP2RXL_TO_DAC1L */ +#define WM8915_DSP1RXL_TO_DAC1L 0x0001 /* DSP1RXL_TO_DAC1L */ +#define WM8915_DSP1RXL_TO_DAC1L_MASK 0x0001 /* DSP1RXL_TO_DAC1L */ +#define WM8915_DSP1RXL_TO_DAC1L_SHIFT 0 /* DSP1RXL_TO_DAC1L */ +#define WM8915_DSP1RXL_TO_DAC1L_WIDTH 1 /* DSP1RXL_TO_DAC1L */ + +/* + * R1538 (0x602) - DAC1 Right Mixer Routing + */ +#define WM8915_ADCR_TO_DAC1R 0x0020 /* ADCR_TO_DAC1R */ +#define WM8915_ADCR_TO_DAC1R_MASK 0x0020 /* ADCR_TO_DAC1R */ +#define WM8915_ADCR_TO_DAC1R_SHIFT 5 /* ADCR_TO_DAC1R */ +#define WM8915_ADCR_TO_DAC1R_WIDTH 1 /* ADCR_TO_DAC1R */ +#define WM8915_ADCL_TO_DAC1R 0x0010 /* ADCL_TO_DAC1R */ +#define WM8915_ADCL_TO_DAC1R_MASK 0x0010 /* ADCL_TO_DAC1R */ +#define WM8915_ADCL_TO_DAC1R_SHIFT 4 /* ADCL_TO_DAC1R */ +#define WM8915_ADCL_TO_DAC1R_WIDTH 1 /* ADCL_TO_DAC1R */ +#define WM8915_DSP2RXR_TO_DAC1R 0x0002 /* DSP2RXR_TO_DAC1R */ +#define WM8915_DSP2RXR_TO_DAC1R_MASK 0x0002 /* DSP2RXR_TO_DAC1R */ +#define WM8915_DSP2RXR_TO_DAC1R_SHIFT 1 /* DSP2RXR_TO_DAC1R */ +#define WM8915_DSP2RXR_TO_DAC1R_WIDTH 1 /* DSP2RXR_TO_DAC1R */ +#define WM8915_DSP1RXR_TO_DAC1R 0x0001 /* DSP1RXR_TO_DAC1R */ +#define WM8915_DSP1RXR_TO_DAC1R_MASK 0x0001 /* DSP1RXR_TO_DAC1R */ +#define WM8915_DSP1RXR_TO_DAC1R_SHIFT 0 /* DSP1RXR_TO_DAC1R */ +#define WM8915_DSP1RXR_TO_DAC1R_WIDTH 1 /* DSP1RXR_TO_DAC1R */ + +/* + * R1539 (0x603) - DAC2 Mixer Volumes + */ +#define WM8915_ADCR_DAC2_VOL_MASK 0x03E0 /* ADCR_DAC2_VOL - [9:5] */ +#define WM8915_ADCR_DAC2_VOL_SHIFT 5 /* ADCR_DAC2_VOL - [9:5] */ +#define WM8915_ADCR_DAC2_VOL_WIDTH 5 /* ADCR_DAC2_VOL - [9:5] */ +#define WM8915_ADCL_DAC2_VOL_MASK 0x001F /* ADCL_DAC2_VOL - [4:0] */ +#define WM8915_ADCL_DAC2_VOL_SHIFT 0 /* ADCL_DAC2_VOL - [4:0] */ +#define WM8915_ADCL_DAC2_VOL_WIDTH 5 /* ADCL_DAC2_VOL - [4:0] */ + +/* + * R1540 (0x604) - DAC2 Left Mixer Routing + */ +#define WM8915_ADCR_TO_DAC2L 0x0020 /* ADCR_TO_DAC2L */ +#define WM8915_ADCR_TO_DAC2L_MASK 0x0020 /* ADCR_TO_DAC2L */ +#define WM8915_ADCR_TO_DAC2L_SHIFT 5 /* ADCR_TO_DAC2L */ +#define WM8915_ADCR_TO_DAC2L_WIDTH 1 /* ADCR_TO_DAC2L */ +#define WM8915_ADCL_TO_DAC2L 0x0010 /* ADCL_TO_DAC2L */ +#define WM8915_ADCL_TO_DAC2L_MASK 0x0010 /* ADCL_TO_DAC2L */ +#define WM8915_ADCL_TO_DAC2L_SHIFT 4 /* ADCL_TO_DAC2L */ +#define WM8915_ADCL_TO_DAC2L_WIDTH 1 /* ADCL_TO_DAC2L */ +#define WM8915_DSP2RXL_TO_DAC2L 0x0002 /* DSP2RXL_TO_DAC2L */ +#define WM8915_DSP2RXL_TO_DAC2L_MASK 0x0002 /* DSP2RXL_TO_DAC2L */ +#define WM8915_DSP2RXL_TO_DAC2L_SHIFT 1 /* DSP2RXL_TO_DAC2L */ +#define WM8915_DSP2RXL_TO_DAC2L_WIDTH 1 /* DSP2RXL_TO_DAC2L */ +#define WM8915_DSP1RXL_TO_DAC2L 0x0001 /* DSP1RXL_TO_DAC2L */ +#define WM8915_DSP1RXL_TO_DAC2L_MASK 0x0001 /* DSP1RXL_TO_DAC2L */ +#define WM8915_DSP1RXL_TO_DAC2L_SHIFT 0 /* DSP1RXL_TO_DAC2L */ +#define WM8915_DSP1RXL_TO_DAC2L_WIDTH 1 /* DSP1RXL_TO_DAC2L */ + +/* + * R1541 (0x605) - DAC2 Right Mixer Routing + */ +#define WM8915_ADCR_TO_DAC2R 0x0020 /* ADCR_TO_DAC2R */ +#define WM8915_ADCR_TO_DAC2R_MASK 0x0020 /* ADCR_TO_DAC2R */ +#define WM8915_ADCR_TO_DAC2R_SHIFT 5 /* ADCR_TO_DAC2R */ +#define WM8915_ADCR_TO_DAC2R_WIDTH 1 /* ADCR_TO_DAC2R */ +#define WM8915_ADCL_TO_DAC2R 0x0010 /* ADCL_TO_DAC2R */ +#define WM8915_ADCL_TO_DAC2R_MASK 0x0010 /* ADCL_TO_DAC2R */ +#define WM8915_ADCL_TO_DAC2R_SHIFT 4 /* ADCL_TO_DAC2R */ +#define WM8915_ADCL_TO_DAC2R_WIDTH 1 /* ADCL_TO_DAC2R */ +#define WM8915_DSP2RXR_TO_DAC2R 0x0002 /* DSP2RXR_TO_DAC2R */ +#define WM8915_DSP2RXR_TO_DAC2R_MASK 0x0002 /* DSP2RXR_TO_DAC2R */ +#define WM8915_DSP2RXR_TO_DAC2R_SHIFT 1 /* DSP2RXR_TO_DAC2R */ +#define WM8915_DSP2RXR_TO_DAC2R_WIDTH 1 /* DSP2RXR_TO_DAC2R */ +#define WM8915_DSP1RXR_TO_DAC2R 0x0001 /* DSP1RXR_TO_DAC2R */ +#define WM8915_DSP1RXR_TO_DAC2R_MASK 0x0001 /* DSP1RXR_TO_DAC2R */ +#define WM8915_DSP1RXR_TO_DAC2R_SHIFT 0 /* DSP1RXR_TO_DAC2R */ +#define WM8915_DSP1RXR_TO_DAC2R_WIDTH 1 /* DSP1RXR_TO_DAC2R */ + +/* + * R1542 (0x606) - DSP1 TX Left Mixer Routing + */ +#define WM8915_ADC1L_TO_DSP1TXL 0x0002 /* ADC1L_TO_DSP1TXL */ +#define WM8915_ADC1L_TO_DSP1TXL_MASK 0x0002 /* ADC1L_TO_DSP1TXL */ +#define WM8915_ADC1L_TO_DSP1TXL_SHIFT 1 /* ADC1L_TO_DSP1TXL */ +#define WM8915_ADC1L_TO_DSP1TXL_WIDTH 1 /* ADC1L_TO_DSP1TXL */ +#define WM8915_DACL_TO_DSP1TXL 0x0001 /* DACL_TO_DSP1TXL */ +#define WM8915_DACL_TO_DSP1TXL_MASK 0x0001 /* DACL_TO_DSP1TXL */ +#define WM8915_DACL_TO_DSP1TXL_SHIFT 0 /* DACL_TO_DSP1TXL */ +#define WM8915_DACL_TO_DSP1TXL_WIDTH 1 /* DACL_TO_DSP1TXL */ + +/* + * R1543 (0x607) - DSP1 TX Right Mixer Routing + */ +#define WM8915_ADC1R_TO_DSP1TXR 0x0002 /* ADC1R_TO_DSP1TXR */ +#define WM8915_ADC1R_TO_DSP1TXR_MASK 0x0002 /* ADC1R_TO_DSP1TXR */ +#define WM8915_ADC1R_TO_DSP1TXR_SHIFT 1 /* ADC1R_TO_DSP1TXR */ +#define WM8915_ADC1R_TO_DSP1TXR_WIDTH 1 /* ADC1R_TO_DSP1TXR */ +#define WM8915_DACR_TO_DSP1TXR 0x0001 /* DACR_TO_DSP1TXR */ +#define WM8915_DACR_TO_DSP1TXR_MASK 0x0001 /* DACR_TO_DSP1TXR */ +#define WM8915_DACR_TO_DSP1TXR_SHIFT 0 /* DACR_TO_DSP1TXR */ +#define WM8915_DACR_TO_DSP1TXR_WIDTH 1 /* DACR_TO_DSP1TXR */ + +/* + * R1544 (0x608) - DSP2 TX Left Mixer Routing + */ +#define WM8915_ADC2L_TO_DSP2TXL 0x0002 /* ADC2L_TO_DSP2TXL */ +#define WM8915_ADC2L_TO_DSP2TXL_MASK 0x0002 /* ADC2L_TO_DSP2TXL */ +#define WM8915_ADC2L_TO_DSP2TXL_SHIFT 1 /* ADC2L_TO_DSP2TXL */ +#define WM8915_ADC2L_TO_DSP2TXL_WIDTH 1 /* ADC2L_TO_DSP2TXL */ +#define WM8915_DACL_TO_DSP2TXL 0x0001 /* DACL_TO_DSP2TXL */ +#define WM8915_DACL_TO_DSP2TXL_MASK 0x0001 /* DACL_TO_DSP2TXL */ +#define WM8915_DACL_TO_DSP2TXL_SHIFT 0 /* DACL_TO_DSP2TXL */ +#define WM8915_DACL_TO_DSP2TXL_WIDTH 1 /* DACL_TO_DSP2TXL */ + +/* + * R1545 (0x609) - DSP2 TX Right Mixer Routing + */ +#define WM8915_ADC2R_TO_DSP2TXR 0x0002 /* ADC2R_TO_DSP2TXR */ +#define WM8915_ADC2R_TO_DSP2TXR_MASK 0x0002 /* ADC2R_TO_DSP2TXR */ +#define WM8915_ADC2R_TO_DSP2TXR_SHIFT 1 /* ADC2R_TO_DSP2TXR */ +#define WM8915_ADC2R_TO_DSP2TXR_WIDTH 1 /* ADC2R_TO_DSP2TXR */ +#define WM8915_DACR_TO_DSP2TXR 0x0001 /* DACR_TO_DSP2TXR */ +#define WM8915_DACR_TO_DSP2TXR_MASK 0x0001 /* DACR_TO_DSP2TXR */ +#define WM8915_DACR_TO_DSP2TXR_SHIFT 0 /* DACR_TO_DSP2TXR */ +#define WM8915_DACR_TO_DSP2TXR_WIDTH 1 /* DACR_TO_DSP2TXR */ + +/* + * R1546 (0x60A) - DSP TX Mixer Select + */ +#define WM8915_DAC_TO_DSPTX_SRC 0x0001 /* DAC_TO_DSPTX_SRC */ +#define WM8915_DAC_TO_DSPTX_SRC_MASK 0x0001 /* DAC_TO_DSPTX_SRC */ +#define WM8915_DAC_TO_DSPTX_SRC_SHIFT 0 /* DAC_TO_DSPTX_SRC */ +#define WM8915_DAC_TO_DSPTX_SRC_WIDTH 1 /* DAC_TO_DSPTX_SRC */ + +/* + * R1552 (0x610) - DAC Softmute + */ +#define WM8915_DAC_SOFTMUTEMODE 0x0002 /* DAC_SOFTMUTEMODE */ +#define WM8915_DAC_SOFTMUTEMODE_MASK 0x0002 /* DAC_SOFTMUTEMODE */ +#define WM8915_DAC_SOFTMUTEMODE_SHIFT 1 /* DAC_SOFTMUTEMODE */ +#define WM8915_DAC_SOFTMUTEMODE_WIDTH 1 /* DAC_SOFTMUTEMODE */ +#define WM8915_DAC_MUTERATE 0x0001 /* DAC_MUTERATE */ +#define WM8915_DAC_MUTERATE_MASK 0x0001 /* DAC_MUTERATE */ +#define WM8915_DAC_MUTERATE_SHIFT 0 /* DAC_MUTERATE */ +#define WM8915_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */ + +/* + * R1568 (0x620) - Oversampling + */ +#define WM8915_SPK_OSR128 0x0008 /* SPK_OSR128 */ +#define WM8915_SPK_OSR128_MASK 0x0008 /* SPK_OSR128 */ +#define WM8915_SPK_OSR128_SHIFT 3 /* SPK_OSR128 */ +#define WM8915_SPK_OSR128_WIDTH 1 /* SPK_OSR128 */ +#define WM8915_DMIC_OSR64 0x0004 /* DMIC_OSR64 */ +#define WM8915_DMIC_OSR64_MASK 0x0004 /* DMIC_OSR64 */ +#define WM8915_DMIC_OSR64_SHIFT 2 /* DMIC_OSR64 */ +#define WM8915_DMIC_OSR64_WIDTH 1 /* DMIC_OSR64 */ +#define WM8915_ADC_OSR128 0x0002 /* ADC_OSR128 */ +#define WM8915_ADC_OSR128_MASK 0x0002 /* ADC_OSR128 */ +#define WM8915_ADC_OSR128_SHIFT 1 /* ADC_OSR128 */ +#define WM8915_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */ +#define WM8915_DAC_OSR128 0x0001 /* DAC_OSR128 */ +#define WM8915_DAC_OSR128_MASK 0x0001 /* DAC_OSR128 */ +#define WM8915_DAC_OSR128_SHIFT 0 /* DAC_OSR128 */ +#define WM8915_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */ + +/* + * R1569 (0x621) - Sidetone + */ +#define WM8915_ST_LPF 0x1000 /* ST_LPF */ +#define WM8915_ST_LPF_MASK 0x1000 /* ST_LPF */ +#define WM8915_ST_LPF_SHIFT 12 /* ST_LPF */ +#define WM8915_ST_LPF_WIDTH 1 /* ST_LPF */ +#define WM8915_ST_HPF_CUT_MASK 0x0380 /* ST_HPF_CUT - [9:7] */ +#define WM8915_ST_HPF_CUT_SHIFT 7 /* ST_HPF_CUT - [9:7] */ +#define WM8915_ST_HPF_CUT_WIDTH 3 /* ST_HPF_CUT - [9:7] */ +#define WM8915_ST_HPF 0x0040 /* ST_HPF */ +#define WM8915_ST_HPF_MASK 0x0040 /* ST_HPF */ +#define WM8915_ST_HPF_SHIFT 6 /* ST_HPF */ +#define WM8915_ST_HPF_WIDTH 1 /* ST_HPF */ +#define WM8915_STR_SEL 0x0002 /* STR_SEL */ +#define WM8915_STR_SEL_MASK 0x0002 /* STR_SEL */ +#define WM8915_STR_SEL_SHIFT 1 /* STR_SEL */ +#define WM8915_STR_SEL_WIDTH 1 /* STR_SEL */ +#define WM8915_STL_SEL 0x0001 /* STL_SEL */ +#define WM8915_STL_SEL_MASK 0x0001 /* STL_SEL */ +#define WM8915_STL_SEL_SHIFT 0 /* STL_SEL */ +#define WM8915_STL_SEL_WIDTH 1 /* STL_SEL */ + +/* + * R1792 (0x700) - GPIO 1 + */ +#define WM8915_GP1_DIR 0x8000 /* GP1_DIR */ +#define WM8915_GP1_DIR_MASK 0x8000 /* GP1_DIR */ +#define WM8915_GP1_DIR_SHIFT 15 /* GP1_DIR */ +#define WM8915_GP1_DIR_WIDTH 1 /* GP1_DIR */ +#define WM8915_GP1_PU 0x4000 /* GP1_PU */ +#define WM8915_GP1_PU_MASK 0x4000 /* GP1_PU */ +#define WM8915_GP1_PU_SHIFT 14 /* GP1_PU */ +#define WM8915_GP1_PU_WIDTH 1 /* GP1_PU */ +#define WM8915_GP1_PD 0x2000 /* GP1_PD */ +#define WM8915_GP1_PD_MASK 0x2000 /* GP1_PD */ +#define WM8915_GP1_PD_SHIFT 13 /* GP1_PD */ +#define WM8915_GP1_PD_WIDTH 1 /* GP1_PD */ +#define WM8915_GP1_POL 0x0400 /* GP1_POL */ +#define WM8915_GP1_POL_MASK 0x0400 /* GP1_POL */ +#define WM8915_GP1_POL_SHIFT 10 /* GP1_POL */ +#define WM8915_GP1_POL_WIDTH 1 /* GP1_POL */ +#define WM8915_GP1_OP_CFG 0x0200 /* GP1_OP_CFG */ +#define WM8915_GP1_OP_CFG_MASK 0x0200 /* GP1_OP_CFG */ +#define WM8915_GP1_OP_CFG_SHIFT 9 /* GP1_OP_CFG */ +#define WM8915_GP1_OP_CFG_WIDTH 1 /* GP1_OP_CFG */ +#define WM8915_GP1_DB 0x0100 /* GP1_DB */ +#define WM8915_GP1_DB_MASK 0x0100 /* GP1_DB */ +#define WM8915_GP1_DB_SHIFT 8 /* GP1_DB */ +#define WM8915_GP1_DB_WIDTH 1 /* GP1_DB */ +#define WM8915_GP1_LVL 0x0040 /* GP1_LVL */ +#define WM8915_GP1_LVL_MASK 0x0040 /* GP1_LVL */ +#define WM8915_GP1_LVL_SHIFT 6 /* GP1_LVL */ +#define WM8915_GP1_LVL_WIDTH 1 /* GP1_LVL */ +#define WM8915_GP1_FN_MASK 0x000F /* GP1_FN - [3:0] */ +#define WM8915_GP1_FN_SHIFT 0 /* GP1_FN - [3:0] */ +#define WM8915_GP1_FN_WIDTH 4 /* GP1_FN - [3:0] */ + +/* + * R1793 (0x701) - GPIO 2 + */ +#define WM8915_GP2_DIR 0x8000 /* GP2_DIR */ +#define WM8915_GP2_DIR_MASK 0x8000 /* GP2_DIR */ +#define WM8915_GP2_DIR_SHIFT 15 /* GP2_DIR */ +#define WM8915_GP2_DIR_WIDTH 1 /* GP2_DIR */ +#define WM8915_GP2_PU 0x4000 /* GP2_PU */ +#define WM8915_GP2_PU_MASK 0x4000 /* GP2_PU */ +#define WM8915_GP2_PU_SHIFT 14 /* GP2_PU */ +#define WM8915_GP2_PU_WIDTH 1 /* GP2_PU */ +#define WM8915_GP2_PD 0x2000 /* GP2_PD */ +#define WM8915_GP2_PD_MASK 0x2000 /* GP2_PD */ +#define WM8915_GP2_PD_SHIFT 13 /* GP2_PD */ +#define WM8915_GP2_PD_WIDTH 1 /* GP2_PD */ +#define WM8915_GP2_POL 0x0400 /* GP2_POL */ +#define WM8915_GP2_POL_MASK 0x0400 /* GP2_POL */ +#define WM8915_GP2_POL_SHIFT 10 /* GP2_POL */ +#define WM8915_GP2_POL_WIDTH 1 /* GP2_POL */ +#define WM8915_GP2_OP_CFG 0x0200 /* GP2_OP_CFG */ +#define WM8915_GP2_OP_CFG_MASK 0x0200 /* GP2_OP_CFG */ +#define WM8915_GP2_OP_CFG_SHIFT 9 /* GP2_OP_CFG */ +#define WM8915_GP2_OP_CFG_WIDTH 1 /* GP2_OP_CFG */ +#define WM8915_GP2_DB 0x0100 /* GP2_DB */ +#define WM8915_GP2_DB_MASK 0x0100 /* GP2_DB */ +#define WM8915_GP2_DB_SHIFT 8 /* GP2_DB */ +#define WM8915_GP2_DB_WIDTH 1 /* GP2_DB */ +#define WM8915_GP2_LVL 0x0040 /* GP2_LVL */ +#define WM8915_GP2_LVL_MASK 0x0040 /* GP2_LVL */ +#define WM8915_GP2_LVL_SHIFT 6 /* GP2_LVL */ +#define WM8915_GP2_LVL_WIDTH 1 /* GP2_LVL */ +#define WM8915_GP2_FN_MASK 0x000F /* GP2_FN - [3:0] */ +#define WM8915_GP2_FN_SHIFT 0 /* GP2_FN - [3:0] */ +#define WM8915_GP2_FN_WIDTH 4 /* GP2_FN - [3:0] */ + +/* + * R1794 (0x702) - GPIO 3 + */ +#define WM8915_GP3_DIR 0x8000 /* GP3_DIR */ +#define WM8915_GP3_DIR_MASK 0x8000 /* GP3_DIR */ +#define WM8915_GP3_DIR_SHIFT 15 /* GP3_DIR */ +#define WM8915_GP3_DIR_WIDTH 1 /* GP3_DIR */ +#define WM8915_GP3_PU 0x4000 /* GP3_PU */ +#define WM8915_GP3_PU_MASK 0x4000 /* GP3_PU */ +#define WM8915_GP3_PU_SHIFT 14 /* GP3_PU */ +#define WM8915_GP3_PU_WIDTH 1 /* GP3_PU */ +#define WM8915_GP3_PD 0x2000 /* GP3_PD */ +#define WM8915_GP3_PD_MASK 0x2000 /* GP3_PD */ +#define WM8915_GP3_PD_SHIFT 13 /* GP3_PD */ +#define WM8915_GP3_PD_WIDTH 1 /* GP3_PD */ +#define WM8915_GP3_POL 0x0400 /* GP3_POL */ +#define WM8915_GP3_POL_MASK 0x0400 /* GP3_POL */ +#define WM8915_GP3_POL_SHIFT 10 /* GP3_POL */ +#define WM8915_GP3_POL_WIDTH 1 /* GP3_POL */ +#define WM8915_GP3_OP_CFG 0x0200 /* GP3_OP_CFG */ +#define WM8915_GP3_OP_CFG_MASK 0x0200 /* GP3_OP_CFG */ +#define WM8915_GP3_OP_CFG_SHIFT 9 /* GP3_OP_CFG */ +#define WM8915_GP3_OP_CFG_WIDTH 1 /* GP3_OP_CFG */ +#define WM8915_GP3_DB 0x0100 /* GP3_DB */ +#define WM8915_GP3_DB_MASK 0x0100 /* GP3_DB */ +#define WM8915_GP3_DB_SHIFT 8 /* GP3_DB */ +#define WM8915_GP3_DB_WIDTH 1 /* GP3_DB */ +#define WM8915_GP3_LVL 0x0040 /* GP3_LVL */ +#define WM8915_GP3_LVL_MASK 0x0040 /* GP3_LVL */ +#define WM8915_GP3_LVL_SHIFT 6 /* GP3_LVL */ +#define WM8915_GP3_LVL_WIDTH 1 /* GP3_LVL */ +#define WM8915_GP3_FN_MASK 0x000F /* GP3_FN - [3:0] */ +#define WM8915_GP3_FN_SHIFT 0 /* GP3_FN - [3:0] */ +#define WM8915_GP3_FN_WIDTH 4 /* GP3_FN - [3:0] */ + +/* + * R1795 (0x703) - GPIO 4 + */ +#define WM8915_GP4_DIR 0x8000 /* GP4_DIR */ +#define WM8915_GP4_DIR_MASK 0x8000 /* GP4_DIR */ +#define WM8915_GP4_DIR_SHIFT 15 /* GP4_DIR */ +#define WM8915_GP4_DIR_WIDTH 1 /* GP4_DIR */ +#define WM8915_GP4_PU 0x4000 /* GP4_PU */ +#define WM8915_GP4_PU_MASK 0x4000 /* GP4_PU */ +#define WM8915_GP4_PU_SHIFT 14 /* GP4_PU */ +#define WM8915_GP4_PU_WIDTH 1 /* GP4_PU */ +#define WM8915_GP4_PD 0x2000 /* GP4_PD */ +#define WM8915_GP4_PD_MASK 0x2000 /* GP4_PD */ +#define WM8915_GP4_PD_SHIFT 13 /* GP4_PD */ +#define WM8915_GP4_PD_WIDTH 1 /* GP4_PD */ +#define WM8915_GP4_POL 0x0400 /* GP4_POL */ +#define WM8915_GP4_POL_MASK 0x0400 /* GP4_POL */ +#define WM8915_GP4_POL_SHIFT 10 /* GP4_POL */ +#define WM8915_GP4_POL_WIDTH 1 /* GP4_POL */ +#define WM8915_GP4_OP_CFG 0x0200 /* GP4_OP_CFG */ +#define WM8915_GP4_OP_CFG_MASK 0x0200 /* GP4_OP_CFG */ +#define WM8915_GP4_OP_CFG_SHIFT 9 /* GP4_OP_CFG */ +#define WM8915_GP4_OP_CFG_WIDTH 1 /* GP4_OP_CFG */ +#define WM8915_GP4_DB 0x0100 /* GP4_DB */ +#define WM8915_GP4_DB_MASK 0x0100 /* GP4_DB */ +#define WM8915_GP4_DB_SHIFT 8 /* GP4_DB */ +#define WM8915_GP4_DB_WIDTH 1 /* GP4_DB */ +#define WM8915_GP4_LVL 0x0040 /* GP4_LVL */ +#define WM8915_GP4_LVL_MASK 0x0040 /* GP4_LVL */ +#define WM8915_GP4_LVL_SHIFT 6 /* GP4_LVL */ +#define WM8915_GP4_LVL_WIDTH 1 /* GP4_LVL */ +#define WM8915_GP4_FN_MASK 0x000F /* GP4_FN - [3:0] */ +#define WM8915_GP4_FN_SHIFT 0 /* GP4_FN - [3:0] */ +#define WM8915_GP4_FN_WIDTH 4 /* GP4_FN - [3:0] */ + +/* + * R1796 (0x704) - GPIO 5 + */ +#define WM8915_GP5_DIR 0x8000 /* GP5_DIR */ +#define WM8915_GP5_DIR_MASK 0x8000 /* GP5_DIR */ +#define WM8915_GP5_DIR_SHIFT 15 /* GP5_DIR */ +#define WM8915_GP5_DIR_WIDTH 1 /* GP5_DIR */ +#define WM8915_GP5_PU 0x4000 /* GP5_PU */ +#define WM8915_GP5_PU_MASK 0x4000 /* GP5_PU */ +#define WM8915_GP5_PU_SHIFT 14 /* GP5_PU */ +#define WM8915_GP5_PU_WIDTH 1 /* GP5_PU */ +#define WM8915_GP5_PD 0x2000 /* GP5_PD */ +#define WM8915_GP5_PD_MASK 0x2000 /* GP5_PD */ +#define WM8915_GP5_PD_SHIFT 13 /* GP5_PD */ +#define WM8915_GP5_PD_WIDTH 1 /* GP5_PD */ +#define WM8915_GP5_POL 0x0400 /* GP5_POL */ +#define WM8915_GP5_POL_MASK 0x0400 /* GP5_POL */ +#define WM8915_GP5_POL_SHIFT 10 /* GP5_POL */ +#define WM8915_GP5_POL_WIDTH 1 /* GP5_POL */ +#define WM8915_GP5_OP_CFG 0x0200 /* GP5_OP_CFG */ +#define WM8915_GP5_OP_CFG_MASK 0x0200 /* GP5_OP_CFG */ +#define WM8915_GP5_OP_CFG_SHIFT 9 /* GP5_OP_CFG */ +#define WM8915_GP5_OP_CFG_WIDTH 1 /* GP5_OP_CFG */ +#define WM8915_GP5_DB 0x0100 /* GP5_DB */ +#define WM8915_GP5_DB_MASK 0x0100 /* GP5_DB */ +#define WM8915_GP5_DB_SHIFT 8 /* GP5_DB */ +#define WM8915_GP5_DB_WIDTH 1 /* GP5_DB */ +#define WM8915_GP5_LVL 0x0040 /* GP5_LVL */ +#define WM8915_GP5_LVL_MASK 0x0040 /* GP5_LVL */ +#define WM8915_GP5_LVL_SHIFT 6 /* GP5_LVL */ +#define WM8915_GP5_LVL_WIDTH 1 /* GP5_LVL */ +#define WM8915_GP5_FN_MASK 0x000F /* GP5_FN - [3:0] */ +#define WM8915_GP5_FN_SHIFT 0 /* GP5_FN - [3:0] */ +#define WM8915_GP5_FN_WIDTH 4 /* GP5_FN - [3:0] */ + +/* + * R1824 (0x720) - Pull Control (1) + */ +#define WM8915_DMICDAT2_PD 0x1000 /* DMICDAT2_PD */ +#define WM8915_DMICDAT2_PD_MASK 0x1000 /* DMICDAT2_PD */ +#define WM8915_DMICDAT2_PD_SHIFT 12 /* DMICDAT2_PD */ +#define WM8915_DMICDAT2_PD_WIDTH 1 /* DMICDAT2_PD */ +#define WM8915_DMICDAT1_PD 0x0400 /* DMICDAT1_PD */ +#define WM8915_DMICDAT1_PD_MASK 0x0400 /* DMICDAT1_PD */ +#define WM8915_DMICDAT1_PD_SHIFT 10 /* DMICDAT1_PD */ +#define WM8915_DMICDAT1_PD_WIDTH 1 /* DMICDAT1_PD */ +#define WM8915_MCLK2_PU 0x0200 /* MCLK2_PU */ +#define WM8915_MCLK2_PU_MASK 0x0200 /* MCLK2_PU */ +#define WM8915_MCLK2_PU_SHIFT 9 /* MCLK2_PU */ +#define WM8915_MCLK2_PU_WIDTH 1 /* MCLK2_PU */ +#define WM8915_MCLK2_PD 0x0100 /* MCLK2_PD */ +#define WM8915_MCLK2_PD_MASK 0x0100 /* MCLK2_PD */ +#define WM8915_MCLK2_PD_SHIFT 8 /* MCLK2_PD */ +#define WM8915_MCLK2_PD_WIDTH 1 /* MCLK2_PD */ +#define WM8915_MCLK1_PU 0x0080 /* MCLK1_PU */ +#define WM8915_MCLK1_PU_MASK 0x0080 /* MCLK1_PU */ +#define WM8915_MCLK1_PU_SHIFT 7 /* MCLK1_PU */ +#define WM8915_MCLK1_PU_WIDTH 1 /* MCLK1_PU */ +#define WM8915_MCLK1_PD 0x0040 /* MCLK1_PD */ +#define WM8915_MCLK1_PD_MASK 0x0040 /* MCLK1_PD */ +#define WM8915_MCLK1_PD_SHIFT 6 /* MCLK1_PD */ +#define WM8915_MCLK1_PD_WIDTH 1 /* MCLK1_PD */ +#define WM8915_DACDAT1_PU 0x0020 /* DACDAT1_PU */ +#define WM8915_DACDAT1_PU_MASK 0x0020 /* DACDAT1_PU */ +#define WM8915_DACDAT1_PU_SHIFT 5 /* DACDAT1_PU */ +#define WM8915_DACDAT1_PU_WIDTH 1 /* DACDAT1_PU */ +#define WM8915_DACDAT1_PD 0x0010 /* DACDAT1_PD */ +#define WM8915_DACDAT1_PD_MASK 0x0010 /* DACDAT1_PD */ +#define WM8915_DACDAT1_PD_SHIFT 4 /* DACDAT1_PD */ +#define WM8915_DACDAT1_PD_WIDTH 1 /* DACDAT1_PD */ +#define WM8915_DACLRCLK1_PU 0x0008 /* DACLRCLK1_PU */ +#define WM8915_DACLRCLK1_PU_MASK 0x0008 /* DACLRCLK1_PU */ +#define WM8915_DACLRCLK1_PU_SHIFT 3 /* DACLRCLK1_PU */ +#define WM8915_DACLRCLK1_PU_WIDTH 1 /* DACLRCLK1_PU */ +#define WM8915_DACLRCLK1_PD 0x0004 /* DACLRCLK1_PD */ +#define WM8915_DACLRCLK1_PD_MASK 0x0004 /* DACLRCLK1_PD */ +#define WM8915_DACLRCLK1_PD_SHIFT 2 /* DACLRCLK1_PD */ +#define WM8915_DACLRCLK1_PD_WIDTH 1 /* DACLRCLK1_PD */ +#define WM8915_BCLK1_PU 0x0002 /* BCLK1_PU */ +#define WM8915_BCLK1_PU_MASK 0x0002 /* BCLK1_PU */ +#define WM8915_BCLK1_PU_SHIFT 1 /* BCLK1_PU */ +#define WM8915_BCLK1_PU_WIDTH 1 /* BCLK1_PU */ +#define WM8915_BCLK1_PD 0x0001 /* BCLK1_PD */ +#define WM8915_BCLK1_PD_MASK 0x0001 /* BCLK1_PD */ +#define WM8915_BCLK1_PD_SHIFT 0 /* BCLK1_PD */ +#define WM8915_BCLK1_PD_WIDTH 1 /* BCLK1_PD */ + +/* + * R1825 (0x721) - Pull Control (2) + */ +#define WM8915_LDO1ENA_PD 0x0100 /* LDO1ENA_PD */ +#define WM8915_LDO1ENA_PD_MASK 0x0100 /* LDO1ENA_PD */ +#define WM8915_LDO1ENA_PD_SHIFT 8 /* LDO1ENA_PD */ +#define WM8915_LDO1ENA_PD_WIDTH 1 /* LDO1ENA_PD */ +#define WM8915_ADDR_PD 0x0040 /* ADDR_PD */ +#define WM8915_ADDR_PD_MASK 0x0040 /* ADDR_PD */ +#define WM8915_ADDR_PD_SHIFT 6 /* ADDR_PD */ +#define WM8915_ADDR_PD_WIDTH 1 /* ADDR_PD */ +#define WM8915_DACDAT2_PU 0x0020 /* DACDAT2_PU */ +#define WM8915_DACDAT2_PU_MASK 0x0020 /* DACDAT2_PU */ +#define WM8915_DACDAT2_PU_SHIFT 5 /* DACDAT2_PU */ +#define WM8915_DACDAT2_PU_WIDTH 1 /* DACDAT2_PU */ +#define WM8915_DACDAT2_PD 0x0010 /* DACDAT2_PD */ +#define WM8915_DACDAT2_PD_MASK 0x0010 /* DACDAT2_PD */ +#define WM8915_DACDAT2_PD_SHIFT 4 /* DACDAT2_PD */ +#define WM8915_DACDAT2_PD_WIDTH 1 /* DACDAT2_PD */ +#define WM8915_DACLRCLK2_PU 0x0008 /* DACLRCLK2_PU */ +#define WM8915_DACLRCLK2_PU_MASK 0x0008 /* DACLRCLK2_PU */ +#define WM8915_DACLRCLK2_PU_SHIFT 3 /* DACLRCLK2_PU */ +#define WM8915_DACLRCLK2_PU_WIDTH 1 /* DACLRCLK2_PU */ +#define WM8915_DACLRCLK2_PD 0x0004 /* DACLRCLK2_PD */ +#define WM8915_DACLRCLK2_PD_MASK 0x0004 /* DACLRCLK2_PD */ +#define WM8915_DACLRCLK2_PD_SHIFT 2 /* DACLRCLK2_PD */ +#define WM8915_DACLRCLK2_PD_WIDTH 1 /* DACLRCLK2_PD */ +#define WM8915_BCLK2_PU 0x0002 /* BCLK2_PU */ +#define WM8915_BCLK2_PU_MASK 0x0002 /* BCLK2_PU */ +#define WM8915_BCLK2_PU_SHIFT 1 /* BCLK2_PU */ +#define WM8915_BCLK2_PU_WIDTH 1 /* BCLK2_PU */ +#define WM8915_BCLK2_PD 0x0001 /* BCLK2_PD */ +#define WM8915_BCLK2_PD_MASK 0x0001 /* BCLK2_PD */ +#define WM8915_BCLK2_PD_SHIFT 0 /* BCLK2_PD */ +#define WM8915_BCLK2_PD_WIDTH 1 /* BCLK2_PD */ + +/* + * R1840 (0x730) - Interrupt Status 1 + */ +#define WM8915_GP5_EINT 0x0010 /* GP5_EINT */ +#define WM8915_GP5_EINT_MASK 0x0010 /* GP5_EINT */ +#define WM8915_GP5_EINT_SHIFT 4 /* GP5_EINT */ +#define WM8915_GP5_EINT_WIDTH 1 /* GP5_EINT */ +#define WM8915_GP4_EINT 0x0008 /* GP4_EINT */ +#define WM8915_GP4_EINT_MASK 0x0008 /* GP4_EINT */ +#define WM8915_GP4_EINT_SHIFT 3 /* GP4_EINT */ +#define WM8915_GP4_EINT_WIDTH 1 /* GP4_EINT */ +#define WM8915_GP3_EINT 0x0004 /* GP3_EINT */ +#define WM8915_GP3_EINT_MASK 0x0004 /* GP3_EINT */ +#define WM8915_GP3_EINT_SHIFT 2 /* GP3_EINT */ +#define WM8915_GP3_EINT_WIDTH 1 /* GP3_EINT */ +#define WM8915_GP2_EINT 0x0002 /* GP2_EINT */ +#define WM8915_GP2_EINT_MASK 0x0002 /* GP2_EINT */ +#define WM8915_GP2_EINT_SHIFT 1 /* GP2_EINT */ +#define WM8915_GP2_EINT_WIDTH 1 /* GP2_EINT */ +#define WM8915_GP1_EINT 0x0001 /* GP1_EINT */ +#define WM8915_GP1_EINT_MASK 0x0001 /* GP1_EINT */ +#define WM8915_GP1_EINT_SHIFT 0 /* GP1_EINT */ +#define WM8915_GP1_EINT_WIDTH 1 /* GP1_EINT */ + +/* + * R1841 (0x731) - Interrupt Status 2 + */ +#define WM8915_DCS_DONE_23_EINT 0x1000 /* DCS_DONE_23_EINT */ +#define WM8915_DCS_DONE_23_EINT_MASK 0x1000 /* DCS_DONE_23_EINT */ +#define WM8915_DCS_DONE_23_EINT_SHIFT 12 /* DCS_DONE_23_EINT */ +#define WM8915_DCS_DONE_23_EINT_WIDTH 1 /* DCS_DONE_23_EINT */ +#define WM8915_DCS_DONE_01_EINT 0x0800 /* DCS_DONE_01_EINT */ +#define WM8915_DCS_DONE_01_EINT_MASK 0x0800 /* DCS_DONE_01_EINT */ +#define WM8915_DCS_DONE_01_EINT_SHIFT 11 /* DCS_DONE_01_EINT */ +#define WM8915_DCS_DONE_01_EINT_WIDTH 1 /* DCS_DONE_01_EINT */ +#define WM8915_WSEQ_DONE_EINT 0x0400 /* WSEQ_DONE_EINT */ +#define WM8915_WSEQ_DONE_EINT_MASK 0x0400 /* WSEQ_DONE_EINT */ +#define WM8915_WSEQ_DONE_EINT_SHIFT 10 /* WSEQ_DONE_EINT */ +#define WM8915_WSEQ_DONE_EINT_WIDTH 1 /* WSEQ_DONE_EINT */ +#define WM8915_FIFOS_ERR_EINT 0x0200 /* FIFOS_ERR_EINT */ +#define WM8915_FIFOS_ERR_EINT_MASK 0x0200 /* FIFOS_ERR_EINT */ +#define WM8915_FIFOS_ERR_EINT_SHIFT 9 /* FIFOS_ERR_EINT */ +#define WM8915_FIFOS_ERR_EINT_WIDTH 1 /* FIFOS_ERR_EINT */ +#define WM8915_DSP2DRC_SIG_DET_EINT 0x0080 /* DSP2DRC_SIG_DET_EINT */ +#define WM8915_DSP2DRC_SIG_DET_EINT_MASK 0x0080 /* DSP2DRC_SIG_DET_EINT */ +#define WM8915_DSP2DRC_SIG_DET_EINT_SHIFT 7 /* DSP2DRC_SIG_DET_EINT */ +#define WM8915_DSP2DRC_SIG_DET_EINT_WIDTH 1 /* DSP2DRC_SIG_DET_EINT */ +#define WM8915_DSP1DRC_SIG_DET_EINT 0x0040 /* DSP1DRC_SIG_DET_EINT */ +#define WM8915_DSP1DRC_SIG_DET_EINT_MASK 0x0040 /* DSP1DRC_SIG_DET_EINT */ +#define WM8915_DSP1DRC_SIG_DET_EINT_SHIFT 6 /* DSP1DRC_SIG_DET_EINT */ +#define WM8915_DSP1DRC_SIG_DET_EINT_WIDTH 1 /* DSP1DRC_SIG_DET_EINT */ +#define WM8915_FLL_SW_CLK_DONE_EINT 0x0008 /* FLL_SW_CLK_DONE_EINT */ +#define WM8915_FLL_SW_CLK_DONE_EINT_MASK 0x0008 /* FLL_SW_CLK_DONE_EINT */ +#define WM8915_FLL_SW_CLK_DONE_EINT_SHIFT 3 /* FLL_SW_CLK_DONE_EINT */ +#define WM8915_FLL_SW_CLK_DONE_EINT_WIDTH 1 /* FLL_SW_CLK_DONE_EINT */ +#define WM8915_FLL_LOCK_EINT 0x0004 /* FLL_LOCK_EINT */ +#define WM8915_FLL_LOCK_EINT_MASK 0x0004 /* FLL_LOCK_EINT */ +#define WM8915_FLL_LOCK_EINT_SHIFT 2 /* FLL_LOCK_EINT */ +#define WM8915_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */ +#define WM8915_HP_DONE_EINT 0x0002 /* HP_DONE_EINT */ +#define WM8915_HP_DONE_EINT_MASK 0x0002 /* HP_DONE_EINT */ +#define WM8915_HP_DONE_EINT_SHIFT 1 /* HP_DONE_EINT */ +#define WM8915_HP_DONE_EINT_WIDTH 1 /* HP_DONE_EINT */ +#define WM8915_MICD_EINT 0x0001 /* MICD_EINT */ +#define WM8915_MICD_EINT_MASK 0x0001 /* MICD_EINT */ +#define WM8915_MICD_EINT_SHIFT 0 /* MICD_EINT */ +#define WM8915_MICD_EINT_WIDTH 1 /* MICD_EINT */ + +/* + * R1842 (0x732) - Interrupt Raw Status 2 + */ +#define WM8915_DCS_DONE_23_STS 0x1000 /* DCS_DONE_23_STS */ +#define WM8915_DCS_DONE_23_STS_MASK 0x1000 /* DCS_DONE_23_STS */ +#define WM8915_DCS_DONE_23_STS_SHIFT 12 /* DCS_DONE_23_STS */ +#define WM8915_DCS_DONE_23_STS_WIDTH 1 /* DCS_DONE_23_STS */ +#define WM8915_DCS_DONE_01_STS 0x0800 /* DCS_DONE_01_STS */ +#define WM8915_DCS_DONE_01_STS_MASK 0x0800 /* DCS_DONE_01_STS */ +#define WM8915_DCS_DONE_01_STS_SHIFT 11 /* DCS_DONE_01_STS */ +#define WM8915_DCS_DONE_01_STS_WIDTH 1 /* DCS_DONE_01_STS */ +#define WM8915_WSEQ_DONE_STS 0x0400 /* WSEQ_DONE_STS */ +#define WM8915_WSEQ_DONE_STS_MASK 0x0400 /* WSEQ_DONE_STS */ +#define WM8915_WSEQ_DONE_STS_SHIFT 10 /* WSEQ_DONE_STS */ +#define WM8915_WSEQ_DONE_STS_WIDTH 1 /* WSEQ_DONE_STS */ +#define WM8915_FIFOS_ERR_STS 0x0200 /* FIFOS_ERR_STS */ +#define WM8915_FIFOS_ERR_STS_MASK 0x0200 /* FIFOS_ERR_STS */ +#define WM8915_FIFOS_ERR_STS_SHIFT 9 /* FIFOS_ERR_STS */ +#define WM8915_FIFOS_ERR_STS_WIDTH 1 /* FIFOS_ERR_STS */ +#define WM8915_DSP2DRC_SIG_DET_STS 0x0080 /* DSP2DRC_SIG_DET_STS */ +#define WM8915_DSP2DRC_SIG_DET_STS_MASK 0x0080 /* DSP2DRC_SIG_DET_STS */ +#define WM8915_DSP2DRC_SIG_DET_STS_SHIFT 7 /* DSP2DRC_SIG_DET_STS */ +#define WM8915_DSP2DRC_SIG_DET_STS_WIDTH 1 /* DSP2DRC_SIG_DET_STS */ +#define WM8915_DSP1DRC_SIG_DET_STS 0x0040 /* DSP1DRC_SIG_DET_STS */ +#define WM8915_DSP1DRC_SIG_DET_STS_MASK 0x0040 /* DSP1DRC_SIG_DET_STS */ +#define WM8915_DSP1DRC_SIG_DET_STS_SHIFT 6 /* DSP1DRC_SIG_DET_STS */ +#define WM8915_DSP1DRC_SIG_DET_STS_WIDTH 1 /* DSP1DRC_SIG_DET_STS */ +#define WM8915_FLL_LOCK_STS 0x0004 /* FLL_LOCK_STS */ +#define WM8915_FLL_LOCK_STS_MASK 0x0004 /* FLL_LOCK_STS */ +#define WM8915_FLL_LOCK_STS_SHIFT 2 /* FLL_LOCK_STS */ +#define WM8915_FLL_LOCK_STS_WIDTH 1 /* FLL_LOCK_STS */ + +/* + * R1848 (0x738) - Interrupt Status 1 Mask + */ +#define WM8915_IM_GP5_EINT 0x0010 /* IM_GP5_EINT */ +#define WM8915_IM_GP5_EINT_MASK 0x0010 /* IM_GP5_EINT */ +#define WM8915_IM_GP5_EINT_SHIFT 4 /* IM_GP5_EINT */ +#define WM8915_IM_GP5_EINT_WIDTH 1 /* IM_GP5_EINT */ +#define WM8915_IM_GP4_EINT 0x0008 /* IM_GP4_EINT */ +#define WM8915_IM_GP4_EINT_MASK 0x0008 /* IM_GP4_EINT */ +#define WM8915_IM_GP4_EINT_SHIFT 3 /* IM_GP4_EINT */ +#define WM8915_IM_GP4_EINT_WIDTH 1 /* IM_GP4_EINT */ +#define WM8915_IM_GP3_EINT 0x0004 /* IM_GP3_EINT */ +#define WM8915_IM_GP3_EINT_MASK 0x0004 /* IM_GP3_EINT */ +#define WM8915_IM_GP3_EINT_SHIFT 2 /* IM_GP3_EINT */ +#define WM8915_IM_GP3_EINT_WIDTH 1 /* IM_GP3_EINT */ +#define WM8915_IM_GP2_EINT 0x0002 /* IM_GP2_EINT */ +#define WM8915_IM_GP2_EINT_MASK 0x0002 /* IM_GP2_EINT */ +#define WM8915_IM_GP2_EINT_SHIFT 1 /* IM_GP2_EINT */ +#define WM8915_IM_GP2_EINT_WIDTH 1 /* IM_GP2_EINT */ +#define WM8915_IM_GP1_EINT 0x0001 /* IM_GP1_EINT */ +#define WM8915_IM_GP1_EINT_MASK 0x0001 /* IM_GP1_EINT */ +#define WM8915_IM_GP1_EINT_SHIFT 0 /* IM_GP1_EINT */ +#define WM8915_IM_GP1_EINT_WIDTH 1 /* IM_GP1_EINT */ + +/* + * R1849 (0x739) - Interrupt Status 2 Mask + */ +#define WM8915_IM_DCS_DONE_23_EINT 0x1000 /* IM_DCS_DONE_23_EINT */ +#define WM8915_IM_DCS_DONE_23_EINT_MASK 0x1000 /* IM_DCS_DONE_23_EINT */ +#define WM8915_IM_DCS_DONE_23_EINT_SHIFT 12 /* IM_DCS_DONE_23_EINT */ +#define WM8915_IM_DCS_DONE_23_EINT_WIDTH 1 /* IM_DCS_DONE_23_EINT */ +#define WM8915_IM_DCS_DONE_01_EINT 0x0800 /* IM_DCS_DONE_01_EINT */ +#define WM8915_IM_DCS_DONE_01_EINT_MASK 0x0800 /* IM_DCS_DONE_01_EINT */ +#define WM8915_IM_DCS_DONE_01_EINT_SHIFT 11 /* IM_DCS_DONE_01_EINT */ +#define WM8915_IM_DCS_DONE_01_EINT_WIDTH 1 /* IM_DCS_DONE_01_EINT */ +#define WM8915_IM_WSEQ_DONE_EINT 0x0400 /* IM_WSEQ_DONE_EINT */ +#define WM8915_IM_WSEQ_DONE_EINT_MASK 0x0400 /* IM_WSEQ_DONE_EINT */ +#define WM8915_IM_WSEQ_DONE_EINT_SHIFT 10 /* IM_WSEQ_DONE_EINT */ +#define WM8915_IM_WSEQ_DONE_EINT_WIDTH 1 /* IM_WSEQ_DONE_EINT */ +#define WM8915_IM_FIFOS_ERR_EINT 0x0200 /* IM_FIFOS_ERR_EINT */ +#define WM8915_IM_FIFOS_ERR_EINT_MASK 0x0200 /* IM_FIFOS_ERR_EINT */ +#define WM8915_IM_FIFOS_ERR_EINT_SHIFT 9 /* IM_FIFOS_ERR_EINT */ +#define WM8915_IM_FIFOS_ERR_EINT_WIDTH 1 /* IM_FIFOS_ERR_EINT */ +#define WM8915_IM_DSP2DRC_SIG_DET_EINT 0x0080 /* IM_DSP2DRC_SIG_DET_EINT */ +#define WM8915_IM_DSP2DRC_SIG_DET_EINT_MASK 0x0080 /* IM_DSP2DRC_SIG_DET_EINT */ +#define WM8915_IM_DSP2DRC_SIG_DET_EINT_SHIFT 7 /* IM_DSP2DRC_SIG_DET_EINT */ +#define WM8915_IM_DSP2DRC_SIG_DET_EINT_WIDTH 1 /* IM_DSP2DRC_SIG_DET_EINT */ +#define WM8915_IM_DSP1DRC_SIG_DET_EINT 0x0040 /* IM_DSP1DRC_SIG_DET_EINT */ +#define WM8915_IM_DSP1DRC_SIG_DET_EINT_MASK 0x0040 /* IM_DSP1DRC_SIG_DET_EINT */ +#define WM8915_IM_DSP1DRC_SIG_DET_EINT_SHIFT 6 /* IM_DSP1DRC_SIG_DET_EINT */ +#define WM8915_IM_DSP1DRC_SIG_DET_EINT_WIDTH 1 /* IM_DSP1DRC_SIG_DET_EINT */ +#define WM8915_IM_FLL_SW_CLK_DONE_EINT 0x0008 /* IM_FLL_SW_CLK_DONE_EINT */ +#define WM8915_IM_FLL_SW_CLK_DONE_EINT_MASK 0x0008 /* IM_FLL_SW_CLK_DONE_EINT */ +#define WM8915_IM_FLL_SW_CLK_DONE_EINT_SHIFT 3 /* IM_FLL_SW_CLK_DONE_EINT */ +#define WM8915_IM_FLL_SW_CLK_DONE_EINT_WIDTH 1 /* IM_FLL_SW_CLK_DONE_EINT */ +#define WM8915_IM_FLL_LOCK_EINT 0x0004 /* IM_FLL_LOCK_EINT */ +#define WM8915_IM_FLL_LOCK_EINT_MASK 0x0004 /* IM_FLL_LOCK_EINT */ +#define WM8915_IM_FLL_LOCK_EINT_SHIFT 2 /* IM_FLL_LOCK_EINT */ +#define WM8915_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */ +#define WM8915_IM_HP_DONE_EINT 0x0002 /* IM_HP_DONE_EINT */ +#define WM8915_IM_HP_DONE_EINT_MASK 0x0002 /* IM_HP_DONE_EINT */ +#define WM8915_IM_HP_DONE_EINT_SHIFT 1 /* IM_HP_DONE_EINT */ +#define WM8915_IM_HP_DONE_EINT_WIDTH 1 /* IM_HP_DONE_EINT */ +#define WM8915_IM_MICD_EINT 0x0001 /* IM_MICD_EINT */ +#define WM8915_IM_MICD_EINT_MASK 0x0001 /* IM_MICD_EINT */ +#define WM8915_IM_MICD_EINT_SHIFT 0 /* IM_MICD_EINT */ +#define WM8915_IM_MICD_EINT_WIDTH 1 /* IM_MICD_EINT */ + +/* + * R1856 (0x740) - Interrupt Control + */ +#define WM8915_IM_IRQ 0x0001 /* IM_IRQ */ +#define WM8915_IM_IRQ_MASK 0x0001 /* IM_IRQ */ +#define WM8915_IM_IRQ_SHIFT 0 /* IM_IRQ */ +#define WM8915_IM_IRQ_WIDTH 1 /* IM_IRQ */ + +/* + * R2048 (0x800) - Left PDM Speaker + */ +#define WM8915_SPKL_ENA 0x0010 /* SPKL_ENA */ +#define WM8915_SPKL_ENA_MASK 0x0010 /* SPKL_ENA */ +#define WM8915_SPKL_ENA_SHIFT 4 /* SPKL_ENA */ +#define WM8915_SPKL_ENA_WIDTH 1 /* SPKL_ENA */ +#define WM8915_SPKL_MUTE 0x0008 /* SPKL_MUTE */ +#define WM8915_SPKL_MUTE_MASK 0x0008 /* SPKL_MUTE */ +#define WM8915_SPKL_MUTE_SHIFT 3 /* SPKL_MUTE */ +#define WM8915_SPKL_MUTE_WIDTH 1 /* SPKL_MUTE */ +#define WM8915_SPKL_MUTE_ZC 0x0004 /* SPKL_MUTE_ZC */ +#define WM8915_SPKL_MUTE_ZC_MASK 0x0004 /* SPKL_MUTE_ZC */ +#define WM8915_SPKL_MUTE_ZC_SHIFT 2 /* SPKL_MUTE_ZC */ +#define WM8915_SPKL_MUTE_ZC_WIDTH 1 /* SPKL_MUTE_ZC */ +#define WM8915_SPKL_SRC_MASK 0x0003 /* SPKL_SRC - [1:0] */ +#define WM8915_SPKL_SRC_SHIFT 0 /* SPKL_SRC - [1:0] */ +#define WM8915_SPKL_SRC_WIDTH 2 /* SPKL_SRC - [1:0] */ + +/* + * R2049 (0x801) - Right PDM Speaker + */ +#define WM8915_SPKR_ENA 0x0010 /* SPKR_ENA */ +#define WM8915_SPKR_ENA_MASK 0x0010 /* SPKR_ENA */ +#define WM8915_SPKR_ENA_SHIFT 4 /* SPKR_ENA */ +#define WM8915_SPKR_ENA_WIDTH 1 /* SPKR_ENA */ +#define WM8915_SPKR_MUTE 0x0008 /* SPKR_MUTE */ +#define WM8915_SPKR_MUTE_MASK 0x0008 /* SPKR_MUTE */ +#define WM8915_SPKR_MUTE_SHIFT 3 /* SPKR_MUTE */ +#define WM8915_SPKR_MUTE_WIDTH 1 /* SPKR_MUTE */ +#define WM8915_SPKR_MUTE_ZC 0x0004 /* SPKR_MUTE_ZC */ +#define WM8915_SPKR_MUTE_ZC_MASK 0x0004 /* SPKR_MUTE_ZC */ +#define WM8915_SPKR_MUTE_ZC_SHIFT 2 /* SPKR_MUTE_ZC */ +#define WM8915_SPKR_MUTE_ZC_WIDTH 1 /* SPKR_MUTE_ZC */ +#define WM8915_SPKR_SRC_MASK 0x0003 /* SPKR_SRC - [1:0] */ +#define WM8915_SPKR_SRC_SHIFT 0 /* SPKR_SRC - [1:0] */ +#define WM8915_SPKR_SRC_WIDTH 2 /* SPKR_SRC - [1:0] */ + +/* + * R2050 (0x802) - PDM Speaker Mute Sequence + */ +#define WM8915_SPK_MUTE_ENDIAN 0x0100 /* SPK_MUTE_ENDIAN */ +#define WM8915_SPK_MUTE_ENDIAN_MASK 0x0100 /* SPK_MUTE_ENDIAN */ +#define WM8915_SPK_MUTE_ENDIAN_SHIFT 8 /* SPK_MUTE_ENDIAN */ +#define WM8915_SPK_MUTE_ENDIAN_WIDTH 1 /* SPK_MUTE_ENDIAN */ +#define WM8915_SPK_MUTE_SEQ1_MASK 0x00FF /* SPK_MUTE_SEQ1 - [7:0] */ +#define WM8915_SPK_MUTE_SEQ1_SHIFT 0 /* SPK_MUTE_SEQ1 - [7:0] */ +#define WM8915_SPK_MUTE_SEQ1_WIDTH 8 /* SPK_MUTE_SEQ1 - [7:0] */ + +/* + * R2051 (0x803) - PDM Speaker Volume + */ +#define WM8915_SPKR_VOL_MASK 0x00F0 /* SPKR_VOL - [7:4] */ +#define WM8915_SPKR_VOL_SHIFT 4 /* SPKR_VOL - [7:4] */ +#define WM8915_SPKR_VOL_WIDTH 4 /* SPKR_VOL - [7:4] */ +#define WM8915_SPKL_VOL_MASK 0x000F /* SPKL_VOL - [3:0] */ +#define WM8915_SPKL_VOL_SHIFT 0 /* SPKL_VOL - [3:0] */ +#define WM8915_SPKL_VOL_WIDTH 4 /* SPKL_VOL - [3:0] */ + +#endif diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 5e0214d6293e..3c7198779c31 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -176,7 +176,7 @@ static int wm8995_pll_factors(struct device *dev, return 0; } -/* Lookup table specifiying SRATE (table 25 in datasheet); some of the +/* Lookup table specifying SRATE (table 25 in datasheet); some of the * output frequencies have been rounded to the standard frequencies * they are intended to match where the error is slight. */ static struct { diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c new file mode 100644 index 000000000000..0293763debe5 --- /dev/null +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -0,0 +1,1051 @@ +/* + * wm8958-dsp2.c -- WM8958 DSP2 support + * + * Copyright 2011 Wolfson Microelectronics plc + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <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/slab.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <trace/events/asoc.h> + +#include <linux/mfd/wm8994/core.h> +#include <linux/mfd/wm8994/registers.h> +#include <linux/mfd/wm8994/pdata.h> +#include <linux/mfd/wm8994/gpio.h> + +#include "wm8994.h" + +#define WM_FW_BLOCK_INFO 0xff +#define WM_FW_BLOCK_PM 0x00 +#define WM_FW_BLOCK_X 0x01 +#define WM_FW_BLOCK_Y 0x02 +#define WM_FW_BLOCK_Z 0x03 +#define WM_FW_BLOCK_I 0x06 +#define WM_FW_BLOCK_A 0x08 +#define WM_FW_BLOCK_C 0x0c + +static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name, + const struct firmware *fw, bool check) +{ + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + u64 data64; + u32 data32; + const u8 *data; + char *str; + size_t block_len, len; + int ret = 0; + + /* Suppress unneeded downloads */ + if (wm8994->cur_fw == fw) + return 0; + + if (fw->size < 32) { + dev_err(codec->dev, "%s: firmware too short\n", name); + goto err; + } + + if (memcmp(fw->data, "WMFW", 4) != 0) { + dev_err(codec->dev, "%s: firmware has bad file magic %08x\n", + name, data32); + goto err; + } + + memcpy(&data32, fw->data + 4, sizeof(data32)); + len = be32_to_cpu(data32); + + memcpy(&data32, fw->data + 8, sizeof(data32)); + data32 = be32_to_cpu(data32); + if ((data32 >> 24) & 0xff) { + dev_err(codec->dev, "%s: unsupported firmware version %d\n", + name, (data32 >> 24) & 0xff); + goto err; + } + if ((data32 & 0xffff) != 8958) { + dev_err(codec->dev, "%s: unsupported target device %d\n", + name, data32 & 0xffff); + goto err; + } + if (((data32 >> 16) & 0xff) != 0xc) { + dev_err(codec->dev, "%s: unsupported target core %d\n", + name, (data32 >> 16) & 0xff); + goto err; + } + + if (check) { + memcpy(&data64, fw->data + 24, sizeof(u64)); + dev_info(codec->dev, "%s timestamp %llx\n", + name, be64_to_cpu(data64)); + } else { + snd_soc_write(codec, 0x102, 0x2); + snd_soc_write(codec, 0x900, 0x2); + } + + data = fw->data + len; + len = fw->size - len; + while (len) { + if (len < 12) { + dev_err(codec->dev, "%s short data block of %zd\n", + name, len); + goto err; + } + + memcpy(&data32, data + 4, sizeof(data32)); + block_len = be32_to_cpu(data32); + if (block_len + 8 > len) { + dev_err(codec->dev, "%zd byte block longer than file\n", + block_len); + goto err; + } + if (block_len == 0) { + dev_err(codec->dev, "Zero length block\n"); + goto err; + } + + memcpy(&data32, data, sizeof(data32)); + data32 = be32_to_cpu(data32); + + switch ((data32 >> 24) & 0xff) { + case WM_FW_BLOCK_INFO: + /* Informational text */ + if (!check) + break; + + str = kzalloc(block_len + 1, GFP_KERNEL); + if (str) { + memcpy(str, data + 8, block_len); + dev_info(codec->dev, "%s: %s\n", name, str); + kfree(str); + } else { + dev_err(codec->dev, "Out of memory\n"); + } + break; + case WM_FW_BLOCK_PM: + case WM_FW_BLOCK_X: + case WM_FW_BLOCK_Y: + case WM_FW_BLOCK_Z: + case WM_FW_BLOCK_I: + case WM_FW_BLOCK_A: + case WM_FW_BLOCK_C: + dev_dbg(codec->dev, "%s: %zd bytes of %x@%x\n", name, + block_len, (data32 >> 24) & 0xff, + data32 & 0xffffff); + + if (check) + break; + + data32 &= 0xffffff; + + wm8994_bulk_write(codec->control_data, + data32 & 0xffffff, + block_len / 2, + (void *)(data + 8)); + + break; + default: + dev_warn(codec->dev, "%s: unknown block type %d\n", + name, (data32 >> 24) & 0xff); + break; + } + + /* Round up to the next 32 bit word */ + block_len += block_len % 4; + + data += block_len + 8; + len -= block_len + 8; + } + + if (!check) { + dev_dbg(codec->dev, "%s: download done\n", name); + wm8994->cur_fw = fw; + } else { + dev_info(codec->dev, "%s: got firmware\n", name); + } + + goto ok; + +err: + ret = -EINVAL; +ok: + if (!check) { + snd_soc_write(codec, 0x900, 0x0); + snd_soc_write(codec, 0x102, 0x0); + } + + return ret; +} + +static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) +{ + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994_pdata *pdata = wm8994->pdata; + int i; + + /* If the DSP is already running then noop */ + if (snd_soc_read(codec, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA) + return; + + /* If we have MBC firmware download it */ + if (wm8994->mbc) + wm8958_dsp2_fw(codec, "MBC", wm8994->mbc, false); + + snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, + WM8958_DSP2_ENA, WM8958_DSP2_ENA); + + /* If we've got user supplied MBC settings use them */ + if (pdata && pdata->num_mbc_cfgs) { + struct wm8958_mbc_cfg *cfg + = &pdata->mbc_cfgs[wm8994->mbc_cfg]; + + for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++) + snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1, + cfg->coeff_regs[i]); + + for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++) + snd_soc_write(codec, + i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1, + cfg->cutoff_regs[i]); + } + + /* Run the DSP */ + snd_soc_write(codec, WM8958_DSP2_EXECCONTROL, + WM8958_DSP2_RUNR); + + /* And we're off! */ + snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, + WM8958_MBC_ENA | + WM8958_MBC_SEL_MASK, + path << WM8958_MBC_SEL_SHIFT | + WM8958_MBC_ENA); +} + +static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) +{ + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994_pdata *pdata = wm8994->pdata; + int i, ena; + + if (wm8994->mbc_vss) + wm8958_dsp2_fw(codec, "MBC+VSS", wm8994->mbc_vss, false); + + snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, + WM8958_DSP2_ENA, WM8958_DSP2_ENA); + + /* If we've got user supplied settings use them */ + if (pdata && pdata->num_mbc_cfgs) { + struct wm8958_mbc_cfg *cfg + = &pdata->mbc_cfgs[wm8994->mbc_cfg]; + + for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++) + snd_soc_write(codec, i + 0x2800, + cfg->combined_regs[i]); + } + + if (pdata && pdata->num_vss_cfgs) { + struct wm8958_vss_cfg *cfg + = &pdata->vss_cfgs[wm8994->vss_cfg]; + + for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) + snd_soc_write(codec, i + 0x2600, cfg->regs[i]); + } + + if (pdata && pdata->num_vss_hpf_cfgs) { + struct wm8958_vss_hpf_cfg *cfg + = &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg]; + + for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) + snd_soc_write(codec, i + 0x2400, cfg->regs[i]); + } + + /* Run the DSP */ + snd_soc_write(codec, WM8958_DSP2_EXECCONTROL, + WM8958_DSP2_RUNR); + + /* Enable the algorithms we've selected */ + ena = 0; + if (wm8994->mbc_ena[path]) + ena |= 0x8; + if (wm8994->hpf2_ena[path]) + ena |= 0x4; + if (wm8994->hpf1_ena[path]) + ena |= 0x2; + if (wm8994->vss_ena[path]) + ena |= 0x1; + + snd_soc_write(codec, 0x2201, ena); + + /* Switch the DSP into the data path */ + snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, + WM8958_MBC_SEL_MASK | WM8958_MBC_ENA, + path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA); +} + +static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path) +{ + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994_pdata *pdata = wm8994->pdata; + int i; + + wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false); + + snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, + WM8958_DSP2_ENA, WM8958_DSP2_ENA); + + /* If we've got user supplied settings use them */ + if (pdata && pdata->num_enh_eq_cfgs) { + struct wm8958_enh_eq_cfg *cfg + = &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg]; + + for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) + snd_soc_write(codec, i + 0x2200, + cfg->regs[i]); + } + + /* Run the DSP */ + snd_soc_write(codec, WM8958_DSP2_EXECCONTROL, + WM8958_DSP2_RUNR); + + /* Switch the DSP into the data path */ + snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, + WM8958_MBC_SEL_MASK | WM8958_MBC_ENA, + path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA); +} + +static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start) +{ + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5); + int ena, reg, aif; + + switch (path) { + case 0: + pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA); + aif = 0; + break; + case 1: + pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA); + aif = 0; + break; + case 2: + pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA); + aif = 1; + break; + default: + BUG(); + return; + } + + /* Do we have both an active AIF and an active algorithm? */ + ena = wm8994->mbc_ena[path] || wm8994->vss_ena[path] || + wm8994->hpf1_ena[path] || wm8994->hpf2_ena[path] || + wm8994->enh_eq_ena[path]; + if (!pwr_reg) + ena = 0; + + reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM); + + dev_dbg(codec->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n", + path, wm8994->dsp_active, start, pwr_reg, reg); + + if (start && ena) { + /* If the DSP is already running then noop */ + if (reg & WM8958_DSP2_ENA) + return; + + /* If either AIFnCLK is not yet enabled postpone */ + if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) + & WM8994_AIF1CLK_ENA_MASK) && + !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1) + & WM8994_AIF2CLK_ENA_MASK)) + return; + + /* Switch the clock over to the appropriate AIF */ + snd_soc_update_bits(codec, WM8994_CLOCKING_1, + WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA, + aif << WM8958_DSP2CLK_SRC_SHIFT | + WM8958_DSP2CLK_ENA); + + if (wm8994->enh_eq_ena[path]) + wm8958_dsp_start_enh_eq(codec, path); + else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] || + wm8994->hpf2_ena[path]) + wm8958_dsp_start_vss(codec, path); + else if (wm8994->mbc_ena[path]) + wm8958_dsp_start_mbc(codec, path); + + wm8994->dsp_active = path; + + dev_dbg(codec->dev, "DSP running in path %d\n", path); + } + + if (!start && wm8994->dsp_active == path) { + /* If the DSP is already stopped then noop */ + if (!(reg & WM8958_DSP2_ENA)) + return; + + snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, + WM8958_MBC_ENA, 0); + snd_soc_write(codec, WM8958_DSP2_EXECCONTROL, + WM8958_DSP2_STOP); + snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, + WM8958_DSP2_ENA, 0); + snd_soc_update_bits(codec, WM8994_CLOCKING_1, + WM8958_DSP2CLK_ENA, 0); + + wm8994->dsp_active = -1; + + dev_dbg(codec->dev, "DSP stopped\n"); + } +} + +int wm8958_aif_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + int i; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_PRE_PMU: + for (i = 0; i < 3; i++) + wm8958_dsp_apply(codec, i, 1); + break; + case SND_SOC_DAPM_POST_PMD: + case SND_SOC_DAPM_PRE_PMD: + for (i = 0; i < 3; i++) + wm8958_dsp_apply(codec, i, 0); + break; + } + + return 0; +} + +/* Check if DSP2 is in use on another AIF */ +static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) { + if (i == aif) + continue; + if (wm8994->mbc_ena[i] || wm8994->vss_ena[i] || + wm8994->hpf1_ena[i] || wm8994->hpf2_ena[i]) + return 1; + } + + return 0; +} + +static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994_pdata *pdata = wm8994->pdata; + int value = ucontrol->value.integer.value[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ + reg = snd_soc_read(codec, WM8994_CLOCKING_1); + if (reg < 0 || reg & WM8958_DSP2CLK_ENA) + return -EBUSY; + + if (value >= pdata->num_mbc_cfgs) + return -EINVAL; + + wm8994->mbc_cfg = value; + + return 0; +} + +static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg; + + return 0; +} + +static int wm8958_mbc_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int wm8958_mbc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int mbc = kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc]; + + return 0; +} + +static int wm8958_mbc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int mbc = kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0]) + return 0; + + if (ucontrol->value.integer.value[0] > 1) + return -EINVAL; + + if (wm8958_dsp2_busy(wm8994, mbc)) { + dev_dbg(codec->dev, "DSP2 active on %d already\n", mbc); + return -EBUSY; + } + + if (wm8994->enh_eq_ena[mbc]) + return -EBUSY; + + wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0]; + + wm8958_dsp_apply(codec, mbc, wm8994->mbc_ena[mbc]); + + return 0; +} + +#define WM8958_MBC_SWITCH(xname, xval) {\ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .info = wm8958_mbc_info, \ + .get = wm8958_mbc_get, .put = wm8958_mbc_put, \ + .private_value = xval } + +static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994_pdata *pdata = wm8994->pdata; + int value = ucontrol->value.integer.value[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ + reg = snd_soc_read(codec, WM8994_CLOCKING_1); + if (reg < 0 || reg & WM8958_DSP2CLK_ENA) + return -EBUSY; + + if (value >= pdata->num_vss_cfgs) + return -EINVAL; + + wm8994->vss_cfg = value; + + return 0; +} + +static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = wm8994->vss_cfg; + + return 0; +} + +static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994_pdata *pdata = wm8994->pdata; + int value = ucontrol->value.integer.value[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ + reg = snd_soc_read(codec, WM8994_CLOCKING_1); + if (reg < 0 || reg & WM8958_DSP2CLK_ENA) + return -EBUSY; + + if (value >= pdata->num_vss_hpf_cfgs) + return -EINVAL; + + wm8994->vss_hpf_cfg = value; + + return 0; +} + +static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg; + + return 0; +} + +static int wm8958_vss_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int wm8958_vss_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int vss = kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = wm8994->vss_ena[vss]; + + return 0; +} + +static int wm8958_vss_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int vss = kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0]) + return 0; + + if (ucontrol->value.integer.value[0] > 1) + return -EINVAL; + + if (!wm8994->mbc_vss) + return -ENODEV; + + if (wm8958_dsp2_busy(wm8994, vss)) { + dev_dbg(codec->dev, "DSP2 active on %d already\n", vss); + return -EBUSY; + } + + if (wm8994->enh_eq_ena[vss]) + return -EBUSY; + + wm8994->vss_ena[vss] = ucontrol->value.integer.value[0]; + + wm8958_dsp_apply(codec, vss, wm8994->vss_ena[vss]); + + return 0; +} + + +#define WM8958_VSS_SWITCH(xname, xval) {\ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .info = wm8958_vss_info, \ + .get = wm8958_vss_get, .put = wm8958_vss_put, \ + .private_value = xval } + +static int wm8958_hpf_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int wm8958_hpf_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int hpf = kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + if (hpf < 3) + ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3]; + else + ucontrol->value.integer.value[0] = wm8994->hpf2_ena[hpf % 3]; + + return 0; +} + +static int wm8958_hpf_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int hpf = kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + if (hpf < 3) { + if (wm8994->hpf1_ena[hpf % 3] == + ucontrol->value.integer.value[0]) + return 0; + } else { + if (wm8994->hpf2_ena[hpf % 3] == + ucontrol->value.integer.value[0]) + return 0; + } + + if (ucontrol->value.integer.value[0] > 1) + return -EINVAL; + + if (!wm8994->mbc_vss) + return -ENODEV; + + if (wm8958_dsp2_busy(wm8994, hpf % 3)) { + dev_dbg(codec->dev, "DSP2 active on %d already\n", hpf); + return -EBUSY; + } + + if (wm8994->enh_eq_ena[hpf % 3]) + return -EBUSY; + + if (hpf < 3) + wm8994->hpf1_ena[hpf % 3] = ucontrol->value.integer.value[0]; + else + wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0]; + + wm8958_dsp_apply(codec, hpf % 3, ucontrol->value.integer.value[0]); + + return 0; +} + +#define WM8958_HPF_SWITCH(xname, xval) {\ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .info = wm8958_hpf_info, \ + .get = wm8958_hpf_get, .put = wm8958_hpf_put, \ + .private_value = xval } + +static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994_pdata *pdata = wm8994->pdata; + int value = ucontrol->value.integer.value[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ + reg = snd_soc_read(codec, WM8994_CLOCKING_1); + if (reg < 0 || reg & WM8958_DSP2CLK_ENA) + return -EBUSY; + + if (value >= pdata->num_enh_eq_cfgs) + return -EINVAL; + + wm8994->enh_eq_cfg = value; + + return 0; +} + +static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg; + + return 0; +} + +static int wm8958_enh_eq_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int eq = kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq]; + + return 0; +} + +static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int eq = kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0]) + return 0; + + if (ucontrol->value.integer.value[0] > 1) + return -EINVAL; + + if (!wm8994->enh_eq) + return -ENODEV; + + if (wm8958_dsp2_busy(wm8994, eq)) { + dev_dbg(codec->dev, "DSP2 active on %d already\n", eq); + return -EBUSY; + } + + if (wm8994->mbc_ena[eq] || wm8994->vss_ena[eq] || + wm8994->hpf1_ena[eq] || wm8994->hpf2_ena[eq]) + return -EBUSY; + + wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0]; + + wm8958_dsp_apply(codec, eq, ucontrol->value.integer.value[0]); + + return 0; +} + +#define WM8958_ENH_EQ_SWITCH(xname, xval) {\ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .info = wm8958_enh_eq_info, \ + .get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \ + .private_value = xval } + +static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = { +WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0), +WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1), +WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2), +}; + +static const struct snd_kcontrol_new wm8958_vss_snd_controls[] = { +WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0), +WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1), +WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2), +WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0), +WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1), +WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2), +WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3), +WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4), +WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5), +}; + +static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls[] = { +WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0), +WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1), +WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2), +}; + +static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context) +{ + struct snd_soc_codec *codec = context; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) { + mutex_lock(&codec->mutex); + wm8994->enh_eq = fw; + mutex_unlock(&codec->mutex); + } +} + +static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) +{ + struct snd_soc_codec *codec = context; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) { + mutex_lock(&codec->mutex); + wm8994->mbc_vss = fw; + mutex_unlock(&codec->mutex); + } + + /* We can't have more than one request outstanding at once so + * we daisy chain. + */ + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + "wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL, + codec, wm8958_enh_eq_loaded); +} + +static void wm8958_mbc_loaded(const struct firmware *fw, void *context) +{ + struct snd_soc_codec *codec = context; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0) + return; + + mutex_lock(&codec->mutex); + wm8994->mbc = fw; + mutex_unlock(&codec->mutex); + + /* We can't have more than one request outstanding at once so + * we daisy chain. + */ + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL, + codec, wm8958_mbc_vss_loaded); +} + +void wm8958_dsp2_init(struct snd_soc_codec *codec) +{ + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994_pdata *pdata = wm8994->pdata; + int ret, i; + + wm8994->dsp_active = -1; + + snd_soc_add_controls(codec, wm8958_mbc_snd_controls, + ARRAY_SIZE(wm8958_mbc_snd_controls)); + snd_soc_add_controls(codec, wm8958_vss_snd_controls, + ARRAY_SIZE(wm8958_vss_snd_controls)); + snd_soc_add_controls(codec, wm8958_enh_eq_snd_controls, + ARRAY_SIZE(wm8958_enh_eq_snd_controls)); + + + /* We don't *require* firmware and don't want to delay boot */ + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + "wm8958_mbc.wfw", codec->dev, GFP_KERNEL, + codec, wm8958_mbc_loaded); + + if (!pdata) + return; + + if (pdata->num_mbc_cfgs) { + struct snd_kcontrol_new control[] = { + SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum, + wm8958_get_mbc_enum, wm8958_put_mbc_enum), + }; + + /* We need an array of texts for the enum API */ + wm8994->mbc_texts = kmalloc(sizeof(char *) + * pdata->num_mbc_cfgs, GFP_KERNEL); + if (!wm8994->mbc_texts) { + dev_err(wm8994->codec->dev, + "Failed to allocate %d MBC config texts\n", + pdata->num_mbc_cfgs); + return; + } + + for (i = 0; i < pdata->num_mbc_cfgs; i++) + wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name; + + wm8994->mbc_enum.max = pdata->num_mbc_cfgs; + wm8994->mbc_enum.texts = wm8994->mbc_texts; + + ret = snd_soc_add_controls(wm8994->codec, control, 1); + if (ret != 0) + dev_err(wm8994->codec->dev, + "Failed to add MBC mode controls: %d\n", ret); + } + + if (pdata->num_vss_cfgs) { + struct snd_kcontrol_new control[] = { + SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum, + wm8958_get_vss_enum, wm8958_put_vss_enum), + }; + + /* We need an array of texts for the enum API */ + wm8994->vss_texts = kmalloc(sizeof(char *) + * pdata->num_vss_cfgs, GFP_KERNEL); + if (!wm8994->vss_texts) { + dev_err(wm8994->codec->dev, + "Failed to allocate %d VSS config texts\n", + pdata->num_vss_cfgs); + return; + } + + for (i = 0; i < pdata->num_vss_cfgs; i++) + wm8994->vss_texts[i] = pdata->vss_cfgs[i].name; + + wm8994->vss_enum.max = pdata->num_vss_cfgs; + wm8994->vss_enum.texts = wm8994->vss_texts; + + ret = snd_soc_add_controls(wm8994->codec, control, 1); + if (ret != 0) + dev_err(wm8994->codec->dev, + "Failed to add VSS mode controls: %d\n", ret); + } + + if (pdata->num_vss_hpf_cfgs) { + struct snd_kcontrol_new control[] = { + SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum, + wm8958_get_vss_hpf_enum, + wm8958_put_vss_hpf_enum), + }; + + /* We need an array of texts for the enum API */ + wm8994->vss_hpf_texts = kmalloc(sizeof(char *) + * pdata->num_vss_hpf_cfgs, GFP_KERNEL); + if (!wm8994->vss_hpf_texts) { + dev_err(wm8994->codec->dev, + "Failed to allocate %d VSS HPF config texts\n", + pdata->num_vss_hpf_cfgs); + return; + } + + for (i = 0; i < pdata->num_vss_hpf_cfgs; i++) + wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name; + + wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs; + wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; + + ret = snd_soc_add_controls(wm8994->codec, control, 1); + if (ret != 0) + dev_err(wm8994->codec->dev, + "Failed to add VSS HPFmode controls: %d\n", + ret); + } + + if (pdata->num_enh_eq_cfgs) { + struct snd_kcontrol_new control[] = { + SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum, + wm8958_get_enh_eq_enum, + wm8958_put_enh_eq_enum), + }; + + /* We need an array of texts for the enum API */ + wm8994->enh_eq_texts = kmalloc(sizeof(char *) + * pdata->num_enh_eq_cfgs, GFP_KERNEL); + if (!wm8994->enh_eq_texts) { + dev_err(wm8994->codec->dev, + "Failed to allocate %d enhanced EQ config texts\n", + pdata->num_enh_eq_cfgs); + return; + } + + for (i = 0; i < pdata->num_enh_eq_cfgs; i++) + wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name; + + wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs; + wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; + + ret = snd_soc_add_controls(wm8994->codec, control, 1); + if (ret != 0) + dev_err(wm8994->codec->dev, + "Failed to add enhanced EQ controls: %d\n", + ret); + } +} diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 3b71dd65c966..f90ae427242b 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -58,6 +58,7 @@ struct wm8962_priv { int bclk; /* Desired BCLK */ int lrclk; + struct completion fll_lock; int fll_src; int fll_fref; int fll_fout; @@ -2038,6 +2039,13 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol, return 0; } +static const char *cap_hpf_mode_text[] = { + "Hi-fi", "Application" +}; + +static const struct soc_enum cap_hpf_mode = + SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text); + static const struct snd_kcontrol_new wm8962_snd_controls[] = { SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1), @@ -2063,6 +2071,9 @@ SOC_DOUBLE_R("Capture Switch", WM8962_LEFT_INPUT_VOLUME, WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1), SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME, WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1), +SOC_SINGLE("Capture HPF Switch", WM8962_ADC_DAC_CONTROL_1, 0, 1, 1), +SOC_ENUM("Capture HPF Mode", cap_hpf_mode), +SOC_SINGLE("Capture HPF Cutoff", WM8962_ADC_DAC_CONTROL_2, 7, 7, 0), SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1, WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv), @@ -2467,6 +2478,7 @@ SND_SOC_DAPM_INPUT("IN3R"), SND_SOC_DAPM_INPUT("IN4L"), SND_SOC_DAPM_INPUT("IN4R"), SND_SOC_DAPM_INPUT("Beep"), +SND_SOC_DAPM_INPUT("DMICDAT"), SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0), @@ -2486,6 +2498,8 @@ SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0, SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0, mixinr, ARRAY_SIZE(mixinr)), +SND_SOC_DAPM_AIF_IN("DMIC", NULL, 0, WM8962_PWR_MGMT_1, 10, 0), + SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0), SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0), @@ -2563,13 +2577,17 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = { { "MICBIAS", NULL, "SYSCLK" }, + { "DMIC", NULL, "DMICDAT" }, + { "ADCL", NULL, "SYSCLK" }, { "ADCL", NULL, "TOCLK" }, { "ADCL", NULL, "MIXINL" }, + { "ADCL", NULL, "DMIC" }, { "ADCR", NULL, "SYSCLK" }, { "ADCR", NULL, "TOCLK" }, { "ADCR", NULL, "MIXINR" }, + { "ADCR", NULL, "DMIC" }, { "STL", "Left", "ADCL" }, { "STL", "Right", "ADCR" }, @@ -2990,7 +3008,6 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, case WM8962_SYSCLK_FLL: wm8962->sysclk = WM8962_SYSCLK_FLL; src = 1 << WM8962_SYSCLK_SRC_SHIFT; - WARN_ON(freq != wm8962->fll_fout); break; default: return -EINVAL; @@ -3137,7 +3154,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, pr_debug("FLL Fvco=%dHz\n", target); - /* Find an appropraite FLL_FRATIO and factor it out of the target */ + /* Find an appropriate FLL_FRATIO and factor it out of the target */ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { fll_div->fll_fratio = fll_fratios[i].fll_fratio; @@ -3172,12 +3189,12 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, return 0; } -static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source, +static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, unsigned int Fref, unsigned int Fout) { - struct snd_soc_codec *codec = dai->codec; struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); struct _fll_div fll_div; + unsigned long timeout; int ret; int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA; @@ -3244,6 +3261,11 @@ static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source, dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); + /* This should be a massive overestimate */ + timeout = msecs_to_jiffies(1); + + wait_for_completion_timeout(&wm8962->fll_lock, timeout); + wm8962->fll_fref = Fref; wm8962->fll_fout = Fout; wm8962->fll_src = source; @@ -3274,7 +3296,6 @@ static struct snd_soc_dai_ops wm8962_dai_ops = { .hw_params = wm8962_hw_params, .set_sysclk = wm8962_set_dai_sysclk, .set_fmt = wm8962_set_dai_fmt, - .set_pll = wm8962_set_fll, .digital_mute = wm8962_mute, }; @@ -3340,6 +3361,11 @@ static irqreturn_t wm8962_irq(int irq, void *data) active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); active &= ~mask; + if (active & WM8962_FLL_LOCK_EINT) { + dev_dbg(codec->dev, "FLL locked\n"); + complete(&wm8962->fll_lock); + } + if (active & WM8962_FIFOS_ERR_EINT) dev_err(codec->dev, "FIFO error\n"); @@ -3709,9 +3735,11 @@ static int wm8962_probe(struct snd_soc_codec *codec) dev); u16 *reg_cache = codec->reg_cache; int i, trigger, irq_pol; + bool dmicclk, dmicdat; wm8962->codec = codec; INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work); + init_completion(&wm8962->fll_lock); codec->cache_sync = 1; codec->dapm.idle_bias_off = 1; @@ -3845,6 +3873,29 @@ static int wm8962_probe(struct snd_soc_codec *codec) wm8962_add_widgets(codec); + /* Save boards having to disable DMIC when not in use */ + dmicclk = false; + dmicdat = false; + for (i = 0; i < WM8962_MAX_GPIO; i++) { + switch (snd_soc_read(codec, WM8962_GPIO_BASE + i) + & WM8962_GP2_FN_MASK) { + case WM8962_GPIO_FN_DMICCLK: + dmicclk = true; + break; + case WM8962_GPIO_FN_DMICDAT: + dmicdat = true; + break; + default: + break; + } + } + if (!dmicclk || !dmicdat) { + dev_dbg(codec->dev, "DMIC not in use, disabling\n"); + snd_soc_dapm_nc_pin(&codec->dapm, "DMICDAT"); + } + if (dmicclk != dmicdat) + dev_warn(codec->dev, "DMIC GPIOs partially configured\n"); + wm8962_init_beep(codec); wm8962_init_gpio(codec); @@ -3868,9 +3919,10 @@ static int wm8962_probe(struct snd_soc_codec *codec) i2c->irq, ret); /* Non-fatal */ } else { - /* Enable error reporting IRQs by default */ + /* Enable some IRQs by default */ snd_soc_update_bits(codec, WM8962_INTERRUPT_STATUS_2_MASK, + WM8962_FLL_LOCK_EINT | WM8962_TEMP_SHUT_EINT | WM8962_FIFOS_ERR_EINT, 0); } @@ -3918,6 +3970,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8962 = { .reg_cache_default = wm8962_reg, .volatile_register = wm8962_volatile_register, .readable_register = wm8962_readable_register, + .set_pll = wm8962_set_fll, }; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 28fdfd66661d..3c2ee1bb73cd 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -981,7 +981,7 @@ static int wm8991_set_dai_pll(struct snd_soc_dai *codec_dai, reg = snd_soc_read(codec, WM8991_CLOCKING_2); snd_soc_write(codec, WM8991_CLOCKING_2, reg | WM8991_SYSCLK_SRC); - /* set up N , fractional mode and pre-divisor if neccessary */ + /* set up N , fractional mode and pre-divisor if necessary */ snd_soc_write(codec, WM8991_PLL1, pll_div.n | WM8991_SDM | (pll_div.div2 ? WM8991_PRESCALE : 0)); snd_soc_write(codec, WM8991_PLL2, (u8)(pll_div.k>>8)); diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 379fa22c5b6c..9e5ff789b805 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -324,7 +324,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, pr_debug("Fvco=%dHz\n", target); - /* Find an appropraite FLL_FRATIO and factor it out of the target */ + /* Find an appropriate FLL_FRATIO and factor it out of the target */ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { fll_div->fll_fratio = fll_fratios[i].fll_fratio; @@ -718,7 +718,8 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, static int class_w_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct snd_soc_codec *codec = widget->codec; struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); int ret; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 3dc64c8b6a5c..970a95c5360b 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -38,12 +38,6 @@ #include "wm8994.h" #include "wm_hubs.h" -struct fll_config { - int src; - int in; - int out; -}; - #define WM8994_NUM_DRC 3 #define WM8994_NUM_EQ 3 @@ -59,63 +53,11 @@ static int wm8994_retune_mobile_base[] = { WM8994_AIF2_EQ_GAINS_1, }; -struct wm8994_micdet { - struct snd_soc_jack *jack; - int det; - int shrt; -}; - -/* codec private data */ -struct wm8994_priv { - struct wm_hubs_data hubs; - enum snd_soc_control_type control_type; - void *control_data; - struct snd_soc_codec *codec; - int sysclk[2]; - int sysclk_rate[2]; - int mclk[2]; - int aifclk[2]; - struct fll_config fll[2], fll_suspend[2]; - - int dac_rates[2]; - int lrclk_shared[2]; - - int mbc_ena[3]; - - /* Platform dependant DRC configuration */ - const char **drc_texts; - int drc_cfg[WM8994_NUM_DRC]; - struct soc_enum drc_enum; - - /* Platform dependant ReTune mobile configuration */ - int num_retune_mobile_texts; - const char **retune_mobile_texts; - int retune_mobile_cfg[WM8994_NUM_EQ]; - struct soc_enum retune_mobile_enum; - - /* Platform dependant MBC configuration */ - int mbc_cfg; - const char **mbc_texts; - struct soc_enum mbc_enum; - - struct wm8994_micdet micdet[2]; - - wm8958_micdet_cb jack_cb; - void *jack_cb_data; - int micdet_irq; - - int revision; - struct wm8994_pdata *pdata; - - unsigned int aif1clk_enable:1; - unsigned int aif2clk_enable:1; - - unsigned int aif1clk_disable:1; - unsigned int aif2clk_disable:1; -}; - static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) { + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->control_data; + switch (reg) { case WM8994_GPIO_1: case WM8994_GPIO_2: @@ -132,6 +74,15 @@ static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) case WM8994_INTERRUPT_STATUS_2: case WM8994_INTERRUPT_RAW_STATUS_2: return 1; + + case WM8958_DSP2_PROGRAM: + case WM8958_DSP2_CONFIG: + case WM8958_DSP2_EXECCONTROL: + if (control->type == WM8958) + return 1; + else + return 0; + default: break; } @@ -574,215 +525,6 @@ static const struct soc_enum dac_osr = static const struct soc_enum adc_osr = SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text); -static void wm8958_mbc_apply(struct snd_soc_codec *codec, int mbc, int start) -{ - struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; - int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5); - int ena, reg, aif, i; - - switch (mbc) { - case 0: - pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA); - aif = 0; - break; - case 1: - pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA); - aif = 0; - break; - case 2: - pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA); - aif = 1; - break; - default: - BUG(); - return; - } - - /* We can only enable the MBC if the AIF is enabled and we - * want it to be enabled. */ - ena = pwr_reg && wm8994->mbc_ena[mbc]; - - reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM); - - dev_dbg(codec->dev, "MBC %d startup: %d, power: %x, DSP: %x\n", - mbc, start, pwr_reg, reg); - - if (start && ena) { - /* If the DSP is already running then noop */ - if (reg & WM8958_DSP2_ENA) - return; - - /* Switch the clock over to the appropriate AIF */ - snd_soc_update_bits(codec, WM8994_CLOCKING_1, - WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA, - aif << WM8958_DSP2CLK_SRC_SHIFT | - WM8958_DSP2CLK_ENA); - - snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, - WM8958_DSP2_ENA, WM8958_DSP2_ENA); - - /* If we've got user supplied MBC settings use them */ - if (pdata && pdata->num_mbc_cfgs) { - struct wm8958_mbc_cfg *cfg - = &pdata->mbc_cfgs[wm8994->mbc_cfg]; - - for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++) - snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1, - cfg->coeff_regs[i]); - - for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++) - snd_soc_write(codec, - i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1, - cfg->cutoff_regs[i]); - } - - /* Run the DSP */ - snd_soc_write(codec, WM8958_DSP2_EXECCONTROL, - WM8958_DSP2_RUNR); - - /* And we're off! */ - snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, - WM8958_MBC_ENA | WM8958_MBC_SEL_MASK, - mbc << WM8958_MBC_SEL_SHIFT | - WM8958_MBC_ENA); - } else { - /* If the DSP is already stopped then noop */ - if (!(reg & WM8958_DSP2_ENA)) - return; - - snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, - WM8958_MBC_ENA, 0); - snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, - WM8958_DSP2_ENA, 0); - snd_soc_update_bits(codec, WM8994_CLOCKING_1, - WM8958_DSP2CLK_ENA, 0); - } -} - -static int wm8958_aif_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - int mbc; - - switch (w->shift) { - case 13: - case 12: - mbc = 2; - break; - case 11: - case 10: - mbc = 1; - break; - case 9: - case 8: - mbc = 0; - break; - default: - BUG(); - return -EINVAL; - } - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - wm8958_mbc_apply(codec, mbc, 1); - break; - case SND_SOC_DAPM_POST_PMD: - wm8958_mbc_apply(codec, mbc, 0); - break; - } - - return 0; -} - -static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; - int value = ucontrol->value.integer.value[0]; - int reg; - - /* Don't allow on the fly reconfiguration */ - reg = snd_soc_read(codec, WM8994_CLOCKING_1); - if (reg < 0 || reg & WM8958_DSP2CLK_ENA) - return -EBUSY; - - if (value >= pdata->num_mbc_cfgs) - return -EINVAL; - - wm8994->mbc_cfg = value; - - return 0; -} - -static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg; - - return 0; -} - -static int wm8958_mbc_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int wm8958_mbc_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int mbc = kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - - ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc]; - - return 0; -} - -static int wm8958_mbc_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int mbc = kcontrol->private_value; - int i; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - - if (ucontrol->value.integer.value[0] > 1) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) { - if (mbc != i && wm8994->mbc_ena[i]) { - dev_dbg(codec->dev, "MBC %d active already\n", mbc); - return -EBUSY; - } - } - - wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0]; - - wm8958_mbc_apply(codec, mbc, wm8994->mbc_ena[mbc]); - - return 0; -} - -#define WM8958_MBC_SWITCH(xname, xval) {\ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .info = wm8958_mbc_info, \ - .get = wm8958_mbc_get, .put = wm8958_mbc_put, \ - .private_value = xval } - static const struct snd_kcontrol_new wm8994_snd_controls[] = { SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, WM8994_AIF1_ADC1_RIGHT_VOLUME, @@ -924,9 +666,6 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0, static const struct snd_kcontrol_new wm8958_snd_controls[] = { SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), -WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0), -WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1), -WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2), }; static int clk_sys_event(struct snd_soc_dapm_widget *w, @@ -1032,6 +771,9 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w, break; } + /* We may also have postponed startup of DSP, handle that. */ + wm8958_aif_ev(w, kcontrol, event); + return 0; } @@ -1135,7 +877,8 @@ static const char *hp_mux_text[] = { static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *w = wlist->widgets[0]; struct snd_soc_codec *codec = w->codec; int ret; @@ -1262,7 +1005,8 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *w = wlist->widgets[0]; struct snd_soc_codec *codec = w->codec; int ret; @@ -2180,6 +1924,8 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, WM8994_VMID_BUF_ENA | WM8994_VMID_RAMP_MASK, 0); + wm8994->cur_fw = NULL; + pm_runtime_put(codec->dev); } break; @@ -2672,11 +2418,22 @@ static struct snd_soc_dai_driver wm8994_dai[] = { static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = codec->control_data; int i, ret; + switch (control->type) { + case WM8994: + snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0); + break; + case WM8958: + snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, + WM8958_MICD_ENA, 0); + break; + } + for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], - sizeof(struct fll_config)); + sizeof(struct wm8994_fll_config)); ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0); if (ret < 0) dev_warn(codec->dev, "Failed to stop FLL%d: %d\n", @@ -2691,6 +2448,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state) static int wm8994_resume(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = codec->control_data; int i, ret; unsigned int val, mask; @@ -2729,6 +2487,19 @@ static int wm8994_resume(struct snd_soc_codec *codec) i + 1, ret); } + switch (control->type) { + case WM8994: + if (wm8994->micdet[0].jack || wm8994->micdet[1].jack) + snd_soc_update_bits(codec, WM8994_MICBIAS, + WM8994_MICD_ENA, WM8994_MICD_ENA); + break; + case WM8958: + if (wm8994->jack_cb) + snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, + WM8958_MICD_ENA, WM8958_MICD_ENA); + break; + } + return 0; } #else @@ -2862,34 +2633,6 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) dev_dbg(codec->dev, "%d ReTune Mobile configurations\n", pdata->num_retune_mobile_cfgs); - if (pdata->num_mbc_cfgs) { - struct snd_kcontrol_new control[] = { - SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum, - wm8958_get_mbc_enum, wm8958_put_mbc_enum), - }; - - /* We need an array of texts for the enum API */ - wm8994->mbc_texts = kmalloc(sizeof(char *) - * pdata->num_mbc_cfgs, GFP_KERNEL); - if (!wm8994->mbc_texts) { - dev_err(wm8994->codec->dev, - "Failed to allocate %d MBC config texts\n", - pdata->num_mbc_cfgs); - return; - } - - for (i = 0; i < pdata->num_mbc_cfgs; i++) - wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name; - - wm8994->mbc_enum.max = pdata->num_mbc_cfgs; - wm8994->mbc_enum.texts = wm8994->mbc_texts; - - ret = snd_soc_add_controls(wm8994->codec, control, 1); - if (ret != 0) - dev_err(wm8994->codec->dev, - "Failed to add MBC mode controls: %d\n", ret); - } - if (pdata->num_retune_mobile_cfgs) wm8994_handle_retune_mobile_pdata(wm8994); else @@ -3261,20 +3004,36 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch volume updates (right only; we always do left then right). */ + snd_soc_update_bits(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, + WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); + snd_soc_update_bits(codec, WM8994_AIF1_DAC2_LEFT_VOLUME, + WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU); snd_soc_update_bits(codec, WM8994_AIF1_DAC2_RIGHT_VOLUME, WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU); + snd_soc_update_bits(codec, WM8994_AIF2_DAC_LEFT_VOLUME, + WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU); snd_soc_update_bits(codec, WM8994_AIF2_DAC_RIGHT_VOLUME, WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU); + snd_soc_update_bits(codec, WM8994_AIF1_ADC1_LEFT_VOLUME, + WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU); snd_soc_update_bits(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME, WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU); + snd_soc_update_bits(codec, WM8994_AIF1_ADC2_LEFT_VOLUME, + WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU); snd_soc_update_bits(codec, WM8994_AIF1_ADC2_RIGHT_VOLUME, WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU); + snd_soc_update_bits(codec, WM8994_AIF2_ADC_LEFT_VOLUME, + WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU); snd_soc_update_bits(codec, WM8994_AIF2_ADC_RIGHT_VOLUME, WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU); + snd_soc_update_bits(codec, WM8994_DAC1_LEFT_VOLUME, + WM8994_DAC1_VU, WM8994_DAC1_VU); snd_soc_update_bits(codec, WM8994_DAC1_RIGHT_VOLUME, WM8994_DAC1_VU, WM8994_DAC1_VU); + snd_soc_update_bits(codec, WM8994_DAC2_LEFT_VOLUME, + WM8994_DAC2_VU, WM8994_DAC2_VU); snd_soc_update_bits(codec, WM8994_DAC2_RIGHT_VOLUME, WM8994_DAC2_VU, WM8994_DAC2_VU); @@ -3327,14 +3086,23 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) case WM8958: snd_soc_add_controls(codec, wm8958_snd_controls, ARRAY_SIZE(wm8958_snd_controls)); - snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets, - ARRAY_SIZE(wm8994_lateclk_widgets)); - snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets, - ARRAY_SIZE(wm8994_adc_widgets)); - snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets, - ARRAY_SIZE(wm8994_dac_widgets)); snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets, ARRAY_SIZE(wm8958_dapm_widgets)); + if (wm8994->revision < 1) { + snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, + ARRAY_SIZE(wm8994_lateclk_revd_widgets)); + snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets, + ARRAY_SIZE(wm8994_adc_revd_widgets)); + snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets, + ARRAY_SIZE(wm8994_dac_revd_widgets)); + } else { + snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets, + ARRAY_SIZE(wm8994_lateclk_widgets)); + snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets, + ARRAY_SIZE(wm8994_adc_widgets)); + snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets, + ARRAY_SIZE(wm8994_dac_widgets)); + } break; } @@ -3358,10 +3126,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) } break; case WM8958: - snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon, - ARRAY_SIZE(wm8994_lateclk_intercon)); - snd_soc_dapm_add_routes(dapm, wm8958_intercon, - ARRAY_SIZE(wm8958_intercon)); + if (wm8994->revision < 1) { + snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon, + ARRAY_SIZE(wm8994_revd_intercon)); + snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon, + ARRAY_SIZE(wm8994_lateclk_revd_intercon)); + } else { + snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon, + ARRAY_SIZE(wm8994_lateclk_intercon)); + snd_soc_dapm_add_routes(dapm, wm8958_intercon, + ARRAY_SIZE(wm8958_intercon)); + } + + wm8958_dsp2_init(codec); break; } @@ -3404,6 +3181,12 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) free_irq(wm8994->micdet_irq, wm8994); break; } + if (wm8994->mbc) + release_firmware(wm8994->mbc); + if (wm8994->mbc_vss) + release_firmware(wm8994->mbc_vss); + if (wm8994->enh_eq) + release_firmware(wm8994->enh_eq); kfree(wm8994->retune_mobile_texts); kfree(wm8994->drc_texts); kfree(wm8994); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 999b8851226b..0a1db04b73bd 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -10,6 +10,9 @@ #define _WM8994_H #include <sound/soc.h> +#include <linux/firmware.h> + +#include "wm_hubs.h" /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ #define WM8994_SYSCLK_MCLK1 1 @@ -45,4 +48,98 @@ struct wm8994_access_mask { extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE]; extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE]; +int wm8958_aif_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); + +void wm8958_dsp2_init(struct snd_soc_codec *codec); + +struct wm8994_micdet { + struct snd_soc_jack *jack; + int det; + int shrt; +}; + +/* codec private data */ +struct wm8994_fll_config { + int src; + int in; + int out; +}; + +#define WM8994_NUM_DRC 3 +#define WM8994_NUM_EQ 3 + +struct wm8994_priv { + struct wm_hubs_data hubs; + enum snd_soc_control_type control_type; + void *control_data; + struct snd_soc_codec *codec; + int sysclk[2]; + int sysclk_rate[2]; + int mclk[2]; + int aifclk[2]; + struct wm8994_fll_config fll[2], fll_suspend[2]; + + int dac_rates[2]; + int lrclk_shared[2]; + + int mbc_ena[3]; + int hpf1_ena[3]; + int hpf2_ena[3]; + int vss_ena[3]; + int enh_eq_ena[3]; + + /* Platform dependant DRC configuration */ + const char **drc_texts; + int drc_cfg[WM8994_NUM_DRC]; + struct soc_enum drc_enum; + + /* Platform dependant ReTune mobile configuration */ + int num_retune_mobile_texts; + const char **retune_mobile_texts; + int retune_mobile_cfg[WM8994_NUM_EQ]; + struct soc_enum retune_mobile_enum; + + /* Platform dependant MBC configuration */ + int mbc_cfg; + const char **mbc_texts; + struct soc_enum mbc_enum; + + /* Platform dependant VSS configuration */ + int vss_cfg; + const char **vss_texts; + struct soc_enum vss_enum; + + /* Platform dependant VSS HPF configuration */ + int vss_hpf_cfg; + const char **vss_hpf_texts; + struct soc_enum vss_hpf_enum; + + /* Platform dependant enhanced EQ configuration */ + int enh_eq_cfg; + const char **enh_eq_texts; + struct soc_enum enh_eq_enum; + + struct wm8994_micdet micdet[2]; + + wm8958_micdet_cb jack_cb; + void *jack_cb_data; + int micdet_irq; + + int revision; + struct wm8994_pdata *pdata; + + unsigned int aif1clk_enable:1; + unsigned int aif2clk_enable:1; + + unsigned int aif1clk_disable:1; + unsigned int aif2clk_disable:1; + + int dsp_active; + const struct firmware *cur_fw; + const struct firmware *mbc; + const struct firmware *mbc_vss; + const struct firmware *enh_eq; +}; + #endif diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 67eaaecbb42e..5ad873fda814 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -305,11 +305,11 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source, static int wm8995_put_class_w(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *w = wlist->widgets[0]; struct snd_soc_codec *codec; int ret; - w = snd_kcontrol_chip(kcontrol); codec = w->codec; ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); wm8995_update_class_w(codec); diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 55cdf2982020..91c6b39de50c 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -305,7 +305,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol, /* * Stop any attempts to change speaker mode while the speaker is enabled. * - * We also have some special anti-pop controls dependant on speaker + * We also have some special anti-pop controls dependent on speaker * mode which must be changed along with the mode. */ static int speaker_mode_put(struct snd_kcontrol *kcontrol, @@ -456,7 +456,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, pr_debug("Fvco=%dHz\n", target); - /* Find an appropraite FLL_FRATIO and factor it out of the target */ + /* Find an appropriate FLL_FRATIO and factor it out of the target */ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { fll_div->fll_fratio = fll_fratios[i].fll_fratio; diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 47b357adabdd..646b58dda849 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -142,7 +142,7 @@ static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = { * constantly enabled, we use the mutes on those inputs to simulate such * controls. */ -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm9705_audio_map[] = { /* HP mixer */ {"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"}, {"HP Mixer", "CD Playback Switch", "CD PGA"}, @@ -200,17 +200,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Right ADC", NULL, "ADC PGA"}, }; -static int wm9705_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm9705_dapm_widgets, - ARRAY_SIZE(wm9705_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - return 0; -} - /* We use a register cache to enhance read performance. */ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { @@ -364,7 +353,6 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, wm9705_snd_ac97_controls, ARRAY_SIZE(wm9705_snd_ac97_controls)); - wm9705_add_widgets(codec); return 0; @@ -390,6 +378,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = { .reg_word_size = sizeof(u16), .reg_cache_step = 2, .reg_cache_default = wm9705_reg, + .dapm_widgets = wm9705_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets), + .dapm_routes = wm9705_audio_map, + .num_dapm_routes = ARRAY_SIZE(wm9705_audio_map), }; static __devinit int wm9705_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index bf5d4ef1a2a6..90117f8156e8 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -332,7 +332,7 @@ SND_SOC_DAPM_INPUT("MIC1"), SND_SOC_DAPM_INPUT("MIC2"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm9712_audio_map[] = { /* virtual mixer - mixes left & right channels for spk and mono */ {"AC97 Mixer", NULL, "Left DAC"}, {"AC97 Mixer", NULL, "Right DAC"}, @@ -429,17 +429,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"ROUT2", NULL, "Speaker PGA"}, }; -static int wm9712_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm9712_dapm_widgets, - ARRAY_SIZE(wm9712_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - return 0; -} - static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { @@ -651,7 +640,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); snd_soc_add_controls(codec, wm9712_snd_ac97_controls, ARRAY_SIZE(wm9712_snd_ac97_controls)); - wm9712_add_widgets(codec); return 0; @@ -678,6 +666,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { .reg_word_size = sizeof(u16), .reg_cache_step = 2, .reg_cache_default = wm9712_reg, + .dapm_widgets = wm9712_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets), + .dapm_routes = wm9712_audio_map, + .num_dapm_routes = ARRAY_SIZE(wm9712_audio_map), }; static __devinit int wm9712_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 38ed98558718..7167cb6787db 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -487,7 +487,7 @@ SND_SOC_DAPM_INPUT("MIC2B"), SND_SOC_DAPM_VMID("VMID"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm9713_audio_map[] = { /* left HP mixer */ {"Left HP Mixer", "Beep Playback Switch", "PCBEEP"}, {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, @@ -644,18 +644,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Capture Mono Mux", "Right", "Right Capture Source"}, }; -static int wm9713_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm9713_dapm_widgets, - ARRAY_SIZE(wm9713_dapm_widgets)); - - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - return 0; -} - static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { @@ -1231,7 +1219,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) snd_soc_add_controls(codec, wm9713_snd_ac97_controls, ARRAY_SIZE(wm9713_snd_ac97_controls)); - wm9713_add_widgets(codec); return 0; @@ -1262,6 +1249,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { .reg_word_size = sizeof(u16), .reg_cache_step = 2, .reg_cache_default = wm9713_reg, + .dapm_widgets = wm9713_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), + .dapm_routes = wm9713_audio_map, + .num_dapm_routes = ARRAY_SIZE(wm9713_audio_map), }; static __devinit int wm9713_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 7b6b3c18e299..e55b298c14a0 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -740,12 +740,12 @@ static const struct snd_soc_dapm_route analogue_routes[] = { { "SPKL", "Input Switch", "MIXINL" }, { "SPKL", "IN1LP Switch", "IN1LP" }, - { "SPKL", "Output Switch", "Left Output Mixer" }, + { "SPKL", "Output Switch", "Left Output PGA" }, { "SPKL", NULL, "TOCLK" }, { "SPKR", "Input Switch", "MIXINR" }, { "SPKR", "IN1RP Switch", "IN1RP" }, - { "SPKR", "Output Switch", "Right Output Mixer" }, + { "SPKR", "Output Switch", "Right Output PGA" }, { "SPKR", NULL, "TOCLK" }, { "SPKL Boost", "Direct Voice Switch", "Direct Voice" }, @@ -767,8 +767,8 @@ static const struct snd_soc_dapm_route analogue_routes[] = { { "SPKOUTRP", NULL, "SPKR Driver" }, { "SPKOUTRN", NULL, "SPKR Driver" }, - { "Left Headphone Mux", "Mixer", "Left Output Mixer" }, - { "Right Headphone Mux", "Mixer", "Right Output Mixer" }, + { "Left Headphone Mux", "Mixer", "Left Output PGA" }, + { "Right Headphone Mux", "Mixer", "Right Output PGA" }, { "Headphone PGA", NULL, "Left Headphone Mux" }, { "Headphone PGA", NULL, "Right Headphone Mux" }, @@ -787,17 +787,17 @@ static const struct snd_soc_dapm_route analogue_routes[] = { static const struct snd_soc_dapm_route lineout1_diff_routes[] = { { "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" }, { "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" }, - { "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" }, + { "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" }, { "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" }, { "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" }, }; static const struct snd_soc_dapm_route lineout1_se_routes[] = { - { "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" }, - { "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" }, + { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" }, + { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" }, - { "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" }, + { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, { "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" }, @@ -806,17 +806,17 @@ static const struct snd_soc_dapm_route lineout1_se_routes[] = { static const struct snd_soc_dapm_route lineout2_diff_routes[] = { { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" }, { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" }, - { "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" }, + { "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" }, { "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" }, }; static const struct snd_soc_dapm_route lineout2_se_routes[] = { - { "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" }, - { "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" }, + { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" }, + { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" }, - { "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" }, + { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, { "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" }, @@ -836,17 +836,21 @@ int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, WM8993_IN2_VU, WM8993_IN2_VU); + snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_LEFT, + WM8993_SPKOUT_VU, WM8993_SPKOUT_VU); snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT, WM8993_SPKOUT_VU, WM8993_SPKOUT_VU); snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME, - WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC); + WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC, + WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC); snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME, WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC, WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC); snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME, - WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC); + WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU, + WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU); snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME, WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU, WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU); diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index a5af834c8ef5..8566238db2a5 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -434,17 +434,21 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); - mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x7 << 26)); + mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, + ACLKX | AHCLKX | AFSX); break; case SND_SOC_DAIFMT_CBM_CFS: /* codec is clock master and frame slave */ - mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE); - mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); - mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x2d << 26)); + mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, + ACLKX | ACLKR); + mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, + AFSX | AFSR); break; case SND_SOC_DAIFMT_CBM_CFM: /* codec is clock and frame master */ @@ -454,7 +458,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); - mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, (0x3f << 26)); + mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, + ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); break; default: @@ -644,7 +649,7 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask); mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD); - if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32)) + if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32)) mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXMOD(dev->tdm_slots), FSXMOD(0x1FF)); else @@ -660,7 +665,7 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) AHCLKRE); mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask); - if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32)) + if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32)) mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRMOD(dev->tdm_slots), FSRMOD(0x1FF)); else @@ -904,6 +909,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; + dma_data->sram_size = pdata->sram_size_playback; dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + mem->start); @@ -920,6 +926,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; + dma_data->sram_size = pdata->sram_size_capture; dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + mem->start); diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 13e05a302a92..9259f1f34899 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -205,7 +205,7 @@ static struct snd_soc_dai_driver davinci_vcif_dai = { static int davinci_vcif_probe(struct platform_device *pdev) { - struct davinci_vc *davinci_vc = mfd_get_data(pdev); + struct davinci_vc *davinci_vc = pdev->dev.platform_data; struct davinci_vcif_dev *davinci_vcif_dev; int ret; diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c index 671ef8dd524c..aab7765f401a 100644 --- a/sound/soc/imx/imx-pcm-dma-mx2.c +++ b/sound/soc/imx/imx-pcm-dma-mx2.c @@ -110,12 +110,12 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream, slave_config.direction = DMA_TO_DEVICE; slave_config.dst_addr = dma_params->dma_addr; slave_config.dst_addr_width = buswidth; - slave_config.dst_maxburst = dma_params->burstsize; + slave_config.dst_maxburst = dma_params->burstsize * buswidth; } else { slave_config.direction = DMA_FROM_DEVICE; slave_config.src_addr = dma_params->dma_addr; slave_config.src_addr_width = buswidth; - slave_config.src_maxburst = dma_params->burstsize; + slave_config.src_maxburst = dma_params->burstsize * buswidth; } ret = dmaengine_slave_config(iprtd->dma_chan, &slave_config); @@ -303,6 +303,11 @@ static struct snd_soc_platform_driver imx_soc_platform_mx2 = { static int __devinit imx_soc_platform_probe(struct platform_device *pdev) { + struct imx_ssi *ssi = platform_get_drvdata(pdev); + + ssi->dma_params_tx.burstsize = 6; + ssi->dma_params_rx.burstsize = 4; + return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2); } diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index bc92ec620004..5b13feca7537 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -16,7 +16,7 @@ * sane processor vendors have a FIFO per AC97 slot, the i.MX has only * one FIFO which combines all valid receive slots. We cannot even select * which slots we want to receive. The WM9712 with which this driver - * was developped with always sends GPIO status data in slot 12 which + * was developed with always sends GPIO status data in slot 12 which * we receive in our (PCM-) data stream. The only chance we have is to * manually skip this data in the FIQ handler. With sampling rates different * from 48000Hz not every frame has valid receive data, so the ratio @@ -667,12 +667,6 @@ static int imx_ssi_probe(struct platform_device *pdev) if (res) ssi->dma_params_rx.dma = res->start; - if ((cpu_is_mx27() || cpu_is_mx21()) && - !(ssi->flags & IMX_SSI_USE_AC97) && - (ssi->flags & IMX_SSI_DMA)) { - ssi->flags |= IMX_SSI_DMA; - } - platform_set_drvdata(pdev, ssi); ret = snd_soc_register_dai(&pdev->dev, dai); diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h index a4406a134892..dc8a87530e3e 100644 --- a/sound/soc/imx/imx-ssi.h +++ b/sound/soc/imx/imx-ssi.h @@ -234,7 +234,4 @@ void imx_pcm_free(struct snd_pcm *pcm); */ #define IMX_SSI_DMABUF_SIZE (64 * 1024) -#define DMA_RXFIFO_BURST 0x4 -#define DMA_TXFIFO_BURST 0x6 - #endif /* _IMX_SSI_H */ diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 419bf4f5534a..cd22a54b2f14 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -133,7 +133,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); uint32_t conf; - if (!dai->active) + if (dai->active) return; conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c index 49723e3e7e38..c5fc339f68f1 100644 --- a/sound/soc/jz4740/qi_lb60.c +++ b/sound/soc/jz4740/qi_lb60.c @@ -27,11 +27,7 @@ static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *ctrl, int event) { - int on = 0; - if (event & SND_SOC_DAPM_POST_PMU) - on = 1; - else if (event & SND_SOC_DAPM_PRE_PMD) - on = 0; + int on = !SND_SOC_DAPM_EVENT_OFF(event); gpio_set_value(QI_LB60_SND_GPIO, on); gpio_set_value(QI_LB60_AMP_GPIO, on); @@ -70,12 +66,6 @@ static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } - snd_soc_dapm_new_controls(dapm, qi_lb60_widgets, - ARRAY_SIZE(qi_lb60_widgets)); - snd_soc_dapm_add_routes(dapm, qi_lb60_routes, - ARRAY_SIZE(qi_lb60_routes)); - snd_soc_dapm_sync(dapm); - return 0; } @@ -93,10 +83,20 @@ static struct snd_soc_card qi_lb60 = { .name = "QI LB60", .dai_link = &qi_lb60_dai, .num_links = 1, + + .dapm_widgets = qi_lb60_widgets, + .num_dapm_widgets = ARRAY_SIZE(qi_lb60_widgets), + .dapm_routes = qi_lb60_routes, + .num_dapm_routes = ARRAY_SIZE(qi_lb60_routes), }; static struct platform_device *qi_lb60_snd_device; +static const struct gpio qi_lb60_gpios[] = { + { QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" }, + { QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" }, +}; + static int __init qi_lb60_init(void) { int ret; @@ -106,23 +106,12 @@ static int __init qi_lb60_init(void) if (!qi_lb60_snd_device) return -ENOMEM; - ret = gpio_request(QI_LB60_SND_GPIO, "SND"); + ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); if (ret) { - pr_err("qi_lb60 snd: Failed to request SND GPIO(%d): %d\n", - QI_LB60_SND_GPIO, ret); + pr_err("qi_lb60 snd: Failed to request gpios: %d\n", ret); goto err_device_put; } - ret = gpio_request(QI_LB60_AMP_GPIO, "AMP"); - if (ret) { - pr_err("qi_lb60 snd: Failed to request AMP GPIO(%d): %d\n", - QI_LB60_AMP_GPIO, ret); - goto err_gpio_free_snd; - } - - gpio_direction_output(QI_LB60_SND_GPIO, 0); - gpio_direction_output(QI_LB60_AMP_GPIO, 0); - platform_set_drvdata(qi_lb60_snd_device, &qi_lb60); ret = platform_device_add(qi_lb60_snd_device); @@ -135,10 +124,8 @@ static int __init qi_lb60_init(void) err_unset_pdata: platform_set_drvdata(qi_lb60_snd_device, NULL); -/*err_gpio_free_amp:*/ - gpio_free(QI_LB60_AMP_GPIO); -err_gpio_free_snd: - gpio_free(QI_LB60_SND_GPIO); +/*err_gpio_free_array:*/ + gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); err_device_put: platform_device_put(qi_lb60_snd_device); @@ -148,9 +135,8 @@ module_init(qi_lb60_init); static void __exit qi_lb60_exit(void) { - gpio_free(QI_LB60_AMP_GPIO); - gpio_free(QI_LB60_SND_GPIO); platform_device_unregister(qi_lb60_snd_device); + gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); } module_exit(qi_lb60_exit); diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index 0fd6a630db01..e13c6ce46328 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -132,7 +132,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) priv = snd_soc_dai_get_dma_data(cpu_dai, substream); snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw); - /* Ensure that all constraints linked to dma burst are fullfilled */ + /* Ensure that all constraints linked to dma burst are fulfilled */ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, priv->burst * 2, @@ -170,7 +170,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) /* * Enable Error interrupts. We're only ack'ing them but - * it's usefull for diagnostics + * it's useful for diagnostics */ writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK); } diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index ee2c22475a76..5a946b4115a2 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -116,18 +116,20 @@ struct snd_soc_dai_driver sst_platform_dai[] = { static inline void sst_set_stream_status(struct sst_runtime_stream *stream, int state) { - spin_lock(&stream->status_lock); + unsigned long flags; + spin_lock_irqsave(&stream->status_lock, flags); stream->stream_status = state; - spin_unlock(&stream->status_lock); + spin_unlock_irqrestore(&stream->status_lock, flags); } static inline int sst_get_stream_status(struct sst_runtime_stream *stream) { int state; + unsigned long flags; - spin_lock(&stream->status_lock); + spin_lock_irqsave(&stream->status_lock, flags); state = stream->stream_status; - spin_unlock(&stream->status_lock); + spin_unlock_irqrestore(&stream->status_lock, flags); return state; } @@ -247,10 +249,13 @@ static int sst_platform_open(struct snd_pcm_substream *substream) return -ENOMEM; } stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID; + stream->sstdrv_ops->module_name = SST_CARD_NAMES; /* registering with SST driver to get access to SST APIs to use */ ret_val = register_sst_card(stream->sstdrv_ops); if (ret_val) { pr_err("sst: sst card registration failed\n"); + kfree(stream->sstdrv_ops); + kfree(stream); return ret_val; } runtime->private_data = stream; @@ -268,6 +273,7 @@ static int sst_platform_close(struct snd_pcm_substream *substream) str_id = stream->stream_info.str_id; if (str_id) ret_val = stream->sstdrv_ops->pcm_control->close(str_id); + unregister_sst_card(stream->sstdrv_ops); kfree(stream->sstdrv_ops); kfree(stream); return ret_val; @@ -374,6 +380,11 @@ static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } +static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + static struct snd_pcm_ops sst_platform_ops = { .open = sst_platform_open, .close = sst_platform_close, @@ -382,6 +393,7 @@ static struct snd_pcm_ops sst_platform_ops = { .trigger = sst_platform_pcm_trigger, .pointer = sst_platform_pcm_pointer, .hw_params = sst_platform_pcm_hw_params, + .hw_free = sst_platform_pcm_hw_free, }; static void sst_pcm_free(struct snd_pcm *pcm) @@ -440,7 +452,7 @@ static int sst_platform_remove(struct platform_device *pdev) snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai)); snd_soc_unregister_platform(&pdev->dev); - pr_debug("sst_platform_remove sucess\n"); + pr_debug("sst_platform_remove success\n"); return 0; } @@ -463,7 +475,7 @@ module_init(sst_soc_platform_init); static void __exit sst_soc_platform_exit(void) { platform_driver_unregister(&sst_platform_driver); - pr_debug("sst_soc_platform_exit sucess\n"); + pr_debug("sst_soc_platform_exit success\n"); } module_exit(sst_soc_platform_exit); diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index b5922984eac6..99054cf1f68f 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -65,14 +65,6 @@ config SND_OMAP_SOC_OVERO Say Y if you want to add support for SoC audio on the Gumstix Overo or CompuLab CM-T35 -config SND_OMAP_SOC_OMAP2EVM - tristate "SoC Audio support for OMAP2EVM board" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP2EVM - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the omap2evm board. - config SND_OMAP_SOC_OMAP3EVM tristate "SoC Audio support for OMAP3EVM board" depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index ba9fc650db28..6c2c87eed5bb 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -13,7 +13,6 @@ snd-soc-rx51-objs := rx51.o snd-soc-ams-delta-objs := ams-delta.o snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o -snd-soc-omap2evm-objs := omap2evm.o snd-soc-omap3evm-objs := omap3evm.o snd-soc-am3517evm-objs := am3517evm.o snd-soc-sdp3430-objs := sdp3430.o diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 3167be689621..462cbcbea74a 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -248,7 +248,7 @@ static struct snd_soc_jack_pin ams_delta_hook_switch_pins[] = { */ /* To actually apply any modem controlled configuration changes to the codec, - * we must connect codec DAI pins to the modem for a moment. Be carefull not + * we must connect codec DAI pins to the modem for a moment. Be careful not * to interfere with our digital mute function that shares the same hardware. */ static struct timer_list cx81801_timer; static bool cx81801_cmd_pending; @@ -402,9 +402,9 @@ static struct tty_ldisc_ops cx81801_ops = { /* - * Even if not very usefull, the sound card can still work without any of the + * Even if not very useful, the sound card can still work without any of the * above functonality activated. You can still control its audio input/output - * constellation and speakerphone gain from userspace by issueing AT commands + * constellation and speakerphone gain from userspace by issuing AT commands * over the modem port. */ diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 2175f09e57b6..07b772357244 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -4,7 +4,7 @@ * Copyright (C) 2008 Nokia Corporation * * Contact: Jarkko Nikula <jhnikula@gmail.com> - * Peter Ujfalusi <peter.ujfalusi@nokia.com> + * Peter Ujfalusi <peter.ujfalusi@ti.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -146,7 +146,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) */ - if (cpu_is_omap343x() || cpu_is_omap44xx()) { + if (cpu_is_omap34xx() || cpu_is_omap44xx()) { /* * Rule for the buffer size. We should not allow * smaller buffer than the FIFO size to avoid underruns @@ -258,7 +258,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } - if (cpu_is_omap343x()) { + if (cpu_is_omap34xx()) { dma_data->set_threshold = omap_mcbsp_set_threshold; /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ if (omap_mcbsp_get_dma_op_mode(bus_id) == diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index 37dc7211ed3f..9a7dedd6f5a9 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h @@ -4,7 +4,7 @@ * Copyright (C) 2008 Nokia Corporation * * Contact: Jarkko Nikula <jhnikula@gmail.com> - * Peter Ujfalusi <peter.ujfalusi@nokia.com> + * Peter Ujfalusi <peter.ujfalusi@ti.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 8caeb8d305c3..e6a6b991d05f 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -4,7 +4,7 @@ * Copyright (C) 2008 Nokia Corporation * * Contact: Jarkko Nikula <jhnikula@gmail.com> - * Peter Ujfalusi <peter.ujfalusi@nokia.com> + * Peter Ujfalusi <peter.ujfalusi@ti.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -37,7 +37,8 @@ static const struct snd_pcm_hardware omap_pcm_hardware = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .period_bytes_min = 32, @@ -195,7 +196,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) if ((cpu_is_omap1510())) omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ | OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ); - else + else if (!substream->runtime->no_period_wakeup) omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); if (!(cpu_class_is_omap1())) { diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h index fea0515331fb..a0ed1dbb52d6 100644 --- a/sound/soc/omap/omap-pcm.h +++ b/sound/soc/omap/omap-pcm.h @@ -4,7 +4,7 @@ * Copyright (C) 2008 Nokia Corporation * * Contact: Jarkko Nikula <jhnikula@gmail.com> - * Peter Ujfalusi <peter.ujfalusi@nokia.com> + * Peter Ujfalusi <peter.ujfalusi@ti.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c deleted file mode 100644 index 29b60d6796e7..000000000000 --- a/sound/soc/omap/omap2evm.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * omap2evm.c -- SoC audio machine driver for omap2evm board - * - * Author: Arun KS <arunks@mistralsolutions.com> - * - * Based on sound/soc/omap/overo.c by Steve Sakoman - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <plat/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" - -static int omap2evm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops omap2evm_ops = { - .hw_params = omap2evm_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap2evm_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai_name = "omap-mcbsp-dai.1", - .codec_dai_name = "twl4030-hifi", - .platform_name = "omap-pcm-audio", - .codec_name = "twl4030-codec", - .ops = &omap2evm_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_omap2evm = { - .name = "omap2evm", - .dai_link = &omap2evm_dai, - .num_links = 1, -}; - -static struct platform_device *omap2evm_snd_device; - -static int __init omap2evm_soc_init(void) -{ - int ret; - - if (!machine_is_omap2evm()) - return -ENODEV; - printk(KERN_INFO "omap2evm SoC init\n"); - - omap2evm_snd_device = platform_device_alloc("soc-audio", -1); - if (!omap2evm_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(omap2evm_snd_device, &snd_soc_omap2evm); - - ret = platform_device_add(omap2evm_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(omap2evm_snd_device); - - return ret; -} -module_init(omap2evm_soc_init); - -static void __exit omap2evm_soc_exit(void) -{ - platform_device_unregister(omap2evm_snd_device); -} -module_exit(omap2evm_soc_exit); - -MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); -MODULE_DESCRIPTION("ALSA SoC omap2evm"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index d0986220eff9..0aae998b6540 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 - 2009 Nokia Corporation * - * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com> + * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com> * Eduardo Valentin <eduardo.valentin@nokia.com> * Jarkko Nikula <jhnikula@gmail.com> * diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 580f48571303..33ebc46b45b5 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -155,6 +155,15 @@ config SND_SOC_RAUMFELD help Say Y if you want to add support for SoC audio on Raumfeld devices +config SND_PXA2XX_SOC_HX4700 + tristate "SoC Audio support for HP iPAQ hx4700" + depends on SND_PXA2XX_SOC && MACH_H4700 + select SND_PXA2XX_SOC_I2S + select SND_SOC_AK4641 + help + Say Y if you want to add support for SoC audio on the + HP iPAQ hx4700. + config SND_PXA2XX_SOC_MAGICIAN tristate "SoC Audio support for HTC Magician" depends on SND_PXA2XX_SOC && MACH_MAGICIAN diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 07660165ec8d..af357623be9d 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -22,6 +22,7 @@ snd-soc-palm27x-objs := palm27x.o snd-soc-saarb-objs := saarb.o snd-soc-tavorevb3-objs := tavorevb3.o snd-soc-zylonite-objs := zylonite.o +snd-soc-hx4700-objs := hx4700.o snd-soc-magician-objs := magician.o snd-soc-mioa701-objs := mioa701_wm9713.o snd-soc-z2-objs := z2.o @@ -37,6 +38,7 @@ obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o +obj-$(CONFIG_SND_PXA2XX_SOC_HX4700) += snd-soc-hx4700.o obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 784cff5f67e8..28757fb9df31 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -310,7 +310,7 @@ static struct snd_soc_dai_link corgi_dai = { .cpu_dai_name = "pxa2xx-i2s", .codec_dai_name = "wm8731-hifi", .platform_name = "pxa-pcm-audio", - .codec_name = "wm8731-codec-0.001b", + .codec_name = "wm8731.0-001b", .init = corgi_wm8731_init, .ops = &corgi_ops, }; diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c new file mode 100644 index 000000000000..65c124831a00 --- /dev/null +++ b/sound/soc/pxa/hx4700.c @@ -0,0 +1,255 @@ +/* + * SoC audio for HP iPAQ hx4700 + * + * Copyright (c) 2009 Philipp Zabel + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/gpio.h> + +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include <mach/hx4700.h> +#include <asm/mach-types.h> +#include "pxa2xx-i2s.h" + +#include "../codecs/ak4641.h" + +static struct snd_soc_jack hs_jack; + +/* Headphones jack detection DAPM pin */ +static struct snd_soc_jack_pin hs_jack_pin[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Speaker", + /* disable speaker when hp jack is inserted */ + .mask = SND_JACK_HEADPHONE, + .invert = 1, + }, +}; + +/* Headphones jack detection GPIO */ +static struct snd_soc_jack_gpio hs_jack_gpio = { + .gpio = GPIO75_HX4700_EARPHONE_nDET, + .invert = true, + .name = "hp-gpio", + .report = SND_JACK_HEADPHONE, + .debounce_time = 200, +}; + +/* + * iPAQ hx4700 uses I2S for capture and playback. + */ +static int hx4700_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set the I2S system clock as output */ + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, + SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + + /* inform codec driver about clock freq * + * (PXA I2S always uses divider 256) */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 256 * params_rate(params), + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops hx4700_ops = { + .hw_params = hx4700_hw_params, +}; + +static int hx4700_spk_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + gpio_set_value(GPIO107_HX4700_SPK_nSD, !!SND_SOC_DAPM_EVENT_ON(event)); + return 0; +} + +static int hx4700_hp_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + gpio_set_value(GPIO92_HX4700_HP_DRIVER, !!SND_SOC_DAPM_EVENT_ON(event)); + return 0; +} + +/* hx4700 machine dapm widgets */ +static const struct snd_soc_dapm_widget hx4700_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", hx4700_hp_power), + SND_SOC_DAPM_SPK("Speaker", hx4700_spk_power), + SND_SOC_DAPM_MIC("Built-in Microphone", NULL), +}; + +/* hx4700 machine audio_map */ +static const struct snd_soc_dapm_route hx4700_audio_map[] = { + + /* Headphone connected to LOUT, ROUT */ + {"Headphone Jack", NULL, "LOUT"}, + {"Headphone Jack", NULL, "ROUT"}, + + /* Speaker connected to MOUT2 */ + {"Speaker", NULL, "MOUT2"}, + + /* Microphone connected to MICIN */ + {"MICIN", NULL, "Built-in Microphone"}, + {"AIN", NULL, "MICOUT"}, +}; + +/* + * Logic for a ak4641 as connected on a HP iPAQ hx4700 + */ +static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + int err; + + /* NC codec pins */ + /* FIXME: is anything connected here? */ + snd_soc_dapm_nc_pin(dapm, "MOUT1"); + snd_soc_dapm_nc_pin(dapm, "MICEXT"); + snd_soc_dapm_nc_pin(dapm, "AUX"); + + /* Jack detection API stuff */ + err = snd_soc_jack_new(codec, "Headphone Jack", + SND_JACK_HEADPHONE, &hs_jack); + if (err) + return err; + + err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin), + hs_jack_pin); + if (err) + return err; + + err = snd_soc_jack_add_gpios(&hs_jack, 1, &hs_jack_gpio); + + return err; +} + +/* hx4700 digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link hx4700_dai = { + .name = "ak4641", + .stream_name = "AK4641", + .cpu_dai_name = "pxa2xx-i2s", + .codec_dai_name = "ak4641-hifi", + .platform_name = "pxa-pcm-audio", + .codec_name = "ak4641.0-0012", + .init = hx4700_ak4641_init, + .ops = &hx4700_ops, +}; + +/* hx4700 audio machine driver */ +static struct snd_soc_card snd_soc_card_hx4700 = { + .name = "iPAQ hx4700", + .dai_link = &hx4700_dai, + .num_links = 1, + .dapm_widgets = hx4700_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(hx4700_dapm_widgets), + .dapm_routes = hx4700_audio_map, + .num_dapm_routes = ARRAY_SIZE(hx4700_audio_map), +}; + +static struct gpio hx4700_audio_gpios[] = { + { GPIO107_HX4700_SPK_nSD, GPIOF_OUT_INIT_HIGH, "SPK_POWER" }, + { GPIO92_HX4700_HP_DRIVER, GPIOF_OUT_INIT_LOW, "EP_POWER" }, +}; + +static int __devinit hx4700_audio_probe(struct platform_device *pdev) +{ + int ret; + + if (!machine_is_h4700()) + return -ENODEV; + + ret = gpio_request_array(hx4700_audio_gpios, + ARRAY_SIZE(hx4700_audio_gpios)); + if (ret) + return ret; + + snd_soc_card_hx4700.dev = &pdev->dev; + ret = snd_soc_register_card(&snd_soc_card_hx4700); + if (ret) + return ret; + + return 0; +} + +static int __devexit hx4700_audio_remove(struct platform_device *pdev) +{ + snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio); + snd_soc_unregister_card(&snd_soc_card_hx4700); + + gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0); + gpio_set_value(GPIO107_HX4700_SPK_nSD, 0); + + gpio_free_array(hx4700_audio_gpios, ARRAY_SIZE(hx4700_audio_gpios)); + return 0; +} + +static struct platform_driver hx4700_audio_driver = { + .driver = { + .name = "hx4700-audio", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = hx4700_audio_probe, + .remove = __devexit_p(hx4700_audio_remove), +}; + +static int __init hx4700_modinit(void) +{ + return platform_driver_register(&hx4700_audio_driver); +} +module_init(hx4700_modinit); + +static void __exit hx4700_modexit(void) +{ + platform_driver_unregister(&hx4700_audio_driver); +} + +module_exit(hx4700_modexit); + +MODULE_AUTHOR("Philipp Zabel"); +MODULE_DESCRIPTION("ALSA SoC iPAQ hx4700"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:hx4700-audio"); diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index a7d4999f9b24..da3ae4316cf2 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -276,7 +276,7 @@ static struct snd_soc_dai_link poodle_dai = { .cpu_dai_name = "pxa2xx-i2s", .codec_dai_name = "wm8731-hifi", .platform_name = "pxa-pcm-audio", - .codec_name = "wm8731-codec.0-001b", + .codec_name = "wm8731.0-001b", .init = poodle_wm8731_init, .ops = &poodle_ops, }; diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 02fb66416ddc..2ce0b2d891d5 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -65,6 +65,7 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) if (prtd->dma_ch >= 0) { pxa_free_dma(prtd->dma_ch); prtd->dma_ch = -1; + prtd->params = NULL; } return 0; diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c index 2afabaf59491..1a591f1ebfbd 100644 --- a/sound/soc/pxa/raumfeld.c +++ b/sound/soc/pxa/raumfeld.c @@ -151,13 +151,13 @@ static struct snd_soc_ops raumfeld_cs4270_ops = { .hw_params = raumfeld_cs4270_hw_params, }; -static int raumfeld_line_suspend(struct snd_soc_card *card) +static int raumfeld_analog_suspend(struct snd_soc_card *card) { raumfeld_enable_audio(false); return 0; } -static int raumfeld_line_resume(struct snd_soc_card *card) +static int raumfeld_analog_resume(struct snd_soc_card *card) { raumfeld_enable_audio(true); return 0; @@ -225,32 +225,53 @@ static struct snd_soc_ops raumfeld_ak4104_ops = { .hw_params = raumfeld_ak4104_hw_params, }; -static struct snd_soc_dai_link raumfeld_dai[] = { +#define DAI_LINK_CS4270 \ +{ \ + .name = "CS4270", \ + .stream_name = "CS4270", \ + .cpu_dai_name = "pxa-ssp-dai.0", \ + .platform_name = "pxa-pcm-audio", \ + .codec_dai_name = "cs4270-hifi", \ + .codec_name = "cs4270-codec.0-0048", \ + .ops = &raumfeld_cs4270_ops, \ +} + +#define DAI_LINK_AK4104 \ +{ \ + .name = "ak4104", \ + .stream_name = "Playback", \ + .cpu_dai_name = "pxa-ssp-dai.1", \ + .codec_dai_name = "ak4104-hifi", \ + .platform_name = "pxa-pcm-audio", \ + .ops = &raumfeld_ak4104_ops, \ + .codec_name = "spi0.0", \ +} + +static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] = { - .name = "ak4104", - .stream_name = "Playback", - .cpu_dai_name = "pxa-ssp-dai.1", - .codec_dai_name = "ak4104-hifi", - .platform_name = "pxa-pcm-audio", - .ops = &raumfeld_ak4104_ops, - .codec_name = "ak4104-codec.0", -}, + DAI_LINK_CS4270, + DAI_LINK_AK4104, +}; + +static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] = { - .name = "CS4270", - .stream_name = "CS4270", - .cpu_dai_name = "pxa-ssp-dai.0", - .platform_name = "pxa-pcm-audio", - .codec_dai_name = "cs4270-hifi", - .codec_name = "cs4270-codec.0-0048", - .ops = &raumfeld_cs4270_ops, -},}; - -static struct snd_soc_card snd_soc_raumfeld = { - .name = "Raumfeld", - .dai_link = raumfeld_dai, - .suspend_post = raumfeld_line_suspend, - .resume_pre = raumfeld_line_resume, - .num_links = ARRAY_SIZE(raumfeld_dai), + DAI_LINK_CS4270, +}; + +static struct snd_soc_card snd_soc_raumfeld_connector = { + .name = "Raumfeld Connector", + .dai_link = snd_soc_raumfeld_connector_dai, + .num_links = ARRAY_SIZE(snd_soc_raumfeld_connector_dai), + .suspend_post = raumfeld_analog_suspend, + .resume_pre = raumfeld_analog_resume, +}; + +static struct snd_soc_card snd_soc_raumfeld_speaker = { + .name = "Raumfeld Speaker", + .dai_link = snd_soc_raumfeld_speaker_dai, + .num_links = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai), + .suspend_post = raumfeld_analog_suspend, + .resume_pre = raumfeld_analog_resume, }; static struct platform_device *raumfeld_audio_device; @@ -271,22 +292,25 @@ static int __init raumfeld_audio_init(void) set_max9485_clk(MAX9485_MCLK_FREQ_122880); - /* Register LINE and SPDIF */ + /* Register analog device */ raumfeld_audio_device = platform_device_alloc("soc-audio", 0); if (!raumfeld_audio_device) return -ENOMEM; - platform_set_drvdata(raumfeld_audio_device, - &snd_soc_raumfeld); - ret = platform_device_add(raumfeld_audio_device); - - /* no S/PDIF on Speakers */ if (machine_is_raumfeld_speaker()) + platform_set_drvdata(raumfeld_audio_device, + &snd_soc_raumfeld_speaker); + + if (machine_is_raumfeld_connector()) + platform_set_drvdata(raumfeld_audio_device, + &snd_soc_raumfeld_connector); + + ret = platform_device_add(raumfeld_audio_device); + if (ret < 0) return ret; raumfeld_enable_audio(true); - - return ret; + return 0; } static void __exit raumfeld_audio_exit(void) diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 8e1571350630..b253d864868a 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -42,6 +42,7 @@ static int spitz_jack_func; static int spitz_spk_func; +static int spitz_mic_gpio; static void spitz_ext_control(struct snd_soc_codec *codec) { @@ -217,14 +218,7 @@ static int spitz_set_spk(struct snd_kcontrol *kcontrol, static int spitz_mic_bias(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - if (machine_is_borzoi() || machine_is_spitz()) - gpio_set_value(SPITZ_GPIO_MIC_BIAS, - SND_SOC_DAPM_EVENT_ON(event)); - - if (machine_is_akita()) - gpio_set_value(AKITA_GPIO_MIC_BIAS, - SND_SOC_DAPM_EVENT_ON(event)); - + gpio_set_value_cansleep(spitz_mic_gpio, SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -339,22 +333,45 @@ static int __init spitz_init(void) if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita())) return -ENODEV; + if (machine_is_borzoi() || machine_is_spitz()) + spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS; + else + spitz_mic_gpio = AKITA_GPIO_MIC_BIAS; + + ret = gpio_request(spitz_mic_gpio, "MIC GPIO"); + if (ret) + goto err1; + + ret = gpio_direction_output(spitz_mic_gpio, 0); + if (ret) + goto err2; + spitz_snd_device = platform_device_alloc("soc-audio", -1); - if (!spitz_snd_device) - return -ENOMEM; + if (!spitz_snd_device) { + ret = -ENOMEM; + goto err2; + } platform_set_drvdata(spitz_snd_device, &snd_soc_spitz); - ret = platform_device_add(spitz_snd_device); + ret = platform_device_add(spitz_snd_device); if (ret) - platform_device_put(spitz_snd_device); + goto err3; + + return 0; +err3: + platform_device_put(spitz_snd_device); +err2: + gpio_free(spitz_mic_gpio); +err1: return ret; } static void __exit spitz_exit(void) { platform_device_unregister(spitz_snd_device); + gpio_free(spitz_mic_gpio); } module_init(spitz_init); diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index ac577263b3e3..b6445757fc54 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c @@ -167,7 +167,7 @@ static struct snd_soc_dai_link zylonite_dai[] = { .codec_name = "wm9713-codec", .platform_name = "pxa-pcm-audio", .cpu_dai_name = "pxa2xx-ac97", - .codec_name = "wm9713-hifi", + .codec_dai_name = "wm9713-hifi", .init = zylonite_wm9713_init, }, { @@ -176,7 +176,7 @@ static struct snd_soc_dai_link zylonite_dai[] = { .codec_name = "wm9713-codec", .platform_name = "pxa-pcm-audio", .cpu_dai_name = "pxa2xx-ac97-aux", - .codec_name = "wm9713-aux", + .codec_dai_name = "wm9713-aux", }, { .name = "WM9713 Voice", @@ -184,7 +184,7 @@ static struct snd_soc_dai_link zylonite_dai[] = { .codec_name = "wm9713-codec", .platform_name = "pxa-pcm-audio", .cpu_dai_name = "pxa-ssp-dai.2", - .codec_name = "wm9713-voice", + .codec_dai_name = "wm9713-voice", .ops = &zylonite_voice_ops, }, }; diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index a3fdfb631469..d155cbb58e1c 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,6 +1,6 @@ config SND_SOC_SAMSUNG tristate "ASoC support for Samsung" - depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_EXYNOS4 + depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4 select S3C64XX_DMA if ARCH_S3C64XX select S3C2410_DMA if ARCH_S3C2410 help @@ -55,7 +55,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" - depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDK6442 || MACH_SMDKV210 || MACH_SMDKC110) + depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110) select SND_SOC_WM8580 select SND_SAMSUNG_I2S help @@ -162,3 +162,18 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF select SND_SAMSUNG_SPDIF help Say Y if you want to add support for SoC S/PDIF audio on the SMDK. + +config SND_SOC_SMDK_WM8580_PCM + tristate "SoC PCM Audio support for WM8580 on SMDK" + depends on SND_SOC_SAMSUNG && (MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110) + select SND_SOC_WM8580 + select SND_SAMSUNG_PCM + help + Say Y if you want to add support for SoC audio on the SMDK. + +config SND_SOC_SPEYSIDE + tristate "Audio support for Wolfson Speyside" + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 + select SND_SAMSUNG_I2S + select SND_SOC_WM8915 + select SND_SOC_WM9081 diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 294dec05c26d..683843a2744f 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -34,6 +34,8 @@ snd-soc-smdk-wm9713-objs := smdk_wm9713.o snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o snd-soc-goni-wm8994-objs := goni_wm8994.o snd-soc-smdk-spdif-objs := smdk_spdif.o +snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o +snd-soc-speyside-objs := speyside.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -51,3 +53,5 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o +obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o +obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index f6b3a3ce5919..eb6d72ed55a7 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -236,18 +236,17 @@ static struct snd_soc_dai_link goni_dai[] = { .name = "WM8994", .stream_name = "WM8994 HiFi", .cpu_dai_name = "samsung-i2s.0", - .codec_dai_name = "wm8994-hifi", + .codec_dai_name = "wm8994-aif1", .platform_name = "samsung-audio", - .codec_name = "wm8994-codec.0-0x1a", + .codec_name = "wm8994-codec.0-001a", .init = goni_wm8994_init, .ops = &goni_hifi_ops, }, { .name = "WM8994 Voice", .stream_name = "Voice", .cpu_dai_name = "goni-voice-dai", - .codec_dai_name = "wm8994-voice", - .platform_name = "samsung-audio", - .codec_name = "wm8994-codec.0-0x1a", + .codec_dai_name = "wm8994-aif2", + .codec_name = "wm8994-codec.0-001a", .ops = &goni_voice_ops, }, }; diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 78bfdb3f5d7e..16152ed08648 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -228,7 +228,7 @@ static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { SOC_DAPM_PIN_SWITCH("Handset Mic"), }; -/* GTA02 specific routes and controlls */ +/* GTA02 specific routes and controls */ #ifdef CONFIG_MACH_NEO1973_GTA02 @@ -372,7 +372,7 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) return 0; } -/* GTA01 specific controlls */ +/* GTA01 specific controls */ #ifdef CONFIG_MACH_NEO1973_GTA01 @@ -432,7 +432,6 @@ static struct snd_soc_dai_link neo1973_dai[] = { { /* Voice via BT */ .name = "Bluetooth", .stream_name = "Voice", - .platform_name = "samsung-audio", .cpu_dai_name = "dfbmcs320-pcm", .codec_dai_name = "wm8753-voice", .codec_name = "wm8753-codec.0-001a", diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 38aac7d57a59..9c7e8b48aed6 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -350,8 +350,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai, ctl = readl(regs + S3C_PCM_CTL); switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - /* Nothing to do, NB_NF by default */ + case SND_SOC_DAIFMT_IB_NF: + /* Nothing to do, IB_NF by default */ break; default: dev_err(pcm->dev, "Unsupported clock inversion!\n"); diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index 8aacf23d6f3a..3d26f6607aa4 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -249,7 +249,7 @@ static int __init smdk_audio_init(void) int ret; char *str; - if (machine_is_smdkc100() || machine_is_smdk6442() + if (machine_is_smdkc100() || machine_is_smdkv210() || machine_is_smdkc110()) { smdk.num_links = 3; /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */ diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c new file mode 100644 index 000000000000..0d12092df164 --- /dev/null +++ b/sound/soc/samsung/smdk_wm8580pcm.c @@ -0,0 +1,206 @@ +/* + * sound/soc/samsung/smdk_wm8580pcm.c + * + * Copyright (c) 2011 Samsung Electronics Co. Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <sound/soc.h> +#include <sound/pcm_params.h> +#include <sound/pcm.h> + +#include <asm/mach-types.h> + +#include "../codecs/wm8580.h" +#include "dma.h" +#include "pcm.h" + +/* + * Board Settings: + * o '1' means 'ON' + * o '0' means 'OFF' + * o 'X' means 'Don't care' + * + * SMDK6410, SMDK6440, SMDK6450 Base B/D: CFG1-0000, CFG2-1111 + * SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000 + */ + +#define SMDK_WM8580_EXT_OSC 12000000 +#define SMDK_WM8580_EXT_MCLK 4096000 +#define SMDK_WM8580_EXT_VOICE 2048000 + +static unsigned long mclk_freq; +static unsigned long xtal_freq; + +/* + * If MCLK clock directly gets from XTAL, we don't have to use PLL + * to make MCLK, but if XTAL clock source connects with other codec + * pin (like XTI), we should have to set codec's PLL to make MCLK. + * Because Samsung SoC does not support pcmcdclk output like I2S. + */ + +static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int rfs, ret; + + switch (params_rate(params)) { + case 8000: + break; + default: + printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n", + __func__, __LINE__, params_rate(params)); + return -EINVAL; + } + + rfs = mclk_freq / params_rate(params) / 2; + + /* Set the codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B + | SND_SOC_DAIFMT_IB_NF + | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* Set the cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B + | SND_SOC_DAIFMT_IB_NF + | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + if (mclk_freq == xtal_freq) { + ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK, + mclk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, + WM8580_CLKSRC_MCLK); + if (ret < 0) + return ret; + } else { + ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, + mclk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, + WM8580_CLKSRC_PLLA); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, + xtal_freq, mclk_freq); + if (ret < 0) + return ret; + } + + /* Set PCM source clock on CPU */ + ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX, + mclk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* Set SCLK_DIV for making bclk */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops smdk_wm8580_pcm_ops = { + .hw_params = smdk_wm8580_pcm_hw_params, +}; + +static struct snd_soc_dai_link smdk_dai[] = { + { + .name = "WM8580 PAIF PCM RX", + .stream_name = "Playback", + .cpu_dai_name = "samsung-pcm.0", + .codec_dai_name = "wm8580-hifi-playback", + .platform_name = "samsung-audio", + .codec_name = "wm8580-codec.0-001b", + .ops = &smdk_wm8580_pcm_ops, + }, { + .name = "WM8580 PAIF PCM TX", + .stream_name = "Capture", + .cpu_dai_name = "samsung-pcm.0", + .codec_dai_name = "wm8580-hifi-capture", + .platform_name = "samsung-audio", + .codec_name = "wm8580-codec.0-001b", + .ops = &smdk_wm8580_pcm_ops, + }, +}; + +static struct snd_soc_card smdk_pcm = { + .name = "SMDK-PCM", + .dai_link = smdk_dai, + .num_links = 2, +}; + +/* + * After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1) + * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4), + * 2.0484Mhz, directly with MCLK both Codec and SoC. + */ +static int __devinit snd_smdk_probe(struct platform_device *pdev) +{ + int ret = 0; + + xtal_freq = SMDK_WM8580_EXT_OSC; + mclk_freq = SMDK_WM8580_EXT_MCLK; + + if (machine_is_smdkc110() || machine_is_smdkv210()) + xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE; + + smdk_pcm.dev = &pdev->dev; + ret = snd_soc_register_card(&smdk_pcm); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); + return ret; + } + + return 0; +} + +static int __devexit snd_smdk_remove(struct platform_device *pdev) +{ + snd_soc_unregister_card(&smdk_pcm); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver snd_smdk_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "samsung-smdk-pcm", + }, + .probe = snd_smdk_probe, + .remove = __devexit_p(snd_smdk_remove), +}; + +static int __init smdk_audio_init(void) +{ + return platform_driver_register(&snd_smdk_driver); +} + +module_init(smdk_audio_init); + +static void __exit smdk_audio_exit(void) +{ + platform_driver_unregister(&snd_smdk_driver); +} + +module_exit(smdk_audio_exit); + +MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>"); +MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c new file mode 100644 index 000000000000..360a333cb7c0 --- /dev/null +++ b/sound/soc/samsung/speyside.c @@ -0,0 +1,332 @@ +/* + * Speyside audio support + * + * Copyright 2011 Wolfson Microelectronics + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/jack.h> +#include <linux/gpio.h> + +#include "../codecs/wm8915.h" +#include "../codecs/wm9081.h" + +#define WM8915_HPSEL_GPIO 214 + +static int speyside_set_bias_level(struct snd_soc_card *card, + enum snd_soc_bias_level level) +{ + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + int ret; + + switch (level) { + case SND_SOC_BIAS_STANDBY: + ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK1, + 32768, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK1, + 0, 0, 0); + if (ret < 0) { + pr_err("Failed to stop FLL\n"); + return ret; + } + + default: + break; + } + + return 0; +} + +static int speyside_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK1, + 32768, 256 * 48000); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_FLL, + 256 * 48000, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops speyside_ops = { + .hw_params = speyside_hw_params, +}; + +static struct snd_soc_jack speyside_headset; + +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin speyside_headset_pins[] = { + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, +}; + +/* Default the headphone selection to active high */ +static int speyside_jack_polarity; + +static int speyside_get_micbias(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + if (speyside_jack_polarity && (strcmp(source->name, "MICB1") == 0)) + return 1; + if (!speyside_jack_polarity && (strcmp(source->name, "MICB2") == 0)) + return 1; + + return 0; +} + +static void speyside_set_polarity(struct snd_soc_codec *codec, + int polarity) +{ + speyside_jack_polarity = !polarity; + gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity); + + /* Re-run DAPM to make sure we're using the correct mic bias */ + snd_soc_dapm_sync(&codec->dapm); +} + +static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->codec_dai; + struct snd_soc_codec *codec = rtd->codec; + int ret; + + ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0); + if (ret < 0) + return ret; + + ret = gpio_request(WM8915_HPSEL_GPIO, "HP_SEL"); + if (ret != 0) + pr_err("Failed to request HP_SEL GPIO: %d\n", ret); + gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity); + + ret = snd_soc_jack_new(codec, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &speyside_headset); + if (ret) + return ret; + + ret = snd_soc_jack_add_pins(&speyside_headset, + ARRAY_SIZE(speyside_headset_pins), + speyside_headset_pins); + if (ret) + return ret; + + wm8915_detect(codec, &speyside_headset, speyside_set_polarity); + + return 0; +} + +static int speyside_late_probe(struct snd_soc_card *card) +{ + snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Main AMIC"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Main DMIC"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); + snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Output"); + snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Input"); + + return 0; +} + +static struct snd_soc_dai_link speyside_dai[] = { + { + .name = "CPU", + .stream_name = "CPU", + .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm8915-aif1", + .platform_name = "samsung-audio", + .codec_name = "wm8915.1-001a", + .init = speyside_wm8915_init, + .ops = &speyside_ops, + }, + { + .name = "Baseband", + .stream_name = "Baseband", + .cpu_dai_name = "wm8915-aif2", + .codec_dai_name = "wm1250-ev1", + .codec_name = "wm1250-ev1.1-0027", + .ops = &speyside_ops, + .ignore_suspend = 1, + }, +}; + +static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm) +{ + snd_soc_dapm_nc_pin(dapm, "LINEOUT"); + + /* At any time the WM9081 is active it will have this clock */ + return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, + 48000 * 256, 0); +} + +static struct snd_soc_aux_dev speyside_aux_dev[] = { + { + .name = "wm9081", + .codec_name = "wm9081.1-006c", + .init = speyside_wm9081_init, + }, +}; + +static struct snd_soc_codec_conf speyside_codec_conf[] = { + { + .dev_name = "wm9081.1-006c", + .name_prefix = "Sub", + }, +}; + +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Main Speaker"), + SOC_DAPM_PIN_SWITCH("Main DMIC"), + SOC_DAPM_PIN_SWITCH("Main AMIC"), + SOC_DAPM_PIN_SWITCH("WM1250 Input"), + SOC_DAPM_PIN_SWITCH("WM1250 Output"), +}; + +static struct snd_soc_dapm_widget widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + + SND_SOC_DAPM_SPK("Main Speaker", NULL), + + SND_SOC_DAPM_MIC("Main AMIC", NULL), + SND_SOC_DAPM_MIC("Main DMIC", NULL), +}; + +static struct snd_soc_dapm_route audio_paths[] = { + { "IN1RN", NULL, "MICB1" }, + { "IN1RP", NULL, "MICB1" }, + { "IN1RN", NULL, "MICB2" }, + { "IN1RP", NULL, "MICB2" }, + { "MICB1", NULL, "Headset Mic", speyside_get_micbias }, + { "MICB2", NULL, "Headset Mic", speyside_get_micbias }, + + { "IN1LP", NULL, "MICB2" }, + { "IN1RN", NULL, "MICB1" }, + { "MICB2", NULL, "Main AMIC" }, + + { "DMIC1DAT", NULL, "MICB1" }, + { "DMIC2DAT", NULL, "MICB1" }, + { "MICB1", NULL, "Main DMIC" }, + + { "Headphone", NULL, "HPOUT1L" }, + { "Headphone", NULL, "HPOUT1R" }, + + { "Sub IN1", NULL, "HPOUT2L" }, + { "Sub IN2", NULL, "HPOUT2R" }, + + { "Main Speaker", NULL, "Sub SPKN" }, + { "Main Speaker", NULL, "Sub SPKP" }, + { "Main Speaker", NULL, "SPKDAT" }, +}; + +static struct snd_soc_card speyside = { + .name = "Speyside", + .dai_link = speyside_dai, + .num_links = ARRAY_SIZE(speyside_dai), + .aux_dev = speyside_aux_dev, + .num_aux_devs = ARRAY_SIZE(speyside_aux_dev), + .codec_conf = speyside_codec_conf, + .num_configs = ARRAY_SIZE(speyside_codec_conf), + + .set_bias_level = speyside_set_bias_level, + + .controls = controls, + .num_controls = ARRAY_SIZE(controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = audio_paths, + .num_dapm_routes = ARRAY_SIZE(audio_paths), + + .late_probe = speyside_late_probe, +}; + +static __devinit int speyside_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &speyside; + int ret; + + card->dev = &pdev->dev; + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + ret); + return ret; + } + + return 0; +} + +static int __devexit speyside_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + + return 0; +} + +static struct platform_driver speyside_driver = { + .driver = { + .name = "speyside", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = speyside_probe, + .remove = __devexit_p(speyside_remove), +}; + +static int __init speyside_audio_init(void) +{ + return platform_driver_register(&speyside_driver); +} +module_init(speyside_audio_init); + +static void __exit speyside_audio_exit(void) +{ + platform_driver_unregister(&speyside_driver); +} +module_exit(speyside_audio_exit); + +MODULE_DESCRIPTION("Speyside audio support"); +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:speyside"); diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 0c9997e2d8c0..4a9da6b5f4e1 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -86,8 +86,8 @@ #define SE (1 << 0) /* Fix the master clock */ /* CLK_RST */ -#define B_CLK 0x00000010 -#define A_CLK 0x00000001 +#define CRB (1 << 4) +#define CRA (1 << 0) /* IO SHIFT / MACRO */ #define BI_SHIFT 12 @@ -146,11 +146,20 @@ struct fsi_priv { void __iomem *base; struct fsi_master *master; - int chan_num; struct fsi_stream playback; struct fsi_stream capture; + int chan_num:16; + int clk_master:1; + long rate; + + /* for suspend/resume */ + u32 saved_do_fmt; + u32 saved_di_fmt; + u32 saved_ckg1; + u32 saved_ckg2; + u32 saved_out_sel; }; struct fsi_core { @@ -171,6 +180,14 @@ struct fsi_master { struct fsi_core *core; struct sh_fsi_platform_info *info; spinlock_t lock; + + /* for suspend/resume */ + u32 saved_a_mclk; + u32 saved_b_mclk; + u32 saved_iemsk; + u32 saved_imsk; + u32 saved_clk_rst; + u32 saved_soft_rst; }; /* @@ -244,6 +261,11 @@ static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) return fsi->master; } +static int fsi_is_clk_master(struct fsi_priv *fsi) +{ + return fsi->clk_master; +} + static int fsi_is_port_a(struct fsi_priv *fsi) { return fsi->master->base == fsi->base; @@ -535,20 +557,45 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) } /* - * ctrl function + * clock function */ +#define fsi_module_init(m, d) __fsi_module_clk_ctrl(m, d, 1) +#define fsi_module_kill(m, d) __fsi_module_clk_ctrl(m, d, 0) +static void __fsi_module_clk_ctrl(struct fsi_master *master, + struct device *dev, + int enable) +{ + pm_runtime_get_sync(dev); -static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) + if (enable) { + /* enable only SR */ + fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR); + fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0); + } else { + /* clear all registers */ + fsi_master_mask_set(master, SOFT_RST, FSISR, 0); + } + + pm_runtime_put_sync(dev); +} + +#define fsi_port_start(f) __fsi_port_clk_ctrl(f, 1) +#define fsi_port_stop(f) __fsi_port_clk_ctrl(f, 0) +static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable) { - u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); struct fsi_master *master = fsi_get_master(fsi); + u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR; + u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; + int is_master = fsi_is_clk_master(fsi); - if (enable) - fsi_master_mask_set(master, CLK_RST, val, val); - else - fsi_master_mask_set(master, CLK_RST, val, 0); + fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0); + if (is_master) + fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); } +/* + * ctrl function + */ static void fsi_fifo_init(struct fsi_priv *fsi, int is_play, struct snd_soc_dai *dai) @@ -601,18 +648,6 @@ static void fsi_fifo_init(struct fsi_priv *fsi, } } -static void fsi_soft_all_reset(struct fsi_master *master) -{ - /* port AB reset */ - fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0); - mdelay(10); - - /* soft reset */ - fsi_master_mask_set(master, SOFT_RST, FSISR, 0); - fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR); - mdelay(10); -} - static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) { struct snd_pcm_runtime *runtime; @@ -793,14 +828,13 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, struct fsi_priv *fsi = fsi_get_priv(substream); int is_play = fsi_is_play(substream); struct fsi_master *master = fsi_get_master(fsi); - set_rate_func set_rate; + set_rate_func set_rate = fsi_get_info_set_rate(master); fsi_irq_disable(fsi, is_play); - fsi_clk_ctrl(fsi, 0); - set_rate = fsi_get_info_set_rate(master); - if (set_rate && fsi->rate) + if (fsi_is_clk_master(fsi)) set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); + fsi->rate = 0; pm_runtime_put_sync(dai->dev); @@ -821,8 +855,10 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, frames_to_bytes(runtime, runtime->period_size)); ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); fsi_irq_enable(fsi, is_play); + fsi_port_start(fsi); break; case SNDRV_PCM_TRIGGER_STOP: + fsi_port_stop(fsi); fsi_irq_disable(fsi, is_play); fsi_stream_pop(fsi, is_play); break; @@ -876,6 +912,8 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); + struct fsi_master *master = fsi_get_master(fsi); + set_rate_func set_rate = fsi_get_info_set_rate(master); u32 flags = fsi_get_info_flags(fsi); u32 data = 0; int ret; @@ -886,6 +924,7 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: data = DIMD | DOMD; + fsi->clk_master = 1; break; case SND_SOC_DAIFMT_CBS_CFS: break; @@ -893,6 +932,13 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ret = -EINVAL; goto set_fmt_exit; } + + if (fsi_is_clk_master(fsi) && !set_rate) { + dev_err(dai->dev, "platform doesn't have set_rate\n"); + ret = -EINVAL; + goto set_fmt_exit; + } + fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); /* set format */ @@ -919,13 +965,12 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); struct fsi_master *master = fsi_get_master(fsi); - set_rate_func set_rate; + set_rate_func set_rate = fsi_get_info_set_rate(master); int fsi_ver = master->core->ver; long rate = params_rate(params); int ret; - set_rate = fsi_get_info_set_rate(master); - if (!set_rate) + if (!fsi_is_clk_master(fsi)) return 0; ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); @@ -987,7 +1032,6 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); udelay(10); - fsi_clk_ctrl(fsi, 1); ret = 0; } @@ -1200,10 +1244,9 @@ static int fsi_probe(struct platform_device *pdev) master->fsib.master = master; pm_runtime_enable(&pdev->dev); - pm_runtime_resume(&pdev->dev); dev_set_drvdata(&pdev->dev, master); - fsi_soft_all_reset(master); + fsi_module_init(master, &pdev->dev); ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, id_entry->name, master); @@ -1218,8 +1261,17 @@ static int fsi_probe(struct platform_device *pdev) goto exit_free_irq; } - return snd_soc_register_dais(&pdev->dev, fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); + ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai, + ARRAY_SIZE(fsi_soc_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "cannot snd dai register\n"); + goto exit_snd_soc; + } + + return ret; +exit_snd_soc: + snd_soc_unregister_platform(&pdev->dev); exit_free_irq: free_irq(irq, master); exit_iounmap: @@ -1238,12 +1290,13 @@ static int fsi_remove(struct platform_device *pdev) master = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); - snd_soc_unregister_platform(&pdev->dev); + fsi_module_kill(master, &pdev->dev); + free_irq(master->irq, master); pm_runtime_disable(&pdev->dev); - free_irq(master->irq, master); + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); + snd_soc_unregister_platform(&pdev->dev); iounmap(master->base); kfree(master); @@ -1251,6 +1304,82 @@ static int fsi_remove(struct platform_device *pdev) return 0; } +static void __fsi_suspend(struct fsi_priv *fsi, + struct device *dev, + set_rate_func set_rate) +{ + fsi->saved_do_fmt = fsi_reg_read(fsi, DO_FMT); + fsi->saved_di_fmt = fsi_reg_read(fsi, DI_FMT); + fsi->saved_ckg1 = fsi_reg_read(fsi, CKG1); + fsi->saved_ckg2 = fsi_reg_read(fsi, CKG2); + fsi->saved_out_sel = fsi_reg_read(fsi, OUT_SEL); + + if (fsi_is_clk_master(fsi)) + set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0); +} + +static void __fsi_resume(struct fsi_priv *fsi, + struct device *dev, + set_rate_func set_rate) +{ + fsi_reg_write(fsi, DO_FMT, fsi->saved_do_fmt); + fsi_reg_write(fsi, DI_FMT, fsi->saved_di_fmt); + fsi_reg_write(fsi, CKG1, fsi->saved_ckg1); + fsi_reg_write(fsi, CKG2, fsi->saved_ckg2); + fsi_reg_write(fsi, OUT_SEL, fsi->saved_out_sel); + + if (fsi_is_clk_master(fsi)) + set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1); +} + +static int fsi_suspend(struct device *dev) +{ + struct fsi_master *master = dev_get_drvdata(dev); + set_rate_func set_rate = fsi_get_info_set_rate(master); + + pm_runtime_get_sync(dev); + + __fsi_suspend(&master->fsia, dev, set_rate); + __fsi_suspend(&master->fsib, dev, set_rate); + + master->saved_a_mclk = fsi_core_read(master, a_mclk); + master->saved_b_mclk = fsi_core_read(master, b_mclk); + master->saved_iemsk = fsi_core_read(master, iemsk); + master->saved_imsk = fsi_core_read(master, imsk); + master->saved_clk_rst = fsi_master_read(master, CLK_RST); + master->saved_soft_rst = fsi_master_read(master, SOFT_RST); + + fsi_module_kill(master, dev); + + pm_runtime_put_sync(dev); + + return 0; +} + +static int fsi_resume(struct device *dev) +{ + struct fsi_master *master = dev_get_drvdata(dev); + set_rate_func set_rate = fsi_get_info_set_rate(master); + + pm_runtime_get_sync(dev); + + fsi_module_init(master, dev); + + fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst); + fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst); + fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk); + fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk); + fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk); + fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk); + + __fsi_resume(&master->fsia, dev, set_rate); + __fsi_resume(&master->fsib, dev, set_rate); + + pm_runtime_put_sync(dev); + + return 0; +} + static int fsi_runtime_nop(struct device *dev) { /* Runtime PM callback shared between ->runtime_suspend() @@ -1264,6 +1393,8 @@ static int fsi_runtime_nop(struct device *dev) } static struct dev_pm_ops fsi_pm_ops = { + .suspend = fsi_suspend, + .resume = fsi_resume, .runtime_suspend = fsi_runtime_nop, .runtime_resume = fsi_runtime_nop, }; @@ -1321,3 +1452,4 @@ module_exit(fsi_mobile_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip FSI audio driver"); MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); +MODULE_ALIAS("platform:fsi-pcm-audio"); diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 5d76da43b14c..06b7b81a1601 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -20,40 +20,28 @@ #include <trace/events/asoc.h> -static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, - unsigned int reg) +#ifdef CONFIG_SPI_MASTER +static int do_spi_write(void *control, const char *data, int len) { + struct spi_device *spi = control; int ret; - unsigned int val; - - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - ret = snd_soc_cache_read(codec, reg, &val); + ret = spi_write(spi, data, len); if (ret < 0) - return -1; - return val; + return ret; + + return len; } +#endif -static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) +static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value, const void *data, int len) { - u8 data[2]; int ret; - data[0] = (reg << 4) | ((value >> 8) & 0x000f); - data[1] = value & 0x00ff; - if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { + reg < codec->driver->reg_cache_size && + !codec->cache_bypass) { ret = snd_soc_cache_write(codec, reg, value); if (ret < 0) return -1; @@ -64,8 +52,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, return 0; } - ret = codec->hw_write(codec->control_data, data, 2); - if (ret == 2) + ret = codec->hw_write(codec->control_data, data, len); + if (ret == len) return 0; if (ret < 0) return ret; @@ -73,50 +61,19 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, return -EIO; } -#if defined(CONFIG_SPI_MASTER) -static int snd_soc_4_12_spi_write(void *control_data, const char *data, - int len) -{ - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[1]; - msg[1] = data[0]; - - spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} -#else -#define snd_soc_4_12_spi_write NULL -#endif - -static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, - unsigned int reg) +static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg) { int ret; unsigned int val; if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; + snd_soc_codec_volatile_register(codec, reg) || + codec->cache_bypass) { + if (codec->cache_only) + return -1; - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); + BUG_ON(!codec->hw_read); + return codec->hw_read(codec, reg); } ret = snd_soc_cache_read(codec, reg, &val); @@ -125,259 +82,117 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, return val; } -static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) +static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, + unsigned int reg) { - u8 data[2]; - int ret; - - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - ret = codec->hw_write(codec->control_data, data, 2); - if (ret == 2) - return 0; - if (ret < 0) - return ret; - else - return -EIO; + return do_hw_read(codec, reg); } -#if defined(CONFIG_SPI_MASTER) -static int snd_soc_7_9_spi_write(void *control_data, const char *data, - int len) +static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) { - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; + u16 data; - if (len <= 0) - return 0; + data = cpu_to_be16((reg << 12) | (value & 0xffffff)); - msg[0] = data[0]; - msg[1] = data[1]; + return do_hw_write(codec, reg, value, &data, 2); +} - spi_message_init(&m); - memset(&t, 0, sizeof t); +static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + return do_hw_read(codec, reg); +} - t.tx_buf = &msg[0]; - t.len = len; +static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; - return len; + return do_hw_write(codec, reg, value, data, 2); } -#else -#define snd_soc_7_9_spi_write NULL -#endif static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[2]; - int ret; reg &= 0xff; data[0] = reg; data[1] = value & 0xff; - if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; + return do_hw_write(codec, reg, value, data, 2); } static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, unsigned int reg) { - int ret; - unsigned int val; - - reg &= 0xff; - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - return val; -} - -#if defined(CONFIG_SPI_MASTER) -static int snd_soc_8_8_spi_write(void *control_data, const char *data, - int len) -{ - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return do_hw_read(codec, reg); } -#else -#define snd_soc_8_8_spi_write NULL -#endif static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[3]; - int ret; data[0] = reg; data[1] = (value >> 8) & 0xff; data[2] = value & 0xff; - if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - if (codec->hw_write(codec->control_data, data, 3) == 3) - return 0; - else - return -EIO; + return do_hw_write(codec, reg, value, data, 3); } static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, unsigned int reg) { - int ret; - unsigned int val; - - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - return val; -} - -#if defined(CONFIG_SPI_MASTER) -static int snd_soc_8_16_spi_write(void *control_data, const char *data, - int len) -{ - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; - u8 msg[3]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - msg[2] = data[2]; - - spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return do_hw_read(codec, reg); } -#else -#define snd_soc_8_16_spi_write NULL -#endif #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, - unsigned int r) +static unsigned int do_i2c_read(struct snd_soc_codec *codec, + void *reg, int reglen, + void *data, int datalen) { struct i2c_msg xfer[2]; - u8 reg = r; - u8 data; int ret; struct i2c_client *client = codec->control_data; /* Write register */ xfer[0].addr = client->addr; xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® + xfer[0].len = reglen; + xfer[0].buf = reg; /* Read data */ xfer[1].addr = client->addr; xfer[1].flags = I2C_M_RD; - xfer[1].len = 1; - xfer[1].buf = &data; + xfer[1].len = datalen; + xfer[1].buf = data; ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + if (ret == 2) return 0; - } + else if (ret < 0) + return ret; + else + return -EIO; +} +#endif +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, + unsigned int r) +{ + u8 reg = r; + u8 data; + int ret; + + ret = do_i2c_read(codec, ®, 1, &data, 1); + if (ret < 0) + return 0; return data; } #else @@ -388,30 +203,13 @@ static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, unsigned int r) { - struct i2c_msg xfer[2]; u8 reg = r; u16 data; int ret; - struct i2c_client *client = codec->control_data; - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + ret = do_i2c_read(codec, ®, 1, &data, 2); + if (ret < 0) return 0; - } - return (data >> 8) | ((data & 0xff) << 8); } #else @@ -422,30 +220,13 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, unsigned int r) { - struct i2c_msg xfer[2]; u16 reg = r; u8 data; int ret; - struct i2c_client *client = codec->control_data; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 2; - xfer[0].buf = (u8 *)® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 1; - xfer[1].buf = &data; - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + ret = do_i2c_read(codec, ®, 2, &data, 1); + if (ret < 0) return 0; - } - return data; } #else @@ -453,120 +234,34 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, #endif static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, - unsigned int reg) + unsigned int reg) { - int ret; - unsigned int val; - - reg &= 0xff; - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - return val; + return do_hw_read(codec, reg); } static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) + unsigned int value) { u8 data[3]; - int ret; data[0] = (reg >> 8) & 0xff; data[1] = reg & 0xff; data[2] = value; - reg &= 0xff; - if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - ret = codec->hw_write(codec->control_data, data, 3); - if (ret == 3) - return 0; - if (ret < 0) - return ret; - else - return -EIO; -} - -#if defined(CONFIG_SPI_MASTER) -static int snd_soc_16_8_spi_write(void *control_data, const char *data, - int len) -{ - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; - u8 msg[3]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - msg[2] = data[2]; - - spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return do_hw_write(codec, reg, value, data, 3); } -#else -#define snd_soc_16_8_spi_write NULL -#endif #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, unsigned int r) { - struct i2c_msg xfer[2]; u16 reg = cpu_to_be16(r); u16 data; int ret; - struct i2c_client *client = codec->control_data; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 2; - xfer[0].buf = (u8 *)® - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + ret = do_i2c_read(codec, ®, 2, &data, 2); + if (ret < 0) return 0; - } - return be16_to_cpu(data); } #else @@ -576,52 +271,59 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, unsigned int reg) { - int ret; - unsigned int val; - - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - - return val; + return do_hw_read(codec, reg); } static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[4]; - int ret; data[0] = (reg >> 8) & 0xff; data[1] = reg & 0xff; data[2] = (value >> 8) & 0xff; data[3] = value & 0xff; - if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } + return do_hw_write(codec, reg, value, data, 4); +} - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; +/* Primitive bulk write support for soc-cache. The data pointed to by + * `data' needs to already be in the form the hardware expects + * including any leading register specific data. Any data written + * through this function will not go through the cache as it only + * handles writing to volatile or out of bounds registers. + */ +static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg, + const void *data, size_t len) +{ + int ret; + + /* To ensure that we don't get out of sync with the cache, check + * whether the base register is volatile or if we've directly asked + * to bypass the cache. Out of bounds registers are considered + * volatile. + */ + if (!codec->cache_bypass + && !snd_soc_codec_volatile_register(codec, reg) + && reg < codec->driver->reg_cache_size) + return -EINVAL; + + switch (codec->control_type) { +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) + case SND_SOC_I2C: + ret = i2c_master_send(codec->control_data, data, len); + break; +#endif +#if defined(CONFIG_SPI_MASTER) + case SND_SOC_SPI: + ret = spi_write(codec->control_data, data, len); + break; +#endif + default: + BUG(); } - ret = codec->hw_write(codec->control_data, data, 4); - if (ret == 4) + if (ret == len) return 0; if (ret < 0) return ret; @@ -629,79 +331,40 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, return -EIO; } -#if defined(CONFIG_SPI_MASTER) -static int snd_soc_16_16_spi_write(void *control_data, const char *data, - int len) -{ - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; - u8 msg[4]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - msg[2] = data[2]; - msg[3] = data[3]; - - spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} -#else -#define snd_soc_16_16_spi_write NULL -#endif - static struct { int addr_bits; int data_bits; int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); - int (*spi_write)(void *, const char *, int); unsigned int (*read)(struct snd_soc_codec *, unsigned int); unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); } io_types[] = { { .addr_bits = 4, .data_bits = 12, .write = snd_soc_4_12_write, .read = snd_soc_4_12_read, - .spi_write = snd_soc_4_12_spi_write, }, { .addr_bits = 7, .data_bits = 9, .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, - .spi_write = snd_soc_7_9_spi_write, }, { .addr_bits = 8, .data_bits = 8, .write = snd_soc_8_8_write, .read = snd_soc_8_8_read, .i2c_read = snd_soc_8_8_read_i2c, - .spi_write = snd_soc_8_8_spi_write, }, { .addr_bits = 8, .data_bits = 16, .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, .i2c_read = snd_soc_8_16_read_i2c, - .spi_write = snd_soc_8_16_spi_write, }, { .addr_bits = 16, .data_bits = 8, .write = snd_soc_16_8_write, .read = snd_soc_16_8_read, .i2c_read = snd_soc_16_8_read_i2c, - .spi_write = snd_soc_16_8_spi_write, }, { .addr_bits = 16, .data_bits = 16, .write = snd_soc_16_16_write, .read = snd_soc_16_16_read, .i2c_read = snd_soc_16_16_read_i2c, - .spi_write = snd_soc_16_16_spi_write, }, }; @@ -709,7 +372,6 @@ static struct { * snd_soc_codec_set_cache_io: Set up standard I/O functions. * * @codec: CODEC to configure. - * @type: Type of cache. * @addr_bits: Number of bits of register address data. * @data_bits: Number of bits of data per register. * @control: Control bus used. @@ -744,6 +406,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, codec->write = io_types[i].write; codec->read = io_types[i].read; + codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; switch (control) { case SND_SOC_CUSTOM: @@ -762,8 +425,9 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, break; case SND_SOC_SPI: - if (io_types[i].spi_write) - codec->hw_write = io_types[i].spi_write; +#ifdef CONFIG_SPI_MASTER + codec->hw_write = do_spi_write; +#endif codec->control_data = container_of(codec->dev, struct spi_device, @@ -889,6 +553,8 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec) rbnode = rb_entry(node, struct snd_soc_rbtree_node, node); if (rbnode->value == rbnode->defval) continue; + WARN_ON(codec->writable_register && + codec->writable_register(codec, rbnode->reg)); ret = snd_soc_cache_read(codec, rbnode->reg, &val); if (ret) return ret; @@ -1149,6 +815,8 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) lzo_blocks = codec->reg_cache; for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) { + WARN_ON(codec->writable_register && + codec->writable_register(codec, i)); ret = snd_soc_cache_read(codec, i, &val); if (ret) return ret; @@ -1407,6 +1075,8 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) codec_drv = codec->driver; for (i = 0; i < codec_drv->reg_cache_size; ++i) { + WARN_ON(codec->writable_register && + codec->writable_register(codec, i)); ret = snd_soc_cache_read(codec, i, &val); if (ret) return ret; @@ -1523,7 +1193,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) codec->cache_ops->name, codec->name); return codec->cache_ops->init(codec); } - return -EINVAL; + return -ENOSYS; } /* @@ -1538,7 +1208,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) codec->cache_ops->name, codec->name); return codec->cache_ops->exit(codec); } - return -EINVAL; + return -ENOSYS; } /** @@ -1562,7 +1232,7 @@ int snd_soc_cache_read(struct snd_soc_codec *codec, } mutex_unlock(&codec->cache_rw_mutex); - return -EINVAL; + return -ENOSYS; } EXPORT_SYMBOL_GPL(snd_soc_cache_read); @@ -1587,7 +1257,7 @@ int snd_soc_cache_write(struct snd_soc_codec *codec, } mutex_unlock(&codec->cache_rw_mutex); - return -EINVAL; + return -ENOSYS; } EXPORT_SYMBOL_GPL(snd_soc_cache_write); @@ -1610,7 +1280,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec) } if (!codec->cache_ops || !codec->cache_ops->sync) - return -EINVAL; + return -ENOSYS; if (codec->cache_ops->name) name = codec->cache_ops->name; @@ -1677,3 +1347,17 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec, return codec->driver->reg_access_default[index].read; } EXPORT_SYMBOL_GPL(snd_soc_default_readable_register); + +int snd_soc_default_writable_register(struct snd_soc_codec *codec, + unsigned int reg) +{ + int index; + + if (reg >= codec->driver->reg_cache_size) + return 1; + index = snd_soc_get_reg_access_index(codec, reg); + if (index < 0) + return 0; + return codec->driver->reg_access_default[index].write; +} +EXPORT_SYMBOL_GPL(snd_soc_default_writable_register); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4dda58926bc5..d75043ed7fc0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -92,8 +92,8 @@ static int min_bytes_needed(unsigned long val) static int format_register_str(struct snd_soc_codec *codec, unsigned int reg, char *buf, size_t len) { - int wordsize = codec->driver->reg_word_size * 2; - int regsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; + int wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; + int regsize = codec->driver->reg_word_size * 2; int ret; char tmpbuf[len + 1]; char regbuf[regsize + 1]; @@ -132,8 +132,8 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf, size_t total = 0; loff_t p = 0; - wordsize = codec->driver->reg_word_size * 2; - regsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; + wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; + regsize = codec->driver->reg_word_size * 2; len = wordsize + regsize + 2 + 1; @@ -242,7 +242,7 @@ static ssize_t codec_reg_write_file(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { char buf[32]; - int buf_size; + size_t buf_size; char *start = buf; unsigned long reg, value; int step = 1; @@ -302,13 +302,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) printk(KERN_WARNING "ASoC: Failed to create codec register debugfs file\n"); - codec->dapm.debugfs_dapm = debugfs_create_dir("dapm", - codec->debugfs_codec_root); - if (!codec->dapm.debugfs_dapm) - printk(KERN_WARNING - "Failed to create DAPM debugfs directory\n"); - - snd_soc_dapm_debugfs_init(&codec->dapm); + snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); } static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) @@ -555,7 +549,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } - if (platform->driver->ops->open) { + if (platform->driver->ops && platform->driver->ops->open) { ret = platform->driver->ops->open(substream); if (ret < 0) { printk(KERN_ERR "asoc: can't open platform %s\n", platform->name); @@ -629,6 +623,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) runtime->hw.rates |= codec_dai_drv->capture.rates; } + ret = -EINVAL; snd_pcm_limit_hw_rates(runtime); if (!runtime->hw.rates) { printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", @@ -640,7 +635,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) codec_dai->name, cpu_dai->name); goto config_err; } - if (!runtime->hw.channels_min || !runtime->hw.channels_max) { + if (!runtime->hw.channels_min || !runtime->hw.channels_max || + runtime->hw.channels_min > runtime->hw.channels_max) { printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", codec_dai->name, cpu_dai->name); goto config_err; @@ -683,7 +679,7 @@ machine_err: codec_dai->driver->ops->shutdown(substream, codec_dai); codec_dai_err: - if (platform->driver->ops->close) + if (platform->driver->ops && platform->driver->ops->close) platform->driver->ops->close(substream); platform_err: @@ -765,7 +761,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) rtd->dai_link->ops->shutdown(substream); - if (platform->driver->ops->close) + if (platform->driver->ops && platform->driver->ops->close) platform->driver->ops->close(substream); cpu_dai->runtime = NULL; @@ -808,7 +804,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - if (platform->driver->ops->prepare) { + if (platform->driver->ops && platform->driver->ops->prepare) { ret = platform->driver->ops->prepare(substream); if (ret < 0) { printk(KERN_ERR "asoc: platform prepare error\n"); @@ -897,7 +893,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - if (platform->driver->ops->hw_params) { + if (platform->driver->ops && platform->driver->ops->hw_params) { ret = platform->driver->ops->hw_params(substream, params); if (ret < 0) { printk(KERN_ERR "asoc: platform %s hw params failed\n", @@ -950,7 +946,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) rtd->dai_link->ops->hw_free(substream); /* free any DMA resources */ - if (platform->driver->ops->hw_free) + if (platform->driver->ops && platform->driver->ops->hw_free) platform->driver->ops->hw_free(substream); /* now free hw params for the DAIs */ @@ -978,7 +974,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } - if (platform->driver->ops->trigger) { + if (platform->driver->ops && platform->driver->ops->trigger) { ret = platform->driver->ops->trigger(substream, cmd); if (ret < 0) return ret; @@ -1007,7 +1003,7 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t offset = 0; snd_pcm_sframes_t delay = 0; - if (platform->driver->ops->pointer) + if (platform->driver->ops && platform->driver->ops->pointer) offset = platform->driver->ops->pointer(substream); if (cpu_dai->driver->ops->delay) @@ -1297,6 +1293,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) struct snd_soc_codec *codec; struct snd_soc_platform *platform; struct snd_soc_dai *codec_dai, *cpu_dai; + const char *platform_name; if (rtd->complete) return 1; @@ -1309,10 +1306,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) /* no, then find CPU DAI from registered DAIs*/ list_for_each_entry(cpu_dai, &dai_list, list) { if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) { - - if (!try_module_get(cpu_dai->dev->driver->owner)) - return -ENODEV; - rtd->cpu_dai = cpu_dai; goto find_codec; } @@ -1349,13 +1342,18 @@ find_codec: dai_link->codec_name); find_platform: - /* do we already have the CODEC DAI for this link ? */ - if (rtd->platform) { + /* do we need a platform? */ + if (rtd->platform) goto out; - } - /* no, then find CPU DAI from registered DAIs*/ + + /* if there's no platform we match on the empty platform */ + platform_name = dai_link->platform_name; + if (!platform_name) + platform_name = "snd-soc-dummy"; + + /* no, then find one from the set of registered platforms */ list_for_each_entry(platform, &platform_list, list) { - if (!strcmp(platform->name, dai_link->platform_name)) { + if (!strcmp(platform->name, platform_name)) { rtd->platform = platform; goto out; } @@ -1451,6 +1449,16 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) } } +static void soc_remove_dai_links(struct snd_soc_card *card) +{ + int i; + + for (i = 0; i < card->num_rtd; i++) + soc_remove_dai_link(card, i); + + card->num_rtd = 0; +} + static void soc_set_name_prefix(struct snd_soc_card *card, struct snd_soc_codec *codec) { @@ -1481,6 +1489,12 @@ static int soc_probe_codec(struct snd_soc_card *card, if (!try_module_get(codec->dev->driver->owner)) return -ENODEV; + soc_init_codec_debugfs(codec); + + if (driver->dapm_widgets) + snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, + driver->num_dapm_widgets); + if (driver->probe) { ret = driver->probe(codec); if (ret < 0) { @@ -1491,15 +1505,13 @@ static int soc_probe_codec(struct snd_soc_card *card, } } - if (driver->dapm_widgets) - snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, - driver->num_dapm_widgets); + if (driver->controls) + snd_soc_add_controls(codec, driver->controls, + driver->num_controls); if (driver->dapm_routes) snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, driver->num_dapm_routes); - soc_init_codec_debugfs(codec); - /* mark codec as probed and add to card codec list */ codec->probed = 1; list_add(&codec->card_list, &card->codec_dev_list); @@ -1508,6 +1520,7 @@ static int soc_probe_codec(struct snd_soc_card *card, return 0; err_probe: + soc_cleanup_codec_debugfs(codec); module_put(codec->dev->driver->owner); return ret; @@ -1605,11 +1618,15 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) /* probe the cpu_dai */ if (!cpu_dai->probed) { + if (!try_module_get(cpu_dai->dev->driver->owner)) + return -ENODEV; + if (cpu_dai->driver->probe) { ret = cpu_dai->driver->probe(cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n", cpu_dai->name); + module_put(cpu_dai->dev->driver->owner); return ret; } } @@ -1858,11 +1875,19 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) card->dapm.card = card; list_add(&card->dapm.list, &card->dapm_list); +#ifdef CONFIG_DEBUG_FS + snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); +#endif + #ifdef CONFIG_PM_SLEEP /* deferred resume work */ INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); #endif + if (card->dapm_widgets) + snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, + card->num_dapm_widgets); + /* initialise the sound card only once */ if (card->probe) { ret = card->probe(card); @@ -1888,27 +1913,24 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) } } - if (card->dapm_widgets) - snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, - card->num_dapm_widgets); + /* We should have a non-codec control add function but we don't */ + if (card->controls) + snd_soc_add_controls(list_first_entry(&card->codec_dev_list, + struct snd_soc_codec, + card_list), + card->controls, + card->num_controls); + if (card->dapm_routes) snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, card->num_dapm_routes); -#ifdef CONFIG_DEBUG_FS - card->dapm.debugfs_dapm = debugfs_create_dir("dapm", - card->debugfs_card_root); - if (!card->dapm.debugfs_dapm) - printk(KERN_WARNING - "Failed to create card DAPM debugfs directory\n"); - - snd_soc_dapm_debugfs_init(&card->dapm); -#endif - snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), - "%s", card->name); - snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), "%s", card->name); + snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), + "%s", card->long_name ? card->long_name : card->name); + snprintf(card->snd_card->driver, sizeof(card->snd_card->driver), + "%s", card->driver_name ? card->driver_name : card->name); if (card->late_probe) { ret = card->late_probe(card); @@ -1947,8 +1969,7 @@ probe_aux_dev_err: soc_remove_aux_dev(card, i); probe_dai_err: - for (i = 0; i < card->num_links; i++) - soc_remove_dai_link(card, i); + soc_remove_dai_links(card); card_probe_error: if (card->remove) @@ -2010,8 +2031,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) soc_remove_aux_dev(card, i); /* remove and free each DAI */ - for (i = 0; i < card->num_rtd; i++) - soc_remove_dai_link(card, i); + soc_remove_dai_links(card); soc_cleanup_card_debugfs(card); @@ -2019,6 +2039,8 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) if (card->remove) card->remove(card); + snd_soc_dapm_free(&card->dapm); + kfree(card->rtd); snd_card_free(card->snd_card); return 0; @@ -2060,6 +2082,7 @@ const struct dev_pm_ops snd_soc_pm_ops = { .resume = snd_soc_resume, .poweroff = snd_soc_poweroff, }; +EXPORT_SYMBOL_GPL(snd_soc_pm_ops); /* ASoC platform driver */ static struct platform_driver soc_driver = { @@ -2102,13 +2125,15 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->pcm = pcm; pcm->private_data = rtd; - soc_pcm_ops.mmap = platform->driver->ops->mmap; - soc_pcm_ops.pointer = platform->driver->ops->pointer; - soc_pcm_ops.ioctl = platform->driver->ops->ioctl; - soc_pcm_ops.copy = platform->driver->ops->copy; - soc_pcm_ops.silence = platform->driver->ops->silence; - soc_pcm_ops.ack = platform->driver->ops->ack; - soc_pcm_ops.page = platform->driver->ops->page; + if (platform->driver->ops) { + soc_pcm_ops.mmap = platform->driver->ops->mmap; + soc_pcm_ops.pointer = platform->driver->ops->pointer; + soc_pcm_ops.ioctl = platform->driver->ops->ioctl; + soc_pcm_ops.copy = platform->driver->ops->copy; + soc_pcm_ops.silence = platform->driver->ops->silence; + soc_pcm_ops.ack = platform->driver->ops->ack; + soc_pcm_ops.page = platform->driver->ops->page; + } if (playback) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); @@ -2116,10 +2141,13 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); - ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm); - if (ret < 0) { - printk(KERN_ERR "asoc: platform pcm constructor failed\n"); - return ret; + if (platform->driver->pcm_new) { + ret = platform->driver->pcm_new(rtd->card->snd_card, + codec_dai, pcm); + if (ret < 0) { + pr_err("asoc: platform pcm constructor failed\n"); + return ret; + } } pcm->private_free = platform->driver->pcm_free; @@ -2147,6 +2175,42 @@ int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register); /** + * snd_soc_codec_readable_register: Report if a register is readable. + * + * @codec: CODEC to query. + * @reg: Register to query. + * + * Boolean function indicating if a CODEC register is readable. + */ +int snd_soc_codec_readable_register(struct snd_soc_codec *codec, + unsigned int reg) +{ + if (codec->readable_register) + return codec->readable_register(codec, reg); + else + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register); + +/** + * snd_soc_codec_writable_register: Report if a register is writable. + * + * @codec: CODEC to query. + * @reg: Register to query. + * + * Boolean function indicating if a CODEC register is writable. + */ +int snd_soc_codec_writable_register(struct snd_soc_codec *codec, + unsigned int reg) +{ + if (codec->writable_register) + return codec->writable_register(codec, reg); + else + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register); + +/** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec * @ops: AC97 bus operations @@ -2228,6 +2292,13 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(snd_soc_write); +unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, + unsigned int reg, const void *data, size_t len) +{ + return codec->bulk_write_raw(codec, reg, data, len); +} +EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw); + /** * snd_soc_update_bits - update codec register bits * @codec: audio codec @@ -3288,6 +3359,8 @@ int snd_soc_register_card(struct snd_soc_card *card) if (!card->name || !card->dev) return -EINVAL; + dev_set_drvdata(card->dev, card); + snd_soc_initialize_card_lists(card); soc_init_card_debugfs(card); @@ -3409,7 +3482,7 @@ int snd_soc_register_dai(struct device *dev, dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); if (dai == NULL) - return -ENOMEM; + return -ENOMEM; /* create DAI component name */ dai->name = fmt_single_name(dev, &dai->id); @@ -3548,7 +3621,7 @@ int snd_soc_register_platform(struct device *dev, platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL); if (platform == NULL) - return -ENOMEM; + return -ENOMEM; /* create platform component name */ platform->name = fmt_single_name(dev, &platform->id); @@ -3666,6 +3739,7 @@ int snd_soc_register_codec(struct device *dev, codec->read = codec_drv->read; codec->volatile_register = codec_drv->volatile_register; codec->readable_register = codec_drv->readable_register; + codec->writable_register = codec_drv->writable_register; codec->dapm.bias_level = SND_SOC_BIAS_OFF; codec->dapm.dev = dev; codec->dapm.codec = codec; @@ -3700,6 +3774,8 @@ int snd_soc_register_codec(struct device *dev, codec->volatile_register = snd_soc_default_volatile_register; if (!codec->readable_register) codec->readable_register = snd_soc_default_readable_register; + if (!codec->writable_register) + codec->writable_register = snd_soc_default_writable_register; } for (i = 0; i < num_dai; i++) { @@ -3788,12 +3864,16 @@ static int __init snd_soc_init(void) pr_warn("ASoC: Failed to create platform list debugfs file\n"); #endif + snd_soc_util_init(); + return platform_driver_register(&soc_driver); } module_init(snd_soc_init); static void __exit snd_soc_exit(void) { + snd_soc_util_exit(); + #ifdef CONFIG_DEBUG_FS debugfs_remove_recursive(snd_soc_debugfs_root); #endif diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 81c4052c127c..999bb08cdfb1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -187,7 +187,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_mixer_named_ctl: { int val; struct soc_mixer_control *mc = (struct soc_mixer_control *) - w->kcontrols[i].private_value; + w->kcontrol_news[i].private_value; unsigned int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; @@ -204,7 +204,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, } break; case snd_soc_dapm_mux: { - struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; + struct soc_enum *e = (struct soc_enum *) + w->kcontrol_news[i].private_value; int val, item, bitmask; for (bitmask = 1; bitmask < e->max; bitmask <<= 1) @@ -220,7 +221,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, } break; case snd_soc_dapm_virt_mux: { - struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; + struct soc_enum *e = (struct soc_enum *) + w->kcontrol_news[i].private_value; p->connect = 0; /* since a virtual mux has no backing registers to @@ -235,7 +237,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, break; case snd_soc_dapm_value_mux: { struct soc_enum *e = (struct soc_enum *) - w->kcontrols[i].private_value; + w->kcontrol_news[i].private_value; int val, item; val = snd_soc_read(w->codec, e->reg); @@ -310,11 +312,11 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, /* search for mixer kcontrol */ for (i = 0; i < dest->num_kcontrols; i++) { - if (!strcmp(control_name, dest->kcontrols[i].name)) { + if (!strcmp(control_name, dest->kcontrol_news[i].name)) { list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &dest->sources); list_add(&path->list_source, &src->sinks); - path->name = dest->kcontrols[i].name; + path->name = dest->kcontrol_news[i].name; dapm_set_path_status(dest, path, i); return 0; } @@ -322,43 +324,26 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, return -ENODEV; } -/* update dapm codec register bits */ -static int dapm_update_bits(struct snd_soc_dapm_widget *widget) +static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, + const struct snd_kcontrol_new *kcontrol_new, + struct snd_kcontrol **kcontrol) { - int change, power; - unsigned int old, new; - struct snd_soc_codec *codec = widget->codec; - struct snd_soc_dapm_context *dapm = widget->dapm; - struct snd_soc_card *card = dapm->card; - - /* check for valid widgets */ - if (widget->reg < 0 || widget->id == snd_soc_dapm_input || - widget->id == snd_soc_dapm_output || - widget->id == snd_soc_dapm_hp || - widget->id == snd_soc_dapm_mic || - widget->id == snd_soc_dapm_line || - widget->id == snd_soc_dapm_spk) - return 0; - - power = widget->power; - if (widget->invert) - power = (power ? 0:1); + struct snd_soc_dapm_widget *w; + int i; - old = snd_soc_read(codec, widget->reg); - new = (old & ~(0x1 << widget->shift)) | (power << widget->shift); + *kcontrol = NULL; - change = old != new; - if (change) { - pop_dbg(dapm->dev, card->pop_time, - "pop test %s : %s in %d ms\n", - widget->name, widget->power ? "on" : "off", - card->pop_time); - pop_wait(card->pop_time); - snd_soc_write(codec, widget->reg, new); + list_for_each_entry(w, &dapm->card->widgets, list) { + for (i = 0; i < w->num_kcontrols; i++) { + if (&w->kcontrol_news[i] == kcontrol_new) { + if (w->kcontrols) + *kcontrol = w->kcontrols[i]; + return 1; + } + } } - dev_dbg(dapm->dev, "reg %x old %x new %x change %d\n", widget->reg, - old, new, change); - return change; + + return 0; } /* create new dapm mixer control */ @@ -370,6 +355,8 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_path *path; struct snd_card *card = dapm->card->snd_card; const char *prefix; + struct snd_soc_dapm_widget_list *wlist; + size_t wlistsize; if (dapm->codec) prefix = dapm->codec->name_prefix; @@ -388,23 +375,37 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, list_for_each_entry(path, &w->sources, list_sink) { /* mixer/mux paths name must match control name */ - if (path->name != (char*)w->kcontrols[i].name) + if (path->name != (char *)w->kcontrol_news[i].name) continue; + wlistsize = sizeof(struct snd_soc_dapm_widget_list) + + sizeof(struct snd_soc_dapm_widget *), + wlist = kzalloc(wlistsize, GFP_KERNEL); + if (wlist == NULL) { + dev_err(dapm->dev, + "asoc: can't allocate widget list for %s\n", + w->name); + return -ENOMEM; + } + wlist->num_widgets = 1; + wlist->widgets[0] = w; + /* add dapm control with long name. * for dapm_mixer this is the concatenation of the * mixer and kcontrol name. * for dapm_mixer_named_ctl this is simply the * kcontrol name. */ - name_len = strlen(w->kcontrols[i].name) + 1; + name_len = strlen(w->kcontrol_news[i].name) + 1; if (w->id != snd_soc_dapm_mixer_named_ctl) name_len += 1 + strlen(w->name); path->long_name = kmalloc(name_len, GFP_KERNEL); - if (path->long_name == NULL) + if (path->long_name == NULL) { + kfree(wlist); return -ENOMEM; + } switch (w->id) { default: @@ -416,27 +417,30 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, */ snprintf(path->long_name, name_len, "%s %s", w->name + prefix_len, - w->kcontrols[i].name); + w->kcontrol_news[i].name); break; case snd_soc_dapm_mixer_named_ctl: snprintf(path->long_name, name_len, "%s", - w->kcontrols[i].name); + w->kcontrol_news[i].name); break; } path->long_name[name_len - 1] = '\0'; - path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, - path->long_name, prefix); + path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], + wlist, path->long_name, + prefix); ret = snd_ctl_add(card, path->kcontrol); if (ret < 0) { dev_err(dapm->dev, "asoc: failed to add dapm kcontrol %s: %d\n", path->long_name, ret); + kfree(wlist); kfree(path->long_name); path->long_name = NULL; return ret; } + w->kcontrols[i] = path->kcontrol; } } return ret; @@ -451,42 +455,80 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm, struct snd_card *card = dapm->card->snd_card; const char *prefix; size_t prefix_len; - int ret = 0; - - if (!w->num_kcontrols) { - dev_err(dapm->dev, "asoc: mux %s has no controls\n", w->name); + int ret; + struct snd_soc_dapm_widget_list *wlist; + int shared, wlistentries; + size_t wlistsize; + char *name; + + if (w->num_kcontrols != 1) { + dev_err(dapm->dev, + "asoc: mux %s has incorrect number of controls\n", + w->name); return -EINVAL; } - if (dapm->codec) - prefix = dapm->codec->name_prefix; - else - prefix = NULL; + shared = dapm_is_shared_kcontrol(dapm, &w->kcontrol_news[0], + &kcontrol); + if (kcontrol) { + wlist = kcontrol->private_data; + wlistentries = wlist->num_widgets + 1; + } else { + wlist = NULL; + wlistentries = 1; + } + wlistsize = sizeof(struct snd_soc_dapm_widget_list) + + wlistentries * sizeof(struct snd_soc_dapm_widget *), + wlist = krealloc(wlist, wlistsize, GFP_KERNEL); + if (wlist == NULL) { + dev_err(dapm->dev, + "asoc: can't allocate widget list for %s\n", w->name); + return -ENOMEM; + } + wlist->num_widgets = wlistentries; + wlist->widgets[wlistentries - 1] = w; - if (prefix) - prefix_len = strlen(prefix) + 1; - else - prefix_len = 0; + if (!kcontrol) { + if (dapm->codec) + prefix = dapm->codec->name_prefix; + else + prefix = NULL; + + if (shared) { + name = w->kcontrol_news[0].name; + prefix_len = 0; + } else { + name = w->name; + if (prefix) + prefix_len = strlen(prefix) + 1; + else + prefix_len = 0; + } - /* The control will get a prefix from the control creation - * process but we're also using the same prefix for widgets so - * cut the prefix off the front of the widget name. - */ - kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name + prefix_len, - prefix); - ret = snd_ctl_add(card, kcontrol); + /* + * The control will get a prefix from the control creation + * process but we're also using the same prefix for widgets so + * cut the prefix off the front of the widget name. + */ + kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist, + name + prefix_len, prefix); + ret = snd_ctl_add(card, kcontrol); + if (ret < 0) { + dev_err(dapm->dev, + "asoc: failed to add kcontrol %s\n", w->name); + kfree(wlist); + return ret; + } + } - if (ret < 0) - goto err; + kcontrol->private_data = wlist; + + w->kcontrols[0] = kcontrol; list_for_each_entry(path, &w->sources, list_sink) path->kcontrol = kcontrol; - return ret; - -err: - dev_err(dapm->dev, "asoc: failed to add kcontrol %s\n", w->name); - return ret; + return 0; } /* create new dapm volume control */ @@ -644,57 +686,6 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(dapm_reg_event); -/* Standard power change method, used to apply power changes to most - * widgets. - */ -static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w) -{ - int ret; - - /* call any power change event handlers */ - if (w->event) - dev_dbg(w->dapm->dev, "power %s event for %s flags %x\n", - w->power ? "on" : "off", - w->name, w->event_flags); - - /* power up pre event */ - if (w->power && w->event && - (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { - ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); - if (ret < 0) - return ret; - } - - /* power down pre event */ - if (!w->power && w->event && - (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { - ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); - if (ret < 0) - return ret; - } - - dapm_update_bits(w); - - /* power up post event */ - if (w->power && w->event && - (w->event_flags & SND_SOC_DAPM_POST_PMU)) { - ret = w->event(w, - NULL, SND_SOC_DAPM_POST_PMU); - if (ret < 0) - return ret; - } - - /* power down post event */ - if (!w->power && w->event && - (w->event_flags & SND_SOC_DAPM_POST_PMD)) { - ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); - if (ret < 0) - return ret; - } - - return 0; -} - /* Generic check to see if a widget should be powered. */ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) @@ -981,16 +972,6 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, NULL, SND_SOC_DAPM_POST_PMD); break; - case snd_soc_dapm_input: - case snd_soc_dapm_output: - case snd_soc_dapm_hp: - case snd_soc_dapm_mic: - case snd_soc_dapm_line: - case snd_soc_dapm_spk: - /* No register support currently */ - ret = dapm_generic_apply_power(w); - break; - default: /* Queue it up for application */ cur_sort = sort[w->id]; @@ -1129,7 +1110,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) trace_snd_soc_dapm_start(card); list_for_each_entry(d, &card->dapm_list, list) - if (d->n_widgets) + if (d->n_widgets || d->codec == NULL) d->dev_power = 0; /* Check which widgets we need to power and store them in @@ -1201,6 +1182,15 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) } } + /* Force all contexts in the card to the same bias state */ + power = 0; + list_for_each_entry(d, &card->dapm_list, list) + if (d->dev_power) + power = 1; + list_for_each_entry(d, &card->dapm_list, list) + d->dev_power = power; + + /* Run all the bias changes in parallel */ list_for_each_entry(d, &dapm->card->dapm_list, list) async_schedule_domain(dapm_pre_sequence_async, d, @@ -1304,31 +1294,104 @@ static const struct file_operations dapm_widget_power_fops = { .llseek = default_llseek, }; -void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm) +static int dapm_bias_open_file(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct snd_soc_dapm_context *dapm = file->private_data; + char *level; + + switch (dapm->bias_level) { + case SND_SOC_BIAS_ON: + level = "On\n"; + break; + case SND_SOC_BIAS_PREPARE: + level = "Prepare\n"; + break; + case SND_SOC_BIAS_STANDBY: + level = "Standby\n"; + break; + case SND_SOC_BIAS_OFF: + level = "Off\n"; + break; + default: + BUG(); + level = "Unknown\n"; + break; + } + + return simple_read_from_buffer(user_buf, count, ppos, level, + strlen(level)); +} + +static const struct file_operations dapm_bias_fops = { + .open = dapm_bias_open_file, + .read = dapm_bias_read_file, + .llseek = default_llseek, +}; + +void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, + struct dentry *parent) { - struct snd_soc_dapm_widget *w; struct dentry *d; - if (!dapm->debugfs_dapm) + dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); + + if (!dapm->debugfs_dapm) { + printk(KERN_WARNING + "Failed to create DAPM debugfs directory\n"); return; + } - list_for_each_entry(w, &dapm->card->widgets, list) { - if (!w->name || w->dapm != dapm) - continue; + d = debugfs_create_file("bias_level", 0444, + dapm->debugfs_dapm, dapm, + &dapm_bias_fops); + if (!d) + dev_warn(dapm->dev, + "ASoC: Failed to create bias level debugfs file\n"); +} - d = debugfs_create_file(w->name, 0444, - dapm->debugfs_dapm, w, - &dapm_widget_power_fops); - if (!d) - dev_warn(w->dapm->dev, - "ASoC: Failed to create %s debugfs file\n", - w->name); - } +static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct dentry *d; + + if (!dapm->debugfs_dapm || !w->name) + return; + + d = debugfs_create_file(w->name, 0444, + dapm->debugfs_dapm, w, + &dapm_widget_power_fops); + if (!d) + dev_warn(w->dapm->dev, + "ASoC: Failed to create %s debugfs file\n", + w->name); +} + +static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) +{ + debugfs_remove_recursive(dapm->debugfs_dapm); } + #else -void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm) +void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, + struct dentry *parent) +{ +} + +static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) +{ +} + +static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) { } + #endif /* test and update the power status of a mux widget */ @@ -1496,32 +1559,49 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) kfree(p->long_name); kfree(p); } + kfree(w->kcontrols); kfree(w->name); kfree(w); } } -static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, - const char *pin, int status) +static struct snd_soc_dapm_widget *dapm_find_widget( + struct snd_soc_dapm_context *dapm, const char *pin, + bool search_other_contexts) { struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_widget *fallback = NULL; list_for_each_entry(w, &dapm->card->widgets, list) { - if (w->dapm != dapm) - continue; if (!strcmp(w->name, pin)) { - dev_dbg(w->dapm->dev, "dapm: pin %s = %d\n", - pin, status); - w->connected = status; - /* Allow disabling of forced pins */ - if (status == 0) - w->force = 0; - return 0; + if (w->dapm == dapm) + return w; + else + fallback = w; } } - dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); - return -EINVAL; + if (search_other_contexts) + return fallback; + + return NULL; +} + +static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, + const char *pin, int status) +{ + struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); + + if (!w) { + dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); + return -EINVAL; + } + + w->connected = status; + if (status == 0) + w->force = 0; + + return 0; } /** @@ -1627,7 +1707,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, } /* connect dynamic paths */ - switch(wsink->id) { + switch (wsink->id) { case snd_soc_dapm_adc: case snd_soc_dapm_dac: case snd_soc_dapm_pga: @@ -1650,7 +1730,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, case snd_soc_dapm_virt_mux: case snd_soc_dapm_value_mux: ret = dapm_connect_mux(dapm, wsource, wsink, path, control, - &wsink->kcontrols[0]); + &wsink->kcontrol_news[0]); if (ret != 0) goto err; break; @@ -1730,6 +1810,14 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) if (w->new) continue; + if (w->num_kcontrols) { + w->kcontrols = kzalloc(w->num_kcontrols * + sizeof(struct snd_kcontrol *), + GFP_KERNEL); + if (!w->kcontrols) + return -ENOMEM; + } + switch(w->id) { case snd_soc_dapm_switch: case snd_soc_dapm_mixer: @@ -1785,6 +1873,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) } w->new = 1; + + dapm_debugfs_add_widget(w); } dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); @@ -1804,7 +1894,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int reg = mc->reg; @@ -1843,7 +1934,9 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = widget->codec; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int reg = mc->reg; @@ -1854,6 +1947,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, unsigned int val; int connect, change; struct snd_soc_dapm_update update; + int wi; val = (ucontrol->value.integer.value[0] & mask); @@ -1862,31 +1956,36 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, mask = mask << shift; val = val << shift; - mutex_lock(&widget->codec->mutex); - widget->value = val; + if (val) + /* new connection */ + connect = invert ? 0 : 1; + else + /* old connection must be powered down */ + connect = invert ? 1 : 0; + + mutex_lock(&codec->mutex); change = snd_soc_test_bits(widget->codec, reg, mask, val); if (change) { - if (val) - /* new connection */ - connect = invert ? 0:1; - else - /* old connection must be powered down */ - connect = invert ? 1:0; + for (wi = 0; wi < wlist->num_widgets; wi++) { + widget = wlist->widgets[wi]; - update.kcontrol = kcontrol; - update.widget = widget; - update.reg = reg; - update.mask = mask; - update.val = val; - widget->dapm->update = &update; + widget->value = val; - dapm_mixer_update_power(widget, kcontrol, connect); + update.kcontrol = kcontrol; + update.widget = widget; + update.reg = reg; + update.mask = mask; + update.val = val; + widget->dapm->update = &update; - widget->dapm->update = NULL; + dapm_mixer_update_power(widget, kcontrol, connect); + + widget->dapm->update = NULL; + } } - mutex_unlock(&widget->codec->mutex); + mutex_unlock(&codec->mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); @@ -1903,7 +2002,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int val, bitmask; @@ -1931,11 +2031,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = widget->codec; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int val, mux, change; unsigned int mask, bitmask; struct snd_soc_dapm_update update; + int wi; for (bitmask = 1; bitmask < e->max; bitmask <<= 1) ; @@ -1951,22 +2054,29 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, mask |= (bitmask - 1) << e->shift_r; } - mutex_lock(&widget->codec->mutex); - widget->value = val; + mutex_lock(&codec->mutex); + change = snd_soc_test_bits(widget->codec, e->reg, mask, val); + if (change) { + for (wi = 0; wi < wlist->num_widgets; wi++) { + widget = wlist->widgets[wi]; - update.kcontrol = kcontrol; - update.widget = widget; - update.reg = e->reg; - update.mask = mask; - update.val = val; - widget->dapm->update = &update; + widget->value = val; - dapm_mux_update_power(widget, kcontrol, change, mux, e); + update.kcontrol = kcontrol; + update.widget = widget; + update.reg = e->reg; + update.mask = mask; + update.val = val; + widget->dapm->update = &update; - widget->dapm->update = NULL; + dapm_mux_update_power(widget, kcontrol, change, mux, e); - mutex_unlock(&widget->codec->mutex); + widget->dapm->update = NULL; + } + } + + mutex_unlock(&codec->mutex); return change; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); @@ -1981,7 +2091,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; ucontrol->value.enumerated.item[0] = widget->value; @@ -1999,22 +2110,33 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = widget->codec; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int change; int ret = 0; + int wi; if (ucontrol->value.enumerated.item[0] >= e->max) return -EINVAL; - mutex_lock(&widget->codec->mutex); + mutex_lock(&codec->mutex); change = widget->value != ucontrol->value.enumerated.item[0]; - widget->value = ucontrol->value.enumerated.item[0]; - dapm_mux_update_power(widget, kcontrol, change, widget->value, e); + if (change) { + for (wi = 0; wi < wlist->num_widgets; wi++) { + widget = wlist->widgets[wi]; - mutex_unlock(&widget->codec->mutex); + widget->value = ucontrol->value.enumerated.item[0]; + + dapm_mux_update_power(widget, kcontrol, change, + widget->value, e); + } + } + + mutex_unlock(&codec->mutex); return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); @@ -2035,7 +2157,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int reg_val, val, mux; @@ -2075,11 +2198,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = widget->codec; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int val, mux, change; unsigned int mask; struct snd_soc_dapm_update update; + int wi; if (ucontrol->value.enumerated.item[0] > e->max - 1) return -EINVAL; @@ -2093,22 +2219,29 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, mask |= e->mask << e->shift_r; } - mutex_lock(&widget->codec->mutex); - widget->value = val; + mutex_lock(&codec->mutex); + change = snd_soc_test_bits(widget->codec, e->reg, mask, val); + if (change) { + for (wi = 0; wi < wlist->num_widgets; wi++) { + widget = wlist->widgets[wi]; - update.kcontrol = kcontrol; - update.widget = widget; - update.reg = e->reg; - update.mask = mask; - update.val = val; - widget->dapm->update = &update; + widget->value = val; - dapm_mux_update_power(widget, kcontrol, change, mux, e); + update.kcontrol = kcontrol; + update.widget = widget; + update.reg = e->reg; + update.mask = mask; + update.val = val; + widget->dapm->update = &update; - widget->dapm->update = NULL; + dapm_mux_update_power(widget, kcontrol, change, mux, e); + + widget->dapm->update = NULL; + } + } - mutex_unlock(&widget->codec->mutex); + mutex_unlock(&codec->mutex); return change; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); @@ -2346,22 +2479,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin) { - struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); - list_for_each_entry(w, &dapm->card->widgets, list) { - if (w->dapm != dapm) - continue; - if (!strcmp(w->name, pin)) { - dev_dbg(w->dapm->dev, - "dapm: force enable pin %s\n", pin); - w->connected = 1; - w->force = 1; - return 0; - } + if (!w) { + dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); + return -EINVAL; } - dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); - return -EINVAL; + dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin); + w->connected = 1; + w->force = 1; + + return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin); @@ -2413,14 +2542,10 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, const char *pin) { - struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); - list_for_each_entry(w, &dapm->card->widgets, list) { - if (w->dapm != dapm) - continue; - if (!strcmp(w->name, pin)) - return w->connected; - } + if (w) + return w->connected; return 0; } @@ -2440,19 +2565,16 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin) { - struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false); - list_for_each_entry(w, &dapm->card->widgets, list) { - if (w->dapm != dapm) - continue; - if (!strcmp(w->name, pin)) { - w->ignore_suspend = 1; - return 0; - } + if (!w) { + dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); + return -EINVAL; } - dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); - return -EINVAL; + w->ignore_suspend = 1; + + return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); @@ -2465,6 +2587,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) { snd_soc_dapm_sys_remove(dapm->dev); + dapm_debugfs_cleanup(dapm); dapm_free_widgets(dapm); list_del(&dapm->list); } diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index fcab80b36a37..7c17b98d5846 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -325,13 +325,13 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, gpio_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - jack->codec->dev->driver->name, + gpios[i].name, &gpios[i]); if (ret) goto err; if (gpios[i].wake) { - ret = set_irq_wake(gpio_to_irq(gpios[i].gpio), 1); + ret = irq_set_irq_wake(gpio_to_irq(gpios[i].gpio), 1); if (ret != 0) printk(KERN_ERR "Failed to mark GPIO %d as wake source: %d\n", diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 3f45e6a439bf..ec921ec99c26 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -13,6 +13,7 @@ * option) any later version. */ +#include <linux/platform_device.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -55,3 +56,55 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) return ret; } EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); + +static struct snd_soc_platform_driver dummy_platform; + +static __devinit int snd_soc_dummy_probe(struct platform_device *pdev) +{ + return snd_soc_register_platform(&pdev->dev, &dummy_platform); +} + +static __devexit int snd_soc_dummy_remove(struct platform_device *pdev) +{ + snd_soc_unregister_platform(&pdev->dev); + + return 0; +} + +static struct platform_driver soc_dummy_driver = { + .driver = { + .name = "snd-soc-dummy", + .owner = THIS_MODULE, + }, + .probe = snd_soc_dummy_probe, + .remove = __devexit_p(snd_soc_dummy_remove), +}; + +static struct platform_device *soc_dummy_dev; + +int __init snd_soc_util_init(void) +{ + int ret; + + soc_dummy_dev = platform_device_alloc("snd-soc-dummy", -1); + if (!soc_dummy_dev) + return -ENOMEM; + + ret = platform_device_add(soc_dummy_dev); + if (ret != 0) { + platform_device_put(soc_dummy_dev); + return ret; + } + + ret = platform_driver_register(&soc_dummy_driver); + if (ret != 0) + platform_device_unregister(soc_dummy_dev); + + return ret; +} + +void __exit snd_soc_util_exit(void) +{ + platform_device_unregister(soc_dummy_dev); + platform_driver_unregister(&soc_dummy_driver); +} diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 66b504f06c23..035d39a4beb4 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -1,26 +1,40 @@ -config SND_TEGRA_SOC +config SND_SOC_TEGRA tristate "SoC Audio for the Tegra System-on-Chip" depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA - default m help Say Y or M here if you want support for SoC audio on Tegra. -config SND_TEGRA_SOC_I2S +config SND_SOC_TEGRA_I2S tristate - depends on SND_TEGRA_SOC - default m + depends on SND_SOC_TEGRA help Say Y or M if you want to add support for codecs attached to the Tegra I2S interface. You will also need to select the individual machine drivers to support below. -config SND_TEGRA_SOC_HARMONY - tristate "SoC Audio support for Tegra Harmony reference board" - depends on SND_TEGRA_SOC && MACH_HARMONY && I2C - default m - select SND_TEGRA_SOC_I2S +config MACH_HAS_SND_SOC_TEGRA_WM8903 + bool + help + Machines that use the SND_SOC_TEGRA_WM8903 driver should select + this config option, in order to allow the user to enable + SND_SOC_TEGRA_WM8903. + +config SND_SOC_TEGRA_WM8903 + tristate "SoC Audio support for Tegra boards using a WM8903 codec" + depends on SND_SOC_TEGRA && I2C + depends on MACH_HAS_SND_SOC_TEGRA_WM8903 + select SND_SOC_TEGRA_I2S select SND_SOC_WM8903 help - Say Y or M here if you want to add support for SoC audio on the - Tegra Harmony reference board. + Say Y or M here if you want to add support for SoC audio on Tegra + boards using the WM8093 codec. Currently, the supported boards are + Harmony, Ventana, Seaboard, Kaen, and Aebl. +config SND_SOC_TEGRA_TRIMSLICE + tristate "SoC Audio support for TrimSlice board" + depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C + select SND_SOC_TEGRA_I2S + select SND_SOC_TLV320AIC23 + help + Say Y or M here if you want to add support for SoC audio on the + TrimSlice platform. diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index fd183d3ab4f1..fa6574d92a31 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -4,12 +4,14 @@ snd-soc-tegra-pcm-objs := tegra_pcm.o snd-soc-tegra-i2s-objs := tegra_i2s.o snd-soc-tegra-utils-objs += tegra_asoc_utils.o -obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-utils.o -obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-das.o -obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-pcm.o -obj-$(CONFIG_SND_TEGRA_SOC_I2S) += snd-soc-tegra-i2s.o +obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o +obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o +obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o +obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o # Tegra machine Support -snd-soc-tegra-harmony-objs := harmony.o +snd-soc-tegra-wm8903-objs := tegra_wm8903.o +snd-soc-tegra-trimslice-objs := trimslice.o -obj-$(CONFIG_SND_TEGRA_SOC_HARMONY) += snd-soc-tegra-harmony.o +obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o +obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o diff --git a/sound/soc/tegra/harmony.c b/sound/soc/tegra/harmony.c deleted file mode 100644 index 8585957477eb..000000000000 --- a/sound/soc/tegra/harmony.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * harmony.c - Harmony machine ASoC driver - * - * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010-2011 - NVIDIA, Inc. - * - * Based on code copyright/by: - * - * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. - * - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <asm/mach-types.h> - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/gpio.h> - -#include <mach/harmony_audio.h> - -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "../codecs/wm8903.h" - -#include "tegra_das.h" -#include "tegra_i2s.h" -#include "tegra_pcm.h" -#include "tegra_asoc_utils.h" - -#define DRV_NAME "tegra-snd-harmony" - -#define GPIO_SPKR_EN BIT(0) -#define GPIO_INT_MIC_EN BIT(1) -#define GPIO_EXT_MIC_EN BIT(2) - -struct tegra_harmony { - struct tegra_asoc_utils_data util_data; - struct harmony_audio_platform_data *pdata; - int gpio_requested; -}; - -static int harmony_asoc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_card *card = codec->card; - struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card); - int srate, mclk, mclk_change; - int err; - - srate = params_rate(params); - switch (srate) { - case 64000: - case 88200: - case 96000: - mclk = 128 * srate; - break; - default: - mclk = 256 * srate; - break; - } - /* FIXME: Codec only requires >= 3MHz if OSR==0 */ - while (mclk < 6000000) - mclk *= 2; - - err = tegra_asoc_utils_set_rate(&harmony->util_data, srate, mclk, - &mclk_change); - if (err < 0) { - dev_err(card->dev, "Can't configure clocks\n"); - return err; - } - - err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); - if (err < 0) { - dev_err(card->dev, "codec_dai fmt not set\n"); - return err; - } - - err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); - if (err < 0) { - dev_err(card->dev, "cpu_dai fmt not set\n"); - return err; - } - - if (mclk_change) { - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return err; - } - } - - return 0; -} - -static struct snd_soc_ops harmony_asoc_ops = { - .hw_params = harmony_asoc_hw_params, -}; - -static struct snd_soc_jack harmony_hp_jack; - -static struct snd_soc_jack_pin harmony_hp_jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static struct snd_soc_jack_gpio harmony_hp_jack_gpios[] = { - { - .name = "headphone detect", - .report = SND_JACK_HEADPHONE, - .debounce_time = 150, - .invert = 1, - } -}; - -static struct snd_soc_jack harmony_mic_jack; - -static struct snd_soc_jack_pin harmony_mic_jack_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static int harmony_event_int_spk(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_codec *codec = w->codec; - struct snd_soc_card *card = codec->card; - struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card); - struct harmony_audio_platform_data *pdata = harmony->pdata; - - gpio_set_value_cansleep(pdata->gpio_spkr_en, - SND_SOC_DAPM_EVENT_ON(event)); - - return 0; -} - -static const struct snd_soc_dapm_widget harmony_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Int Spk", harmony_event_int_spk), - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), -}; - -static const struct snd_soc_dapm_route harmony_audio_map[] = { - {"Headphone Jack", NULL, "HPOUTR"}, - {"Headphone Jack", NULL, "HPOUTL"}, - {"Int Spk", NULL, "ROP"}, - {"Int Spk", NULL, "RON"}, - {"Int Spk", NULL, "LOP"}, - {"Int Spk", NULL, "LON"}, - {"Mic Bias", NULL, "Mic Jack"}, - {"IN1L", NULL, "Mic Bias"}, -}; - -static const struct snd_kcontrol_new harmony_controls[] = { - SOC_DAPM_PIN_SWITCH("Int Spk"), -}; - -static int harmony_asoc_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - struct snd_soc_card *card = codec->card; - struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card); - struct harmony_audio_platform_data *pdata = harmony->pdata; - int ret; - - ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); - if (ret) { - dev_err(card->dev, "cannot get spkr_en gpio\n"); - return ret; - } - harmony->gpio_requested |= GPIO_SPKR_EN; - - gpio_direction_output(pdata->gpio_spkr_en, 0); - - ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); - if (ret) { - dev_err(card->dev, "cannot get int_mic_en gpio\n"); - return ret; - } - harmony->gpio_requested |= GPIO_INT_MIC_EN; - - /* Disable int mic; enable signal is active-high */ - gpio_direction_output(pdata->gpio_int_mic_en, 0); - - ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); - if (ret) { - dev_err(card->dev, "cannot get ext_mic_en gpio\n"); - return ret; - } - harmony->gpio_requested |= GPIO_EXT_MIC_EN; - - /* Enable ext mic; enable signal is active-low */ - gpio_direction_output(pdata->gpio_ext_mic_en, 0); - - ret = snd_soc_add_controls(codec, harmony_controls, - ARRAY_SIZE(harmony_controls)); - if (ret < 0) - return ret; - - snd_soc_dapm_new_controls(dapm, harmony_dapm_widgets, - ARRAY_SIZE(harmony_dapm_widgets)); - - snd_soc_dapm_add_routes(dapm, harmony_audio_map, - ARRAY_SIZE(harmony_audio_map)); - - harmony_hp_jack_gpios[0].gpio = pdata->gpio_hp_det; - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, - &harmony_hp_jack); - snd_soc_jack_add_pins(&harmony_hp_jack, - ARRAY_SIZE(harmony_hp_jack_pins), - harmony_hp_jack_pins); - snd_soc_jack_add_gpios(&harmony_hp_jack, - ARRAY_SIZE(harmony_hp_jack_gpios), - harmony_hp_jack_gpios); - - snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, - &harmony_mic_jack); - snd_soc_jack_add_pins(&harmony_mic_jack, - ARRAY_SIZE(harmony_mic_jack_pins), - harmony_mic_jack_pins); - wm8903_mic_detect(codec, &harmony_mic_jack, SND_JACK_MICROPHONE, 0); - - snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); - - snd_soc_dapm_nc_pin(dapm, "IN3L"); - snd_soc_dapm_nc_pin(dapm, "IN3R"); - snd_soc_dapm_nc_pin(dapm, "LINEOUTL"); - snd_soc_dapm_nc_pin(dapm, "LINEOUTR"); - - snd_soc_dapm_sync(dapm); - - return 0; -} - -static struct snd_soc_dai_link harmony_wm8903_dai = { - .name = "WM8903", - .stream_name = "WM8903 PCM", - .codec_name = "wm8903.0-001a", - .platform_name = "tegra-pcm-audio", - .cpu_dai_name = "tegra-i2s.0", - .codec_dai_name = "wm8903-hifi", - .init = harmony_asoc_init, - .ops = &harmony_asoc_ops, -}; - -static struct snd_soc_card snd_soc_harmony = { - .name = "tegra-harmony", - .dai_link = &harmony_wm8903_dai, - .num_links = 1, -}; - -static __devinit int tegra_snd_harmony_probe(struct platform_device *pdev) -{ - struct snd_soc_card *card = &snd_soc_harmony; - struct tegra_harmony *harmony; - struct harmony_audio_platform_data *pdata; - int ret; - - if (!machine_is_harmony()) { - dev_err(&pdev->dev, "Not running on Tegra Harmony!\n"); - return -ENODEV; - } - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "no platform data supplied\n"); - return -EINVAL; - } - - harmony = kzalloc(sizeof(struct tegra_harmony), GFP_KERNEL); - if (!harmony) { - dev_err(&pdev->dev, "Can't allocate tegra_harmony\n"); - return -ENOMEM; - } - - harmony->pdata = pdata; - - ret = tegra_asoc_utils_init(&harmony->util_data, &pdev->dev); - if (ret) - goto err_free_harmony; - - card->dev = &pdev->dev; - platform_set_drvdata(pdev, card); - snd_soc_card_set_drvdata(card, harmony); - - ret = snd_soc_register_card(card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); - goto err_clear_drvdata; - } - - return 0; - -err_clear_drvdata: - snd_soc_card_set_drvdata(card, NULL); - platform_set_drvdata(pdev, NULL); - card->dev = NULL; - tegra_asoc_utils_fini(&harmony->util_data); -err_free_harmony: - kfree(harmony); - return ret; -} - -static int __devexit tegra_snd_harmony_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card); - struct harmony_audio_platform_data *pdata = harmony->pdata; - - snd_soc_unregister_card(card); - - snd_soc_card_set_drvdata(card, NULL); - platform_set_drvdata(pdev, NULL); - card->dev = NULL; - - tegra_asoc_utils_fini(&harmony->util_data); - - if (harmony->gpio_requested & GPIO_EXT_MIC_EN) - gpio_free(pdata->gpio_ext_mic_en); - if (harmony->gpio_requested & GPIO_INT_MIC_EN) - gpio_free(pdata->gpio_int_mic_en); - if (harmony->gpio_requested & GPIO_SPKR_EN) - gpio_free(pdata->gpio_spkr_en); - - kfree(harmony); - - return 0; -} - -static struct platform_driver tegra_snd_harmony_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, - .probe = tegra_snd_harmony_probe, - .remove = __devexit_p(tegra_snd_harmony_remove), -}; - -static int __init snd_tegra_harmony_init(void) -{ - return platform_driver_register(&tegra_snd_harmony_driver); -} -module_init(snd_tegra_harmony_init); - -static void __exit snd_tegra_harmony_exit(void) -{ - platform_driver_unregister(&tegra_snd_harmony_driver); -} -module_exit(snd_tegra_harmony_exit); - -MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); -MODULE_DESCRIPTION("Harmony machine ASoC driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index 52f0a3f9ce40..dfa85cbb05c8 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -28,9 +28,10 @@ #include "tegra_asoc_utils.h" int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, - int mclk, int *mclk_change) + int mclk) { int new_baseclock; + bool clk_change; int err; switch (srate) { @@ -52,10 +53,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, return -EINVAL; } - *mclk_change = ((new_baseclock != data->set_baseclock) || + clk_change = ((new_baseclock != data->set_baseclock) || (mclk != data->set_mclk)); - if (!*mclk_change) - return 0; + if (!clk_change) + return 0; data->set_baseclock = 0; data->set_mclk = 0; diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index bbba7afdfc2c..4818195da25c 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h @@ -36,7 +36,7 @@ struct tegra_asoc_utils_data { }; int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, - int mclk, int *mclk_change); + int mclk); int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, struct device *dev); void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data); diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 4f5e2c90b020..6b817e20548c 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -114,7 +114,7 @@ static void tegra_i2s_debug_remove(struct tegra_i2s *i2s) debugfs_remove(i2s->debug); } #else -static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s) +static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id) { } diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c new file mode 100644 index 000000000000..0d6738a8b29a --- /dev/null +++ b/sound/soc/tegra/tegra_wm8903.c @@ -0,0 +1,475 @@ +/* + * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec. + * + * Author: Stephen Warren <swarren@nvidia.com> + * Copyright (C) 2010-2011 - NVIDIA, Inc. + * + * Based on code copyright/by: + * + * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. + * + * Copyright 2007 Wolfson Microelectronics PLC. + * Author: Graeme Gregory + * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <asm/mach-types.h> + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/gpio.h> + +#include <mach/tegra_wm8903_pdata.h> + +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "../codecs/wm8903.h" + +#include "tegra_das.h" +#include "tegra_i2s.h" +#include "tegra_pcm.h" +#include "tegra_asoc_utils.h" + +#define DRV_NAME "tegra-snd-wm8903" + +#define GPIO_SPKR_EN BIT(0) +#define GPIO_HP_MUTE BIT(1) +#define GPIO_INT_MIC_EN BIT(2) +#define GPIO_EXT_MIC_EN BIT(3) + +struct tegra_wm8903 { + struct tegra_asoc_utils_data util_data; + struct tegra_wm8903_platform_data *pdata; + int gpio_requested; +}; + +static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = codec->card; + struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); + int srate, mclk; + int err; + + srate = params_rate(params); + switch (srate) { + case 64000: + case 88200: + case 96000: + mclk = 128 * srate; + break; + default: + mclk = 256 * srate; + break; + } + /* FIXME: Codec only requires >= 3MHz if OSR==0 */ + while (mclk < 6000000) + mclk *= 2; + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + + err = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + dev_err(card->dev, "codec_dai fmt not set\n"); + return err; + } + + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + dev_err(card->dev, "cpu_dai fmt not set\n"); + return err; + } + + err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, + SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return err; + } + + return 0; +} + +static struct snd_soc_ops tegra_wm8903_ops = { + .hw_params = tegra_wm8903_hw_params, +}; + +static struct snd_soc_jack tegra_wm8903_hp_jack; + +static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, +}; + +static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = { + .name = "headphone detect", + .report = SND_JACK_HEADPHONE, + .debounce_time = 150, + .invert = 1, +}; + +static struct snd_soc_jack tegra_wm8903_mic_jack; + +static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); + struct tegra_wm8903_platform_data *pdata = machine->pdata; + + if (!(machine->gpio_requested & GPIO_SPKR_EN)) + return 0; + + gpio_set_value_cansleep(pdata->gpio_spkr_en, + SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); + struct tegra_wm8903_platform_data *pdata = machine->pdata; + + if (!(machine->gpio_requested & GPIO_HP_MUTE)) + return 0; + + gpio_set_value_cansleep(pdata->gpio_hp_mute, + !SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), + SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp), + SND_SOC_DAPM_MIC("Mic Jack", NULL), +}; + +static const struct snd_soc_dapm_route harmony_audio_map[] = { + {"Headphone Jack", NULL, "HPOUTR"}, + {"Headphone Jack", NULL, "HPOUTL"}, + {"Int Spk", NULL, "ROP"}, + {"Int Spk", NULL, "RON"}, + {"Int Spk", NULL, "LOP"}, + {"Int Spk", NULL, "LON"}, + {"Mic Bias", NULL, "Mic Jack"}, + {"IN1L", NULL, "Mic Bias"}, +}; + +static const struct snd_soc_dapm_route seaboard_audio_map[] = { + {"Headphone Jack", NULL, "HPOUTR"}, + {"Headphone Jack", NULL, "HPOUTL"}, + {"Int Spk", NULL, "ROP"}, + {"Int Spk", NULL, "RON"}, + {"Int Spk", NULL, "LOP"}, + {"Int Spk", NULL, "LON"}, + {"Mic Bias", NULL, "Mic Jack"}, + {"IN1R", NULL, "Mic Bias"}, +}; + +static const struct snd_soc_dapm_route kaen_audio_map[] = { + {"Headphone Jack", NULL, "HPOUTR"}, + {"Headphone Jack", NULL, "HPOUTL"}, + {"Int Spk", NULL, "ROP"}, + {"Int Spk", NULL, "RON"}, + {"Int Spk", NULL, "LOP"}, + {"Int Spk", NULL, "LON"}, + {"Mic Bias", NULL, "Mic Jack"}, + {"IN2R", NULL, "Mic Bias"}, +}; + +static const struct snd_soc_dapm_route aebl_audio_map[] = { + {"Headphone Jack", NULL, "HPOUTR"}, + {"Headphone Jack", NULL, "HPOUTL"}, + {"Int Spk", NULL, "LINEOUTR"}, + {"Int Spk", NULL, "LINEOUTL"}, + {"Mic Bias", NULL, "Mic Jack"}, + {"IN1R", NULL, "Mic Bias"}, +}; + +static const struct snd_kcontrol_new tegra_wm8903_controls[] = { + SOC_DAPM_PIN_SWITCH("Int Spk"), +}; + +static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_card *card = codec->card; + struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); + struct tegra_wm8903_platform_data *pdata = machine->pdata; + int ret; + + if (gpio_is_valid(pdata->gpio_spkr_en)) { + ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); + if (ret) { + dev_err(card->dev, "cannot get spkr_en gpio\n"); + return ret; + } + machine->gpio_requested |= GPIO_SPKR_EN; + + gpio_direction_output(pdata->gpio_spkr_en, 0); + } + + if (gpio_is_valid(pdata->gpio_hp_mute)) { + ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); + if (ret) { + dev_err(card->dev, "cannot get hp_mute gpio\n"); + return ret; + } + machine->gpio_requested |= GPIO_HP_MUTE; + + gpio_direction_output(pdata->gpio_hp_mute, 0); + } + + if (gpio_is_valid(pdata->gpio_int_mic_en)) { + ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); + if (ret) { + dev_err(card->dev, "cannot get int_mic_en gpio\n"); + return ret; + } + machine->gpio_requested |= GPIO_INT_MIC_EN; + + /* Disable int mic; enable signal is active-high */ + gpio_direction_output(pdata->gpio_int_mic_en, 0); + } + + if (gpio_is_valid(pdata->gpio_ext_mic_en)) { + ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); + if (ret) { + dev_err(card->dev, "cannot get ext_mic_en gpio\n"); + return ret; + } + machine->gpio_requested |= GPIO_EXT_MIC_EN; + + /* Enable ext mic; enable signal is active-low */ + gpio_direction_output(pdata->gpio_ext_mic_en, 0); + } + + if (gpio_is_valid(pdata->gpio_hp_det)) { + tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; + snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, + &tegra_wm8903_hp_jack); + snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, + ARRAY_SIZE(tegra_wm8903_hp_jack_pins), + tegra_wm8903_hp_jack_pins); + snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, + 1, + &tegra_wm8903_hp_jack_gpio); + } + + snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, + &tegra_wm8903_mic_jack); + snd_soc_jack_add_pins(&tegra_wm8903_mic_jack, + ARRAY_SIZE(tegra_wm8903_mic_jack_pins), + tegra_wm8903_mic_jack_pins); + wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, + 0); + + snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); + + /* FIXME: Calculate automatically based on DAPM routes? */ + if (!machine_is_harmony() && !machine_is_ventana()) + snd_soc_dapm_nc_pin(dapm, "IN1L"); + if (!machine_is_seaboard() && !machine_is_aebl()) + snd_soc_dapm_nc_pin(dapm, "IN1R"); + snd_soc_dapm_nc_pin(dapm, "IN2L"); + if (!machine_is_kaen()) + snd_soc_dapm_nc_pin(dapm, "IN2R"); + snd_soc_dapm_nc_pin(dapm, "IN3L"); + snd_soc_dapm_nc_pin(dapm, "IN3R"); + + if (machine_is_aebl()) { + snd_soc_dapm_nc_pin(dapm, "LON"); + snd_soc_dapm_nc_pin(dapm, "RON"); + snd_soc_dapm_nc_pin(dapm, "ROP"); + snd_soc_dapm_nc_pin(dapm, "LOP"); + } else { + snd_soc_dapm_nc_pin(dapm, "LINEOUTR"); + snd_soc_dapm_nc_pin(dapm, "LINEOUTL"); + } + + snd_soc_dapm_sync(dapm); + + return 0; +} + +static struct snd_soc_dai_link tegra_wm8903_dai = { + .name = "WM8903", + .stream_name = "WM8903 PCM", + .codec_name = "wm8903.0-001a", + .platform_name = "tegra-pcm-audio", + .cpu_dai_name = "tegra-i2s.0", + .codec_dai_name = "wm8903-hifi", + .init = tegra_wm8903_init, + .ops = &tegra_wm8903_ops, +}; + +static struct snd_soc_card snd_soc_tegra_wm8903 = { + .name = "tegra-wm8903", + .dai_link = &tegra_wm8903_dai, + .num_links = 1, + + .controls = tegra_wm8903_controls, + .num_controls = ARRAY_SIZE(tegra_wm8903_controls), + .dapm_widgets = tegra_wm8903_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets), +}; + +static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_tegra_wm8903; + struct tegra_wm8903 *machine; + struct tegra_wm8903_platform_data *pdata; + int ret; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "No platform data supplied\n"); + return -EINVAL; + } + + machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL); + if (!machine) { + dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n"); + return -ENOMEM; + } + + machine->pdata = pdata; + + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + if (ret) + goto err_free_machine; + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + + if (machine_is_harmony() || machine_is_ventana()) { + card->dapm_routes = harmony_audio_map; + card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); + } else if (machine_is_seaboard()) { + card->dapm_routes = seaboard_audio_map; + card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); + } else if (machine_is_kaen()) { + card->dapm_routes = kaen_audio_map; + card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); + } else { + card->dapm_routes = aebl_audio_map; + card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); + } + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_fini_utils; + } + + return 0; + +err_fini_utils: + tegra_asoc_utils_fini(&machine->util_data); +err_free_machine: + kfree(machine); + return ret; +} + +static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); + struct tegra_wm8903_platform_data *pdata = machine->pdata; + + snd_soc_unregister_card(card); + + tegra_asoc_utils_fini(&machine->util_data); + + if (machine->gpio_requested & GPIO_EXT_MIC_EN) + gpio_free(pdata->gpio_ext_mic_en); + if (machine->gpio_requested & GPIO_INT_MIC_EN) + gpio_free(pdata->gpio_int_mic_en); + if (machine->gpio_requested & GPIO_HP_MUTE) + gpio_free(pdata->gpio_hp_mute); + if (machine->gpio_requested & GPIO_SPKR_EN) + gpio_free(pdata->gpio_spkr_en); + + kfree(machine); + + return 0; +} + +static struct platform_driver tegra_wm8903_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = tegra_wm8903_driver_probe, + .remove = __devexit_p(tegra_wm8903_driver_remove), +}; + +static int __init tegra_wm8903_modinit(void) +{ + return platform_driver_register(&tegra_wm8903_driver); +} +module_init(tegra_wm8903_modinit); + +static void __exit tegra_wm8903_modexit(void) +{ + platform_driver_unregister(&tegra_wm8903_driver); +} +module_exit(tegra_wm8903_modexit); + +MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); +MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c new file mode 100644 index 000000000000..8fc07e9adf2e --- /dev/null +++ b/sound/soc/tegra/trimslice.c @@ -0,0 +1,228 @@ +/* + * trimslice.c - TrimSlice machine ASoC driver + * + * Copyright (C) 2011 - CompuLab, Ltd. + * Author: Mike Rapoport <mike@compulab.co.il> + * + * Based on code copyright/by: + * Author: Stephen Warren <swarren@nvidia.com> + * Copyright (C) 2010-2011 - NVIDIA, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <asm/mach-types.h> + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "../codecs/tlv320aic23.h" + +#include "tegra_das.h" +#include "tegra_i2s.h" +#include "tegra_pcm.h" +#include "tegra_asoc_utils.h" + +#define DRV_NAME "tegra-snd-trimslice" + +struct tegra_trimslice { + struct tegra_asoc_utils_data util_data; +}; + +static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = codec->card; + struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); + int srate, mclk; + int err; + + srate = params_rate(params); + mclk = 128 * srate; + + err = tegra_asoc_utils_set_rate(&trimslice->util_data, srate, mclk); + if (err < 0) { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + + err = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + dev_err(card->dev, "codec_dai fmt not set\n"); + return err; + } + + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + dev_err(card->dev, "cpu_dai fmt not set\n"); + return err; + } + + err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, + SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return err; + } + + return 0; +} + +static struct snd_soc_ops trimslice_asoc_ops = { + .hw_params = trimslice_asoc_hw_params, +}; + +static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = { + SND_SOC_DAPM_HP("Line Out", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), +}; + +static const struct snd_soc_dapm_route trimslice_audio_map[] = { + {"Line Out", NULL, "LOUT"}, + {"Line Out", NULL, "ROUT"}, + + {"LLINEIN", NULL, "Line In"}, + {"RLINEIN", NULL, "Line In"}, +}; + +static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + + snd_soc_dapm_nc_pin(dapm, "LHPOUT"); + snd_soc_dapm_nc_pin(dapm, "RHPOUT"); + snd_soc_dapm_nc_pin(dapm, "MICIN"); + + snd_soc_dapm_sync(dapm); + + return 0; +} + +static struct snd_soc_dai_link trimslice_tlv320aic23_dai = { + .name = "TLV320AIC23", + .stream_name = "AIC23", + .codec_name = "tlv320aic23-codec.2-001a", + .platform_name = "tegra-pcm-audio", + .cpu_dai_name = "tegra-i2s.0", + .codec_dai_name = "tlv320aic23-hifi", + .init = trimslice_asoc_init, + .ops = &trimslice_asoc_ops, +}; + +static struct snd_soc_card snd_soc_trimslice = { + .name = "tegra-trimslice", + .dai_link = &trimslice_tlv320aic23_dai, + .num_links = 1, + + .dapm_widgets = trimslice_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets), + .dapm_routes = trimslice_audio_map, + .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map), +}; + +static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_trimslice; + struct tegra_trimslice *trimslice; + int ret; + + trimslice = kzalloc(sizeof(struct tegra_trimslice), GFP_KERNEL); + if (!trimslice) { + dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n"); + return -ENOMEM; + } + + ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); + if (ret) + goto err_free_trimslice; + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, trimslice); + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_fini_utils; + } + + return 0; + +err_fini_utils: + tegra_asoc_utils_fini(&trimslice->util_data); +err_free_trimslice: + kfree(trimslice); + return ret; +} + +static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); + + snd_soc_unregister_card(card); + + tegra_asoc_utils_fini(&trimslice->util_data); + + kfree(trimslice); + + return 0; +} + +static struct platform_driver tegra_snd_trimslice_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = tegra_snd_trimslice_probe, + .remove = __devexit_p(tegra_snd_trimslice_remove), +}; + +static int __init snd_tegra_trimslice_init(void) +{ + return platform_driver_register(&tegra_snd_trimslice_driver); +} +module_init(snd_tegra_trimslice_init); + +static void __exit snd_tegra_trimslice_exit(void) +{ + platform_driver_unregister(&tegra_snd_trimslice_driver); +} +module_exit(snd_tegra_trimslice_exit); + +MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); +MODULE_DESCRIPTION("Trimslice machine ASoC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index 248463511186..ac828eff1a63 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -65,6 +65,15 @@ init_data[] = { { 0 } /* TERMINATING ENTRY */ }; +static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; +/* values to write to soundcard register for all samplerates */ +static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; +static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; + +enum { + DIGITAL_THRU_ONLY_SAMPLERATE = 3 +}; + static void usb6fire_control_master_vol_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; @@ -95,6 +104,67 @@ static void usb6fire_control_opt_coax_update(struct control_runtime *rt) } } +static int usb6fire_control_set_rate(struct control_runtime *rt, int rate) +{ + int ret; + struct usb_device *device = rt->chip->dev; + struct comm_runtime *comm_rt = rt->chip->comm; + + if (rate < 0 || rate >= CONTROL_N_RATES) + return -EINVAL; + + ret = usb_set_interface(device, 1, rates_altsetting[rate]); + if (ret < 0) + return ret; + + /* set soundcard clock */ + ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate], + rates_6fire_vh[rate]); + if (ret < 0) + return ret; + + return 0; +} + +static int usb6fire_control_set_channels( + struct control_runtime *rt, int n_analog_out, + int n_analog_in, bool spdif_out, bool spdif_in) +{ + int ret; + struct comm_runtime *comm_rt = rt->chip->comm; + + /* enable analog inputs and outputs + * (one bit per stereo-channel) */ + ret = comm_rt->write16(comm_rt, 0x02, 0x02, + (1 << (n_analog_out / 2)) - 1, + (1 << (n_analog_in / 2)) - 1); + if (ret < 0) + return ret; + + /* disable digital inputs and outputs */ + /* TODO: use spdif_x to enable/disable digital channels */ + ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); + if (ret < 0) + return ret; + + return 0; +} + +static int usb6fire_control_streaming_update(struct control_runtime *rt) +{ + struct comm_runtime *comm_rt = rt->chip->comm; + + if (comm_rt) { + if (!rt->usb_streaming && rt->digital_thru_switch) + usb6fire_control_set_rate(rt, + DIGITAL_THRU_ONLY_SAMPLERATE); + return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, + (rt->usb_streaming ? 0x01 : 0x00) | + (rt->digital_thru_switch ? 0x08 : 0x00)); + } + return -EINVAL; +} + static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -195,6 +265,28 @@ static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol, return 0; } +static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + int changed = 0; + + if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) { + rt->digital_thru_switch = ucontrol->value.integer.value[0]; + usb6fire_control_streaming_update(rt); + changed = 1; + } + return changed; +} + +static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = rt->digital_thru_switch; + return 0; +} + static struct __devinitdata snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -223,6 +315,15 @@ static struct __devinitdata snd_kcontrol_new elements[] = { .get = usb6fire_control_opt_coax_get, .put = usb6fire_control_opt_coax_put }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Thru Playback Route", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_mono_info, + .get = usb6fire_control_digital_thru_get, + .put = usb6fire_control_digital_thru_put + }, {} }; @@ -238,6 +339,9 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) return -ENOMEM; rt->chip = chip; + rt->update_streaming = usb6fire_control_streaming_update; + rt->set_rate = usb6fire_control_set_rate; + rt->set_channels = usb6fire_control_set_channels; i = 0; while (init_data[i].type) { @@ -249,6 +353,7 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) usb6fire_control_opt_coax_update(rt); usb6fire_control_line_phono_update(rt); usb6fire_control_master_vol_update(rt); + usb6fire_control_streaming_update(rt); i = 0; while (elements[i].name) { diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index b534c777ab02..8f5aeead2e3d 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h @@ -21,12 +21,29 @@ enum { CONTROL_MAX_ELEMENTS = 32 }; +enum { + CONTROL_RATE_44KHZ, + CONTROL_RATE_48KHZ, + CONTROL_RATE_88KHZ, + CONTROL_RATE_96KHZ, + CONTROL_RATE_176KHZ, + CONTROL_RATE_192KHZ, + CONTROL_N_RATES +}; + struct control_runtime { + int (*update_streaming)(struct control_runtime *rt); + int (*set_rate)(struct control_runtime *rt, int rate); + int (*set_channels)(struct control_runtime *rt, int n_analog_out, + int n_analog_in, bool spdif_out, bool spdif_in); + struct sfire_chip *chip; struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS]; bool opt_coax_switch; bool line_phono_switch; + bool digital_thru_switch; + bool usb_streaming; u8 master_vol; }; diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 9081a54a9c6c..d47beffedb0f 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -3,12 +3,6 @@ * * Firmware loader * - * Currently not working for all devices. To be able to use the device - * in linux, it is also possible to let the windows driver upload the firmware. - * For that, start the computer in windows and reboot. - * As long as the device is connected to the power supply, no firmware reload - * needs to be performed. - * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 * Version: 0.3.0 @@ -21,6 +15,7 @@ */ #include <linux/firmware.h> +#include <linux/bitrev.h> #include "firmware.h" #include "chip.h" @@ -33,32 +28,6 @@ enum { FPGA_BUFSIZE = 512, FPGA_EP = 2 }; -static const u8 BIT_REVERSE_TABLE[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, - 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, - 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, - 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, - 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, - 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, - 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, - 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, - 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, - 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, - 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, - 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, - 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, - 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, - 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, - 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, - 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, - 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, - 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, - 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, - 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, - 0xbf, 0x7f, 0xff }; - /* * wMaxPacketSize of pcm endpoints. * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c @@ -72,11 +41,15 @@ static const u8 ep_w_max_packet_size[] = { 0x94, 0x01, 0x5c, 0x02 /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */ }; +static const u8 known_fw_versions[][4] = { + { 0x03, 0x01, 0x0b, 0x00 } +}; + struct ihex_record { u16 address; u8 len; u8 data[256]; - char error; /* true if an error occured parsing this record */ + char error; /* true if an error occurred parsing this record */ u8 max_len; /* maximum record length in whole ihex */ @@ -107,7 +80,7 @@ static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc) /* * returns true if record is available, false otherwise. - * iff an error occured, false will be returned and record->error will be true. + * iff an error occurred, false will be returned and record->error will be true. */ static bool usb6fire_fw_ihex_next_record(struct ihex_record *record) { @@ -340,7 +313,7 @@ static int usb6fire_fw_fpga_upload( while (c != end) { for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++) - buffer[i] = BIT_REVERSE_TABLE[(u8) *c]; + buffer[i] = byte_rev_table[(u8) *c]; ret = usb6fire_fw_fpga_write(device, buffer, i); if (ret < 0) { @@ -363,6 +336,25 @@ static int usb6fire_fw_fpga_upload( return 0; } +/* check, if the firmware version the devices has currently loaded + * is known by this driver. 'version' needs to have 4 bytes version + * info data. */ +static int usb6fire_fw_check(u8 *version) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++) + if (!memcmp(version, known_fw_versions + i, 4)) + return 0; + + snd_printk(KERN_ERR PREFIX "invalid fimware version in device: " + "%02x %02x %02x %02x. " + "please reconnect to power. if this failure " + "still happens, check your firmware installation.", + version[0], version[1], version[2], version[3]); + return -EINVAL; +} + int usb6fire_fw_init(struct usb_interface *intf) { int i; @@ -378,9 +370,7 @@ int usb6fire_fw_init(struct usb_interface *intf) "firmware state.\n"); return ret; } - if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55 - || buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7] - != 0x00) { + if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) { snd_printk(KERN_ERR PREFIX "unknown device firmware state " "received from device: "); for (i = 0; i < 8; i++) @@ -389,7 +379,7 @@ int usb6fire_fw_init(struct usb_interface *intf) return -EIO; } /* do we need fpga loader ezusb firmware? */ - if (buffer[3] == 0x01 && buffer[6] == 0x19) { + if (buffer[3] == 0x01) { ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6firel2.ihx", 0, NULL, 0); if (ret < 0) @@ -397,7 +387,10 @@ int usb6fire_fw_init(struct usb_interface *intf) return FW_NOT_READY; } /* do we need fpga firmware and application ezusb firmware? */ - else if (buffer[3] == 0x02 && buffer[6] == 0x0b) { + else if (buffer[3] == 0x02) { + ret = usb6fire_fw_check(buffer + 4); + if (ret < 0) + return ret; ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin"); if (ret < 0) return ret; @@ -410,8 +403,8 @@ int usb6fire_fw_init(struct usb_interface *intf) return FW_NOT_READY; } /* all fw loaded? */ - else if (buffer[3] == 0x03 && buffer[6] == 0x0b) - return 0; + else if (buffer[3] == 0x03) + return usb6fire_fw_check(buffer + 4); /* unknown data? */ else { snd_printk(KERN_ERR PREFIX "unknown device firmware state " diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index ba62c7468ba8..b137b25865cc 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -17,26 +17,23 @@ #include "pcm.h" #include "chip.h" #include "comm.h" +#include "control.h" enum { OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4 }; /* keep next two synced with - * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */ + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE + * and CONTROL_RATE_XXX in control.h */ static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 }; static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 }; static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; -static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; static const int rates_alsaid[] = { SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000, SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000, SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 }; -/* values to write to soundcard register for all samplerates */ -static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; -static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; - enum { /* settings for pcm */ OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 }; @@ -48,15 +45,6 @@ enum { /* pcm streaming states */ STREAM_STOPPING }; -enum { /* pcm sample rates (also index into RATES_XXX[]) */ - RATE_44KHZ, - RATE_48KHZ, - RATE_88KHZ, - RATE_96KHZ, - RATE_176KHZ, - RATE_192KHZ -}; - static const struct snd_pcm_hardware pcm_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -64,7 +52,7 @@ static const struct snd_pcm_hardware pcm_hw = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH, - .formats = SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | @@ -87,57 +75,34 @@ static const struct snd_pcm_hardware pcm_hw = { static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) { int ret; - struct usb_device *device = rt->chip->dev; - struct comm_runtime *comm_rt = rt->chip->comm; + struct control_runtime *ctrl_rt = rt->chip->control; - if (rt->rate >= ARRAY_SIZE(rates)) - return -EINVAL; - /* disable streaming */ - ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00); + ctrl_rt->usb_streaming = false; + ret = ctrl_rt->update_streaming(ctrl_rt); if (ret < 0) { snd_printk(KERN_ERR PREFIX "error stopping streaming while " "setting samplerate %d.\n", rates[rt->rate]); return ret; } - ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]); - if (ret < 0) { - snd_printk(KERN_ERR PREFIX "error setting interface " - "altsetting %d for samplerate %d.\n", - rates_altsetting[rt->rate], rates[rt->rate]); - return ret; - } - - /* set soundcard clock */ - ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate], - rates_6fire_vh[rt->rate]); + ret = ctrl_rt->set_rate(ctrl_rt, rt->rate); if (ret < 0) { snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n", rates[rt->rate]); return ret; } - /* enable analog inputs and outputs - * (one bit per stereo-channel) */ - ret = comm_rt->write16(comm_rt, 0x02, 0x02, - (1 << (OUT_N_CHANNELS / 2)) - 1, - (1 << (IN_N_CHANNELS / 2)) - 1); + ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS, + false, false); if (ret < 0) { - snd_printk(KERN_ERR PREFIX "error initializing analog channels " + snd_printk(KERN_ERR PREFIX "error initializing channels " "while setting samplerate %d.\n", rates[rt->rate]); return ret; } - /* disable digital inputs and outputs */ - ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); - if (ret < 0) { - snd_printk(KERN_ERR PREFIX "error initializing digital " - "channels while setting samplerate %d.\n", - rates[rt->rate]); - return ret; - } - ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01); + ctrl_rt->usb_streaming = true; + ret = ctrl_rt->update_streaming(ctrl_rt); if (ret < 0) { snd_printk(KERN_ERR PREFIX "error starting streaming while " "setting samplerate %d.\n", rates[rt->rate]); @@ -168,12 +133,15 @@ static struct pcm_substream *usb6fire_pcm_get_substream( static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) { int i; + struct control_runtime *ctrl_rt = rt->chip->control; if (rt->stream_state != STREAM_DISABLED) { for (i = 0; i < PCM_N_URBS; i++) { usb_kill_urb(&rt->in_urbs[i].instance); usb_kill_urb(&rt->out_urbs[i].instance); } + ctrl_rt->usb_streaming = false; + ctrl_rt->update_streaming(ctrl_rt); rt->stream_state = STREAM_DISABLED; } } @@ -228,7 +196,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) unsigned int total_length = 0; struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; - u32 *src = (u32 *) urb->buffer; + u32 *src = NULL; u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off * (alsa_rt->frame_bits >> 3)); u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size @@ -244,7 +212,12 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) else frame_count = 0; - src = (u32 *) (urb->buffer + total_length); + if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) + src = (u32 *) (urb->buffer + total_length); + else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) + src = (u32 *) (urb->buffer - 1 + total_length); + else + return; src++; /* skip leading 4 bytes of every packet */ total_length += urb->packets[i].length; for (frame = 0; frame < frame_count; frame++) { @@ -274,9 +247,18 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub, * (alsa_rt->frame_bits >> 3)); u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size * (alsa_rt->frame_bits >> 3)); - u32 *dest = (u32 *) urb->buffer; + u32 *dest; int bytes_per_frame = alsa_rt->channels << 2; + if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) + dest = (u32 *) (urb->buffer - 1); + else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) + dest = (u32 *) (urb->buffer); + else { + snd_printk(KERN_ERR PREFIX "Unknown sample format."); + return; + } + for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { /* at least 4 header bytes for valid packet. * after that: 32 bits per sample for analog channels */ @@ -456,7 +438,7 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) /* all substreams closed? if so, stop streaming */ if (!rt->playback.instance && !rt->capture.instance) { usb6fire_pcm_stream_stop(rt); - rt->rate = -1; + rt->rate = ARRAY_SIZE(rates); } } mutex_unlock(&rt->stream_mutex); @@ -480,7 +462,6 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; - int i; int ret; if (rt->panic) @@ -493,12 +474,10 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) sub->period_off = 0; if (rt->stream_state == STREAM_DISABLED) { - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (alsa_rt->rate == rates[i]) { - rt->rate = i; + for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++) + if (alsa_rt->rate == rates[rt->rate]) break; - } - if (i == ARRAY_SIZE(rates)) { + if (rt->rate == ARRAY_SIZE(rates)) { mutex_unlock(&rt->stream_mutex); snd_printk("invalid rate %d in prepare.\n", alsa_rt->rate); @@ -613,7 +592,7 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip) rt->chip = chip; rt->stream_state = STREAM_DISABLED; - rt->rate = -1; + rt->rate = ARRAY_SIZE(rates); init_waitqueue_head(&rt->stream_wait_queue); mutex_init(&rt->stream_mutex); diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 97724d8fa9f6..8beb77563da2 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -100,19 +100,17 @@ config SND_USB_US122L config SND_USB_6FIRE tristate "TerraTec DMX 6Fire USB" - depends on EXPERIMENTAL select FW_LOADER + select BITREVERSE select SND_RAWMIDI select SND_PCM help Say Y here to include support for TerraTec 6fire DMX USB interface. You will need firmware files in order to be able to use the device - after it has been coldstarted. This driver currently does not support - firmware loading for all devices. If you own such a device, - you could start windows and let the windows driver upload - the firmware. As long as you do not unplug your device from power, - it should be usable. + after it has been coldstarted. An install script for the firmware + and further help can be found at + http://sixfireusb.sourceforge.net endif # SND_USB diff --git a/sound/usb/card.c b/sound/usb/card.c index a90662af2d6b..220c6167dd86 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -48,6 +48,7 @@ #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> +#include <sound/control.h> #include <sound/core.h> #include <sound/info.h> #include <sound/pcm.h> @@ -492,14 +493,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } } - chip->txfr_quirk = 0; - err = 1; /* continue */ - if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { - /* need some special handlings */ - if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) - goto __error; - } - /* * For devices with more than one control interface, we assume the * first contains the audio controls. We might need a more specific @@ -508,6 +501,14 @@ static void *snd_usb_audio_probe(struct usb_device *dev, if (!chip->ctrl_intf) chip->ctrl_intf = alts; + chip->txfr_quirk = 0; + err = 1; /* continue */ + if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { + /* need some special handlings */ + if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) + goto __error; + } + if (err > 0) { /* create normal USB audio interfaces */ if (snd_usb_create_streams(chip, ifnum) < 0 || diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 7754a1034545..075195e8661a 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -104,6 +104,15 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) int err; unsigned char data; struct usb_device *dev = chip->dev; + struct uac_clock_source_descriptor *cs_desc = + snd_usb_find_clock_source(chip->ctrl_intf, source_id); + + if (!cs_desc) + return 0; + + /* If a clock source can't tell us whether it's valid, we assume it is */ + if (!uac2_control_is_readable(cs_desc->bmControls, UAC2_CS_CONTROL_CLOCK_VALID)) + return 1; err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, @@ -114,7 +123,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) if (err < 0) { snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", __func__, source_id); - return err; + return 0; } return !!data; diff --git a/sound/usb/debug.h b/sound/usb/debug.h index 343ec2d9ee66..58030176f008 100644 --- a/sound/usb/debug.h +++ b/sound/usb/debug.h @@ -8,7 +8,7 @@ #ifdef HW_CONST_DEBUG #define hwc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args) #else -#define hwc_debug(fmt, args...) /**/ +#define hwc_debug(fmt, args...) do { } while(0) #endif #endif /* __USBAUDIO_DEBUG_H */ diff --git a/sound/usb/format.c b/sound/usb/format.c index 5b792d2c8061..8d042dce0d16 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -30,6 +30,7 @@ #include "helper.h" #include "debug.h" #include "clock.h" +#include "format.h" /* * parse the audio format type I descriptor @@ -176,9 +177,11 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof if (!rate) continue; /* C-Media CM6501 mislabels its 96 kHz altsetting */ + /* Terratec Aureon 7.1 USB C-Media 6206, too */ if (rate == 48000 && nr_rates == 1 && (chip->usb_id == USB_ID(0x0d8c, 0x0201) || - chip->usb_id == USB_ID(0x0d8c, 0x0102)) && + chip->usb_id == USB_ID(0x0d8c, 0x0102) || + chip->usb_id == USB_ID(0x0ccd, 0x00b1)) && fp->altsetting == 5 && fp->maxpacksize == 392) rate = 96000; /* Creative VF0470 Live Cam reports 16 kHz instead of 8kHz */ diff --git a/sound/usb/midi.c b/sound/usb/midi.c index b4b39c0b6c9e..f9289102886a 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1301,6 +1301,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */ case USB_ID(0x15ca, 0x1806): /* Textech USB Midi Cable */ case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */ + case USB_ID(0xfc08, 0x0101): /* Unknown vendor Cable */ ep->max_transfer = 4; break; /* diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 5e4775716607..c22fa76e363a 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -86,16 +86,6 @@ struct mixer_build { const struct usbmix_selector_map *selector_map; }; -enum { - USB_MIXER_BOOLEAN, - USB_MIXER_INV_BOOLEAN, - USB_MIXER_S8, - USB_MIXER_U8, - USB_MIXER_S16, - USB_MIXER_U16, -}; - - /*E-mu 0202/0404/0204 eXtension Unit(XU) control*/ enum { USB_XU_CLOCK_RATE = 0xe301, @@ -535,20 +525,21 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou * if failed, give up and free the control instance. */ -static int add_control_to_empty(struct mixer_build *state, struct snd_kcontrol *kctl) +int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, + struct snd_kcontrol *kctl) { struct usb_mixer_elem_info *cval = kctl->private_data; int err; - while (snd_ctl_find_id(state->chip->card, &kctl->id)) + while (snd_ctl_find_id(mixer->chip->card, &kctl->id)) kctl->id.index++; - if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { + if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) { snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); return err; } cval->elem_id = &kctl->id; - cval->next_id_elem = state->mixer->id_elems[cval->id]; - state->mixer->id_elems[cval->id] = cval; + cval->next_id_elem = mixer->id_elems[cval->id]; + mixer->id_elems[cval->id] = cval; return 0; } @@ -984,6 +975,9 @@ static struct snd_kcontrol_new usb_feature_unit_ctl_ro = { .put = NULL, }; +/* This symbol is exported in order to allow the mixer quirks to + * hook up to the standard feature unit control mechanism */ +struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl; /* * build a feature control @@ -1097,11 +1091,13 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, append_ctl_name(kctl, control == UAC_FU_MUTE ? " Switch" : " Volume"); if (control == UAC_FU_VOLUME) { - kctl->tlv.c = mixer_vol_tlv; - kctl->vd[0].access |= - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; check_mapped_dB(map, cval); + if (cval->dBmin < cval->dBmax) { + kctl->tlv.c = mixer_vol_tlv; + kctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; + } } break; @@ -1174,7 +1170,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); - add_control_to_empty(state, kctl); + snd_usb_mixer_add_control(state->mixer, kctl); } @@ -1182,7 +1178,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, /* * parse a feature unit * - * most of controlls are defined here. + * most of controls are defined here. */ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void *_ftr) { @@ -1338,7 +1334,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - add_control_to_empty(state, kctl); + snd_usb_mixer_add_control(state->mixer, kctl); } @@ -1639,7 +1635,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - if ((err = add_control_to_empty(state, kctl)) < 0) + if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0) return err; } return 0; @@ -1856,7 +1852,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", cval->id, kctl->id.name, desc->bNrInPins); - if ((err = add_control_to_empty(state, kctl)) < 0) + if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0) return err; return 0; diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index b4a2c8165e4b..ae1a14dcfe82 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -24,7 +24,16 @@ struct usb_mixer_interface { u8 xonar_u1_status; }; -#define MAX_CHANNELS 10 /* max logical channels */ +#define MAX_CHANNELS 16 /* max logical channels */ + +enum { + USB_MIXER_BOOLEAN, + USB_MIXER_INV_BOOLEAN, + USB_MIXER_S8, + USB_MIXER_U8, + USB_MIXER_S16, + USB_MIXER_U16, +}; struct usb_mixer_elem_info { struct usb_mixer_interface *mixer; @@ -55,4 +64,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer); int snd_usb_mixer_activate(struct usb_mixer_interface *mixer); +int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, + struct snd_kcontrol *kctl); + #endif /* __USBMIXER_H */ diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 73dcc8256bc0..3d0f4873112b 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -40,6 +40,8 @@ #include "mixer_quirks.h" #include "helper.h" +extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; + /* * Sound Blaster remote control configuration * @@ -61,6 +63,7 @@ static const struct rc_config { { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */ + { USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ }; @@ -188,6 +191,12 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, !value, 0, NULL, 0, 100); + /* USB X-Fi S51 Pro */ + if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + !value, 0, NULL, 0, 100); else err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, @@ -234,9 +243,13 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) /* USB X-Fi S51 doesn't have a CMSS LED */ if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0) continue; + /* USB X-Fi S51 Pro doesn't have one either */ + if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0) + continue; if (i > 1 && /* Live24ext has 2 LEDs only */ (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || mixer->chip->usb_id == USB_ID(0x041e, 0x3042) || + mixer->chip->usb_id == USB_ID(0x041e, 0x30df) || mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) break; err = snd_ctl_add(mixer->chip->card, @@ -481,6 +494,69 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, return err; } +/* M-Audio FastTrack Ultra quirks */ + +/* private_free callback */ +static void usb_mixer_elem_free(struct snd_kcontrol *kctl) +{ + kfree(kctl->private_data); + kctl->private_data = NULL; +} + +static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer, + int in, int out, const char *name) +{ + struct usb_mixer_elem_info *cval; + struct snd_kcontrol *kctl; + + cval = kzalloc(sizeof(*cval), GFP_KERNEL); + if (!cval) + return -ENOMEM; + + cval->id = 5; + cval->mixer = mixer; + cval->val_type = USB_MIXER_S16; + cval->channels = 1; + cval->control = out + 1; + cval->cmask = 1 << in; + + kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); + if (!kctl) { + kfree(cval); + return -ENOMEM; + } + + snprintf(kctl->id.name, sizeof(kctl->id.name), name); + kctl->private_free = usb_mixer_elem_free; + return snd_usb_mixer_add_control(mixer, kctl); +} + +static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer) +{ + char name[64]; + int in, out, err; + + for (out = 0; out < 8; out++) { + for (in = 0; in < 8; in++) { + snprintf(name, sizeof(name), + "AIn%d - Out%d Capture Volume", in + 1, out + 1); + err = snd_maudio_ftu_create_ctl(mixer, in, out, name); + if (err < 0) + return err; + } + + for (in = 8; in < 16; in++) { + snprintf(name, sizeof(name), + "DIn%d - Out%d Playback Volume", in - 7, out + 1); + err = snd_maudio_ftu_create_ctl(mixer, in, out, name); + if (err < 0) + return err; + } + } + + return 0; +} + void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, unsigned char samplerate_id) { @@ -512,6 +588,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x041e, 0x3020): case USB_ID(0x041e, 0x3040): case USB_ID(0x041e, 0x3042): + case USB_ID(0x041e, 0x30df): case USB_ID(0x041e, 0x3048): err = snd_audigy2nx_controls_create(mixer); if (err < 0) @@ -521,6 +598,11 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) snd_audigy2nx_proc_read); break; + case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ + case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ + err = snd_maudio_ftu_create_mixer(mixer); + break; + case USB_ID(0x0b05, 0x1739): case USB_ID(0x0b05, 0x1743): err = snd_xonar_u1_controls_create(mixer); diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index c66d3f64dcf8..0b2ae8e1c02d 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1651,6 +1651,32 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + USB_DEVICE(0x0582, 0x0127), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "GR-55", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, /* Guillemot devices */ { @@ -1953,7 +1979,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { - USB_DEVICE(0x0763, 0x2080), + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "M-Audio", */ /* .product_name = "Fast Track Ultra", */ @@ -1962,7 +1988,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .data = & (const struct snd_usb_audio_quirk[]) { { .ifnum = 0, - .type = QUIRK_IGNORE_INTERFACE + .type = QUIRK_AUDIO_STANDARD_MIXER, }, { .ifnum = 1, @@ -2020,7 +2046,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { - USB_DEVICE(0x0763, 0x2081), + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2081), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "M-Audio", */ /* .product_name = "Fast Track Ultra 8R", */ @@ -2029,7 +2055,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .data = & (const struct snd_usb_audio_quirk[]) { { .ifnum = 0, - .type = QUIRK_IGNORE_INTERFACE + .type = QUIRK_AUDIO_STANDARD_MIXER, }, { .ifnum = 1, @@ -2179,6 +2205,17 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* KORG devices */ +{ + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0200), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "KORG, Inc.", + /* .product_name = "PANDORA PX5D", */ + .ifnum = 3, + .type = QUIRK_MIDI_STANDARD_INTERFACE, + } +}, + /* AKAI devices */ { USB_DEVICE(0x09e8, 0x0062), @@ -2332,6 +2369,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), /* Native Instruments MK2 series */ { + /* Komplete Audio 6 */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x17cc, + .idProduct = 0x1000, +}, +{ /* Traktor Audio 6 */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x17cc, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 355759bad581..2e969cbb393b 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -19,6 +19,7 @@ #include <linux/usb.h> #include <linux/usb/audio.h> +#include <sound/control.h> #include <sound/core.h> #include <sound/info.h> #include <sound/pcm.h> @@ -263,10 +264,24 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, } /* + * Create a standard mixer for the specified interface. + */ +static int create_standard_mixer_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + struct usb_driver *driver, + const struct snd_usb_audio_quirk *quirk) +{ + if (quirk->ifnum < 0) + return 0; + + return snd_usb_create_mixer(chip, quirk->ifnum, 0); +} + +/* * audio-interface quirks * * returns zero if no standard audio/MIDI parsing is needed. - * returns a postive value if standard audio/midi interfaces are parsed + * returns a positive value if standard audio/midi interfaces are parsed * after this. * returns a negative value at error. */ @@ -294,7 +309,8 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, - [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk + [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk, + [QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk, }; if (quirk->type < QUIRK_TYPE_COUNT) { @@ -533,12 +549,14 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, case USB_ID(0x0d8c, 0x0102): /* C-Media CM6206 / CM106-Like Sound Device */ + case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */ return snd_usb_cm6206_boot_quirk(dev); case USB_ID(0x133e, 0x0815): /* Access Music VirusTI Desktop */ return snd_usb_accessmusic_boot_quirk(dev); + case USB_ID(0x17cc, 0x1000): /* Komplete Audio 6 */ case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */ case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */ return snd_usb_nativeinstruments_boot_quirk(dev); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 32f2a97f2f14..1e79986b5777 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -84,6 +84,7 @@ enum quirk_type { QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UAXX, QUIRK_AUDIO_ALIGN_TRANSFER, + QUIRK_AUDIO_STANDARD_MIXER, QUIRK_TYPE_COUNT }; diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 287ef73b1237..a51340f6f2db 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -20,7 +20,7 @@ at standard samplerates, what led to this part of the usx2y module: It provides the alsa kernel half of the usx2y-alsa-jack driver pair. - The pair uses a hardware dependant alsa-device for mmaped pcm transport. + The pair uses a hardware dependent alsa-device for mmaped pcm transport. Advantage achieved: The usb_hc moves pcm data from/into memory via DMA. That memory is mmaped by jack's usx2y driver. @@ -38,7 +38,7 @@ 2periods works but is useless cause of crackling). This is a first "proof of concept" implementation. - Later, functionalities should migrate to more apropriate places: + Later, functionalities should migrate to more appropriate places: Userland: - The jackd could mmap its float-pcm buffers directly from alsa-lib. - alsa-lib could provide power of 2 period sized shaping combined with int/float |