diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 13:00:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 13:00:13 -0700 |
commit | b2094ef840697bc8ca5d17a83b7e30fad5f1e9fa (patch) | |
tree | 64e5f7253b6a85b6d5d36f95c0d3c67c1798918d /sound | |
parent | 424a6f6ef990b7e9f56f6627bfc6c46b493faeb4 (diff) | |
parent | 6681bc0deba495fad0d6fb349e40524abd1b1732 (diff) | |
download | linux-3.10-b2094ef840697bc8ca5d17a83b7e30fad5f1e9fa.tar.gz linux-3.10-b2094ef840697bc8ca5d17a83b7e30fad5f1e9fa.tar.bz2 linux-3.10-b2094ef840697bc8ca5d17a83b7e30fad5f1e9fa.zip |
Merge tag 'sound-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull updates of sound stuff from Takashi Iwai:
"Here is the first big update chunk of sound stuff for 3.4-rc1.
In the common sound infrastructure, there are a few changes for
dynamic PCM support (used in ASoC) and a few clean-ups. Majority of
changes are found, as usual, in HD-audio and ASoC.
Some highlights of HD-audio changes:
- All the long-standing static quirk codes for Realtek codec were
finally removed by fixing and extending the Realtek auto-parser.
- The mute-LED control is standardized over all HD-audio codec
drivers using the extended vmaster hook.
- The vmaster slave mixer elements are initialized to 0dB as default
so that the user won't be annoyed by the silent output after
updates, e.g. due to the additions of new elements.
- Other many fix-ups for the misc HD-audio devices.
In the ASoC side, this is a very active release, including a quite a
few framework enhancements. Some highlights:
- Support for widgets not associated with a CODEC, an important part
of the dynamic PCM framework.
- A library factoring out the common code shared by dmaengine based
DMA drivers contributed by Lars-Peter Clausen. This will save a
lot of code and make it much easier to deploy enhancements to
dmaengine.
- Support for binary controls, used for providing runtime
configuration of algorithm coefficients.
- A new DAPM widget type for regulator supplies allowing drivers for
devices that can power down unused supplies while active to do
without any per-driver code.
- DAPM widgets for DAIs, initially giving a speed boost for playback
startup and shutdown and also the basis for CODEC<->CODEC DAI link
support.
- Support for specifying the number of significant bits on audio
interfaces, useful for allowing applications to know how much
effort to put into generating data for a larger sample format.
- Conversion of the FSI driver used on some SH processors to
DMAEngine.
- Conversion of EP93xx drivers to DMAEngine.
- New CODEC drivers for Maxim MAX9768 and Wolfson Microelectronics
WM2200.
- Move audmux driver from arc/arm to sound/soc
- McBSP move from arch/ to sound/ and updates
Also, a few small updates and fixes for other drivers like au88x0,
ymfpci, USB 6fire, USB usx2yaudio are included."
* tag 'sound-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (446 commits)
ASoC: wm8994: Provide VMID mode control and fix default sequence
ASoC: wm8994: Add missing break in resume
ASoC: wm_hubs: Don't actively manage LINEOUT_VMID_BUF
ASoC: pxa-ssp: atomically set stream active masks
ASoC: fsl: p1022ds: tell the WM8776 codec driver that it's the master
ASoC: Samsung: Added to support mono recording
ALSA: hda - Fix build with CONFIG_PM=n
ALSA: au88x0 - Avoid possible Oops at unbinding
ALSA: usb-audio - Fix build error by consitification of rate list
ASoC: core: Fix obscure leak of runtime array
ALSA: pcm - Avoid GFP_ATOMIC in snd_pcm_link()
ALSA: pcm: Constify the list in snd_pcm_hw_constraint_list
ASoC: wm8996: Add 44.1kHz support
ALSA: hda - Fix build of patch_sigmatel.c without CONFIG_SND_HDA_POWER_SAVE
ASoC: mx27vis-aic32x4: Convert it to platform driver
ALSA: hda - fix printing of high HDMI sample rates
ALSA: ymfpci - Fix legacy registers on S3/S4 resume
ALSA: control - Fixe a trailing white space error
ALSA: hda - Add expose_enum_ctl flag to snd_hda_add_vmaster_hook()
ALSA: hda - Add "Mute-LED Mode" enum control
...
Diffstat (limited to 'sound')
222 files changed, 17497 insertions, 11199 deletions
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index 762af68c899..270790d384e 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -1132,15 +1132,4 @@ static struct i2c_driver onyx_driver = { .id_table = onyx_i2c_id, }; -static int __init onyx_init(void) -{ - return i2c_add_driver(&onyx_driver); -} - -static void __exit onyx_exit(void) -{ - i2c_del_driver(&onyx_driver); -} - -module_init(onyx_init); -module_exit(onyx_exit); +module_i2c_driver(onyx_driver); diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index fd2188c3df2..8e63d1f35ce 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -1026,15 +1026,4 @@ static struct i2c_driver tas_driver = { .id_table = tas_i2c_id, }; -static int __init tas_init(void) -{ - return i2c_add_driver(&tas_driver); -} - -static void __exit tas_exit(void) -{ - i2c_del_driver(&tas_driver); -} - -module_init(tas_init); -module_exit(tas_exit); +module_i2c_driver(tas_driver); diff --git a/sound/core/control.c b/sound/core/control.c index 819a5c579a3..2487a6bb1c5 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1313,7 +1313,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, err = -EPERM; goto __kctl_end; } - err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); + err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); if (err > 0) { up_read(&card->controls_rwsem); snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); diff --git a/sound/core/init.c b/sound/core/init.c index 3ac49b1b7cb..068cf08d3ff 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -480,74 +480,104 @@ int snd_card_free(struct snd_card *card) EXPORT_SYMBOL(snd_card_free); -static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) +/* retrieve the last word of shortname or longname */ +static const char *retrieve_id_from_card_name(const char *name) { - int i, len, idx_flag = 0, loops = SNDRV_CARDS; - const char *spos, *src; - char *id; - - if (nid == NULL) { - id = card->shortname; - spos = src = id; - while (*id != '\0') { - if (*id == ' ') - spos = id + 1; - id++; - } - } else { - spos = src = nid; + const char *spos = name; + + while (*name) { + if (isspace(*name) && isalnum(name[1])) + spos = name + 1; + name++; } - id = card->id; - while (*spos != '\0' && !isalnum(*spos)) - spos++; - if (isdigit(*spos)) - *id++ = isalpha(src[0]) ? src[0] : 'D'; - while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) { - if (isalnum(*spos)) - *id++ = *spos; - spos++; + return spos; +} + +/* return true if the given id string doesn't conflict any other card ids */ +static bool card_id_ok(struct snd_card *card, const char *id) +{ + int i; + if (!snd_info_check_reserved_words(id)) + return false; + for (i = 0; i < snd_ecards_limit; i++) { + if (snd_cards[i] && snd_cards[i] != card && + !strcmp(snd_cards[i]->id, id)) + return false; } - *id = '\0'; + return true; +} - id = card->id; +/* copy to card->id only with valid letters from nid */ +static void copy_valid_id_string(struct snd_card *card, const char *src, + const char *nid) +{ + char *id = card->id; + + while (*nid && !isalnum(*nid)) + nid++; + if (isdigit(*nid)) + *id++ = isalpha(*src) ? *src : 'D'; + while (*nid && (size_t)(id - card->id) < sizeof(card->id) - 1) { + if (isalnum(*nid)) + *id++ = *nid; + nid++; + } + *id = 0; +} + +/* Set card->id from the given string + * If the string conflicts with other ids, add a suffix to make it unique. + */ +static void snd_card_set_id_no_lock(struct snd_card *card, const char *src, + const char *nid) +{ + int len, loops; + bool with_suffix; + bool is_default = false; + char *id; - if (*id == '\0') + copy_valid_id_string(card, src, nid); + id = card->id; + + again: + /* use "Default" for obviously invalid strings + * ("card" conflicts with proc directories) + */ + if (!*id || !strncmp(id, "card", 4)) { strcpy(id, "Default"); + is_default = true; + } - while (1) { - if (loops-- == 0) { - snd_printk(KERN_ERR "unable to set card id (%s)\n", id); - strcpy(card->id, card->proc_root->name); - return; - } - if (!snd_info_check_reserved_words(id)) - goto __change; - for (i = 0; i < snd_ecards_limit; i++) { - if (snd_cards[i] && !strcmp(snd_cards[i]->id, id)) - goto __change; - } - break; + with_suffix = false; + for (loops = 0; loops < SNDRV_CARDS; loops++) { + if (card_id_ok(card, id)) + return; /* OK */ - __change: len = strlen(id); - if (idx_flag) { - if (id[len-1] != '9') - id[len-1]++; - else - id[len-1] = 'A'; - } else if ((size_t)len <= sizeof(card->id) - 3) { - strcat(id, "_1"); - idx_flag++; + if (!with_suffix) { + /* add the "_X" suffix */ + char *spos = id + len; + if (len > sizeof(card->id) - 3) + spos = id + sizeof(card->id) - 3; + strcpy(spos, "_1"); + with_suffix = true; } else { - spos = id + len - 2; - if ((size_t)len <= sizeof(card->id) - 2) - spos++; - *(char *)spos++ = '_'; - *(char *)spos++ = '1'; - *(char *)spos++ = '\0'; - idx_flag++; + /* modify the existing suffix */ + if (id[len - 1] != '9') + id[len - 1]++; + else + id[len - 1] = 'A'; } } + /* fallback to the default id */ + if (!is_default) { + *id = 0; + goto again; + } + /* last resort... */ + snd_printk(KERN_ERR "unable to set card id (%s)\n", id); + if (card->proc_root->name) + strcpy(card->id, card->proc_root->name); } /** @@ -564,7 +594,7 @@ void snd_card_set_id(struct snd_card *card, const char *nid) if (card->id[0] != '\0') return; mutex_lock(&snd_card_mutex); - snd_card_set_id_no_lock(card, nid); + snd_card_set_id_no_lock(card, nid, nid); mutex_unlock(&snd_card_mutex); } EXPORT_SYMBOL(snd_card_set_id); @@ -596,22 +626,12 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, memcpy(buf1, buf, copy); buf1[copy] = '\0'; mutex_lock(&snd_card_mutex); - if (!snd_info_check_reserved_words(buf1)) { - __exist: + if (!card_id_ok(NULL, buf1)) { mutex_unlock(&snd_card_mutex); return -EEXIST; } - for (idx = 0; idx < snd_ecards_limit; idx++) { - if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) { - if (card == snd_cards[idx]) - goto __ok; - else - goto __exist; - } - } strcpy(card->id, buf1); snd_info_card_id_change(card); -__ok: mutex_unlock(&snd_card_mutex); return count; @@ -665,7 +685,18 @@ int snd_card_register(struct snd_card *card) mutex_unlock(&snd_card_mutex); return 0; } - snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id); + if (*card->id) { + /* make a unique id name from the given string */ + char tmpid[sizeof(card->id)]; + memcpy(tmpid, card->id, sizeof(card->id)); + snd_card_set_id_no_lock(card, tmpid, tmpid); + } else { + /* create an id from either shortname or longname */ + const char *src; + src = *card->shortname ? card->shortname : card->longname; + snd_card_set_id_no_lock(card, src, + retrieve_id_from_card_name(src)); + } snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); init_info_for_card(card); diff --git a/sound/core/jack.c b/sound/core/jack.c index 26edf63b265..471e1e3b0a9 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -25,7 +25,7 @@ #include <sound/jack.h> #include <sound/core.h> -static int jack_switch_types[] = { +static int jack_switch_types[SND_JACK_SWITCH_TYPES] = { SW_HEADPHONE_INSERT, SW_MICROPHONE_INSERT, SW_LINEOUT_INSERT, @@ -128,7 +128,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, jack->type = type; - for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) + for (i = 0; i < SND_JACK_SWITCH_TYPES; i++) if (type & (1 << i)) input_set_capability(jack->input_dev, EV_SW, jack_switch_types[i]); diff --git a/sound/core/misc.c b/sound/core/misc.c index 465f0ce772c..76816792540 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -72,7 +72,7 @@ void __snd_printk(unsigned int level, const char *path, int line, char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV"; #endif -#ifdef CONFIG_SND_DEBUG +#ifdef CONFIG_SND_DEBUG if (debug < level) return; #endif diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8928ca871c2..6e4bfcc1425 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -650,7 +650,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) pstr->stream = stream; pstr->pcm = pcm; pstr->substream_count = substream_count; - if (substream_count > 0) { + if (substream_count > 0 && !pcm->internal) { err = snd_pcm_stream_proc_init(pstr); if (err < 0) { snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n"); @@ -674,15 +674,18 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) pstr->substream = substream; else prev->next = substream; - err = snd_pcm_substream_proc_init(substream); - if (err < 0) { - snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n"); - if (prev == NULL) - pstr->substream = NULL; - else - prev->next = NULL; - kfree(substream); - return err; + + if (!pcm->internal) { + err = snd_pcm_substream_proc_init(substream); + if (err < 0) { + snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n"); + if (prev == NULL) + pstr->substream = NULL; + else + prev->next = NULL; + kfree(substream); + return err; + } } substream->group = &substream->self_group; spin_lock_init(&substream->self_group.lock); @@ -696,25 +699,9 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) EXPORT_SYMBOL(snd_pcm_new_stream); -/** - * snd_pcm_new - create a new PCM instance - * @card: the card instance - * @id: the id string - * @device: the device index (zero based) - * @playback_count: the number of substreams for playback - * @capture_count: the number of substreams for capture - * @rpcm: the pointer to store the new pcm instance - * - * Creates a new PCM instance. - * - * The pcm operators have to be set afterwards to the new instance - * via snd_pcm_set_ops(). - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_new(struct snd_card *card, const char *id, int device, - int playback_count, int capture_count, - struct snd_pcm ** rpcm) +static int _snd_pcm_new(struct snd_card *card, const char *id, int device, + int playback_count, int capture_count, bool internal, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -735,6 +722,7 @@ int snd_pcm_new(struct snd_card *card, const char *id, int device, } pcm->card = card; pcm->device = device; + pcm->internal = internal; if (id) strlcpy(pcm->id, id, sizeof(pcm->id)); if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { @@ -756,8 +744,59 @@ int snd_pcm_new(struct snd_card *card, const char *id, int device, return 0; } +/** + * snd_pcm_new - create a new PCM instance + * @card: the card instance + * @id: the id string + * @device: the device index (zero based) + * @playback_count: the number of substreams for playback + * @capture_count: the number of substreams for capture + * @rpcm: the pointer to store the new pcm instance + * + * Creates a new PCM instance. + * + * The pcm operators have to be set afterwards to the new instance + * via snd_pcm_set_ops(). + * + * Returns zero if successful, or a negative error code on failure. + */ +int snd_pcm_new(struct snd_card *card, const char *id, int device, + int playback_count, int capture_count, struct snd_pcm **rpcm) +{ + return _snd_pcm_new(card, id, device, playback_count, capture_count, + false, rpcm); +} EXPORT_SYMBOL(snd_pcm_new); +/** + * snd_pcm_new_internal - create a new internal PCM instance + * @card: the card instance + * @id: the id string + * @device: the device index (zero based - shared with normal PCMs) + * @playback_count: the number of substreams for playback + * @capture_count: the number of substreams for capture + * @rpcm: the pointer to store the new pcm instance + * + * Creates a new internal PCM instance with no userspace device or procfs + * entries. This is used by ASoC Back End PCMs in order to create a PCM that + * will only be used internally by kernel drivers. i.e. it cannot be opened + * by userspace. It provides existing ASoC components drivers with a substream + * and access to any private data. + * + * The pcm operators have to be set afterwards to the new instance + * via snd_pcm_set_ops(). + * + * Returns zero if successful, or a negative error code on failure. + */ +int snd_pcm_new_internal(struct snd_card *card, const char *id, int device, + int playback_count, int capture_count, + struct snd_pcm **rpcm) +{ + return _snd_pcm_new(card, id, device, playback_count, capture_count, + true, rpcm); +} +EXPORT_SYMBOL(snd_pcm_new_internal); + static void snd_pcm_free_stream(struct snd_pcm_str * pstr) { struct snd_pcm_substream *substream, *substream_next; @@ -994,7 +1033,7 @@ static int snd_pcm_dev_register(struct snd_device *device) } for (cidx = 0; cidx < 2; cidx++) { int devtype = -1; - if (pcm->streams[cidx].substream == NULL) + if (pcm->streams[cidx].substream == NULL || pcm->internal) continue; switch (cidx) { case SNDRV_PCM_STREAM_PLAYBACK: diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 3420bd3da5d..4d18941178e 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1029,7 +1029,8 @@ static int snd_interval_ratden(struct snd_interval *i, * * Returns non-zero if the value is changed, zero if not changed. */ -int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask) +int snd_interval_list(struct snd_interval *i, unsigned int count, + const unsigned int *list, unsigned int mask) { unsigned int k; struct snd_interval list_range; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 25ed9fe41b8..3fe99e644eb 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1586,12 +1586,18 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) struct file *file; struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream1; + struct snd_pcm_group *group; file = snd_pcm_file_fd(fd); if (!file) return -EBADFD; pcm_file = file->private_data; substream1 = pcm_file->substream; + group = kmalloc(sizeof(*group), GFP_KERNEL); + if (!group) { + res = -ENOMEM; + goto _nolock; + } down_write(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || @@ -1604,11 +1610,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) goto _end; } if (!snd_pcm_stream_linked(substream)) { - substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC); - if (substream->group == NULL) { - res = -ENOMEM; - goto _end; - } + substream->group = group; spin_lock_init(&substream->group->lock); INIT_LIST_HEAD(&substream->group->substreams); list_add_tail(&substream->link_list, &substream->group->substreams); @@ -1620,7 +1622,10 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) _end: write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); + _nolock: fput(file); + if (res < 0) + kfree(group); return res; } diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 130cfe677d6..14a286a7bf2 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -37,6 +37,8 @@ struct link_master { struct link_ctl_info info; int val; /* the master value */ unsigned int tlv[4]; + void (*hook)(void *private_data, int); + void *hook_private_data; }; /* @@ -126,7 +128,9 @@ static int master_init(struct link_master *master) master->info.count = 1; /* always mono */ /* set full volume as default (= no attenuation) */ master->val = master->info.max_val; - return 0; + if (master->hook) + master->hook(master->hook_private_data, master->val); + return 1; } return -ENOENT; } @@ -329,6 +333,8 @@ static int master_put(struct snd_kcontrol *kcontrol, slave_put_val(slave, uval); } kfree(uval); + if (master->hook && !err) + master->hook(master->hook_private_data, master->val); return 1; } @@ -408,3 +414,41 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, return kctl; } EXPORT_SYMBOL(snd_ctl_make_virtual_master); + +/** + * snd_ctl_add_vmaster_hook - Add a hook to a vmaster control + * @kcontrol: vmaster kctl element + * @hook: the hook function + * + * Adds the given hook to the vmaster control element so that it's called + * at each time when the value is changed. + */ +int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol, + void (*hook)(void *private_data, int), + void *private_data) +{ + struct link_master *master = snd_kcontrol_chip(kcontrol); + master->hook = hook; + master->hook_private_data = private_data; + return 0; +} +EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook); + +/** + * snd_ctl_sync_vmaster_hook - Sync the vmaster hook + * @kcontrol: vmaster kctl element + * + * Call the hook function to synchronize with the current value of the given + * vmaster element. NOP when NULL is passed to @kcontrol or the hook doesn't + * exist. + */ +void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol) +{ + struct link_master *master; + if (!kcontrol) + return; + master = snd_kcontrol_chip(kcontrol); + if (master->hook) + master->hook(master->hook_private_data, master->val); +} +EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook); diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index bb938153a96..466a5c8e835 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h @@ -26,7 +26,7 @@ #include <sound/mpu401.h> #include <sound/hwdep.h> #include <sound/ac97_codec.h> - +#include <sound/tlv.h> #endif #ifndef CHIP_AU8820 @@ -107,6 +107,14 @@ #define NR_WTPB 0x20 /* WT channels per each bank. */ #define NR_PCM 0x10 +struct pcm_vol { + struct snd_kcontrol *kctl; + int active; + int dma; + int mixin[4]; + int vol[4]; +}; + /* Structs */ typedef struct { //int this_08; /* Still unknown */ @@ -168,6 +176,7 @@ struct snd_vortex { /* Xtalk canceler */ int xt_mode; /* 1: speakers, 0:headphones. */ #endif + struct pcm_vol pcm_vol[NR_PCM]; int isquad; /* cache of extended ID codec flag. */ @@ -239,7 +248,7 @@ static int vortex_alsafmt_aspfmt(int alsafmt); /* Connection stuff. */ static void vortex_connect_default(vortex_t * vortex, int en); static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, - int dir, int type); + int dir, int type, int subdev); static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype); #ifndef CHIP_AU8810 diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 6933a27a5d7..525f881f040 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2050,8 +2050,6 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) } /* Default Connections */ -static int -vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type); static void vortex_connect_default(vortex_t * vortex, int en) { @@ -2111,15 +2109,13 @@ static void vortex_connect_default(vortex_t * vortex, int en) Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0. */ static int -vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) +vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, + int type, int subdev) { stream_t *stream; int i, en; + struct pcm_vol *p; - if ((nr_ch == 3) - || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2))) - return -EBUSY; - if (dma >= 0) { en = 0; vortex_adb_checkinout(vortex, @@ -2250,6 +2246,14 @@ vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) MIX_DEFIGAIN); #endif } + if (stream->type == VORTEX_PCM_ADB && en) { + p = &vortex->pcm_vol[subdev]; + p->dma = dma; + for (i = 0; i < nr_ch; i++) + p->mixin[i] = mix[i]; + for (i = 0; i < ch_top; i++) + p->vol[i] = 0; + } } #ifndef CHIP_AU8820 else { @@ -2473,7 +2477,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) hwread(vortex->mmio, VORTEX_IRQ_STAT); handled = 1; } - if (source & IRQ_MIDI) { + if ((source & IRQ_MIDI) && vortex->rmidi) { snd_mpu401_uart_interrupt(vortex->irq, vortex->rmidi->private_data); handled = 1; diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 0ef2f971220..e59f120742a 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -122,6 +122,18 @@ static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { .mask = 0, }; #endif + +static void vortex_notify_pcm_vol_change(struct snd_card *card, + struct snd_kcontrol *kctl, int activate) +{ + if (activate) + kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + else + kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE | + SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id)); +} + /* open callback */ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) { @@ -230,12 +242,14 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, if (stream != NULL) vortex_adb_allocroute(chip, stream->dma, stream->nr_ch, stream->dir, - stream->type); + stream->type, + substream->number); /* Alloc routes. */ dma = vortex_adb_allocroute(chip, -1, params_channels(hw_params), - substream->stream, type); + substream->stream, type, + substream->number); if (dma < 0) { spin_unlock_irq(&chip->lock); return dma; @@ -246,6 +260,11 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, vortex_adbdma_setbuffers(chip, dma, params_period_bytes(hw_params), params_periods(hw_params)); + if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { + chip->pcm_vol[substream->number].active = 1; + vortex_notify_pcm_vol_change(chip->card, + chip->pcm_vol[substream->number].kctl, 1); + } } #ifndef CHIP_AU8810 else { @@ -275,10 +294,18 @@ static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream) spin_lock_irq(&chip->lock); // Delete audio routes. if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { - if (stream != NULL) + if (stream != NULL) { + if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { + chip->pcm_vol[substream->number].active = 0; + vortex_notify_pcm_vol_change(chip->card, + chip->pcm_vol[substream->number].kctl, + 0); + } vortex_adb_allocroute(chip, stream->dma, stream->nr_ch, stream->dir, - stream->type); + stream->type, + substream->number); + } } #ifndef CHIP_AU8810 else { @@ -506,6 +533,83 @@ static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = { }, }; +/* subdevice PCM Volume control */ + +static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2); + uinfo->value.integer.min = -128; + uinfo->value.integer.max = 32; + return 0; +} + +static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int i; + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + int subdev = kcontrol->id.subdevice; + struct pcm_vol *p = &vortex->pcm_vol[subdev]; + int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); + for (i = 0; i < max_chn; i++) + ucontrol->value.integer.value[i] = p->vol[i]; + return 0; +} + +static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int i; + int changed = 0; + int mixin; + unsigned char vol; + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + int subdev = kcontrol->id.subdevice; + struct pcm_vol *p = &vortex->pcm_vol[subdev]; + int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); + for (i = 0; i < max_chn; i++) { + if (p->vol[i] != ucontrol->value.integer.value[i]) { + p->vol[i] = ucontrol->value.integer.value[i]; + if (p->active) { + switch (vortex->dma_adb[p->dma].nr_ch) { + case 1: + mixin = p->mixin[0]; + break; + case 2: + default: + mixin = p->mixin[(i < 2) ? i : (i - 2)]; + break; + case 4: + mixin = p->mixin[i]; + break; + }; + vol = p->vol[i]; + vortex_mix_setinputvolumebyte(vortex, + vortex->mixplayb[i], mixin, vol); + } + changed = 1; + } + } + return changed; +} + +static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); + +static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_INACTIVE, + .info = snd_vortex_pcm_vol_info, + .get = snd_vortex_pcm_vol_get, + .put = snd_vortex_pcm_vol_put, + .tlv = { .p = vortex_pcm_vol_db_scale }, +}; + /* create a pcm device */ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) { @@ -555,5 +659,20 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) return err; } } + if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) { + for (i = 0; i < NR_PCM; i++) { + chip->pcm_vol[i].active = 0; + chip->pcm_vol[i].dma = -1; + kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip); + if (!kctl) + return -ENOMEM; + chip->pcm_vol[i].kctl = kctl; + kctl->id.device = 0; + kctl->id.subdevice = i; + err = snd_ctl_add(chip->card, kctl); + if (err < 0) + return err; + } + } return 0; } diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index b78f3fc3c33..6109490b83e 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -36,7 +36,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size) size = CT_PAGE_ALIGN(size); if (size > vm->size) { - printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural " + printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual " "memory space available!\n"); return NULL; } diff --git a/sound/pci/hda/alc260_quirks.c b/sound/pci/hda/alc260_quirks.c deleted file mode 100644 index 3b5170b9700..00000000000 --- a/sound/pci/hda/alc260_quirks.c +++ /dev/null @@ -1,968 +0,0 @@ -/* - * ALC260 quirk models - * included by patch_realtek.c - */ - -/* ALC260 models */ -enum { - ALC260_AUTO, - ALC260_BASIC, - ALC260_FUJITSU_S702X, - ALC260_ACER, - ALC260_WILL, - ALC260_REPLACER_672V, - ALC260_FAVORIT100, -#ifdef CONFIG_SND_DEBUG - ALC260_TEST, -#endif - ALC260_MODEL_LAST /* last tag */ -}; - -static const hda_nid_t alc260_dac_nids[1] = { - /* front */ - 0x02, -}; - -static const hda_nid_t alc260_adc_nids[1] = { - /* ADC0 */ - 0x04, -}; - -static const hda_nid_t alc260_adc_nids_alt[1] = { - /* ADC1 */ - 0x05, -}; - -/* NIDs used when simultaneous access to both ADCs makes sense. Note that - * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. - */ -static const hda_nid_t alc260_dual_adc_nids[2] = { - /* ADC0, ADC1 */ - 0x04, 0x05 -}; - -#define ALC260_DIGOUT_NID 0x03 -#define ALC260_DIGIN_NID 0x06 - -static const struct hda_input_mux alc260_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, - * headphone jack and the internal CD lines since these are the only pins at - * which audio can appear. For flexibility, also allow the option of - * recording the mixer output on the second ADC (ADC0 doesn't have a - * connection to the mixer output). - */ -static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = { - { - .num_items = 3, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x4 }, - { "Headphone", 0x2 }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x4 }, - { "Headphone", 0x2 }, - { "Mixer", 0x5 }, - }, - }, - -}; - -/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to - * the Fujitsu S702x, but jacks are marked differently. - */ -static const struct hda_input_mux alc260_acer_capture_sources[2] = { - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Headphone", 0x5 }, - }, - }, - { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Headphone", 0x6 }, - { "Mixer", 0x5 }, - }, - }, -}; - -/* Maxdata Favorit 100XS */ -static const struct hda_input_mux alc260_favorit100_capture_sources[2] = { - { - .num_items = 2, - .items = { - { "Line/Mic", 0x0 }, - { "CD", 0x4 }, - }, - }, - { - .num_items = 3, - .items = { - { "Line/Mic", 0x0 }, - { "CD", 0x4 }, - { "Mixer", 0x5 }, - }, - }, -}; - -/* - * This is just place-holder, so there's something for alc_build_pcms to look - * at when it calculates the maximum number of channels. ALC260 has no mixer - * element which allows changing the channel mode, so the verb list is - * never used. - */ -static const struct hda_channel_mode alc260_modes[1] = { - { 2, NULL }, -}; - - -/* Mixer combinations - * - * basic: base_output + input + pc_beep + capture - * fujitsu: fujitsu + capture - * acer: acer + capture - */ - -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), - HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), - { } /* end */ -}; - -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), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), - { } /* end */ -}; - -/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, - * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. - */ -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), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT), - { } /* end */ -}; - -/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current - * versions of the ALC260 don't act on requests to enable mic bias from NID - * 0x0f (used to drive the headphone jack in these laptops). The ALC260 - * datasheet doesn't mention this restriction. At this stage it's not clear - * whether this behaviour is intentional or is a hardware bug in chip - * revisions available in early 2006. Therefore for now allow the - * "Headphone Jack Mode" control to span all choices, but if it turns out - * that the lack of mic bias for this NID is intentional we could change the - * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. - * - * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006 - * don't appear to make the mic bias available from the "line" jack, even - * though the NID used for this jack (0x14) can supply it. The theory is - * that perhaps Acer have included blocking capacitors between the ALC260 - * and the output jack. If this turns out to be the case for all such - * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT - * to ALC_PIN_DIR_INOUT_NOMICBIAS. - * - * The C20x Tablet series have a mono internal speaker which is controlled - * via the chip's Mono sum widget and pin complex, so include the necessary - * controls for such models. On models without a "mono speaker" the control - * won't do anything. - */ -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), - HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, - HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - { } /* end */ -}; - -/* Maxdata Favorit 100XS: one output and one input (0x12) jack - */ -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), - HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - { } /* end */ -}; - -/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12, - * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17. - */ -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), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - { } /* end */ -}; - -/* Replacer 672V ALC260 pin usage: Mic jack = 0x12, - * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f. - */ -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), - HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), - ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), - HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), - ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), - { } /* end */ -}; - -/* - * initialization 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 */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* LINE-2 is used for line-out in rear */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* select line-out */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LINE-OUT pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* enable HP */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* enable Mono */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to line in (default select for this ADC) */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* mute capture amp left and right */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to line in (default select for this ADC) */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* set vol=0 Line-Out mixer amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 HP mixer amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 Mono mixer amp left and right */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* unmute LINE-2 out pin */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & - * Line In 2 = 0x03 - */ - /* mute analog inputs */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* mute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* mute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* mute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } -}; - -/* Initialisation sequence for ALC260 as configured in Fujitsu S702x - * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD - * audio = 0x16, internal speaker = 0x10. - */ -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 */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Headphone/Line-out jack connects to Line1 pin; make it an output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Ensure all other unused pins are disabled and muted. */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Line1 pin widget takes its input from the OUT1 sum bus - * when acting as an output. - */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Line1 pin widget output buffer since it starts as an output. - * If the pin mode is changed by the user the pin mode control will - * take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute input buffer of pin widget used for Line-in (no equiv - * mixer ctrl) - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - line - * in (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do the same for the second ADC: mute capture input amp and - * set ADC connection to line in (on mic1 pin) - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -/* Initialisation sequence for ALC260 as configured in Acer TravelMate and - * similar laptops (adapted from Fujitsu 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. - */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - /* Internal speaker/Headphone jack is connected to Line-out pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Internal microphone/Mic jack is connected to Mic1 pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - /* Line In jack is connected to Line1 pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Ensure all other unused pins are disabled and muted. */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum - * bus when acting as outputs. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute Line-out pin widget amp left and right - * (no equiv mixer ctrl) - */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mic1 and Line1 pin widget input buffers since they start as - * inputs. If the pin mode is changed by the user the pin mode control - * will take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - mic - * (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do similar with the second ADC: mute capture input amp and - * set ADC connection to mic to match ALSA's default state. - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -/* Initialisation sequence for Maxdata Favorit 100XS - * (adapted from Acer 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. - */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - /* Line/Mic input jack is connected to Mic1 pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - /* Ensure all other unused pins are disabled and muted. */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Disable digital (SPDIF) pins */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum - * bus when acting as outputs. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute Line-out pin widget amp left and right - * (no equiv mixer ctrl) - */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Unmute Mic1 and Line1 pin widget input buffers since they start as - * inputs. If the pin mode is changed by the user the pin mode control - * will take care of enabling the pin's input/output buffers as needed. - * Therefore there's no need to enable the input buffer at this - * stage. - */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting - mic - * (on mic1 pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do similar with the second ADC: mute capture input amp and - * set ADC connection to mic to match ALSA's default state. - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; - -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}, - {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x1a, AC_VERB_SET_PROC_COEF, 0x3040}, - {} -}; - -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}, - - {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, - - {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc260_replacer_672v_automute(struct hda_codec *codec) -{ - unsigned int present; - - /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */ - present = snd_hda_jack_detect(codec, 0x0f); - if (present) { - snd_hda_codec_write_cache(codec, 0x01, 0, - AC_VERB_SET_GPIO_DATA, 1); - snd_hda_codec_write_cache(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_HP); - } else { - snd_hda_codec_write_cache(codec, 0x01, 0, - AC_VERB_SET_GPIO_DATA, 0); - snd_hda_codec_write_cache(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - PIN_OUT); - } -} - -static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc260_replacer_672v_automute(codec); -} - -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}, - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {} -}; - -/* Test configuration for debugging, modelled after the ALC880 test - * configuration. - */ -#ifdef CONFIG_SND_DEBUG -static const hda_nid_t alc260_test_dac_nids[1] = { - 0x02, -}; -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 const struct hda_input_mux alc260_test_capture_sources[2] = { - { - .num_items = 7, - .items = { - { "MIC1 pin", 0x0 }, - { "MIC2 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "LINE2 pin", 0x3 }, - { "CD pin", 0x4 }, - { "LINE-OUT pin", 0x5 }, - { "HP-OUT pin", 0x6 }, - }, - }, - { - .num_items = 8, - .items = { - { "MIC1 pin", 0x0 }, - { "MIC2 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "LINE2 pin", 0x3 }, - { "CD pin", 0x4 }, - { "Mixer", 0x5 }, - { "LINE-OUT pin", 0x6 }, - { "HP-OUT pin", 0x7 }, - }, - }, -}; -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), - HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT), - HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), - - /* Modes for retasking pin widgets - * Note: the ALC260 doesn't seem to act on requests to enable mic - * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't - * mention this restriction. At this stage it's not clear whether - * this behaviour is intentional or is a hardware bug in chip - * revisions available at least up until early 2006. Therefore for - * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all - * choices, but if it turns out that the lack of mic bias for these - * NIDs is intentional we could change their modes from - * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. - */ - ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT), - ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT), - - /* Loopback mixer controls */ - HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), - HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT), - - /* Controls for GPIO pins, assuming they are configured as outputs */ - ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), - ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), - ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), - ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), - - /* Switches to allow the digital IO pins to be enabled. The datasheet - * is ambigious as to which NID is which; testing on laptops which - * make this output available should provide clarification. - */ - ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), - ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), - - /* A switch allowing EAPD to be enabled. Some laptops seem to use - * this output to turn on an external amplifier. - */ - ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), - ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), - - { } /* end */ -}; -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}, - {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, - - /* Enable retasking pins as output, initially without power amp */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x0f, 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}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - /* Disable digital (SPDIF) pins initially, but users can enable - * them via a mixer switch. In the case of SPDIF-out, this initverb - * payload also sets the generation to 0, output to be in "consumer" - * PCM format, copyright asserted, no pre-emphasis and no validity - * control. - */ - {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, - {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, - - /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the - * OUT1 sum bus when acting as an output. - */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0c, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0}, - - /* Start with output sum widgets muted and their output gains at min */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* Unmute retasking pin widget output buffers since the default - * state appears to be output. As the pin mode is changed by the - * user the pin mode control will take care of enabling the pin's - * input/output buffers as needed. - */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Also unmute the mono-out pin widget */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - /* Set ADC connection select to match default mixer setting (mic1 - * pin) - */ - {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Do the same for the second ADC: mute capture input amp and - * set ADC connection to mic1 pin - */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ - - { } -}; -#endif - -/* - * ALC260 configurations - */ -static const char * const alc260_models[ALC260_MODEL_LAST] = { - [ALC260_BASIC] = "basic", - [ALC260_FUJITSU_S702X] = "fujitsu", - [ALC260_ACER] = "acer", - [ALC260_WILL] = "will", - [ALC260_REPLACER_672V] = "replacer", - [ALC260_FAVORIT100] = "favorit100", -#ifdef CONFIG_SND_DEBUG - [ALC260_TEST] = "test", -#endif - [ALC260_AUTO] = "auto", -}; - -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), - SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), - SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), - SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), - SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), - SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), - SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), - {} -}; - -static const struct alc_config_preset alc260_presets[] = { - [ALC260_BASIC] = { - .mixers = { alc260_base_output_mixer, - alc260_input_mixer }, - .init_verbs = { alc260_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_FUJITSU_S702X] = { - .mixers = { alc260_fujitsu_mixer }, - .init_verbs = { alc260_fujitsu_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources), - .input_mux = alc260_fujitsu_capture_sources, - }, - [ALC260_ACER] = { - .mixers = { alc260_acer_mixer }, - .init_verbs = { alc260_acer_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), - .input_mux = alc260_acer_capture_sources, - }, - [ALC260_FAVORIT100] = { - .mixers = { alc260_favorit100_mixer }, - .init_verbs = { alc260_favorit100_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_dual_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources), - .input_mux = alc260_favorit100_capture_sources, - }, - [ALC260_WILL] = { - .mixers = { alc260_will_mixer }, - .init_verbs = { alc260_init_verbs, alc260_will_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, - .dig_out_nid = ALC260_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - }, - [ALC260_REPLACER_672V] = { - .mixers = { alc260_replacer_672v_mixer }, - .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, - .num_dacs = ARRAY_SIZE(alc260_dac_nids), - .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), - .adc_nids = alc260_adc_nids, - .dig_out_nid = ALC260_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .input_mux = &alc260_capture_source, - .unsol_event = alc260_replacer_672v_unsol_event, - .init_hook = alc260_replacer_672v_automute, - }, -#ifdef CONFIG_SND_DEBUG - [ALC260_TEST] = { - .mixers = { alc260_test_mixer }, - .init_verbs = { alc260_test_init_verbs }, - .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), - .dac_nids = alc260_test_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids), - .adc_nids = alc260_test_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc260_modes), - .channel_mode = alc260_modes, - .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources), - .input_mux = alc260_test_capture_sources, - }, -#endif -}; - diff --git a/sound/pci/hda/alc880_quirks.c b/sound/pci/hda/alc880_quirks.c deleted file mode 100644 index 501501ef36a..00000000000 --- a/sound/pci/hda/alc880_quirks.c +++ /dev/null @@ -1,1707 +0,0 @@ -/* - * ALC880 quirk models - * included by patch_realtek.c - */ - -/* ALC880 board config type */ -enum { - ALC880_AUTO, - ALC880_3ST, - ALC880_3ST_DIG, - ALC880_5ST, - ALC880_5ST_DIG, - ALC880_W810, - ALC880_Z71V, - ALC880_6ST, - ALC880_6ST_DIG, - ALC880_F1734, - ALC880_ASUS, - ALC880_ASUS_DIG, - ALC880_ASUS_W1V, - ALC880_ASUS_DIG2, - ALC880_FUJITSU, - ALC880_UNIWILL_DIG, - ALC880_UNIWILL, - ALC880_UNIWILL_P53, - ALC880_CLEVO, - ALC880_TCL_S700, - ALC880_LG, -#ifdef CONFIG_SND_DEBUG - ALC880_TEST, -#endif - ALC880_MODEL_LAST /* last tag */ -}; - -/* - * ALC880 3-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) - * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, - * F-Mic = 0x1b, HP = 0x19 - */ - -static const hda_nid_t alc880_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x05, 0x04, 0x03 -}; - -static const hda_nid_t alc880_adc_nids[3] = { - /* ADC0-2 */ - 0x07, 0x08, 0x09, -}; - -/* The datasheet says the node 0x07 is connected from inputs, - * but it shows zero connection in the real implementation on some devices. - * Note: this is a 915GAV bug, fixed on 915GLV - */ -static const hda_nid_t alc880_adc_nids_alt[2] = { - /* ADC1-2 */ - 0x08, 0x09, -}; - -#define ALC880_DIGOUT_NID 0x06 -#define ALC880_DIGIN_NID 0x0a -#define ALC880_PIN_CD_NID 0x1c - -static const struct hda_input_mux alc880_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* channel source setting (2/6 channel selection for 3-stack) */ -/* 2ch mode */ -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 }, - /* set mic-in to input vref 80%, mute it */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* 6ch mode */ -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 }, - /* set mic-in to output, unmute it */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static const struct hda_channel_mode alc880_threestack_modes[2] = { - { 2, alc880_threestack_ch2_init }, - { 6, alc880_threestack_ch6_init }, -}; - -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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* - * ALC880 5-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), - * Side = 0x02 (0xd) - * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 - * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 - */ - -/* additional mixers to alc880_three_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 */ -}; - -/* channel source setting (6/8 channel selection for 5-stack) */ -/* 6ch mode */ -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 }, - { } /* end */ -}; - -/* 8ch mode */ -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 const struct hda_channel_mode alc880_fivestack_modes[2] = { - { 6, alc880_fivestack_ch6_init }, - { 8, alc880_fivestack_ch8_init }, -}; - - -/* - * ALC880 6-stack model - * - * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), - * Side = 0x05 (0x0f) - * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, - * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b - */ - -static const hda_nid_t alc880_6st_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -static const struct hda_input_mux alc880_6stack_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* fixed 8-channels */ -static const struct hda_channel_mode alc880_sixstack_modes[1] = { - { 8, NULL }, -}; - -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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - - -/* - * ALC880 W810 model - * - * W810 has rear IO for: - * Front (DAC 02) - * Surround (DAC 03) - * Center/LFE (DAC 04) - * Digital out (06) - * - * The system also has a pair of internal speakers, and a headphone jack. - * These are both connected to Line2 on the codec, hence to DAC 02. - * - * There is a variable resistor to control the speaker or headphone - * volume. This is a hardware-only device without a software API. - * - * Plugging headphones in will disable the internal speakers. This is - * implemented in hardware, not via the driver using jack sense. In - * a similar fashion, plugging into the rear socket marked "front" will - * disable both the speakers and headphones. - * - * For input, there's a microphone jack, and an "audio in" jack. - * These may not do anything useful with this driver yet, because I - * haven't setup any initialization verbs for these yet... - */ - -static const hda_nid_t alc880_w810_dac_nids[3] = { - /* front, rear/surround, clfe */ - 0x02, 0x03, 0x04 -}; - -/* fixed 6 channels */ -static const struct hda_channel_mode alc880_w810_modes[1] = { - { 6, NULL } -}; - -/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ -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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -}; - - -/* - * Z710V model - * - * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) - * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), - * Line = 0x1a - */ - -static const hda_nid_t alc880_z71v_dac_nids[1] = { - 0x02 -}; -#define ALC880_Z71V_HP_DAC 0x03 - -/* fixed 2 channels */ -static const struct hda_channel_mode alc880_2_jack_modes[1] = { - { 2, NULL } -}; - -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), - HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - - -/* - * ALC880 F1734 model - * - * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) - * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 - */ - -static const hda_nid_t alc880_f1734_dac_nids[1] = { - 0x03 -}; -#define ALC880_F1734_HP_DAC 0x02 - -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), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static const struct hda_input_mux alc880_f1734_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "CD", 0x4 }, - }, -}; - - -/* - * ALC880 ASUS model - * - * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) - * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, - * Mic = 0x18, Line = 0x1a - */ - -#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ -#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ - -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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -/* - * ALC880 ASUS W1V model - * - * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) - * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, - * Mic = 0x18, Line = 0x1a, Line2 = 0x1b - */ - -/* additional mixers to alc880_asus_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 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), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* Uniwill */ -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), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -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), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -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), - HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* - * initialize the codec volumes, etc - */ - -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb alc880_volume_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for front - * panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; - -/* - * 3-stack pin configuration: - * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b - */ -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 - */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ - - /* - * Set pin mode and muting - */ - /* set front pin widgets 0x14 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line2 (as front mic) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 5-stack pin configuration: - * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, - * line-in/side = 0x1a, f-mic = 0x1b - */ -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 - */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ - - /* - * Set pin mode and muting - */ - /* set pin widgets 0x14-0x17 for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* unmute pins for output (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mic2 (as headphone out) for HP output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line2 (as front mic) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * W810 pin configuration: - * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b - */ -static const struct hda_verb alc880_pin_w810_init_verbs[] = { - /* hphone/speaker input selector: front DAC */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - - {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_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - { } -}; - -/* - * Z71V pin configuration: - * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) - */ -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}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * 6-stack pin configuration: - * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, - * f-mic = 0x19, line = 0x1a, HP = 0x1b - */ -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}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {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}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {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}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* - * Uniwill pin configuration: - * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, - * line = 0x1a - */ -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}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {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}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */ - /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, - - { } -}; - -/* -* Uniwill P53 -* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, - */ -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}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {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}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_DCVOL_EVENT}, - - { } -}; - -static const struct hda_verb alc880_beep_init_verbs[] = { - { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, - { } -}; - -static void alc880_uniwill_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x16; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); -} - -static void alc880_uniwill_init_hook(struct hda_codec *codec) -{ - alc_hp_automute(codec); - alc88x_simple_mic_automute(codec); -} - -static void alc880_uniwill_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - res >>= 28; - switch (res) { - case ALC_MIC_EVENT: - alc88x_simple_mic_automute(codec); - break; - default: - alc_exec_unsol_event(codec, res); - break; - } -} - -static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) -{ - alc_exec_unsol_event(codec, res >> 28); -} - -static void alc880_uniwill_p53_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); -} - -static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); - present &= HDA_AMP_VOLMASK; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, present); - snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, present); -} - -static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - res >>= 28; - if (res == ALC_DCVOL_EVENT) - alc880_uniwill_p53_dcvol_automute(codec); - else - alc_exec_unsol_event(codec, res); -} - -/* - * F1734 pin configuration: - * HP = 0x14, speaker-out = 0x15, mic = 0x18 - */ -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}, - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, - {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_DCVOL_EVENT}, - - { } -}; - -/* - * ASUS pin configuration: - * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a - */ -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}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - { } -}; - -/* Enable GPIO mask and set output */ -#define alc880_gpio1_init_verbs alc_gpio1_init_verbs -#define alc880_gpio2_init_verbs alc_gpio2_init_verbs -#define alc880_gpio3_init_verbs alc_gpio3_init_verbs - -/* Clevo m520g init */ -static const struct hda_verb alc880_pin_clevo_init_verbs[] = { - /* headphone output */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* line-out */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line-in */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* CD */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic1 (rear panel) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Mic2 (front panel) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* headphone */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, - - { } -}; - -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}, - - /* Headphone output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Front output*/ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - - /* change to EAPD mode */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, - {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, - - { } -}; - -/* - * LG m1 express dual - * - * Pin assignment: - * Rear Line-In/Out (blue): 0x14 - * Build-in Mic-In: 0x15 - * Speaker-out: 0x17 - * HP-Out (green): 0x1b - * Mic-In/Out (red): 0x19 - * SPDIF-Out: 0x1e - */ - -/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ -static const hda_nid_t alc880_lg_dac_nids[3] = { - 0x05, 0x02, 0x03 -}; - -/* seems analog CD is not working */ -static const struct hda_input_mux alc880_lg_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x1 }, - { "Line", 0x5 }, - { "Internal Mic", 0x6 }, - }, -}; - -/* 2,4,6 channel modes */ -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 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 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 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 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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -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)}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* mute all amp mixer inputs */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* line-in to input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* built-in mic */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* speaker-out */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* mic-in to input */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* HP-out */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, - { } -}; - -/* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x17; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); -} - -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc880_lg_loopbacks[] = { - { 0x0b, HDA_INPUT, 1 }, - { 0x0b, HDA_INPUT, 6 }, - { 0x0b, HDA_INPUT, 7 }, - { } /* end */ -}; -#endif - -/* - * Test configuration for debugging - * - * Almost all inputs/outputs are enabled. I/O pins can be configured via - * enum controls. - */ -#ifdef CONFIG_SND_DEBUG -static const hda_nid_t alc880_test_dac_nids[4] = { - 0x02, 0x03, 0x04, 0x05 -}; - -static const struct hda_input_mux alc880_test_capture_source = { - .num_items = 7, - .items = { - { "In-1", 0x0 }, - { "In-2", 0x1 }, - { "In-3", 0x2 }, - { "In-4", 0x3 }, - { "CD", 0x4 }, - { "Front", 0x5 }, - { "Surround", 0x6 }, - }, -}; - -static const struct hda_channel_mode alc880_test_modes[4] = { - { 2, NULL }, - { 4, NULL }, - { 6, NULL }, - { 8, NULL }, -}; - -static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "N/A", "Line Out", "HP Out", - "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item >= 8) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int pin_ctl, item = 0; - - pin_ctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pin_ctl & AC_PINCTL_OUT_EN) { - if (pin_ctl & AC_PINCTL_HP_EN) - item = 2; - else - item = 1; - } else if (pin_ctl & AC_PINCTL_IN_EN) { - switch (pin_ctl & AC_PINCTL_VREFEN) { - case AC_PINCTL_VREF_HIZ: item = 3; break; - case AC_PINCTL_VREF_50: item = 4; break; - case AC_PINCTL_VREF_GRD: item = 5; break; - case AC_PINCTL_VREF_80: item = 6; break; - case AC_PINCTL_VREF_100: item = 7; break; - } - } - ucontrol->value.enumerated.item[0] = item; - return 0; -} - -static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - 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, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, - }; - unsigned int old_ctl, new_ctl; - - old_ctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - new_ctl = ctls[ucontrol->value.enumerated.item[0]]; - if (old_ctl != new_ctl) { - int val; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - new_ctl); - val = ucontrol->value.enumerated.item[0] >= 3 ? - HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, val); - return 1; - } - return 0; -} - -static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "Front", "Surround", "CLFE", "Side" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int sel; - - sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); - ucontrol->value.enumerated.item[0] = sel & 3; - return 0; -} - -static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = (hda_nid_t)kcontrol->private_value; - unsigned int sel; - - sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; - if (ucontrol->value.enumerated.item[0] != sel) { - sel = ucontrol->value.enumerated.item[0] & 3; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, sel); - return 1; - } - return 0; -} - -#define PIN_CTL_TEST(xname,nid) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_test_pin_ctl_info, \ - .get = alc_test_pin_ctl_get, \ - .put = alc_test_pin_ctl_put, \ - .private_value = nid \ - } - -#define PIN_SRC_TEST(xname,nid) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_test_pin_src_info, \ - .get = alc_test_pin_src_get, \ - .put = alc_test_pin_src_put, \ - .private_value = nid \ - } - -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), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - PIN_CTL_TEST("Front Pin Mode", 0x14), - PIN_CTL_TEST("Surround Pin Mode", 0x15), - PIN_CTL_TEST("CLFE Pin Mode", 0x16), - PIN_CTL_TEST("Side Pin Mode", 0x17), - PIN_CTL_TEST("In-1 Pin Mode", 0x18), - PIN_CTL_TEST("In-2 Pin Mode", 0x19), - PIN_CTL_TEST("In-3 Pin Mode", 0x1a), - PIN_CTL_TEST("In-4 Pin Mode", 0x1b), - PIN_SRC_TEST("In-1 Pin Source", 0x18), - PIN_SRC_TEST("In-2 Pin Source", 0x19), - PIN_SRC_TEST("In-3 Pin Source", 0x1a), - PIN_SRC_TEST("In-4 Pin Source", 0x1b), - HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -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)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Vol output for 0x0c-0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Set output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Unmute output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Set input pins 0x18-0x1c */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mute input pins 0x18-0x1b */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* ADC set up */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Analog input/passthru */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } -}; -#endif - -/* - */ - -static const char * const alc880_models[ALC880_MODEL_LAST] = { - [ALC880_3ST] = "3stack", - [ALC880_TCL_S700] = "tcl", - [ALC880_3ST_DIG] = "3stack-digout", - [ALC880_CLEVO] = "clevo", - [ALC880_5ST] = "5stack", - [ALC880_5ST_DIG] = "5stack-digout", - [ALC880_W810] = "w810", - [ALC880_Z71V] = "z71v", - [ALC880_6ST] = "6stack", - [ALC880_6ST_DIG] = "6stack-digout", - [ALC880_ASUS] = "asus", - [ALC880_ASUS_W1V] = "asus-w1v", - [ALC880_ASUS_DIG] = "asus-dig", - [ALC880_ASUS_DIG2] = "asus-dig2", - [ALC880_UNIWILL_DIG] = "uniwill", - [ALC880_UNIWILL_P53] = "uniwill-p53", - [ALC880_FUJITSU] = "fujitsu", - [ALC880_F1734] = "F1734", - [ALC880_LG] = "lg", -#ifdef CONFIG_SND_DEBUG - [ALC880_TEST] = "test", -#endif - [ALC880_AUTO] = "auto", -}; - -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), - SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), - SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), - SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V), - /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ - SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), - SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), - SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), - SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */ - SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), - SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), - SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), - SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), - SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), - SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), - SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), - SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), - SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734), - SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), - SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), - SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), - SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), - SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), - SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), - SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), - SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), - SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), - SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), - SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */ - SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), - SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), - /* default Intel */ - SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST), - SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), - SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), - {} -}; - -/* - * ALC880 codec presets - */ -static const struct alc_config_preset alc880_presets[] = { - [ALC880_3ST] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_3ST_DIG] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_3stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_TCL_S700] = { - .mixers = { alc880_tcl_s700_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_tcl_S700_init_verbs, - alc880_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */ - .num_adc_nids = 1, /* single ADC */ - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_5ST] = { - .mixers = { alc880_three_stack_mixer, - alc880_five_stack_mixer}, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_5stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), - .channel_mode = alc880_fivestack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_5ST_DIG] = { - .mixers = { alc880_three_stack_mixer, - alc880_five_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_5stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), - .channel_mode = alc880_fivestack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_6ST] = { - .mixers = { alc880_six_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), - .dac_nids = alc880_6st_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), - .channel_mode = alc880_sixstack_modes, - .input_mux = &alc880_6stack_capture_source, - }, - [ALC880_6ST_DIG] = { - .mixers = { alc880_six_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_6stack_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), - .dac_nids = alc880_6st_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), - .channel_mode = alc880_sixstack_modes, - .input_mux = &alc880_6stack_capture_source, - }, - [ALC880_W810] = { - .mixers = { alc880_w810_base_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_w810_init_verbs, - alc880_gpio2_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), - .channel_mode = alc880_w810_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_Z71V] = { - .mixers = { alc880_z71v_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_z71v_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), - .dac_nids = alc880_z71v_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - }, - [ALC880_F1734] = { - .mixers = { alc880_f1734_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_f1734_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), - .dac_nids = alc880_f1734_dac_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_f1734_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_ASUS] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_DIG] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_DIG2] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio2_init_verbs }, /* use GPIO2 */ - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_ASUS_W1V] = { - .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_UNIWILL_DIG] = { - .mixers = { alc880_asus_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_asus_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), - .channel_mode = alc880_asus_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_UNIWILL] = { - .mixers = { alc880_uniwill_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_unsol_event, - .setup = alc880_uniwill_setup, - .init_hook = alc880_uniwill_init_hook, - }, - [ALC880_UNIWILL_P53] = { - .mixers = { alc880_uniwill_p53_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_p53_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), - .dac_nids = alc880_asus_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), - .channel_mode = alc880_threestack_modes, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_FUJITSU] = { - .mixers = { alc880_fujitsu_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_uniwill_p53_init_verbs, - alc880_beep_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), - .channel_mode = alc880_2_jack_modes, - .input_mux = &alc880_capture_source, - .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_hp_automute, - }, - [ALC880_CLEVO] = { - .mixers = { alc880_three_stack_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_pin_clevo_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc880_capture_source, - }, - [ALC880_LG] = { - .mixers = { alc880_lg_mixer }, - .init_verbs = { alc880_volume_init_verbs, - alc880_lg_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids), - .dac_nids = alc880_lg_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), - .channel_mode = alc880_lg_ch_modes, - .need_dac_fix = 1, - .input_mux = &alc880_lg_capture_source, - .unsol_event = alc880_unsol_event, - .setup = alc880_lg_setup, - .init_hook = alc_hp_automute, -#ifdef CONFIG_SND_HDA_POWER_SAVE - .loopbacks = alc880_lg_loopbacks, -#endif - }, -#ifdef CONFIG_SND_DEBUG - [ALC880_TEST] = { - .mixers = { alc880_test_mixer }, - .init_verbs = { alc880_test_init_verbs }, - .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), - .dac_nids = alc880_test_dac_nids, - .dig_out_nid = ALC880_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_test_modes), - .channel_mode = alc880_test_modes, - .input_mux = &alc880_test_capture_source, - }, -#endif -}; - diff --git a/sound/pci/hda/alc882_quirks.c b/sound/pci/hda/alc882_quirks.c deleted file mode 100644 index bb364a53f54..00000000000 --- a/sound/pci/hda/alc882_quirks.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * ALC882/ALC883/ALC888/ALC889 quirk models - * included by patch_realtek.c - */ - -/* ALC882 models */ -enum { - ALC882_AUTO, - ALC885_MBA21, - ALC885_MBP3, - ALC885_MB5, - ALC885_MACMINI3, - ALC885_IMAC91, - ALC889A_MB31, - ALC882_MODEL_LAST, -}; - -#define ALC882_DIGOUT_NID 0x06 -#define ALC882_DIGIN_NID 0x0a -#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID -#define ALC883_DIGIN_NID ALC882_DIGIN_NID -#define ALC1200_DIGOUT_NID 0x10 - - -static const struct hda_channel_mode alc882_ch_modes[1] = { - { 8, NULL } -}; - -/* DACs */ -static const hda_nid_t alc882_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; -#define alc883_dac_nids alc882_dac_nids - -/* ADCs */ -#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 const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; -#define alc883_capsrc_nids alc882_capsrc_nids_alt - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ - -static const struct hda_input_mux alc882_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -#define alc883_capture_source alc882_capture_source - -static const struct hda_input_mux mb5_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x1 }, - { "Line", 0x7 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux macmini3_capture_source = { - .num_items = 2, - .items = { - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc883_3stack_6ch_intel = { - .num_items = 4, - .items = { - { "Mic", 0x1 }, - { "Front Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static const struct hda_input_mux alc889A_mb31_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - /* Front Mic (0x01) unused */ - { "Line", 0x2 }, - /* Line 2 (0x03) unused */ - /* CD (0x04) unused? */ - }, -}; - -static const struct hda_input_mux alc889A_imac91_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x01 }, - { "Line", 0x2 }, /* Not sure! */ - }, -}; - -/* Macbook Air 2,1 */ - -static const struct hda_channel_mode alc885_mba21_ch_modes[1] = { - { 2, NULL }, -}; - -/* - * macbook pro ALC885 can switch LineIn to LineOut without losing Mic - */ - -/* - * 2ch mode - */ -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)}, - { } /* end */ -}; - -/* - * 4ch mode - */ -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 }, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - { } /* end */ -}; - -static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = { - { 2, alc885_mbp_ch2_init }, - { 4, alc885_mbp_ch4_init }, -}; - -/* - * 2ch - * Speakers/Woofer/HP = Front - * LineIn = Input - */ -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 */ -}; - -/* - * 6ch mode - * Speakers/HP = Front - * Woofer = LFE - * LineIn = Surround - */ -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 const struct hda_channel_mode alc885_mb5_6ch_modes[2] = { - { 2, alc885_mb5_ch2_init }, - { 6, alc885_mb5_ch6_init }, -}; - -#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes - -/* Macbook Air 2,1 same control for HP and internal Speaker */ - -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 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), - HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), - { } /* end */ -}; - -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), - HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT), - { } /* end */ -}; - -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), - HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), - { } /* end */ -}; - -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 const struct snd_kcontrol_new alc882_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -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)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin: output 1 (0x0d) */ - {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}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {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}, - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -#define alc883_init_verbs alc882_base_init_verbs - -/* Macbook 5,1 */ -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}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Front mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Surround mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* LFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LFE Pin (0x0e) */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* HP Pin (0x0f) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)}, - { } -}; - -/* Macmini 3,1 */ -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}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Front mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Surround mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* LFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LFE Pin (0x0e) */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* HP Pin (0x0f) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Line In pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } -}; - - -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)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /*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}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP Pin: output 0 (0x0e) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)}, - /* Line in (is hp when jack connected)*/ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - { } - }; - - -/* Macbook Pro rev3 */ -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)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP Pin: output 0 (0x0e) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: use output 1 when in LineOut mode */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* 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)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - - { } -}; - -/* iMac 9,1 */ -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}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* HP Pin: Rear */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)}, - /* Line in Rear */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Line-Out 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)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } -}; - -/* Toggle speaker-output according to the hp-jack state */ -static void alc885_imac24_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->autocfg.speaker_pins[1] = 0x1a; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); -} - -#define alc885_mb5_setup alc885_imac24_setup -#define alc885_macmini3_setup alc885_imac24_setup - -/* Macbook Air 2,1 */ -static void alc885_mba21_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); -} - - - -static void alc885_mbp3_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); -} - -static void alc885_imac91_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->autocfg.speaker_pins[1] = 0x1a; - alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); -} - -/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ -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 */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ - { } /* end */ -}; - -/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ -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 */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ - { } /* end */ -}; - -/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ -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 */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ - { } /* end */ -}; - -/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ -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 */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ - { } /* end */ -}; - -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 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), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -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), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT), - /* Output switches */ - HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), - /* Boost mixers */ - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), - /* Input mixers */ - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new alc883_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -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 */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, - /* Init line pin (used as output in 4ch and 6ch mode) */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */ - /* Init line 2 pin (used as headphone out by default) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */ - { } /* end */ -}; - -/* Mute speakers according to the headphone jack state */ -static void alc889A_mb31_automute(struct hda_codec *codec) -{ - unsigned int present; - - /* Mute only in 2ch or 4ch mode */ - if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) - == 0x00) { - present = snd_hda_jack_detect(codec, 0x15); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - } -} - -static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC_HP_EVENT) - alc889A_mb31_automute(codec); -} - -static void alc882_unsol_event(struct hda_codec *codec, unsigned int res) -{ - alc_exec_unsol_event(codec, res >> 26); -} - -/* - * configuration and preset - */ -static const char * const alc882_models[ALC882_MODEL_LAST] = { - [ALC885_MB5] = "mb5", - [ALC885_MACMINI3] = "macmini3", - [ALC885_MBA21] = "mba21", - [ALC885_MBP3] = "mbp3", - [ALC885_IMAC91] = "imac91", - [ALC889A_MB31] = "mb31", - [ALC882_AUTO] = "auto", -}; - -/* codec SSID table for Intel Mac */ -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), - SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), - SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21), - SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), - SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), - SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91), - SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), - SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5), - /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, - * so apparently no perfect solution yet - */ - SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), - SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), - SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3), - {} /* terminator */ -}; - -static const struct alc_config_preset alc882_presets[] = { - [ALC885_MBA21] = { - .mixers = { alc885_mba21_mixer }, - .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs }, - .num_dacs = 2, - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mba21_ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), - .input_mux = &alc882_capture_source, - .unsol_event = alc882_unsol_event, - .setup = alc885_mba21_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MBP3] = { - .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_mbp3_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = 2, - .dac_nids = alc882_dac_nids, - .hp_nid = 0x04, - .channel_mode = alc885_mbp_4ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes), - .input_mux = &alc882_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc882_unsol_event, - .setup = alc885_mbp3_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MB5] = { - .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_mb5_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mb5_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), - .input_mux = &mb5_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc882_unsol_event, - .setup = alc885_mb5_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_MACMINI3] = { - .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_macmini3_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_macmini3_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes), - .input_mux = &macmini3_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc882_unsol_event, - .setup = alc885_macmini3_setup, - .init_hook = alc_hp_automute, - }, - [ALC885_IMAC91] = { - .mixers = {alc885_imac91_mixer}, - .init_verbs = { alc885_imac91_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mba21_ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), - .input_mux = &alc889A_imac91_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc882_unsol_event, - .setup = alc885_imac91_setup, - .init_hook = alc_hp_automute, - }, - [ALC889A_MB31] = { - .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer}, - .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs, - alc880_gpio1_init_verbs }, - .adc_nids = alc883_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .capsrc_nids = alc883_capsrc_nids, - .dac_nids = alc883_dac_nids, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .channel_mode = alc889A_mb31_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes), - .input_mux = &alc889A_mb31_capture_source, - .dig_out_nid = ALC883_DIGOUT_NID, - .unsol_event = alc889A_mb31_unsol_event, - .init_hook = alc889A_mb31_automute, - }, -}; - - diff --git a/sound/pci/hda/alc_quirks.c b/sound/pci/hda/alc_quirks.c deleted file mode 100644 index a18952ed431..00000000000 --- a/sound/pci/hda/alc_quirks.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Common codes for Realtek codec quirks - * included by patch_realtek.c - */ - -/* - * configuration template - to be copied to the spec instance - */ -struct alc_config_preset { - const struct snd_kcontrol_new *mixers[5]; /* should be identical size - * with spec - */ - const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ - const struct hda_verb *init_verbs[5]; - unsigned int num_dacs; - const hda_nid_t *dac_nids; - hda_nid_t dig_out_nid; /* optional */ - hda_nid_t hp_nid; /* optional */ - const hda_nid_t *slave_dig_outs; - unsigned int num_adc_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; - int need_dac_fix; - int const_channel_count; - unsigned int num_mux_defs; - const struct hda_input_mux *input_mux; - void (*unsol_event)(struct hda_codec *, unsigned int); - void (*setup)(struct hda_codec *); - void (*init_hook)(struct hda_codec *); -#ifdef CONFIG_SND_HDA_POWER_SAVE - const struct hda_amp_list *loopbacks; - void (*power_hook)(struct hda_codec *codec); -#endif -}; - -/* - * channel mode setting - */ -static int alc_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; - return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, - spec->num_channel_mode); -} - -static int alc_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; - return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - spec->ext_channel_count); -} - -static int alc_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 err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, - spec->num_channel_mode, - &spec->ext_channel_count); - if (err >= 0 && !spec->const_channel_count) { - spec->multiout.max_channels = spec->ext_channel_count; - if (spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - } - return err; -} - -/* - * Control the mode of pin widget settings via the mixer. "pc" is used - * 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. - * - * Note: some retasking pin complexes seem to ignore requests for input - * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these - * are requested. Therefore order this list so that this behaviour will not - * cause problems when mixer clients move through the enum sequentially. - * NIDs 0x0f and 0x10 have been observed to have this behaviour as of - * March 2006. - */ -static const char * const alc_pin_mode_names[] = { - "Mic 50pc bias", "Mic 80pc bias", - "Line in", "Line out", "Headphone out", -}; -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 - * in the pin being assumed to be exclusively an input or an output pin. In - * addition, "input" pins may or may not process the mic bias option - * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to - * accept requests for bias as of chip versions up to March 2006) and/or - * wiring in the computer. - */ -#define ALC_PIN_DIR_IN 0x00 -#define ALC_PIN_DIR_OUT 0x01 -#define ALC_PIN_DIR_INOUT 0x02 -#define ALC_PIN_DIR_IN_NOMICBIAS 0x03 -#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04 - -/* Info about the pin modes supported by the different pin direction modes. - * For each direction the minimum and maximum values are given. - */ -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 */ - { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */ - { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */ -}; -#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0]) -#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1]) -#define alc_pin_mode_n_items(_dir) \ - (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1) - -static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - unsigned int item_num = uinfo->value.enumerated.item; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = alc_pin_mode_n_items(dir); - - if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir)) - item_num = alc_pin_mode_min(dir); - strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]); - return 0; -} - -static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int i; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - - /* Find enumerated value for current pinctl setting */ - i = alc_pin_mode_min(dir); - while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl) - i++; - *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir); - return 0; -} - -static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char dir = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - - if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir)) - val = alc_pin_mode_min(dir); - - change = pinctl != alc_pin_mode_values[val]; - if (change) { - /* Set pin mode to that requested */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - alc_pin_mode_values[val]); - - /* Also enable the retasking pin's input/output as required - * for the requested pin mode. Enum values of 2 or less are - * input modes. - * - * Dynamically switching the input/output buffers probably - * reduces noise slightly (particularly on input) so we'll - * do it. However, having both input and output buffers - * enabled simultaneously doesn't seem to be problematic if - * this turns out to be necessary in the future. - */ - if (val <= 2) { - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, - HDA_AMP_MUTE, 0); - } else { - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, 0); - } - } - return change; -} - -#define ALC_PIN_MODE(xname, nid, dir) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_pin_mode_info, \ - .get = alc_pin_mode_get, \ - .put = alc_pin_mode_put, \ - .private_value = nid | (dir<<16) } - -/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged - * together using a mask with more than one bit set. This control is - * currently used only by the ALC260 test model. At this stage they are not - * needed for any "production" models. - */ -#ifdef CONFIG_SND_DEBUG -#define alc_gpio_data_info snd_ctl_boolean_mono_info - -static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_GPIO_DATA, 0x00); - - *valp = (val & mask) != 0; - return 0; -} -static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_GPIO_DATA, - 0x00); - - /* Set/unset the masked GPIO bit(s) as needed */ - change = (val == 0 ? 0 : mask) != (gpio_data & mask); - if (val == 0) - gpio_data &= ~mask; - else - gpio_data |= mask; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_GPIO_DATA, gpio_data); - - return change; -} -#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_gpio_data_info, \ - .get = alc_gpio_data_get, \ - .put = alc_gpio_data_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -/* A switch control to allow the enabling of the digital IO pins on the - * ALC260. This is incredibly simplistic; the intention of this control is - * to provide something in the test model allowing digital outputs to be - * identified if present. If models are found which can utilise these - * outputs a more complete mixer control can be devised for those models if - * necessary. - */ -#ifdef CONFIG_SND_DEBUG -#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info - -static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DIGI_CONVERT_1, 0x00); - - *valp = (val & mask) != 0; - return 0; -} -static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - signed int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DIGI_CONVERT_1, - 0x00); - - /* Set/unset the masked control bit(s) as needed */ - change = (val == 0 ? 0 : mask) != (ctrl_data & mask); - if (val==0) - ctrl_data &= ~mask; - else - ctrl_data |= mask; - snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - ctrl_data); - - return change; -} -#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_spdif_ctrl_info, \ - .get = alc_spdif_ctrl_get, \ - .put = alc_spdif_ctrl_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -/* A switch control to allow the enabling EAPD digital outputs on the ALC26x. - * Again, this is only used in the ALC26x test models to help identify when - * the EAPD line must be asserted for features to work. - */ -#ifdef CONFIG_SND_DEBUG -#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info - -static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long *valp = ucontrol->value.integer.value; - unsigned int val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_EAPD_BTLENABLE, 0x00); - - *valp = (val & mask) != 0; - return 0; -} - -static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int change; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value & 0xffff; - unsigned char mask = (kcontrol->private_value >> 16) & 0xff; - long val = *ucontrol->value.integer.value; - unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_EAPD_BTLENABLE, - 0x00); - - /* Set/unset the masked control bit(s) as needed */ - change = (!val ? 0 : mask) != (ctrl_data & mask); - if (!val) - ctrl_data &= ~mask; - else - ctrl_data |= mask; - snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, - ctrl_data); - - return change; -} - -#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ - .info = alc_eapd_ctrl_info, \ - .get = alc_eapd_ctrl_get, \ - .put = alc_eapd_ctrl_put, \ - .private_value = nid | (mask<<16) } -#endif /* CONFIG_SND_DEBUG */ - -static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (!cfg->line_outs) { - while (cfg->line_outs < AUTO_CFG_MAX_OUTS && - cfg->line_out_pins[cfg->line_outs]) - cfg->line_outs++; - } - if (!cfg->speaker_outs) { - while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS && - cfg->speaker_pins[cfg->speaker_outs]) - cfg->speaker_outs++; - } - if (!cfg->hp_outs) { - while (cfg->hp_outs < AUTO_CFG_MAX_OUTS && - cfg->hp_pins[cfg->hp_outs]) - cfg->hp_outs++; - } -} - -/* - * set up from the preset table - */ -static void setup_preset(struct hda_codec *codec, - const struct alc_config_preset *preset) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) - add_mixer(spec, preset->mixers[i]); - spec->cap_mixer = preset->cap_mixer; - for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; - i++) - add_verb(spec, preset->init_verbs[i]); - - spec->channel_mode = preset->channel_mode; - spec->num_channel_mode = preset->num_channel_mode; - spec->need_dac_fix = preset->need_dac_fix; - spec->const_channel_count = preset->const_channel_count; - - if (preset->const_channel_count) - spec->multiout.max_channels = preset->const_channel_count; - else - spec->multiout.max_channels = spec->channel_mode[0].channels; - spec->ext_channel_count = spec->channel_mode[0].channels; - - spec->multiout.num_dacs = preset->num_dacs; - spec->multiout.dac_nids = preset->dac_nids; - spec->multiout.dig_out_nid = preset->dig_out_nid; - spec->multiout.slave_dig_outs = preset->slave_dig_outs; - spec->multiout.hp_nid = preset->hp_nid; - - spec->num_mux_defs = preset->num_mux_defs; - if (!spec->num_mux_defs) - spec->num_mux_defs = 1; - spec->input_mux = preset->input_mux; - - spec->num_adc_nids = preset->num_adc_nids; - spec->adc_nids = preset->adc_nids; - spec->capsrc_nids = preset->capsrc_nids; - spec->dig_in_nid = preset->dig_in_nid; - - spec->unsol_event = preset->unsol_event; - spec->init_hook = preset->init_hook; -#ifdef CONFIG_SND_HDA_POWER_SAVE - spec->power_hook = preset->power_hook; - spec->loopback.amplist = preset->loopbacks; -#endif - - if (preset->setup) - preset->setup(codec); - - alc_fixup_autocfg_pin_nums(codec); -} - -static void alc_simple_setup_automute(struct alc_spec *spec, int mode) -{ - int lo_pin = spec->autocfg.line_out_pins[0]; - - if (lo_pin == spec->autocfg.speaker_pins[0] || - lo_pin == spec->autocfg.hp_pins[0]) - lo_pin = 0; - spec->automute_mode = mode; - spec->detect_hp = !!spec->autocfg.hp_pins[0]; - spec->detect_lo = !!lo_pin; - spec->automute_lo = spec->automute_lo_possible = !!lo_pin; - spec->automute_speaker = spec->automute_speaker_possible = !!spec->autocfg.speaker_pins[0]; -} - -/* auto-toggle front mic */ -static void alc88x_simple_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x18); - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); -} - diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 684307372d7..7a8fcc4c15f 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/mm.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/slab.h> @@ -2304,7 +2305,7 @@ typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *); /* apply the function to all matching slave ctls in the mixer list */ static int map_slaves(struct hda_codec *codec, const char * const *slaves, - map_slave_func_t func, void *data) + const char *suffix, map_slave_func_t func, void *data) { struct hda_nid_item *items; const char * const *s; @@ -2317,7 +2318,14 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves, sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER) continue; for (s = slaves; *s; s++) { - if (!strcmp(sctl->id.name, *s)) { + char tmpname[sizeof(sctl->id.name)]; + const char *name = *s; + if (suffix) { + snprintf(tmpname, sizeof(tmpname), "%s %s", + name, suffix); + name = tmpname; + } + if (!strcmp(sctl->id.name, name)) { err = func(data, sctl); if (err) return err; @@ -2333,12 +2341,65 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl) return 1; } +/* guess the value corresponding to 0dB */ +static int get_kctl_0dB_offset(struct snd_kcontrol *kctl) +{ + int _tlv[4]; + const int *tlv = NULL; + int val = -1; + + if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + /* FIXME: set_fs() hack for obtaining user-space TLV data */ + mm_segment_t fs = get_fs(); + set_fs(get_ds()); + if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv)) + tlv = _tlv; + set_fs(fs); + } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) + tlv = kctl->tlv.p; + if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) + val = -tlv[2] / tlv[3]; + return val; +} + +/* call kctl->put with the given value(s) */ +static int put_kctl_with_value(struct snd_kcontrol *kctl, int val) +{ + struct snd_ctl_elem_value *ucontrol; + ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); + if (!ucontrol) + return -ENOMEM; + ucontrol->value.integer.value[0] = val; + ucontrol->value.integer.value[1] = val; + kctl->put(kctl, ucontrol); + kfree(ucontrol); + return 0; +} + +/* initialize the slave volume with 0dB */ +static int init_slave_0dB(void *data, struct snd_kcontrol *slave) +{ + int offset = get_kctl_0dB_offset(slave); + if (offset > 0) + put_kctl_with_value(slave, offset); + return 0; +} + +/* unmute the slave */ +static int init_slave_unmute(void *data, struct snd_kcontrol *slave) +{ + return put_kctl_with_value(slave, 1); +} + /** * snd_hda_add_vmaster - create a virtual master control and add slaves * @codec: HD-audio codec * @name: vmaster control name * @tlv: TLV data (optional) * @slaves: slave control names (optional) + * @suffix: suffix string to each slave name (optional) + * @init_slave_vol: initialize slaves to unmute/0dB + * @ctl_ret: store the vmaster kcontrol in return * * Create a virtual master control with the given name. The TLV data * must be either NULL or a valid data. @@ -2349,13 +2410,18 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl) * * This function returns zero if successful or a negative error code. */ -int snd_hda_add_vmaster(struct hda_codec *codec, char *name, - unsigned int *tlv, const char * const *slaves) +int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, + unsigned int *tlv, const char * const *slaves, + const char *suffix, bool init_slave_vol, + struct snd_kcontrol **ctl_ret) { struct snd_kcontrol *kctl; int err; - err = map_slaves(codec, slaves, check_slave_present, NULL); + if (ctl_ret) + *ctl_ret = NULL; + + err = map_slaves(codec, slaves, suffix, check_slave_present, NULL); if (err != 1) { snd_printdd("No slave found for %s\n", name); return 0; @@ -2367,13 +2433,119 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, if (err < 0) return err; - err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave, - kctl); + err = map_slaves(codec, slaves, suffix, + (map_slave_func_t)snd_ctl_add_slave, kctl); if (err < 0) return err; + + /* init with master mute & zero volume */ + put_kctl_with_value(kctl, 0); + if (init_slave_vol) + map_slaves(codec, slaves, suffix, + tlv ? init_slave_0dB : init_slave_unmute, kctl); + + if (ctl_ret) + *ctl_ret = kctl; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); +EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster); + +/* + * mute-LED control using vmaster + */ +static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[] = { + "Off", "On", "Follow Master" + }; + unsigned int index; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + index = uinfo->value.enumerated.item; + if (index >= 3) + index = 2; + strcpy(uinfo->value.enumerated.name, texts[index]); + return 0; +} + +static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol); + ucontrol->value.enumerated.item[0] = hook->mute_mode; + return 0; +} + +static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol); + unsigned int old_mode = hook->mute_mode; + + hook->mute_mode = ucontrol->value.enumerated.item[0]; + if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER) + hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; + if (old_mode == hook->mute_mode) + return 0; + snd_hda_sync_vmaster_hook(hook); + return 1; +} + +static struct snd_kcontrol_new vmaster_mute_mode = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mute-LED Mode", + .info = vmaster_mute_mode_info, + .get = vmaster_mute_mode_get, + .put = vmaster_mute_mode_put, +}; + +/* + * Add a mute-LED hook with the given vmaster switch kctl + * "Mute-LED Mode" control is automatically created and associated with + * the given hook. + */ +int snd_hda_add_vmaster_hook(struct hda_codec *codec, + struct hda_vmaster_mute_hook *hook, + bool expose_enum_ctl) +{ + struct snd_kcontrol *kctl; + + if (!hook->hook || !hook->sw_kctl) + return 0; + snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec); + hook->codec = codec; + hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; + if (!expose_enum_ctl) + return 0; + kctl = snd_ctl_new1(&vmaster_mute_mode, hook); + if (!kctl) + return -ENOMEM; + return snd_hda_ctl_add(codec, 0, kctl); +} +EXPORT_SYMBOL_HDA(snd_hda_add_vmaster_hook); + +/* + * Call the hook with the current value for synchronization + * Should be called in init callback + */ +void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook) +{ + if (!hook->hook || !hook->codec) + return; + switch (hook->mute_mode) { + case HDA_VMUTE_FOLLOW_MASTER: + snd_ctl_sync_vmaster_hook(hook->sw_kctl); + break; + default: + hook->hook(hook->codec, hook->mute_mode); + break; + } +} +EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook); + /** * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch @@ -5272,6 +5444,10 @@ int snd_hda_suspend(struct hda_bus *bus) list_for_each_entry(codec, &bus->codec_list, list) { if (hda_codec_is_power_on(codec)) hda_call_codec_suspend(codec); + else /* forcibly change the power to D3 even if not used */ + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D3); if (codec->patch_ops.post_suspend) codec->patch_ops.post_suspend(codec); } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index f0f1943a4b2..9a9f372e1be 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -855,6 +855,7 @@ struct hda_codec { unsigned int pins_shutup:1; /* pins are shut up */ unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */ + unsigned int no_jack_detect:1; /* Machine has no jack-detection */ #ifdef CONFIG_SND_HDA_POWER_SAVE unsigned int power_on :1; /* current (global) power-state */ unsigned int power_transition :1; /* power-state in transition */ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index c1da422e085..b58b4b1687f 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -385,8 +385,8 @@ error: static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) { static unsigned int alsa_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, - 96000, 176400, 192000, 384000 + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, + 88200, 96000, 176400, 192000, 384000 }; int i, j; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 95dfb687494..c19e71a94e1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -84,7 +84,7 @@ module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); module_param_array(position_fix, int, NULL, 0444); MODULE_PARM_DESC(position_fix, "DMA pointer read method." - "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO)."); + "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO)."); module_param_array(bdl_pos_adj, int, NULL, 0644); MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); module_param_array(probe_mask, int, NULL, 0444); @@ -94,7 +94,7 @@ MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); module_param(single_cmd, bool, 0444); MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " "(for debugging only)."); -module_param(enable_msi, int, 0444); +module_param(enable_msi, bint, 0444); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); #ifdef CONFIG_SND_HDA_PATCH_LOADER module_param_array(patch, charp, NULL, 0444); @@ -121,8 +121,8 @@ module_param(power_save_controller, bool, 0644); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); #endif -static bool align_buffer_size = 1; -module_param(align_buffer_size, bool, 0644); +static int align_buffer_size = -1; +module_param(align_buffer_size, bint, 0644); MODULE_PARM_DESC(align_buffer_size, "Force buffer and period sizes to be multiple of 128 bytes."); @@ -148,6 +148,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, PCH}," "{Intel, CPT}," "{Intel, PPT}," + "{Intel, LPT}," "{Intel, PBG}," "{Intel, SCH}," "{ATI, SB450}," @@ -329,6 +330,7 @@ enum { POS_FIX_LPIB, POS_FIX_POSBUF, POS_FIX_VIACOMBO, + POS_FIX_COMBO, }; /* Defines for ATI HD Audio support in SB450 south bridge */ @@ -515,6 +517,7 @@ enum { #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ #define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ #define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ +#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -527,7 +530,8 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ - (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI) + (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\ + AZX_DCAPS_ALIGN_BUFSIZE) static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ICH] = "HDA Intel", @@ -2347,17 +2351,6 @@ static void azx_power_notify(struct hda_bus *bus) * power management */ -static int snd_hda_codecs_inuse(struct hda_bus *bus) -{ - struct hda_codec *codec; - - list_for_each_entry(codec, &bus->codec_list, list) { - if (snd_hda_codec_needs_resume(codec)) - return 1; - } - return 0; -} - static int azx_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); @@ -2404,8 +2397,7 @@ static int azx_resume(struct pci_dev *pci) return -EIO; azx_init_pci(chip); - if (snd_hda_codecs_inuse(chip->bus)) - azx_init_chip(chip, 1); + azx_init_chip(chip, 1); snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); @@ -2517,6 +2509,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix) case POS_FIX_LPIB: case POS_FIX_POSBUF: case POS_FIX_VIACOMBO: + case POS_FIX_COMBO: return fix; } @@ -2696,6 +2689,12 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->position_fix[0] = chip->position_fix[1] = check_position_fix(chip, position_fix[dev]); + /* combo mode uses LPIB for playback */ + if (chip->position_fix[0] == POS_FIX_COMBO) { + chip->position_fix[0] = POS_FIX_LPIB; + chip->position_fix[1] = POS_FIX_AUTO; + } + check_probe_mask(chip, dev); chip->single_cmd = single_cmd; @@ -2774,9 +2773,16 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } /* disable buffer size rounding to 128-byte multiples if supported */ - chip->align_buffer_size = align_buffer_size; - if (chip->driver_caps & AZX_DCAPS_BUFSIZE) - chip->align_buffer_size = 0; + if (align_buffer_size >= 0) + chip->align_buffer_size = !!align_buffer_size; + else { + if (chip->driver_caps & AZX_DCAPS_BUFSIZE) + chip->align_buffer_size = 0; + else if (chip->driver_caps & AZX_DCAPS_ALIGN_BUFSIZE) + chip->align_buffer_size = 1; + else + chip->align_buffer_size = 1; + } /* allow 64bit DMA address if supported by H/W */ if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) @@ -2992,6 +2998,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE}, + /* Lynx Point */ + { PCI_DEVICE(0x8086, 0x8c20), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | + AZX_DCAPS_BUFSIZE}, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 9d819c4b492..d68948499fb 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -19,6 +19,22 @@ #include "hda_local.h" #include "hda_jack.h" +bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) +{ + if (codec->no_jack_detect) + return false; + if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) + return false; + if (!codec->ignore_misc_bit && + (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & + AC_DEFCFG_MISC_NO_PRESENCE)) + return false; + if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + return false; + return true; +} +EXPORT_SYMBOL_HDA(is_jack_detectable); + /* execute pin sense measurement */ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) { diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index f8f97c71c9c..c66655cf413 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -62,18 +62,7 @@ int snd_hda_jack_detect_enable(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) -{ - if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) - return false; - if (!codec->ignore_misc_bit && - (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & - AC_DEFCFG_MISC_NO_PRESENCE)) - return false; - if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) - return false; - return true; -} +bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, const char *name, int idx); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index aca8d3193b9..0ec9248165b 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -139,10 +139,36 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int *tlv); struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name); -int snd_hda_add_vmaster(struct hda_codec *codec, char *name, - unsigned int *tlv, const char * const *slaves); +int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, + unsigned int *tlv, const char * const *slaves, + const char *suffix, bool init_slave_vol, + struct snd_kcontrol **ctl_ret); +#define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \ + __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL) int snd_hda_codec_reset(struct hda_codec *codec); +enum { + HDA_VMUTE_OFF, + HDA_VMUTE_ON, + HDA_VMUTE_FOLLOW_MASTER, +}; + +struct hda_vmaster_mute_hook { + /* below two fields must be filled by the caller of + * snd_hda_add_vmaster_hook() beforehand + */ + struct snd_kcontrol *sw_kctl; + void (*hook)(void *, int); + /* below are initialized automatically */ + unsigned int mute_mode; /* HDA_VMUTE_XXX */ + struct hda_codec *codec; +}; + +int snd_hda_add_vmaster_hook(struct hda_codec *codec, + struct hda_vmaster_mute_hook *hook, + bool expose_enum_ctl); +void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook); + /* amp value bits */ #define HDA_AMP_MUTE 0x80 #define HDA_AMP_UNMUTE 0x00 diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 9cb14b42dff..7143393927d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -82,6 +82,7 @@ struct ad198x_spec { unsigned int inv_jack_detect: 1;/* inverted jack-detection */ unsigned int inv_eapd: 1; /* inverted EAPD implementation */ unsigned int analog_beep: 1; /* analog beep input present */ + unsigned int avoid_init_slave_vol:1; #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; @@ -137,51 +138,17 @@ static int ad198x_init(struct hda_codec *codec) return 0; } -static const char * const ad_slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "Headphone Playback Volume", - "Mono Playback Volume", - "Speaker Playback Volume", - "IEC958 Playback Volume", +static const char * const ad_slave_pfxs[] = { + "Front", "Surround", "Center", "LFE", "Side", + "Headphone", "Mono", "Speaker", "IEC958", NULL }; -static const char * const ad_slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "Headphone Playback Switch", - "Mono Playback Switch", - "Speaker Playback Switch", - "IEC958 Playback Switch", +static const char * const ad1988_6stack_fp_slave_pfxs[] = { + "Front", "Surround", "Center", "LFE", "Side", "IEC958", NULL }; -static const char * const ad1988_6stack_fp_slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "IEC958 Playback Volume", - NULL -}; - -static const char * const ad1988_6stack_fp_slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "IEC958 Playback Switch", - NULL -}; static void ad198x_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP @@ -257,10 +224,12 @@ static int ad198x_build_controls(struct hda_codec *codec) unsigned int vmaster_tlv[4]; snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", + err = __snd_hda_add_vmaster(codec, "Master Playback Volume", vmaster_tlv, (spec->slave_vols ? - spec->slave_vols : ad_slave_vols)); + spec->slave_vols : ad_slave_pfxs), + "Playback Volume", + !spec->avoid_init_slave_vol, NULL); if (err < 0) return err; } @@ -268,7 +237,8 @@ static int ad198x_build_controls(struct hda_codec *codec) err = snd_hda_add_vmaster(codec, "Master Playback Switch", NULL, (spec->slave_sws ? - spec->slave_sws : ad_slave_sws)); + spec->slave_sws : ad_slave_pfxs), + "Playback Switch"); if (err < 0) return err; } @@ -3385,8 +3355,8 @@ static int patch_ad1988(struct hda_codec *codec) if (spec->autocfg.hp_pins[0]) { spec->mixers[spec->num_mixers++] = ad1988_hp_mixers; - spec->slave_vols = ad1988_6stack_fp_slave_vols; - spec->slave_sws = ad1988_6stack_fp_slave_sws; + spec->slave_vols = ad1988_6stack_fp_slave_pfxs; + spec->slave_sws = ad1988_6stack_fp_slave_pfxs; spec->alt_dac_nid = ad1988_alt_dac_nid; spec->stream_analog_alt_playback = &ad198x_pcm_analog_alt_playback; @@ -3594,16 +3564,8 @@ static const struct hda_amp_list ad1884_loopbacks[] = { #endif static const char * const ad1884_slave_vols[] = { - "PCM Playback Volume", - "Mic Playback Volume", - "Mono Playback Volume", - "Front Mic Playback Volume", - "Mic Playback Volume", - "CD Playback Volume", - "Internal Mic Playback Volume", - "Docking Mic Playback Volume", - /* "Beep Playback Volume", */ - "IEC958 Playback Volume", + "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD", + "Internal Mic", "Docking Mic", /* "Beep", */ "IEC958", NULL }; @@ -3644,6 +3606,8 @@ static int patch_ad1884(struct hda_codec *codec) spec->vmaster_nid = 0x04; /* we need to cover all playback volumes */ spec->slave_vols = ad1884_slave_vols; + /* slaves may contain input volumes, so we can't raise to 0dB blindly */ + spec->avoid_init_slave_vol = 1; codec->patch_ops = ad198x_patch_ops; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index f584f6d8ffc..8c6523bbc79 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -70,6 +70,8 @@ struct conexant_spec { const struct snd_kcontrol_new *mixers[5]; int num_mixers; hda_nid_t vmaster_nid; + struct hda_vmaster_mute_hook vmaster_mute; + bool vmaster_mute_led; const struct hda_verb *init_verbs[5]; /* initialization verbs * don't forget NULL @@ -465,21 +467,8 @@ static const struct snd_kcontrol_new cxt_beep_mixer[] = { }; #endif -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", +static const char * const slave_pfxs[] = { + "Headphone", "Speaker", "Front", "Surround", "CLFE", NULL }; @@ -519,14 +508,17 @@ static int conexant_build_controls(struct hda_codec *codec) snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, HDA_OUTPUT, vmaster_tlv); err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_vols); + vmaster_tlv, slave_pfxs, + "Playback Volume"); if (err < 0) return err; } if (spec->vmaster_nid && !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_sws); + err = __snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, slave_pfxs, + "Playback Switch", true, + &spec->vmaster_mute.sw_kctl); if (err < 0) return err; } @@ -3034,7 +3026,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { 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 */ SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO), {} }; @@ -3943,6 +3934,63 @@ static void enable_unsol_pins(struct hda_codec *codec, int num_pins, snd_hda_jack_detect_enable(codec, pins[i], action); } +static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) +{ + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return true; + return false; +} + +/* is the given NID found in any of autocfg items? */ +static bool found_in_autocfg(struct auto_pin_cfg *cfg, hda_nid_t nid) +{ + int i; + + if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || + found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || + found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs) || + found_in_nid_list(nid, cfg->dig_out_pins, cfg->dig_outs)) + return true; + for (i = 0; i < cfg->num_inputs; i++) + if (cfg->inputs[i].pin == nid) + return true; + if (cfg->dig_in_pin == nid) + return true; + return false; +} + +/* clear unsol-event tags on unused pins; Conexant codecs seem to leave + * invalid unsol tags by some reason + */ +static void clear_unsol_on_unused_pins(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < codec->init_pins.used; i++) { + struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); + if (!found_in_autocfg(cfg, pin->nid)) + snd_hda_codec_write(codec, pin->nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, 0); + } +} + +/* turn on/off EAPD according to Master switch */ +static void cx_auto_vmaster_hook(void *private_data, int enabled) +{ + struct hda_codec *codec = private_data; + struct conexant_spec *spec = codec->spec; + + if (enabled && spec->pin_eapd_ctrls) { + cx_auto_update_speakers(codec); + return; + } + cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled); +} + static void cx_auto_init_output(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -3983,6 +4031,7 @@ static void cx_auto_init_output(struct hda_codec *codec) /* turn on all EAPDs if no individual EAPD control is available */ if (!spec->pin_eapd_ctrls) cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); + clear_unsol_on_unused_pins(codec); } static void cx_auto_init_input(struct hda_codec *codec) @@ -4046,11 +4095,13 @@ static void cx_auto_init_digital(struct hda_codec *codec) static int cx_auto_init(struct hda_codec *codec) { + struct conexant_spec *spec = codec->spec; /*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/ cx_auto_init_output(codec); cx_auto_init_input(codec); cx_auto_init_digital(codec); snd_hda_jack_report_sync(codec); + snd_hda_sync_vmaster_hook(&spec->vmaster_mute); return 0; } @@ -4296,6 +4347,13 @@ static int cx_auto_build_controls(struct hda_codec *codec) err = snd_hda_jack_add_kctls(codec, &spec->autocfg); if (err < 0) return err; + if (spec->vmaster_mute.sw_kctl) { + spec->vmaster_mute.hook = cx_auto_vmaster_hook; + err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, + spec->vmaster_mute_led); + if (err < 0) + return err; + } return 0; } @@ -4320,7 +4378,6 @@ static int cx_auto_search_adcs(struct hda_codec *codec) return 0; } - static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = cx_auto_build_controls, .build_pcms = conexant_build_pcms, @@ -4368,6 +4425,7 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = { { 0x16, 0x042140ff }, /* HP (seq# overridden) */ { 0x17, 0x21a11000 }, /* dock-mic */ { 0x19, 0x2121103f }, /* dock-HP */ + { 0x1c, 0x21440100 }, /* dock SPDIF out */ {} }; @@ -4421,6 +4479,18 @@ static int patch_conexant_auto(struct hda_codec *codec) apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl); + /* Show mute-led control only on HP laptops + * This is a sort of white-list: on HP laptops, EAPD corresponds + * only to the mute-LED without actualy amp function. Meanwhile, + * others may use EAPD really as an amp switch, so it might be + * not good to expose it blindly. + */ + switch (codec->subsystem_id >> 16) { + case 0x103c: + spec->vmaster_mute_led = 1; + break; + } + err = cx_auto_search_adcs(codec); if (err < 0) return err; @@ -4434,6 +4504,18 @@ static int patch_conexant_auto(struct hda_codec *codec) codec->patch_ops = cx_auto_patch_ops; if (spec->beep_amp) snd_hda_attach_beep_device(codec, spec->beep_amp); + + /* Some laptops with Conexant chips show stalls in S3 resume, + * which falls into the single-cmd mode. + * Better to make reset, then. + */ + if (!codec->bus->sync_write) { + snd_printd("hda_codec: " + "Enable sync_write for stable communication\n"); + codec->bus->sync_write = 1; + codec->bus->allow_bus_reset = 1; + } + return 0; } diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 1168ebd3fb5..540cd13f7f1 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1912,6 +1912,7 @@ static const struct hda_codec_preset snd_hda_preset_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 = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi }, { .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, {} /* terminator */ }; @@ -1958,6 +1959,7 @@ 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:80862880"); 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 22c73b78ac6..8ea2fd65432 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -198,8 +198,11 @@ struct alc_spec { /* for virtual master */ hda_nid_t vmaster_nid; + struct hda_vmaster_mute_hook vmaster_mute; #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; + int num_loopbacks; + struct hda_amp_list loopback_list[8]; #endif /* for PLL fix */ @@ -220,8 +223,6 @@ struct alc_spec { struct snd_array bind_ctls; }; -#define ALC_MODEL_AUTO 0 /* common for all chips */ - static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int bits) { @@ -300,6 +301,9 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, int i, type, num_conns; hda_nid_t nid; + if (!spec->input_mux) + return 0; + mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; if (!imux->num_items && mux_idx > 0) @@ -651,15 +655,51 @@ static void alc_exec_unsol_event(struct hda_codec *codec, int action) snd_hda_jack_report_sync(codec); } +/* update the master volume per volume-knob's unsol event */ +static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int val; + struct snd_kcontrol *kctl; + struct snd_ctl_elem_value *uctl; + + kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume"); + if (!kctl) + return; + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); + if (!uctl) + return; + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); + val &= HDA_AMP_VOLMASK; + uctl->value.integer.value[0] = val; + uctl->value.integer.value[1] = val; + kctl->put(kctl, uctl); + kfree(uctl); +} + /* unsolicited event for HP jack sensing */ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) { + int action; + if (codec->vendor_id == 0x10ec0880) res >>= 28; else res >>= 26; - res = snd_hda_jack_get_action(codec, res); - alc_exec_unsol_event(codec, res); + action = snd_hda_jack_get_action(codec, res); + if (action == ALC_DCVOL_EVENT) { + /* Execute the dc-vol event here as it requires the NID + * but we don't pass NID to alc_exec_unsol_event(). + * Once when we convert all static quirks to the auto-parser, + * this can be integerated into there. + */ + struct hda_jack_tbl *jack; + jack = snd_hda_jack_tbl_get_from_tag(codec, res); + if (jack) + alc_update_knob_master(codec, jack->nid); + return; + } + alc_exec_unsol_event(codec, action); } /* call init functions of standard auto-mute helpers */ @@ -1033,45 +1073,6 @@ static bool alc_check_dyn_adc_switch(struct hda_codec *codec) return true; } -/* rebuild imux for matching with the given auto-mic pins (if not yet) */ -static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux; - static char * const texts[3] = { - "Mic", "Internal Mic", "Dock Mic" - }; - int i; - - if (!spec->auto_mic) - return false; - imux = &spec->private_imux[0]; - if (spec->input_mux == imux) - return true; - spec->imux_pins[0] = spec->ext_mic_pin; - spec->imux_pins[1] = spec->int_mic_pin; - spec->imux_pins[2] = spec->dock_mic_pin; - for (i = 0; i < 3; i++) { - strcpy(imux->items[i].label, texts[i]); - if (spec->imux_pins[i]) { - hda_nid_t pin = spec->imux_pins[i]; - int c; - for (c = 0; c < spec->num_adc_nids; c++) { - hda_nid_t cap = get_capsrc(spec, c); - int idx = get_connection_index(codec, cap, pin); - if (idx >= 0) { - imux->items[i].index = idx; - break; - } - } - imux->num_items = i + 1; - } - } - spec->num_mux_defs = 1; - spec->input_mux = imux; - return true; -} - /* check whether all auto-mic pins are valid; setup indices if OK */ static bool alc_auto_mic_check_imux(struct hda_codec *codec) { @@ -1441,6 +1442,7 @@ enum { ALC_FIXUP_ACT_PRE_PROBE, ALC_FIXUP_ACT_PROBE, ALC_FIXUP_ACT_INIT, + ALC_FIXUP_ACT_BUILD, }; static void alc_apply_fixup(struct hda_codec *codec, int action) @@ -1520,6 +1522,13 @@ static void alc_pick_fixup(struct hda_codec *codec, int id = -1; const char *name = NULL; + /* when model=nofixup is given, don't pick up any fixups */ + if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { + spec->fixup_list = NULL; + spec->fixup_id = -1; + return; + } + if (codec->modelname && models) { while (models->name) { if (!strcmp(codec->modelname, models->name)) { @@ -1847,36 +1856,10 @@ DEFINE_CAPMIX_NOSRC(3); /* * slave controls for virtual master */ -static const char * const alc_slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "Headphone Playback Volume", - "Speaker Playback Volume", - "Mono Playback Volume", - "Line Out Playback Volume", - "CLFE Playback Volume", - "Bass Speaker Playback Volume", - "PCM Playback Volume", - NULL, -}; - -static const char * const alc_slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "Headphone Playback Switch", - "Speaker Playback Switch", - "Mono Playback Switch", - "IEC958 Playback Switch", - "Line Out Playback Switch", - "CLFE Playback Switch", - "Bass Speaker Playback Switch", - "PCM Playback Switch", +static const char * const alc_slave_pfxs[] = { + "Front", "Surround", "Center", "LFE", "Side", + "Headphone", "Speaker", "Mono", "Line Out", + "CLFE", "Bass Speaker", "PCM", NULL, }; @@ -1967,14 +1950,17 @@ static int __alc_build_controls(struct hda_codec *codec) snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, HDA_OUTPUT, vmaster_tlv); err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, alc_slave_vols); + vmaster_tlv, alc_slave_pfxs, + "Playback Volume"); if (err < 0) return err; } if (!spec->no_analog && !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, alc_slave_sws); + err = __snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, alc_slave_pfxs, + "Playback Switch", + true, &spec->vmaster_mute.sw_kctl); if (err < 0) return err; } @@ -2059,7 +2045,11 @@ static int alc_build_controls(struct hda_codec *codec) int err = __alc_build_controls(codec); if (err < 0) return err; - return snd_hda_jack_add_kctls(codec, &spec->autocfg); + err = snd_hda_jack_add_kctls(codec, &spec->autocfg); + if (err < 0) + return err; + alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD); + return 0; } @@ -2068,15 +2058,15 @@ static int alc_build_controls(struct hda_codec *codec) */ static void alc_init_special_input_src(struct hda_codec *codec); -static int alc269_fill_coef(struct hda_codec *codec); +static void alc_auto_init_std(struct hda_codec *codec); static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; unsigned int i; - if (codec->vendor_id == 0x10ec0269) - alc269_fill_coef(codec); + if (spec->init_hook) + spec->init_hook(codec); alc_fix_pll(codec); alc_auto_init_amp(codec, spec->init_amp); @@ -2084,9 +2074,7 @@ static int alc_init(struct hda_codec *codec) for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); alc_init_special_input_src(codec); - - if (spec->init_hook) - spec->init_hook(codec); + alc_auto_init_std(codec); alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); @@ -2675,6 +2663,25 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, return channel_name[ch]; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* add the powersave loopback-list entry */ +static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx) +{ + struct hda_amp_list *list; + + if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) + return; + list = spec->loopback_list + spec->num_loopbacks; + list->nid = mix; + list->dir = HDA_INPUT; + list->idx = idx; + spec->num_loopbacks++; + spec->loopback.amplist = spec->loopback_list; +} +#else +#define add_loopback_list(spec, mix, idx) /* NOP */ +#endif + /* create input playback/capture controls for the given pin */ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname, int ctlidx, @@ -2690,6 +2697,7 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); if (err < 0) return err; + add_loopback_list(spec, mix_nid, idx); return 0; } @@ -2954,10 +2962,27 @@ static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, return 0; } +static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) +{ + struct alc_spec *spec = codec->spec; + int i; + if (found_in_nid_list(nid, spec->multiout.dac_nids, + ARRAY_SIZE(spec->private_dac_nids)) || + found_in_nid_list(nid, spec->multiout.hp_out_nid, + ARRAY_SIZE(spec->multiout.hp_out_nid)) || + found_in_nid_list(nid, spec->multiout.extra_out_nid, + ARRAY_SIZE(spec->multiout.extra_out_nid))) + return true; + for (i = 0; i < spec->multi_ios; i++) { + if (spec->multi_io[i].dac == nid) + return true; + } + return false; +} + /* look for an empty DAC slot */ 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, num; @@ -2967,16 +2992,8 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); if (!nid) continue; - if (found_in_nid_list(nid, spec->multiout.dac_nids, - ARRAY_SIZE(spec->private_dac_nids))) - continue; - if (found_in_nid_list(nid, spec->multiout.hp_out_nid, - ARRAY_SIZE(spec->multiout.hp_out_nid))) - continue; - if (found_in_nid_list(nid, spec->multiout.extra_out_nid, - ARRAY_SIZE(spec->multiout.extra_out_nid))) - continue; - return nid; + if (!alc_is_dac_already_used(codec, nid)) + return nid; } return 0; } @@ -2988,6 +3005,8 @@ static bool alc_auto_is_dac_reachable(struct hda_codec *codec, hda_nid_t srcs[5]; int i, num; + if (!pin || !dac) + return false; pin = alc_go_down_to_selector(codec, pin); num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); for (i = 0; i < num; i++) { @@ -3000,83 +3019,260 @@ static bool alc_auto_is_dac_reachable(struct hda_codec *codec, static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) { + struct alc_spec *spec = codec->spec; hda_nid_t sel = alc_go_down_to_selector(codec, pin); - if (snd_hda_get_conn_list(codec, sel, NULL) == 1) + hda_nid_t nid, nid_found, srcs[5]; + int i, num = snd_hda_get_connections(codec, sel, srcs, + ARRAY_SIZE(srcs)); + if (num == 1) return alc_auto_look_for_dac(codec, pin); - return 0; + nid_found = 0; + for (i = 0; i < num; i++) { + if (srcs[i] == spec->mixer_nid) + continue; + nid = alc_auto_mix_to_dac(codec, srcs[i]); + if (nid && !alc_is_dac_already_used(codec, nid)) { + if (nid_found) + return 0; + nid_found = nid; + } + } + return nid_found; } -/* return 0 if no possible DAC is found, 1 if one or more found */ -static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs, - const hda_nid_t *pins, hda_nid_t *dacs) +/* mark up volume and mute control NIDs: used during badness parsing and + * at creating actual controls + */ +static inline unsigned int get_ctl_pos(unsigned int data) { - int i; + hda_nid_t nid = get_amp_nid_(data); + unsigned int dir; + if (snd_BUG_ON(nid >= MAX_VOL_NIDS)) + return 0; + dir = get_amp_direction_(data); + return (nid << 1) | dir; +} - if (num_outs && !dacs[0]) { - dacs[0] = alc_auto_look_for_dac(codec, pins[0]); - if (!dacs[0]) - return 0; - } +#define is_ctl_used(bits, data) \ + test_bit(get_ctl_pos(data), bits) +#define mark_ctl_usage(bits, data) \ + set_bit(get_ctl_pos(data), bits) - for (i = 1; i < num_outs; i++) - dacs[i] = get_dac_if_single(codec, pins[i]); - for (i = 1; i < num_outs; i++) { +static void clear_vol_marks(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + memset(spec->vol_ctls, 0, sizeof(spec->vol_ctls)); + memset(spec->sw_ctls, 0, sizeof(spec->sw_ctls)); +} + +/* badness definition */ +enum { + /* No primary DAC is found for the main output */ + BAD_NO_PRIMARY_DAC = 0x10000, + /* No DAC is found for the extra output */ + BAD_NO_DAC = 0x4000, + /* No possible multi-ios */ + BAD_MULTI_IO = 0x103, + /* No individual DAC for extra output */ + BAD_NO_EXTRA_DAC = 0x102, + /* No individual DAC for extra surrounds */ + BAD_NO_EXTRA_SURR_DAC = 0x101, + /* Primary DAC shared with main surrounds */ + BAD_SHARED_SURROUND = 0x100, + /* Primary DAC shared with main CLFE */ + BAD_SHARED_CLFE = 0x10, + /* Primary DAC shared with extra surrounds */ + BAD_SHARED_EXTRA_SURROUND = 0x10, + /* Volume widget is shared */ + BAD_SHARED_VOL = 0x10, +}; + +static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec, + hda_nid_t pin, hda_nid_t dac); +static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, + hda_nid_t pin, hda_nid_t dac); + +static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t dac) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid; + unsigned int val; + int badness = 0; + + nid = alc_look_for_out_vol_nid(codec, pin, dac); + if (nid) { + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + if (is_ctl_used(spec->vol_ctls, nid)) + badness += BAD_SHARED_VOL; + else + mark_ctl_usage(spec->vol_ctls, val); + } else + badness += BAD_SHARED_VOL; + nid = alc_look_for_out_mute_nid(codec, pin, dac); + if (nid) { + unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); + if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + else + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); + if (is_ctl_used(spec->sw_ctls, val)) + badness += BAD_SHARED_VOL; + else + mark_ctl_usage(spec->sw_ctls, val); + } else + badness += BAD_SHARED_VOL; + return badness; +} + +struct badness_table { + int no_primary_dac; /* no primary DAC */ + int no_dac; /* no secondary DACs */ + int shared_primary; /* primary DAC is shared with main output */ + int shared_surr; /* secondary DAC shared with main or primary */ + int shared_clfe; /* third DAC shared with main or primary */ + int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ +}; + +static struct badness_table main_out_badness = { + .no_primary_dac = BAD_NO_PRIMARY_DAC, + .no_dac = BAD_NO_DAC, + .shared_primary = BAD_NO_PRIMARY_DAC, + .shared_surr = BAD_SHARED_SURROUND, + .shared_clfe = BAD_SHARED_CLFE, + .shared_surr_main = BAD_SHARED_SURROUND, +}; + +static struct badness_table extra_out_badness = { + .no_primary_dac = BAD_NO_DAC, + .no_dac = BAD_NO_DAC, + .shared_primary = BAD_NO_EXTRA_DAC, + .shared_surr = BAD_SHARED_EXTRA_SURROUND, + .shared_clfe = BAD_SHARED_EXTRA_SURROUND, + .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, +}; + +/* try to assign DACs to pins and return the resultant badness */ +static int alc_auto_fill_dacs(struct hda_codec *codec, int num_outs, + const hda_nid_t *pins, hda_nid_t *dacs, + const struct badness_table *bad) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, j; + int badness = 0; + hda_nid_t dac; + + if (!num_outs) + return 0; + + for (i = 0; i < num_outs; i++) { + hda_nid_t pin = pins[i]; if (!dacs[i]) - dacs[i] = alc_auto_look_for_dac(codec, pins[i]); + dacs[i] = alc_auto_look_for_dac(codec, pin); + if (!dacs[i] && !i) { + for (j = 1; j < num_outs; j++) { + if (alc_auto_is_dac_reachable(codec, pin, dacs[j])) { + dacs[0] = dacs[j]; + dacs[j] = 0; + break; + } + } + } + dac = dacs[i]; + if (!dac) { + if (alc_auto_is_dac_reachable(codec, pin, dacs[0])) + dac = dacs[0]; + else if (cfg->line_outs > i && + alc_auto_is_dac_reachable(codec, pin, + spec->private_dac_nids[i])) + dac = spec->private_dac_nids[i]; + if (dac) { + if (!i) + badness += bad->shared_primary; + else if (i == 1) + badness += bad->shared_surr; + else + badness += bad->shared_clfe; + } else if (alc_auto_is_dac_reachable(codec, pin, + spec->private_dac_nids[0])) { + dac = spec->private_dac_nids[0]; + badness += bad->shared_surr_main; + } else if (!i) + badness += bad->no_primary_dac; + else + badness += bad->no_dac; + } + if (dac) + badness += eval_shared_vol_badness(codec, pin, dac); } - return 1; + + return badness; } static int alc_auto_fill_multi_ios(struct hda_codec *codec, - unsigned int location, int offset); -static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac); + hda_nid_t reference_pin, + bool hardwired, int offset); + +static bool alc_map_singles(struct hda_codec *codec, int outs, + const hda_nid_t *pins, hda_nid_t *dacs) +{ + int i; + bool found = false; + for (i = 0; i < outs; i++) { + if (dacs[i]) + continue; + dacs[i] = get_dac_if_single(codec, pins[i]); + if (dacs[i]) + found = true; + } + return found; +} /* fill in the dac_nids table from the parsed pin configuration */ -static int alc_auto_fill_dac_nids(struct hda_codec *codec) +static int fill_and_eval_dacs(struct hda_codec *codec, + bool fill_hardwired, + bool fill_mio_first) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int location, defcfg; - int num_pins; - bool redone = false; - int i; + int i, err, badness; - again: /* set num_dacs once to full for alc_auto_look_for_dac() */ spec->multiout.num_dacs = cfg->line_outs; - spec->multiout.hp_out_nid[0] = 0; - spec->multiout.extra_out_nid[0] = 0; - memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); spec->multiout.dac_nids = spec->private_dac_nids; + memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); + memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); + memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); spec->multi_ios = 0; + clear_vol_marks(codec); + badness = 0; /* fill hard-wired DACs first */ - if (!redone) { - for (i = 0; i < cfg->line_outs; i++) - spec->private_dac_nids[i] = - get_dac_if_single(codec, cfg->line_out_pins[i]); - if (cfg->hp_outs) - spec->multiout.hp_out_nid[0] = - get_dac_if_single(codec, cfg->hp_pins[0]); - if (cfg->speaker_outs) - spec->multiout.extra_out_nid[0] = - get_dac_if_single(codec, cfg->speaker_pins[0]); + if (fill_hardwired) { + bool mapped; + do { + mapped = alc_map_singles(codec, cfg->line_outs, + cfg->line_out_pins, + spec->private_dac_nids); + mapped |= alc_map_singles(codec, cfg->hp_outs, + cfg->hp_pins, + spec->multiout.hp_out_nid); + mapped |= alc_map_singles(codec, cfg->speaker_outs, + cfg->speaker_pins, + spec->multiout.extra_out_nid); + if (fill_mio_first && cfg->line_outs == 1 && + cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], true, 0); + if (!err) + mapped = true; + } + } while (mapped); } - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t pin = cfg->line_out_pins[i]; - if (spec->private_dac_nids[i]) - continue; - spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin); - if (!spec->private_dac_nids[i] && !redone) { - /* if we can't find primary DACs, re-probe without - * checking the hard-wired DACs - */ - redone = true; - goto again; - } - } + badness += alc_auto_fill_dacs(codec, cfg->line_outs, cfg->line_out_pins, + spec->private_dac_nids, + &main_out_badness); /* re-count num_dacs and squash invalid entries */ spec->multiout.num_dacs = 0; @@ -3091,30 +3287,144 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) } } - if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + if (fill_mio_first && + cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { /* try to fill multi-io first */ - 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, 0); - if (num_pins > 0) { - spec->multi_ios = num_pins; - spec->ext_channel_count = 2; - spec->multiout.num_dacs = num_pins + 1; - } + err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); + if (err < 0) + return err; + /* we don't count badness at this stage yet */ } - if (cfg->line_out_type != AUTO_PIN_HP_OUT) - alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins, - spec->multiout.hp_out_nid); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = alc_auto_fill_dacs(codec, cfg->hp_outs, cfg->hp_pins, + spec->multiout.hp_out_nid, + &extra_out_badness); + if (err < 0) + return err; + badness += err; + } if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - int err = alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, - cfg->speaker_pins, - spec->multiout.extra_out_nid); - /* if no speaker volume is assigned, try again as the primary - * output - */ - if (!err && cfg->speaker_outs > 0 && + err = alc_auto_fill_dacs(codec, cfg->speaker_outs, + cfg->speaker_pins, + spec->multiout.extra_out_nid, + &extra_out_badness); + if (err < 0) + return err; + badness += err; + } + if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); + if (err < 0) + return err; + badness += err; + } + if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + /* try multi-ios with HP + inputs */ + int offset = 0; + if (cfg->line_outs >= 3) + offset = 1; + err = alc_auto_fill_multi_ios(codec, cfg->hp_pins[0], false, + offset); + if (err < 0) + return err; + badness += err; + } + + if (spec->multi_ios == 2) { + for (i = 0; i < 2; i++) + spec->private_dac_nids[spec->multiout.num_dacs++] = + spec->multi_io[i].dac; + spec->ext_channel_count = 2; + } else if (spec->multi_ios) { + spec->multi_ios = 0; + badness += BAD_MULTI_IO; + } + + return badness; +} + +#define DEBUG_BADNESS + +#ifdef DEBUG_BADNESS +#define debug_badness snd_printdd +#else +#define debug_badness(...) +#endif + +static void debug_show_configs(struct alc_spec *spec, struct auto_pin_cfg *cfg) +{ + debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", + cfg->line_out_pins[0], cfg->line_out_pins[1], + cfg->line_out_pins[2], cfg->line_out_pins[2], + spec->multiout.dac_nids[0], + spec->multiout.dac_nids[1], + spec->multiout.dac_nids[2], + spec->multiout.dac_nids[3]); + if (spec->multi_ios > 0) + debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", + spec->multi_ios, + spec->multi_io[0].pin, spec->multi_io[1].pin, + spec->multi_io[0].dac, spec->multi_io[1].dac); + debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", + cfg->hp_pins[0], cfg->hp_pins[1], + cfg->hp_pins[2], cfg->hp_pins[2], + spec->multiout.hp_out_nid[0], + spec->multiout.hp_out_nid[1], + spec->multiout.hp_out_nid[2], + spec->multiout.hp_out_nid[3]); + debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", + cfg->speaker_pins[0], cfg->speaker_pins[1], + cfg->speaker_pins[2], cfg->speaker_pins[3], + spec->multiout.extra_out_nid[0], + spec->multiout.extra_out_nid[1], + spec->multiout.extra_out_nid[2], + spec->multiout.extra_out_nid[3]); +} + +static int alc_auto_fill_dac_nids(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + struct auto_pin_cfg *best_cfg; + int best_badness = INT_MAX; + int badness; + bool fill_hardwired = true, fill_mio_first = true; + bool best_wired = true, best_mio = true; + bool hp_spk_swapped = false; + + best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); + if (!best_cfg) + return -ENOMEM; + *best_cfg = *cfg; + + for (;;) { + badness = fill_and_eval_dacs(codec, fill_hardwired, + fill_mio_first); + if (badness < 0) + return badness; + debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", + cfg->line_out_type, fill_hardwired, fill_mio_first, + badness); + debug_show_configs(spec, cfg); + if (badness < best_badness) { + best_badness = badness; + *best_cfg = *cfg; + best_wired = fill_hardwired; + best_mio = fill_mio_first; + } + if (!badness) + break; + fill_mio_first = !fill_mio_first; + if (!fill_mio_first) + continue; + fill_hardwired = !fill_hardwired; + if (!fill_hardwired) + continue; + if (hp_spk_swapped) + break; + hp_spk_swapped = true; + if (cfg->speaker_outs > 0 && cfg->line_out_type == AUTO_PIN_HP_OUT) { cfg->hp_outs = cfg->line_outs; memcpy(cfg->hp_pins, cfg->line_out_pins, @@ -3125,48 +3435,45 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) cfg->speaker_outs = 0; memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; - redone = false; - goto again; - } + fill_hardwired = true; + continue; + } + if (cfg->hp_outs > 0 && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + cfg->speaker_outs = cfg->line_outs; + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->line_outs = cfg->hp_outs; + memcpy(cfg->line_out_pins, cfg->hp_pins, + sizeof(cfg->hp_pins)); + cfg->hp_outs = 0; + memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); + cfg->line_out_type = AUTO_PIN_HP_OUT; + fill_hardwired = true; + continue; + } + break; } - if (!spec->multi_ios && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->hp_outs) { - /* try multi-ios with HP + inputs */ - defcfg = snd_hda_codec_get_pincfg(codec, cfg->hp_pins[0]); - location = get_defcfg_location(defcfg); - - num_pins = alc_auto_fill_multi_ios(codec, location, 1); - if (num_pins > 0) { - spec->multi_ios = num_pins; - spec->ext_channel_count = 2; - spec->multiout.num_dacs = num_pins + 1; - } + if (badness) { + *cfg = *best_cfg; + fill_and_eval_dacs(codec, best_wired, best_mio); } + debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", + cfg->line_out_type, best_wired, best_mio); + debug_show_configs(spec, cfg); if (cfg->line_out_pins[0]) spec->vmaster_nid = alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0], spec->multiout.dac_nids[0]); - return 0; -} -static inline unsigned int get_ctl_pos(unsigned int data) -{ - hda_nid_t nid = get_amp_nid_(data); - unsigned int dir; - if (snd_BUG_ON(nid >= MAX_VOL_NIDS)) - return 0; - dir = get_amp_direction_(data); - return (nid << 1) | dir; + /* clear the bitmap flags for creating controls */ + clear_vol_marks(codec); + kfree(best_cfg); + return 0; } -#define is_ctl_used(bits, data) \ - test_bit(get_ctl_pos(data), bits) -#define mark_ctl_usage(bits, data) \ - set_bit(get_ctl_pos(data), bits) - static int alc_auto_add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, hda_nid_t nid, unsigned int chs) @@ -3278,14 +3585,17 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, dac = spec->multiout.dac_nids[i]; if (!dac) continue; - if (i >= cfg->line_outs) + if (i >= cfg->line_outs) { pin = spec->multi_io[i - 1].pin; - else + index = 0; + name = channel_name[i]; + } else { pin = cfg->line_out_pins[i]; + name = alc_get_line_out_pfx(spec, i, true, &index); + } sw = alc_look_for_out_mute_nid(codec, pin, dac); vol = alc_look_for_out_vol_nid(codec, pin, dac); - name = alc_get_line_out_pfx(spec, i, true, &index); if (!name || !strcmp(name, "CLFE")) { /* Center/LFE */ err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1); @@ -3382,41 +3692,31 @@ static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins, return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0); } - if (dacs[num_pins - 1]) { - /* OK, we have a multi-output system with individual volumes */ - for (i = 0; i < num_pins; i++) { - if (num_pins >= 3) { - snprintf(name, sizeof(name), "%s %s", - pfx, channel_name[i]); - err = alc_auto_create_extra_out(codec, pins[i], dacs[i], - name, 0); - } else { - err = alc_auto_create_extra_out(codec, pins[i], dacs[i], - pfx, i); - } - if (err < 0) - return err; - } - return 0; - } - - /* Let's create a bind-controls */ - ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw); - if (!ctl) - return -ENOMEM; - n = 0; for (i = 0; i < num_pins; i++) { - if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP) - ctl->values[n++] = - HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT); - } - if (n) { - snprintf(name, sizeof(name), "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl); + hda_nid_t dac; + if (dacs[num_pins - 1]) + dac = dacs[i]; /* with individual volumes */ + else + dac = 0; + if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) { + err = alc_auto_create_extra_out(codec, pins[i], dac, + "Bass Speaker", 0); + } else if (num_pins >= 3) { + snprintf(name, sizeof(name), "%s %s", + pfx, channel_name[i]); + err = alc_auto_create_extra_out(codec, pins[i], dac, + name, 0); + } else { + err = alc_auto_create_extra_out(codec, pins[i], dac, + pfx, i); + } if (err < 0) return err; } + if (dacs[num_pins - 1]) + return 0; + /* Let's create a bind-controls for volumes */ ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol); if (!ctl) return -ENOMEM; @@ -3552,58 +3852,111 @@ static void alc_auto_init_extra_out(struct hda_codec *codec) } } +/* check whether the given pin can be a multi-io pin */ +static bool can_be_multiio_pin(struct hda_codec *codec, + unsigned int location, hda_nid_t nid) +{ + unsigned int defcfg, caps; + + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) + return false; + if (location && get_defcfg_location(defcfg) != location) + return false; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_OUT)) + return false; + return true; +} + /* * multi-io helper + * + * When hardwired is set, try to fill ony hardwired pins, and returns + * zero if any pins are filled, non-zero if nothing found. + * When hardwired is off, try to fill possible input pins, and returns + * the badness value. */ static int alc_auto_fill_multi_ios(struct hda_codec *codec, - unsigned int location, - int offset) + hda_nid_t reference_pin, + bool hardwired, int offset) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t prime_dac = spec->private_dac_nids[0]; - int type, i, dacs, num_pins = 0; + int type, i, j, dacs, num_pins, old_pins; + unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); + unsigned int location = get_defcfg_location(defcfg); + int badness = 0; + + old_pins = spec->multi_ios; + if (old_pins >= 2) + goto end_fill; + + num_pins = 0; + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type != type) + continue; + if (can_be_multiio_pin(codec, location, + cfg->inputs[i].pin)) + num_pins++; + } + } + if (num_pins < 2) + goto end_fill; dacs = spec->multiout.num_dacs; 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 = 0; - 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) + if (!can_be_multiio_pin(codec, location, nid)) continue; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_OUT)) + for (j = 0; j < spec->multi_ios; j++) { + if (nid == spec->multi_io[j].pin) + break; + } + if (j < spec->multi_ios) continue; - if (offset && offset + num_pins < dacs) { - dac = spec->private_dac_nids[offset + num_pins]; + + if (offset && offset + spec->multi_ios < dacs) { + dac = spec->private_dac_nids[offset + spec->multi_ios]; if (!alc_auto_is_dac_reachable(codec, nid, dac)) dac = 0; } - if (!dac) + if (hardwired) + dac = get_dac_if_single(codec, nid); + else if (!dac) dac = alc_auto_look_for_dac(codec, nid); - if (!dac) + if (!dac) { + badness++; 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->multi_io[spec->multi_ios].pin = nid; + spec->multi_io[spec->multi_ios].dac = dac; + spec->multi_ios++; + if (spec->multi_ios >= 2) + break; } } - spec->multiout.num_dacs = dacs; - if (num_pins < 2) { - /* clear up again */ - memset(spec->private_dac_nids + dacs, 0, - sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - dacs)); - spec->private_dac_nids[0] = prime_dac; - return 0; + end_fill: + if (badness) + badness = BAD_MULTI_IO; + if (old_pins == spec->multi_ios) { + if (hardwired) + return 1; /* nothing found */ + else + return badness; /* no badness if nothing found */ + } + if (!hardwired && spec->multi_ios < 2) { + spec->multi_ios = old_pins; + return badness; } - return num_pins; + + return 0; } static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, @@ -3958,6 +4311,7 @@ static const struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), + SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1), SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), {} }; @@ -4057,6 +4411,9 @@ static int alc_parse_auto_config(struct hda_codec *codec, if (spec->kctls.list) add_mixer(spec, spec->kctls.list); + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); + return 1; } @@ -4067,26 +4424,47 @@ static int alc880_parse_auto_config(struct hda_codec *codec) return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids); } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc880_loopbacks[] = { - { 0x0b, HDA_INPUT, 0 }, - { 0x0b, HDA_INPUT, 1 }, - { 0x0b, HDA_INPUT, 2 }, - { 0x0b, HDA_INPUT, 3 }, - { 0x0b, HDA_INPUT, 4 }, - { } /* end */ -}; -#endif - /* * ALC880 fix-ups */ enum { + ALC880_FIXUP_GPIO1, ALC880_FIXUP_GPIO2, ALC880_FIXUP_MEDION_RIM, + ALC880_FIXUP_LG, + ALC880_FIXUP_W810, + ALC880_FIXUP_EAPD_COEF, + ALC880_FIXUP_TCL_S700, + ALC880_FIXUP_VOL_KNOB, + ALC880_FIXUP_FUJITSU, + ALC880_FIXUP_F1734, + ALC880_FIXUP_UNIWILL, + ALC880_FIXUP_UNIWILL_DIG, + ALC880_FIXUP_Z71V, + ALC880_FIXUP_3ST_BASE, + ALC880_FIXUP_3ST, + ALC880_FIXUP_3ST_DIG, + ALC880_FIXUP_5ST_BASE, + ALC880_FIXUP_5ST, + ALC880_FIXUP_5ST_DIG, + ALC880_FIXUP_6ST_BASE, + ALC880_FIXUP_6ST, + ALC880_FIXUP_6ST_DIG, }; +/* enable the volume-knob widget support on NID 0x21 */ +static void alc880_fixup_vol_knob(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + if (action == ALC_FIXUP_ACT_PROBE) + snd_hda_jack_detect_enable(codec, 0x21, ALC_DCVOL_EVENT); +} + static const struct alc_fixup alc880_fixups[] = { + [ALC880_FIXUP_GPIO1] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = alc_gpio1_init_verbs, + }, [ALC880_FIXUP_GPIO2] = { .type = ALC_FIXUP_VERBS, .v.verbs = alc_gpio2_init_verbs, @@ -4101,40 +4479,323 @@ static const struct alc_fixup alc880_fixups[] = { .chained = true, .chain_id = ALC880_FIXUP_GPIO2, }, + [ALC880_FIXUP_LG] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + /* disable bogus unused pins */ + { 0x16, 0x411111f0 }, + { 0x18, 0x411111f0 }, + { 0x1a, 0x411111f0 }, + { } + } + }, + [ALC880_FIXUP_W810] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + /* disable bogus unused pins */ + { 0x17, 0x411111f0 }, + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_GPIO2, + }, + [ALC880_FIXUP_EAPD_COEF] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* change to EAPD mode */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, + {} + }, + }, + [ALC880_FIXUP_TCL_S700] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* change to EAPD mode */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, + {} + }, + .chained = true, + .chain_id = ALC880_FIXUP_GPIO2, + }, + [ALC880_FIXUP_VOL_KNOB] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc880_fixup_vol_knob, + }, + [ALC880_FIXUP_FUJITSU] = { + /* override all pins as BIOS on old Amilo is broken */ + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x0121411f }, /* HP */ + { 0x15, 0x99030120 }, /* speaker */ + { 0x16, 0x99030130 }, /* bass speaker */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x411111f0 }, /* N/A */ + { 0x19, 0x01a19950 }, /* mic-in */ + { 0x1a, 0x411111f0 }, /* N/A */ + { 0x1b, 0x411111f0 }, /* N/A */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0x01454140 }, /* SPDIF out */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_VOL_KNOB, + }, + [ALC880_FIXUP_F1734] = { + /* almost compatible with FUJITSU, but no bass and SPDIF */ + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x0121411f }, /* HP */ + { 0x15, 0x99030120 }, /* speaker */ + { 0x16, 0x411111f0 }, /* N/A */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x411111f0 }, /* N/A */ + { 0x19, 0x01a19950 }, /* mic-in */ + { 0x1a, 0x411111f0 }, /* N/A */ + { 0x1b, 0x411111f0 }, /* N/A */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0x411111f0 }, /* N/A */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_VOL_KNOB, + }, + [ALC880_FIXUP_UNIWILL] = { + /* need to fix HP and speaker pins to be parsed correctly */ + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x0121411f }, /* HP */ + { 0x15, 0x99030120 }, /* speaker */ + { 0x16, 0x99030130 }, /* bass speaker */ + { } + }, + }, + [ALC880_FIXUP_UNIWILL_DIG] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + /* disable bogus unused pins */ + { 0x17, 0x411111f0 }, + { 0x19, 0x411111f0 }, + { 0x1b, 0x411111f0 }, + { 0x1f, 0x411111f0 }, + { } + } + }, + [ALC880_FIXUP_Z71V] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + /* set up the whole pins as BIOS is utterly broken */ + { 0x14, 0x99030120 }, /* speaker */ + { 0x15, 0x0121411f }, /* HP */ + { 0x16, 0x411111f0 }, /* N/A */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x01a19950 }, /* mic-in */ + { 0x19, 0x411111f0 }, /* N/A */ + { 0x1a, 0x01813031 }, /* line-in */ + { 0x1b, 0x411111f0 }, /* N/A */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0x0144111e }, /* SPDIF */ + { } + } + }, + [ALC880_FIXUP_3ST_BASE] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x01014010 }, /* line-out */ + { 0x15, 0x411111f0 }, /* N/A */ + { 0x16, 0x411111f0 }, /* N/A */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x01a19c30 }, /* mic-in */ + { 0x19, 0x0121411f }, /* HP */ + { 0x1a, 0x01813031 }, /* line-in */ + { 0x1b, 0x02a19c40 }, /* front-mic */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + /* 0x1e is filled in below */ + { 0x1f, 0x411111f0 }, /* N/A */ + { } + } + }, + [ALC880_FIXUP_3ST] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x1e, 0x411111f0 }, /* N/A */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_3ST_BASE, + }, + [ALC880_FIXUP_3ST_DIG] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x1e, 0x0144111e }, /* SPDIF */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_3ST_BASE, + }, + [ALC880_FIXUP_5ST_BASE] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x01014010 }, /* front */ + { 0x15, 0x411111f0 }, /* N/A */ + { 0x16, 0x01011411 }, /* CLFE */ + { 0x17, 0x01016412 }, /* surr */ + { 0x18, 0x01a19c30 }, /* mic-in */ + { 0x19, 0x0121411f }, /* HP */ + { 0x1a, 0x01813031 }, /* line-in */ + { 0x1b, 0x02a19c40 }, /* front-mic */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + /* 0x1e is filled in below */ + { 0x1f, 0x411111f0 }, /* N/A */ + { } + } + }, + [ALC880_FIXUP_5ST] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x1e, 0x411111f0 }, /* N/A */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_5ST_BASE, + }, + [ALC880_FIXUP_5ST_DIG] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x1e, 0x0144111e }, /* SPDIF */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_5ST_BASE, + }, + [ALC880_FIXUP_6ST_BASE] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x01014010 }, /* front */ + { 0x15, 0x01016412 }, /* surr */ + { 0x16, 0x01011411 }, /* CLFE */ + { 0x17, 0x01012414 }, /* side */ + { 0x18, 0x01a19c30 }, /* mic-in */ + { 0x19, 0x02a19c40 }, /* front-mic */ + { 0x1a, 0x01813031 }, /* line-in */ + { 0x1b, 0x0121411f }, /* HP */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + /* 0x1e is filled in below */ + { 0x1f, 0x411111f0 }, /* N/A */ + { } + } + }, + [ALC880_FIXUP_6ST] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x1e, 0x411111f0 }, /* N/A */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_6ST_BASE, + }, + [ALC880_FIXUP_6ST_DIG] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x1e, 0x0144111e }, /* SPDIF */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_6ST_BASE, + }, }; static const struct snd_pci_quirk alc880_fixup_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810), + SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), + SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1), + SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2), + SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF), + SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG), + SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734), + SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL), + SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB), + SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), + SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734), + SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), + SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), + SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU), + SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG), + SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG), + SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG), + SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700), + + /* Below is the copied entries from alc880_quirks.c. + * It's not quite sure whether BIOS sets the correct pin-config table + * on these machines, thus they are kept to be compatible with + * the old static quirks. Once when it's confirmed to work without + * these overrides, it'd be better to remove. + */ + SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST), + SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST), + SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST), + SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST), + SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST), + SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST), + SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST), + SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */ + SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG), + SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG), + /* default Intel */ + SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST), + SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG), + SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG), {} }; +static const struct alc_model_fixup alc880_fixup_models[] = { + {.id = ALC880_FIXUP_3ST, .name = "3stack"}, + {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"}, + {.id = ALC880_FIXUP_5ST, .name = "5stack"}, + {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"}, + {.id = ALC880_FIXUP_6ST, .name = "6stack"}, + {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"}, + {} +}; -/* - * board setups - */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#define alc_board_config \ - snd_hda_check_board_config -#define alc_board_codec_sid_config \ - snd_hda_check_board_codec_sid_config -#include "alc_quirks.c" -#else -#define alc_board_config(codec, nums, models, tbl) -1 -#define alc_board_codec_sid_config(codec, nums, models, tbl) -1 -#define setup_preset(codec, x) /* NOP */ -#endif /* * OK, here we have finally the patch for ALC880 */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc880_quirks.c" -#endif - static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; - int board_config; int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -4146,47 +4807,14 @@ static int patch_alc880(struct hda_codec *codec) spec->mixer_nid = 0x0b; spec->need_dac_fix = 1; - board_config = alc_board_config(codec, ALC880_MODEL_LAST, - alc880_models, alc880_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } - - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc880_fixup_tbl, alc880_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } - - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc880_parse_auto_config(codec); - if (err < 0) - goto error; -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using 3-stack mode...\n"); - board_config = ALC880_3ST; - } -#endif - } - - if (board_config != ALC_MODEL_AUTO) { - spec->vmaster_nid = 0x0c; - setup_preset(codec, &alc880_presets[board_config]); - } - - if (!spec->no_analog && !spec->adc_nids) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } + alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, + alc880_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + /* automatic parse from the BIOS config */ + err = alc880_parse_auto_config(codec); + if (err < 0) + goto error; if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); @@ -4195,17 +4823,9 @@ static int patch_alc880(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - else - codec->patch_ops.build_controls = __alc_build_controls; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc880_loopbacks; -#endif + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); return 0; @@ -4225,49 +4845,115 @@ static int alc260_parse_auto_config(struct hda_codec *codec) return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids); } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc260_loopbacks[] = { - { 0x07, HDA_INPUT, 0 }, - { 0x07, HDA_INPUT, 1 }, - { 0x07, HDA_INPUT, 2 }, - { 0x07, HDA_INPUT, 3 }, - { 0x07, HDA_INPUT, 4 }, - { } /* end */ -}; -#endif - /* * Pin config fixes */ enum { - PINFIX_HP_DC5750, + ALC260_FIXUP_HP_DC5750, + ALC260_FIXUP_HP_PIN_0F, + ALC260_FIXUP_COEF, + ALC260_FIXUP_GPIO1, + ALC260_FIXUP_GPIO1_TOGGLE, + ALC260_FIXUP_REPLACER, + ALC260_FIXUP_HP_B1900, }; +static void alc260_gpio1_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->hp_jack_present); +} + +static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action == ALC_FIXUP_ACT_PROBE) { + /* although the machine has only one output pin, we need to + * toggle GPIO1 according to the jack state + */ + spec->automute_hook = alc260_gpio1_automute; + spec->detect_hp = 1; + spec->automute_speaker = 1; + spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ + snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT); + spec->unsol_event = alc_sku_unsol_event; + add_verb(codec->spec, alc_gpio1_init_verbs); + } +} + static const struct alc_fixup alc260_fixups[] = { - [PINFIX_HP_DC5750] = { + [ALC260_FIXUP_HP_DC5750] = { .type = ALC_FIXUP_PINS, .v.pins = (const struct alc_pincfg[]) { { 0x11, 0x90130110 }, /* speaker */ { } } }, + [ALC260_FIXUP_HP_PIN_0F] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x0f, 0x01214000 }, /* HP */ + { } + } + }, + [ALC260_FIXUP_COEF] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3040 }, + { } + }, + .chained = true, + .chain_id = ALC260_FIXUP_HP_PIN_0F, + }, + [ALC260_FIXUP_GPIO1] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = alc_gpio1_init_verbs, + }, + [ALC260_FIXUP_GPIO1_TOGGLE] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc260_fixup_gpio1_toggle, + .chained = true, + .chain_id = ALC260_FIXUP_HP_PIN_0F, + }, + [ALC260_FIXUP_REPLACER] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, + { } + }, + .chained = true, + .chain_id = ALC260_FIXUP_GPIO1_TOGGLE, + }, + [ALC260_FIXUP_HP_B1900] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc260_fixup_gpio1_toggle, + .chained = true, + .chain_id = ALC260_FIXUP_COEF, + } }; static const struct snd_pci_quirk alc260_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), + SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1), + SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF), + SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1), + SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750), + SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900), + SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1), + SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER), + SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF), {} }; /* */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc260_quirks.c" -#endif - static int patch_alc260(struct hda_codec *codec) { struct alc_spec *spec; - int err, board_config; + int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -4277,47 +4963,13 @@ static int patch_alc260(struct hda_codec *codec) spec->mixer_nid = 0x07; - board_config = alc_board_config(codec, ALC260_MODEL_LAST, - alc260_models, alc260_cfg_tbl); - if (board_config < 0) { - snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } - - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } - - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc260_parse_auto_config(codec); - if (err < 0) - goto error; -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS - else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC260_BASIC; - } -#endif - } - - if (board_config != ALC_MODEL_AUTO) { - setup_preset(codec, &alc260_presets[board_config]); - spec->vmaster_nid = 0x08; - } - - if (!spec->no_analog && !spec->adc_nids) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } + alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + /* automatic parse from the BIOS config */ + err = alc260_parse_auto_config(codec); + if (err < 0) + goto error; if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); @@ -4326,18 +4978,10 @@ static int patch_alc260(struct hda_codec *codec) set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); } - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - else - codec->patch_ops.build_controls = __alc_build_controls; spec->shutup = alc_eapd_shutup; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc260_loopbacks; -#endif + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); return 0; @@ -4358,9 +5002,6 @@ static int patch_alc260(struct hda_codec *codec) * In addition, an independent DAC for the multi-playback (not used in this * driver yet). */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc882_loopbacks alc880_loopbacks -#endif /* * Pin config fixes @@ -4377,6 +5018,8 @@ enum { ALC882_FIXUP_EAPD, ALC883_FIXUP_EAPD, ALC883_FIXUP_ACER_EAPD, + ALC882_FIXUP_GPIO1, + ALC882_FIXUP_GPIO2, ALC882_FIXUP_GPIO3, ALC889_FIXUP_COEF, ALC882_FIXUP_ASUS_W2JC, @@ -4385,6 +5028,8 @@ enum { ALC882_FIXUP_ASPIRE_8930G_VERBS, ALC885_FIXUP_MACPRO_GPIO, ALC889_FIXUP_DAC_ROUTE, + ALC889_FIXUP_MBP_VREF, + ALC889_FIXUP_IMAC91_VREF, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -4463,6 +5108,51 @@ static void alc889_fixup_dac_route(struct hda_codec *codec, } } +/* Set VREF on HP pin */ +static void alc889_fixup_mbp_vref(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static hda_nid_t nids[2] = { 0x14, 0x15 }; + int i; + + if (action != ALC_FIXUP_ACT_INIT) + return; + for (i = 0; i < ARRAY_SIZE(nids); i++) { + unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]); + if (get_defcfg_device(val) != AC_JACK_HP_OUT) + continue; + val = snd_hda_codec_read(codec, nids[i], 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + val |= AC_PINCTL_VREF_80; + snd_hda_codec_write(codec, nids[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, val); + spec->keep_vref_in_automute = 1; + break; + } +} + +/* Set VREF on speaker pins on imac91 */ +static void alc889_fixup_imac91_vref(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static hda_nid_t nids[2] = { 0x18, 0x1a }; + int i; + + if (action != ALC_FIXUP_ACT_INIT) + return; + for (i = 0; i < ARRAY_SIZE(nids); i++) { + unsigned int val; + val = snd_hda_codec_read(codec, nids[i], 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + val |= AC_PINCTL_VREF_50; + snd_hda_codec_write(codec, nids[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, val); + } + spec->keep_vref_in_automute = 1; +} + static const struct alc_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { .type = ALC_FIXUP_PINS, @@ -4548,6 +5238,14 @@ static const struct alc_fixup alc882_fixups[] = { { } } }, + [ALC882_FIXUP_GPIO1] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = alc_gpio1_init_verbs, + }, + [ALC882_FIXUP_GPIO2] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = alc_gpio2_init_verbs, + }, [ALC882_FIXUP_GPIO3] = { .type = ALC_FIXUP_VERBS, .v.verbs = alc_gpio3_init_verbs, @@ -4621,6 +5319,18 @@ static const struct alc_fixup alc882_fixups[] = { .type = ALC_FIXUP_FUNC, .v.func = alc889_fixup_dac_route, }, + [ALC889_FIXUP_MBP_VREF] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc889_fixup_mbp_vref, + .chained = true, + .chain_id = ALC882_FIXUP_GPIO1, + }, + [ALC889_FIXUP_IMAC91_VREF] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc889_fixup_imac91_vref, + .chained = true, + .chain_id = ALC882_FIXUP_GPIO1, + }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -4654,11 +5364,26 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), /* All Apple entries are in codec SSIDs */ + SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO), SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO), SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD), + SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), @@ -4684,14 +5409,10 @@ static int alc882_parse_auto_config(struct hda_codec *codec) /* */ -#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS -#include "alc882_quirks.c" -#endif - static int patch_alc882(struct hda_codec *codec) { struct alc_spec *spec; - int err, board_config; + int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -4715,45 +5436,15 @@ static int patch_alc882(struct hda_codec *codec) if (err < 0) goto error; - board_config = alc_board_config(codec, ALC882_MODEL_LAST, - alc882_models, NULL); - if (board_config < 0) - board_config = alc_board_codec_sid_config(codec, - ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl); - - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = ALC_MODEL_AUTO; - } - - if (board_config == ALC_MODEL_AUTO) { - alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } + alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); - if (board_config == ALC_MODEL_AUTO) { - /* automatic parse from the BIOS config */ - err = alc882_parse_auto_config(codec); - if (err < 0) - goto error; - } - - if (board_config != ALC_MODEL_AUTO) { - setup_preset(codec, &alc882_presets[board_config]); - spec->vmaster_nid = 0x0c; - } - - if (!spec->no_analog && !spec->adc_nids) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } - - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + /* automatic parse from the BIOS config */ + err = alc882_parse_auto_config(codec); + if (err < 0) + goto error; if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); @@ -4762,18 +5453,9 @@ static int patch_alc882(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - codec->patch_ops = alc_patch_ops; - if (board_config == ALC_MODEL_AUTO) - spec->init_hook = alc_auto_init_std; - else - codec->patch_ops.build_controls = __alc_build_controls; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc882_loopbacks; -#endif + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); return 0; @@ -4869,10 +5551,6 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = { }; -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc262_loopbacks alc880_loopbacks -#endif - /* */ static int patch_alc262(struct hda_codec *codec) @@ -4912,15 +5590,6 @@ static int patch_alc262(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && !spec->adc_nids) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } - - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); - if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) @@ -4928,16 +5597,10 @@ static int patch_alc262(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc262_loopbacks; -#endif + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); return 0; @@ -5031,17 +5694,7 @@ static int patch_alc268(struct hda_codec *codec) (0 << AC_AMPCAP_MUTE_SHIFT)); } - if (!spec->no_analog && !spec->adc_nids) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } - - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); - codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; return 0; @@ -5054,10 +5707,6 @@ static int patch_alc268(struct hda_codec *codec) /* * ALC269 */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc269_loopbacks alc880_loopbacks -#endif - static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -5079,35 +5728,6 @@ static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = { /* NID is set in alc_build_pcms */ }; -#ifdef CONFIG_SND_HDA_POWER_SAVE -static int alc269_mic2_for_mute_led(struct hda_codec *codec) -{ - switch (codec->subsystem_id) { - case 0x103c1586: - return 1; - } - return 0; -} - -static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) -{ - /* update mute-LED according to the speaker mute state */ - if (nid == 0x01 || nid == 0x14) { - int pinval; - if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) & - HDA_AMP_MUTE) - pinval = 0x24; - else - pinval = 0x20; - /* mic2 vref pin is used for mute LED control */ - snd_hda_codec_update_cache(codec, 0x19, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinval); - } - return alc_check_power_status(codec, nid); -} -#endif /* CONFIG_SND_HDA_POWER_SAVE */ - /* different alc269-variants */ enum { ALC269_TYPE_ALC269VA, @@ -5258,6 +5878,31 @@ static void alc269_fixup_quanta_mute(struct hda_codec *codec, spec->automute_hook = alc269_quanta_automute; } +/* update mute-LED according to the speaker mute state via mic2 VREF pin */ +static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled) +{ + struct hda_codec *codec = private_data; + unsigned int pinval = enabled ? 0x20 : 0x24; + snd_hda_codec_update_cache(codec, 0x19, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinval); +} + +static void alc269_fixup_mic2_mute(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + switch (action) { + case ALC_FIXUP_ACT_BUILD: + spec->vmaster_mute.hook = alc269_fixup_mic2_mute_hook; + snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true); + /* fallthru */ + case ALC_FIXUP_ACT_INIT: + snd_hda_sync_vmaster_hook(&spec->vmaster_mute); + break; + } +} + enum { ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, @@ -5275,6 +5920,7 @@ enum { ALC269_FIXUP_DMIC, ALC269VB_FIXUP_AMIC, ALC269VB_FIXUP_DMIC, + ALC269_FIXUP_MIC2_MUTE_LED, }; static const struct alc_fixup alc269_fixups[] = { @@ -5395,9 +6041,14 @@ static const struct alc_fixup alc269_fixups[] = { { } }, }, + [ALC269_FIXUP_MIC2_MUTE_LED] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc269_fixup_mic2_mute, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), @@ -5420,7 +6071,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), -#if 1 +#if 0 /* Below is a quirk table taken from the old code. * Basically the device should work as is without the fixup table. * If BIOS doesn't give a proper info, enable the corresponding @@ -5478,13 +6129,13 @@ static const struct alc_model_fixup alc269_fixup_models[] = { }; -static int alc269_fill_coef(struct hda_codec *codec) +static void alc269_fill_coef(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int val; if (spec->codec_variant != ALC269_TYPE_ALC269VB) - return 0; + return; if ((alc_get_coef0(codec) & 0x00ff) < 0x015) { alc_write_coef_idx(codec, 0xf, 0x960b); @@ -5520,8 +6171,6 @@ static int alc269_fill_coef(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0x4); /* HP */ alc_write_coef_idx(codec, 0x4, val | (1<<11)); - - return 0; } /* @@ -5565,6 +6214,7 @@ static int patch_alc269(struct hda_codec *codec) } if (err < 0) goto error; + spec->init_hook = alc269_fill_coef; alc269_fill_coef(codec); } @@ -5577,15 +6227,6 @@ static int patch_alc269(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && !spec->adc_nids) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } - - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); - if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) @@ -5593,21 +6234,13 @@ static int patch_alc269(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); } - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - codec->patch_ops = alc_patch_ops; #ifdef CONFIG_PM codec->patch_ops.resume = alc269_resume; #endif - spec->init_hook = alc_auto_init_std; spec->shutup = alc269_shutup; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc269_loopbacks; - if (alc269_mic2_for_mute_led(codec)) - codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps; -#endif + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); return 0; @@ -5627,21 +6260,12 @@ static int alc861_parse_auto_config(struct hda_codec *codec) return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids); } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static const struct hda_amp_list alc861_loopbacks[] = { - { 0x15, HDA_INPUT, 0 }, - { 0x15, HDA_INPUT, 1 }, - { 0x15, HDA_INPUT, 2 }, - { 0x15, HDA_INPUT, 3 }, - { } /* end */ -}; -#endif - - /* Pin config fixes */ enum { - PINFIX_FSC_AMILO_PI1505, - PINFIX_ASUS_A6RP, + ALC861_FIXUP_FSC_AMILO_PI1505, + ALC861_FIXUP_AMP_VREF_0F, + ALC861_FIXUP_NO_JACK_DETECT, + ALC861_FIXUP_ASUS_A6RP, }; /* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */ @@ -5663,8 +6287,16 @@ static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec, spec->keep_vref_in_automute = 1; } +/* suppress the jack-detection */ +static void alc_fixup_no_jack_detect(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + if (action == ALC_FIXUP_ACT_PRE_PROBE) + codec->no_jack_detect = 1; +} + static const struct alc_fixup alc861_fixups[] = { - [PINFIX_FSC_AMILO_PI1505] = { + [ALC861_FIXUP_FSC_AMILO_PI1505] = { .type = ALC_FIXUP_PINS, .v.pins = (const struct alc_pincfg[]) { { 0x0b, 0x0221101f }, /* HP */ @@ -5672,17 +6304,29 @@ static const struct alc_fixup alc861_fixups[] = { { } } }, - [PINFIX_ASUS_A6RP] = { + [ALC861_FIXUP_AMP_VREF_0F] = { .type = ALC_FIXUP_FUNC, .v.func = alc861_fixup_asus_amp_vref_0f, }, + [ALC861_FIXUP_NO_JACK_DETECT] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc_fixup_no_jack_detect, + }, + [ALC861_FIXUP_ASUS_A6RP] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc861_fixup_asus_amp_vref_0f, + .chained = true, + .chain_id = ALC861_FIXUP_NO_JACK_DETECT, + } }; static const struct snd_pci_quirk alc861_fixup_tbl[] = { - SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", PINFIX_ASUS_A6RP), - SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", PINFIX_ASUS_A6RP), - SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", PINFIX_ASUS_A6RP), - SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), + SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), + SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F), + SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT), + SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", ALC861_FIXUP_AMP_VREF_0F), + SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", ALC861_FIXUP_AMP_VREF_0F), + SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505), {} }; @@ -5709,15 +6353,6 @@ static int patch_alc861(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && !spec->adc_nids) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } - - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); - if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); if (err < 0) @@ -5725,16 +6360,13 @@ static int patch_alc861(struct hda_codec *codec) set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); } - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->power_hook = alc_power_eapd; - if (!spec->loopback.amplist) - spec->loopback.amplist = alc861_loopbacks; #endif + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + return 0; error: @@ -5749,10 +6381,6 @@ static int patch_alc861(struct hda_codec *codec) * * In addition, an independent DAC */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc861vd_loopbacks alc880_loopbacks -#endif - static int alc861vd_parse_auto_config(struct hda_codec *codec) { static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; @@ -5833,15 +6461,6 @@ static int patch_alc861vd(struct hda_codec *codec) add_verb(spec, alc660vd_eapd_verbs); } - if (!spec->no_analog && !spec->adc_nids) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } - - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); - if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); if (err < 0) @@ -5849,16 +6468,11 @@ static int patch_alc861vd(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc861vd_loopbacks; -#endif + + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); return 0; @@ -5878,9 +6492,6 @@ static int patch_alc861vd(struct hda_codec *codec) * In addition, an independent DAC for the multi-playback (not used in this * driver yet). */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc662_loopbacks alc880_loopbacks -#endif /* * BIOS auto configuration @@ -5930,6 +6541,7 @@ enum { ALC662_FIXUP_ASUS_MODE6, ALC662_FIXUP_ASUS_MODE7, ALC662_FIXUP_ASUS_MODE8, + ALC662_FIXUP_NO_JACK_DETECT, }; static const struct alc_fixup alc662_fixups[] = { @@ -6075,6 +6687,10 @@ static const struct alc_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC662_FIXUP_SKU_IGNORE }, + [ALC662_FIXUP_NO_JACK_DETECT] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc_fixup_no_jack_detect, + }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -6083,6 +6699,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { 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(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), + SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), @@ -6204,15 +6821,6 @@ static int patch_alc662(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && !spec->adc_nids) { - alc_auto_fill_adc_caps(codec); - alc_rebuild_imux_for_auto_mic(codec); - alc_remove_invalid_adc_nids(codec); - } - - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); - if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) @@ -6232,16 +6840,10 @@ static int patch_alc662(struct hda_codec *codec) } } - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc662_loopbacks; -#endif + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); return 0; @@ -6281,11 +6883,7 @@ static int patch_alc680(struct hda_codec *codec) return err; } - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); - codec->patch_ops = alc_patch_ops; - spec->init_hook = alc_auto_init_std; return 0; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9dbb5735d77..33a9946b492 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -99,6 +99,7 @@ enum { STAC_DELL_VOSTRO_3500, STAC_92HD83XXX_HP_cNB11_INTQUAD, STAC_HP_DV7_4000, + STAC_HP_ZEPHYR, STAC_92HD83XXX_MODELS }; @@ -309,6 +310,8 @@ struct sigmatel_spec { unsigned long auto_capvols[MAX_ADCS_NUM]; unsigned auto_dmic_cnt; hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; + + struct hda_vmaster_mute_hook vmaster_mute; }; static const hda_nid_t stac9200_adc_nids[1] = { @@ -662,7 +665,6 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, return 0; } -#ifdef CONFIG_SND_HDA_POWER_SAVE static int stac_vrefout_set(struct hda_codec *codec, hda_nid_t nid, unsigned int new_vref) { @@ -686,7 +688,6 @@ static int stac_vrefout_set(struct hda_codec *codec, return 1; } -#endif static unsigned int stac92xx_vref_set(struct hda_codec *codec, hda_nid_t nid, unsigned int new_vref) @@ -894,6 +895,13 @@ static const struct hda_verb stac92hd83xxx_core_init[] = { {} }; +static const struct hda_verb stac92hd83xxx_hp_zephyr_init[] = { + { 0x22, 0x785, 0x43 }, + { 0x22, 0x782, 0xe0 }, + { 0x22, 0x795, 0x00 }, + {} +}; + static const struct hda_verb stac92hd71bxx_core_init[] = { /* set master volume and direct control */ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, @@ -999,8 +1007,8 @@ static const struct hda_verb stac9205_core_init[] = { } 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_MIN_MUTE("PCM Playback Volume", 0xb, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0xb, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), { } /* end */ @@ -1027,8 +1035,8 @@ static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = { }; 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), + HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xe, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x0e, 0, HDA_OUTPUT), { } /* end */ }; @@ -1060,34 +1068,25 @@ static struct snd_kcontrol_new stac_smux_mixer = { .put = stac92xx_smux_enum_put, }; -static const char * const slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "Headphone Playback Volume", - "Speaker Playback Volume", +static const char * const slave_pfxs[] = { + "Front", "Surround", "Center", "LFE", "Side", + "Headphone", "Speaker", "IEC958", NULL }; -static const char * const slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "Headphone Playback Switch", - "Speaker Playback Switch", - "IEC958 Playback Switch", - NULL -}; +static void stac92xx_update_led_status(struct hda_codec *codec, int enabled); + +static void stac92xx_vmaster_hook(void *private_data, int val) +{ + stac92xx_update_led_status(private_data, val); +} static void stac92xx_free_kctls(struct hda_codec *codec); static int stac92xx_build_controls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; + unsigned int vmaster_tlv[4]; int err; int i; @@ -1144,22 +1143,28 @@ static int stac92xx_build_controls(struct hda_codec *codec) } /* if we have no master control, let's create it */ - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], - HDA_OUTPUT, vmaster_tlv); - /* correct volume offset */ - vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; - /* minimum value is actually mute */ - vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_vols); - if (err < 0) - return err; - } - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_sws); + snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], + HDA_OUTPUT, vmaster_tlv); + /* correct volume offset */ + vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; + /* minimum value is actually mute */ + vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; + err = snd_hda_add_vmaster(codec, "Master Playback Volume", + vmaster_tlv, slave_pfxs, + "Playback Volume"); + if (err < 0) + return err; + + err = __snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, slave_pfxs, + "Playback Switch", true, + &spec->vmaster_mute.sw_kctl); + if (err < 0) + return err; + + if (spec->gpio_led) { + spec->vmaster_mute.hook = stac92xx_vmaster_hook; + err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true); if (err < 0) return err; } @@ -1636,6 +1641,12 @@ static const unsigned int hp_dv7_4000_pin_configs[10] = { 0x40f000f0, 0x40f000f0, }; +static const unsigned int hp_zephyr_pin_configs[10] = { + 0x01813050, 0x0421201f, 0x04a1205e, 0x96130310, + 0x96130310, 0x0101401f, 0x1111611f, 0xd5a30130, + 0, 0, +}; + static const unsigned int hp_cNB11_intquad_pin_configs[10] = { 0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110, 0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130, @@ -1649,6 +1660,7 @@ static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs, [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs, [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, + [STAC_HP_ZEPHYR] = hp_zephyr_pin_configs, }; static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { @@ -1659,6 +1671,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500", [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad", [STAC_HP_DV7_4000] = "hp-dv7-4000", + [STAC_HP_ZEPHYR] = "hp-zephyr", }; static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -1711,6 +1724,14 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561, + "HP", STAC_HP_ZEPHYR), + {} /* terminator */ +}; + +static const struct snd_pci_quirk stac92hd83xxx_codec_id_cfg_tbl[] = { + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561, + "HP", STAC_HP_ZEPHYR), {} /* terminator */ }; @@ -4410,8 +4431,7 @@ static int stac92xx_init(struct hda_codec *codec) snd_hda_jack_report_sync(codec); /* sync mute LED */ - if (spec->gpio_led) - hda_call_check_power_status(codec, 0x01); + snd_hda_sync_vmaster_hook(&spec->vmaster_mute); if (spec->dac_list) stac92xx_power_down(codec); return 0; @@ -4989,7 +5009,6 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) return 0; } -#ifdef CONFIG_SND_HDA_POWER_SAVE static int stac92xx_pre_resume(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -5024,82 +5043,40 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg, afg_power_state); snd_hda_codec_set_power_to_all(codec, fg, power_state, true); } +#else +#define stac92xx_suspend NULL +#define stac92xx_resume NULL +#define stac92xx_pre_resume NULL +#define stac92xx_set_power_state NULL +#endif /* CONFIG_PM */ -/* - * For this feature CONFIG_SND_HDA_POWER_SAVE is needed - * as mute LED state is updated in check_power_status hook - */ -static int stac92xx_update_led_status(struct hda_codec *codec) +/* update mute-LED accoring to the master switch */ +static void stac92xx_update_led_status(struct hda_codec *codec, int enabled) { struct sigmatel_spec *spec = codec->spec; - int i, num_ext_dacs, muted = 1; - unsigned int muted_lvl, notmtd_lvl; - hda_nid_t nid; + int muted = !enabled; if (!spec->gpio_led) - return 0; + return; + + /* LED state is inverted on these systems */ + if (spec->gpio_led_polarity) + muted = !muted; - for (i = 0; i < spec->multiout.num_dacs; i++) { - nid = spec->multiout.dac_nids[i]; - if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & - HDA_AMP_MUTE)) { - muted = 0; /* something heard */ - break; - } - } - if (muted && spec->multiout.hp_nid) - if (!(snd_hda_codec_amp_read(codec, - spec->multiout.hp_nid, 0, HDA_OUTPUT, 0) & - HDA_AMP_MUTE)) { - muted = 0; /* HP is not muted */ - } - num_ext_dacs = ARRAY_SIZE(spec->multiout.extra_out_nid); - for (i = 0; muted && i < num_ext_dacs; i++) { - nid = spec->multiout.extra_out_nid[i]; - if (nid == 0) - break; - if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & - HDA_AMP_MUTE)) { - muted = 0; /* extra output is not muted */ - } - } /*polarity defines *not* muted state level*/ if (!spec->vref_mute_led_nid) { if (muted) spec->gpio_data &= ~spec->gpio_led; /* orange */ else spec->gpio_data |= spec->gpio_led; /* white */ - - if (!spec->gpio_led_polarity) { - /* LED state is inverted on these systems */ - spec->gpio_data ^= spec->gpio_led; - } stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); } else { - notmtd_lvl = spec->gpio_led_polarity ? - AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD; - muted_lvl = spec->gpio_led_polarity ? - AC_PINCTL_VREF_GRD : AC_PINCTL_VREF_50; - spec->vref_led = muted ? muted_lvl : notmtd_lvl; + spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD; stac_vrefout_set(codec, spec->vref_mute_led_nid, spec->vref_led); } - return 0; -} - -/* - * use power check for controlling mute led of HP notebooks - */ -static int stac92xx_check_power_status(struct hda_codec *codec, - hda_nid_t nid) -{ - stac92xx_update_led_status(codec); - - return 0; } -#endif /* CONFIG_SND_HDA_POWER_SAVE */ -#endif /* CONFIG_PM */ static const struct hda_codec_ops stac92xx_patch_ops = { .build_controls = stac92xx_build_controls, @@ -5580,6 +5557,12 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) STAC_92HD83XXX_MODELS, stac92hd83xxx_models, stac92hd83xxx_cfg_tbl); + /* check codec subsystem id if not found */ + if (spec->board_config < 0) + spec->board_config = + snd_hda_check_board_codec_sid_config(codec, + STAC_92HD83XXX_MODELS, stac92hd83xxx_models, + stac92hd83xxx_codec_id_cfg_tbl); again: if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", @@ -5590,12 +5573,17 @@ again: codec->patch_ops = stac92xx_patch_ops; + switch (spec->board_config) { + case STAC_HP_ZEPHYR: + spec->init = stac92hd83xxx_hp_zephyr_init; + break; + } + if (find_mute_led_cfg(codec, -1/*no default cfg*/)) snd_printd("mute LED gpio %d polarity %d\n", spec->gpio_led, spec->gpio_led_polarity); -#ifdef CONFIG_SND_HDA_POWER_SAVE if (spec->gpio_led) { if (!spec->vref_mute_led_nid) { spec->gpio_mask |= spec->gpio_led; @@ -5605,11 +5593,10 @@ again: codec->patch_ops.set_power_state = stac92xx_set_power_state; } +#ifdef CONFIG_PM codec->patch_ops.pre_resume = stac92xx_pre_resume; - codec->patch_ops.check_power_status = - stac92xx_check_power_status; +#endif } -#endif err = stac92xx_parse_auto_config(codec); if (!err) { @@ -5906,7 +5893,6 @@ again: spec->gpio_led, spec->gpio_led_polarity); -#ifdef CONFIG_SND_HDA_POWER_SAVE if (spec->gpio_led) { if (!spec->vref_mute_led_nid) { spec->gpio_mask |= spec->gpio_led; @@ -5916,11 +5902,10 @@ again: codec->patch_ops.set_power_state = stac92xx_set_power_state; } +#ifdef CONFIG_PM codec->patch_ops.pre_resume = stac92xx_pre_resume; - codec->patch_ops.check_power_status = - stac92xx_check_power_status; +#endif } -#endif spec->multiout.dac_nids = spec->dac_nids; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index dff9a00ee8f..06214fdc948 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -550,7 +550,10 @@ static void via_auto_init_output(struct hda_codec *codec, pin = path->path[path->depth - 1]; init_output_pin(codec, pin, pin_type); - caps = query_amp_caps(codec, pin, HDA_OUTPUT); + if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) + caps = query_amp_caps(codec, pin, HDA_OUTPUT); + else + caps = 0; if (caps & AC_AMPCAP_MUTE) { unsigned int val; val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; @@ -645,6 +648,10 @@ static void via_auto_init_analog_input(struct hda_codec *codec) /* init ADCs */ 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) || + !(query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)) + continue; snd_hda_codec_write(codec, spec->adc_nids[i], 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)); @@ -1445,25 +1452,9 @@ static const struct hda_pcm_stream via_pcm_digital_capture = { /* * slave controls for virtual master */ -static const char * const via_slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "Headphone Playback Volume", - "Speaker Playback Volume", - NULL, -}; - -static const char * const via_slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "Headphone Playback Switch", - "Speaker Playback Switch", +static const char * const via_slave_pfxs[] = { + "Front", "Surround", "Center", "LFE", "Side", + "Headphone", "Speaker", NULL, }; @@ -1508,13 +1499,15 @@ static int via_build_controls(struct hda_codec *codec) snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], HDA_OUTPUT, vmaster_tlv); err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, via_slave_vols); + vmaster_tlv, via_slave_pfxs, + "Playback Volume"); if (err < 0) return err; } if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, via_slave_sws); + NULL, via_slave_pfxs, + "Playback Switch"); if (err < 0) return err; } @@ -1522,6 +1515,8 @@ static int via_build_controls(struct hda_codec *codec) /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); for (i = 0; kctl && i < kctl->count; i++) { + if (!spec->mux_nids[i]) + continue; err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]); if (err < 0) return err; @@ -2488,6 +2483,8 @@ static int create_mic_boost_ctls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; const struct auto_pin_cfg *cfg = &spec->autocfg; + const char *prev_label = NULL; + int type_idx = 0; int i, err; for (i = 0; i < cfg->num_inputs; i++) { @@ -2502,8 +2499,13 @@ static int create_mic_boost_ctls(struct hda_codec *codec) if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS)) continue; label = hda_get_autocfg_input_label(codec, cfg, i); + if (prev_label && !strcmp(label, prev_label)) + type_idx++; + else + type_idx = 0; + prev_label = label; snprintf(name, sizeof(name), "%s Boost Volume", label); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx, HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT)); if (err < 0) return err; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 92362973764..812d10e43ae 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -1013,6 +1013,25 @@ static int set_rate_constraints(struct snd_ice1712 *ice, ice->hw_rates); } +/* if the card has the internal rate locked (is_pro_locked), limit runtime + hw rates to the current internal rate only. +*/ +static void constrain_rate_if_locked(struct snd_pcm_substream *substream) +{ + struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int rate; + if (is_pro_rate_locked(ice)) { + rate = ice->get_rate(ice); + if (rate >= runtime->hw.rate_min + && rate <= runtime->hw.rate_max) { + runtime->hw.rate_min = rate; + runtime->hw.rate_max = rate; + } + } +} + + /* multi-channel playback needs alignment 8x32bit regardless of the channels * actually used */ @@ -1046,6 +1065,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + constrain_rate_if_locked(substream); if (ice->pro_open) ice->pro_open(ice, substream); return 0; @@ -1066,6 +1086,7 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + constrain_rate_if_locked(substream); if (ice->pro_open) ice->pro_open(ice, substream); return 0; @@ -1215,6 +1236,7 @@ static int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + constrain_rate_if_locked(substream); if (ice->spdif.ops.open) ice->spdif.ops.open(ice, substream); return 0; @@ -1251,6 +1273,7 @@ static int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + constrain_rate_if_locked(substream); if (ice->spdif.ops.open) ice->spdif.ops.open(ice, substream); return 0; diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 12a9a2b0338..a8159b81e9c 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -2317,6 +2317,10 @@ int snd_ymfpci_suspend(struct pci_dev *pci, pm_message_t state) for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); + pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, + &chip->saved_dsxg_legacy); + pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY, + &chip->saved_dsxg_elegacy); snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); snd_ymfpci_disable_dsp(chip); @@ -2351,6 +2355,11 @@ int snd_ymfpci_resume(struct pci_dev *pci) snd_ac97_resume(chip->ac97); + pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, + chip->saved_dsxg_legacy); + pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, + chip->saved_dsxg_elegacy); + /* start hw again */ if (chip->start_count > 0) { spin_lock_irq(&chip->reg_lock); diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 35e662d270e..91c985599d3 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -25,6 +25,9 @@ if SND_SOC config SND_SOC_AC97_BUS bool +config SND_SOC_DMAENGINE_PCM + bool + # All the supported SoCs source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 9ea8ac827ad..2feaf376e94 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,6 +1,9 @@ snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o snd-soc-core-objs += soc-pcm.o soc-io.o +snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o +obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o + obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += atmel/ diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index a21ff459e5d..9b84f985770 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -362,7 +362,7 @@ static struct snd_pcm_ops atmel_pcm_ops = { /*--------------------------------------------------------------------------*\ * ASoC platform driver \*--------------------------------------------------------------------------*/ -static u64 atmel_pcm_dmamask = 0xffffffff; +static u64 atmel_pcm_dmamask = DMA_BIT_MASK(32); static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) { @@ -373,7 +373,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!card->dev->dma_mask) card->dev->dma_mask = &atmel_pcm_dmamask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = atmel_pcm_preallocate_dma_buffer(pcm, diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c index 4ca667d477f..f65f08beac3 100644 --- a/sound/soc/atmel/snd-soc-afeb9260.c +++ b/sound/soc/atmel/snd-soc-afeb9260.c @@ -46,29 +46,8 @@ static int afeb9260_hw_params(struct snd_pcm_substream *substream, { 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 err; - /* Set codec DAI configuration */ - err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S| - SND_SOC_DAIFMT_NB_IF | - SND_SOC_DAIFMT_CBM_CFM); - if (err < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return err; - } - - /* Set cpu DAI configuration */ - err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_IF | - SND_SOC_DAIFMT_CBM_CFM); - if (err < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return err; - } - /* Set the codec system clock for DAC and ADC */ err = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); @@ -91,7 +70,7 @@ static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { SND_SOC_DAPM_MIC("Mic Jack", NULL), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route afeb9260_audio_map[] = { {"Headphone Jack", NULL, "LHPOUT"}, {"Headphone Jack", NULL, "RHPOUT"}, @@ -106,13 +85,6 @@ static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - /* Add afeb9260 specific widgets */ - snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets, - ARRAY_SIZE(tlv320aic23_dapm_widgets)); - - /* Set up afeb9260 specific audio path audio_map */ - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); snd_soc_dapm_enable_pin(dapm, "Line In"); snd_soc_dapm_enable_pin(dapm, "Mic Jack"); @@ -129,6 +101,8 @@ static struct snd_soc_dai_link afeb9260_dai = { .platform_name = "atmel_pcm-audio", .codec_name = "tlv320aic23-codec.0-001a", .init = afeb9260_tlv320aic23_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBM_CFM, .ops = &afeb9260_ops, }; @@ -138,6 +112,11 @@ static struct snd_soc_card snd_soc_machine_afeb9260 = { .owner = THIS_MODULE, .dai_link = &afeb9260_dai, .num_links = 1, + + .dapm_widgets = tlv320aic23_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), + .dapm_routes = afeb9260_audio_map, + .num_dapm_routes = ARRAY_SIZE(afeb9260_audio_map), }; static struct platform_device *afeb9260_snd_device; diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c index 60962ce6cd4..d542d406377 100644 --- a/sound/soc/blackfin/bf5xx-ad1836.c +++ b/sound/soc/blackfin/bf5xx-ad1836.c @@ -40,20 +40,8 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, { 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 channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7}; int ret = 0; - /* 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); - if (ret < 0) - return ret; - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; /* set cpu DAI channel mapping */ ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map), @@ -68,6 +56,9 @@ static struct snd_soc_ops bf5xx_ad1836_ops = { .hw_params = bf5xx_ad1836_hw_params, }; +#define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \ + SND_SOC_DAIFMT_CBM_CFM) + static struct snd_soc_dai_link bf5xx_ad1836_dai[] = { { .name = "ad1836", @@ -77,6 +68,7 @@ static struct snd_soc_dai_link bf5xx_ad1836_dai[] = { .platform_name = "bfin-tdm-pcm-audio", .codec_name = "spi0.4", .ops = &bf5xx_ad1836_ops, + .dai_fmt = BF5XX_AD1836_DAIFMT, }, { .name = "ad1836", @@ -86,6 +78,7 @@ static struct snd_soc_dai_link bf5xx_ad1836_dai[] = { .platform_name = "bfin-tdm-pcm-audio", .codec_name = "spi0.4", .ops = &bf5xx_ad1836_ops, + .dai_fmt = BF5XX_AD1836_DAIFMT, }, }; diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c index 2d8d82dbc15..0e55e9f2a51 100644 --- a/sound/soc/blackfin/bf5xx-ad193x.c +++ b/sound/soc/blackfin/bf5xx-ad193x.c @@ -60,18 +60,6 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream, 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); - if (ret < 0) - return ret; - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); - 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); @@ -92,6 +80,9 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream, return 0; } +#define BF5XX_AD193X_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \ + SND_SOC_DAIFMT_CBM_CFM) + static struct snd_soc_ops bf5xx_ad193x_ops = { .hw_params = bf5xx_ad193x_hw_params, }; @@ -105,6 +96,7 @@ static struct snd_soc_dai_link bf5xx_ad193x_dai[] = { .platform_name = "bfin-tdm-pcm-audio", .codec_name = "spi0.5", .ops = &bf5xx_ad193x_ops, + .dai_fmt = BF5XX_AD193X_DAIFMT, }, { .name = "ad193x", @@ -114,6 +106,7 @@ static struct snd_soc_dai_link bf5xx_ad193x_dai[] = { .platform_name = "bfin-tdm-pcm-audio", .codec_name = "spi0.5", .ops = &bf5xx_ad193x_ops, + .dai_fmt = BF5XX_AD193X_DAIFMT, }, }; diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 8e49508596d..61cc91d4a02 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -145,29 +145,8 @@ static int bf5xx_probe(struct snd_soc_card *card) return 0; } -static int bf5xx_ad73311_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; - int ret = 0; - - pr_debug("%s rate %d format %x\n", __func__, params_rate(params), - params_format(params)); - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - return 0; -} - - -static struct snd_soc_ops bf5xx_ad73311_ops = { - .hw_params = bf5xx_ad73311_hw_params, -}; +#define BF5XX_AD7311_DAI_FMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBM_CFM) static struct snd_soc_dai_link bf5xx_ad73311_dai[] = { { @@ -177,7 +156,7 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai[] = { .codec_dai_name = "ad73311-hifi", .platform_name = "bfin-i2s-pcm-audio", .codec_name = "ad73311", - .ops = &bf5xx_ad73311_ops, + .dai_fmt = BF5XX_AD7311_DAI_FMT, }, { .name = "ad73311", @@ -186,7 +165,7 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai[] = { .codec_dai_name = "ad73311-hifi", .platform_name = "bfin-i2s-pcm-audio", .codec_name = "ad73311", - .ops = &bf5xx_ad73311_ops, + .dai_fmt = BF5XX_AD7311_DAI_FMT, }, }; diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index 03030323804..df3ac73f877 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -49,7 +49,6 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream, { 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; unsigned int clk = 0; int ret = 0; @@ -75,21 +74,6 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream, break; } - /* - * CODEC is master for BCLK and LRC in this configuration. - */ - - /* 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) - 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) - return ret; - ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk, SND_SOC_CLOCK_IN); if (ret < 0) @@ -102,6 +86,10 @@ static struct snd_soc_ops bf5xx_ssm2602_ops = { .hw_params = bf5xx_ssm2602_hw_params, }; +/* CODEC is master for BCLK and LRC in this configuration. */ +#define BF5XX_SSM2602_DAIFMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBM_CFM) + static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = { { .name = "ssm2602", diff --git a/sound/soc/blackfin/bfin-eval-adau1373.c b/sound/soc/blackfin/bfin-eval-adau1373.c index 26b271c62ef..f3adbdbdd5e 100644 --- a/sound/soc/blackfin/bfin-eval-adau1373.c +++ b/sound/soc/blackfin/bfin-eval-adau1373.c @@ -67,21 +67,10 @@ static int bfin_eval_adau1373_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; int pll_rate; - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) - return 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) - return ret; - switch (params_rate(params)) { case 48000: case 8000: @@ -143,6 +132,8 @@ static struct snd_soc_dai_link bfin_eval_adau1373_dai = { .codec_name = "adau1373.0-001a", .ops = &bfin_eval_adau1373_ops, .init = bfin_eval_adau1373_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, }; static struct snd_soc_card bfin_eval_adau1373 = { diff --git a/sound/soc/blackfin/bfin-eval-adau1701.c b/sound/soc/blackfin/bfin-eval-adau1701.c index c0064fa1dca..b0531fc9d81 100644 --- a/sound/soc/blackfin/bfin-eval-adau1701.c +++ b/sound/soc/blackfin/bfin-eval-adau1701.c @@ -37,20 +37,9 @@ static int bfin_eval_adau1701_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(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) - return 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) - return ret; - ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000, SND_SOC_CLOCK_IN); @@ -61,6 +50,9 @@ static struct snd_soc_ops bfin_eval_adau1701_ops = { .hw_params = bfin_eval_adau1701_hw_params, }; +#define BFIN_EVAL_ADAU1701_DAI_FMT (SND_SOC_DAIFMT_I2S | \ + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM) + static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = { { .name = "adau1701", @@ -70,6 +62,7 @@ static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = { .platform_name = "bfin-i2s-pcm-audio", .codec_name = "adau1701.0-0034", .ops = &bfin_eval_adau1701_ops, + .dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT, }, { .name = "adau1701", @@ -79,6 +72,7 @@ static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = { .platform_name = "bfin-i2s-pcm-audio", .codec_name = "adau1701.0-0034", .ops = &bfin_eval_adau1701_ops, + .dai_fmt = BFIN_EVAL_ADAU1701_DAI_FMT, }, }; diff --git a/sound/soc/blackfin/bfin-eval-adav80x.c b/sound/soc/blackfin/bfin-eval-adav80x.c index 4ef079f95e2..84b09987b7f 100644 --- a/sound/soc/blackfin/bfin-eval-adav80x.c +++ b/sound/soc/blackfin/bfin-eval-adav80x.c @@ -34,20 +34,9 @@ static int bfin_eval_adav80x_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(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - if (ret) - return 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) - return ret; - ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_PLL1, ADAV80X_PLL_SRC_XTAL, 27000000, params_rate(params) * 256); if (ret) @@ -88,6 +77,8 @@ static struct snd_soc_dai_link bfin_eval_adav80x_dais[] = { .platform_name = "bfin-i2s-pcm-audio", .init = bfin_eval_adav80x_codec_init, .ops = &bfin_eval_adav80x_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, }, }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7c205e77d83..6508e8b790b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -40,6 +40,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98088 if I2C select SND_SOC_MAX98095 if I2C select SND_SOC_MAX9850 if I2C + select SND_SOC_MAX9768 if I2C select SND_SOC_MAX9877 if I2C select SND_SOC_PCM3008 select SND_SOC_RT5631 if I2C @@ -62,6 +63,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WL1273 if MFD_WL1273_CORE select SND_SOC_WM1250_EV1 if I2C select SND_SOC_WM2000 if I2C + select SND_SOC_WM2200 if I2C select SND_SOC_WM5100 if I2C select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8400 if MFD_WM8400 @@ -292,6 +294,9 @@ config SND_SOC_WM1250_EV1 config SND_SOC_WM2000 tristate +config SND_SOC_WM2200 + tristate + config SND_SOC_WM5100 tristate @@ -425,6 +430,9 @@ config SND_SOC_WM9713 config SND_SOC_LM4857 tristate +config SND_SOC_MAX9768 + tristate + config SND_SOC_MAX9877 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index de8078178f8..6662eb0cdcc 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -25,6 +25,7 @@ snd-soc-dmic-objs := dmic.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o snd-soc-lm4857-objs := lm4857.o +snd-soc-max9768-objs := max9768.o snd-soc-max98088-objs := max98088.o snd-soc-max98095-objs := max98095.o snd-soc-max9850-objs := max9850.o @@ -51,6 +52,7 @@ snd-soc-uda1380-objs := uda1380.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm1250-ev1-objs := wm1250-ev1.o snd-soc-wm2000-objs := wm2000.o +snd-soc-wm2200-objs := wm2200.o snd-soc-wm5100-objs := wm5100.o wm5100-tables.o snd-soc-wm8350-objs := wm8350.o snd-soc-wm8400-objs := wm8400.o @@ -129,6 +131,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o +obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.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 @@ -153,6 +156,7 @@ 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_WM2000) += snd-soc-wm2000.o +obj-$(CONFIG_SND_SOC_WM2200) += snd-soc-wm2200.o obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 982d201c2e8..12e3b411855 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -277,7 +277,7 @@ static int ad1836_probe(struct snd_soc_codec *codec) if (ad1836->type == AD1836) { /* left/right diff:PGA/MUX */ snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); - ret = snd_soc_add_controls(codec, ad1836_controls, + ret = snd_soc_add_codec_controls(codec, ad1836_controls, ARRAY_SIZE(ad1836_controls)); if (ret) return ret; @@ -285,11 +285,11 @@ static int ad1836_probe(struct snd_soc_codec *codec) snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00); } - ret = snd_soc_add_controls(codec, ad183x_dac_controls, num_dacs * 2); + ret = snd_soc_add_codec_controls(codec, ad183x_dac_controls, num_dacs * 2); if (ret) return ret; - ret = snd_soc_add_controls(codec, ad183x_adc_controls, num_adcs); + ret = snd_soc_add_codec_controls(codec, ad183x_adc_controls, num_adcs); if (ret) return ret; diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 9bba7f84946..8c39dddd7d0 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -228,7 +228,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); - snd_soc_add_controls(codec, ad1980_snd_ac97_controls, + snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls, ARRAY_SIZE(ad1980_snd_ac97_controls)); return 0; diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 971ba452917..44f59064d8d 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1244,8 +1244,6 @@ static int adau1373_probe(struct snd_soc_codec *codec) return ret; } - codec->dapm.idle_bias_off = true; - if (pdata) { if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting)) return -EINVAL; @@ -1259,7 +1257,7 @@ static int adau1373_probe(struct snd_soc_codec *codec) pdata->drc_setting[i]); } - snd_soc_add_controls(codec, adau1373_drc_controls, + snd_soc_add_codec_controls(codec, adau1373_drc_controls, pdata->num_drc); val = 0; @@ -1284,7 +1282,7 @@ static int adau1373_probe(struct snd_soc_codec *codec) } if (!lineout_differential) { - snd_soc_add_controls(codec, adau1373_lineout2_controls, + snd_soc_add_codec_controls(codec, adau1373_lineout2_controls, ARRAY_SIZE(adau1373_lineout2_controls)); } @@ -1340,6 +1338,7 @@ static struct snd_soc_codec_driver adau1373_codec_driver = { .suspend = adau1373_suspend, .resume = adau1373_resume, .set_bias_level = adau1373_set_bias_level, + .idle_bias_off = true, .reg_cache_size = ARRAY_SIZE(adau1373_default_regs), .reg_cache_default = adau1373_default_regs, .reg_word_size = sizeof(uint8_t), diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 6b325ea0386..78e9ce48bb9 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -457,7 +457,6 @@ static int adau1701_probe(struct snd_soc_codec *codec) { int ret; - codec->dapm.idle_bias_off = 1; codec->control_data = to_i2c_client(codec->dev); ret = adau1701_load_firmware(codec); @@ -473,6 +472,7 @@ static int adau1701_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver adau1701_codec_drv = { .probe = adau1701_probe, .set_bias_level = adau1701_set_bias_level, + .idle_bias_off = true, .reg_cache_size = ADAU1701_NUM_REGS, .reg_word_size = sizeof(u16), diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index d27b5e4cce9..ceb96ecf558 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -46,75 +46,15 @@ #define DRV_NAME "ak4104-codec" struct ak4104_private { - enum snd_soc_control_type control_type; - void *control_data; + struct regmap *regmap; }; -static int ak4104_fill_cache(struct snd_soc_codec *codec) -{ - int i; - u8 *reg_cache = codec->reg_cache; - struct spi_device *spi = codec->control_data; - - for (i = 0; i < codec->driver->reg_cache_size; i++) { - int ret = spi_w8r8(spi, i | AK4104_READ); - if (ret < 0) { - dev_err(&spi->dev, "SPI write failure\n"); - return ret; - } - - reg_cache[i] = ret; - } - - return 0; -} - -static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 *reg_cache = codec->reg_cache; - - if (reg >= codec->driver->reg_cache_size) - return -EINVAL; - - return reg_cache[reg]; -} - -static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 *cache = codec->reg_cache; - struct spi_device *spi = codec->control_data; - - if (reg >= codec->driver->reg_cache_size) - return -EINVAL; - - /* only write to the hardware if value has changed */ - if (cache[reg] != value) { - u8 tmp[2] = { (reg & AK4104_REG_MASK) | AK4104_WRITE, value }; - - if (spi_write(spi, tmp, sizeof(tmp))) { - dev_err(&spi->dev, "SPI write failed\n"); - return -EIO; - } - - cache[reg] = value; - } - - return 0; -} - static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int format) { struct snd_soc_codec *codec = codec_dai->codec; int val = 0; - - val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1); - if (val < 0) - return val; - - val &= ~(AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1); + int ret; /* set DAI format */ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -135,7 +75,13 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) return -EINVAL; - return ak4104_spi_write(codec, AK4104_REG_CONTROL1, val); + ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1, + AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1, + val); + if (ret < 0) + return ret; + + return 0; } static int ak4104_hw_params(struct snd_pcm_substream *substream, @@ -148,7 +94,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, /* set the IEC958 bits: consumer mode, no copyright bit */ val |= IEC958_AES0_CON_NOT_COPYRIGHT; - ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(0), val); + snd_soc_write(codec, AK4104_REG_CHN_STATUS(0), val); val = 0; @@ -167,7 +113,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - return ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(3), val); + return snd_soc_write(codec, AK4104_REG_CHN_STATUS(3), val); } static const struct snd_soc_dai_ops ak4101_dai_ops = { @@ -192,67 +138,57 @@ static struct snd_soc_dai_driver ak4104_dai = { static int ak4104_probe(struct snd_soc_codec *codec) { struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); - int ret, val; - - codec->control_data = ak4104->control_data; + int ret; - /* read all regs and fill the cache */ - ret = ak4104_fill_cache(codec); - if (ret < 0) { - dev_err(codec->dev, "failed to fill register cache\n"); + codec->control_data = ak4104->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); + if (ret != 0) return ret; - } - - /* read the 'reserved' register - according to the datasheet, it - * should contain 0x5b. Not a good way to verify the presence of - * the device, but there is no hardware ID register. */ - if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) != - AK4104_RESERVED_VAL) - return -ENODEV; /* set power-up and non-reset bits */ - val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1); - val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN; - ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val); + ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1, + AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, + AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); if (ret < 0) return ret; /* enable transmitter */ - val = ak4104_read_reg_cache(codec, AK4104_REG_TX); - val |= AK4104_TX_TXE; - ret = ak4104_spi_write(codec, AK4104_REG_TX, val); + ret = snd_soc_update_bits(codec, AK4104_REG_TX, + AK4104_TX_TXE, AK4104_TX_TXE); if (ret < 0) return ret; - dev_info(codec->dev, "SPI device initialized\n"); return 0; } static int ak4104_remove(struct snd_soc_codec *codec) { - int val, ret; - - val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1); - if (val < 0) - return val; - - /* clear power-up and non-reset bits */ - val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); - ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val); + snd_soc_update_bits(codec, AK4104_REG_CONTROL1, + AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); - return ret; + return 0; } static struct snd_soc_codec_driver soc_codec_device_ak4104 = { .probe = ak4104_probe, .remove = ak4104_remove, - .reg_cache_size = AK4104_NUM_REGS, - .reg_word_size = sizeof(u8), +}; + +static const struct regmap_config ak4104_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = AK4104_NUM_REGS - 1, + .read_flag_mask = AK4104_READ, + .write_flag_mask = AK4104_WRITE, + + .cache_type = REGCACHE_RBTREE, }; static int ak4104_spi_probe(struct spi_device *spi) { struct ak4104_private *ak4104; + unsigned int val; int ret; spi->bits_per_word = 8; @@ -266,17 +202,41 @@ static int ak4104_spi_probe(struct spi_device *spi) if (ak4104 == NULL) return -ENOMEM; - ak4104->control_data = spi; - ak4104->control_type = SND_SOC_SPI; + ak4104->regmap = regmap_init_spi(spi, &ak4104_regmap); + if (IS_ERR(ak4104->regmap)) { + ret = PTR_ERR(ak4104->regmap); + return ret; + } + + /* read the 'reserved' register - according to the datasheet, it + * should contain 0x5b. Not a good way to verify the presence of + * the device, but there is no hardware ID register. */ + ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val); + if (ret != 0) + goto err; + if (val != AK4104_RESERVED_VAL) { + ret = -ENODEV; + goto err; + } + spi_set_drvdata(spi, ak4104); ret = snd_soc_register_codec(&spi->dev, &soc_codec_device_ak4104, &ak4104_dai, 1); + if (ret != 0) + goto err; + + return 0; + +err: + regmap_exit(ak4104->regmap); return ret; } static int __devexit ak4104_spi_remove(struct spi_device *spi) { + struct ak4104_private *ak4101 = spi_get_drvdata(spi); + regmap_exit(ak4101->regmap); snd_soc_unregister_codec(&spi->dev); return 0; } @@ -290,17 +250,7 @@ static struct spi_driver ak4104_spi_driver = { .remove = __devexit_p(ak4104_spi_remove), }; -static int __init ak4104_init(void) -{ - return spi_register_driver(&ak4104_spi_driver); -} -module_init(ak4104_init); - -static void __exit ak4104_exit(void) -{ - spi_unregister_driver(&ak4104_spi_driver); -} -module_exit(ak4104_exit); +module_spi_driver(ak4104_spi_driver); MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver"); diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 9e809e05d06..838ae8b22b5 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -27,24 +28,43 @@ #include "ak4535.h" -#define AK4535_VERSION "0.3" - /* codec private data */ struct ak4535_priv { + struct regmap *regmap; unsigned int sysclk; - enum snd_soc_control_type control_type; }; /* * ak4535 register cache */ -static const u8 ak4535_reg[AK4535_CACHEREGNUM] = { - 0x00, 0x80, 0x00, 0x03, - 0x02, 0x00, 0x11, 0x01, - 0x00, 0x40, 0x36, 0x10, - 0x00, 0x00, 0x57, 0x00, +static const struct reg_default ak4535_reg_defaults[] = { + { 0, 0x00 }, + { 1, 0x80 }, + { 2, 0x00 }, + { 3, 0x03 }, + { 4, 0x02 }, + { 5, 0x00 }, + { 6, 0x11 }, + { 7, 0x01 }, + { 8, 0x00 }, + { 9, 0x40 }, + { 10, 0x36 }, + { 11, 0x10 }, + { 12, 0x00 }, + { 13, 0x00 }, + { 14, 0x57 }, }; +static bool ak4535_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AK4535_STATUS: + return true; + default: + return false; + } +} + static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"}; static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"}; static const char *ak4535_hp_out[] = {"Stereo", "Mono"}; @@ -372,9 +392,8 @@ static int ak4535_probe(struct snd_soc_codec *codec) struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec); int ret; - printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); - - ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4535->control_type); + codec->control_data = ak4535->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -382,7 +401,7 @@ static int ak4535_probe(struct snd_soc_codec *codec) /* power on device */ ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_controls(codec, ak4535_snd_controls, + snd_soc_add_codec_controls(codec, ak4535_snd_controls, ARRAY_SIZE(ak4535_snd_controls)); return 0; } @@ -394,22 +413,30 @@ static int ak4535_remove(struct snd_soc_codec *codec) return 0; } +static const struct regmap_config ak4535_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = AK4535_STATUS, + .volatile_reg = ak4535_volatile, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = ak4535_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ak4535_reg_defaults), +}; + static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { .probe = ak4535_probe, .remove = ak4535_remove, .suspend = ak4535_suspend, .resume = ak4535_resume, .set_bias_level = ak4535_set_bias_level, - .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) static __devinit int ak4535_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -421,17 +448,29 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c, if (ak4535 == NULL) return -ENOMEM; + ak4535->regmap = regmap_init_i2c(i2c, &ak4535_regmap); + if (IS_ERR(ak4535->regmap)) { + ret = PTR_ERR(ak4535->regmap); + dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); + return ret; + } + i2c_set_clientdata(i2c, ak4535); - ak4535->control_type = SND_SOC_I2C; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4535, &ak4535_dai, 1); + if (ret != 0) + regmap_exit(ak4535->regmap); + return ret; } static __devexit int ak4535_i2c_remove(struct i2c_client *client) { + struct ak4535_priv *ak4535 = i2c_get_clientdata(client); + snd_soc_unregister_codec(&client->dev); + regmap_exit(ak4535->regmap); return 0; } @@ -443,36 +482,15 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id); static struct i2c_driver ak4535_i2c_driver = { .driver = { - .name = "ak4535-codec", + .name = "ak4535", .owner = THIS_MODULE, }, .probe = ak4535_i2c_probe, .remove = __devexit_p(ak4535_i2c_remove), .id_table = ak4535_i2c_id, }; -#endif -static int __init ak4535_modinit(void) -{ - int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&ak4535_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register AK4535 I2C driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(ak4535_modinit); - -static void __exit ak4535_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&ak4535_i2c_driver); -#endif -} -module_exit(ak4535_exit); +module_i2c_driver(ak4535_i2c_driver); MODULE_DESCRIPTION("Soc AK4535 driver"); MODULE_AUTHOR("Richard Purdie"); diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h index 0431e5f634a..402de1d274b 100644 --- a/sound/soc/codecs/ak4535.h +++ b/sound/soc/codecs/ak4535.h @@ -34,6 +34,4 @@ #define AK4535_VOL 0xe #define AK4535_STATUS 0xf -#define AK4535_CACHEREGNUM 0x10 - #endif diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 278c0a0575f..f8e10ced244 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -477,7 +477,7 @@ static int ak4642_probe(struct snd_soc_codec *codec) return ret; } - snd_soc_add_controls(codec, ak4642_snd_controls, + snd_soc_add_codec_controls(codec, ak4642_snd_controls, ARRAY_SIZE(ak4642_snd_controls)); ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY); diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index a53b152e6a0..5fb7c2a80e6 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -628,7 +628,7 @@ static int ak4671_probe(struct snd_soc_codec *codec) return ret; } - snd_soc_add_controls(codec, ak4671_snd_controls, + snd_soc_add_codec_controls(codec, ak4671_snd_controls, ARRAY_SIZE(ak4671_snd_controls)); ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 3feee569cee..d47b62ddb21 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -925,22 +925,22 @@ static int alc5623_probe(struct snd_soc_codec *codec) switch (alc5623->id) { case 0x21: - snd_soc_add_controls(codec, alc5621_vol_snd_controls, + snd_soc_add_codec_controls(codec, alc5621_vol_snd_controls, ARRAY_SIZE(alc5621_vol_snd_controls)); break; case 0x22: - snd_soc_add_controls(codec, alc5622_vol_snd_controls, + snd_soc_add_codec_controls(codec, alc5622_vol_snd_controls, ARRAY_SIZE(alc5622_vol_snd_controls)); break; case 0x23: - snd_soc_add_controls(codec, alc5623_vol_snd_controls, + snd_soc_add_codec_controls(codec, alc5623_vol_snd_controls, ARRAY_SIZE(alc5623_vol_snd_controls)); break; default: return -EINVAL; } - snd_soc_add_controls(codec, alc5623_snd_controls, + snd_soc_add_codec_controls(codec, alc5623_snd_controls, ARRAY_SIZE(alc5623_snd_controls)); snd_soc_dapm_new_controls(dapm, alc5623_dapm_widgets, @@ -992,7 +992,7 @@ static struct snd_soc_codec_driver soc_codec_device_alc5623 = { * low = 0x1a * high = 0x1b */ -static int alc5623_i2c_probe(struct i2c_client *client, +static __devinit int alc5623_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct alc5623_platform_data *pdata; @@ -1059,7 +1059,7 @@ static int alc5623_i2c_probe(struct i2c_client *client, return ret; } -static int alc5623_i2c_remove(struct i2c_client *client) +static __devexit int alc5623_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); return 0; diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 390e437d7c5..e2111e0ccad 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -145,15 +145,14 @@ static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0); /* -16.5db min scale, 1.5db steps, no mute */ static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0); static const unsigned int boost_tlv[] = { - TLV_DB_RANGE_HEAD(3), - 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), - 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), - 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), + TLV_DB_RANGE_HEAD(2), + 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), + 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0), }; /* 0db min scale, 6 db steps, no mute */ static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0); /* 0db min scalem 0.75db steps, no mute */ -static const DECLARE_TLV_DB_SCALE(vdac_tlv, -3525, 075, 0); +static const DECLARE_TLV_DB_SCALE(vdac_tlv, -3525, 75, 0); static const struct snd_kcontrol_new alc5632_vol_snd_controls[] = { /* left starts at bit 8, right at bit 0 */ @@ -176,26 +175,32 @@ static const struct snd_kcontrol_new alc5632_snd_controls[] = { ALC5632_AUX_OUT_VOL, 15, 7, 1, 1), SOC_SINGLE_TLV("Voice DAC Playback Volume", ALC5632_VOICE_DAC_VOL, 0, 63, 0, vdac_tlv), - SOC_SINGLE_TLV("Phone Capture Volume", + SOC_SINGLE("Voice DAC Playback Switch", + ALC5632_VOICE_DAC_VOL, 12, 1, 1), + SOC_SINGLE_TLV("Phone Playback Volume", ALC5632_PHONE_IN_VOL, 8, 31, 1, vol_tlv), - SOC_DOUBLE_TLV("LineIn Capture Volume", + SOC_DOUBLE_TLV("LineIn Playback Volume", ALC5632_LINE_IN_VOL, 8, 0, 31, 1, vol_tlv), SOC_DOUBLE_TLV("Master Playback Volume", ALC5632_STEREO_DAC_IN_VOL, 8, 0, 63, 1, vdac_tlv), SOC_DOUBLE("Master Playback Switch", ALC5632_STEREO_DAC_IN_VOL, 15, 7, 1, 1), - SOC_SINGLE_TLV("Mic1 Capture Volume", + SOC_SINGLE_TLV("Mic1 Playback Volume", ALC5632_MIC_VOL, 8, 31, 1, vol_tlv), - SOC_SINGLE_TLV("Mic2 Capture Volume", + SOC_SINGLE_TLV("Mic2 Playback Volume", ALC5632_MIC_VOL, 0, 31, 1, vol_tlv), SOC_DOUBLE_TLV("Rec Capture Volume", ALC5632_ADC_REC_GAIN, 8, 0, 31, 0, adc_rec_tlv), SOC_SINGLE_TLV("Mic 1 Boost Volume", - ALC5632_MIC_CTRL, 10, 2, 0, boost_tlv), + ALC5632_MIC_CTRL, 10, 3, 0, boost_tlv), SOC_SINGLE_TLV("Mic 2 Boost Volume", - ALC5632_MIC_CTRL, 8, 2, 0, boost_tlv), - SOC_SINGLE_TLV("Digital Boost Volume", + ALC5632_MIC_CTRL, 8, 3, 0, boost_tlv), + SOC_SINGLE_TLV("DMIC Boost Capture Volume", ALC5632_DIGI_BOOST_CTRL, 0, 7, 0, dig_tlv), + SOC_SINGLE("DMIC En Capture Switch", + ALC5632_DIGI_BOOST_CTRL, 15, 1, 0), + SOC_SINGLE("DMIC PreFilter Capture Switch", + ALC5632_DIGI_BOOST_CTRL, 12, 1, 0), }; /* @@ -244,36 +249,48 @@ SOC_DAPM_SINGLE("VOICE2SPK Playback Switch", ALC5632_VOICE_DAC_VOL, 14, 1, 1), /* Left Record Mixer */ static const struct snd_kcontrol_new alc5632_captureL_mixer_controls[] = { -SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5632_ADC_REC_MIXER, 14, 1, 1), -SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5632_ADC_REC_MIXER, 13, 1, 1), -SOC_DAPM_SINGLE("LineInL Capture Switch", ALC5632_ADC_REC_MIXER, 12, 1, 1), -SOC_DAPM_SINGLE("Left Phone Capture Switch", ALC5632_ADC_REC_MIXER, 11, 1, 1), -SOC_DAPM_SINGLE("HPMixerL Capture Switch", ALC5632_ADC_REC_MIXER, 10, 1, 1), -SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5632_ADC_REC_MIXER, 9, 1, 1), -SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5632_ADC_REC_MIXER, 8, 1, 1), +SOC_DAPM_SINGLE("MIC12REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 14, 1, 1), +SOC_DAPM_SINGLE("MIC22REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 13, 1, 1), +SOC_DAPM_SINGLE("LIL2REC Capture Switch", ALC5632_ADC_REC_MIXER, 12, 1, 1), +SOC_DAPM_SINGLE("PH2REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 11, 1, 1), +SOC_DAPM_SINGLE("HPL2REC Capture Switch", ALC5632_ADC_REC_MIXER, 10, 1, 1), +SOC_DAPM_SINGLE("SPK2REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 9, 1, 1), +SOC_DAPM_SINGLE("MONO2REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 8, 1, 1), }; /* Right Record Mixer */ static const struct snd_kcontrol_new alc5632_captureR_mixer_controls[] = { -SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5632_ADC_REC_MIXER, 6, 1, 1), -SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5632_ADC_REC_MIXER, 5, 1, 1), -SOC_DAPM_SINGLE("LineInR Capture Switch", ALC5632_ADC_REC_MIXER, 4, 1, 1), -SOC_DAPM_SINGLE("Right Phone Capture Switch", ALC5632_ADC_REC_MIXER, 3, 1, 1), -SOC_DAPM_SINGLE("HPMixerR Capture Switch", ALC5632_ADC_REC_MIXER, 2, 1, 1), -SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5632_ADC_REC_MIXER, 1, 1, 1), -SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5632_ADC_REC_MIXER, 0, 1, 1), +SOC_DAPM_SINGLE("MIC12REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 6, 1, 1), +SOC_DAPM_SINGLE("MIC22REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 5, 1, 1), +SOC_DAPM_SINGLE("LIR2REC Capture Switch", ALC5632_ADC_REC_MIXER, 4, 1, 1), +SOC_DAPM_SINGLE("PH2REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 3, 1, 1), +SOC_DAPM_SINGLE("HPR2REC Capture Switch", ALC5632_ADC_REC_MIXER, 2, 1, 1), +SOC_DAPM_SINGLE("SPK2REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 1, 1, 1), +SOC_DAPM_SINGLE("MONO2REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 0, 1, 1), }; -static const char *alc5632_spk_n_sour_sel[] = { +/* Dmic Mixer */ +static const struct snd_kcontrol_new alc5632_dmicl_mixer_controls[] = { +SOC_DAPM_SINGLE("DMICL2ADC Capture Switch", ALC5632_DIGI_BOOST_CTRL, 7, 1, 1), +}; +static const struct snd_kcontrol_new alc5632_dmicr_mixer_controls[] = { +SOC_DAPM_SINGLE("DMICR2ADC Capture Switch", ALC5632_DIGI_BOOST_CTRL, 6, 1, 1), +}; + +static const char * const alc5632_spk_n_sour_sel[] = { "RN/-R", "RP/+R", "LN/-R", "Mute"}; -static const char *alc5632_hpl_out_input_sel[] = { +static const char * const alc5632_hpl_out_input_sel[] = { "Vmid", "HP Left Mix"}; -static const char *alc5632_hpr_out_input_sel[] = { +static const char * const alc5632_hpr_out_input_sel[] = { "Vmid", "HP Right Mix"}; -static const char *alc5632_spkout_input_sel[] = { +static const char * const alc5632_spkout_input_sel[] = { "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; -static const char *alc5632_aux_out_input_sel[] = { +static const char * const alc5632_aux_out_input_sel[] = { "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; +static const char * const alc5632_adcr_func_sel[] = { + "Stereo ADC", "Voice ADC"}; +static const char * const alc5632_i2s_out_sel[] = { + "ADC LR", "Voice Stereo Digital"}; /* auxout output mux */ static const struct soc_enum alc5632_aux_out_input_enum = @@ -312,6 +329,17 @@ static const struct soc_enum alc5632_amp_enum = static const struct snd_kcontrol_new alc5632_amp_mux_controls = SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum); +/* ADC output select */ +static const struct soc_enum alc5632_adcr_func_enum = + SOC_ENUM_SINGLE(ALC5632_DAC_FUNC_SELECT, 5, 2, alc5632_adcr_func_sel); +static const struct snd_kcontrol_new alc5632_adcr_func_controls = + SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum); + +/* I2S out select */ +static const struct soc_enum alc5632_i2s_out_enum = + SOC_ENUM_SINGLE(ALC5632_I2S_OUT_CTL, 5, 2, alc5632_i2s_out_sel); +static const struct snd_kcontrol_new alc5632_i2s_out_controls = + SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum); static const struct snd_soc_dapm_widget alc5632_dapm_widgets[] = { /* Muxes */ @@ -325,6 +353,10 @@ SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &alc5632_hpr_out_mux_controls), SND_SOC_DAPM_MUX("SpeakerOut N Mux", SND_SOC_NOPM, 0, 0, &alc5632_spkoutn_mux_controls), +SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, + &alc5632_adcr_func_controls), +SND_SOC_DAPM_MUX("I2SOut Mux", ALC5632_PWR_MANAG_ADD1, 11, 0, + &alc5632_i2s_out_controls), /* output mixers */ SND_SOC_DAPM_MIXER("HP Mix", SND_SOC_NOPM, 0, 0, @@ -343,6 +375,12 @@ SND_SOC_DAPM_MIXER("Mono Mix", ALC5632_PWR_MANAG_ADD2, 2, 0, SND_SOC_DAPM_MIXER("Speaker Mix", ALC5632_PWR_MANAG_ADD2, 3, 0, &alc5632_speaker_mixer_controls[0], ARRAY_SIZE(alc5632_speaker_mixer_controls)), +SND_SOC_DAPM_MIXER("DMICL Mix", SND_SOC_NOPM, 0, 0, + &alc5632_dmicl_mixer_controls[0], + ARRAY_SIZE(alc5632_dmicl_mixer_controls)), +SND_SOC_DAPM_MIXER("DMICR Mix", SND_SOC_NOPM, 0, 0, + &alc5632_dmicr_mixer_controls[0], + ARRAY_SIZE(alc5632_dmicr_mixer_controls)), /* input mixers */ SND_SOC_DAPM_MIXER("Left Capture Mix", ALC5632_PWR_MANAG_ADD2, 1, 0, @@ -352,20 +390,28 @@ SND_SOC_DAPM_MIXER("Right Capture Mix", ALC5632_PWR_MANAG_ADD2, 0, 0, &alc5632_captureR_mixer_controls[0], ARRAY_SIZE(alc5632_captureR_mixer_controls)), -SND_SOC_DAPM_DAC("Left DAC", "HiFi Playback", - ALC5632_PWR_MANAG_ADD2, 9, 0), -SND_SOC_DAPM_DAC("Right DAC", "HiFi Playback", - ALC5632_PWR_MANAG_ADD2, 8, 0), +SND_SOC_DAPM_AIF_IN("AIFRXL", "Left HiFi Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIFRXR", "Right HiFi Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIFTXL", "Left HiFi Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIFTXR", "Right HiFi Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("VAIFRX", "Voice Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("VAIFTX", "Voice Capture", 0, SND_SOC_NOPM, 0, 0), + +SND_SOC_DAPM_DAC("Voice DAC", NULL, ALC5632_PWR_MANAG_ADD2, 10, 0), +SND_SOC_DAPM_DAC("Left DAC", NULL, ALC5632_PWR_MANAG_ADD2, 9, 0), +SND_SOC_DAPM_DAC("Right DAC", NULL, ALC5632_PWR_MANAG_ADD2, 8, 0), +SND_SOC_DAPM_ADC("Left ADC", NULL, ALC5632_PWR_MANAG_ADD2, 7, 0), +SND_SOC_DAPM_ADC("Right ADC", NULL, ALC5632_PWR_MANAG_ADD2, 6, 0), + SND_SOC_DAPM_MIXER("DAC Left Channel", ALC5632_PWR_MANAG_ADD1, 15, 0, NULL, 0), SND_SOC_DAPM_MIXER("DAC Right Channel", ALC5632_PWR_MANAG_ADD1, 14, 0, NULL, 0), SND_SOC_DAPM_MIXER("I2S Mix", ALC5632_PWR_MANAG_ADD1, 11, 0, NULL, 0), SND_SOC_DAPM_MIXER("Phone Mix", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("Line Mix", SND_SOC_NOPM, 0, 0, NULL, 0), -SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", - ALC5632_PWR_MANAG_ADD2, 7, 0), -SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", - ALC5632_PWR_MANAG_ADD2, 6, 0), +SND_SOC_DAPM_MIXER("Voice Mix", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_MIXER("ADCLR", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Headphone", ALC5632_PWR_MANAG_ADD3, 11, 0, NULL, 0), SND_SOC_DAPM_PGA("Right Headphone", ALC5632_PWR_MANAG_ADD3, 10, 0, NULL, 0), SND_SOC_DAPM_PGA("Left Speaker", ALC5632_PWR_MANAG_ADD3, 13, 0, NULL, 0), @@ -393,10 +439,12 @@ SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), SND_SOC_DAPM_OUTPUT("SPKOUT"), SND_SOC_DAPM_OUTPUT("SPKOUTN"), + SND_SOC_DAPM_INPUT("LINEINL"), SND_SOC_DAPM_INPUT("LINEINR"), SND_SOC_DAPM_INPUT("PHONEP"), SND_SOC_DAPM_INPUT("PHONEN"), +SND_SOC_DAPM_INPUT("DMICDAT"), SND_SOC_DAPM_INPUT("MIC1"), SND_SOC_DAPM_INPUT("MIC2"), SND_SOC_DAPM_VMID("Vmid"), @@ -404,6 +452,10 @@ SND_SOC_DAPM_VMID("Vmid"), static const struct snd_soc_dapm_route alc5632_dapm_routes[] = { + /* Playback streams */ + {"Left DAC", NULL, "AIFRXL"}, + {"Right DAC", NULL, "AIFRXR"}, + /* virtual mixer - mixes left & right channels */ {"I2S Mix", NULL, "Left DAC"}, {"I2S Mix", NULL, "Right DAC"}, @@ -426,9 +478,12 @@ static const struct snd_soc_dapm_route alc5632_dapm_routes[] = { {"HP Mix", "PHONE2HP Playback Switch", "Phone Mix"}, {"HP Mix", "MIC12HP Playback Switch", "MIC1 PGA"}, {"HP Mix", "MIC22HP Playback Switch", "MIC2 PGA"}, - + {"HP Mix", "VOICE2HP Playback Switch", "Voice Mix"}, {"HPR Mix", "DACR2HP Playback Switch", "DAC Right Channel"}, {"HPL Mix", "DACL2HP Playback Switch", "DAC Left Channel"}, + {"HPOut Mix", NULL, "HP Mix"}, + {"HPOut Mix", NULL, "HPR Mix"}, + {"HPOut Mix", NULL, "HPL Mix"}, /* speaker mixer */ {"Speaker Mix", "LI2SPK Playback Switch", "Line Mix"}, @@ -436,35 +491,34 @@ static const struct snd_soc_dapm_route alc5632_dapm_routes[] = { {"Speaker Mix", "MIC12SPK Playback Switch", "MIC1 PGA"}, {"Speaker Mix", "MIC22SPK Playback Switch", "MIC2 PGA"}, {"Speaker Mix", "DAC2SPK Playback Switch", "DAC Left Channel"}, - - + {"Speaker Mix", "VOICE2SPK Playback Switch", "Voice Mix"}, /* mono mixer */ {"Mono Mix", "ADC2MONO_L Playback Switch", "Left Capture Mix"}, {"Mono Mix", "ADC2MONO_R Playback Switch", "Right Capture Mix"}, {"Mono Mix", "LI2MONO Playback Switch", "Line Mix"}, - {"Mono Mix", "VOICE2MONO Playback Switch", "Phone Mix"}, {"Mono Mix", "MIC12MONO Playback Switch", "MIC1 PGA"}, {"Mono Mix", "MIC22MONO Playback Switch", "MIC2 PGA"}, {"Mono Mix", "DAC2MONO Playback Switch", "DAC Left Channel"}, + {"Mono Mix", "VOICE2MONO Playback Switch", "Voice Mix"}, /* Left record mixer */ - {"Left Capture Mix", "LineInL Capture Switch", "LINEINL"}, - {"Left Capture Mix", "Left Phone Capture Switch", "PHONEN"}, - {"Left Capture Mix", "Mic1 Capture Switch", "MIC1 Pre Amp"}, - {"Left Capture Mix", "Mic2 Capture Switch", "MIC2 Pre Amp"}, - {"Left Capture Mix", "HPMixerL Capture Switch", "HPL Mix"}, - {"Left Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"}, - {"Left Capture Mix", "MonoMixer Capture Switch", "Mono Mix"}, + {"Left Capture Mix", "LIL2REC Capture Switch", "LINEINL"}, + {"Left Capture Mix", "PH2REC_L Capture Switch", "PHONEN"}, + {"Left Capture Mix", "MIC12REC_L Capture Switch", "MIC1 Pre Amp"}, + {"Left Capture Mix", "MIC22REC_L Capture Switch", "MIC2 Pre Amp"}, + {"Left Capture Mix", "HPL2REC Capture Switch", "HPL Mix"}, + {"Left Capture Mix", "SPK2REC_L Capture Switch", "Speaker Mix"}, + {"Left Capture Mix", "MONO2REC_L Capture Switch", "Mono Mix"}, /*Right record mixer */ - {"Right Capture Mix", "LineInR Capture Switch", "LINEINR"}, - {"Right Capture Mix", "Right Phone Capture Switch", "PHONEP"}, - {"Right Capture Mix", "Mic1 Capture Switch", "MIC1 Pre Amp"}, - {"Right Capture Mix", "Mic2 Capture Switch", "MIC2 Pre Amp"}, - {"Right Capture Mix", "HPMixerR Capture Switch", "HPR Mix"}, - {"Right Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"}, - {"Right Capture Mix", "MonoMixer Capture Switch", "Mono Mix"}, + {"Right Capture Mix", "LIR2REC Capture Switch", "LINEINR"}, + {"Right Capture Mix", "PH2REC_R Capture Switch", "PHONEP"}, + {"Right Capture Mix", "MIC12REC_R Capture Switch", "MIC1 Pre Amp"}, + {"Right Capture Mix", "MIC22REC_R Capture Switch", "MIC2 Pre Amp"}, + {"Right Capture Mix", "HPR2REC Capture Switch", "HPR Mix"}, + {"Right Capture Mix", "SPK2REC_R Capture Switch", "Speaker Mix"}, + {"Right Capture Mix", "MONO2REC_R Capture Switch", "Mono Mix"}, /* headphone left mux */ {"Left Headphone Mux", "HP Left Mix", "HPL Mix"}, @@ -504,10 +558,30 @@ static const struct snd_soc_dapm_route alc5632_dapm_routes[] = { /* left ADC */ {"Left ADC", NULL, "Left Capture Mix"}, + {"DMICL Mix", "DMICL2ADC Capture Switch", "DMICDAT"}, + {"Left ADC", NULL, "DMICL Mix"}, + {"ADCLR", NULL, "Left ADC"}, /* right ADC */ - {"Right ADC", NULL, "Right Capture Mix"}, - + {"Right ADC", NULL, "Right Capture Mix"}, + {"DMICR Mix", "DMICR2ADC Capture Switch", "DMICDAT"}, + {"Right ADC", NULL, "DMICR Mix"}, + {"ADCR Mux", "Stereo ADC", "Right ADC"}, + {"ADCR Mux", "Voice ADC", "Right ADC"}, + {"ADCLR", NULL, "ADCR Mux"}, + {"VAIFTX", NULL, "ADCR Mux"}, + + /* Digital I2S out */ + {"I2SOut Mux", "ADC LR", "ADCLR"}, + {"I2SOut Mux", "Voice Stereo Digital", "VAIFRX"}, + {"AIFTXL", NULL, "I2SOut Mux"}, + {"AIFTXR", NULL, "I2SOut Mux"}, + + /* Voice Mix */ + {"Voice DAC", NULL, "VAIFRX"}, + {"Voice Mix", NULL, "Voice DAC"}, + + /* Speaker Output */ {"SpeakerOut N Mux", "RN/-R", "Left Speaker"}, {"SpeakerOut N Mux", "RP/+R", "Left Speaker"}, {"SpeakerOut N Mux", "LN/-R", "Left Speaker"}, @@ -714,6 +788,7 @@ static int alc5632_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); switch (freq) { + case 4096000: case 8192000: case 11289600: case 12288000: @@ -994,7 +1069,7 @@ static int alc5632_probe(struct snd_soc_codec *codec) switch (alc5632->id) { case 0x5c: - snd_soc_add_controls(codec, alc5632_vol_snd_controls, + snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls, ARRAY_SIZE(alc5632_vol_snd_controls)); break; default: @@ -1109,7 +1184,7 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client, return ret; } -static int alc5632_i2c_remove(struct i2c_client *client) +static __devexit int alc5632_i2c_remove(struct i2c_client *client) { struct alc5632_priv *alc5632 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); diff --git a/sound/soc/codecs/alc5632.h b/sound/soc/codecs/alc5632.h index 357651ec074..1b5bda594ea 100644 --- a/sound/soc/codecs/alc5632.h +++ b/sound/soc/codecs/alc5632.h @@ -51,6 +51,7 @@ #define ALC5632_ADC_REC_MONOMIX (1 << 0) #define ALC5632_VOICE_DAC_VOL 0x18 /* voice dac vol */ +#define ALC5632_I2S_OUT_CTL 0x1A /* undocumented reg. found in path scheme */ /* ALC5632_OUTPUT_MIXER_CTRL : */ /* same remark as for reg 2 line vs speaker */ #define ALC5632_OUTPUT_MIXER_CTRL 0x1C /* out mix ctrl */ diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 4854b472d5f..064cd6a9351 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -38,8 +38,6 @@ #include <sound/soc.h> #include <sound/initval.h> -#include <mach/dm365.h> - static inline unsigned int cq93vc_read(struct snd_soc_codec *codec, unsigned int reg) { @@ -159,7 +157,7 @@ static int cq93vc_probe(struct snd_soc_codec *codec) codec->control_data = davinci_vc; /* Set controls */ - snd_soc_add_controls(codec, cq93vc_snd_controls, + snd_soc_add_codec_controls(codec, cq93vc_snd_controls, ARRAY_SIZE(cq93vc_snd_controls)); /* Off, with power on */ diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 055536645da..1d672f52866 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -521,7 +521,7 @@ static int cs4270_probe(struct snd_soc_codec *codec) } /* Add the non-DAPM controls */ - ret = snd_soc_add_controls(codec, cs4270_snd_controls, + ret = snd_soc_add_codec_controls(codec, cs4270_snd_controls, ARRAY_SIZE(cs4270_snd_controls)); if (ret < 0) { dev_err(codec->dev, "failed to add controls\n"); @@ -715,7 +715,7 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id); */ static struct i2c_driver cs4270_i2c_driver = { .driver = { - .name = "cs4270-codec", + .name = "cs4270", .owner = THIS_MODULE, }, .id_table = cs4270_id, diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index f6fe846b6a6..bf7141280a7 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -513,7 +513,7 @@ static int cs4271_probe(struct snd_soc_codec *codec) /* Power-up sequence requires 85 uS */ udelay(85); - return snd_soc_add_controls(codec, cs4271_snd_controls, + return snd_soc_add_codec_controls(codec, cs4271_snd_controls, ARRAY_SIZE(cs4271_snd_controls)); } diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index ab38e93c354..7843711729b 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <linux/module.h> #include <sound/pcm.h> @@ -626,41 +627,82 @@ static const struct snd_soc_dapm_route da7210_audio_map[] = { /* Codec private data */ struct da7210_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; }; -/* - * Register cache - */ -static const u8 da7210_reg[] = { - 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R0 - R7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, /* R8 - RF */ - 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x54, /* R10 - R17 */ - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R18 - R1F */ - 0x00, 0x00, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, /* R20 - R27 */ - 0x04, 0x00, 0x00, 0x30, 0x2A, 0x00, 0x40, 0x00, /* R28 - R2F */ - 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, /* R30 - R37 */ - 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, /* R38 - R3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R40 - R4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R48 - R4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R50 - R57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R58 - R5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R60 - R67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R68 - R6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R70 - R77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x00, /* R78 - R7F */ - 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, /* R80 - R87 */ - 0x00, /* R88 */ +static struct reg_default da7210_reg_defaults[] = { + { 0x01, 0x11 }, + { 0x03, 0x00 }, + { 0x04, 0x00 }, + { 0x05, 0x00 }, + { 0x06, 0x00 }, + { 0x07, 0x00 }, + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x0c, 0x00 }, + { 0x0d, 0x00 }, + { 0x0e, 0x00 }, + { 0x0f, 0x08 }, + { 0x10, 0x00 }, + { 0x11, 0x00 }, + { 0x12, 0x00 }, + { 0x13, 0x00 }, + { 0x14, 0x08 }, + { 0x15, 0x10 }, + { 0x16, 0x10 }, + { 0x17, 0x54 }, + { 0x18, 0x40 }, + { 0x19, 0x00 }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x00 }, + { 0x1e, 0x00 }, + { 0x1f, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x23, 0x02 }, + { 0x24, 0x00 }, + { 0x25, 0x76 }, + { 0x26, 0x00 }, + { 0x27, 0x00 }, + { 0x28, 0x04 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + { 0x2b, 0x30 }, + { 0x2c, 0x2A }, + { 0x83, 0x00 }, + { 0x84, 0x00 }, + { 0x85, 0x00 }, + { 0x86, 0x00 }, + { 0x87, 0x00 }, + { 0x88, 0x00 }, }; -static int da7210_volatile_register(struct snd_soc_codec *codec, +static bool da7210_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA7210_A_HID_UNLOCK: + case DA7210_A_TEST_UNLOCK: + case DA7210_A_PLL1: + case DA7210_A_CP_MODE: + return false; + default: + return true; + } +} + +static bool da7210_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case DA7210_STATUS: - return 1; + return true; default: - return 0; + return false; } } @@ -866,7 +908,8 @@ static int da7210_probe(struct snd_soc_codec *codec) dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); - ret = snd_soc_codec_set_cache_io(codec, 8, 8, da7210->control_type); + codec->control_data = da7210->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -983,12 +1026,14 @@ static int da7210_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN); /* As suggested by Dialog */ - snd_soc_write(codec, DA7210_A_HID_UNLOCK, 0x8B); /* unlock */ - snd_soc_write(codec, DA7210_A_TEST_UNLOCK, 0xB4); - snd_soc_write(codec, DA7210_A_PLL1, 0x01); - snd_soc_write(codec, DA7210_A_CP_MODE, 0x7C); - snd_soc_write(codec, DA7210_A_HID_UNLOCK, 0x00); /* re-lock */ - snd_soc_write(codec, DA7210_A_TEST_UNLOCK, 0x00); + /* unlock */ + regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK, 0x8B); + regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK, 0xB4); + regmap_write(da7210->regmap, DA7210_A_PLL1, 0x01); + regmap_write(da7210->regmap, DA7210_A_CP_MODE, 0x7C); + /* re-lock */ + regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK, 0x00); + regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK, 0x00); /* Activate all enabled subsystem */ snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN); @@ -1000,10 +1045,6 @@ static int da7210_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_da7210 = { .probe = da7210_probe, - .reg_cache_size = ARRAY_SIZE(da7210_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = da7210_reg, - .volatile_register = da7210_volatile_register, .controls = da7210_snd_controls, .num_controls = ARRAY_SIZE(da7210_snd_controls), @@ -1014,6 +1055,17 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = { .num_dapm_routes = ARRAY_SIZE(da7210_audio_map), }; +static struct regmap_config da7210_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .reg_defaults = da7210_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults), + .volatile_reg = da7210_volatile_register, + .readable_reg = da7210_readable_register, + .cache_type = REGCACHE_RBTREE, +}; + #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static int __devinit da7210_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) @@ -1027,16 +1079,34 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c, return -ENOMEM; i2c_set_clientdata(i2c, da7210); - da7210->control_type = SND_SOC_I2C; + + da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap); + if (IS_ERR(da7210->regmap)) { + ret = PTR_ERR(da7210->regmap); + dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); + return ret; + } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7210, &da7210_dai, 1); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + goto err_regmap; + } + return ret; + +err_regmap: + regmap_exit(da7210->regmap); + return ret; } static int __devexit da7210_i2c_remove(struct i2c_client *client) { + struct da7210_priv *da7210 = i2c_get_clientdata(client); + snd_soc_unregister_codec(&client->dev); + regmap_exit(da7210->regmap); return 0; } diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 319039240e0..ba4fafb93e5 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -179,7 +179,7 @@ static int lm4857_probe(struct snd_soc_codec *codec) codec->control_data = lm4857->i2c; - ret = snd_soc_add_controls(codec, lm4857_controls, + ret = snd_soc_add_codec_controls(codec, lm4857_controls, ARRAY_SIZE(lm4857_controls)); if (ret) return ret; diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c new file mode 100644 index 00000000000..17b3ec2d05c --- /dev/null +++ b/sound/soc/codecs/max9768.c @@ -0,0 +1,247 @@ +/* + * MAX9768 AMP driver + * + * Copyright (C) 2011, 2012 by Wolfram Sang, Pengutronix e.K. + * + * 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; version 2 of the License. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/regmap.h> + +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include <sound/max9768.h> + +/* "Registers" */ +#define MAX9768_VOL 0 +#define MAX9768_CTRL 3 + +/* Commands */ +#define MAX9768_CTRL_PWM 0x15 +#define MAX9768_CTRL_FILTERLESS 0x16 + +struct max9768 { + struct regmap *regmap; + int mute_gpio; + int shdn_gpio; + u32 flags; +}; + +static struct reg_default max9768_default_regs[] = { + { 0, 0 }, + { 3, MAX9768_CTRL_FILTERLESS}, +}; + +static int max9768_get_gpio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); + int val = gpio_get_value_cansleep(max9768->mute_gpio); + + ucontrol->value.integer.value[0] = !val; + + return 0; +} + +static int max9768_set_gpio(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); + + gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]); + + return 0; +} + +static const unsigned int volume_tlv[] = { + TLV_DB_RANGE_HEAD(43), + 0, 0, TLV_DB_SCALE_ITEM(-16150, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(-9280, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(-9030, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(-8680, 0, 0), + 4, 4, TLV_DB_SCALE_ITEM(-8430, 0, 0), + 5, 5, TLV_DB_SCALE_ITEM(-8080, 0, 0), + 6, 6, TLV_DB_SCALE_ITEM(-7830, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(-7470, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(-7220, 0, 0), + 9, 9, TLV_DB_SCALE_ITEM(-6870, 0, 0), + 10, 10, TLV_DB_SCALE_ITEM(-6620, 0, 0), + 11, 11, TLV_DB_SCALE_ITEM(-6270, 0, 0), + 12, 12, TLV_DB_SCALE_ITEM(-6020, 0, 0), + 13, 13, TLV_DB_SCALE_ITEM(-5670, 0, 0), + 14, 14, TLV_DB_SCALE_ITEM(-5420, 0, 0), + 15, 17, TLV_DB_SCALE_ITEM(-5060, 250, 0), + 18, 18, TLV_DB_SCALE_ITEM(-4370, 0, 0), + 19, 19, TLV_DB_SCALE_ITEM(-4210, 0, 0), + 20, 20, TLV_DB_SCALE_ITEM(-3960, 0, 0), + 21, 21, TLV_DB_SCALE_ITEM(-3760, 0, 0), + 22, 22, TLV_DB_SCALE_ITEM(-3600, 0, 0), + 23, 23, TLV_DB_SCALE_ITEM(-3340, 0, 0), + 24, 24, TLV_DB_SCALE_ITEM(-3150, 0, 0), + 25, 25, TLV_DB_SCALE_ITEM(-2980, 0, 0), + 26, 26, TLV_DB_SCALE_ITEM(-2720, 0, 0), + 27, 27, TLV_DB_SCALE_ITEM(-2520, 0, 0), + 28, 30, TLV_DB_SCALE_ITEM(-2350, 190, 0), + 31, 31, TLV_DB_SCALE_ITEM(-1750, 0, 0), + 32, 34, TLV_DB_SCALE_ITEM(-1640, 100, 0), + 35, 37, TLV_DB_SCALE_ITEM(-1310, 110, 0), + 38, 39, TLV_DB_SCALE_ITEM(-990, 100, 0), + 40, 40, TLV_DB_SCALE_ITEM(-710, 0, 0), + 41, 41, TLV_DB_SCALE_ITEM(-600, 0, 0), + 42, 42, TLV_DB_SCALE_ITEM(-500, 0, 0), + 43, 43, TLV_DB_SCALE_ITEM(-340, 0, 0), + 44, 44, TLV_DB_SCALE_ITEM(-190, 0, 0), + 45, 45, TLV_DB_SCALE_ITEM(-50, 0, 0), + 46, 46, TLV_DB_SCALE_ITEM(50, 0, 0), + 47, 50, TLV_DB_SCALE_ITEM(120, 40, 0), + 51, 57, TLV_DB_SCALE_ITEM(290, 50, 0), + 58, 58, TLV_DB_SCALE_ITEM(650, 0, 0), + 59, 62, TLV_DB_SCALE_ITEM(700, 60, 0), + 63, 63, TLV_DB_SCALE_ITEM(950, 0, 0), +}; + +static const struct snd_kcontrol_new max9768_volume[] = { + SOC_SINGLE_TLV("Playback Volume", MAX9768_VOL, 0, 63, 0, volume_tlv), +}; + +static const struct snd_kcontrol_new max9768_mute[] = { + SOC_SINGLE_BOOL_EXT("Playback Switch", 0, max9768_get_gpio, max9768_set_gpio), +}; + +static int max9768_probe(struct snd_soc_codec *codec) +{ + struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); + int ret; + + codec->control_data = max9768->regmap; + ret = snd_soc_codec_set_cache_io(codec, 2, 6, SND_SOC_REGMAP); + if (ret) + return ret; + + if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) { + ret = snd_soc_write(codec, MAX9768_CTRL, MAX9768_CTRL_PWM); + if (ret) + return ret; + } + + if (gpio_is_valid(max9768->mute_gpio)) { + ret = snd_soc_add_codec_controls(codec, max9768_mute, + ARRAY_SIZE(max9768_mute)); + if (ret) + return ret; + } + + return 0; +} + +static struct snd_soc_codec_driver max9768_codec_driver = { + .probe = max9768_probe, + .controls = max9768_volume, + .num_controls = ARRAY_SIZE(max9768_volume), +}; + +static const struct regmap_config max9768_i2c_regmap_config = { + .reg_bits = 2, + .val_bits = 6, + .max_register = 3, + .reg_defaults = max9768_default_regs, + .num_reg_defaults = ARRAY_SIZE(max9768_default_regs), + .cache_type = REGCACHE_RBTREE, +}; + +static int __devinit max9768_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max9768 *max9768; + struct max9768_pdata *pdata = client->dev.platform_data; + int err; + + max9768 = devm_kzalloc(&client->dev, sizeof(*max9768), GFP_KERNEL); + if (!max9768) + return -ENOMEM; + + if (pdata) { + /* Mute on powerup to avoid clicks */ + err = gpio_request_one(pdata->mute_gpio, GPIOF_INIT_HIGH, "MAX9768 Mute"); + max9768->mute_gpio = err ?: pdata->mute_gpio; + + /* Activate chip by releasing shutdown, enables I2C */ + err = gpio_request_one(pdata->shdn_gpio, GPIOF_INIT_HIGH, "MAX9768 Shutdown"); + max9768->shdn_gpio = err ?: pdata->shdn_gpio; + + max9768->flags = pdata->flags; + } else { + max9768->shdn_gpio = -EINVAL; + max9768->mute_gpio = -EINVAL; + } + + i2c_set_clientdata(client, max9768); + + max9768->regmap = regmap_init_i2c(client, &max9768_i2c_regmap_config); + if (IS_ERR(max9768->regmap)) { + err = PTR_ERR(max9768->regmap); + goto err_gpio_free; + } + + err = snd_soc_register_codec(&client->dev, &max9768_codec_driver, NULL, 0); + if (err) + goto err_regmap_free; + + return 0; + + err_regmap_free: + regmap_exit(max9768->regmap); + err_gpio_free: + if (gpio_is_valid(max9768->shdn_gpio)) + gpio_free(max9768->shdn_gpio); + if (gpio_is_valid(max9768->mute_gpio)) + gpio_free(max9768->mute_gpio); + + return err; +} + +static int __devexit max9768_i2c_remove(struct i2c_client *client) +{ + struct max9768 *max9768 = i2c_get_clientdata(client); + + snd_soc_unregister_codec(&client->dev); + regmap_exit(max9768->regmap); + + if (gpio_is_valid(max9768->shdn_gpio)) + gpio_free(max9768->shdn_gpio); + if (gpio_is_valid(max9768->mute_gpio)) + gpio_free(max9768->mute_gpio); + + return 0; +} + +static const struct i2c_device_id max9768_i2c_id[] = { + { "max9768", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max9768_i2c_id); + +static struct i2c_driver max9768_i2c_driver = { + .driver = { + .name = "max9768", + .owner = THIS_MODULE, + }, + .probe = max9768_i2c_probe, + .remove = __devexit_p(max9768_i2c_remove), + .id_table = max9768_i2c_id, +}; +module_i2c_driver(max9768_i2c_driver); + +MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); +MODULE_DESCRIPTION("ASoC MAX9768 amplifier driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 006efcfe6dd..af7324b79dd 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1908,7 +1908,7 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec) max98088->eq_enum.texts = max98088->eq_texts; max98088->eq_enum.max = max98088->eq_textcnt; - ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls)); + ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); if (ret != 0) dev_err(codec->dev, "Failed to add EQ control: %d\n", ret); } @@ -2030,7 +2030,7 @@ static int max98088_probe(struct snd_soc_codec *codec) max98088_handle_pdata(codec); - snd_soc_add_controls(codec, max98088_snd_controls, + snd_soc_add_codec_controls(codec, max98088_snd_controls, ARRAY_SIZE(max98088_snd_controls)); err_access: diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index fcfa7497d7b..0bb511a0388 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -1284,7 +1284,7 @@ static const struct snd_soc_dapm_route max98095_audio_map[] = { static int max98095_add_widgets(struct snd_soc_codec *codec) { - snd_soc_add_controls(codec, max98095_snd_controls, + snd_soc_add_codec_controls(codec, max98095_snd_controls, ARRAY_SIZE(max98095_snd_controls)); return 0; @@ -1984,7 +1984,7 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec) max98095->eq_enum.texts = max98095->eq_texts; max98095->eq_enum.max = max98095->eq_textcnt; - ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls)); + ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); if (ret != 0) dev_err(codec->dev, "Failed to add EQ control: %d\n", ret); } @@ -2139,7 +2139,7 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec) max98095->bq_enum.texts = max98095->bq_texts; max98095->bq_enum.max = max98095->bq_textcnt; - ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls)); + ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); if (ret != 0) dev_err(codec->dev, "Failed to add Biquad control: %d\n", ret); } diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index dcf6f2a1600..3a2ba3d8fd6 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -253,7 +253,7 @@ static const struct snd_kcontrol_new max9877_controls[] = { /* This function is called from ASoC machine driver */ int max9877_add_controls(struct snd_soc_codec *codec) { - return snd_soc_add_controls(codec, max9877_controls, + return snd_soc_add_codec_controls(codec, max9877_controls, ARRAY_SIZE(max9877_controls)); } EXPORT_SYMBOL_GPL(max9877_add_controls); diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 7f4ba819a9f..d1926266fe0 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -227,7 +227,7 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { }; /* routes for sgtl5000 */ -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = { {"Capture Mux", "LINE_IN", "LINE_IN"}, /* line_in --> adc_mux */ {"Capture Mux", "MIC_IN", "MIC_IN"}, /* mic_in --> adc_mux */ @@ -1248,7 +1248,7 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) } rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT; - dev_info(codec->dev, "sgtl5000 revision %d\n", rev); + dev_info(codec->dev, "sgtl5000 revision 0x%x\n", rev); /* * workaround for revision 0x11 and later, @@ -1353,15 +1353,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) if (ret) goto err; - snd_soc_add_controls(codec, sgtl5000_snd_controls, - ARRAY_SIZE(sgtl5000_snd_controls)); - - snd_soc_dapm_new_controls(&codec->dapm, sgtl5000_dapm_widgets, - ARRAY_SIZE(sgtl5000_dapm_widgets)); - - snd_soc_dapm_add_routes(&codec->dapm, audio_map, - ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(&codec->dapm); return 0; @@ -1402,6 +1393,12 @@ static struct snd_soc_codec_driver sgtl5000_driver = { .reg_cache_step = 2, .reg_cache_default = sgtl5000_regs, .volatile_register = sgtl5000_volatile_register, + .controls = sgtl5000_snd_controls, + .num_controls = ARRAY_SIZE(sgtl5000_snd_controls), + .dapm_widgets = sgtl5000_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sgtl5000_dapm_widgets), + .dapm_routes = sgtl5000_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sgtl5000_dapm_routes), }; static __devinit int sgtl5000_i2c_probe(struct i2c_client *client, diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index f99baa0b8c3..50dbdb9357e 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -827,8 +827,6 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) { pr_debug("codec_probe called\n"); - codec->dapm.idle_bias_off = 1; - /* PCM interface config * This sets the pcm rx slot conguration to max 6 slots * for max 4 dais (2 stereo and 2 mono) @@ -871,7 +869,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) snd_soc_write(codec, SN95031_SSR2, 0x10); snd_soc_write(codec, SN95031_SSR3, 0x40); - snd_soc_add_controls(codec, sn95031_snd_controls, + snd_soc_add_codec_controls(codec, sn95031_snd_controls, ARRAY_SIZE(sn95031_snd_controls)); return 0; @@ -891,6 +889,7 @@ struct snd_soc_codec_driver sn95031_codec = { .read = sn95031_read, .write = sn95031_write, .set_bias_level = sn95031_set_vaud_bias, + .idle_bias_off = true, .dapm_widgets = sn95031_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), .dapm_routes = sn95031_audio_map, diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 333dd98af39..de2b20544ce 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -548,7 +548,7 @@ static int ssm2602_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, SSM2602_ROUT1V, ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH); - ret = snd_soc_add_controls(codec, ssm2602_snd_controls, + ret = snd_soc_add_codec_controls(codec, ssm2602_snd_controls, ARRAY_SIZE(ssm2602_snd_controls)); if (ret) return ret; diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index cc0566c22ec..982e437799a 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -355,7 +355,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_controls(codec, stac9766_snd_ac97_controls, + snd_soc_add_codec_controls(codec, stac9766_snd_ac97_controls, ARRAY_SIZE(stac9766_snd_ac97_controls)); return 0; diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index dfa41a96599..16d55f91a65 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -593,7 +593,7 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec) snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1); - snd_soc_add_controls(codec, tlv320aic23_snd_controls, + snd_soc_add_codec_controls(codec, tlv320aic23_snd_controls, ARRAY_SIZE(tlv320aic23_snd_controls)); return 0; diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index a038daec682..802064b5030 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -389,7 +389,7 @@ static int aic26_probe(struct snd_soc_codec *codec) /* register controls */ dev_dbg(codec->dev, "Registering controls\n"); - err = snd_soc_add_controls(codec, aic26_snd_controls, + err = snd_soc_add_codec_controls(codec, aic26_snd_controls, ARRAY_SIZE(aic26_snd_controls)); WARN_ON(err < 0); diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 372b0b83bd9..b0a73d37ed5 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -671,7 +671,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec) } aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_controls(codec, aic32x4_snd_controls, + snd_soc_add_codec_controls(codec, aic32x4_snd_controls, ARRAY_SIZE(aic32x4_snd_controls)); aic32x4_add_widgets(codec); diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 492f22f8a4d..8d20f6ec20f 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -121,30 +121,6 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { 0x00, 0x00, 0x02, /* 100 */ }; -/* - * read from the aic3x register space. Only use for this function is if - * wanting to read volatile bits from those registers that has both read-only - * and read/write bits. All other cases should use snd_soc_read. - */ -static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, - u8 *value) -{ - u8 *cache = codec->reg_cache; - - if (codec->cache_only) - return -EINVAL; - if (reg >= AIC3X_CACHEREGNUM) - return -1; - - codec->cache_bypass = 1; - *value = snd_soc_read(codec, reg); - codec->cache_bypass = 0; - - cache[reg] = *value; - - return 0; -} - #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, \ @@ -1185,25 +1161,6 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, return 0; } -void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) -{ - u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; - u8 bit = gpio ? 3: 0; - u8 val = snd_soc_read(codec, reg) & ~(1 << bit); - snd_soc_write(codec, reg, val | (!!state << bit)); -} -EXPORT_SYMBOL_GPL(aic3x_set_gpio); - -int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) -{ - u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; - u8 val = 0, bit = gpio ? 2 : 1; - - aic3x_read(codec, reg, &val); - return (val >> bit) & 1; -} -EXPORT_SYMBOL_GPL(aic3x_get_gpio); - void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, int headset_debounce, int button_debounce) { @@ -1221,23 +1178,6 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); } -EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); - -int aic3x_headset_detected(struct snd_soc_codec *codec) -{ - u8 val = 0; - aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); - return (val >> 4) & 1; -} -EXPORT_SYMBOL_GPL(aic3x_headset_detected); - -int aic3x_button_pressed(struct snd_soc_codec *codec) -{ - u8 val = 0; - aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); - return (val >> 5) & 1; -} -EXPORT_SYMBOL_GPL(aic3x_button_pressed); #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ @@ -1377,7 +1317,6 @@ static int aic3x_probe(struct snd_soc_codec *codec) INIT_LIST_HEAD(&aic3x->list); aic3x->codec = codec; - codec->dapm.idle_bias_off = 1; ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); if (ret != 0) { @@ -1426,10 +1365,10 @@ static int aic3x_probe(struct snd_soc_codec *codec) (aic3x->setup->gpio_func[1] & 0xf) << 4); } - snd_soc_add_controls(codec, aic3x_snd_controls, + snd_soc_add_codec_controls(codec, aic3x_snd_controls, ARRAY_SIZE(aic3x_snd_controls)); if (aic3x->model == AIC3X_MODEL_3007) - snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); + snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); aic3x_add_widgets(codec); list_add(&aic3x->list, &reset_list); @@ -1471,6 +1410,7 @@ static int aic3x_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_aic3x = { .set_bias_level = aic3x_set_bias_level, + .idle_bias_off = true, .reg_cache_size = ARRAY_SIZE(aic3x_reg), .reg_word_size = sizeof(u8), .reg_cache_default = aic3x_reg, diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 06a19784b16..6f097fb6068 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -212,9 +212,6 @@ /* Default input volume */ #define DEFAULT_GAIN 0x20 -void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state); -int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); - /* headset detection / button API */ /* The AIC3x supports detection of stereo headsets (GND + left + right signal) @@ -252,10 +249,4 @@ enum { #define AIC3X_BUTTON_DEBOUNCE_SHIFT 0 #define AIC3X_BUTTON_DEBOUNCE_MASK 3 -/* see the enums above for valid parameters to this function */ -void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, - int headset_debounce, int button_debounce); -int aic3x_headset_detected(struct snd_soc_codec *codec); -int aic3x_button_pressed(struct snd_soc_codec *codec); - #endif /* _AIC3X_H */ diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index f0aad26cdb3..4587ddd0fbf 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -806,8 +806,6 @@ static int dac33_startup(struct snd_pcm_substream *substream, /* Stream started, save the substream pointer */ dac33->substream = substream; - snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24); - return 0; } @@ -1397,7 +1395,6 @@ static int dac33_soc_probe(struct snd_soc_codec *codec) codec->control_data = dac33->control_data; codec->hw_write = (hw_write_t) i2c_master_send; - codec->dapm.idle_bias_off = 1; dac33->codec = codec; /* Read the tlv320dac33 ID registers */ @@ -1440,7 +1437,7 @@ static int dac33_soc_probe(struct snd_soc_codec *codec) /* Only add the FIFO controls, if we have valid IRQ number */ if (dac33->irq >= 0) - snd_soc_add_controls(codec, dac33_mode_snd_controls, + snd_soc_add_codec_controls(codec, dac33_mode_snd_controls, ARRAY_SIZE(dac33_mode_snd_controls)); err_power: @@ -1478,6 +1475,7 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = { .read = dac33_read_reg_cache, .write = dac33_write_locked, .set_bias_level = dac33_set_bias_level, + .idle_bias_off = true, .reg_cache_size = ARRAY_SIZE(dac33_reg), .reg_word_size = sizeof(u8), .reg_cache_default = dac33_reg, @@ -1515,7 +1513,9 @@ static struct snd_soc_dai_driver dac33_dai = { .channels_min = 2, .channels_max = 2, .rates = DAC33_RATES, - .formats = DAC33_FORMATS,}, + .formats = DAC33_FORMATS, + .sig_bits = 24, + }, .ops = &dac33_dai_ops, }; diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 363b99dad8e..6fe4aa3ac54 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -351,10 +351,10 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec) data = i2c_get_clientdata(tpa6130a2_client); if (data->id == TPA6140A2) - return snd_soc_add_controls(codec, tpa6140a2_controls, + return snd_soc_add_codec_controls(codec, tpa6140a2_controls, ARRAY_SIZE(tpa6140a2_controls)); else - return snd_soc_add_controls(codec, tpa6130a2_controls, + return snd_soc_add_codec_controls(codec, tpa6130a2_controls, ARRAY_SIZE(tpa6130a2_controls)); } EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 18e71014cc2..170cf9a8fc7 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1002,8 +1002,8 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, unsigned short mask, bitmask; if (twl4030->configured) { - printk(KERN_ERR "twl4030 operation mode cannot be " - "changed on-the-fly\n"); + dev_err(codec->dev, + "operation mode cannot be changed on-the-fly\n"); return -EBUSY; } @@ -1689,7 +1689,6 @@ static int twl4030_startup(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = rtd->codec; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); - snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24); if (twl4030->master_substream) { twl4030->slave_substream = substream; /* The DAI has one configuration for playback and capture, so @@ -1801,7 +1800,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, mode |= TWL4030_APLL_RATE_96000; break; default: - printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", + dev_err(codec->dev, "%s: unknown rate %d\n", __func__, params_rate(params)); return -EINVAL; } @@ -1818,7 +1817,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, format |= TWL4030_DATA_WIDTH_32S_24W; break; default: - printk(KERN_ERR "TWL4030 hw params: unknown format %d\n", + dev_err(codec->dev, "%s: unknown format %d\n", __func__, params_format(params)); return -EINVAL; } @@ -1868,13 +1867,13 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, case 38400000: break; default: - dev_err(codec->dev, "Unsupported APLL mclk: %u\n", freq); + dev_err(codec->dev, "Unsupported HFCLKIN: %u\n", freq); return -EINVAL; } if ((freq / 1000) != twl4030->sysclk) { dev_err(codec->dev, - "Mismatch in APLL mclk: %u (configured: %u)\n", + "Mismatch in HFCLKIN: %u (configured: %u)\n", freq, twl4030->sysclk * 1000); return -EINVAL; } @@ -1984,9 +1983,9 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream, * not available. */ if (twl4030->sysclk != 26000) { - dev_err(codec->dev, "The board is configured for %u Hz, while" - "the Voice interface needs 26MHz APLL mclk\n", - twl4030->sysclk * 1000); + dev_err(codec->dev, + "%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n", + __func__, twl4030->sysclk); return -EINVAL; } @@ -1997,8 +1996,8 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream, & TWL4030_OPT_MODE; if (mode != TWL4030_OPTION_2) { - printk(KERN_ERR "TWL4030 voice startup: " - "the codec mode is not option2\n"); + dev_err(codec->dev, "%s: the codec mode is not option2\n", + __func__); return -EINVAL; } @@ -2039,7 +2038,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, mode |= TWL4030_SEL_16K; break; default: - printk(KERN_ERR "TWL4030 voice hw params: unknown rate %d\n", + dev_err(codec->dev, "%s: unknown rate %d\n", __func__, params_rate(params)); return -EINVAL; } @@ -2068,13 +2067,14 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); if (freq != 26000000) { - dev_err(codec->dev, "Unsupported APLL mclk: %u, the Voice" - "interface needs 26MHz APLL mclk\n", freq); + dev_err(codec->dev, + "%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n", + __func__, freq / 1000); return -EINVAL; } if ((freq / 1000) != twl4030->sysclk) { dev_err(codec->dev, - "Mismatch in APLL mclk: %u (configured: %u)\n", + "Mismatch in HFCLKIN: %u (configured: %u)\n", freq, twl4030->sysclk * 1000); return -EINVAL; } @@ -2175,13 +2175,15 @@ static struct snd_soc_dai_driver twl4030_dai[] = { .channels_min = 2, .channels_max = 4, .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000, - .formats = TWL4030_FORMATS,}, + .formats = TWL4030_FORMATS, + .sig_bits = 24,}, .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 4, .rates = TWL4030_RATES, - .formats = TWL4030_FORMATS,}, + .formats = TWL4030_FORMATS, + .sig_bits = 24,}, .ops = &twl4030_dai_hifi_ops, }, { @@ -2220,13 +2222,12 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec) twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL); if (twl4030 == NULL) { - printk("Can not allocate memroy\n"); + dev_err(codec->dev, "Can not allocate memory\n"); return -ENOMEM; } snd_soc_codec_set_drvdata(codec, twl4030); /* Set the defaults, and power up the codec */ twl4030->sysclk = twl4030_audio_get_mclk() / 1000; - codec->dapm.idle_bias_off = 1; twl4030_init_chip(codec); @@ -2252,6 +2253,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { .read = twl4030_read_reg_cache, .write = twl4030_write, .set_bias_level = twl4030_set_bias_level, + .idle_bias_off = true, .reg_cache_size = sizeof(twl4030_reg), .reg_word_size = sizeof(u8), .reg_cache_default = twl4030_reg, diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 5b9c79b6f65..2d8c6b825e5 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1052,6 +1052,19 @@ int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim) } EXPORT_SYMBOL_GPL(twl6040_get_trim_value); +int twl6040_get_hs_step_size(struct snd_soc_codec *codec) +{ + struct twl6040 *twl6040 = codec->control_data; + + if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_2) + /* For ES under ES_1.3 HS step is 2 mV */ + return 2; + else + /* For ES_1.3 HS step is 1 mV */ + return 1; +} +EXPORT_SYMBOL_GPL(twl6040_get_hs_step_size); + static const struct snd_kcontrol_new twl6040_snd_controls[] = { /* Capture gains */ SOC_DOUBLE_TLV("Capture Preamplifier Volume", @@ -1125,14 +1138,14 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { TWL6040_REG_MICRCTL, 2, 0), /* Microphone bias */ - SND_SOC_DAPM_MICBIAS("Headset Mic Bias", - TWL6040_REG_AMICBCTL, 0, 0), - SND_SOC_DAPM_MICBIAS("Main Mic Bias", - TWL6040_REG_AMICBCTL, 4, 0), - SND_SOC_DAPM_MICBIAS("Digital Mic1 Bias", - TWL6040_REG_DMICBCTL, 0, 0), - SND_SOC_DAPM_MICBIAS("Digital Mic2 Bias", - TWL6040_REG_DMICBCTL, 4, 0), + SND_SOC_DAPM_SUPPLY("Headset Mic Bias", + TWL6040_REG_AMICBCTL, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Main Mic Bias", + TWL6040_REG_AMICBCTL, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias", + TWL6040_REG_DMICBCTL, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias", + TWL6040_REG_DMICBCTL, 4, 0, NULL, 0), /* DACs */ SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback", SND_SOC_NOPM, 0, 0), @@ -1527,7 +1540,6 @@ static int twl6040_probe(struct snd_soc_codec *codec) priv->codec = codec; codec->control_data = dev_get_drvdata(codec->dev->parent); - codec->ignore_pmdown_time = 1; if (pdata && pdata->hs_left_step && pdata->hs_right_step) { priv->hs_left_step = pdata->hs_left_step; @@ -1613,6 +1625,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { .reg_cache_size = ARRAY_SIZE(twl6040_reg), .reg_word_size = sizeof(u8), .reg_cache_default = twl6040_reg, + .ignore_pmdown_time = true, .controls = twl6040_snd_controls, .num_controls = ARRAY_SIZE(twl6040_snd_controls), diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h index ef273f1fac2..0611406ca7c 100644 --- a/sound/soc/codecs/twl6040.h +++ b/sound/soc/codecs/twl6040.h @@ -39,5 +39,6 @@ void twl6040_hs_jack_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int report); int twl6040_get_clk_id(struct snd_soc_codec *codec); int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim); +int twl6040_get_hs_step_size(struct snd_soc_codec *codec); #endif /* End of __TWL6040_H__ */ diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 8f4f469d641..797b0dde2c6 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -531,15 +531,15 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) switch (pd->model) { case UDA134X_UDA1340: case UDA134X_UDA1344: - ret = snd_soc_add_controls(codec, uda1340_snd_controls, + ret = snd_soc_add_codec_controls(codec, uda1340_snd_controls, ARRAY_SIZE(uda1340_snd_controls)); break; case UDA134X_UDA1341: - ret = snd_soc_add_controls(codec, uda1341_snd_controls, + ret = snd_soc_add_codec_controls(codec, uda1341_snd_controls, ARRAY_SIZE(uda1341_snd_controls)); break; case UDA134X_UDA1345: - ret = snd_soc_add_controls(codec, uda1345_snd_controls, + ret = snd_soc_add_codec_controls(codec, uda1345_snd_controls, ARRAY_SIZE(uda1345_snd_controls)); break; default: diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index 44aacf927ba..3d868dc4009 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -464,7 +464,7 @@ static int wl1273_probe(struct snd_soc_codec *codec) snd_soc_codec_set_drvdata(codec, wl1273); - r = snd_soc_add_controls(codec, wl1273_controls, + r = snd_soc_add_codec_controls(codec, wl1273_controls, ARRAY_SIZE(wl1273_controls)); if (r) kfree(wl1273); diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c new file mode 100644 index 00000000000..acbdc5fde92 --- /dev/null +++ b/sound/soc/codecs/wm2200.c @@ -0,0 +1,2286 @@ +/* + * wm2200.c -- WM2200 ALSA SoC Audio driver + * + * Copyright 2012 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/gcd.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/fixed.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/wm2200.h> + +#include "wm2200.h" + +/* The code assumes DCVDD is generated internally */ +#define WM2200_NUM_CORE_SUPPLIES 2 +static const char *wm2200_core_supply_names[WM2200_NUM_CORE_SUPPLIES] = { + "DBVDD", + "LDOVDD", +}; + +struct wm2200_fll { + int fref; + int fout; + int src; + struct completion lock; +}; + +/* codec private data */ +struct wm2200_priv { + struct regmap *regmap; + struct device *dev; + struct snd_soc_codec *codec; + struct wm2200_pdata pdata; + struct regulator_bulk_data core_supplies[WM2200_NUM_CORE_SUPPLIES]; + + struct completion fll_lock; + int fll_fout; + int fll_fref; + int fll_src; + + int rev; + int sysclk; +}; + +static struct reg_default wm2200_reg_defaults[] = { + { 0x000B, 0x0000 }, /* R11 - Tone Generator 1 */ + { 0x0102, 0x0000 }, /* R258 - Clocking 3 */ + { 0x0103, 0x0011 }, /* R259 - Clocking 4 */ + { 0x0111, 0x0000 }, /* R273 - FLL Control 1 */ + { 0x0112, 0x0000 }, /* R274 - FLL Control 2 */ + { 0x0113, 0x0000 }, /* R275 - FLL Control 3 */ + { 0x0114, 0x0000 }, /* R276 - FLL Control 4 */ + { 0x0116, 0x0177 }, /* R278 - FLL Control 6 */ + { 0x0117, 0x0004 }, /* R279 - FLL Control 7 */ + { 0x0119, 0x0000 }, /* R281 - FLL EFS 1 */ + { 0x011A, 0x0002 }, /* R282 - FLL EFS 2 */ + { 0x0200, 0x0000 }, /* R512 - Mic Charge Pump 1 */ + { 0x0201, 0x03FF }, /* R513 - Mic Charge Pump 2 */ + { 0x0202, 0x9BDE }, /* R514 - DM Charge Pump 1 */ + { 0x020C, 0x0000 }, /* R524 - Mic Bias Ctrl 1 */ + { 0x020D, 0x0000 }, /* R525 - Mic Bias Ctrl 2 */ + { 0x020F, 0x0000 }, /* R527 - Ear Piece Ctrl 1 */ + { 0x0210, 0x0000 }, /* R528 - Ear Piece Ctrl 2 */ + { 0x0301, 0x0000 }, /* R769 - Input Enables */ + { 0x0302, 0x2240 }, /* R770 - IN1L Control */ + { 0x0303, 0x0040 }, /* R771 - IN1R Control */ + { 0x0304, 0x2240 }, /* R772 - IN2L Control */ + { 0x0305, 0x0040 }, /* R773 - IN2R Control */ + { 0x0306, 0x2240 }, /* R774 - IN3L Control */ + { 0x0307, 0x0040 }, /* R775 - IN3R Control */ + { 0x030A, 0x0000 }, /* R778 - RXANC_SRC */ + { 0x030B, 0x0022 }, /* R779 - Input Volume Ramp */ + { 0x030C, 0x0180 }, /* R780 - ADC Digital Volume 1L */ + { 0x030D, 0x0180 }, /* R781 - ADC Digital Volume 1R */ + { 0x030E, 0x0180 }, /* R782 - ADC Digital Volume 2L */ + { 0x030F, 0x0180 }, /* R783 - ADC Digital Volume 2R */ + { 0x0310, 0x0180 }, /* R784 - ADC Digital Volume 3L */ + { 0x0311, 0x0180 }, /* R785 - ADC Digital Volume 3R */ + { 0x0400, 0x0000 }, /* R1024 - Output Enables */ + { 0x0401, 0x0000 }, /* R1025 - DAC Volume Limit 1L */ + { 0x0402, 0x0000 }, /* R1026 - DAC Volume Limit 1R */ + { 0x0403, 0x0000 }, /* R1027 - DAC Volume Limit 2L */ + { 0x0404, 0x0000 }, /* R1028 - DAC Volume Limit 2R */ + { 0x0409, 0x0000 }, /* R1033 - DAC AEC Control 1 */ + { 0x040A, 0x0022 }, /* R1034 - Output Volume Ramp */ + { 0x040B, 0x0180 }, /* R1035 - DAC Digital Volume 1L */ + { 0x040C, 0x0180 }, /* R1036 - DAC Digital Volume 1R */ + { 0x040D, 0x0180 }, /* R1037 - DAC Digital Volume 2L */ + { 0x040E, 0x0180 }, /* R1038 - DAC Digital Volume 2R */ + { 0x0417, 0x0069 }, /* R1047 - PDM 1 */ + { 0x0418, 0x0000 }, /* R1048 - PDM 2 */ + { 0x0500, 0x0000 }, /* R1280 - Audio IF 1_1 */ + { 0x0501, 0x0008 }, /* R1281 - Audio IF 1_2 */ + { 0x0502, 0x0000 }, /* R1282 - Audio IF 1_3 */ + { 0x0503, 0x0000 }, /* R1283 - Audio IF 1_4 */ + { 0x0504, 0x0000 }, /* R1284 - Audio IF 1_5 */ + { 0x0505, 0x0001 }, /* R1285 - Audio IF 1_6 */ + { 0x0506, 0x0001 }, /* R1286 - Audio IF 1_7 */ + { 0x0507, 0x0000 }, /* R1287 - Audio IF 1_8 */ + { 0x0508, 0x0000 }, /* R1288 - Audio IF 1_9 */ + { 0x0509, 0x0000 }, /* R1289 - Audio IF 1_10 */ + { 0x050A, 0x0000 }, /* R1290 - Audio IF 1_11 */ + { 0x050B, 0x0000 }, /* R1291 - Audio IF 1_12 */ + { 0x050C, 0x0000 }, /* R1292 - Audio IF 1_13 */ + { 0x050D, 0x0000 }, /* R1293 - Audio IF 1_14 */ + { 0x050E, 0x0000 }, /* R1294 - Audio IF 1_15 */ + { 0x050F, 0x0000 }, /* R1295 - Audio IF 1_16 */ + { 0x0510, 0x0000 }, /* R1296 - Audio IF 1_17 */ + { 0x0511, 0x0000 }, /* R1297 - Audio IF 1_18 */ + { 0x0512, 0x0000 }, /* R1298 - Audio IF 1_19 */ + { 0x0513, 0x0000 }, /* R1299 - Audio IF 1_20 */ + { 0x0514, 0x0000 }, /* R1300 - Audio IF 1_21 */ + { 0x0515, 0x0001 }, /* R1301 - Audio IF 1_22 */ + { 0x0600, 0x0000 }, /* R1536 - OUT1LMIX Input 1 Source */ + { 0x0601, 0x0080 }, /* R1537 - OUT1LMIX Input 1 Volume */ + { 0x0602, 0x0000 }, /* R1538 - OUT1LMIX Input 2 Source */ + { 0x0603, 0x0080 }, /* R1539 - OUT1LMIX Input 2 Volume */ + { 0x0604, 0x0000 }, /* R1540 - OUT1LMIX Input 3 Source */ + { 0x0605, 0x0080 }, /* R1541 - OUT1LMIX Input 3 Volume */ + { 0x0606, 0x0000 }, /* R1542 - OUT1LMIX Input 4 Source */ + { 0x0607, 0x0080 }, /* R1543 - OUT1LMIX Input 4 Volume */ + { 0x0608, 0x0000 }, /* R1544 - OUT1RMIX Input 1 Source */ + { 0x0609, 0x0080 }, /* R1545 - OUT1RMIX Input 1 Volume */ + { 0x060A, 0x0000 }, /* R1546 - OUT1RMIX Input 2 Source */ + { 0x060B, 0x0080 }, /* R1547 - OUT1RMIX Input 2 Volume */ + { 0x060C, 0x0000 }, /* R1548 - OUT1RMIX Input 3 Source */ + { 0x060D, 0x0080 }, /* R1549 - OUT1RMIX Input 3 Volume */ + { 0x060E, 0x0000 }, /* R1550 - OUT1RMIX Input 4 Source */ + { 0x060F, 0x0080 }, /* R1551 - OUT1RMIX Input 4 Volume */ + { 0x0610, 0x0000 }, /* R1552 - OUT2LMIX Input 1 Source */ + { 0x0611, 0x0080 }, /* R1553 - OUT2LMIX Input 1 Volume */ + { 0x0612, 0x0000 }, /* R1554 - OUT2LMIX Input 2 Source */ + { 0x0613, 0x0080 }, /* R1555 - OUT2LMIX Input 2 Volume */ + { 0x0614, 0x0000 }, /* R1556 - OUT2LMIX Input 3 Source */ + { 0x0615, 0x0080 }, /* R1557 - OUT2LMIX Input 3 Volume */ + { 0x0616, 0x0000 }, /* R1558 - OUT2LMIX Input 4 Source */ + { 0x0617, 0x0080 }, /* R1559 - OUT2LMIX Input 4 Volume */ + { 0x0618, 0x0000 }, /* R1560 - OUT2RMIX Input 1 Source */ + { 0x0619, 0x0080 }, /* R1561 - OUT2RMIX Input 1 Volume */ + { 0x061A, 0x0000 }, /* R1562 - OUT2RMIX Input 2 Source */ + { 0x061B, 0x0080 }, /* R1563 - OUT2RMIX Input 2 Volume */ + { 0x061C, 0x0000 }, /* R1564 - OUT2RMIX Input 3 Source */ + { 0x061D, 0x0080 }, /* R1565 - OUT2RMIX Input 3 Volume */ + { 0x061E, 0x0000 }, /* R1566 - OUT2RMIX Input 4 Source */ + { 0x061F, 0x0080 }, /* R1567 - OUT2RMIX Input 4 Volume */ + { 0x0620, 0x0000 }, /* R1568 - AIF1TX1MIX Input 1 Source */ + { 0x0621, 0x0080 }, /* R1569 - AIF1TX1MIX Input 1 Volume */ + { 0x0622, 0x0000 }, /* R1570 - AIF1TX1MIX Input 2 Source */ + { 0x0623, 0x0080 }, /* R1571 - AIF1TX1MIX Input 2 Volume */ + { 0x0624, 0x0000 }, /* R1572 - AIF1TX1MIX Input 3 Source */ + { 0x0625, 0x0080 }, /* R1573 - AIF1TX1MIX Input 3 Volume */ + { 0x0626, 0x0000 }, /* R1574 - AIF1TX1MIX Input 4 Source */ + { 0x0627, 0x0080 }, /* R1575 - AIF1TX1MIX Input 4 Volume */ + { 0x0628, 0x0000 }, /* R1576 - AIF1TX2MIX Input 1 Source */ + { 0x0629, 0x0080 }, /* R1577 - AIF1TX2MIX Input 1 Volume */ + { 0x062A, 0x0000 }, /* R1578 - AIF1TX2MIX Input 2 Source */ + { 0x062B, 0x0080 }, /* R1579 - AIF1TX2MIX Input 2 Volume */ + { 0x062C, 0x0000 }, /* R1580 - AIF1TX2MIX Input 3 Source */ + { 0x062D, 0x0080 }, /* R1581 - AIF1TX2MIX Input 3 Volume */ + { 0x062E, 0x0000 }, /* R1582 - AIF1TX2MIX Input 4 Source */ + { 0x062F, 0x0080 }, /* R1583 - AIF1TX2MIX Input 4 Volume */ + { 0x0630, 0x0000 }, /* R1584 - AIF1TX3MIX Input 1 Source */ + { 0x0631, 0x0080 }, /* R1585 - AIF1TX3MIX Input 1 Volume */ + { 0x0632, 0x0000 }, /* R1586 - AIF1TX3MIX Input 2 Source */ + { 0x0633, 0x0080 }, /* R1587 - AIF1TX3MIX Input 2 Volume */ + { 0x0634, 0x0000 }, /* R1588 - AIF1TX3MIX Input 3 Source */ + { 0x0635, 0x0080 }, /* R1589 - AIF1TX3MIX Input 3 Volume */ + { 0x0636, 0x0000 }, /* R1590 - AIF1TX3MIX Input 4 Source */ + { 0x0637, 0x0080 }, /* R1591 - AIF1TX3MIX Input 4 Volume */ + { 0x0638, 0x0000 }, /* R1592 - AIF1TX4MIX Input 1 Source */ + { 0x0639, 0x0080 }, /* R1593 - AIF1TX4MIX Input 1 Volume */ + { 0x063A, 0x0000 }, /* R1594 - AIF1TX4MIX Input 2 Source */ + { 0x063B, 0x0080 }, /* R1595 - AIF1TX4MIX Input 2 Volume */ + { 0x063C, 0x0000 }, /* R1596 - AIF1TX4MIX Input 3 Source */ + { 0x063D, 0x0080 }, /* R1597 - AIF1TX4MIX Input 3 Volume */ + { 0x063E, 0x0000 }, /* R1598 - AIF1TX4MIX Input 4 Source */ + { 0x063F, 0x0080 }, /* R1599 - AIF1TX4MIX Input 4 Volume */ + { 0x0640, 0x0000 }, /* R1600 - AIF1TX5MIX Input 1 Source */ + { 0x0641, 0x0080 }, /* R1601 - AIF1TX5MIX Input 1 Volume */ + { 0x0642, 0x0000 }, /* R1602 - AIF1TX5MIX Input 2 Source */ + { 0x0643, 0x0080 }, /* R1603 - AIF1TX5MIX Input 2 Volume */ + { 0x0644, 0x0000 }, /* R1604 - AIF1TX5MIX Input 3 Source */ + { 0x0645, 0x0080 }, /* R1605 - AIF1TX5MIX Input 3 Volume */ + { 0x0646, 0x0000 }, /* R1606 - AIF1TX5MIX Input 4 Source */ + { 0x0647, 0x0080 }, /* R1607 - AIF1TX5MIX Input 4 Volume */ + { 0x0648, 0x0000 }, /* R1608 - AIF1TX6MIX Input 1 Source */ + { 0x0649, 0x0080 }, /* R1609 - AIF1TX6MIX Input 1 Volume */ + { 0x064A, 0x0000 }, /* R1610 - AIF1TX6MIX Input 2 Source */ + { 0x064B, 0x0080 }, /* R1611 - AIF1TX6MIX Input 2 Volume */ + { 0x064C, 0x0000 }, /* R1612 - AIF1TX6MIX Input 3 Source */ + { 0x064D, 0x0080 }, /* R1613 - AIF1TX6MIX Input 3 Volume */ + { 0x064E, 0x0000 }, /* R1614 - AIF1TX6MIX Input 4 Source */ + { 0x064F, 0x0080 }, /* R1615 - AIF1TX6MIX Input 4 Volume */ + { 0x0650, 0x0000 }, /* R1616 - EQLMIX Input 1 Source */ + { 0x0651, 0x0080 }, /* R1617 - EQLMIX Input 1 Volume */ + { 0x0652, 0x0000 }, /* R1618 - EQLMIX Input 2 Source */ + { 0x0653, 0x0080 }, /* R1619 - EQLMIX Input 2 Volume */ + { 0x0654, 0x0000 }, /* R1620 - EQLMIX Input 3 Source */ + { 0x0655, 0x0080 }, /* R1621 - EQLMIX Input 3 Volume */ + { 0x0656, 0x0000 }, /* R1622 - EQLMIX Input 4 Source */ + { 0x0657, 0x0080 }, /* R1623 - EQLMIX Input 4 Volume */ + { 0x0658, 0x0000 }, /* R1624 - EQRMIX Input 1 Source */ + { 0x0659, 0x0080 }, /* R1625 - EQRMIX Input 1 Volume */ + { 0x065A, 0x0000 }, /* R1626 - EQRMIX Input 2 Source */ + { 0x065B, 0x0080 }, /* R1627 - EQRMIX Input 2 Volume */ + { 0x065C, 0x0000 }, /* R1628 - EQRMIX Input 3 Source */ + { 0x065D, 0x0080 }, /* R1629 - EQRMIX Input 3 Volume */ + { 0x065E, 0x0000 }, /* R1630 - EQRMIX Input 4 Source */ + { 0x065F, 0x0080 }, /* R1631 - EQRMIX Input 4 Volume */ + { 0x0660, 0x0000 }, /* R1632 - LHPF1MIX Input 1 Source */ + { 0x0661, 0x0080 }, /* R1633 - LHPF1MIX Input 1 Volume */ + { 0x0662, 0x0000 }, /* R1634 - LHPF1MIX Input 2 Source */ + { 0x0663, 0x0080 }, /* R1635 - LHPF1MIX Input 2 Volume */ + { 0x0664, 0x0000 }, /* R1636 - LHPF1MIX Input 3 Source */ + { 0x0665, 0x0080 }, /* R1637 - LHPF1MIX Input 3 Volume */ + { 0x0666, 0x0000 }, /* R1638 - LHPF1MIX Input 4 Source */ + { 0x0667, 0x0080 }, /* R1639 - LHPF1MIX Input 4 Volume */ + { 0x0668, 0x0000 }, /* R1640 - LHPF2MIX Input 1 Source */ + { 0x0669, 0x0080 }, /* R1641 - LHPF2MIX Input 1 Volume */ + { 0x066A, 0x0000 }, /* R1642 - LHPF2MIX Input 2 Source */ + { 0x066B, 0x0080 }, /* R1643 - LHPF2MIX Input 2 Volume */ + { 0x066C, 0x0000 }, /* R1644 - LHPF2MIX Input 3 Source */ + { 0x066D, 0x0080 }, /* R1645 - LHPF2MIX Input 3 Volume */ + { 0x066E, 0x0000 }, /* R1646 - LHPF2MIX Input 4 Source */ + { 0x066F, 0x0080 }, /* R1647 - LHPF2MIX Input 4 Volume */ + { 0x0670, 0x0000 }, /* R1648 - DSP1LMIX Input 1 Source */ + { 0x0671, 0x0080 }, /* R1649 - DSP1LMIX Input 1 Volume */ + { 0x0672, 0x0000 }, /* R1650 - DSP1LMIX Input 2 Source */ + { 0x0673, 0x0080 }, /* R1651 - DSP1LMIX Input 2 Volume */ + { 0x0674, 0x0000 }, /* R1652 - DSP1LMIX Input 3 Source */ + { 0x0675, 0x0080 }, /* R1653 - DSP1LMIX Input 3 Volume */ + { 0x0676, 0x0000 }, /* R1654 - DSP1LMIX Input 4 Source */ + { 0x0677, 0x0080 }, /* R1655 - DSP1LMIX Input 4 Volume */ + { 0x0678, 0x0000 }, /* R1656 - DSP1RMIX Input 1 Source */ + { 0x0679, 0x0080 }, /* R1657 - DSP1RMIX Input 1 Volume */ + { 0x067A, 0x0000 }, /* R1658 - DSP1RMIX Input 2 Source */ + { 0x067B, 0x0080 }, /* R1659 - DSP1RMIX Input 2 Volume */ + { 0x067C, 0x0000 }, /* R1660 - DSP1RMIX Input 3 Source */ + { 0x067D, 0x0080 }, /* R1661 - DSP1RMIX Input 3 Volume */ + { 0x067E, 0x0000 }, /* R1662 - DSP1RMIX Input 4 Source */ + { 0x067F, 0x0080 }, /* R1663 - DSP1RMIX Input 4 Volume */ + { 0x0680, 0x0000 }, /* R1664 - DSP1AUX1MIX Input 1 Source */ + { 0x0681, 0x0000 }, /* R1665 - DSP1AUX2MIX Input 1 Source */ + { 0x0682, 0x0000 }, /* R1666 - DSP1AUX3MIX Input 1 Source */ + { 0x0683, 0x0000 }, /* R1667 - DSP1AUX4MIX Input 1 Source */ + { 0x0684, 0x0000 }, /* R1668 - DSP1AUX5MIX Input 1 Source */ + { 0x0685, 0x0000 }, /* R1669 - DSP1AUX6MIX Input 1 Source */ + { 0x0686, 0x0000 }, /* R1670 - DSP2LMIX Input 1 Source */ + { 0x0687, 0x0080 }, /* R1671 - DSP2LMIX Input 1 Volume */ + { 0x0688, 0x0000 }, /* R1672 - DSP2LMIX Input 2 Source */ + { 0x0689, 0x0080 }, /* R1673 - DSP2LMIX Input 2 Volume */ + { 0x068A, 0x0000 }, /* R1674 - DSP2LMIX Input 3 Source */ + { 0x068B, 0x0080 }, /* R1675 - DSP2LMIX Input 3 Volume */ + { 0x068C, 0x0000 }, /* R1676 - DSP2LMIX Input 4 Source */ + { 0x068D, 0x0080 }, /* R1677 - DSP2LMIX Input 4 Volume */ + { 0x068E, 0x0000 }, /* R1678 - DSP2RMIX Input 1 Source */ + { 0x068F, 0x0080 }, /* R1679 - DSP2RMIX Input 1 Volume */ + { 0x0690, 0x0000 }, /* R1680 - DSP2RMIX Input 2 Source */ + { 0x0691, 0x0080 }, /* R1681 - DSP2RMIX Input 2 Volume */ + { 0x0692, 0x0000 }, /* R1682 - DSP2RMIX Input 3 Source */ + { 0x0693, 0x0080 }, /* R1683 - DSP2RMIX Input 3 Volume */ + { 0x0694, 0x0000 }, /* R1684 - DSP2RMIX Input 4 Source */ + { 0x0695, 0x0080 }, /* R1685 - DSP2RMIX Input 4 Volume */ + { 0x0696, 0x0000 }, /* R1686 - DSP2AUX1MIX Input 1 Source */ + { 0x0697, 0x0000 }, /* R1687 - DSP2AUX2MIX Input 1 Source */ + { 0x0698, 0x0000 }, /* R1688 - DSP2AUX3MIX Input 1 Source */ + { 0x0699, 0x0000 }, /* R1689 - DSP2AUX4MIX Input 1 Source */ + { 0x069A, 0x0000 }, /* R1690 - DSP2AUX5MIX Input 1 Source */ + { 0x069B, 0x0000 }, /* R1691 - DSP2AUX6MIX Input 1 Source */ + { 0x0700, 0xA101 }, /* R1792 - GPIO CTRL 1 */ + { 0x0701, 0xA101 }, /* R1793 - GPIO CTRL 2 */ + { 0x0702, 0xA101 }, /* R1794 - GPIO CTRL 3 */ + { 0x0703, 0xA101 }, /* R1795 - GPIO CTRL 4 */ + { 0x0709, 0x0000 }, /* R1801 - Misc Pad Ctrl 1 */ + { 0x0801, 0x00FF }, /* R2049 - Interrupt Status 1 Mask */ + { 0x0804, 0xFFFF }, /* R2052 - Interrupt Status 2 Mask */ + { 0x0808, 0x0000 }, /* R2056 - Interrupt Control */ + { 0x0900, 0x0000 }, /* R2304 - EQL_1 */ + { 0x0901, 0x0000 }, /* R2305 - EQL_2 */ + { 0x0902, 0x0000 }, /* R2306 - EQL_3 */ + { 0x0903, 0x0000 }, /* R2307 - EQL_4 */ + { 0x0904, 0x0000 }, /* R2308 - EQL_5 */ + { 0x0905, 0x0000 }, /* R2309 - EQL_6 */ + { 0x0906, 0x0000 }, /* R2310 - EQL_7 */ + { 0x0907, 0x0000 }, /* R2311 - EQL_8 */ + { 0x0908, 0x0000 }, /* R2312 - EQL_9 */ + { 0x0909, 0x0000 }, /* R2313 - EQL_10 */ + { 0x090A, 0x0000 }, /* R2314 - EQL_11 */ + { 0x090B, 0x0000 }, /* R2315 - EQL_12 */ + { 0x090C, 0x0000 }, /* R2316 - EQL_13 */ + { 0x090D, 0x0000 }, /* R2317 - EQL_14 */ + { 0x090E, 0x0000 }, /* R2318 - EQL_15 */ + { 0x090F, 0x0000 }, /* R2319 - EQL_16 */ + { 0x0910, 0x0000 }, /* R2320 - EQL_17 */ + { 0x0911, 0x0000 }, /* R2321 - EQL_18 */ + { 0x0912, 0x0000 }, /* R2322 - EQL_19 */ + { 0x0913, 0x0000 }, /* R2323 - EQL_20 */ + { 0x0916, 0x0000 }, /* R2326 - EQR_1 */ + { 0x0917, 0x0000 }, /* R2327 - EQR_2 */ + { 0x0918, 0x0000 }, /* R2328 - EQR_3 */ + { 0x0919, 0x0000 }, /* R2329 - EQR_4 */ + { 0x091A, 0x0000 }, /* R2330 - EQR_5 */ + { 0x091B, 0x0000 }, /* R2331 - EQR_6 */ + { 0x091C, 0x0000 }, /* R2332 - EQR_7 */ + { 0x091D, 0x0000 }, /* R2333 - EQR_8 */ + { 0x091E, 0x0000 }, /* R2334 - EQR_9 */ + { 0x091F, 0x0000 }, /* R2335 - EQR_10 */ + { 0x0920, 0x0000 }, /* R2336 - EQR_11 */ + { 0x0921, 0x0000 }, /* R2337 - EQR_12 */ + { 0x0922, 0x0000 }, /* R2338 - EQR_13 */ + { 0x0923, 0x0000 }, /* R2339 - EQR_14 */ + { 0x0924, 0x0000 }, /* R2340 - EQR_15 */ + { 0x0925, 0x0000 }, /* R2341 - EQR_16 */ + { 0x0926, 0x0000 }, /* R2342 - EQR_17 */ + { 0x0927, 0x0000 }, /* R2343 - EQR_18 */ + { 0x0928, 0x0000 }, /* R2344 - EQR_19 */ + { 0x0929, 0x0000 }, /* R2345 - EQR_20 */ + { 0x093E, 0x0000 }, /* R2366 - HPLPF1_1 */ + { 0x093F, 0x0000 }, /* R2367 - HPLPF1_2 */ + { 0x0942, 0x0000 }, /* R2370 - HPLPF2_1 */ + { 0x0943, 0x0000 }, /* R2371 - HPLPF2_2 */ + { 0x0A00, 0x0000 }, /* R2560 - DSP1 Control 1 */ + { 0x0A02, 0x0000 }, /* R2562 - DSP1 Control 2 */ + { 0x0A03, 0x0000 }, /* R2563 - DSP1 Control 3 */ + { 0x0A04, 0x0000 }, /* R2564 - DSP1 Control 4 */ + { 0x0A06, 0x0000 }, /* R2566 - DSP1 Control 5 */ + { 0x0A07, 0x0000 }, /* R2567 - DSP1 Control 6 */ + { 0x0A08, 0x0000 }, /* R2568 - DSP1 Control 7 */ + { 0x0A09, 0x0000 }, /* R2569 - DSP1 Control 8 */ + { 0x0A0A, 0x0000 }, /* R2570 - DSP1 Control 9 */ + { 0x0A0B, 0x0000 }, /* R2571 - DSP1 Control 10 */ + { 0x0A0C, 0x0000 }, /* R2572 - DSP1 Control 11 */ + { 0x0A0D, 0x0000 }, /* R2573 - DSP1 Control 12 */ + { 0x0A0F, 0x0000 }, /* R2575 - DSP1 Control 13 */ + { 0x0A10, 0x0000 }, /* R2576 - DSP1 Control 14 */ + { 0x0A11, 0x0000 }, /* R2577 - DSP1 Control 15 */ + { 0x0A12, 0x0000 }, /* R2578 - DSP1 Control 16 */ + { 0x0A13, 0x0000 }, /* R2579 - DSP1 Control 17 */ + { 0x0A14, 0x0000 }, /* R2580 - DSP1 Control 18 */ + { 0x0A16, 0x0000 }, /* R2582 - DSP1 Control 19 */ + { 0x0A17, 0x0000 }, /* R2583 - DSP1 Control 20 */ + { 0x0A18, 0x0000 }, /* R2584 - DSP1 Control 21 */ + { 0x0A1A, 0x1800 }, /* R2586 - DSP1 Control 22 */ + { 0x0A1B, 0x1000 }, /* R2587 - DSP1 Control 23 */ + { 0x0A1C, 0x0400 }, /* R2588 - DSP1 Control 24 */ + { 0x0A1E, 0x0000 }, /* R2590 - DSP1 Control 25 */ + { 0x0A20, 0x0000 }, /* R2592 - DSP1 Control 26 */ + { 0x0A21, 0x0000 }, /* R2593 - DSP1 Control 27 */ + { 0x0A22, 0x0000 }, /* R2594 - DSP1 Control 28 */ + { 0x0A23, 0x0000 }, /* R2595 - DSP1 Control 29 */ + { 0x0A24, 0x0000 }, /* R2596 - DSP1 Control 30 */ + { 0x0A26, 0x0000 }, /* R2598 - DSP1 Control 31 */ + { 0x0B00, 0x0000 }, /* R2816 - DSP2 Control 1 */ + { 0x0B02, 0x0000 }, /* R2818 - DSP2 Control 2 */ + { 0x0B03, 0x0000 }, /* R2819 - DSP2 Control 3 */ + { 0x0B04, 0x0000 }, /* R2820 - DSP2 Control 4 */ + { 0x0B06, 0x0000 }, /* R2822 - DSP2 Control 5 */ + { 0x0B07, 0x0000 }, /* R2823 - DSP2 Control 6 */ + { 0x0B08, 0x0000 }, /* R2824 - DSP2 Control 7 */ + { 0x0B09, 0x0000 }, /* R2825 - DSP2 Control 8 */ + { 0x0B0A, 0x0000 }, /* R2826 - DSP2 Control 9 */ + { 0x0B0B, 0x0000 }, /* R2827 - DSP2 Control 10 */ + { 0x0B0C, 0x0000 }, /* R2828 - DSP2 Control 11 */ + { 0x0B0D, 0x0000 }, /* R2829 - DSP2 Control 12 */ + { 0x0B0F, 0x0000 }, /* R2831 - DSP2 Control 13 */ + { 0x0B10, 0x0000 }, /* R2832 - DSP2 Control 14 */ + { 0x0B11, 0x0000 }, /* R2833 - DSP2 Control 15 */ + { 0x0B12, 0x0000 }, /* R2834 - DSP2 Control 16 */ + { 0x0B13, 0x0000 }, /* R2835 - DSP2 Control 17 */ + { 0x0B14, 0x0000 }, /* R2836 - DSP2 Control 18 */ + { 0x0B16, 0x0000 }, /* R2838 - DSP2 Control 19 */ + { 0x0B17, 0x0000 }, /* R2839 - DSP2 Control 20 */ + { 0x0B18, 0x0000 }, /* R2840 - DSP2 Control 21 */ + { 0x0B1A, 0x0800 }, /* R2842 - DSP2 Control 22 */ + { 0x0B1B, 0x1000 }, /* R2843 - DSP2 Control 23 */ + { 0x0B1C, 0x0400 }, /* R2844 - DSP2 Control 24 */ + { 0x0B1E, 0x0000 }, /* R2846 - DSP2 Control 25 */ + { 0x0B20, 0x0000 }, /* R2848 - DSP2 Control 26 */ + { 0x0B21, 0x0000 }, /* R2849 - DSP2 Control 27 */ + { 0x0B22, 0x0000 }, /* R2850 - DSP2 Control 28 */ + { 0x0B23, 0x0000 }, /* R2851 - DSP2 Control 29 */ + { 0x0B24, 0x0000 }, /* R2852 - DSP2 Control 30 */ + { 0x0B26, 0x0000 }, /* R2854 - DSP2 Control 31 */ +}; + +static bool wm2200_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM2200_SOFTWARE_RESET: + case WM2200_DEVICE_REVISION: + case WM2200_ADPS1_IRQ0: + case WM2200_ADPS1_IRQ1: + case WM2200_INTERRUPT_STATUS_1: + case WM2200_INTERRUPT_STATUS_2: + case WM2200_INTERRUPT_RAW_STATUS_2: + return true; + default: + return false; + } +} + +static bool wm2200_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM2200_SOFTWARE_RESET: + case WM2200_DEVICE_REVISION: + case WM2200_TONE_GENERATOR_1: + case WM2200_CLOCKING_3: + case WM2200_CLOCKING_4: + case WM2200_FLL_CONTROL_1: + case WM2200_FLL_CONTROL_2: + case WM2200_FLL_CONTROL_3: + case WM2200_FLL_CONTROL_4: + case WM2200_FLL_CONTROL_6: + case WM2200_FLL_CONTROL_7: + case WM2200_FLL_EFS_1: + case WM2200_FLL_EFS_2: + case WM2200_MIC_CHARGE_PUMP_1: + case WM2200_MIC_CHARGE_PUMP_2: + case WM2200_DM_CHARGE_PUMP_1: + case WM2200_MIC_BIAS_CTRL_1: + case WM2200_MIC_BIAS_CTRL_2: + case WM2200_EAR_PIECE_CTRL_1: + case WM2200_EAR_PIECE_CTRL_2: + case WM2200_INPUT_ENABLES: + case WM2200_IN1L_CONTROL: + case WM2200_IN1R_CONTROL: + case WM2200_IN2L_CONTROL: + case WM2200_IN2R_CONTROL: + case WM2200_IN3L_CONTROL: + case WM2200_IN3R_CONTROL: + case WM2200_RXANC_SRC: + case WM2200_INPUT_VOLUME_RAMP: + case WM2200_ADC_DIGITAL_VOLUME_1L: + case WM2200_ADC_DIGITAL_VOLUME_1R: + case WM2200_ADC_DIGITAL_VOLUME_2L: + case WM2200_ADC_DIGITAL_VOLUME_2R: + case WM2200_ADC_DIGITAL_VOLUME_3L: + case WM2200_ADC_DIGITAL_VOLUME_3R: + case WM2200_OUTPUT_ENABLES: + case WM2200_DAC_VOLUME_LIMIT_1L: + case WM2200_DAC_VOLUME_LIMIT_1R: + case WM2200_DAC_VOLUME_LIMIT_2L: + case WM2200_DAC_VOLUME_LIMIT_2R: + case WM2200_DAC_AEC_CONTROL_1: + case WM2200_OUTPUT_VOLUME_RAMP: + case WM2200_DAC_DIGITAL_VOLUME_1L: + case WM2200_DAC_DIGITAL_VOLUME_1R: + case WM2200_DAC_DIGITAL_VOLUME_2L: + case WM2200_DAC_DIGITAL_VOLUME_2R: + case WM2200_PDM_1: + case WM2200_PDM_2: + case WM2200_AUDIO_IF_1_1: + case WM2200_AUDIO_IF_1_2: + case WM2200_AUDIO_IF_1_3: + case WM2200_AUDIO_IF_1_4: + case WM2200_AUDIO_IF_1_5: + case WM2200_AUDIO_IF_1_6: + case WM2200_AUDIO_IF_1_7: + case WM2200_AUDIO_IF_1_8: + case WM2200_AUDIO_IF_1_9: + case WM2200_AUDIO_IF_1_10: + case WM2200_AUDIO_IF_1_11: + case WM2200_AUDIO_IF_1_12: + case WM2200_AUDIO_IF_1_13: + case WM2200_AUDIO_IF_1_14: + case WM2200_AUDIO_IF_1_15: + case WM2200_AUDIO_IF_1_16: + case WM2200_AUDIO_IF_1_17: + case WM2200_AUDIO_IF_1_18: + case WM2200_AUDIO_IF_1_19: + case WM2200_AUDIO_IF_1_20: + case WM2200_AUDIO_IF_1_21: + case WM2200_AUDIO_IF_1_22: + case WM2200_OUT1LMIX_INPUT_1_SOURCE: + case WM2200_OUT1LMIX_INPUT_1_VOLUME: + case WM2200_OUT1LMIX_INPUT_2_SOURCE: + case WM2200_OUT1LMIX_INPUT_2_VOLUME: + case WM2200_OUT1LMIX_INPUT_3_SOURCE: + case WM2200_OUT1LMIX_INPUT_3_VOLUME: + case WM2200_OUT1LMIX_INPUT_4_SOURCE: + case WM2200_OUT1LMIX_INPUT_4_VOLUME: + case WM2200_OUT1RMIX_INPUT_1_SOURCE: + case WM2200_OUT1RMIX_INPUT_1_VOLUME: + case WM2200_OUT1RMIX_INPUT_2_SOURCE: + case WM2200_OUT1RMIX_INPUT_2_VOLUME: + case WM2200_OUT1RMIX_INPUT_3_SOURCE: + case WM2200_OUT1RMIX_INPUT_3_VOLUME: + case WM2200_OUT1RMIX_INPUT_4_SOURCE: + case WM2200_OUT1RMIX_INPUT_4_VOLUME: + case WM2200_OUT2LMIX_INPUT_1_SOURCE: + case WM2200_OUT2LMIX_INPUT_1_VOLUME: + case WM2200_OUT2LMIX_INPUT_2_SOURCE: + case WM2200_OUT2LMIX_INPUT_2_VOLUME: + case WM2200_OUT2LMIX_INPUT_3_SOURCE: + case WM2200_OUT2LMIX_INPUT_3_VOLUME: + case WM2200_OUT2LMIX_INPUT_4_SOURCE: + case WM2200_OUT2LMIX_INPUT_4_VOLUME: + case WM2200_OUT2RMIX_INPUT_1_SOURCE: + case WM2200_OUT2RMIX_INPUT_1_VOLUME: + case WM2200_OUT2RMIX_INPUT_2_SOURCE: + case WM2200_OUT2RMIX_INPUT_2_VOLUME: + case WM2200_OUT2RMIX_INPUT_3_SOURCE: + case WM2200_OUT2RMIX_INPUT_3_VOLUME: + case WM2200_OUT2RMIX_INPUT_4_SOURCE: + case WM2200_OUT2RMIX_INPUT_4_VOLUME: + case WM2200_AIF1TX1MIX_INPUT_1_SOURCE: + case WM2200_AIF1TX1MIX_INPUT_1_VOLUME: + case WM2200_AIF1TX1MIX_INPUT_2_SOURCE: + case WM2200_AIF1TX1MIX_INPUT_2_VOLUME: + case WM2200_AIF1TX1MIX_INPUT_3_SOURCE: + case WM2200_AIF1TX1MIX_INPUT_3_VOLUME: + case WM2200_AIF1TX1MIX_INPUT_4_SOURCE: + case WM2200_AIF1TX1MIX_INPUT_4_VOLUME: + case WM2200_AIF1TX2MIX_INPUT_1_SOURCE: + case WM2200_AIF1TX2MIX_INPUT_1_VOLUME: + case WM2200_AIF1TX2MIX_INPUT_2_SOURCE: + case WM2200_AIF1TX2MIX_INPUT_2_VOLUME: + case WM2200_AIF1TX2MIX_INPUT_3_SOURCE: + case WM2200_AIF1TX2MIX_INPUT_3_VOLUME: + case WM2200_AIF1TX2MIX_INPUT_4_SOURCE: + case WM2200_AIF1TX2MIX_INPUT_4_VOLUME: + case WM2200_AIF1TX3MIX_INPUT_1_SOURCE: + case WM2200_AIF1TX3MIX_INPUT_1_VOLUME: + case WM2200_AIF1TX3MIX_INPUT_2_SOURCE: + case WM2200_AIF1TX3MIX_INPUT_2_VOLUME: + case WM2200_AIF1TX3MIX_INPUT_3_SOURCE: + case WM2200_AIF1TX3MIX_INPUT_3_VOLUME: + case WM2200_AIF1TX3MIX_INPUT_4_SOURCE: + case WM2200_AIF1TX3MIX_INPUT_4_VOLUME: + case WM2200_AIF1TX4MIX_INPUT_1_SOURCE: + case WM2200_AIF1TX4MIX_INPUT_1_VOLUME: + case WM2200_AIF1TX4MIX_INPUT_2_SOURCE: + case WM2200_AIF1TX4MIX_INPUT_2_VOLUME: + case WM2200_AIF1TX4MIX_INPUT_3_SOURCE: + case WM2200_AIF1TX4MIX_INPUT_3_VOLUME: + case WM2200_AIF1TX4MIX_INPUT_4_SOURCE: + case WM2200_AIF1TX4MIX_INPUT_4_VOLUME: + case WM2200_AIF1TX5MIX_INPUT_1_SOURCE: + case WM2200_AIF1TX5MIX_INPUT_1_VOLUME: + case WM2200_AIF1TX5MIX_INPUT_2_SOURCE: + case WM2200_AIF1TX5MIX_INPUT_2_VOLUME: + case WM2200_AIF1TX5MIX_INPUT_3_SOURCE: + case WM2200_AIF1TX5MIX_INPUT_3_VOLUME: + case WM2200_AIF1TX5MIX_INPUT_4_SOURCE: + case WM2200_AIF1TX5MIX_INPUT_4_VOLUME: + case WM2200_AIF1TX6MIX_INPUT_1_SOURCE: + case WM2200_AIF1TX6MIX_INPUT_1_VOLUME: + case WM2200_AIF1TX6MIX_INPUT_2_SOURCE: + case WM2200_AIF1TX6MIX_INPUT_2_VOLUME: + case WM2200_AIF1TX6MIX_INPUT_3_SOURCE: + case WM2200_AIF1TX6MIX_INPUT_3_VOLUME: + case WM2200_AIF1TX6MIX_INPUT_4_SOURCE: + case WM2200_AIF1TX6MIX_INPUT_4_VOLUME: + case WM2200_EQLMIX_INPUT_1_SOURCE: + case WM2200_EQLMIX_INPUT_1_VOLUME: + case WM2200_EQLMIX_INPUT_2_SOURCE: + case WM2200_EQLMIX_INPUT_2_VOLUME: + case WM2200_EQLMIX_INPUT_3_SOURCE: + case WM2200_EQLMIX_INPUT_3_VOLUME: + case WM2200_EQLMIX_INPUT_4_SOURCE: + case WM2200_EQLMIX_INPUT_4_VOLUME: + case WM2200_EQRMIX_INPUT_1_SOURCE: + case WM2200_EQRMIX_INPUT_1_VOLUME: + case WM2200_EQRMIX_INPUT_2_SOURCE: + case WM2200_EQRMIX_INPUT_2_VOLUME: + case WM2200_EQRMIX_INPUT_3_SOURCE: + case WM2200_EQRMIX_INPUT_3_VOLUME: + case WM2200_EQRMIX_INPUT_4_SOURCE: + case WM2200_EQRMIX_INPUT_4_VOLUME: + case WM2200_LHPF1MIX_INPUT_1_SOURCE: + case WM2200_LHPF1MIX_INPUT_1_VOLUME: + case WM2200_LHPF1MIX_INPUT_2_SOURCE: + case WM2200_LHPF1MIX_INPUT_2_VOLUME: + case WM2200_LHPF1MIX_INPUT_3_SOURCE: + case WM2200_LHPF1MIX_INPUT_3_VOLUME: + case WM2200_LHPF1MIX_INPUT_4_SOURCE: + case WM2200_LHPF1MIX_INPUT_4_VOLUME: + case WM2200_LHPF2MIX_INPUT_1_SOURCE: + case WM2200_LHPF2MIX_INPUT_1_VOLUME: + case WM2200_LHPF2MIX_INPUT_2_SOURCE: + case WM2200_LHPF2MIX_INPUT_2_VOLUME: + case WM2200_LHPF2MIX_INPUT_3_SOURCE: + case WM2200_LHPF2MIX_INPUT_3_VOLUME: + case WM2200_LHPF2MIX_INPUT_4_SOURCE: + case WM2200_LHPF2MIX_INPUT_4_VOLUME: + case WM2200_DSP1LMIX_INPUT_1_SOURCE: + case WM2200_DSP1LMIX_INPUT_1_VOLUME: + case WM2200_DSP1LMIX_INPUT_2_SOURCE: + case WM2200_DSP1LMIX_INPUT_2_VOLUME: + case WM2200_DSP1LMIX_INPUT_3_SOURCE: + case WM2200_DSP1LMIX_INPUT_3_VOLUME: + case WM2200_DSP1LMIX_INPUT_4_SOURCE: + case WM2200_DSP1LMIX_INPUT_4_VOLUME: + case WM2200_DSP1RMIX_INPUT_1_SOURCE: + case WM2200_DSP1RMIX_INPUT_1_VOLUME: + case WM2200_DSP1RMIX_INPUT_2_SOURCE: + case WM2200_DSP1RMIX_INPUT_2_VOLUME: + case WM2200_DSP1RMIX_INPUT_3_SOURCE: + case WM2200_DSP1RMIX_INPUT_3_VOLUME: + case WM2200_DSP1RMIX_INPUT_4_SOURCE: + case WM2200_DSP1RMIX_INPUT_4_VOLUME: + case WM2200_DSP1AUX1MIX_INPUT_1_SOURCE: + case WM2200_DSP1AUX2MIX_INPUT_1_SOURCE: + case WM2200_DSP1AUX3MIX_INPUT_1_SOURCE: + case WM2200_DSP1AUX4MIX_INPUT_1_SOURCE: + case WM2200_DSP1AUX5MIX_INPUT_1_SOURCE: + case WM2200_DSP1AUX6MIX_INPUT_1_SOURCE: + case WM2200_DSP2LMIX_INPUT_1_SOURCE: + case WM2200_DSP2LMIX_INPUT_1_VOLUME: + case WM2200_DSP2LMIX_INPUT_2_SOURCE: + case WM2200_DSP2LMIX_INPUT_2_VOLUME: + case WM2200_DSP2LMIX_INPUT_3_SOURCE: + case WM2200_DSP2LMIX_INPUT_3_VOLUME: + case WM2200_DSP2LMIX_INPUT_4_SOURCE: + case WM2200_DSP2LMIX_INPUT_4_VOLUME: + case WM2200_DSP2RMIX_INPUT_1_SOURCE: + case WM2200_DSP2RMIX_INPUT_1_VOLUME: + case WM2200_DSP2RMIX_INPUT_2_SOURCE: + case WM2200_DSP2RMIX_INPUT_2_VOLUME: + case WM2200_DSP2RMIX_INPUT_3_SOURCE: + case WM2200_DSP2RMIX_INPUT_3_VOLUME: + case WM2200_DSP2RMIX_INPUT_4_SOURCE: + case WM2200_DSP2RMIX_INPUT_4_VOLUME: + case WM2200_DSP2AUX1MIX_INPUT_1_SOURCE: + case WM2200_DSP2AUX2MIX_INPUT_1_SOURCE: + case WM2200_DSP2AUX3MIX_INPUT_1_SOURCE: + case WM2200_DSP2AUX4MIX_INPUT_1_SOURCE: + case WM2200_DSP2AUX5MIX_INPUT_1_SOURCE: + case WM2200_DSP2AUX6MIX_INPUT_1_SOURCE: + case WM2200_GPIO_CTRL_1: + case WM2200_GPIO_CTRL_2: + case WM2200_GPIO_CTRL_3: + case WM2200_GPIO_CTRL_4: + case WM2200_ADPS1_IRQ0: + case WM2200_ADPS1_IRQ1: + case WM2200_MISC_PAD_CTRL_1: + case WM2200_INTERRUPT_STATUS_1: + case WM2200_INTERRUPT_STATUS_1_MASK: + case WM2200_INTERRUPT_STATUS_2: + case WM2200_INTERRUPT_RAW_STATUS_2: + case WM2200_INTERRUPT_STATUS_2_MASK: + case WM2200_INTERRUPT_CONTROL: + case WM2200_EQL_1: + case WM2200_EQL_2: + case WM2200_EQL_3: + case WM2200_EQL_4: + case WM2200_EQL_5: + case WM2200_EQL_6: + case WM2200_EQL_7: + case WM2200_EQL_8: + case WM2200_EQL_9: + case WM2200_EQL_10: + case WM2200_EQL_11: + case WM2200_EQL_12: + case WM2200_EQL_13: + case WM2200_EQL_14: + case WM2200_EQL_15: + case WM2200_EQL_16: + case WM2200_EQL_17: + case WM2200_EQL_18: + case WM2200_EQL_19: + case WM2200_EQL_20: + case WM2200_EQR_1: + case WM2200_EQR_2: + case WM2200_EQR_3: + case WM2200_EQR_4: + case WM2200_EQR_5: + case WM2200_EQR_6: + case WM2200_EQR_7: + case WM2200_EQR_8: + case WM2200_EQR_9: + case WM2200_EQR_10: + case WM2200_EQR_11: + case WM2200_EQR_12: + case WM2200_EQR_13: + case WM2200_EQR_14: + case WM2200_EQR_15: + case WM2200_EQR_16: + case WM2200_EQR_17: + case WM2200_EQR_18: + case WM2200_EQR_19: + case WM2200_EQR_20: + case WM2200_HPLPF1_1: + case WM2200_HPLPF1_2: + case WM2200_HPLPF2_1: + case WM2200_HPLPF2_2: + case WM2200_DSP1_CONTROL_1: + case WM2200_DSP1_CONTROL_2: + case WM2200_DSP1_CONTROL_3: + case WM2200_DSP1_CONTROL_4: + case WM2200_DSP1_CONTROL_5: + case WM2200_DSP1_CONTROL_6: + case WM2200_DSP1_CONTROL_7: + case WM2200_DSP1_CONTROL_8: + case WM2200_DSP1_CONTROL_9: + case WM2200_DSP1_CONTROL_10: + case WM2200_DSP1_CONTROL_11: + case WM2200_DSP1_CONTROL_12: + case WM2200_DSP1_CONTROL_13: + case WM2200_DSP1_CONTROL_14: + case WM2200_DSP1_CONTROL_15: + case WM2200_DSP1_CONTROL_16: + case WM2200_DSP1_CONTROL_17: + case WM2200_DSP1_CONTROL_18: + case WM2200_DSP1_CONTROL_19: + case WM2200_DSP1_CONTROL_20: + case WM2200_DSP1_CONTROL_21: + case WM2200_DSP1_CONTROL_22: + case WM2200_DSP1_CONTROL_23: + case WM2200_DSP1_CONTROL_24: + case WM2200_DSP1_CONTROL_25: + case WM2200_DSP1_CONTROL_26: + case WM2200_DSP1_CONTROL_27: + case WM2200_DSP1_CONTROL_28: + case WM2200_DSP1_CONTROL_29: + case WM2200_DSP1_CONTROL_30: + case WM2200_DSP1_CONTROL_31: + case WM2200_DSP2_CONTROL_1: + case WM2200_DSP2_CONTROL_2: + case WM2200_DSP2_CONTROL_3: + case WM2200_DSP2_CONTROL_4: + case WM2200_DSP2_CONTROL_5: + case WM2200_DSP2_CONTROL_6: + case WM2200_DSP2_CONTROL_7: + case WM2200_DSP2_CONTROL_8: + case WM2200_DSP2_CONTROL_9: + case WM2200_DSP2_CONTROL_10: + case WM2200_DSP2_CONTROL_11: + case WM2200_DSP2_CONTROL_12: + case WM2200_DSP2_CONTROL_13: + case WM2200_DSP2_CONTROL_14: + case WM2200_DSP2_CONTROL_15: + case WM2200_DSP2_CONTROL_16: + case WM2200_DSP2_CONTROL_17: + case WM2200_DSP2_CONTROL_18: + case WM2200_DSP2_CONTROL_19: + case WM2200_DSP2_CONTROL_20: + case WM2200_DSP2_CONTROL_21: + case WM2200_DSP2_CONTROL_22: + case WM2200_DSP2_CONTROL_23: + case WM2200_DSP2_CONTROL_24: + case WM2200_DSP2_CONTROL_25: + case WM2200_DSP2_CONTROL_26: + case WM2200_DSP2_CONTROL_27: + case WM2200_DSP2_CONTROL_28: + case WM2200_DSP2_CONTROL_29: + case WM2200_DSP2_CONTROL_30: + case WM2200_DSP2_CONTROL_31: + return true; + default: + return false; + } +} + +static const struct reg_default wm2200_reva_patch[] = { + { 0x07, 0x0003 }, + { 0x102, 0x0200 }, + { 0x203, 0x0084 }, + { 0x201, 0x83FF }, + { 0x20C, 0x0062 }, + { 0x20D, 0x0062 }, + { 0x207, 0x2002 }, + { 0x208, 0x20C0 }, + { 0x21D, 0x01C0 }, + { 0x50A, 0x0001 }, + { 0x50B, 0x0002 }, + { 0x50C, 0x0003 }, + { 0x50D, 0x0004 }, + { 0x50E, 0x0005 }, + { 0x510, 0x0001 }, + { 0x511, 0x0002 }, + { 0x512, 0x0003 }, + { 0x513, 0x0004 }, + { 0x514, 0x0005 }, + { 0x515, 0x0000 }, + { 0x201, 0x8084 }, + { 0x202, 0xBBDE }, + { 0x203, 0x00EC }, + { 0x500, 0x8000 }, + { 0x507, 0x1820 }, + { 0x508, 0x1820 }, + { 0x505, 0x0300 }, + { 0x506, 0x0300 }, + { 0x302, 0x2280 }, + { 0x303, 0x0080 }, + { 0x304, 0x2280 }, + { 0x305, 0x0080 }, + { 0x306, 0x2280 }, + { 0x307, 0x0080 }, + { 0x401, 0x0080 }, + { 0x402, 0x0080 }, + { 0x417, 0x3069 }, + { 0x900, 0x6318 }, + { 0x901, 0x6300 }, + { 0x902, 0x0FC8 }, + { 0x903, 0x03FE }, + { 0x904, 0x00E0 }, + { 0x905, 0x1EC4 }, + { 0x906, 0xF136 }, + { 0x907, 0x0409 }, + { 0x908, 0x04CC }, + { 0x909, 0x1C9B }, + { 0x90A, 0xF337 }, + { 0x90B, 0x040B }, + { 0x90C, 0x0CBB }, + { 0x90D, 0x16F8 }, + { 0x90E, 0xF7D9 }, + { 0x90F, 0x040A }, + { 0x910, 0x1F14 }, + { 0x911, 0x058C }, + { 0x912, 0x0563 }, + { 0x913, 0x4000 }, + { 0x916, 0x6318 }, + { 0x917, 0x6300 }, + { 0x918, 0x0FC8 }, + { 0x919, 0x03FE }, + { 0x91A, 0x00E0 }, + { 0x91B, 0x1EC4 }, + { 0x91C, 0xF136 }, + { 0x91D, 0x0409 }, + { 0x91E, 0x04CC }, + { 0x91F, 0x1C9B }, + { 0x920, 0xF337 }, + { 0x921, 0x040B }, + { 0x922, 0x0CBB }, + { 0x923, 0x16F8 }, + { 0x924, 0xF7D9 }, + { 0x925, 0x040A }, + { 0x926, 0x1F14 }, + { 0x927, 0x058C }, + { 0x928, 0x0563 }, + { 0x929, 0x4000 }, + { 0x709, 0x2000 }, + { 0x207, 0x200E }, + { 0x208, 0x20D4 }, + { 0x20A, 0x0080 }, + { 0x07, 0x0000 }, +}; + +static int wm2200_reset(struct wm2200_priv *wm2200) +{ + if (wm2200->pdata.reset) { + gpio_set_value_cansleep(wm2200->pdata.reset, 0); + gpio_set_value_cansleep(wm2200->pdata.reset, 1); + + return 0; + } else { + return regmap_write(wm2200->regmap, WM2200_SOFTWARE_RESET, + 0x2200); + } +} + +static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0); +static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); +static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0); + +static const char *wm2200_mixer_texts[] = { + "None", + "Tone Generator", + "AEC loopback", + "IN1L", + "IN1R", + "IN2L", + "IN2R", + "IN3L", + "IN3R", + "AIF1RX1", + "AIF1RX2", + "AIF1RX3", + "AIF1RX4", + "AIF1RX5", + "AIF1RX6", + "EQL", + "EQR", + "LHPF1", + "LHPF2", + "LHPF3", + "LHPF4", + "DSP1.1", + "DSP1.2", + "DSP1.3", + "DSP1.4", + "DSP1.5", + "DSP1.6", + "DSP2.1", + "DSP2.2", + "DSP2.3", + "DSP2.4", + "DSP2.5", + "DSP2.6", +}; + +static int wm2200_mixer_values[] = { + 0x00, + 0x04, /* Tone */ + 0x08, /* AEC */ + 0x10, /* Input */ + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x20, /* AIF */ + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x50, /* EQ */ + 0x51, + 0x52, + 0x60, /* LHPF1 */ + 0x61, /* LHPF2 */ + 0x68, /* DSP1 */ + 0x69, + 0x6a, + 0x6b, + 0x6c, + 0x6d, + 0x70, /* DSP2 */ + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, +}; + +#define WM2200_MIXER_CONTROLS(name, base) \ + SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \ + WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \ + SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \ + WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \ + SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \ + WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \ + SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \ + WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv) + +#define WM2200_MUX_ENUM_DECL(name, reg) \ + SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \ + wm2200_mixer_texts, wm2200_mixer_values) + +#define WM2200_MUX_CTL_DECL(name) \ + const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_VALUE_ENUM("Route", name##_enum) + +#define WM2200_MIXER_ENUMS(name, base_reg) \ + static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg); \ + static WM2200_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2); \ + static WM2200_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4); \ + static WM2200_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6); \ + static WM2200_MUX_CTL_DECL(name##_in1); \ + static WM2200_MUX_CTL_DECL(name##_in2); \ + static WM2200_MUX_CTL_DECL(name##_in3); \ + static WM2200_MUX_CTL_DECL(name##_in4) + +static const struct snd_kcontrol_new wm2200_snd_controls[] = { +SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL, + WM2200_IN1_OSR_SHIFT, 1, 0), +SOC_SINGLE("IN2 High Performance Switch", WM2200_IN2L_CONTROL, + WM2200_IN2_OSR_SHIFT, 1, 0), +SOC_SINGLE("IN3 High Performance Switch", WM2200_IN3L_CONTROL, + WM2200_IN3_OSR_SHIFT, 1, 0), + +SOC_DOUBLE_R_TLV("IN1 Volume", WM2200_IN1L_CONTROL, WM2200_IN1R_CONTROL, + WM2200_IN1L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv), +SOC_DOUBLE_R_TLV("IN2 Volume", WM2200_IN2L_CONTROL, WM2200_IN2R_CONTROL, + WM2200_IN2L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv), +SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL, + WM2200_IN3L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv), + +SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L, + WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L, + WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L, + WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1), + +SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L, + WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_2L, + WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L, + WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_DIG_VOL_SHIFT, + 0xbf, 0, digital_tlv), + +SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L, + WM2200_OUT1_OSR_SHIFT, 1, 0), +SOC_SINGLE("OUT2 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_2L, + WM2200_OUT2_OSR_SHIFT, 1, 0), + +SOC_DOUBLE_R("OUT1 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_1L, + WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R_TLV("OUT1 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_1L, + WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_VOL_SHIFT, 0x9f, 0, + digital_tlv), +SOC_DOUBLE_R_TLV("OUT1 Volume", WM2200_DAC_VOLUME_LIMIT_1L, + WM2200_DAC_VOLUME_LIMIT_1R, WM2200_OUT1L_PGA_VOL_SHIFT, + 0x46, 0, out_tlv), + +SOC_DOUBLE_R("OUT2 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_2L, + WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L, + WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0, + digital_tlv), +SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT, + WM2200_SPK1R_MUTE_SHIFT, 1, 0), +}; + +WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(OUT1R, WM2200_OUT1RMIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(OUT2L, WM2200_OUT2LMIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(OUT2R, WM2200_OUT2RMIX_INPUT_1_SOURCE); + +WM2200_MIXER_ENUMS(AIF1TX1, WM2200_AIF1TX1MIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(AIF1TX2, WM2200_AIF1TX2MIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(AIF1TX3, WM2200_AIF1TX3MIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(AIF1TX4, WM2200_AIF1TX4MIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(AIF1TX5, WM2200_AIF1TX5MIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(AIF1TX6, WM2200_AIF1TX6MIX_INPUT_1_SOURCE); + +WM2200_MIXER_ENUMS(EQL, WM2200_EQLMIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(EQR, WM2200_EQRMIX_INPUT_1_SOURCE); + +WM2200_MIXER_ENUMS(DSP1L, WM2200_DSP1LMIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(DSP1R, WM2200_DSP1RMIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(DSP2L, WM2200_DSP2LMIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(DSP2R, WM2200_DSP2RMIX_INPUT_1_SOURCE); + +WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE); +WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE); + +#define WM2200_MUX(name, ctrl) \ + SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) + +#define WM2200_MIXER_WIDGETS(name, name_str) \ + WM2200_MUX(name_str " Input 1", &name##_in1_mux), \ + WM2200_MUX(name_str " Input 2", &name##_in2_mux), \ + WM2200_MUX(name_str " Input 3", &name##_in3_mux), \ + WM2200_MUX(name_str " Input 4", &name##_in4_mux), \ + SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0) + +#define WM2200_MIXER_INPUT_ROUTES(name) \ + { name, "Tone Generator", "Tone Generator" }, \ + { name, "IN1L", "IN1L PGA" }, \ + { name, "IN1R", "IN1R PGA" }, \ + { name, "IN2L", "IN2L PGA" }, \ + { name, "IN2R", "IN2R PGA" }, \ + { name, "IN3L", "IN3L PGA" }, \ + { name, "IN3R", "IN3R PGA" }, \ + { name, "DSP1.1", "DSP1" }, \ + { name, "DSP1.2", "DSP1" }, \ + { name, "DSP1.3", "DSP1" }, \ + { name, "DSP1.4", "DSP1" }, \ + { name, "DSP1.5", "DSP1" }, \ + { name, "DSP1.6", "DSP1" }, \ + { name, "DSP2.1", "DSP2" }, \ + { name, "DSP2.2", "DSP2" }, \ + { name, "DSP2.3", "DSP2" }, \ + { name, "DSP2.4", "DSP2" }, \ + { name, "DSP2.5", "DSP2" }, \ + { name, "DSP2.6", "DSP2" }, \ + { name, "AIF1RX1", "AIF1RX1" }, \ + { name, "AIF1RX2", "AIF1RX2" }, \ + { name, "AIF1RX3", "AIF1RX3" }, \ + { name, "AIF1RX4", "AIF1RX4" }, \ + { name, "AIF1RX5", "AIF1RX5" }, \ + { name, "AIF1RX6", "AIF1RX6" }, \ + { name, "EQL", "EQL" }, \ + { name, "EQR", "EQR" }, \ + { name, "LHPF1", "LHPF1" }, \ + { name, "LHPF2", "LHPF2" } + +#define WM2200_MIXER_ROUTES(widget, name) \ + { widget, NULL, name " Mixer" }, \ + { name " Mixer", NULL, name " Input 1" }, \ + { name " Mixer", NULL, name " Input 2" }, \ + { name " Mixer", NULL, name " Input 3" }, \ + { name " Mixer", NULL, name " Input 4" }, \ + WM2200_MIXER_INPUT_ROUTES(name " Input 1"), \ + WM2200_MIXER_INPUT_ROUTES(name " Input 2"), \ + WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \ + WM2200_MIXER_INPUT_ROUTES(name " Input 4") + +static const struct snd_soc_dapm_widget wm2200_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("SYSCLK", WM2200_CLOCKING_3, WM2200_SYSCLK_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_SUPPLY("CP1", WM2200_DM_CHARGE_PUMP_1, WM2200_CPDM_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_SUPPLY("CP2", WM2200_MIC_CHARGE_PUMP_1, WM2200_CPMIC_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1", WM2200_MIC_BIAS_CTRL_1, WM2200_MICB1_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS2", WM2200_MIC_BIAS_CTRL_2, WM2200_MICB2_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), +SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20), + +SND_SOC_DAPM_INPUT("IN1L"), +SND_SOC_DAPM_INPUT("IN1R"), +SND_SOC_DAPM_INPUT("IN2L"), +SND_SOC_DAPM_INPUT("IN2R"), +SND_SOC_DAPM_INPUT("IN3L"), +SND_SOC_DAPM_INPUT("IN3R"), + +SND_SOC_DAPM_SIGGEN("TONE"), +SND_SOC_DAPM_PGA("Tone Generator", WM2200_TONE_GENERATOR_1, + WM2200_TONE_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("IN1L PGA", WM2200_INPUT_ENABLES, WM2200_IN1L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("IN1R PGA", WM2200_INPUT_ENABLES, WM2200_IN1R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("IN2L PGA", WM2200_INPUT_ENABLES, WM2200_IN2L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("IN2R PGA", WM2200_INPUT_ENABLES, WM2200_IN2R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("IN3L PGA", WM2200_INPUT_ENABLES, WM2200_IN3L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("IN3R PGA", WM2200_INPUT_ENABLES, WM2200_IN3R_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_AIF_IN("AIF1RX1", "Playback", 0, + WM2200_AUDIO_IF_1_22, WM2200_AIF1RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX2", "Playback", 1, + WM2200_AUDIO_IF_1_22, WM2200_AIF1RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX3", "Playback", 2, + WM2200_AUDIO_IF_1_22, WM2200_AIF1RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX4", "Playback", 3, + WM2200_AUDIO_IF_1_22, WM2200_AIF1RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX5", "Playback", 4, + WM2200_AUDIO_IF_1_22, WM2200_AIF1RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX6", "Playback", 5, + WM2200_AUDIO_IF_1_22, WM2200_AIF1RX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA("EQL", WM2200_EQL_1, WM2200_EQL_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQR", WM2200_EQR_1, WM2200_EQR_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), +SND_SOC_DAPM_PGA_E("DSP2", SND_SOC_NOPM, 1, 0, NULL, 0, NULL, 0), + +SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, + WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 1, + WM2200_AUDIO_IF_1_22, WM2200_AIF1TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 2, + WM2200_AUDIO_IF_1_22, WM2200_AIF1TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 3, + WM2200_AUDIO_IF_1_22, WM2200_AIF1TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 4, + WM2200_AUDIO_IF_1_22, WM2200_AIF1TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 5, + WM2200_AUDIO_IF_1_22, WM2200_AIF1TX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA_S("OUT1L", 0, WM2200_OUTPUT_ENABLES, + WM2200_OUT1L_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("OUT1R", 0, WM2200_OUTPUT_ENABLES, + WM2200_OUT1R_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA_S("EPD_LP", 1, WM2200_EAR_PIECE_CTRL_1, + WM2200_EPD_LP_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("EPD_OUTP_LP", 1, WM2200_EAR_PIECE_CTRL_1, + WM2200_EPD_OUTP_LP_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LP", 1, WM2200_EAR_PIECE_CTRL_1, + WM2200_EPD_RMV_SHRT_LP_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA_S("EPD_LN", 1, WM2200_EAR_PIECE_CTRL_1, + WM2200_EPD_LN_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("EPD_OUTP_LN", 1, WM2200_EAR_PIECE_CTRL_1, + WM2200_EPD_OUTP_LN_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LN", 1, WM2200_EAR_PIECE_CTRL_1, + WM2200_EPD_RMV_SHRT_LN_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA_S("EPD_RP", 1, WM2200_EAR_PIECE_CTRL_2, + WM2200_EPD_RP_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("EPD_OUTP_RP", 1, WM2200_EAR_PIECE_CTRL_2, + WM2200_EPD_OUTP_RP_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RP", 1, WM2200_EAR_PIECE_CTRL_2, + WM2200_EPD_RMV_SHRT_RP_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA_S("EPD_RN", 1, WM2200_EAR_PIECE_CTRL_2, + WM2200_EPD_RN_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("EPD_OUTP_RN", 1, WM2200_EAR_PIECE_CTRL_2, + WM2200_EPD_OUTP_RN_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RN", 1, WM2200_EAR_PIECE_CTRL_2, + WM2200_EPD_RMV_SHRT_RN_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("OUT2L", WM2200_OUTPUT_ENABLES, WM2200_OUT2L_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_PGA("OUT2R", WM2200_OUTPUT_ENABLES, WM2200_OUT2R_ENA_SHIFT, + 0, NULL, 0), + +SND_SOC_DAPM_OUTPUT("EPOUTLN"), +SND_SOC_DAPM_OUTPUT("EPOUTLP"), +SND_SOC_DAPM_OUTPUT("EPOUTRN"), +SND_SOC_DAPM_OUTPUT("EPOUTRP"), +SND_SOC_DAPM_OUTPUT("SPK"), + +WM2200_MIXER_WIDGETS(EQL, "EQL"), +WM2200_MIXER_WIDGETS(EQR, "EQR"), + +WM2200_MIXER_WIDGETS(LHPF1, "LHPF1"), +WM2200_MIXER_WIDGETS(LHPF2, "LHPF2"), + +WM2200_MIXER_WIDGETS(DSP1L, "DSP1L"), +WM2200_MIXER_WIDGETS(DSP1R, "DSP1R"), +WM2200_MIXER_WIDGETS(DSP2L, "DSP2L"), +WM2200_MIXER_WIDGETS(DSP2R, "DSP2R"), + +WM2200_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), +WM2200_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), +WM2200_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), +WM2200_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), +WM2200_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), +WM2200_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), + +WM2200_MIXER_WIDGETS(OUT1L, "OUT1L"), +WM2200_MIXER_WIDGETS(OUT1R, "OUT1R"), +WM2200_MIXER_WIDGETS(OUT2L, "OUT2L"), +WM2200_MIXER_WIDGETS(OUT2R, "OUT2R"), +}; + +static const struct snd_soc_dapm_route wm2200_dapm_routes[] = { + /* Everything needs SYSCLK but only hook up things on the edge + * of the chip */ + { "IN1L", NULL, "SYSCLK" }, + { "IN1R", NULL, "SYSCLK" }, + { "IN2L", NULL, "SYSCLK" }, + { "IN2R", NULL, "SYSCLK" }, + { "IN3L", NULL, "SYSCLK" }, + { "IN3R", NULL, "SYSCLK" }, + { "OUT1L", NULL, "SYSCLK" }, + { "OUT1R", NULL, "SYSCLK" }, + { "OUT2L", NULL, "SYSCLK" }, + { "OUT2R", NULL, "SYSCLK" }, + { "AIF1RX1", NULL, "SYSCLK" }, + { "AIF1RX2", NULL, "SYSCLK" }, + { "AIF1RX3", NULL, "SYSCLK" }, + { "AIF1RX4", NULL, "SYSCLK" }, + { "AIF1RX5", NULL, "SYSCLK" }, + { "AIF1RX6", NULL, "SYSCLK" }, + { "AIF1TX1", NULL, "SYSCLK" }, + { "AIF1TX2", NULL, "SYSCLK" }, + { "AIF1TX3", NULL, "SYSCLK" }, + { "AIF1TX4", NULL, "SYSCLK" }, + { "AIF1TX5", NULL, "SYSCLK" }, + { "AIF1TX6", NULL, "SYSCLK" }, + + { "IN1L", NULL, "AVDD" }, + { "IN1R", NULL, "AVDD" }, + { "IN2L", NULL, "AVDD" }, + { "IN2R", NULL, "AVDD" }, + { "IN3L", NULL, "AVDD" }, + { "IN3R", NULL, "AVDD" }, + { "OUT1L", NULL, "AVDD" }, + { "OUT1R", NULL, "AVDD" }, + + { "IN1L PGA", NULL, "IN1L" }, + { "IN1R PGA", NULL, "IN1R" }, + { "IN2L PGA", NULL, "IN2L" }, + { "IN2R PGA", NULL, "IN2R" }, + { "IN3L PGA", NULL, "IN3L" }, + { "IN3R PGA", NULL, "IN3R" }, + + { "Tone Generator", NULL, "TONE" }, + + { "CP2", NULL, "CPVDD" }, + { "MICBIAS1", NULL, "CP2" }, + { "MICBIAS2", NULL, "CP2" }, + + { "CP1", NULL, "CPVDD" }, + { "EPD_LN", NULL, "CP1" }, + { "EPD_LP", NULL, "CP1" }, + { "EPD_RN", NULL, "CP1" }, + { "EPD_RP", NULL, "CP1" }, + + { "EPD_LP", NULL, "OUT1L" }, + { "EPD_OUTP_LP", NULL, "EPD_LP" }, + { "EPD_RMV_SHRT_LP", NULL, "EPD_OUTP_LP" }, + { "EPOUTLP", NULL, "EPD_RMV_SHRT_LP" }, + + { "EPD_LN", NULL, "OUT1L" }, + { "EPD_OUTP_LN", NULL, "EPD_LN" }, + { "EPD_RMV_SHRT_LN", NULL, "EPD_OUTP_LN" }, + { "EPOUTLN", NULL, "EPD_RMV_SHRT_LN" }, + + { "EPD_RP", NULL, "OUT1R" }, + { "EPD_OUTP_RP", NULL, "EPD_RP" }, + { "EPD_RMV_SHRT_RP", NULL, "EPD_OUTP_RP" }, + { "EPOUTRP", NULL, "EPD_RMV_SHRT_RP" }, + + { "EPD_RN", NULL, "OUT1R" }, + { "EPD_OUTP_RN", NULL, "EPD_RN" }, + { "EPD_RMV_SHRT_RN", NULL, "EPD_OUTP_RN" }, + { "EPOUTRN", NULL, "EPD_RMV_SHRT_RN" }, + + { "SPK", NULL, "OUT2L" }, + { "SPK", NULL, "OUT2R" }, + + WM2200_MIXER_ROUTES("DSP1", "DSP1L"), + WM2200_MIXER_ROUTES("DSP1", "DSP1R"), + WM2200_MIXER_ROUTES("DSP2", "DSP2L"), + WM2200_MIXER_ROUTES("DSP2", "DSP2R"), + + WM2200_MIXER_ROUTES("OUT1L", "OUT1L"), + WM2200_MIXER_ROUTES("OUT1R", "OUT1R"), + WM2200_MIXER_ROUTES("OUT2L", "OUT2L"), + WM2200_MIXER_ROUTES("OUT2R", "OUT2R"), + + WM2200_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), + WM2200_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), + WM2200_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), + WM2200_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), + WM2200_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), + WM2200_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), + + WM2200_MIXER_ROUTES("EQL", "EQL"), + WM2200_MIXER_ROUTES("EQR", "EQR"), + + WM2200_MIXER_ROUTES("LHPF1", "LHPF1"), + WM2200_MIXER_ROUTES("LHPF2", "LHPF2"), +}; + +static int wm2200_probe(struct snd_soc_codec *codec) +{ + struct wm2200_priv *wm2200 = dev_get_drvdata(codec->dev); + int ret; + + wm2200->codec = codec; + codec->control_data = wm2200->regmap; + codec->dapm.bias_level = SND_SOC_BIAS_OFF; + + ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + return ret; +} + +static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + int lrclk, bclk, fmt_val; + + lrclk = 0; + bclk = 0; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + fmt_val = 0; + break; + case SND_SOC_DAIFMT_DSP_B: + fmt_val = 1; + break; + case SND_SOC_DAIFMT_I2S: + fmt_val = 2; + break; + case SND_SOC_DAIFMT_LEFT_J: + fmt_val = 3; + break; + default: + dev_err(codec->dev, "Unsupported DAI format %d\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + case SND_SOC_DAIFMT_CBS_CFM: + lrclk |= WM2200_AIF1TX_LRCLK_MSTR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + bclk |= WM2200_AIF1_BCLK_MSTR; + break; + case SND_SOC_DAIFMT_CBM_CFM: + lrclk |= WM2200_AIF1TX_LRCLK_MSTR; + bclk |= WM2200_AIF1_BCLK_MSTR; + break; + default: + dev_err(codec->dev, "Unsupported master mode %d\n", + fmt & SND_SOC_DAIFMT_MASTER_MASK); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + bclk |= WM2200_AIF1_BCLK_INV; + lrclk |= WM2200_AIF1TX_LRCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + bclk |= WM2200_AIF1_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + lrclk |= WM2200_AIF1TX_LRCLK_INV; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1, WM2200_AIF1_BCLK_MSTR | + WM2200_AIF1_BCLK_INV, bclk); + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2, + WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV, + lrclk); + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_3, + WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV, + lrclk); + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5, + WM2200_AIF1_FMT_MASK << 1, fmt_val << 1); + + return 0; +} + +static int wm2200_sr_code[] = { + 0, + 12000, + 24000, + 48000, + 96000, + 192000, + 384000, + 768000, + 0, + 11025, + 22050, + 44100, + 88200, + 176400, + 352800, + 705600, + 4000, + 8000, + 16000, + 32000, + 64000, + 128000, + 256000, + 512000, +}; + +#define WM2200_NUM_BCLK_RATES 12 + +static int wm2200_bclk_rates_dat[WM2200_NUM_BCLK_RATES] = { + 6144000, + 3072000, + 2048000, + 1536000, + 768000, + 512000, + 384000, + 256000, + 192000, + 128000, + 96000, + 64000, +}; + +static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = { + 5644800, + 2882400, + 1881600, + 1411200, + 705600, + 470400, + 352800, + 176400, + 117600, + 88200, + 58800, +}; + +static int wm2200_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 wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec); + int i, bclk, lrclk, wl, fl, sr_code; + int *bclk_rates; + + /* Data sizes if not using TDM */ + wl = snd_pcm_format_width(params_format(params)); + if (wl < 0) + return wl; + fl = snd_soc_params_to_frame_size(params); + if (fl < 0) + return fl; + + dev_dbg(codec->dev, "Word length %d bits, frame length %d bits\n", + wl, fl); + + /* Target BCLK rate */ + bclk = snd_soc_params_to_bclk(params); + if (bclk < 0) + return bclk; + + if (!wm2200->sysclk) { + dev_err(codec->dev, "SYSCLK has no rate set\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(wm2200_sr_code); i++) + if (wm2200_sr_code[i] == params_rate(params)) + break; + if (i == ARRAY_SIZE(wm2200_sr_code)) { + dev_err(codec->dev, "Unsupported sample rate: %dHz\n", + params_rate(params)); + return -EINVAL; + } + sr_code = i; + + dev_dbg(codec->dev, "Target BCLK is %dHz, using %dHz SYSCLK\n", + bclk, wm2200->sysclk); + + if (wm2200->sysclk % 4000) + bclk_rates = wm2200_bclk_rates_cd; + else + bclk_rates = wm2200_bclk_rates_dat; + + for (i = 0; i < WM2200_NUM_BCLK_RATES; i++) + if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0)) + break; + if (i == WM2200_NUM_BCLK_RATES) { + dev_err(codec->dev, + "No valid BCLK for %dHz found from %dHz SYSCLK\n", + bclk, wm2200->sysclk); + return -EINVAL; + } + + bclk = i; + dev_dbg(codec->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]); + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1, + WM2200_AIF1_BCLK_DIV_MASK, bclk); + + lrclk = bclk_rates[bclk] / params_rate(params); + dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || + dai->symmetric_rates) + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7, + WM2200_AIF1RX_BCPF_MASK, lrclk); + else + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_6, + WM2200_AIF1TX_BCPF_MASK, lrclk); + + i = (wl << WM2200_AIF1TX_WL_SHIFT) | wl; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_9, + WM2200_AIF1RX_WL_MASK | + WM2200_AIF1RX_SLOT_LEN_MASK, i); + else + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_8, + WM2200_AIF1TX_WL_MASK | + WM2200_AIF1TX_SLOT_LEN_MASK, i); + + snd_soc_update_bits(codec, WM2200_CLOCKING_4, + WM2200_SAMPLE_RATE_1_MASK, sr_code); + + return 0; +} + +static const struct snd_soc_dai_ops wm2200_dai_ops = { + .set_fmt = wm2200_set_fmt, + .hw_params = wm2200_hw_params, +}; + +static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id, + int source, unsigned int freq, int dir) +{ + struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec); + int fval; + + switch (clk_id) { + case WM2200_CLK_SYSCLK: + break; + + default: + dev_err(codec->dev, "Unknown clock %d\n", clk_id); + return -EINVAL; + } + + switch (source) { + case WM2200_CLKSRC_MCLK1: + case WM2200_CLKSRC_MCLK2: + case WM2200_CLKSRC_FLL: + case WM2200_CLKSRC_BCLK1: + break; + default: + dev_err(codec->dev, "Invalid source %d\n", source); + return -EINVAL; + } + + switch (freq) { + case 22579200: + case 24576000: + fval = 2; + break; + default: + dev_err(codec->dev, "Invalid clock rate: %d\n", freq); + return -EINVAL; + } + + /* TODO: Check if MCLKs are in use and enable/disable pulls to + * match. + */ + + snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_FREQ_MASK | + WM2200_SYSCLK_SRC_MASK, + fval << WM2200_SYSCLK_FREQ_SHIFT | source); + + wm2200->sysclk = freq; + + return 0; +} + +struct _fll_div { + u16 fll_fratio; + u16 fll_outdiv; + u16 fll_refclk_div; + 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; + + /* 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(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n", + fll_div->fll_fratio, fratio, fll_div->fll_outdiv, + fll_div->fll_refclk_div); + + return 0; +} + +static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source, + unsigned int Fref, unsigned int Fout) +{ + struct i2c_client *i2c = to_i2c_client(codec->dev); + struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec); + struct _fll_div factors; + int ret, i, timeout; + + if (!Fout) { + dev_dbg(codec->dev, "FLL disabled"); + + if (wm2200->fll_fout) + pm_runtime_put(codec->dev); + + wm2200->fll_fout = 0; + snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1, + WM2200_FLL_ENA, 0); + return 0; + } + + switch (source) { + case WM2200_FLL_SRC_MCLK1: + case WM2200_FLL_SRC_MCLK2: + case WM2200_FLL_SRC_BCLK: + break; + default: + dev_err(codec->dev, "Invalid FLL source %d\n", source); + return -EINVAL; + } + + ret = fll_factors(&factors, Fref, Fout); + if (ret < 0) + return ret; + + /* Disable the FLL while we reconfigure */ + snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1, WM2200_FLL_ENA, 0); + + snd_soc_update_bits(codec, WM2200_FLL_CONTROL_2, + WM2200_FLL_OUTDIV_MASK | WM2200_FLL_FRATIO_MASK, + (factors.fll_outdiv << WM2200_FLL_OUTDIV_SHIFT) | + factors.fll_fratio); + if (factors.theta) { + snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3, + WM2200_FLL_FRACN_ENA, + WM2200_FLL_FRACN_ENA); + snd_soc_update_bits(codec, WM2200_FLL_EFS_2, + WM2200_FLL_EFS_ENA, + WM2200_FLL_EFS_ENA); + } else { + snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3, + WM2200_FLL_FRACN_ENA, 0); + snd_soc_update_bits(codec, WM2200_FLL_EFS_2, + WM2200_FLL_EFS_ENA, 0); + } + + snd_soc_update_bits(codec, WM2200_FLL_CONTROL_4, WM2200_FLL_THETA_MASK, + factors.theta); + snd_soc_update_bits(codec, WM2200_FLL_CONTROL_6, WM2200_FLL_N_MASK, + factors.n); + snd_soc_update_bits(codec, WM2200_FLL_CONTROL_7, + WM2200_FLL_CLK_REF_DIV_MASK | + WM2200_FLL_CLK_REF_SRC_MASK, + (factors.fll_refclk_div + << WM2200_FLL_CLK_REF_DIV_SHIFT) | source); + snd_soc_update_bits(codec, WM2200_FLL_EFS_1, + WM2200_FLL_LAMBDA_MASK, factors.lambda); + + /* Clear any pending completions */ + try_wait_for_completion(&wm2200->fll_lock); + + pm_runtime_get_sync(codec->dev); + + snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1, + WM2200_FLL_ENA, WM2200_FLL_ENA); + + if (i2c->irq) + timeout = 2; + else + timeout = 50; + + snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_ENA, + WM2200_SYSCLK_ENA); + + /* Poll for the lock; will use the interrupt to exit quickly */ + for (i = 0; i < timeout; i++) { + if (i2c->irq) { + ret = wait_for_completion_timeout(&wm2200->fll_lock, + msecs_to_jiffies(25)); + if (ret > 0) + break; + } else { + msleep(1); + } + + ret = snd_soc_read(codec, + WM2200_INTERRUPT_RAW_STATUS_2); + if (ret < 0) { + dev_err(codec->dev, + "Failed to read FLL status: %d\n", + ret); + continue; + } + if (ret & WM2200_FLL_LOCK_STS) + break; + } + if (i == timeout) { + dev_err(codec->dev, "FLL lock timed out\n"); + pm_runtime_put(codec->dev); + return -ETIMEDOUT; + } + + wm2200->fll_src = source; + wm2200->fll_fref = Fref; + wm2200->fll_fout = Fout; + + dev_dbg(codec->dev, "FLL running %dHz->%dHz\n", Fref, Fout); + + return 0; +} + +static int wm2200_dai_probe(struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val = 0; + int ret; + + ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1); + if (ret >= 0) { + if ((ret & WM2200_GP1_FN_MASK) != 0) { + dai->symmetric_rates = true; + val = WM2200_AIF1TX_LRCLK_SRC; + } + } else { + dev_err(codec->dev, "Failed to read GPIO 1 config: %d\n", ret); + } + + snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2, + WM2200_AIF1TX_LRCLK_SRC, val); + + return 0; +} + +#define WM2200_RATES SNDRV_PCM_RATE_8000_48000 + +#define WM2200_FORMATS (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_driver wm2200_dai = { + .name = "wm2200", + .probe = wm2200_dai_probe, + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM2200_RATES, + .formats = WM2200_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = WM2200_RATES, + .formats = WM2200_FORMATS, + }, + .ops = &wm2200_dai_ops, +}; + +static struct snd_soc_codec_driver soc_codec_wm2200 = { + .probe = wm2200_probe, + + .idle_bias_off = true, + .ignore_pmdown_time = true, + .set_sysclk = wm2200_set_sysclk, + .set_pll = wm2200_set_fll, + + .controls = wm2200_snd_controls, + .num_controls = ARRAY_SIZE(wm2200_snd_controls), + .dapm_widgets = wm2200_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm2200_dapm_widgets), + .dapm_routes = wm2200_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes), +}; + +static irqreturn_t wm2200_irq(int irq, void *data) +{ + struct wm2200_priv *wm2200 = data; + unsigned int val, mask; + int ret; + + ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, &val); + if (ret != 0) { + dev_err(wm2200->dev, "Failed to read IRQ status: %d\n", ret); + return IRQ_NONE; + } + + ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2_MASK, + &mask); + if (ret != 0) { + dev_warn(wm2200->dev, "Failed to read IRQ mask: %d\n", ret); + mask = 0; + } + + val &= ~mask; + + if (val & WM2200_FLL_LOCK_EINT) { + dev_dbg(wm2200->dev, "FLL locked\n"); + complete(&wm2200->fll_lock); + } + + if (val) { + regmap_write(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, val); + + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } +} + +static const struct regmap_config wm2200_regmap = { + .reg_bits = 16, + .val_bits = 16, + + .max_register = WM2200_MAX_REGISTER, + .reg_defaults = wm2200_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults), + .volatile_reg = wm2200_volatile_register, + .readable_reg = wm2200_readable_register, + .cache_type = REGCACHE_RBTREE, +}; + +static const unsigned int wm2200_dig_vu[] = { + WM2200_DAC_DIGITAL_VOLUME_1L, + WM2200_DAC_DIGITAL_VOLUME_1R, + WM2200_DAC_DIGITAL_VOLUME_2L, + WM2200_DAC_DIGITAL_VOLUME_2R, + WM2200_ADC_DIGITAL_VOLUME_1L, + WM2200_ADC_DIGITAL_VOLUME_1R, + WM2200_ADC_DIGITAL_VOLUME_2L, + WM2200_ADC_DIGITAL_VOLUME_2R, + WM2200_ADC_DIGITAL_VOLUME_3L, + WM2200_ADC_DIGITAL_VOLUME_3R, +}; + +static const unsigned int wm2200_mic_ctrl_reg[] = { + WM2200_IN1L_CONTROL, + WM2200_IN2L_CONTROL, + WM2200_IN3L_CONTROL, +}; + +static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm2200_pdata *pdata = dev_get_platdata(&i2c->dev); + struct wm2200_priv *wm2200; + unsigned int reg; + int ret, i; + + wm2200 = devm_kzalloc(&i2c->dev, sizeof(struct wm2200_priv), + GFP_KERNEL); + if (wm2200 == NULL) + return -ENOMEM; + + wm2200->dev = &i2c->dev; + init_completion(&wm2200->fll_lock); + + wm2200->regmap = regmap_init_i2c(i2c, &wm2200_regmap); + if (IS_ERR(wm2200->regmap)) { + ret = PTR_ERR(wm2200->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + goto err; + } + + if (pdata) + wm2200->pdata = *pdata; + + i2c_set_clientdata(i2c, wm2200); + + for (i = 0; i < ARRAY_SIZE(wm2200->core_supplies); i++) + wm2200->core_supplies[i].supply = wm2200_core_supply_names[i]; + + ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request core supplies: %d\n", + ret); + goto err_regmap; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to enable core supplies: %d\n", + ret); + goto err_core; + } + + if (wm2200->pdata.ldo_ena) { + ret = gpio_request_one(wm2200->pdata.ldo_ena, + GPIOF_OUT_INIT_HIGH, "WM2200 LDOENA"); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n", + wm2200->pdata.ldo_ena, ret); + goto err_enable; + } + msleep(2); + } + + if (wm2200->pdata.reset) { + ret = gpio_request_one(wm2200->pdata.reset, + GPIOF_OUT_INIT_HIGH, "WM2200 /RESET"); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n", + wm2200->pdata.reset, ret); + goto err_ldo; + } + } + + ret = regmap_read(wm2200->regmap, WM2200_SOFTWARE_RESET, ®); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret); + goto err_reset; + } + switch (reg) { + case 0x2200: + break; + + default: + dev_err(&i2c->dev, "Device is not a WM2200, ID is %x\n", reg); + ret = -EINVAL; + goto err_reset; + } + + ret = regmap_read(wm2200->regmap, WM2200_DEVICE_REVISION, ®); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read revision register\n"); + goto err_reset; + } + + wm2200->rev = reg & WM2200_DEVICE_REVISION_MASK; + + dev_info(&i2c->dev, "revision %c\n", wm2200->rev + 'A'); + + switch (wm2200->rev) { + case 0: + ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch, + ARRAY_SIZE(wm2200_reva_patch)); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register patch: %d\n", + ret); + } + break; + default: + break; + } + + ret = wm2200_reset(wm2200); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to issue reset\n"); + goto err_reset; + } + + for (i = 0; i < ARRAY_SIZE(wm2200->pdata.gpio_defaults); i++) { + if (!wm2200->pdata.gpio_defaults[i]) + continue; + + regmap_write(wm2200->regmap, WM2200_GPIO_CTRL_1 + i, + wm2200->pdata.gpio_defaults[i]); + } + + for (i = 0; i < ARRAY_SIZE(wm2200_dig_vu); i++) + regmap_update_bits(wm2200->regmap, wm2200_dig_vu[i], + WM2200_OUT_VU, WM2200_OUT_VU); + + /* Assign slots 1-6 to channels 1-6 for both TX and RX */ + for (i = 0; i < 6; i++) { + regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_10 + i, i); + regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_16 + i, i); + } + + for (i = 0; i < ARRAY_SIZE(wm2200->pdata.in_mode); i++) { + regmap_update_bits(wm2200->regmap, wm2200_mic_ctrl_reg[i], + WM2200_IN1_MODE_MASK | + WM2200_IN1_DMIC_SUP_MASK, + (wm2200->pdata.in_mode[i] << + WM2200_IN1_MODE_SHIFT) | + (wm2200->pdata.dmic_sup[i] << + WM2200_IN1_DMIC_SUP_SHIFT)); + } + + if (i2c->irq) { + ret = request_threaded_irq(i2c->irq, NULL, wm2200_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "wm2200", wm2200); + if (ret == 0) + regmap_update_bits(wm2200->regmap, + WM2200_INTERRUPT_STATUS_2_MASK, + WM2200_FLL_LOCK_EINT, 0); + else + dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", + i2c->irq, ret); + } + + pm_runtime_set_active(&i2c->dev); + pm_runtime_enable(&i2c->dev); + pm_request_idle(&i2c->dev); + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_wm2200, + &wm2200_dai, 1); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + goto err_pm_runtime; + } + + return 0; + +err_pm_runtime: + pm_runtime_disable(&i2c->dev); +err_reset: + if (wm2200->pdata.reset) { + gpio_set_value_cansleep(wm2200->pdata.reset, 0); + gpio_free(wm2200->pdata.reset); + } +err_ldo: + if (wm2200->pdata.ldo_ena) { + gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); + gpio_free(wm2200->pdata.ldo_ena); + } +err_enable: + regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); +err_core: + regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); +err_regmap: + regmap_exit(wm2200->regmap); +err: + return ret; +} + +static __devexit int wm2200_i2c_remove(struct i2c_client *i2c) +{ + struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c); + + snd_soc_unregister_codec(&i2c->dev); + if (i2c->irq) + free_irq(i2c->irq, wm2200); + if (wm2200->pdata.reset) { + gpio_set_value_cansleep(wm2200->pdata.reset, 0); + gpio_free(wm2200->pdata.reset); + } + if (wm2200->pdata.ldo_ena) { + gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); + gpio_free(wm2200->pdata.ldo_ena); + } + regulator_bulk_free(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); + regmap_exit(wm2200->regmap); + + return 0; +} + +#ifdef CONFIG_PM_RUNTIME +static int wm2200_runtime_suspend(struct device *dev) +{ + struct wm2200_priv *wm2200 = dev_get_drvdata(dev); + + regcache_cache_only(wm2200->regmap, true); + regcache_mark_dirty(wm2200->regmap); + if (wm2200->pdata.ldo_ena) + gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); + regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); + + return 0; +} + +static int wm2200_runtime_resume(struct device *dev) +{ + struct wm2200_priv *wm2200 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", + ret); + return ret; + } + + if (wm2200->pdata.ldo_ena) { + gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 1); + msleep(2); + } + + regcache_cache_only(wm2200->regmap, false); + regcache_sync(wm2200->regmap); + + return 0; +} +#endif + +static struct dev_pm_ops wm2200_pm = { + SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume, + NULL) +}; + +static const struct i2c_device_id wm2200_i2c_id[] = { + { "wm2200", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id); + +static struct i2c_driver wm2200_i2c_driver = { + .driver = { + .name = "wm2200", + .owner = THIS_MODULE, + .pm = &wm2200_pm, + }, + .probe = wm2200_i2c_probe, + .remove = __devexit_p(wm2200_i2c_remove), + .id_table = wm2200_i2c_id, +}; + +static int __init wm2200_modinit(void) +{ + return i2c_add_driver(&wm2200_i2c_driver); +} +module_init(wm2200_modinit); + +static void __exit wm2200_exit(void) +{ + i2c_del_driver(&wm2200_i2c_driver); +} +module_exit(wm2200_exit); + +MODULE_DESCRIPTION("ASoC WM2200 driver"); +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm2200.h b/sound/soc/codecs/wm2200.h new file mode 100644 index 00000000000..5d719d6b4a8 --- /dev/null +++ b/sound/soc/codecs/wm2200.h @@ -0,0 +1,3674 @@ +/* + * wm2200.h - WM2200 audio codec interface + * + * Copyright 2012 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 _WM2200_H +#define _WM2200_H + +#define WM2200_CLK_SYSCLK 1 + +#define WM2200_CLKSRC_MCLK1 0 +#define WM2200_CLKSRC_MCLK2 1 +#define WM2200_CLKSRC_FLL 4 +#define WM2200_CLKSRC_BCLK1 8 + +#define WM2200_FLL_SRC_MCLK1 0 +#define WM2200_FLL_SRC_MCLK2 1 +#define WM2200_FLL_SRC_BCLK 2 + +/* + * Register values. + */ +#define WM2200_SOFTWARE_RESET 0x00 +#define WM2200_DEVICE_REVISION 0x01 +#define WM2200_TONE_GENERATOR_1 0x0B +#define WM2200_CLOCKING_3 0x102 +#define WM2200_CLOCKING_4 0x103 +#define WM2200_FLL_CONTROL_1 0x111 +#define WM2200_FLL_CONTROL_2 0x112 +#define WM2200_FLL_CONTROL_3 0x113 +#define WM2200_FLL_CONTROL_4 0x114 +#define WM2200_FLL_CONTROL_6 0x116 +#define WM2200_FLL_CONTROL_7 0x117 +#define WM2200_FLL_EFS_1 0x119 +#define WM2200_FLL_EFS_2 0x11A +#define WM2200_MIC_CHARGE_PUMP_1 0x200 +#define WM2200_MIC_CHARGE_PUMP_2 0x201 +#define WM2200_DM_CHARGE_PUMP_1 0x202 +#define WM2200_MIC_BIAS_CTRL_1 0x20C +#define WM2200_MIC_BIAS_CTRL_2 0x20D +#define WM2200_EAR_PIECE_CTRL_1 0x20F +#define WM2200_EAR_PIECE_CTRL_2 0x210 +#define WM2200_INPUT_ENABLES 0x301 +#define WM2200_IN1L_CONTROL 0x302 +#define WM2200_IN1R_CONTROL 0x303 +#define WM2200_IN2L_CONTROL 0x304 +#define WM2200_IN2R_CONTROL 0x305 +#define WM2200_IN3L_CONTROL 0x306 +#define WM2200_IN3R_CONTROL 0x307 +#define WM2200_RXANC_SRC 0x30A +#define WM2200_INPUT_VOLUME_RAMP 0x30B +#define WM2200_ADC_DIGITAL_VOLUME_1L 0x30C +#define WM2200_ADC_DIGITAL_VOLUME_1R 0x30D +#define WM2200_ADC_DIGITAL_VOLUME_2L 0x30E +#define WM2200_ADC_DIGITAL_VOLUME_2R 0x30F +#define WM2200_ADC_DIGITAL_VOLUME_3L 0x310 +#define WM2200_ADC_DIGITAL_VOLUME_3R 0x311 +#define WM2200_OUTPUT_ENABLES 0x400 +#define WM2200_DAC_VOLUME_LIMIT_1L 0x401 +#define WM2200_DAC_VOLUME_LIMIT_1R 0x402 +#define WM2200_DAC_VOLUME_LIMIT_2L 0x403 +#define WM2200_DAC_VOLUME_LIMIT_2R 0x404 +#define WM2200_DAC_AEC_CONTROL_1 0x409 +#define WM2200_OUTPUT_VOLUME_RAMP 0x40A +#define WM2200_DAC_DIGITAL_VOLUME_1L 0x40B +#define WM2200_DAC_DIGITAL_VOLUME_1R 0x40C +#define WM2200_DAC_DIGITAL_VOLUME_2L 0x40D +#define WM2200_DAC_DIGITAL_VOLUME_2R 0x40E +#define WM2200_PDM_1 0x417 +#define WM2200_PDM_2 0x418 +#define WM2200_AUDIO_IF_1_1 0x500 +#define WM2200_AUDIO_IF_1_2 0x501 +#define WM2200_AUDIO_IF_1_3 0x502 +#define WM2200_AUDIO_IF_1_4 0x503 +#define WM2200_AUDIO_IF_1_5 0x504 +#define WM2200_AUDIO_IF_1_6 0x505 +#define WM2200_AUDIO_IF_1_7 0x506 +#define WM2200_AUDIO_IF_1_8 0x507 +#define WM2200_AUDIO_IF_1_9 0x508 +#define WM2200_AUDIO_IF_1_10 0x509 +#define WM2200_AUDIO_IF_1_11 0x50A +#define WM2200_AUDIO_IF_1_12 0x50B +#define WM2200_AUDIO_IF_1_13 0x50C +#define WM2200_AUDIO_IF_1_14 0x50D +#define WM2200_AUDIO_IF_1_15 0x50E +#define WM2200_AUDIO_IF_1_16 0x50F +#define WM2200_AUDIO_IF_1_17 0x510 +#define WM2200_AUDIO_IF_1_18 0x511 +#define WM2200_AUDIO_IF_1_19 0x512 +#define WM2200_AUDIO_IF_1_20 0x513 +#define WM2200_AUDIO_IF_1_21 0x514 +#define WM2200_AUDIO_IF_1_22 0x515 +#define WM2200_OUT1LMIX_INPUT_1_SOURCE 0x600 +#define WM2200_OUT1LMIX_INPUT_1_VOLUME 0x601 +#define WM2200_OUT1LMIX_INPUT_2_SOURCE 0x602 +#define WM2200_OUT1LMIX_INPUT_2_VOLUME 0x603 +#define WM2200_OUT1LMIX_INPUT_3_SOURCE 0x604 +#define WM2200_OUT1LMIX_INPUT_3_VOLUME 0x605 +#define WM2200_OUT1LMIX_INPUT_4_SOURCE 0x606 +#define WM2200_OUT1LMIX_INPUT_4_VOLUME 0x607 +#define WM2200_OUT1RMIX_INPUT_1_SOURCE 0x608 +#define WM2200_OUT1RMIX_INPUT_1_VOLUME 0x609 +#define WM2200_OUT1RMIX_INPUT_2_SOURCE 0x60A +#define WM2200_OUT1RMIX_INPUT_2_VOLUME 0x60B +#define WM2200_OUT1RMIX_INPUT_3_SOURCE 0x60C +#define WM2200_OUT1RMIX_INPUT_3_VOLUME 0x60D +#define WM2200_OUT1RMIX_INPUT_4_SOURCE 0x60E +#define WM2200_OUT1RMIX_INPUT_4_VOLUME 0x60F +#define WM2200_OUT2LMIX_INPUT_1_SOURCE 0x610 +#define WM2200_OUT2LMIX_INPUT_1_VOLUME 0x611 +#define WM2200_OUT2LMIX_INPUT_2_SOURCE 0x612 +#define WM2200_OUT2LMIX_INPUT_2_VOLUME 0x613 +#define WM2200_OUT2LMIX_INPUT_3_SOURCE 0x614 +#define WM2200_OUT2LMIX_INPUT_3_VOLUME 0x615 +#define WM2200_OUT2LMIX_INPUT_4_SOURCE 0x616 +#define WM2200_OUT2LMIX_INPUT_4_VOLUME 0x617 +#define WM2200_OUT2RMIX_INPUT_1_SOURCE 0x618 +#define WM2200_OUT2RMIX_INPUT_1_VOLUME 0x619 +#define WM2200_OUT2RMIX_INPUT_2_SOURCE 0x61A +#define WM2200_OUT2RMIX_INPUT_2_VOLUME 0x61B +#define WM2200_OUT2RMIX_INPUT_3_SOURCE 0x61C +#define WM2200_OUT2RMIX_INPUT_3_VOLUME 0x61D +#define WM2200_OUT2RMIX_INPUT_4_SOURCE 0x61E +#define WM2200_OUT2RMIX_INPUT_4_VOLUME 0x61F +#define WM2200_AIF1TX1MIX_INPUT_1_SOURCE 0x620 +#define WM2200_AIF1TX1MIX_INPUT_1_VOLUME 0x621 +#define WM2200_AIF1TX1MIX_INPUT_2_SOURCE 0x622 +#define WM2200_AIF1TX1MIX_INPUT_2_VOLUME 0x623 +#define WM2200_AIF1TX1MIX_INPUT_3_SOURCE 0x624 +#define WM2200_AIF1TX1MIX_INPUT_3_VOLUME 0x625 +#define WM2200_AIF1TX1MIX_INPUT_4_SOURCE 0x626 +#define WM2200_AIF1TX1MIX_INPUT_4_VOLUME 0x627 +#define WM2200_AIF1TX2MIX_INPUT_1_SOURCE 0x628 +#define WM2200_AIF1TX2MIX_INPUT_1_VOLUME 0x629 +#define WM2200_AIF1TX2MIX_INPUT_2_SOURCE 0x62A +#define WM2200_AIF1TX2MIX_INPUT_2_VOLUME 0x62B +#define WM2200_AIF1TX2MIX_INPUT_3_SOURCE 0x62C +#define WM2200_AIF1TX2MIX_INPUT_3_VOLUME 0x62D +#define WM2200_AIF1TX2MIX_INPUT_4_SOURCE 0x62E +#define WM2200_AIF1TX2MIX_INPUT_4_VOLUME 0x62F +#define WM2200_AIF1TX3MIX_INPUT_1_SOURCE 0x630 +#define WM2200_AIF1TX3MIX_INPUT_1_VOLUME 0x631 +#define WM2200_AIF1TX3MIX_INPUT_2_SOURCE 0x632 +#define WM2200_AIF1TX3MIX_INPUT_2_VOLUME 0x633 +#define WM2200_AIF1TX3MIX_INPUT_3_SOURCE 0x634 +#define WM2200_AIF1TX3MIX_INPUT_3_VOLUME 0x635 +#define WM2200_AIF1TX3MIX_INPUT_4_SOURCE 0x636 +#define WM2200_AIF1TX3MIX_INPUT_4_VOLUME 0x637 +#define WM2200_AIF1TX4MIX_INPUT_1_SOURCE 0x638 +#define WM2200_AIF1TX4MIX_INPUT_1_VOLUME 0x639 +#define WM2200_AIF1TX4MIX_INPUT_2_SOURCE 0x63A +#define WM2200_AIF1TX4MIX_INPUT_2_VOLUME 0x63B +#define WM2200_AIF1TX4MIX_INPUT_3_SOURCE 0x63C +#define WM2200_AIF1TX4MIX_INPUT_3_VOLUME 0x63D +#define WM2200_AIF1TX4MIX_INPUT_4_SOURCE 0x63E +#define WM2200_AIF1TX4MIX_INPUT_4_VOLUME 0x63F +#define WM2200_AIF1TX5MIX_INPUT_1_SOURCE 0x640 +#define WM2200_AIF1TX5MIX_INPUT_1_VOLUME 0x641 +#define WM2200_AIF1TX5MIX_INPUT_2_SOURCE 0x642 +#define WM2200_AIF1TX5MIX_INPUT_2_VOLUME 0x643 +#define WM2200_AIF1TX5MIX_INPUT_3_SOURCE 0x644 +#define WM2200_AIF1TX5MIX_INPUT_3_VOLUME 0x645 +#define WM2200_AIF1TX5MIX_INPUT_4_SOURCE 0x646 +#define WM2200_AIF1TX5MIX_INPUT_4_VOLUME 0x647 +#define WM2200_AIF1TX6MIX_INPUT_1_SOURCE 0x648 +#define WM2200_AIF1TX6MIX_INPUT_1_VOLUME 0x649 +#define WM2200_AIF1TX6MIX_INPUT_2_SOURCE 0x64A +#define WM2200_AIF1TX6MIX_INPUT_2_VOLUME 0x64B +#define WM2200_AIF1TX6MIX_INPUT_3_SOURCE 0x64C +#define WM2200_AIF1TX6MIX_INPUT_3_VOLUME 0x64D +#define WM2200_AIF1TX6MIX_INPUT_4_SOURCE 0x64E +#define WM2200_AIF1TX6MIX_INPUT_4_VOLUME 0x64F +#define WM2200_EQLMIX_INPUT_1_SOURCE 0x650 +#define WM2200_EQLMIX_INPUT_1_VOLUME 0x651 +#define WM2200_EQLMIX_INPUT_2_SOURCE 0x652 +#define WM2200_EQLMIX_INPUT_2_VOLUME 0x653 +#define WM2200_EQLMIX_INPUT_3_SOURCE 0x654 +#define WM2200_EQLMIX_INPUT_3_VOLUME 0x655 +#define WM2200_EQLMIX_INPUT_4_SOURCE 0x656 +#define WM2200_EQLMIX_INPUT_4_VOLUME 0x657 +#define WM2200_EQRMIX_INPUT_1_SOURCE 0x658 +#define WM2200_EQRMIX_INPUT_1_VOLUME 0x659 +#define WM2200_EQRMIX_INPUT_2_SOURCE 0x65A +#define WM2200_EQRMIX_INPUT_2_VOLUME 0x65B +#define WM2200_EQRMIX_INPUT_3_SOURCE 0x65C +#define WM2200_EQRMIX_INPUT_3_VOLUME 0x65D +#define WM2200_EQRMIX_INPUT_4_SOURCE 0x65E +#define WM2200_EQRMIX_INPUT_4_VOLUME 0x65F +#define WM2200_LHPF1MIX_INPUT_1_SOURCE 0x660 +#define WM2200_LHPF1MIX_INPUT_1_VOLUME 0x661 +#define WM2200_LHPF1MIX_INPUT_2_SOURCE 0x662 +#define WM2200_LHPF1MIX_INPUT_2_VOLUME 0x663 +#define WM2200_LHPF1MIX_INPUT_3_SOURCE 0x664 +#define WM2200_LHPF1MIX_INPUT_3_VOLUME 0x665 +#define WM2200_LHPF1MIX_INPUT_4_SOURCE 0x666 +#define WM2200_LHPF1MIX_INPUT_4_VOLUME 0x667 +#define WM2200_LHPF2MIX_INPUT_1_SOURCE 0x668 +#define WM2200_LHPF2MIX_INPUT_1_VOLUME 0x669 +#define WM2200_LHPF2MIX_INPUT_2_SOURCE 0x66A +#define WM2200_LHPF2MIX_INPUT_2_VOLUME 0x66B +#define WM2200_LHPF2MIX_INPUT_3_SOURCE 0x66C +#define WM2200_LHPF2MIX_INPUT_3_VOLUME 0x66D +#define WM2200_LHPF2MIX_INPUT_4_SOURCE 0x66E +#define WM2200_LHPF2MIX_INPUT_4_VOLUME 0x66F +#define WM2200_DSP1LMIX_INPUT_1_SOURCE 0x670 +#define WM2200_DSP1LMIX_INPUT_1_VOLUME 0x671 +#define WM2200_DSP1LMIX_INPUT_2_SOURCE 0x672 +#define WM2200_DSP1LMIX_INPUT_2_VOLUME 0x673 +#define WM2200_DSP1LMIX_INPUT_3_SOURCE 0x674 +#define WM2200_DSP1LMIX_INPUT_3_VOLUME 0x675 +#define WM2200_DSP1LMIX_INPUT_4_SOURCE 0x676 +#define WM2200_DSP1LMIX_INPUT_4_VOLUME 0x677 +#define WM2200_DSP1RMIX_INPUT_1_SOURCE 0x678 +#define WM2200_DSP1RMIX_INPUT_1_VOLUME 0x679 +#define WM2200_DSP1RMIX_INPUT_2_SOURCE 0x67A +#define WM2200_DSP1RMIX_INPUT_2_VOLUME 0x67B +#define WM2200_DSP1RMIX_INPUT_3_SOURCE 0x67C +#define WM2200_DSP1RMIX_INPUT_3_VOLUME 0x67D +#define WM2200_DSP1RMIX_INPUT_4_SOURCE 0x67E +#define WM2200_DSP1RMIX_INPUT_4_VOLUME 0x67F +#define WM2200_DSP1AUX1MIX_INPUT_1_SOURCE 0x680 +#define WM2200_DSP1AUX2MIX_INPUT_1_SOURCE 0x681 +#define WM2200_DSP1AUX3MIX_INPUT_1_SOURCE 0x682 +#define WM2200_DSP1AUX4MIX_INPUT_1_SOURCE 0x683 +#define WM2200_DSP1AUX5MIX_INPUT_1_SOURCE 0x684 +#define WM2200_DSP1AUX6MIX_INPUT_1_SOURCE 0x685 +#define WM2200_DSP2LMIX_INPUT_1_SOURCE 0x686 +#define WM2200_DSP2LMIX_INPUT_1_VOLUME 0x687 +#define WM2200_DSP2LMIX_INPUT_2_SOURCE 0x688 +#define WM2200_DSP2LMIX_INPUT_2_VOLUME 0x689 +#define WM2200_DSP2LMIX_INPUT_3_SOURCE 0x68A +#define WM2200_DSP2LMIX_INPUT_3_VOLUME 0x68B +#define WM2200_DSP2LMIX_INPUT_4_SOURCE 0x68C +#define WM2200_DSP2LMIX_INPUT_4_VOLUME 0x68D +#define WM2200_DSP2RMIX_INPUT_1_SOURCE 0x68E +#define WM2200_DSP2RMIX_INPUT_1_VOLUME 0x68F +#define WM2200_DSP2RMIX_INPUT_2_SOURCE 0x690 +#define WM2200_DSP2RMIX_INPUT_2_VOLUME 0x691 +#define WM2200_DSP2RMIX_INPUT_3_SOURCE 0x692 +#define WM2200_DSP2RMIX_INPUT_3_VOLUME 0x693 +#define WM2200_DSP2RMIX_INPUT_4_SOURCE 0x694 +#define WM2200_DSP2RMIX_INPUT_4_VOLUME 0x695 +#define WM2200_DSP2AUX1MIX_INPUT_1_SOURCE 0x696 +#define WM2200_DSP2AUX2MIX_INPUT_1_SOURCE 0x697 +#define WM2200_DSP2AUX3MIX_INPUT_1_SOURCE 0x698 +#define WM2200_DSP2AUX4MIX_INPUT_1_SOURCE 0x699 +#define WM2200_DSP2AUX5MIX_INPUT_1_SOURCE 0x69A +#define WM2200_DSP2AUX6MIX_INPUT_1_SOURCE 0x69B +#define WM2200_GPIO_CTRL_1 0x700 +#define WM2200_GPIO_CTRL_2 0x701 +#define WM2200_GPIO_CTRL_3 0x702 +#define WM2200_GPIO_CTRL_4 0x703 +#define WM2200_ADPS1_IRQ0 0x707 +#define WM2200_ADPS1_IRQ1 0x708 +#define WM2200_MISC_PAD_CTRL_1 0x709 +#define WM2200_INTERRUPT_STATUS_1 0x800 +#define WM2200_INTERRUPT_STATUS_1_MASK 0x801 +#define WM2200_INTERRUPT_STATUS_2 0x802 +#define WM2200_INTERRUPT_RAW_STATUS_2 0x803 +#define WM2200_INTERRUPT_STATUS_2_MASK 0x804 +#define WM2200_INTERRUPT_CONTROL 0x808 +#define WM2200_EQL_1 0x900 +#define WM2200_EQL_2 0x901 +#define WM2200_EQL_3 0x902 +#define WM2200_EQL_4 0x903 +#define WM2200_EQL_5 0x904 +#define WM2200_EQL_6 0x905 +#define WM2200_EQL_7 0x906 +#define WM2200_EQL_8 0x907 +#define WM2200_EQL_9 0x908 +#define WM2200_EQL_10 0x909 +#define WM2200_EQL_11 0x90A +#define WM2200_EQL_12 0x90B +#define WM2200_EQL_13 0x90C +#define WM2200_EQL_14 0x90D +#define WM2200_EQL_15 0x90E +#define WM2200_EQL_16 0x90F +#define WM2200_EQL_17 0x910 +#define WM2200_EQL_18 0x911 +#define WM2200_EQL_19 0x912 +#define WM2200_EQL_20 0x913 +#define WM2200_EQR_1 0x916 +#define WM2200_EQR_2 0x917 +#define WM2200_EQR_3 0x918 +#define WM2200_EQR_4 0x919 +#define WM2200_EQR_5 0x91A +#define WM2200_EQR_6 0x91B +#define WM2200_EQR_7 0x91C +#define WM2200_EQR_8 0x91D +#define WM2200_EQR_9 0x91E +#define WM2200_EQR_10 0x91F +#define WM2200_EQR_11 0x920 +#define WM2200_EQR_12 0x921 +#define WM2200_EQR_13 0x922 +#define WM2200_EQR_14 0x923 +#define WM2200_EQR_15 0x924 +#define WM2200_EQR_16 0x925 +#define WM2200_EQR_17 0x926 +#define WM2200_EQR_18 0x927 +#define WM2200_EQR_19 0x928 +#define WM2200_EQR_20 0x929 +#define WM2200_HPLPF1_1 0x93E +#define WM2200_HPLPF1_2 0x93F +#define WM2200_HPLPF2_1 0x942 +#define WM2200_HPLPF2_2 0x943 +#define WM2200_DSP1_CONTROL_1 0xA00 +#define WM2200_DSP1_CONTROL_2 0xA02 +#define WM2200_DSP1_CONTROL_3 0xA03 +#define WM2200_DSP1_CONTROL_4 0xA04 +#define WM2200_DSP1_CONTROL_5 0xA06 +#define WM2200_DSP1_CONTROL_6 0xA07 +#define WM2200_DSP1_CONTROL_7 0xA08 +#define WM2200_DSP1_CONTROL_8 0xA09 +#define WM2200_DSP1_CONTROL_9 0xA0A +#define WM2200_DSP1_CONTROL_10 0xA0B +#define WM2200_DSP1_CONTROL_11 0xA0C +#define WM2200_DSP1_CONTROL_12 0xA0D +#define WM2200_DSP1_CONTROL_13 0xA0F +#define WM2200_DSP1_CONTROL_14 0xA10 +#define WM2200_DSP1_CONTROL_15 0xA11 +#define WM2200_DSP1_CONTROL_16 0xA12 +#define WM2200_DSP1_CONTROL_17 0xA13 +#define WM2200_DSP1_CONTROL_18 0xA14 +#define WM2200_DSP1_CONTROL_19 0xA16 +#define WM2200_DSP1_CONTROL_20 0xA17 +#define WM2200_DSP1_CONTROL_21 0xA18 +#define WM2200_DSP1_CONTROL_22 0xA1A +#define WM2200_DSP1_CONTROL_23 0xA1B +#define WM2200_DSP1_CONTROL_24 0xA1C +#define WM2200_DSP1_CONTROL_25 0xA1E +#define WM2200_DSP1_CONTROL_26 0xA20 +#define WM2200_DSP1_CONTROL_27 0xA21 +#define WM2200_DSP1_CONTROL_28 0xA22 +#define WM2200_DSP1_CONTROL_29 0xA23 +#define WM2200_DSP1_CONTROL_30 0xA24 +#define WM2200_DSP1_CONTROL_31 0xA26 +#define WM2200_DSP2_CONTROL_1 0xB00 +#define WM2200_DSP2_CONTROL_2 0xB02 +#define WM2200_DSP2_CONTROL_3 0xB03 +#define WM2200_DSP2_CONTROL_4 0xB04 +#define WM2200_DSP2_CONTROL_5 0xB06 +#define WM2200_DSP2_CONTROL_6 0xB07 +#define WM2200_DSP2_CONTROL_7 0xB08 +#define WM2200_DSP2_CONTROL_8 0xB09 +#define WM2200_DSP2_CONTROL_9 0xB0A +#define WM2200_DSP2_CONTROL_10 0xB0B +#define WM2200_DSP2_CONTROL_11 0xB0C +#define WM2200_DSP2_CONTROL_12 0xB0D +#define WM2200_DSP2_CONTROL_13 0xB0F +#define WM2200_DSP2_CONTROL_14 0xB10 +#define WM2200_DSP2_CONTROL_15 0xB11 +#define WM2200_DSP2_CONTROL_16 0xB12 +#define WM2200_DSP2_CONTROL_17 0xB13 +#define WM2200_DSP2_CONTROL_18 0xB14 +#define WM2200_DSP2_CONTROL_19 0xB16 +#define WM2200_DSP2_CONTROL_20 0xB17 +#define WM2200_DSP2_CONTROL_21 0xB18 +#define WM2200_DSP2_CONTROL_22 0xB1A +#define WM2200_DSP2_CONTROL_23 0xB1B +#define WM2200_DSP2_CONTROL_24 0xB1C +#define WM2200_DSP2_CONTROL_25 0xB1E +#define WM2200_DSP2_CONTROL_26 0xB20 +#define WM2200_DSP2_CONTROL_27 0xB21 +#define WM2200_DSP2_CONTROL_28 0xB22 +#define WM2200_DSP2_CONTROL_29 0xB23 +#define WM2200_DSP2_CONTROL_30 0xB24 +#define WM2200_DSP2_CONTROL_31 0xB26 +#define WM2200_ANC_CTRL1 0xD00 +#define WM2200_ANC_CTRL2 0xD01 +#define WM2200_ANC_CTRL3 0xD02 +#define WM2200_ANC_CTRL7 0xD08 +#define WM2200_ANC_CTRL8 0xD09 +#define WM2200_ANC_CTRL9 0xD0A +#define WM2200_ANC_CTRL10 0xD0B +#define WM2200_ANC_CTRL11 0xD0C +#define WM2200_ANC_CTRL12 0xD0D +#define WM2200_ANC_CTRL13 0xD0E +#define WM2200_ANC_CTRL14 0xD0F +#define WM2200_ANC_CTRL15 0xD10 +#define WM2200_ANC_CTRL16 0xD11 +#define WM2200_ANC_CTRL17 0xD12 +#define WM2200_ANC_CTRL18 0xD15 +#define WM2200_ANC_CTRL19 0xD16 +#define WM2200_ANC_CTRL20 0xD17 +#define WM2200_ANC_CTRL21 0xD18 +#define WM2200_ANC_CTRL22 0xD19 +#define WM2200_ANC_CTRL23 0xD1A +#define WM2200_ANC_CTRL24 0xD1B +#define WM2200_ANC_CTRL25 0xD1C +#define WM2200_ANC_CTRL26 0xD1D +#define WM2200_ANC_CTRL27 0xD1E +#define WM2200_ANC_CTRL28 0xD1F +#define WM2200_ANC_CTRL29 0xD20 +#define WM2200_ANC_CTRL30 0xD21 +#define WM2200_ANC_CTRL31 0xD23 +#define WM2200_ANC_CTRL32 0xD24 +#define WM2200_ANC_CTRL33 0xD25 +#define WM2200_ANC_CTRL34 0xD27 +#define WM2200_ANC_CTRL35 0xD28 +#define WM2200_ANC_CTRL36 0xD29 +#define WM2200_ANC_CTRL37 0xD2A +#define WM2200_ANC_CTRL38 0xD2B +#define WM2200_ANC_CTRL39 0xD2C +#define WM2200_ANC_CTRL40 0xD2D +#define WM2200_ANC_CTRL41 0xD2E +#define WM2200_ANC_CTRL42 0xD2F +#define WM2200_ANC_CTRL43 0xD30 +#define WM2200_ANC_CTRL44 0xD31 +#define WM2200_ANC_CTRL45 0xD32 +#define WM2200_ANC_CTRL46 0xD33 +#define WM2200_ANC_CTRL47 0xD34 +#define WM2200_ANC_CTRL48 0xD35 +#define WM2200_ANC_CTRL49 0xD36 +#define WM2200_ANC_CTRL50 0xD37 +#define WM2200_ANC_CTRL51 0xD38 +#define WM2200_ANC_CTRL52 0xD39 +#define WM2200_ANC_CTRL53 0xD3A +#define WM2200_ANC_CTRL54 0xD3B +#define WM2200_ANC_CTRL55 0xD3C +#define WM2200_ANC_CTRL56 0xD3D +#define WM2200_ANC_CTRL57 0xD3E +#define WM2200_ANC_CTRL58 0xD3F +#define WM2200_ANC_CTRL59 0xD40 +#define WM2200_ANC_CTRL60 0xD41 +#define WM2200_ANC_CTRL61 0xD42 +#define WM2200_ANC_CTRL62 0xD43 +#define WM2200_ANC_CTRL63 0xD44 +#define WM2200_ANC_CTRL64 0xD45 +#define WM2200_ANC_CTRL65 0xD46 +#define WM2200_ANC_CTRL66 0xD47 +#define WM2200_ANC_CTRL67 0xD48 +#define WM2200_ANC_CTRL68 0xD49 +#define WM2200_ANC_CTRL69 0xD4A +#define WM2200_ANC_CTRL70 0xD4B +#define WM2200_ANC_CTRL71 0xD4C +#define WM2200_ANC_CTRL72 0xD4D +#define WM2200_ANC_CTRL73 0xD4E +#define WM2200_ANC_CTRL74 0xD4F +#define WM2200_ANC_CTRL75 0xD50 +#define WM2200_ANC_CTRL76 0xD51 +#define WM2200_ANC_CTRL77 0xD52 +#define WM2200_ANC_CTRL78 0xD53 +#define WM2200_ANC_CTRL79 0xD54 +#define WM2200_ANC_CTRL80 0xD55 +#define WM2200_ANC_CTRL81 0xD56 +#define WM2200_ANC_CTRL82 0xD57 +#define WM2200_ANC_CTRL83 0xD58 +#define WM2200_ANC_CTRL84 0xD5B +#define WM2200_ANC_CTRL85 0xD5C +#define WM2200_ANC_CTRL86 0xD5F +#define WM2200_ANC_CTRL87 0xD60 +#define WM2200_ANC_CTRL88 0xD61 +#define WM2200_ANC_CTRL89 0xD62 +#define WM2200_ANC_CTRL90 0xD63 +#define WM2200_ANC_CTRL91 0xD64 +#define WM2200_ANC_CTRL92 0xD65 +#define WM2200_ANC_CTRL93 0xD66 +#define WM2200_ANC_CTRL94 0xD67 +#define WM2200_ANC_CTRL95 0xD68 +#define WM2200_ANC_CTRL96 0xD69 +#define WM2200_DSP1_DM_0 0x3000 +#define WM2200_DSP1_DM_1 0x3001 +#define WM2200_DSP1_DM_2 0x3002 +#define WM2200_DSP1_DM_3 0x3003 +#define WM2200_DSP1_DM_2044 0x37FC +#define WM2200_DSP1_DM_2045 0x37FD +#define WM2200_DSP1_DM_2046 0x37FE +#define WM2200_DSP1_DM_2047 0x37FF +#define WM2200_DSP1_PM_0 0x3800 +#define WM2200_DSP1_PM_1 0x3801 +#define WM2200_DSP1_PM_2 0x3802 +#define WM2200_DSP1_PM_3 0x3803 +#define WM2200_DSP1_PM_4 0x3804 +#define WM2200_DSP1_PM_5 0x3805 +#define WM2200_DSP1_PM_762 0x3AFA +#define WM2200_DSP1_PM_763 0x3AFB +#define WM2200_DSP1_PM_764 0x3AFC +#define WM2200_DSP1_PM_765 0x3AFD +#define WM2200_DSP1_PM_766 0x3AFE +#define WM2200_DSP1_PM_767 0x3AFF +#define WM2200_DSP1_ZM_0 0x3C00 +#define WM2200_DSP1_ZM_1 0x3C01 +#define WM2200_DSP1_ZM_2 0x3C02 +#define WM2200_DSP1_ZM_3 0x3C03 +#define WM2200_DSP1_ZM_1020 0x3FFC +#define WM2200_DSP1_ZM_1021 0x3FFD +#define WM2200_DSP1_ZM_1022 0x3FFE +#define WM2200_DSP1_ZM_1023 0x3FFF +#define WM2200_DSP2_DM_0 0x4000 +#define WM2200_DSP2_DM_1 0x4001 +#define WM2200_DSP2_DM_2 0x4002 +#define WM2200_DSP2_DM_3 0x4003 +#define WM2200_DSP2_DM_2044 0x47FC +#define WM2200_DSP2_DM_2045 0x47FD +#define WM2200_DSP2_DM_2046 0x47FE +#define WM2200_DSP2_DM_2047 0x47FF +#define WM2200_DSP2_PM_0 0x4800 +#define WM2200_DSP2_PM_1 0x4801 +#define WM2200_DSP2_PM_2 0x4802 +#define WM2200_DSP2_PM_3 0x4803 +#define WM2200_DSP2_PM_4 0x4804 +#define WM2200_DSP2_PM_5 0x4805 +#define WM2200_DSP2_PM_762 0x4AFA +#define WM2200_DSP2_PM_763 0x4AFB +#define WM2200_DSP2_PM_764 0x4AFC +#define WM2200_DSP2_PM_765 0x4AFD +#define WM2200_DSP2_PM_766 0x4AFE +#define WM2200_DSP2_PM_767 0x4AFF +#define WM2200_DSP2_ZM_0 0x4C00 +#define WM2200_DSP2_ZM_1 0x4C01 +#define WM2200_DSP2_ZM_2 0x4C02 +#define WM2200_DSP2_ZM_3 0x4C03 +#define WM2200_DSP2_ZM_1020 0x4FFC +#define WM2200_DSP2_ZM_1021 0x4FFD +#define WM2200_DSP2_ZM_1022 0x4FFE +#define WM2200_DSP2_ZM_1023 0x4FFF + +#define WM2200_REGISTER_COUNT 494 +#define WM2200_MAX_REGISTER 0x4FFF + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - software reset + */ +#define WM2200_SW_RESET_CHIP_ID1_MASK 0xFFFF /* SW_RESET_CHIP_ID1 - [15:0] */ +#define WM2200_SW_RESET_CHIP_ID1_SHIFT 0 /* SW_RESET_CHIP_ID1 - [15:0] */ +#define WM2200_SW_RESET_CHIP_ID1_WIDTH 16 /* SW_RESET_CHIP_ID1 - [15:0] */ + +/* + * R1 (0x01) - Device Revision + */ +#define WM2200_DEVICE_REVISION_MASK 0x000F /* DEVICE_REVISION - [3:0] */ +#define WM2200_DEVICE_REVISION_SHIFT 0 /* DEVICE_REVISION - [3:0] */ +#define WM2200_DEVICE_REVISION_WIDTH 4 /* DEVICE_REVISION - [3:0] */ + +/* + * R11 (0x0B) - Tone Generator 1 + */ +#define WM2200_TONE_ENA 0x0001 /* TONE_ENA */ +#define WM2200_TONE_ENA_MASK 0x0001 /* TONE_ENA */ +#define WM2200_TONE_ENA_SHIFT 0 /* TONE_ENA */ +#define WM2200_TONE_ENA_WIDTH 1 /* TONE_ENA */ + +/* + * R258 (0x102) - Clocking 3 + */ +#define WM2200_SYSCLK_FREQ_MASK 0x0700 /* SYSCLK_FREQ - [10:8] */ +#define WM2200_SYSCLK_FREQ_SHIFT 8 /* SYSCLK_FREQ - [10:8] */ +#define WM2200_SYSCLK_FREQ_WIDTH 3 /* SYSCLK_FREQ - [10:8] */ +#define WM2200_SYSCLK_ENA 0x0040 /* SYSCLK_ENA */ +#define WM2200_SYSCLK_ENA_MASK 0x0040 /* SYSCLK_ENA */ +#define WM2200_SYSCLK_ENA_SHIFT 6 /* SYSCLK_ENA */ +#define WM2200_SYSCLK_ENA_WIDTH 1 /* SYSCLK_ENA */ +#define WM2200_SYSCLK_SRC_MASK 0x000F /* SYSCLK_SRC - [3:0] */ +#define WM2200_SYSCLK_SRC_SHIFT 0 /* SYSCLK_SRC - [3:0] */ +#define WM2200_SYSCLK_SRC_WIDTH 4 /* SYSCLK_SRC - [3:0] */ + +/* + * R259 (0x103) - Clocking 4 + */ +#define WM2200_SAMPLE_RATE_1_MASK 0x001F /* SAMPLE_RATE_1 - [4:0] */ +#define WM2200_SAMPLE_RATE_1_SHIFT 0 /* SAMPLE_RATE_1 - [4:0] */ +#define WM2200_SAMPLE_RATE_1_WIDTH 5 /* SAMPLE_RATE_1 - [4:0] */ + +/* + * R273 (0x111) - FLL Control 1 + */ +#define WM2200_FLL_ENA 0x0001 /* FLL_ENA */ +#define WM2200_FLL_ENA_MASK 0x0001 /* FLL_ENA */ +#define WM2200_FLL_ENA_SHIFT 0 /* FLL_ENA */ +#define WM2200_FLL_ENA_WIDTH 1 /* FLL_ENA */ + +/* + * R274 (0x112) - FLL Control 2 + */ +#define WM2200_FLL_OUTDIV_MASK 0x3F00 /* FLL_OUTDIV - [13:8] */ +#define WM2200_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [13:8] */ +#define WM2200_FLL_OUTDIV_WIDTH 6 /* FLL_OUTDIV - [13:8] */ +#define WM2200_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */ +#define WM2200_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */ +#define WM2200_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */ + +/* + * R275 (0x113) - FLL Control 3 + */ +#define WM2200_FLL_FRACN_ENA 0x0001 /* FLL_FRACN_ENA */ +#define WM2200_FLL_FRACN_ENA_MASK 0x0001 /* FLL_FRACN_ENA */ +#define WM2200_FLL_FRACN_ENA_SHIFT 0 /* FLL_FRACN_ENA */ +#define WM2200_FLL_FRACN_ENA_WIDTH 1 /* FLL_FRACN_ENA */ + +/* + * R276 (0x114) - FLL Control 4 + */ +#define WM2200_FLL_THETA_MASK 0xFFFF /* FLL_THETA - [15:0] */ +#define WM2200_FLL_THETA_SHIFT 0 /* FLL_THETA - [15:0] */ +#define WM2200_FLL_THETA_WIDTH 16 /* FLL_THETA - [15:0] */ + +/* + * R278 (0x116) - FLL Control 6 + */ +#define WM2200_FLL_N_MASK 0x03FF /* FLL_N - [9:0] */ +#define WM2200_FLL_N_SHIFT 0 /* FLL_N - [9:0] */ +#define WM2200_FLL_N_WIDTH 10 /* FLL_N - [9:0] */ + +/* + * R279 (0x117) - FLL Control 7 + */ +#define WM2200_FLL_CLK_REF_DIV_MASK 0x0030 /* FLL_CLK_REF_DIV - [5:4] */ +#define WM2200_FLL_CLK_REF_DIV_SHIFT 4 /* FLL_CLK_REF_DIV - [5:4] */ +#define WM2200_FLL_CLK_REF_DIV_WIDTH 2 /* FLL_CLK_REF_DIV - [5:4] */ +#define WM2200_FLL_CLK_REF_SRC_MASK 0x0003 /* FLL_CLK_REF_SRC - [1:0] */ +#define WM2200_FLL_CLK_REF_SRC_SHIFT 0 /* FLL_CLK_REF_SRC - [1:0] */ +#define WM2200_FLL_CLK_REF_SRC_WIDTH 2 /* FLL_CLK_REF_SRC - [1:0] */ + +/* + * R281 (0x119) - FLL EFS 1 + */ +#define WM2200_FLL_LAMBDA_MASK 0xFFFF /* FLL_LAMBDA - [15:0] */ +#define WM2200_FLL_LAMBDA_SHIFT 0 /* FLL_LAMBDA - [15:0] */ +#define WM2200_FLL_LAMBDA_WIDTH 16 /* FLL_LAMBDA - [15:0] */ + +/* + * R282 (0x11A) - FLL EFS 2 + */ +#define WM2200_FLL_EFS_ENA 0x0001 /* FLL_EFS_ENA */ +#define WM2200_FLL_EFS_ENA_MASK 0x0001 /* FLL_EFS_ENA */ +#define WM2200_FLL_EFS_ENA_SHIFT 0 /* FLL_EFS_ENA */ +#define WM2200_FLL_EFS_ENA_WIDTH 1 /* FLL_EFS_ENA */ + +/* + * R512 (0x200) - Mic Charge Pump 1 + */ +#define WM2200_CPMIC_BYPASS_MODE 0x0020 /* CPMIC_BYPASS_MODE */ +#define WM2200_CPMIC_BYPASS_MODE_MASK 0x0020 /* CPMIC_BYPASS_MODE */ +#define WM2200_CPMIC_BYPASS_MODE_SHIFT 5 /* CPMIC_BYPASS_MODE */ +#define WM2200_CPMIC_BYPASS_MODE_WIDTH 1 /* CPMIC_BYPASS_MODE */ +#define WM2200_CPMIC_ENA 0x0001 /* CPMIC_ENA */ +#define WM2200_CPMIC_ENA_MASK 0x0001 /* CPMIC_ENA */ +#define WM2200_CPMIC_ENA_SHIFT 0 /* CPMIC_ENA */ +#define WM2200_CPMIC_ENA_WIDTH 1 /* CPMIC_ENA */ + +/* + * R513 (0x201) - Mic Charge Pump 2 + */ +#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_MASK 0xF800 /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */ +#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_SHIFT 11 /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */ +#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_WIDTH 5 /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */ + +/* + * R514 (0x202) - DM Charge Pump 1 + */ +#define WM2200_CPDM_ENA 0x0001 /* CPDM_ENA */ +#define WM2200_CPDM_ENA_MASK 0x0001 /* CPDM_ENA */ +#define WM2200_CPDM_ENA_SHIFT 0 /* CPDM_ENA */ +#define WM2200_CPDM_ENA_WIDTH 1 /* CPDM_ENA */ + +/* + * R524 (0x20C) - Mic Bias Ctrl 1 + */ +#define WM2200_MICB1_DISCH 0x0040 /* MICB1_DISCH */ +#define WM2200_MICB1_DISCH_MASK 0x0040 /* MICB1_DISCH */ +#define WM2200_MICB1_DISCH_SHIFT 6 /* MICB1_DISCH */ +#define WM2200_MICB1_DISCH_WIDTH 1 /* MICB1_DISCH */ +#define WM2200_MICB1_RATE 0x0020 /* MICB1_RATE */ +#define WM2200_MICB1_RATE_MASK 0x0020 /* MICB1_RATE */ +#define WM2200_MICB1_RATE_SHIFT 5 /* MICB1_RATE */ +#define WM2200_MICB1_RATE_WIDTH 1 /* MICB1_RATE */ +#define WM2200_MICB1_LVL_MASK 0x001C /* MICB1_LVL - [4:2] */ +#define WM2200_MICB1_LVL_SHIFT 2 /* MICB1_LVL - [4:2] */ +#define WM2200_MICB1_LVL_WIDTH 3 /* MICB1_LVL - [4:2] */ +#define WM2200_MICB1_MODE 0x0002 /* MICB1_MODE */ +#define WM2200_MICB1_MODE_MASK 0x0002 /* MICB1_MODE */ +#define WM2200_MICB1_MODE_SHIFT 1 /* MICB1_MODE */ +#define WM2200_MICB1_MODE_WIDTH 1 /* MICB1_MODE */ +#define WM2200_MICB1_ENA 0x0001 /* MICB1_ENA */ +#define WM2200_MICB1_ENA_MASK 0x0001 /* MICB1_ENA */ +#define WM2200_MICB1_ENA_SHIFT 0 /* MICB1_ENA */ +#define WM2200_MICB1_ENA_WIDTH 1 /* MICB1_ENA */ + +/* + * R525 (0x20D) - Mic Bias Ctrl 2 + */ +#define WM2200_MICB2_DISCH 0x0040 /* MICB2_DISCH */ +#define WM2200_MICB2_DISCH_MASK 0x0040 /* MICB2_DISCH */ +#define WM2200_MICB2_DISCH_SHIFT 6 /* MICB2_DISCH */ +#define WM2200_MICB2_DISCH_WIDTH 1 /* MICB2_DISCH */ +#define WM2200_MICB2_RATE 0x0020 /* MICB2_RATE */ +#define WM2200_MICB2_RATE_MASK 0x0020 /* MICB2_RATE */ +#define WM2200_MICB2_RATE_SHIFT 5 /* MICB2_RATE */ +#define WM2200_MICB2_RATE_WIDTH 1 /* MICB2_RATE */ +#define WM2200_MICB2_LVL_MASK 0x001C /* MICB2_LVL - [4:2] */ +#define WM2200_MICB2_LVL_SHIFT 2 /* MICB2_LVL - [4:2] */ +#define WM2200_MICB2_LVL_WIDTH 3 /* MICB2_LVL - [4:2] */ +#define WM2200_MICB2_MODE 0x0002 /* MICB2_MODE */ +#define WM2200_MICB2_MODE_MASK 0x0002 /* MICB2_MODE */ +#define WM2200_MICB2_MODE_SHIFT 1 /* MICB2_MODE */ +#define WM2200_MICB2_MODE_WIDTH 1 /* MICB2_MODE */ +#define WM2200_MICB2_ENA 0x0001 /* MICB2_ENA */ +#define WM2200_MICB2_ENA_MASK 0x0001 /* MICB2_ENA */ +#define WM2200_MICB2_ENA_SHIFT 0 /* MICB2_ENA */ +#define WM2200_MICB2_ENA_WIDTH 1 /* MICB2_ENA */ + +/* + * R527 (0x20F) - Ear Piece Ctrl 1 + */ +#define WM2200_EPD_LP_ENA 0x4000 /* EPD_LP_ENA */ +#define WM2200_EPD_LP_ENA_MASK 0x4000 /* EPD_LP_ENA */ +#define WM2200_EPD_LP_ENA_SHIFT 14 /* EPD_LP_ENA */ +#define WM2200_EPD_LP_ENA_WIDTH 1 /* EPD_LP_ENA */ +#define WM2200_EPD_OUTP_LP_ENA 0x2000 /* EPD_OUTP_LP_ENA */ +#define WM2200_EPD_OUTP_LP_ENA_MASK 0x2000 /* EPD_OUTP_LP_ENA */ +#define WM2200_EPD_OUTP_LP_ENA_SHIFT 13 /* EPD_OUTP_LP_ENA */ +#define WM2200_EPD_OUTP_LP_ENA_WIDTH 1 /* EPD_OUTP_LP_ENA */ +#define WM2200_EPD_RMV_SHRT_LP 0x1000 /* EPD_RMV_SHRT_LP */ +#define WM2200_EPD_RMV_SHRT_LP_MASK 0x1000 /* EPD_RMV_SHRT_LP */ +#define WM2200_EPD_RMV_SHRT_LP_SHIFT 12 /* EPD_RMV_SHRT_LP */ +#define WM2200_EPD_RMV_SHRT_LP_WIDTH 1 /* EPD_RMV_SHRT_LP */ +#define WM2200_EPD_LN_ENA 0x0800 /* EPD_LN_ENA */ +#define WM2200_EPD_LN_ENA_MASK 0x0800 /* EPD_LN_ENA */ +#define WM2200_EPD_LN_ENA_SHIFT 11 /* EPD_LN_ENA */ +#define WM2200_EPD_LN_ENA_WIDTH 1 /* EPD_LN_ENA */ +#define WM2200_EPD_OUTP_LN_ENA 0x0400 /* EPD_OUTP_LN_ENA */ +#define WM2200_EPD_OUTP_LN_ENA_MASK 0x0400 /* EPD_OUTP_LN_ENA */ +#define WM2200_EPD_OUTP_LN_ENA_SHIFT 10 /* EPD_OUTP_LN_ENA */ +#define WM2200_EPD_OUTP_LN_ENA_WIDTH 1 /* EPD_OUTP_LN_ENA */ +#define WM2200_EPD_RMV_SHRT_LN 0x0200 /* EPD_RMV_SHRT_LN */ +#define WM2200_EPD_RMV_SHRT_LN_MASK 0x0200 /* EPD_RMV_SHRT_LN */ +#define WM2200_EPD_RMV_SHRT_LN_SHIFT 9 /* EPD_RMV_SHRT_LN */ +#define WM2200_EPD_RMV_SHRT_LN_WIDTH 1 /* EPD_RMV_SHRT_LN */ + +/* + * R528 (0x210) - Ear Piece Ctrl 2 + */ +#define WM2200_EPD_RP_ENA 0x4000 /* EPD_RP_ENA */ +#define WM2200_EPD_RP_ENA_MASK 0x4000 /* EPD_RP_ENA */ +#define WM2200_EPD_RP_ENA_SHIFT 14 /* EPD_RP_ENA */ +#define WM2200_EPD_RP_ENA_WIDTH 1 /* EPD_RP_ENA */ +#define WM2200_EPD_OUTP_RP_ENA 0x2000 /* EPD_OUTP_RP_ENA */ +#define WM2200_EPD_OUTP_RP_ENA_MASK 0x2000 /* EPD_OUTP_RP_ENA */ +#define WM2200_EPD_OUTP_RP_ENA_SHIFT 13 /* EPD_OUTP_RP_ENA */ +#define WM2200_EPD_OUTP_RP_ENA_WIDTH 1 /* EPD_OUTP_RP_ENA */ +#define WM2200_EPD_RMV_SHRT_RP 0x1000 /* EPD_RMV_SHRT_RP */ +#define WM2200_EPD_RMV_SHRT_RP_MASK 0x1000 /* EPD_RMV_SHRT_RP */ +#define WM2200_EPD_RMV_SHRT_RP_SHIFT 12 /* EPD_RMV_SHRT_RP */ +#define WM2200_EPD_RMV_SHRT_RP_WIDTH 1 /* EPD_RMV_SHRT_RP */ +#define WM2200_EPD_RN_ENA 0x0800 /* EPD_RN_ENA */ +#define WM2200_EPD_RN_ENA_MASK 0x0800 /* EPD_RN_ENA */ +#define WM2200_EPD_RN_ENA_SHIFT 11 /* EPD_RN_ENA */ +#define WM2200_EPD_RN_ENA_WIDTH 1 /* EPD_RN_ENA */ +#define WM2200_EPD_OUTP_RN_ENA 0x0400 /* EPD_OUTP_RN_ENA */ +#define WM2200_EPD_OUTP_RN_ENA_MASK 0x0400 /* EPD_OUTP_RN_ENA */ +#define WM2200_EPD_OUTP_RN_ENA_SHIFT 10 /* EPD_OUTP_RN_ENA */ +#define WM2200_EPD_OUTP_RN_ENA_WIDTH 1 /* EPD_OUTP_RN_ENA */ +#define WM2200_EPD_RMV_SHRT_RN 0x0200 /* EPD_RMV_SHRT_RN */ +#define WM2200_EPD_RMV_SHRT_RN_MASK 0x0200 /* EPD_RMV_SHRT_RN */ +#define WM2200_EPD_RMV_SHRT_RN_SHIFT 9 /* EPD_RMV_SHRT_RN */ +#define WM2200_EPD_RMV_SHRT_RN_WIDTH 1 /* EPD_RMV_SHRT_RN */ + +/* + * R769 (0x301) - Input Enables + */ +#define WM2200_IN3L_ENA 0x0020 /* IN3L_ENA */ +#define WM2200_IN3L_ENA_MASK 0x0020 /* IN3L_ENA */ +#define WM2200_IN3L_ENA_SHIFT 5 /* IN3L_ENA */ +#define WM2200_IN3L_ENA_WIDTH 1 /* IN3L_ENA */ +#define WM2200_IN3R_ENA 0x0010 /* IN3R_ENA */ +#define WM2200_IN3R_ENA_MASK 0x0010 /* IN3R_ENA */ +#define WM2200_IN3R_ENA_SHIFT 4 /* IN3R_ENA */ +#define WM2200_IN3R_ENA_WIDTH 1 /* IN3R_ENA */ +#define WM2200_IN2L_ENA 0x0008 /* IN2L_ENA */ +#define WM2200_IN2L_ENA_MASK 0x0008 /* IN2L_ENA */ +#define WM2200_IN2L_ENA_SHIFT 3 /* IN2L_ENA */ +#define WM2200_IN2L_ENA_WIDTH 1 /* IN2L_ENA */ +#define WM2200_IN2R_ENA 0x0004 /* IN2R_ENA */ +#define WM2200_IN2R_ENA_MASK 0x0004 /* IN2R_ENA */ +#define WM2200_IN2R_ENA_SHIFT 2 /* IN2R_ENA */ +#define WM2200_IN2R_ENA_WIDTH 1 /* IN2R_ENA */ +#define WM2200_IN1L_ENA 0x0002 /* IN1L_ENA */ +#define WM2200_IN1L_ENA_MASK 0x0002 /* IN1L_ENA */ +#define WM2200_IN1L_ENA_SHIFT 1 /* IN1L_ENA */ +#define WM2200_IN1L_ENA_WIDTH 1 /* IN1L_ENA */ +#define WM2200_IN1R_ENA 0x0001 /* IN1R_ENA */ +#define WM2200_IN1R_ENA_MASK 0x0001 /* IN1R_ENA */ +#define WM2200_IN1R_ENA_SHIFT 0 /* IN1R_ENA */ +#define WM2200_IN1R_ENA_WIDTH 1 /* IN1R_ENA */ + +/* + * R770 (0x302) - IN1L Control + */ +#define WM2200_IN1_OSR 0x2000 /* IN1_OSR */ +#define WM2200_IN1_OSR_MASK 0x2000 /* IN1_OSR */ +#define WM2200_IN1_OSR_SHIFT 13 /* IN1_OSR */ +#define WM2200_IN1_OSR_WIDTH 1 /* IN1_OSR */ +#define WM2200_IN1_DMIC_SUP_MASK 0x1800 /* IN1_DMIC_SUP - [12:11] */ +#define WM2200_IN1_DMIC_SUP_SHIFT 11 /* IN1_DMIC_SUP - [12:11] */ +#define WM2200_IN1_DMIC_SUP_WIDTH 2 /* IN1_DMIC_SUP - [12:11] */ +#define WM2200_IN1_MODE_MASK 0x0600 /* IN1_MODE - [10:9] */ +#define WM2200_IN1_MODE_SHIFT 9 /* IN1_MODE - [10:9] */ +#define WM2200_IN1_MODE_WIDTH 2 /* IN1_MODE - [10:9] */ +#define WM2200_IN1L_PGA_VOL_MASK 0x00FE /* IN1L_PGA_VOL - [7:1] */ +#define WM2200_IN1L_PGA_VOL_SHIFT 1 /* IN1L_PGA_VOL - [7:1] */ +#define WM2200_IN1L_PGA_VOL_WIDTH 7 /* IN1L_PGA_VOL - [7:1] */ + +/* + * R771 (0x303) - IN1R Control + */ +#define WM2200_IN1R_PGA_VOL_MASK 0x00FE /* IN1R_PGA_VOL - [7:1] */ +#define WM2200_IN1R_PGA_VOL_SHIFT 1 /* IN1R_PGA_VOL - [7:1] */ +#define WM2200_IN1R_PGA_VOL_WIDTH 7 /* IN1R_PGA_VOL - [7:1] */ + +/* + * R772 (0x304) - IN2L Control + */ +#define WM2200_IN2_OSR 0x2000 /* IN2_OSR */ +#define WM2200_IN2_OSR_MASK 0x2000 /* IN2_OSR */ +#define WM2200_IN2_OSR_SHIFT 13 /* IN2_OSR */ +#define WM2200_IN2_OSR_WIDTH 1 /* IN2_OSR */ +#define WM2200_IN2_DMIC_SUP_MASK 0x1800 /* IN2_DMIC_SUP - [12:11] */ +#define WM2200_IN2_DMIC_SUP_SHIFT 11 /* IN2_DMIC_SUP - [12:11] */ +#define WM2200_IN2_DMIC_SUP_WIDTH 2 /* IN2_DMIC_SUP - [12:11] */ +#define WM2200_IN2_MODE_MASK 0x0600 /* IN2_MODE - [10:9] */ +#define WM2200_IN2_MODE_SHIFT 9 /* IN2_MODE - [10:9] */ +#define WM2200_IN2_MODE_WIDTH 2 /* IN2_MODE - [10:9] */ +#define WM2200_IN2L_PGA_VOL_MASK 0x00FE /* IN2L_PGA_VOL - [7:1] */ +#define WM2200_IN2L_PGA_VOL_SHIFT 1 /* IN2L_PGA_VOL - [7:1] */ +#define WM2200_IN2L_PGA_VOL_WIDTH 7 /* IN2L_PGA_VOL - [7:1] */ + +/* + * R773 (0x305) - IN2R Control + */ +#define WM2200_IN2R_PGA_VOL_MASK 0x00FE /* IN2R_PGA_VOL - [7:1] */ +#define WM2200_IN2R_PGA_VOL_SHIFT 1 /* IN2R_PGA_VOL - [7:1] */ +#define WM2200_IN2R_PGA_VOL_WIDTH 7 /* IN2R_PGA_VOL - [7:1] */ + +/* + * R774 (0x306) - IN3L Control + */ +#define WM2200_IN3_OSR 0x2000 /* IN3_OSR */ +#define WM2200_IN3_OSR_MASK 0x2000 /* IN3_OSR */ +#define WM2200_IN3_OSR_SHIFT 13 /* IN3_OSR */ +#define WM2200_IN3_OSR_WIDTH 1 /* IN3_OSR */ +#define WM2200_IN3_DMIC_SUP_MASK 0x1800 /* IN3_DMIC_SUP - [12:11] */ +#define WM2200_IN3_DMIC_SUP_SHIFT 11 /* IN3_DMIC_SUP - [12:11] */ +#define WM2200_IN3_DMIC_SUP_WIDTH 2 /* IN3_DMIC_SUP - [12:11] */ +#define WM2200_IN3_MODE_MASK 0x0600 /* IN3_MODE - [10:9] */ +#define WM2200_IN3_MODE_SHIFT 9 /* IN3_MODE - [10:9] */ +#define WM2200_IN3_MODE_WIDTH 2 /* IN3_MODE - [10:9] */ +#define WM2200_IN3L_PGA_VOL_MASK 0x00FE /* IN3L_PGA_VOL - [7:1] */ +#define WM2200_IN3L_PGA_VOL_SHIFT 1 /* IN3L_PGA_VOL - [7:1] */ +#define WM2200_IN3L_PGA_VOL_WIDTH 7 /* IN3L_PGA_VOL - [7:1] */ + +/* + * R775 (0x307) - IN3R Control + */ +#define WM2200_IN3R_PGA_VOL_MASK 0x00FE /* IN3R_PGA_VOL - [7:1] */ +#define WM2200_IN3R_PGA_VOL_SHIFT 1 /* IN3R_PGA_VOL - [7:1] */ +#define WM2200_IN3R_PGA_VOL_WIDTH 7 /* IN3R_PGA_VOL - [7:1] */ + +/* + * R778 (0x30A) - RXANC_SRC + */ +#define WM2200_IN_RXANC_SEL_MASK 0x0007 /* IN_RXANC_SEL - [2:0] */ +#define WM2200_IN_RXANC_SEL_SHIFT 0 /* IN_RXANC_SEL - [2:0] */ +#define WM2200_IN_RXANC_SEL_WIDTH 3 /* IN_RXANC_SEL - [2:0] */ + +/* + * R779 (0x30B) - Input Volume Ramp + */ +#define WM2200_IN_VD_RAMP_MASK 0x0070 /* IN_VD_RAMP - [6:4] */ +#define WM2200_IN_VD_RAMP_SHIFT 4 /* IN_VD_RAMP - [6:4] */ +#define WM2200_IN_VD_RAMP_WIDTH 3 /* IN_VD_RAMP - [6:4] */ +#define WM2200_IN_VI_RAMP_MASK 0x0007 /* IN_VI_RAMP - [2:0] */ +#define WM2200_IN_VI_RAMP_SHIFT 0 /* IN_VI_RAMP - [2:0] */ +#define WM2200_IN_VI_RAMP_WIDTH 3 /* IN_VI_RAMP - [2:0] */ + +/* + * R780 (0x30C) - ADC Digital Volume 1L + */ +#define WM2200_IN_VU 0x0200 /* IN_VU */ +#define WM2200_IN_VU_MASK 0x0200 /* IN_VU */ +#define WM2200_IN_VU_SHIFT 9 /* IN_VU */ +#define WM2200_IN_VU_WIDTH 1 /* IN_VU */ +#define WM2200_IN1L_MUTE 0x0100 /* IN1L_MUTE */ +#define WM2200_IN1L_MUTE_MASK 0x0100 /* IN1L_MUTE */ +#define WM2200_IN1L_MUTE_SHIFT 8 /* IN1L_MUTE */ +#define WM2200_IN1L_MUTE_WIDTH 1 /* IN1L_MUTE */ +#define WM2200_IN1L_DIG_VOL_MASK 0x00FF /* IN1L_DIG_VOL - [7:0] */ +#define WM2200_IN1L_DIG_VOL_SHIFT 0 /* IN1L_DIG_VOL - [7:0] */ +#define WM2200_IN1L_DIG_VOL_WIDTH 8 /* IN1L_DIG_VOL - [7:0] */ + +/* + * R781 (0x30D) - ADC Digital Volume 1R + */ +#define WM2200_IN_VU 0x0200 /* IN_VU */ +#define WM2200_IN_VU_MASK 0x0200 /* IN_VU */ +#define WM2200_IN_VU_SHIFT 9 /* IN_VU */ +#define WM2200_IN_VU_WIDTH 1 /* IN_VU */ +#define WM2200_IN1R_MUTE 0x0100 /* IN1R_MUTE */ +#define WM2200_IN1R_MUTE_MASK 0x0100 /* IN1R_MUTE */ +#define WM2200_IN1R_MUTE_SHIFT 8 /* IN1R_MUTE */ +#define WM2200_IN1R_MUTE_WIDTH 1 /* IN1R_MUTE */ +#define WM2200_IN1R_DIG_VOL_MASK 0x00FF /* IN1R_DIG_VOL - [7:0] */ +#define WM2200_IN1R_DIG_VOL_SHIFT 0 /* IN1R_DIG_VOL - [7:0] */ +#define WM2200_IN1R_DIG_VOL_WIDTH 8 /* IN1R_DIG_VOL - [7:0] */ + +/* + * R782 (0x30E) - ADC Digital Volume 2L + */ +#define WM2200_IN_VU 0x0200 /* IN_VU */ +#define WM2200_IN_VU_MASK 0x0200 /* IN_VU */ +#define WM2200_IN_VU_SHIFT 9 /* IN_VU */ +#define WM2200_IN_VU_WIDTH 1 /* IN_VU */ +#define WM2200_IN2L_MUTE 0x0100 /* IN2L_MUTE */ +#define WM2200_IN2L_MUTE_MASK 0x0100 /* IN2L_MUTE */ +#define WM2200_IN2L_MUTE_SHIFT 8 /* IN2L_MUTE */ +#define WM2200_IN2L_MUTE_WIDTH 1 /* IN2L_MUTE */ +#define WM2200_IN2L_DIG_VOL_MASK 0x00FF /* IN2L_DIG_VOL - [7:0] */ +#define WM2200_IN2L_DIG_VOL_SHIFT 0 /* IN2L_DIG_VOL - [7:0] */ +#define WM2200_IN2L_DIG_VOL_WIDTH 8 /* IN2L_DIG_VOL - [7:0] */ + +/* + * R783 (0x30F) - ADC Digital Volume 2R + */ +#define WM2200_IN_VU 0x0200 /* IN_VU */ +#define WM2200_IN_VU_MASK 0x0200 /* IN_VU */ +#define WM2200_IN_VU_SHIFT 9 /* IN_VU */ +#define WM2200_IN_VU_WIDTH 1 /* IN_VU */ +#define WM2200_IN2R_MUTE 0x0100 /* IN2R_MUTE */ +#define WM2200_IN2R_MUTE_MASK 0x0100 /* IN2R_MUTE */ +#define WM2200_IN2R_MUTE_SHIFT 8 /* IN2R_MUTE */ +#define WM2200_IN2R_MUTE_WIDTH 1 /* IN2R_MUTE */ +#define WM2200_IN2R_DIG_VOL_MASK 0x00FF /* IN2R_DIG_VOL - [7:0] */ +#define WM2200_IN2R_DIG_VOL_SHIFT 0 /* IN2R_DIG_VOL - [7:0] */ +#define WM2200_IN2R_DIG_VOL_WIDTH 8 /* IN2R_DIG_VOL - [7:0] */ + +/* + * R784 (0x310) - ADC Digital Volume 3L + */ +#define WM2200_IN_VU 0x0200 /* IN_VU */ +#define WM2200_IN_VU_MASK 0x0200 /* IN_VU */ +#define WM2200_IN_VU_SHIFT 9 /* IN_VU */ +#define WM2200_IN_VU_WIDTH 1 /* IN_VU */ +#define WM2200_IN3L_MUTE 0x0100 /* IN3L_MUTE */ +#define WM2200_IN3L_MUTE_MASK 0x0100 /* IN3L_MUTE */ +#define WM2200_IN3L_MUTE_SHIFT 8 /* IN3L_MUTE */ +#define WM2200_IN3L_MUTE_WIDTH 1 /* IN3L_MUTE */ +#define WM2200_IN3L_DIG_VOL_MASK 0x00FF /* IN3L_DIG_VOL - [7:0] */ +#define WM2200_IN3L_DIG_VOL_SHIFT 0 /* IN3L_DIG_VOL - [7:0] */ +#define WM2200_IN3L_DIG_VOL_WIDTH 8 /* IN3L_DIG_VOL - [7:0] */ + +/* + * R785 (0x311) - ADC Digital Volume 3R + */ +#define WM2200_IN_VU 0x0200 /* IN_VU */ +#define WM2200_IN_VU_MASK 0x0200 /* IN_VU */ +#define WM2200_IN_VU_SHIFT 9 /* IN_VU */ +#define WM2200_IN_VU_WIDTH 1 /* IN_VU */ +#define WM2200_IN3R_MUTE 0x0100 /* IN3R_MUTE */ +#define WM2200_IN3R_MUTE_MASK 0x0100 /* IN3R_MUTE */ +#define WM2200_IN3R_MUTE_SHIFT 8 /* IN3R_MUTE */ +#define WM2200_IN3R_MUTE_WIDTH 1 /* IN3R_MUTE */ +#define WM2200_IN3R_DIG_VOL_MASK 0x00FF /* IN3R_DIG_VOL - [7:0] */ +#define WM2200_IN3R_DIG_VOL_SHIFT 0 /* IN3R_DIG_VOL - [7:0] */ +#define WM2200_IN3R_DIG_VOL_WIDTH 8 /* IN3R_DIG_VOL - [7:0] */ + +/* + * R1024 (0x400) - Output Enables + */ +#define WM2200_OUT2L_ENA 0x0008 /* OUT2L_ENA */ +#define WM2200_OUT2L_ENA_MASK 0x0008 /* OUT2L_ENA */ +#define WM2200_OUT2L_ENA_SHIFT 3 /* OUT2L_ENA */ +#define WM2200_OUT2L_ENA_WIDTH 1 /* OUT2L_ENA */ +#define WM2200_OUT2R_ENA 0x0004 /* OUT2R_ENA */ +#define WM2200_OUT2R_ENA_MASK 0x0004 /* OUT2R_ENA */ +#define WM2200_OUT2R_ENA_SHIFT 2 /* OUT2R_ENA */ +#define WM2200_OUT2R_ENA_WIDTH 1 /* OUT2R_ENA */ +#define WM2200_OUT1L_ENA 0x0002 /* OUT1L_ENA */ +#define WM2200_OUT1L_ENA_MASK 0x0002 /* OUT1L_ENA */ +#define WM2200_OUT1L_ENA_SHIFT 1 /* OUT1L_ENA */ +#define WM2200_OUT1L_ENA_WIDTH 1 /* OUT1L_ENA */ +#define WM2200_OUT1R_ENA 0x0001 /* OUT1R_ENA */ +#define WM2200_OUT1R_ENA_MASK 0x0001 /* OUT1R_ENA */ +#define WM2200_OUT1R_ENA_SHIFT 0 /* OUT1R_ENA */ +#define WM2200_OUT1R_ENA_WIDTH 1 /* OUT1R_ENA */ + +/* + * R1025 (0x401) - DAC Volume Limit 1L + */ +#define WM2200_OUT1_OSR 0x2000 /* OUT1_OSR */ +#define WM2200_OUT1_OSR_MASK 0x2000 /* OUT1_OSR */ +#define WM2200_OUT1_OSR_SHIFT 13 /* OUT1_OSR */ +#define WM2200_OUT1_OSR_WIDTH 1 /* OUT1_OSR */ +#define WM2200_OUT1L_ANC_SRC 0x0800 /* OUT1L_ANC_SRC */ +#define WM2200_OUT1L_ANC_SRC_MASK 0x0800 /* OUT1L_ANC_SRC */ +#define WM2200_OUT1L_ANC_SRC_SHIFT 11 /* OUT1L_ANC_SRC */ +#define WM2200_OUT1L_ANC_SRC_WIDTH 1 /* OUT1L_ANC_SRC */ +#define WM2200_OUT1L_PGA_VOL_MASK 0x00FE /* OUT1L_PGA_VOL - [7:1] */ +#define WM2200_OUT1L_PGA_VOL_SHIFT 1 /* OUT1L_PGA_VOL - [7:1] */ +#define WM2200_OUT1L_PGA_VOL_WIDTH 7 /* OUT1L_PGA_VOL - [7:1] */ + +/* + * R1026 (0x402) - DAC Volume Limit 1R + */ +#define WM2200_OUT1R_ANC_SRC 0x0800 /* OUT1R_ANC_SRC */ +#define WM2200_OUT1R_ANC_SRC_MASK 0x0800 /* OUT1R_ANC_SRC */ +#define WM2200_OUT1R_ANC_SRC_SHIFT 11 /* OUT1R_ANC_SRC */ +#define WM2200_OUT1R_ANC_SRC_WIDTH 1 /* OUT1R_ANC_SRC */ +#define WM2200_OUT1R_PGA_VOL_MASK 0x00FE /* OUT1R_PGA_VOL - [7:1] */ +#define WM2200_OUT1R_PGA_VOL_SHIFT 1 /* OUT1R_PGA_VOL - [7:1] */ +#define WM2200_OUT1R_PGA_VOL_WIDTH 7 /* OUT1R_PGA_VOL - [7:1] */ + +/* + * R1027 (0x403) - DAC Volume Limit 2L + */ +#define WM2200_OUT2_OSR 0x2000 /* OUT2_OSR */ +#define WM2200_OUT2_OSR_MASK 0x2000 /* OUT2_OSR */ +#define WM2200_OUT2_OSR_SHIFT 13 /* OUT2_OSR */ +#define WM2200_OUT2_OSR_WIDTH 1 /* OUT2_OSR */ +#define WM2200_OUT2L_ANC_SRC 0x0800 /* OUT2L_ANC_SRC */ +#define WM2200_OUT2L_ANC_SRC_MASK 0x0800 /* OUT2L_ANC_SRC */ +#define WM2200_OUT2L_ANC_SRC_SHIFT 11 /* OUT2L_ANC_SRC */ +#define WM2200_OUT2L_ANC_SRC_WIDTH 1 /* OUT2L_ANC_SRC */ + +/* + * R1028 (0x404) - DAC Volume Limit 2R + */ +#define WM2200_OUT2R_ANC_SRC 0x0800 /* OUT2R_ANC_SRC */ +#define WM2200_OUT2R_ANC_SRC_MASK 0x0800 /* OUT2R_ANC_SRC */ +#define WM2200_OUT2R_ANC_SRC_SHIFT 11 /* OUT2R_ANC_SRC */ +#define WM2200_OUT2R_ANC_SRC_WIDTH 1 /* OUT2R_ANC_SRC */ + +/* + * R1033 (0x409) - DAC AEC Control 1 + */ +#define WM2200_AEC_LOOPBACK_ENA 0x0004 /* AEC_LOOPBACK_ENA */ +#define WM2200_AEC_LOOPBACK_ENA_MASK 0x0004 /* AEC_LOOPBACK_ENA */ +#define WM2200_AEC_LOOPBACK_ENA_SHIFT 2 /* AEC_LOOPBACK_ENA */ +#define WM2200_AEC_LOOPBACK_ENA_WIDTH 1 /* AEC_LOOPBACK_ENA */ +#define WM2200_AEC_LOOPBACK_SRC_MASK 0x0003 /* AEC_LOOPBACK_SRC - [1:0] */ +#define WM2200_AEC_LOOPBACK_SRC_SHIFT 0 /* AEC_LOOPBACK_SRC - [1:0] */ +#define WM2200_AEC_LOOPBACK_SRC_WIDTH 2 /* AEC_LOOPBACK_SRC - [1:0] */ + +/* + * R1034 (0x40A) - Output Volume Ramp + */ +#define WM2200_OUT_VD_RAMP_MASK 0x0070 /* OUT_VD_RAMP - [6:4] */ +#define WM2200_OUT_VD_RAMP_SHIFT 4 /* OUT_VD_RAMP - [6:4] */ +#define WM2200_OUT_VD_RAMP_WIDTH 3 /* OUT_VD_RAMP - [6:4] */ +#define WM2200_OUT_VI_RAMP_MASK 0x0007 /* OUT_VI_RAMP - [2:0] */ +#define WM2200_OUT_VI_RAMP_SHIFT 0 /* OUT_VI_RAMP - [2:0] */ +#define WM2200_OUT_VI_RAMP_WIDTH 3 /* OUT_VI_RAMP - [2:0] */ + +/* + * R1035 (0x40B) - DAC Digital Volume 1L + */ +#define WM2200_OUT_VU 0x0200 /* OUT_VU */ +#define WM2200_OUT_VU_MASK 0x0200 /* OUT_VU */ +#define WM2200_OUT_VU_SHIFT 9 /* OUT_VU */ +#define WM2200_OUT_VU_WIDTH 1 /* OUT_VU */ +#define WM2200_OUT1L_MUTE 0x0100 /* OUT1L_MUTE */ +#define WM2200_OUT1L_MUTE_MASK 0x0100 /* OUT1L_MUTE */ +#define WM2200_OUT1L_MUTE_SHIFT 8 /* OUT1L_MUTE */ +#define WM2200_OUT1L_MUTE_WIDTH 1 /* OUT1L_MUTE */ +#define WM2200_OUT1L_VOL_MASK 0x00FF /* OUT1L_VOL - [7:0] */ +#define WM2200_OUT1L_VOL_SHIFT 0 /* OUT1L_VOL - [7:0] */ +#define WM2200_OUT1L_VOL_WIDTH 8 /* OUT1L_VOL - [7:0] */ + +/* + * R1036 (0x40C) - DAC Digital Volume 1R + */ +#define WM2200_OUT_VU 0x0200 /* OUT_VU */ +#define WM2200_OUT_VU_MASK 0x0200 /* OUT_VU */ +#define WM2200_OUT_VU_SHIFT 9 /* OUT_VU */ +#define WM2200_OUT_VU_WIDTH 1 /* OUT_VU */ +#define WM2200_OUT1R_MUTE 0x0100 /* OUT1R_MUTE */ +#define WM2200_OUT1R_MUTE_MASK 0x0100 /* OUT1R_MUTE */ +#define WM2200_OUT1R_MUTE_SHIFT 8 /* OUT1R_MUTE */ +#define WM2200_OUT1R_MUTE_WIDTH 1 /* OUT1R_MUTE */ +#define WM2200_OUT1R_VOL_MASK 0x00FF /* OUT1R_VOL - [7:0] */ +#define WM2200_OUT1R_VOL_SHIFT 0 /* OUT1R_VOL - [7:0] */ +#define WM2200_OUT1R_VOL_WIDTH 8 /* OUT1R_VOL - [7:0] */ + +/* + * R1037 (0x40D) - DAC Digital Volume 2L + */ +#define WM2200_OUT_VU 0x0200 /* OUT_VU */ +#define WM2200_OUT_VU_MASK 0x0200 /* OUT_VU */ +#define WM2200_OUT_VU_SHIFT 9 /* OUT_VU */ +#define WM2200_OUT_VU_WIDTH 1 /* OUT_VU */ +#define WM2200_OUT2L_MUTE 0x0100 /* OUT2L_MUTE */ +#define WM2200_OUT2L_MUTE_MASK 0x0100 /* OUT2L_MUTE */ +#define WM2200_OUT2L_MUTE_SHIFT 8 /* OUT2L_MUTE */ +#define WM2200_OUT2L_MUTE_WIDTH 1 /* OUT2L_MUTE */ +#define WM2200_OUT2L_VOL_MASK 0x00FF /* OUT2L_VOL - [7:0] */ +#define WM2200_OUT2L_VOL_SHIFT 0 /* OUT2L_VOL - [7:0] */ +#define WM2200_OUT2L_VOL_WIDTH 8 /* OUT2L_VOL - [7:0] */ + +/* + * R1038 (0x40E) - DAC Digital Volume 2R + */ +#define WM2200_OUT_VU 0x0200 /* OUT_VU */ +#define WM2200_OUT_VU_MASK 0x0200 /* OUT_VU */ +#define WM2200_OUT_VU_SHIFT 9 /* OUT_VU */ +#define WM2200_OUT_VU_WIDTH 1 /* OUT_VU */ +#define WM2200_OUT2R_MUTE 0x0100 /* OUT2R_MUTE */ +#define WM2200_OUT2R_MUTE_MASK 0x0100 /* OUT2R_MUTE */ +#define WM2200_OUT2R_MUTE_SHIFT 8 /* OUT2R_MUTE */ +#define WM2200_OUT2R_MUTE_WIDTH 1 /* OUT2R_MUTE */ +#define WM2200_OUT2R_VOL_MASK 0x00FF /* OUT2R_VOL - [7:0] */ +#define WM2200_OUT2R_VOL_SHIFT 0 /* OUT2R_VOL - [7:0] */ +#define WM2200_OUT2R_VOL_WIDTH 8 /* OUT2R_VOL - [7:0] */ + +/* + * R1047 (0x417) - PDM 1 + */ +#define WM2200_SPK1R_MUTE 0x2000 /* SPK1R_MUTE */ +#define WM2200_SPK1R_MUTE_MASK 0x2000 /* SPK1R_MUTE */ +#define WM2200_SPK1R_MUTE_SHIFT 13 /* SPK1R_MUTE */ +#define WM2200_SPK1R_MUTE_WIDTH 1 /* SPK1R_MUTE */ +#define WM2200_SPK1L_MUTE 0x1000 /* SPK1L_MUTE */ +#define WM2200_SPK1L_MUTE_MASK 0x1000 /* SPK1L_MUTE */ +#define WM2200_SPK1L_MUTE_SHIFT 12 /* SPK1L_MUTE */ +#define WM2200_SPK1L_MUTE_WIDTH 1 /* SPK1L_MUTE */ +#define WM2200_SPK1_MUTE_ENDIAN 0x0100 /* SPK1_MUTE_ENDIAN */ +#define WM2200_SPK1_MUTE_ENDIAN_MASK 0x0100 /* SPK1_MUTE_ENDIAN */ +#define WM2200_SPK1_MUTE_ENDIAN_SHIFT 8 /* SPK1_MUTE_ENDIAN */ +#define WM2200_SPK1_MUTE_ENDIAN_WIDTH 1 /* SPK1_MUTE_ENDIAN */ +#define WM2200_SPK1_MUTE_SEQL_MASK 0x00FF /* SPK1_MUTE_SEQL - [7:0] */ +#define WM2200_SPK1_MUTE_SEQL_SHIFT 0 /* SPK1_MUTE_SEQL - [7:0] */ +#define WM2200_SPK1_MUTE_SEQL_WIDTH 8 /* SPK1_MUTE_SEQL - [7:0] */ + +/* + * R1048 (0x418) - PDM 2 + */ +#define WM2200_SPK1_FMT 0x0001 /* SPK1_FMT */ +#define WM2200_SPK1_FMT_MASK 0x0001 /* SPK1_FMT */ +#define WM2200_SPK1_FMT_SHIFT 0 /* SPK1_FMT */ +#define WM2200_SPK1_FMT_WIDTH 1 /* SPK1_FMT */ + +/* + * R1280 (0x500) - Audio IF 1_1 + */ +#define WM2200_AIF1_BCLK_INV 0x0040 /* AIF1_BCLK_INV */ +#define WM2200_AIF1_BCLK_INV_MASK 0x0040 /* AIF1_BCLK_INV */ +#define WM2200_AIF1_BCLK_INV_SHIFT 6 /* AIF1_BCLK_INV */ +#define WM2200_AIF1_BCLK_INV_WIDTH 1 /* AIF1_BCLK_INV */ +#define WM2200_AIF1_BCLK_FRC 0x0020 /* AIF1_BCLK_FRC */ +#define WM2200_AIF1_BCLK_FRC_MASK 0x0020 /* AIF1_BCLK_FRC */ +#define WM2200_AIF1_BCLK_FRC_SHIFT 5 /* AIF1_BCLK_FRC */ +#define WM2200_AIF1_BCLK_FRC_WIDTH 1 /* AIF1_BCLK_FRC */ +#define WM2200_AIF1_BCLK_MSTR 0x0010 /* AIF1_BCLK_MSTR */ +#define WM2200_AIF1_BCLK_MSTR_MASK 0x0010 /* AIF1_BCLK_MSTR */ +#define WM2200_AIF1_BCLK_MSTR_SHIFT 4 /* AIF1_BCLK_MSTR */ +#define WM2200_AIF1_BCLK_MSTR_WIDTH 1 /* AIF1_BCLK_MSTR */ +#define WM2200_AIF1_BCLK_DIV_MASK 0x000F /* AIF1_BCLK_DIV - [3:0] */ +#define WM2200_AIF1_BCLK_DIV_SHIFT 0 /* AIF1_BCLK_DIV - [3:0] */ +#define WM2200_AIF1_BCLK_DIV_WIDTH 4 /* AIF1_BCLK_DIV - [3:0] */ + +/* + * R1281 (0x501) - Audio IF 1_2 + */ +#define WM2200_AIF1TX_DAT_TRI 0x0020 /* AIF1TX_DAT_TRI */ +#define WM2200_AIF1TX_DAT_TRI_MASK 0x0020 /* AIF1TX_DAT_TRI */ +#define WM2200_AIF1TX_DAT_TRI_SHIFT 5 /* AIF1TX_DAT_TRI */ +#define WM2200_AIF1TX_DAT_TRI_WIDTH 1 /* AIF1TX_DAT_TRI */ +#define WM2200_AIF1TX_LRCLK_SRC 0x0008 /* AIF1TX_LRCLK_SRC */ +#define WM2200_AIF1TX_LRCLK_SRC_MASK 0x0008 /* AIF1TX_LRCLK_SRC */ +#define WM2200_AIF1TX_LRCLK_SRC_SHIFT 3 /* AIF1TX_LRCLK_SRC */ +#define WM2200_AIF1TX_LRCLK_SRC_WIDTH 1 /* AIF1TX_LRCLK_SRC */ +#define WM2200_AIF1TX_LRCLK_INV 0x0004 /* AIF1TX_LRCLK_INV */ +#define WM2200_AIF1TX_LRCLK_INV_MASK 0x0004 /* AIF1TX_LRCLK_INV */ +#define WM2200_AIF1TX_LRCLK_INV_SHIFT 2 /* AIF1TX_LRCLK_INV */ +#define WM2200_AIF1TX_LRCLK_INV_WIDTH 1 /* AIF1TX_LRCLK_INV */ +#define WM2200_AIF1TX_LRCLK_FRC 0x0002 /* AIF1TX_LRCLK_FRC */ +#define WM2200_AIF1TX_LRCLK_FRC_MASK 0x0002 /* AIF1TX_LRCLK_FRC */ +#define WM2200_AIF1TX_LRCLK_FRC_SHIFT 1 /* AIF1TX_LRCLK_FRC */ +#define WM2200_AIF1TX_LRCLK_FRC_WIDTH 1 /* AIF1TX_LRCLK_FRC */ +#define WM2200_AIF1TX_LRCLK_MSTR 0x0001 /* AIF1TX_LRCLK_MSTR */ +#define WM2200_AIF1TX_LRCLK_MSTR_MASK 0x0001 /* AIF1TX_LRCLK_MSTR */ +#define WM2200_AIF1TX_LRCLK_MSTR_SHIFT 0 /* AIF1TX_LRCLK_MSTR */ +#define WM2200_AIF1TX_LRCLK_MSTR_WIDTH 1 /* AIF1TX_LRCLK_MSTR */ + +/* + * R1282 (0x502) - Audio IF 1_3 + */ +#define WM2200_AIF1RX_LRCLK_INV 0x0004 /* AIF1RX_LRCLK_INV */ +#define WM2200_AIF1RX_LRCLK_INV_MASK 0x0004 /* AIF1RX_LRCLK_INV */ +#define WM2200_AIF1RX_LRCLK_INV_SHIFT 2 /* AIF1RX_LRCLK_INV */ +#define WM2200_AIF1RX_LRCLK_INV_WIDTH 1 /* AIF1RX_LRCLK_INV */ +#define WM2200_AIF1RX_LRCLK_FRC 0x0002 /* AIF1RX_LRCLK_FRC */ +#define WM2200_AIF1RX_LRCLK_FRC_MASK 0x0002 /* AIF1RX_LRCLK_FRC */ +#define WM2200_AIF1RX_LRCLK_FRC_SHIFT 1 /* AIF1RX_LRCLK_FRC */ +#define WM2200_AIF1RX_LRCLK_FRC_WIDTH 1 /* AIF1RX_LRCLK_FRC */ +#define WM2200_AIF1RX_LRCLK_MSTR 0x0001 /* AIF1RX_LRCLK_MSTR */ +#define WM2200_AIF1RX_LRCLK_MSTR_MASK 0x0001 /* AIF1RX_LRCLK_MSTR */ +#define WM2200_AIF1RX_LRCLK_MSTR_SHIFT 0 /* AIF1RX_LRCLK_MSTR */ +#define WM2200_AIF1RX_LRCLK_MSTR_WIDTH 1 /* AIF1RX_LRCLK_MSTR */ + +/* + * R1283 (0x503) - Audio IF 1_4 + */ +#define WM2200_AIF1_TRI 0x0040 /* AIF1_TRI */ +#define WM2200_AIF1_TRI_MASK 0x0040 /* AIF1_TRI */ +#define WM2200_AIF1_TRI_SHIFT 6 /* AIF1_TRI */ +#define WM2200_AIF1_TRI_WIDTH 1 /* AIF1_TRI */ + +/* + * R1284 (0x504) - Audio IF 1_5 + */ +#define WM2200_AIF1_FMT_MASK 0x0007 /* AIF1_FMT - [2:0] */ +#define WM2200_AIF1_FMT_SHIFT 0 /* AIF1_FMT - [2:0] */ +#define WM2200_AIF1_FMT_WIDTH 3 /* AIF1_FMT - [2:0] */ + +/* + * R1285 (0x505) - Audio IF 1_6 + */ +#define WM2200_AIF1TX_BCPF_MASK 0x07FF /* AIF1TX_BCPF - [10:0] */ +#define WM2200_AIF1TX_BCPF_SHIFT 0 /* AIF1TX_BCPF - [10:0] */ +#define WM2200_AIF1TX_BCPF_WIDTH 11 /* AIF1TX_BCPF - [10:0] */ + +/* + * R1286 (0x506) - Audio IF 1_7 + */ +#define WM2200_AIF1RX_BCPF_MASK 0x07FF /* AIF1RX_BCPF - [10:0] */ +#define WM2200_AIF1RX_BCPF_SHIFT 0 /* AIF1RX_BCPF - [10:0] */ +#define WM2200_AIF1RX_BCPF_WIDTH 11 /* AIF1RX_BCPF - [10:0] */ + +/* + * R1287 (0x507) - Audio IF 1_8 + */ +#define WM2200_AIF1TX_WL_MASK 0x3F00 /* AIF1TX_WL - [13:8] */ +#define WM2200_AIF1TX_WL_SHIFT 8 /* AIF1TX_WL - [13:8] */ +#define WM2200_AIF1TX_WL_WIDTH 6 /* AIF1TX_WL - [13:8] */ +#define WM2200_AIF1TX_SLOT_LEN_MASK 0x00FF /* AIF1TX_SLOT_LEN - [7:0] */ +#define WM2200_AIF1TX_SLOT_LEN_SHIFT 0 /* AIF1TX_SLOT_LEN - [7:0] */ +#define WM2200_AIF1TX_SLOT_LEN_WIDTH 8 /* AIF1TX_SLOT_LEN - [7:0] */ + +/* + * R1288 (0x508) - Audio IF 1_9 + */ +#define WM2200_AIF1RX_WL_MASK 0x3F00 /* AIF1RX_WL - [13:8] */ +#define WM2200_AIF1RX_WL_SHIFT 8 /* AIF1RX_WL - [13:8] */ +#define WM2200_AIF1RX_WL_WIDTH 6 /* AIF1RX_WL - [13:8] */ +#define WM2200_AIF1RX_SLOT_LEN_MASK 0x00FF /* AIF1RX_SLOT_LEN - [7:0] */ +#define WM2200_AIF1RX_SLOT_LEN_SHIFT 0 /* AIF1RX_SLOT_LEN - [7:0] */ +#define WM2200_AIF1RX_SLOT_LEN_WIDTH 8 /* AIF1RX_SLOT_LEN - [7:0] */ + +/* + * R1289 (0x509) - Audio IF 1_10 + */ +#define WM2200_AIF1TX1_SLOT_MASK 0x003F /* AIF1TX1_SLOT - [5:0] */ +#define WM2200_AIF1TX1_SLOT_SHIFT 0 /* AIF1TX1_SLOT - [5:0] */ +#define WM2200_AIF1TX1_SLOT_WIDTH 6 /* AIF1TX1_SLOT - [5:0] */ + +/* + * R1290 (0x50A) - Audio IF 1_11 + */ +#define WM2200_AIF1TX2_SLOT_MASK 0x003F /* AIF1TX2_SLOT - [5:0] */ +#define WM2200_AIF1TX2_SLOT_SHIFT 0 /* AIF1TX2_SLOT - [5:0] */ +#define WM2200_AIF1TX2_SLOT_WIDTH 6 /* AIF1TX2_SLOT - [5:0] */ + +/* + * R1291 (0x50B) - Audio IF 1_12 + */ +#define WM2200_AIF1TX3_SLOT_MASK 0x003F /* AIF1TX3_SLOT - [5:0] */ +#define WM2200_AIF1TX3_SLOT_SHIFT 0 /* AIF1TX3_SLOT - [5:0] */ +#define WM2200_AIF1TX3_SLOT_WIDTH 6 /* AIF1TX3_SLOT - [5:0] */ + +/* + * R1292 (0x50C) - Audio IF 1_13 + */ +#define WM2200_AIF1TX4_SLOT_MASK 0x003F /* AIF1TX4_SLOT - [5:0] */ +#define WM2200_AIF1TX4_SLOT_SHIFT 0 /* AIF1TX4_SLOT - [5:0] */ +#define WM2200_AIF1TX4_SLOT_WIDTH 6 /* AIF1TX4_SLOT - [5:0] */ + +/* + * R1293 (0x50D) - Audio IF 1_14 + */ +#define WM2200_AIF1TX5_SLOT_MASK 0x003F /* AIF1TX5_SLOT - [5:0] */ +#define WM2200_AIF1TX5_SLOT_SHIFT 0 /* AIF1TX5_SLOT - [5:0] */ +#define WM2200_AIF1TX5_SLOT_WIDTH 6 /* AIF1TX5_SLOT - [5:0] */ + +/* + * R1294 (0x50E) - Audio IF 1_15 + */ +#define WM2200_AIF1TX6_SLOT_MASK 0x003F /* AIF1TX6_SLOT - [5:0] */ +#define WM2200_AIF1TX6_SLOT_SHIFT 0 /* AIF1TX6_SLOT - [5:0] */ +#define WM2200_AIF1TX6_SLOT_WIDTH 6 /* AIF1TX6_SLOT - [5:0] */ + +/* + * R1295 (0x50F) - Audio IF 1_16 + */ +#define WM2200_AIF1RX1_SLOT_MASK 0x003F /* AIF1RX1_SLOT - [5:0] */ +#define WM2200_AIF1RX1_SLOT_SHIFT 0 /* AIF1RX1_SLOT - [5:0] */ +#define WM2200_AIF1RX1_SLOT_WIDTH 6 /* AIF1RX1_SLOT - [5:0] */ + +/* + * R1296 (0x510) - Audio IF 1_17 + */ +#define WM2200_AIF1RX2_SLOT_MASK 0x003F /* AIF1RX2_SLOT - [5:0] */ +#define WM2200_AIF1RX2_SLOT_SHIFT 0 /* AIF1RX2_SLOT - [5:0] */ +#define WM2200_AIF1RX2_SLOT_WIDTH 6 /* AIF1RX2_SLOT - [5:0] */ + +/* + * R1297 (0x511) - Audio IF 1_18 + */ +#define WM2200_AIF1RX3_SLOT_MASK 0x003F /* AIF1RX3_SLOT - [5:0] */ +#define WM2200_AIF1RX3_SLOT_SHIFT 0 /* AIF1RX3_SLOT - [5:0] */ +#define WM2200_AIF1RX3_SLOT_WIDTH 6 /* AIF1RX3_SLOT - [5:0] */ + +/* + * R1298 (0x512) - Audio IF 1_19 + */ +#define WM2200_AIF1RX4_SLOT_MASK 0x003F /* AIF1RX4_SLOT - [5:0] */ +#define WM2200_AIF1RX4_SLOT_SHIFT 0 /* AIF1RX4_SLOT - [5:0] */ +#define WM2200_AIF1RX4_SLOT_WIDTH 6 /* AIF1RX4_SLOT - [5:0] */ + +/* + * R1299 (0x513) - Audio IF 1_20 + */ +#define WM2200_AIF1RX5_SLOT_MASK 0x003F /* AIF1RX5_SLOT - [5:0] */ +#define WM2200_AIF1RX5_SLOT_SHIFT 0 /* AIF1RX5_SLOT - [5:0] */ +#define WM2200_AIF1RX5_SLOT_WIDTH 6 /* AIF1RX5_SLOT - [5:0] */ + +/* + * R1300 (0x514) - Audio IF 1_21 + */ +#define WM2200_AIF1RX6_SLOT_MASK 0x003F /* AIF1RX6_SLOT - [5:0] */ +#define WM2200_AIF1RX6_SLOT_SHIFT 0 /* AIF1RX6_SLOT - [5:0] */ +#define WM2200_AIF1RX6_SLOT_WIDTH 6 /* AIF1RX6_SLOT - [5:0] */ + +/* + * R1301 (0x515) - Audio IF 1_22 + */ +#define WM2200_AIF1RX6_ENA 0x0800 /* AIF1RX6_ENA */ +#define WM2200_AIF1RX6_ENA_MASK 0x0800 /* AIF1RX6_ENA */ +#define WM2200_AIF1RX6_ENA_SHIFT 11 /* AIF1RX6_ENA */ +#define WM2200_AIF1RX6_ENA_WIDTH 1 /* AIF1RX6_ENA */ +#define WM2200_AIF1RX5_ENA 0x0400 /* AIF1RX5_ENA */ +#define WM2200_AIF1RX5_ENA_MASK 0x0400 /* AIF1RX5_ENA */ +#define WM2200_AIF1RX5_ENA_SHIFT 10 /* AIF1RX5_ENA */ +#define WM2200_AIF1RX5_ENA_WIDTH 1 /* AIF1RX5_ENA */ +#define WM2200_AIF1RX4_ENA 0x0200 /* AIF1RX4_ENA */ +#define WM2200_AIF1RX4_ENA_MASK 0x0200 /* AIF1RX4_ENA */ +#define WM2200_AIF1RX4_ENA_SHIFT 9 /* AIF1RX4_ENA */ +#define WM2200_AIF1RX4_ENA_WIDTH 1 /* AIF1RX4_ENA */ +#define WM2200_AIF1RX3_ENA 0x0100 /* AIF1RX3_ENA */ +#define WM2200_AIF1RX3_ENA_MASK 0x0100 /* AIF1RX3_ENA */ +#define WM2200_AIF1RX3_ENA_SHIFT 8 /* AIF1RX3_ENA */ +#define WM2200_AIF1RX3_ENA_WIDTH 1 /* AIF1RX3_ENA */ +#define WM2200_AIF1RX2_ENA 0x0080 /* AIF1RX2_ENA */ +#define WM2200_AIF1RX2_ENA_MASK 0x0080 /* AIF1RX2_ENA */ +#define WM2200_AIF1RX2_ENA_SHIFT 7 /* AIF1RX2_ENA */ +#define WM2200_AIF1RX2_ENA_WIDTH 1 /* AIF1RX2_ENA */ +#define WM2200_AIF1RX1_ENA 0x0040 /* AIF1RX1_ENA */ +#define WM2200_AIF1RX1_ENA_MASK 0x0040 /* AIF1RX1_ENA */ +#define WM2200_AIF1RX1_ENA_SHIFT 6 /* AIF1RX1_ENA */ +#define WM2200_AIF1RX1_ENA_WIDTH 1 /* AIF1RX1_ENA */ +#define WM2200_AIF1TX6_ENA 0x0020 /* AIF1TX6_ENA */ +#define WM2200_AIF1TX6_ENA_MASK 0x0020 /* AIF1TX6_ENA */ +#define WM2200_AIF1TX6_ENA_SHIFT 5 /* AIF1TX6_ENA */ +#define WM2200_AIF1TX6_ENA_WIDTH 1 /* AIF1TX6_ENA */ +#define WM2200_AIF1TX5_ENA 0x0010 /* AIF1TX5_ENA */ +#define WM2200_AIF1TX5_ENA_MASK 0x0010 /* AIF1TX5_ENA */ +#define WM2200_AIF1TX5_ENA_SHIFT 4 /* AIF1TX5_ENA */ +#define WM2200_AIF1TX5_ENA_WIDTH 1 /* AIF1TX5_ENA */ +#define WM2200_AIF1TX4_ENA 0x0008 /* AIF1TX4_ENA */ +#define WM2200_AIF1TX4_ENA_MASK 0x0008 /* AIF1TX4_ENA */ +#define WM2200_AIF1TX4_ENA_SHIFT 3 /* AIF1TX4_ENA */ +#define WM2200_AIF1TX4_ENA_WIDTH 1 /* AIF1TX4_ENA */ +#define WM2200_AIF1TX3_ENA 0x0004 /* AIF1TX3_ENA */ +#define WM2200_AIF1TX3_ENA_MASK 0x0004 /* AIF1TX3_ENA */ +#define WM2200_AIF1TX3_ENA_SHIFT 2 /* AIF1TX3_ENA */ +#define WM2200_AIF1TX3_ENA_WIDTH 1 /* AIF1TX3_ENA */ +#define WM2200_AIF1TX2_ENA 0x0002 /* AIF1TX2_ENA */ +#define WM2200_AIF1TX2_ENA_MASK 0x0002 /* AIF1TX2_ENA */ +#define WM2200_AIF1TX2_ENA_SHIFT 1 /* AIF1TX2_ENA */ +#define WM2200_AIF1TX2_ENA_WIDTH 1 /* AIF1TX2_ENA */ +#define WM2200_AIF1TX1_ENA 0x0001 /* AIF1TX1_ENA */ +#define WM2200_AIF1TX1_ENA_MASK 0x0001 /* AIF1TX1_ENA */ +#define WM2200_AIF1TX1_ENA_SHIFT 0 /* AIF1TX1_ENA */ +#define WM2200_AIF1TX1_ENA_WIDTH 1 /* AIF1TX1_ENA */ + +/* + * R1536 (0x600) - OUT1LMIX Input 1 Source + */ +#define WM2200_OUT1LMIX_SRC1_MASK 0x007F /* OUT1LMIX_SRC1 - [6:0] */ +#define WM2200_OUT1LMIX_SRC1_SHIFT 0 /* OUT1LMIX_SRC1 - [6:0] */ +#define WM2200_OUT1LMIX_SRC1_WIDTH 7 /* OUT1LMIX_SRC1 - [6:0] */ + +/* + * R1537 (0x601) - OUT1LMIX Input 1 Volume + */ +#define WM2200_OUT1LMIX_VOL1_MASK 0x00FE /* OUT1LMIX_VOL1 - [7:1] */ +#define WM2200_OUT1LMIX_VOL1_SHIFT 1 /* OUT1LMIX_VOL1 - [7:1] */ +#define WM2200_OUT1LMIX_VOL1_WIDTH 7 /* OUT1LMIX_VOL1 - [7:1] */ + +/* + * R1538 (0x602) - OUT1LMIX Input 2 Source + */ +#define WM2200_OUT1LMIX_SRC2_MASK 0x007F /* OUT1LMIX_SRC2 - [6:0] */ +#define WM2200_OUT1LMIX_SRC2_SHIFT 0 /* OUT1LMIX_SRC2 - [6:0] */ +#define WM2200_OUT1LMIX_SRC2_WIDTH 7 /* OUT1LMIX_SRC2 - [6:0] */ + +/* + * R1539 (0x603) - OUT1LMIX Input 2 Volume + */ +#define WM2200_OUT1LMIX_VOL2_MASK 0x00FE /* OUT1LMIX_VOL2 - [7:1] */ +#define WM2200_OUT1LMIX_VOL2_SHIFT 1 /* OUT1LMIX_VOL2 - [7:1] */ +#define WM2200_OUT1LMIX_VOL2_WIDTH 7 /* OUT1LMIX_VOL2 - [7:1] */ + +/* + * R1540 (0x604) - OUT1LMIX Input 3 Source + */ +#define WM2200_OUT1LMIX_SRC3_MASK 0x007F /* OUT1LMIX_SRC3 - [6:0] */ +#define WM2200_OUT1LMIX_SRC3_SHIFT 0 /* OUT1LMIX_SRC3 - [6:0] */ +#define WM2200_OUT1LMIX_SRC3_WIDTH 7 /* OUT1LMIX_SRC3 - [6:0] */ + +/* + * R1541 (0x605) - OUT1LMIX Input 3 Volume + */ +#define WM2200_OUT1LMIX_VOL3_MASK 0x00FE /* OUT1LMIX_VOL3 - [7:1] */ +#define WM2200_OUT1LMIX_VOL3_SHIFT 1 /* OUT1LMIX_VOL3 - [7:1] */ +#define WM2200_OUT1LMIX_VOL3_WIDTH 7 /* OUT1LMIX_VOL3 - [7:1] */ + +/* + * R1542 (0x606) - OUT1LMIX Input 4 Source + */ +#define WM2200_OUT1LMIX_SRC4_MASK 0x007F /* OUT1LMIX_SRC4 - [6:0] */ +#define WM2200_OUT1LMIX_SRC4_SHIFT 0 /* OUT1LMIX_SRC4 - [6:0] */ +#define WM2200_OUT1LMIX_SRC4_WIDTH 7 /* OUT1LMIX_SRC4 - [6:0] */ + +/* + * R1543 (0x607) - OUT1LMIX Input 4 Volume + */ +#define WM2200_OUT1LMIX_VOL4_MASK 0x00FE /* OUT1LMIX_VOL4 - [7:1] */ +#define WM2200_OUT1LMIX_VOL4_SHIFT 1 /* OUT1LMIX_VOL4 - [7:1] */ +#define WM2200_OUT1LMIX_VOL4_WIDTH 7 /* OUT1LMIX_VOL4 - [7:1] */ + +/* + * R1544 (0x608) - OUT1RMIX Input 1 Source + */ +#define WM2200_OUT1RMIX_SRC1_MASK 0x007F /* OUT1RMIX_SRC1 - [6:0] */ +#define WM2200_OUT1RMIX_SRC1_SHIFT 0 /* OUT1RMIX_SRC1 - [6:0] */ +#define WM2200_OUT1RMIX_SRC1_WIDTH 7 /* OUT1RMIX_SRC1 - [6:0] */ + +/* + * R1545 (0x609) - OUT1RMIX Input 1 Volume + */ +#define WM2200_OUT1RMIX_VOL1_MASK 0x00FE /* OUT1RMIX_VOL1 - [7:1] */ +#define WM2200_OUT1RMIX_VOL1_SHIFT 1 /* OUT1RMIX_VOL1 - [7:1] */ +#define WM2200_OUT1RMIX_VOL1_WIDTH 7 /* OUT1RMIX_VOL1 - [7:1] */ + +/* + * R1546 (0x60A) - OUT1RMIX Input 2 Source + */ +#define WM2200_OUT1RMIX_SRC2_MASK 0x007F /* OUT1RMIX_SRC2 - [6:0] */ +#define WM2200_OUT1RMIX_SRC2_SHIFT 0 /* OUT1RMIX_SRC2 - [6:0] */ +#define WM2200_OUT1RMIX_SRC2_WIDTH 7 /* OUT1RMIX_SRC2 - [6:0] */ + +/* + * R1547 (0x60B) - OUT1RMIX Input 2 Volume + */ +#define WM2200_OUT1RMIX_VOL2_MASK 0x00FE /* OUT1RMIX_VOL2 - [7:1] */ +#define WM2200_OUT1RMIX_VOL2_SHIFT 1 /* OUT1RMIX_VOL2 - [7:1] */ +#define WM2200_OUT1RMIX_VOL2_WIDTH 7 /* OUT1RMIX_VOL2 - [7:1] */ + +/* + * R1548 (0x60C) - OUT1RMIX Input 3 Source + */ +#define WM2200_OUT1RMIX_SRC3_MASK 0x007F /* OUT1RMIX_SRC3 - [6:0] */ +#define WM2200_OUT1RMIX_SRC3_SHIFT 0 /* OUT1RMIX_SRC3 - [6:0] */ +#define WM2200_OUT1RMIX_SRC3_WIDTH 7 /* OUT1RMIX_SRC3 - [6:0] */ + +/* + * R1549 (0x60D) - OUT1RMIX Input 3 Volume + */ +#define WM2200_OUT1RMIX_VOL3_MASK 0x00FE /* OUT1RMIX_VOL3 - [7:1] */ +#define WM2200_OUT1RMIX_VOL3_SHIFT 1 /* OUT1RMIX_VOL3 - [7:1] */ +#define WM2200_OUT1RMIX_VOL3_WIDTH 7 /* OUT1RMIX_VOL3 - [7:1] */ + +/* + * R1550 (0x60E) - OUT1RMIX Input 4 Source + */ +#define WM2200_OUT1RMIX_SRC4_MASK 0x007F /* OUT1RMIX_SRC4 - [6:0] */ +#define WM2200_OUT1RMIX_SRC4_SHIFT 0 /* OUT1RMIX_SRC4 - [6:0] */ +#define WM2200_OUT1RMIX_SRC4_WIDTH 7 /* OUT1RMIX_SRC4 - [6:0] */ + +/* + * R1551 (0x60F) - OUT1RMIX Input 4 Volume + */ +#define WM2200_OUT1RMIX_VOL4_MASK 0x00FE /* OUT1RMIX_VOL4 - [7:1] */ +#define WM2200_OUT1RMIX_VOL4_SHIFT 1 /* OUT1RMIX_VOL4 - [7:1] */ +#define WM2200_OUT1RMIX_VOL4_WIDTH 7 /* OUT1RMIX_VOL4 - [7:1] */ + +/* + * R1552 (0x610) - OUT2LMIX Input 1 Source + */ +#define WM2200_OUT2LMIX_SRC1_MASK 0x007F /* OUT2LMIX_SRC1 - [6:0] */ +#define WM2200_OUT2LMIX_SRC1_SHIFT 0 /* OUT2LMIX_SRC1 - [6:0] */ +#define WM2200_OUT2LMIX_SRC1_WIDTH 7 /* OUT2LMIX_SRC1 - [6:0] */ + +/* + * R1553 (0x611) - OUT2LMIX Input 1 Volume + */ +#define WM2200_OUT2LMIX_VOL1_MASK 0x00FE /* OUT2LMIX_VOL1 - [7:1] */ +#define WM2200_OUT2LMIX_VOL1_SHIFT 1 /* OUT2LMIX_VOL1 - [7:1] */ +#define WM2200_OUT2LMIX_VOL1_WIDTH 7 /* OUT2LMIX_VOL1 - [7:1] */ + +/* + * R1554 (0x612) - OUT2LMIX Input 2 Source + */ +#define WM2200_OUT2LMIX_SRC2_MASK 0x007F /* OUT2LMIX_SRC2 - [6:0] */ +#define WM2200_OUT2LMIX_SRC2_SHIFT 0 /* OUT2LMIX_SRC2 - [6:0] */ +#define WM2200_OUT2LMIX_SRC2_WIDTH 7 /* OUT2LMIX_SRC2 - [6:0] */ + +/* + * R1555 (0x613) - OUT2LMIX Input 2 Volume + */ +#define WM2200_OUT2LMIX_VOL2_MASK 0x00FE /* OUT2LMIX_VOL2 - [7:1] */ +#define WM2200_OUT2LMIX_VOL2_SHIFT 1 /* OUT2LMIX_VOL2 - [7:1] */ +#define WM2200_OUT2LMIX_VOL2_WIDTH 7 /* OUT2LMIX_VOL2 - [7:1] */ + +/* + * R1556 (0x614) - OUT2LMIX Input 3 Source + */ +#define WM2200_OUT2LMIX_SRC3_MASK 0x007F /* OUT2LMIX_SRC3 - [6:0] */ +#define WM2200_OUT2LMIX_SRC3_SHIFT 0 /* OUT2LMIX_SRC3 - [6:0] */ +#define WM2200_OUT2LMIX_SRC3_WIDTH 7 /* OUT2LMIX_SRC3 - [6:0] */ + +/* + * R1557 (0x615) - OUT2LMIX Input 3 Volume + */ +#define WM2200_OUT2LMIX_VOL3_MASK 0x00FE /* OUT2LMIX_VOL3 - [7:1] */ +#define WM2200_OUT2LMIX_VOL3_SHIFT 1 /* OUT2LMIX_VOL3 - [7:1] */ +#define WM2200_OUT2LMIX_VOL3_WIDTH 7 /* OUT2LMIX_VOL3 - [7:1] */ + +/* + * R1558 (0x616) - OUT2LMIX Input 4 Source + */ +#define WM2200_OUT2LMIX_SRC4_MASK 0x007F /* OUT2LMIX_SRC4 - [6:0] */ +#define WM2200_OUT2LMIX_SRC4_SHIFT 0 /* OUT2LMIX_SRC4 - [6:0] */ +#define WM2200_OUT2LMIX_SRC4_WIDTH 7 /* OUT2LMIX_SRC4 - [6:0] */ + +/* + * R1559 (0x617) - OUT2LMIX Input 4 Volume + */ +#define WM2200_OUT2LMIX_VOL4_MASK 0x00FE /* OUT2LMIX_VOL4 - [7:1] */ +#define WM2200_OUT2LMIX_VOL4_SHIFT 1 /* OUT2LMIX_VOL4 - [7:1] */ +#define WM2200_OUT2LMIX_VOL4_WIDTH 7 /* OUT2LMIX_VOL4 - [7:1] */ + +/* + * R1560 (0x618) - OUT2RMIX Input 1 Source + */ +#define WM2200_OUT2RMIX_SRC1_MASK 0x007F /* OUT2RMIX_SRC1 - [6:0] */ +#define WM2200_OUT2RMIX_SRC1_SHIFT 0 /* OUT2RMIX_SRC1 - [6:0] */ +#define WM2200_OUT2RMIX_SRC1_WIDTH 7 /* OUT2RMIX_SRC1 - [6:0] */ + +/* + * R1561 (0x619) - OUT2RMIX Input 1 Volume + */ +#define WM2200_OUT2RMIX_VOL1_MASK 0x00FE /* OUT2RMIX_VOL1 - [7:1] */ +#define WM2200_OUT2RMIX_VOL1_SHIFT 1 /* OUT2RMIX_VOL1 - [7:1] */ +#define WM2200_OUT2RMIX_VOL1_WIDTH 7 /* OUT2RMIX_VOL1 - [7:1] */ + +/* + * R1562 (0x61A) - OUT2RMIX Input 2 Source + */ +#define WM2200_OUT2RMIX_SRC2_MASK 0x007F /* OUT2RMIX_SRC2 - [6:0] */ +#define WM2200_OUT2RMIX_SRC2_SHIFT 0 /* OUT2RMIX_SRC2 - [6:0] */ +#define WM2200_OUT2RMIX_SRC2_WIDTH 7 /* OUT2RMIX_SRC2 - [6:0] */ + +/* + * R1563 (0x61B) - OUT2RMIX Input 2 Volume + */ +#define WM2200_OUT2RMIX_VOL2_MASK 0x00FE /* OUT2RMIX_VOL2 - [7:1] */ +#define WM2200_OUT2RMIX_VOL2_SHIFT 1 /* OUT2RMIX_VOL2 - [7:1] */ +#define WM2200_OUT2RMIX_VOL2_WIDTH 7 /* OUT2RMIX_VOL2 - [7:1] */ + +/* + * R1564 (0x61C) - OUT2RMIX Input 3 Source + */ +#define WM2200_OUT2RMIX_SRC3_MASK 0x007F /* OUT2RMIX_SRC3 - [6:0] */ +#define WM2200_OUT2RMIX_SRC3_SHIFT 0 /* OUT2RMIX_SRC3 - [6:0] */ +#define WM2200_OUT2RMIX_SRC3_WIDTH 7 /* OUT2RMIX_SRC3 - [6:0] */ + +/* + * R1565 (0x61D) - OUT2RMIX Input 3 Volume + */ +#define WM2200_OUT2RMIX_VOL3_MASK 0x00FE /* OUT2RMIX_VOL3 - [7:1] */ +#define WM2200_OUT2RMIX_VOL3_SHIFT 1 /* OUT2RMIX_VOL3 - [7:1] */ +#define WM2200_OUT2RMIX_VOL3_WIDTH 7 /* OUT2RMIX_VOL3 - [7:1] */ + +/* + * R1566 (0x61E) - OUT2RMIX Input 4 Source + */ +#define WM2200_OUT2RMIX_SRC4_MASK 0x007F /* OUT2RMIX_SRC4 - [6:0] */ +#define WM2200_OUT2RMIX_SRC4_SHIFT 0 /* OUT2RMIX_SRC4 - [6:0] */ +#define WM2200_OUT2RMIX_SRC4_WIDTH 7 /* OUT2RMIX_SRC4 - [6:0] */ + +/* + * R1567 (0x61F) - OUT2RMIX Input 4 Volume + */ +#define WM2200_OUT2RMIX_VOL4_MASK 0x00FE /* OUT2RMIX_VOL4 - [7:1] */ +#define WM2200_OUT2RMIX_VOL4_SHIFT 1 /* OUT2RMIX_VOL4 - [7:1] */ +#define WM2200_OUT2RMIX_VOL4_WIDTH 7 /* OUT2RMIX_VOL4 - [7:1] */ + +/* + * R1568 (0x620) - AIF1TX1MIX Input 1 Source + */ +#define WM2200_AIF1TX1MIX_SRC1_MASK 0x007F /* AIF1TX1MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX1MIX_SRC1_SHIFT 0 /* AIF1TX1MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX1MIX_SRC1_WIDTH 7 /* AIF1TX1MIX_SRC1 - [6:0] */ + +/* + * R1569 (0x621) - AIF1TX1MIX Input 1 Volume + */ +#define WM2200_AIF1TX1MIX_VOL1_MASK 0x00FE /* AIF1TX1MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX1MIX_VOL1_SHIFT 1 /* AIF1TX1MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX1MIX_VOL1_WIDTH 7 /* AIF1TX1MIX_VOL1 - [7:1] */ + +/* + * R1570 (0x622) - AIF1TX1MIX Input 2 Source + */ +#define WM2200_AIF1TX1MIX_SRC2_MASK 0x007F /* AIF1TX1MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX1MIX_SRC2_SHIFT 0 /* AIF1TX1MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX1MIX_SRC2_WIDTH 7 /* AIF1TX1MIX_SRC2 - [6:0] */ + +/* + * R1571 (0x623) - AIF1TX1MIX Input 2 Volume + */ +#define WM2200_AIF1TX1MIX_VOL2_MASK 0x00FE /* AIF1TX1MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX1MIX_VOL2_SHIFT 1 /* AIF1TX1MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX1MIX_VOL2_WIDTH 7 /* AIF1TX1MIX_VOL2 - [7:1] */ + +/* + * R1572 (0x624) - AIF1TX1MIX Input 3 Source + */ +#define WM2200_AIF1TX1MIX_SRC3_MASK 0x007F /* AIF1TX1MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX1MIX_SRC3_SHIFT 0 /* AIF1TX1MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX1MIX_SRC3_WIDTH 7 /* AIF1TX1MIX_SRC3 - [6:0] */ + +/* + * R1573 (0x625) - AIF1TX1MIX Input 3 Volume + */ +#define WM2200_AIF1TX1MIX_VOL3_MASK 0x00FE /* AIF1TX1MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX1MIX_VOL3_SHIFT 1 /* AIF1TX1MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX1MIX_VOL3_WIDTH 7 /* AIF1TX1MIX_VOL3 - [7:1] */ + +/* + * R1574 (0x626) - AIF1TX1MIX Input 4 Source + */ +#define WM2200_AIF1TX1MIX_SRC4_MASK 0x007F /* AIF1TX1MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX1MIX_SRC4_SHIFT 0 /* AIF1TX1MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX1MIX_SRC4_WIDTH 7 /* AIF1TX1MIX_SRC4 - [6:0] */ + +/* + * R1575 (0x627) - AIF1TX1MIX Input 4 Volume + */ +#define WM2200_AIF1TX1MIX_VOL4_MASK 0x00FE /* AIF1TX1MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX1MIX_VOL4_SHIFT 1 /* AIF1TX1MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX1MIX_VOL4_WIDTH 7 /* AIF1TX1MIX_VOL4 - [7:1] */ + +/* + * R1576 (0x628) - AIF1TX2MIX Input 1 Source + */ +#define WM2200_AIF1TX2MIX_SRC1_MASK 0x007F /* AIF1TX2MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX2MIX_SRC1_SHIFT 0 /* AIF1TX2MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX2MIX_SRC1_WIDTH 7 /* AIF1TX2MIX_SRC1 - [6:0] */ + +/* + * R1577 (0x629) - AIF1TX2MIX Input 1 Volume + */ +#define WM2200_AIF1TX2MIX_VOL1_MASK 0x00FE /* AIF1TX2MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX2MIX_VOL1_SHIFT 1 /* AIF1TX2MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX2MIX_VOL1_WIDTH 7 /* AIF1TX2MIX_VOL1 - [7:1] */ + +/* + * R1578 (0x62A) - AIF1TX2MIX Input 2 Source + */ +#define WM2200_AIF1TX2MIX_SRC2_MASK 0x007F /* AIF1TX2MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX2MIX_SRC2_SHIFT 0 /* AIF1TX2MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX2MIX_SRC2_WIDTH 7 /* AIF1TX2MIX_SRC2 - [6:0] */ + +/* + * R1579 (0x62B) - AIF1TX2MIX Input 2 Volume + */ +#define WM2200_AIF1TX2MIX_VOL2_MASK 0x00FE /* AIF1TX2MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX2MIX_VOL2_SHIFT 1 /* AIF1TX2MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX2MIX_VOL2_WIDTH 7 /* AIF1TX2MIX_VOL2 - [7:1] */ + +/* + * R1580 (0x62C) - AIF1TX2MIX Input 3 Source + */ +#define WM2200_AIF1TX2MIX_SRC3_MASK 0x007F /* AIF1TX2MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX2MIX_SRC3_SHIFT 0 /* AIF1TX2MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX2MIX_SRC3_WIDTH 7 /* AIF1TX2MIX_SRC3 - [6:0] */ + +/* + * R1581 (0x62D) - AIF1TX2MIX Input 3 Volume + */ +#define WM2200_AIF1TX2MIX_VOL3_MASK 0x00FE /* AIF1TX2MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX2MIX_VOL3_SHIFT 1 /* AIF1TX2MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX2MIX_VOL3_WIDTH 7 /* AIF1TX2MIX_VOL3 - [7:1] */ + +/* + * R1582 (0x62E) - AIF1TX2MIX Input 4 Source + */ +#define WM2200_AIF1TX2MIX_SRC4_MASK 0x007F /* AIF1TX2MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX2MIX_SRC4_SHIFT 0 /* AIF1TX2MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX2MIX_SRC4_WIDTH 7 /* AIF1TX2MIX_SRC4 - [6:0] */ + +/* + * R1583 (0x62F) - AIF1TX2MIX Input 4 Volume + */ +#define WM2200_AIF1TX2MIX_VOL4_MASK 0x00FE /* AIF1TX2MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX2MIX_VOL4_SHIFT 1 /* AIF1TX2MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX2MIX_VOL4_WIDTH 7 /* AIF1TX2MIX_VOL4 - [7:1] */ + +/* + * R1584 (0x630) - AIF1TX3MIX Input 1 Source + */ +#define WM2200_AIF1TX3MIX_SRC1_MASK 0x007F /* AIF1TX3MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX3MIX_SRC1_SHIFT 0 /* AIF1TX3MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX3MIX_SRC1_WIDTH 7 /* AIF1TX3MIX_SRC1 - [6:0] */ + +/* + * R1585 (0x631) - AIF1TX3MIX Input 1 Volume + */ +#define WM2200_AIF1TX3MIX_VOL1_MASK 0x00FE /* AIF1TX3MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX3MIX_VOL1_SHIFT 1 /* AIF1TX3MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX3MIX_VOL1_WIDTH 7 /* AIF1TX3MIX_VOL1 - [7:1] */ + +/* + * R1586 (0x632) - AIF1TX3MIX Input 2 Source + */ +#define WM2200_AIF1TX3MIX_SRC2_MASK 0x007F /* AIF1TX3MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX3MIX_SRC2_SHIFT 0 /* AIF1TX3MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX3MIX_SRC2_WIDTH 7 /* AIF1TX3MIX_SRC2 - [6:0] */ + +/* + * R1587 (0x633) - AIF1TX3MIX Input 2 Volume + */ +#define WM2200_AIF1TX3MIX_VOL2_MASK 0x00FE /* AIF1TX3MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX3MIX_VOL2_SHIFT 1 /* AIF1TX3MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX3MIX_VOL2_WIDTH 7 /* AIF1TX3MIX_VOL2 - [7:1] */ + +/* + * R1588 (0x634) - AIF1TX3MIX Input 3 Source + */ +#define WM2200_AIF1TX3MIX_SRC3_MASK 0x007F /* AIF1TX3MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX3MIX_SRC3_SHIFT 0 /* AIF1TX3MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX3MIX_SRC3_WIDTH 7 /* AIF1TX3MIX_SRC3 - [6:0] */ + +/* + * R1589 (0x635) - AIF1TX3MIX Input 3 Volume + */ +#define WM2200_AIF1TX3MIX_VOL3_MASK 0x00FE /* AIF1TX3MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX3MIX_VOL3_SHIFT 1 /* AIF1TX3MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX3MIX_VOL3_WIDTH 7 /* AIF1TX3MIX_VOL3 - [7:1] */ + +/* + * R1590 (0x636) - AIF1TX3MIX Input 4 Source + */ +#define WM2200_AIF1TX3MIX_SRC4_MASK 0x007F /* AIF1TX3MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX3MIX_SRC4_SHIFT 0 /* AIF1TX3MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX3MIX_SRC4_WIDTH 7 /* AIF1TX3MIX_SRC4 - [6:0] */ + +/* + * R1591 (0x637) - AIF1TX3MIX Input 4 Volume + */ +#define WM2200_AIF1TX3MIX_VOL4_MASK 0x00FE /* AIF1TX3MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX3MIX_VOL4_SHIFT 1 /* AIF1TX3MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX3MIX_VOL4_WIDTH 7 /* AIF1TX3MIX_VOL4 - [7:1] */ + +/* + * R1592 (0x638) - AIF1TX4MIX Input 1 Source + */ +#define WM2200_AIF1TX4MIX_SRC1_MASK 0x007F /* AIF1TX4MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX4MIX_SRC1_SHIFT 0 /* AIF1TX4MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX4MIX_SRC1_WIDTH 7 /* AIF1TX4MIX_SRC1 - [6:0] */ + +/* + * R1593 (0x639) - AIF1TX4MIX Input 1 Volume + */ +#define WM2200_AIF1TX4MIX_VOL1_MASK 0x00FE /* AIF1TX4MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX4MIX_VOL1_SHIFT 1 /* AIF1TX4MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX4MIX_VOL1_WIDTH 7 /* AIF1TX4MIX_VOL1 - [7:1] */ + +/* + * R1594 (0x63A) - AIF1TX4MIX Input 2 Source + */ +#define WM2200_AIF1TX4MIX_SRC2_MASK 0x007F /* AIF1TX4MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX4MIX_SRC2_SHIFT 0 /* AIF1TX4MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX4MIX_SRC2_WIDTH 7 /* AIF1TX4MIX_SRC2 - [6:0] */ + +/* + * R1595 (0x63B) - AIF1TX4MIX Input 2 Volume + */ +#define WM2200_AIF1TX4MIX_VOL2_MASK 0x00FE /* AIF1TX4MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX4MIX_VOL2_SHIFT 1 /* AIF1TX4MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX4MIX_VOL2_WIDTH 7 /* AIF1TX4MIX_VOL2 - [7:1] */ + +/* + * R1596 (0x63C) - AIF1TX4MIX Input 3 Source + */ +#define WM2200_AIF1TX4MIX_SRC3_MASK 0x007F /* AIF1TX4MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX4MIX_SRC3_SHIFT 0 /* AIF1TX4MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX4MIX_SRC3_WIDTH 7 /* AIF1TX4MIX_SRC3 - [6:0] */ + +/* + * R1597 (0x63D) - AIF1TX4MIX Input 3 Volume + */ +#define WM2200_AIF1TX4MIX_VOL3_MASK 0x00FE /* AIF1TX4MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX4MIX_VOL3_SHIFT 1 /* AIF1TX4MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX4MIX_VOL3_WIDTH 7 /* AIF1TX4MIX_VOL3 - [7:1] */ + +/* + * R1598 (0x63E) - AIF1TX4MIX Input 4 Source + */ +#define WM2200_AIF1TX4MIX_SRC4_MASK 0x007F /* AIF1TX4MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX4MIX_SRC4_SHIFT 0 /* AIF1TX4MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX4MIX_SRC4_WIDTH 7 /* AIF1TX4MIX_SRC4 - [6:0] */ + +/* + * R1599 (0x63F) - AIF1TX4MIX Input 4 Volume + */ +#define WM2200_AIF1TX4MIX_VOL4_MASK 0x00FE /* AIF1TX4MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX4MIX_VOL4_SHIFT 1 /* AIF1TX4MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX4MIX_VOL4_WIDTH 7 /* AIF1TX4MIX_VOL4 - [7:1] */ + +/* + * R1600 (0x640) - AIF1TX5MIX Input 1 Source + */ +#define WM2200_AIF1TX5MIX_SRC1_MASK 0x007F /* AIF1TX5MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX5MIX_SRC1_SHIFT 0 /* AIF1TX5MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX5MIX_SRC1_WIDTH 7 /* AIF1TX5MIX_SRC1 - [6:0] */ + +/* + * R1601 (0x641) - AIF1TX5MIX Input 1 Volume + */ +#define WM2200_AIF1TX5MIX_VOL1_MASK 0x00FE /* AIF1TX5MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX5MIX_VOL1_SHIFT 1 /* AIF1TX5MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX5MIX_VOL1_WIDTH 7 /* AIF1TX5MIX_VOL1 - [7:1] */ + +/* + * R1602 (0x642) - AIF1TX5MIX Input 2 Source + */ +#define WM2200_AIF1TX5MIX_SRC2_MASK 0x007F /* AIF1TX5MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX5MIX_SRC2_SHIFT 0 /* AIF1TX5MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX5MIX_SRC2_WIDTH 7 /* AIF1TX5MIX_SRC2 - [6:0] */ + +/* + * R1603 (0x643) - AIF1TX5MIX Input 2 Volume + */ +#define WM2200_AIF1TX5MIX_VOL2_MASK 0x00FE /* AIF1TX5MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX5MIX_VOL2_SHIFT 1 /* AIF1TX5MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX5MIX_VOL2_WIDTH 7 /* AIF1TX5MIX_VOL2 - [7:1] */ + +/* + * R1604 (0x644) - AIF1TX5MIX Input 3 Source + */ +#define WM2200_AIF1TX5MIX_SRC3_MASK 0x007F /* AIF1TX5MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX5MIX_SRC3_SHIFT 0 /* AIF1TX5MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX5MIX_SRC3_WIDTH 7 /* AIF1TX5MIX_SRC3 - [6:0] */ + +/* + * R1605 (0x645) - AIF1TX5MIX Input 3 Volume + */ +#define WM2200_AIF1TX5MIX_VOL3_MASK 0x00FE /* AIF1TX5MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX5MIX_VOL3_SHIFT 1 /* AIF1TX5MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX5MIX_VOL3_WIDTH 7 /* AIF1TX5MIX_VOL3 - [7:1] */ + +/* + * R1606 (0x646) - AIF1TX5MIX Input 4 Source + */ +#define WM2200_AIF1TX5MIX_SRC4_MASK 0x007F /* AIF1TX5MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX5MIX_SRC4_SHIFT 0 /* AIF1TX5MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX5MIX_SRC4_WIDTH 7 /* AIF1TX5MIX_SRC4 - [6:0] */ + +/* + * R1607 (0x647) - AIF1TX5MIX Input 4 Volume + */ +#define WM2200_AIF1TX5MIX_VOL4_MASK 0x00FE /* AIF1TX5MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX5MIX_VOL4_SHIFT 1 /* AIF1TX5MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX5MIX_VOL4_WIDTH 7 /* AIF1TX5MIX_VOL4 - [7:1] */ + +/* + * R1608 (0x648) - AIF1TX6MIX Input 1 Source + */ +#define WM2200_AIF1TX6MIX_SRC1_MASK 0x007F /* AIF1TX6MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX6MIX_SRC1_SHIFT 0 /* AIF1TX6MIX_SRC1 - [6:0] */ +#define WM2200_AIF1TX6MIX_SRC1_WIDTH 7 /* AIF1TX6MIX_SRC1 - [6:0] */ + +/* + * R1609 (0x649) - AIF1TX6MIX Input 1 Volume + */ +#define WM2200_AIF1TX6MIX_VOL1_MASK 0x00FE /* AIF1TX6MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX6MIX_VOL1_SHIFT 1 /* AIF1TX6MIX_VOL1 - [7:1] */ +#define WM2200_AIF1TX6MIX_VOL1_WIDTH 7 /* AIF1TX6MIX_VOL1 - [7:1] */ + +/* + * R1610 (0x64A) - AIF1TX6MIX Input 2 Source + */ +#define WM2200_AIF1TX6MIX_SRC2_MASK 0x007F /* AIF1TX6MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX6MIX_SRC2_SHIFT 0 /* AIF1TX6MIX_SRC2 - [6:0] */ +#define WM2200_AIF1TX6MIX_SRC2_WIDTH 7 /* AIF1TX6MIX_SRC2 - [6:0] */ + +/* + * R1611 (0x64B) - AIF1TX6MIX Input 2 Volume + */ +#define WM2200_AIF1TX6MIX_VOL2_MASK 0x00FE /* AIF1TX6MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX6MIX_VOL2_SHIFT 1 /* AIF1TX6MIX_VOL2 - [7:1] */ +#define WM2200_AIF1TX6MIX_VOL2_WIDTH 7 /* AIF1TX6MIX_VOL2 - [7:1] */ + +/* + * R1612 (0x64C) - AIF1TX6MIX Input 3 Source + */ +#define WM2200_AIF1TX6MIX_SRC3_MASK 0x007F /* AIF1TX6MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX6MIX_SRC3_SHIFT 0 /* AIF1TX6MIX_SRC3 - [6:0] */ +#define WM2200_AIF1TX6MIX_SRC3_WIDTH 7 /* AIF1TX6MIX_SRC3 - [6:0] */ + +/* + * R1613 (0x64D) - AIF1TX6MIX Input 3 Volume + */ +#define WM2200_AIF1TX6MIX_VOL3_MASK 0x00FE /* AIF1TX6MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX6MIX_VOL3_SHIFT 1 /* AIF1TX6MIX_VOL3 - [7:1] */ +#define WM2200_AIF1TX6MIX_VOL3_WIDTH 7 /* AIF1TX6MIX_VOL3 - [7:1] */ + +/* + * R1614 (0x64E) - AIF1TX6MIX Input 4 Source + */ +#define WM2200_AIF1TX6MIX_SRC4_MASK 0x007F /* AIF1TX6MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX6MIX_SRC4_SHIFT 0 /* AIF1TX6MIX_SRC4 - [6:0] */ +#define WM2200_AIF1TX6MIX_SRC4_WIDTH 7 /* AIF1TX6MIX_SRC4 - [6:0] */ + +/* + * R1615 (0x64F) - AIF1TX6MIX Input 4 Volume + */ +#define WM2200_AIF1TX6MIX_VOL4_MASK 0x00FE /* AIF1TX6MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX6MIX_VOL4_SHIFT 1 /* AIF1TX6MIX_VOL4 - [7:1] */ +#define WM2200_AIF1TX6MIX_VOL4_WIDTH 7 /* AIF1TX6MIX_VOL4 - [7:1] */ + +/* + * R1616 (0x650) - EQLMIX Input 1 Source + */ +#define WM2200_EQLMIX_SRC1_MASK 0x007F /* EQLMIX_SRC1 - [6:0] */ +#define WM2200_EQLMIX_SRC1_SHIFT 0 /* EQLMIX_SRC1 - [6:0] */ +#define WM2200_EQLMIX_SRC1_WIDTH 7 /* EQLMIX_SRC1 - [6:0] */ + +/* + * R1617 (0x651) - EQLMIX Input 1 Volume + */ +#define WM2200_EQLMIX_VOL1_MASK 0x00FE /* EQLMIX_VOL1 - [7:1] */ +#define WM2200_EQLMIX_VOL1_SHIFT 1 /* EQLMIX_VOL1 - [7:1] */ +#define WM2200_EQLMIX_VOL1_WIDTH 7 /* EQLMIX_VOL1 - [7:1] */ + +/* + * R1618 (0x652) - EQLMIX Input 2 Source + */ +#define WM2200_EQLMIX_SRC2_MASK 0x007F /* EQLMIX_SRC2 - [6:0] */ +#define WM2200_EQLMIX_SRC2_SHIFT 0 /* EQLMIX_SRC2 - [6:0] */ +#define WM2200_EQLMIX_SRC2_WIDTH 7 /* EQLMIX_SRC2 - [6:0] */ + +/* + * R1619 (0x653) - EQLMIX Input 2 Volume + */ +#define WM2200_EQLMIX_VOL2_MASK 0x00FE /* EQLMIX_VOL2 - [7:1] */ +#define WM2200_EQLMIX_VOL2_SHIFT 1 /* EQLMIX_VOL2 - [7:1] */ +#define WM2200_EQLMIX_VOL2_WIDTH 7 /* EQLMIX_VOL2 - [7:1] */ + +/* + * R1620 (0x654) - EQLMIX Input 3 Source + */ +#define WM2200_EQLMIX_SRC3_MASK 0x007F /* EQLMIX_SRC3 - [6:0] */ +#define WM2200_EQLMIX_SRC3_SHIFT 0 /* EQLMIX_SRC3 - [6:0] */ +#define WM2200_EQLMIX_SRC3_WIDTH 7 /* EQLMIX_SRC3 - [6:0] */ + +/* + * R1621 (0x655) - EQLMIX Input 3 Volume + */ +#define WM2200_EQLMIX_VOL3_MASK 0x00FE /* EQLMIX_VOL3 - [7:1] */ +#define WM2200_EQLMIX_VOL3_SHIFT 1 /* EQLMIX_VOL3 - [7:1] */ +#define WM2200_EQLMIX_VOL3_WIDTH 7 /* EQLMIX_VOL3 - [7:1] */ + +/* + * R1622 (0x656) - EQLMIX Input 4 Source + */ +#define WM2200_EQLMIX_SRC4_MASK 0x007F /* EQLMIX_SRC4 - [6:0] */ +#define WM2200_EQLMIX_SRC4_SHIFT 0 /* EQLMIX_SRC4 - [6:0] */ +#define WM2200_EQLMIX_SRC4_WIDTH 7 /* EQLMIX_SRC4 - [6:0] */ + +/* + * R1623 (0x657) - EQLMIX Input 4 Volume + */ +#define WM2200_EQLMIX_VOL4_MASK 0x00FE /* EQLMIX_VOL4 - [7:1] */ +#define WM2200_EQLMIX_VOL4_SHIFT 1 /* EQLMIX_VOL4 - [7:1] */ +#define WM2200_EQLMIX_VOL4_WIDTH 7 /* EQLMIX_VOL4 - [7:1] */ + +/* + * R1624 (0x658) - EQRMIX Input 1 Source + */ +#define WM2200_EQRMIX_SRC1_MASK 0x007F /* EQRMIX_SRC1 - [6:0] */ +#define WM2200_EQRMIX_SRC1_SHIFT 0 /* EQRMIX_SRC1 - [6:0] */ +#define WM2200_EQRMIX_SRC1_WIDTH 7 /* EQRMIX_SRC1 - [6:0] */ + +/* + * R1625 (0x659) - EQRMIX Input 1 Volume + */ +#define WM2200_EQRMIX_VOL1_MASK 0x00FE /* EQRMIX_VOL1 - [7:1] */ +#define WM2200_EQRMIX_VOL1_SHIFT 1 /* EQRMIX_VOL1 - [7:1] */ +#define WM2200_EQRMIX_VOL1_WIDTH 7 /* EQRMIX_VOL1 - [7:1] */ + +/* + * R1626 (0x65A) - EQRMIX Input 2 Source + */ +#define WM2200_EQRMIX_SRC2_MASK 0x007F /* EQRMIX_SRC2 - [6:0] */ +#define WM2200_EQRMIX_SRC2_SHIFT 0 /* EQRMIX_SRC2 - [6:0] */ +#define WM2200_EQRMIX_SRC2_WIDTH 7 /* EQRMIX_SRC2 - [6:0] */ + +/* + * R1627 (0x65B) - EQRMIX Input 2 Volume + */ +#define WM2200_EQRMIX_VOL2_MASK 0x00FE /* EQRMIX_VOL2 - [7:1] */ +#define WM2200_EQRMIX_VOL2_SHIFT 1 /* EQRMIX_VOL2 - [7:1] */ +#define WM2200_EQRMIX_VOL2_WIDTH 7 /* EQRMIX_VOL2 - [7:1] */ + +/* + * R1628 (0x65C) - EQRMIX Input 3 Source + */ +#define WM2200_EQRMIX_SRC3_MASK 0x007F /* EQRMIX_SRC3 - [6:0] */ +#define WM2200_EQRMIX_SRC3_SHIFT 0 /* EQRMIX_SRC3 - [6:0] */ +#define WM2200_EQRMIX_SRC3_WIDTH 7 /* EQRMIX_SRC3 - [6:0] */ + +/* + * R1629 (0x65D) - EQRMIX Input 3 Volume + */ +#define WM2200_EQRMIX_VOL3_MASK 0x00FE /* EQRMIX_VOL3 - [7:1] */ +#define WM2200_EQRMIX_VOL3_SHIFT 1 /* EQRMIX_VOL3 - [7:1] */ +#define WM2200_EQRMIX_VOL3_WIDTH 7 /* EQRMIX_VOL3 - [7:1] */ + +/* + * R1630 (0x65E) - EQRMIX Input 4 Source + */ +#define WM2200_EQRMIX_SRC4_MASK 0x007F /* EQRMIX_SRC4 - [6:0] */ +#define WM2200_EQRMIX_SRC4_SHIFT 0 /* EQRMIX_SRC4 - [6:0] */ +#define WM2200_EQRMIX_SRC4_WIDTH 7 /* EQRMIX_SRC4 - [6:0] */ + +/* + * R1631 (0x65F) - EQRMIX Input 4 Volume + */ +#define WM2200_EQRMIX_VOL4_MASK 0x00FE /* EQRMIX_VOL4 - [7:1] */ +#define WM2200_EQRMIX_VOL4_SHIFT 1 /* EQRMIX_VOL4 - [7:1] */ +#define WM2200_EQRMIX_VOL4_WIDTH 7 /* EQRMIX_VOL4 - [7:1] */ + +/* + * R1632 (0x660) - LHPF1MIX Input 1 Source + */ +#define WM2200_LHPF1MIX_SRC1_MASK 0x007F /* LHPF1MIX_SRC1 - [6:0] */ +#define WM2200_LHPF1MIX_SRC1_SHIFT 0 /* LHPF1MIX_SRC1 - [6:0] */ +#define WM2200_LHPF1MIX_SRC1_WIDTH 7 /* LHPF1MIX_SRC1 - [6:0] */ + +/* + * R1633 (0x661) - LHPF1MIX Input 1 Volume + */ +#define WM2200_LHPF1MIX_VOL1_MASK 0x00FE /* LHPF1MIX_VOL1 - [7:1] */ +#define WM2200_LHPF1MIX_VOL1_SHIFT 1 /* LHPF1MIX_VOL1 - [7:1] */ +#define WM2200_LHPF1MIX_VOL1_WIDTH 7 /* LHPF1MIX_VOL1 - [7:1] */ + +/* + * R1634 (0x662) - LHPF1MIX Input 2 Source + */ +#define WM2200_LHPF1MIX_SRC2_MASK 0x007F /* LHPF1MIX_SRC2 - [6:0] */ +#define WM2200_LHPF1MIX_SRC2_SHIFT 0 /* LHPF1MIX_SRC2 - [6:0] */ +#define WM2200_LHPF1MIX_SRC2_WIDTH 7 /* LHPF1MIX_SRC2 - [6:0] */ + +/* + * R1635 (0x663) - LHPF1MIX Input 2 Volume + */ +#define WM2200_LHPF1MIX_VOL2_MASK 0x00FE /* LHPF1MIX_VOL2 - [7:1] */ +#define WM2200_LHPF1MIX_VOL2_SHIFT 1 /* LHPF1MIX_VOL2 - [7:1] */ +#define WM2200_LHPF1MIX_VOL2_WIDTH 7 /* LHPF1MIX_VOL2 - [7:1] */ + +/* + * R1636 (0x664) - LHPF1MIX Input 3 Source + */ +#define WM2200_LHPF1MIX_SRC3_MASK 0x007F /* LHPF1MIX_SRC3 - [6:0] */ +#define WM2200_LHPF1MIX_SRC3_SHIFT 0 /* LHPF1MIX_SRC3 - [6:0] */ +#define WM2200_LHPF1MIX_SRC3_WIDTH 7 /* LHPF1MIX_SRC3 - [6:0] */ + +/* + * R1637 (0x665) - LHPF1MIX Input 3 Volume + */ +#define WM2200_LHPF1MIX_VOL3_MASK 0x00FE /* LHPF1MIX_VOL3 - [7:1] */ +#define WM2200_LHPF1MIX_VOL3_SHIFT 1 /* LHPF1MIX_VOL3 - [7:1] */ +#define WM2200_LHPF1MIX_VOL3_WIDTH 7 /* LHPF1MIX_VOL3 - [7:1] */ + +/* + * R1638 (0x666) - LHPF1MIX Input 4 Source + */ +#define WM2200_LHPF1MIX_SRC4_MASK 0x007F /* LHPF1MIX_SRC4 - [6:0] */ +#define WM2200_LHPF1MIX_SRC4_SHIFT 0 /* LHPF1MIX_SRC4 - [6:0] */ +#define WM2200_LHPF1MIX_SRC4_WIDTH 7 /* LHPF1MIX_SRC4 - [6:0] */ + +/* + * R1639 (0x667) - LHPF1MIX Input 4 Volume + */ +#define WM2200_LHPF1MIX_VOL4_MASK 0x00FE /* LHPF1MIX_VOL4 - [7:1] */ +#define WM2200_LHPF1MIX_VOL4_SHIFT 1 /* LHPF1MIX_VOL4 - [7:1] */ +#define WM2200_LHPF1MIX_VOL4_WIDTH 7 /* LHPF1MIX_VOL4 - [7:1] */ + +/* + * R1640 (0x668) - LHPF2MIX Input 1 Source + */ +#define WM2200_LHPF2MIX_SRC1_MASK 0x007F /* LHPF2MIX_SRC1 - [6:0] */ +#define WM2200_LHPF2MIX_SRC1_SHIFT 0 /* LHPF2MIX_SRC1 - [6:0] */ +#define WM2200_LHPF2MIX_SRC1_WIDTH 7 /* LHPF2MIX_SRC1 - [6:0] */ + +/* + * R1641 (0x669) - LHPF2MIX Input 1 Volume + */ +#define WM2200_LHPF2MIX_VOL1_MASK 0x00FE /* LHPF2MIX_VOL1 - [7:1] */ +#define WM2200_LHPF2MIX_VOL1_SHIFT 1 /* LHPF2MIX_VOL1 - [7:1] */ +#define WM2200_LHPF2MIX_VOL1_WIDTH 7 /* LHPF2MIX_VOL1 - [7:1] */ + +/* + * R1642 (0x66A) - LHPF2MIX Input 2 Source + */ +#define WM2200_LHPF2MIX_SRC2_MASK 0x007F /* LHPF2MIX_SRC2 - [6:0] */ +#define WM2200_LHPF2MIX_SRC2_SHIFT 0 /* LHPF2MIX_SRC2 - [6:0] */ +#define WM2200_LHPF2MIX_SRC2_WIDTH 7 /* LHPF2MIX_SRC2 - [6:0] */ + +/* + * R1643 (0x66B) - LHPF2MIX Input 2 Volume + */ +#define WM2200_LHPF2MIX_VOL2_MASK 0x00FE /* LHPF2MIX_VOL2 - [7:1] */ +#define WM2200_LHPF2MIX_VOL2_SHIFT 1 /* LHPF2MIX_VOL2 - [7:1] */ +#define WM2200_LHPF2MIX_VOL2_WIDTH 7 /* LHPF2MIX_VOL2 - [7:1] */ + +/* + * R1644 (0x66C) - LHPF2MIX Input 3 Source + */ +#define WM2200_LHPF2MIX_SRC3_MASK 0x007F /* LHPF2MIX_SRC3 - [6:0] */ +#define WM2200_LHPF2MIX_SRC3_SHIFT 0 /* LHPF2MIX_SRC3 - [6:0] */ +#define WM2200_LHPF2MIX_SRC3_WIDTH 7 /* LHPF2MIX_SRC3 - [6:0] */ + +/* + * R1645 (0x66D) - LHPF2MIX Input 3 Volume + */ +#define WM2200_LHPF2MIX_VOL3_MASK 0x00FE /* LHPF2MIX_VOL3 - [7:1] */ +#define WM2200_LHPF2MIX_VOL3_SHIFT 1 /* LHPF2MIX_VOL3 - [7:1] */ +#define WM2200_LHPF2MIX_VOL3_WIDTH 7 /* LHPF2MIX_VOL3 - [7:1] */ + +/* + * R1646 (0x66E) - LHPF2MIX Input 4 Source + */ +#define WM2200_LHPF2MIX_SRC4_MASK 0x007F /* LHPF2MIX_SRC4 - [6:0] */ +#define WM2200_LHPF2MIX_SRC4_SHIFT 0 /* LHPF2MIX_SRC4 - [6:0] */ +#define WM2200_LHPF2MIX_SRC4_WIDTH 7 /* LHPF2MIX_SRC4 - [6:0] */ + +/* + * R1647 (0x66F) - LHPF2MIX Input 4 Volume + */ +#define WM2200_LHPF2MIX_VOL4_MASK 0x00FE /* LHPF2MIX_VOL4 - [7:1] */ +#define WM2200_LHPF2MIX_VOL4_SHIFT 1 /* LHPF2MIX_VOL4 - [7:1] */ +#define WM2200_LHPF2MIX_VOL4_WIDTH 7 /* LHPF2MIX_VOL4 - [7:1] */ + +/* + * R1648 (0x670) - DSP1LMIX Input 1 Source + */ +#define WM2200_DSP1LMIX_SRC1_MASK 0x007F /* DSP1LMIX_SRC1 - [6:0] */ +#define WM2200_DSP1LMIX_SRC1_SHIFT 0 /* DSP1LMIX_SRC1 - [6:0] */ +#define WM2200_DSP1LMIX_SRC1_WIDTH 7 /* DSP1LMIX_SRC1 - [6:0] */ + +/* + * R1649 (0x671) - DSP1LMIX Input 1 Volume + */ +#define WM2200_DSP1LMIX_VOL1_MASK 0x00FE /* DSP1LMIX_VOL1 - [7:1] */ +#define WM2200_DSP1LMIX_VOL1_SHIFT 1 /* DSP1LMIX_VOL1 - [7:1] */ +#define WM2200_DSP1LMIX_VOL1_WIDTH 7 /* DSP1LMIX_VOL1 - [7:1] */ + +/* + * R1650 (0x672) - DSP1LMIX Input 2 Source + */ +#define WM2200_DSP1LMIX_SRC2_MASK 0x007F /* DSP1LMIX_SRC2 - [6:0] */ +#define WM2200_DSP1LMIX_SRC2_SHIFT 0 /* DSP1LMIX_SRC2 - [6:0] */ +#define WM2200_DSP1LMIX_SRC2_WIDTH 7 /* DSP1LMIX_SRC2 - [6:0] */ + +/* + * R1651 (0x673) - DSP1LMIX Input 2 Volume + */ +#define WM2200_DSP1LMIX_VOL2_MASK 0x00FE /* DSP1LMIX_VOL2 - [7:1] */ +#define WM2200_DSP1LMIX_VOL2_SHIFT 1 /* DSP1LMIX_VOL2 - [7:1] */ +#define WM2200_DSP1LMIX_VOL2_WIDTH 7 /* DSP1LMIX_VOL2 - [7:1] */ + +/* + * R1652 (0x674) - DSP1LMIX Input 3 Source + */ +#define WM2200_DSP1LMIX_SRC3_MASK 0x007F /* DSP1LMIX_SRC3 - [6:0] */ +#define WM2200_DSP1LMIX_SRC3_SHIFT 0 /* DSP1LMIX_SRC3 - [6:0] */ +#define WM2200_DSP1LMIX_SRC3_WIDTH 7 /* DSP1LMIX_SRC3 - [6:0] */ + +/* + * R1653 (0x675) - DSP1LMIX Input 3 Volume + */ +#define WM2200_DSP1LMIX_VOL3_MASK 0x00FE /* DSP1LMIX_VOL3 - [7:1] */ +#define WM2200_DSP1LMIX_VOL3_SHIFT 1 /* DSP1LMIX_VOL3 - [7:1] */ +#define WM2200_DSP1LMIX_VOL3_WIDTH 7 /* DSP1LMIX_VOL3 - [7:1] */ + +/* + * R1654 (0x676) - DSP1LMIX Input 4 Source + */ +#define WM2200_DSP1LMIX_SRC4_MASK 0x007F /* DSP1LMIX_SRC4 - [6:0] */ +#define WM2200_DSP1LMIX_SRC4_SHIFT 0 /* DSP1LMIX_SRC4 - [6:0] */ +#define WM2200_DSP1LMIX_SRC4_WIDTH 7 /* DSP1LMIX_SRC4 - [6:0] */ + +/* + * R1655 (0x677) - DSP1LMIX Input 4 Volume + */ +#define WM2200_DSP1LMIX_VOL4_MASK 0x00FE /* DSP1LMIX_VOL4 - [7:1] */ +#define WM2200_DSP1LMIX_VOL4_SHIFT 1 /* DSP1LMIX_VOL4 - [7:1] */ +#define WM2200_DSP1LMIX_VOL4_WIDTH 7 /* DSP1LMIX_VOL4 - [7:1] */ + +/* + * R1656 (0x678) - DSP1RMIX Input 1 Source + */ +#define WM2200_DSP1RMIX_SRC1_MASK 0x007F /* DSP1RMIX_SRC1 - [6:0] */ +#define WM2200_DSP1RMIX_SRC1_SHIFT 0 /* DSP1RMIX_SRC1 - [6:0] */ +#define WM2200_DSP1RMIX_SRC1_WIDTH 7 /* DSP1RMIX_SRC1 - [6:0] */ + +/* + * R1657 (0x679) - DSP1RMIX Input 1 Volume + */ +#define WM2200_DSP1RMIX_VOL1_MASK 0x00FE /* DSP1RMIX_VOL1 - [7:1] */ +#define WM2200_DSP1RMIX_VOL1_SHIFT 1 /* DSP1RMIX_VOL1 - [7:1] */ +#define WM2200_DSP1RMIX_VOL1_WIDTH 7 /* DSP1RMIX_VOL1 - [7:1] */ + +/* + * R1658 (0x67A) - DSP1RMIX Input 2 Source + */ +#define WM2200_DSP1RMIX_SRC2_MASK 0x007F /* DSP1RMIX_SRC2 - [6:0] */ +#define WM2200_DSP1RMIX_SRC2_SHIFT 0 /* DSP1RMIX_SRC2 - [6:0] */ +#define WM2200_DSP1RMIX_SRC2_WIDTH 7 /* DSP1RMIX_SRC2 - [6:0] */ + +/* + * R1659 (0x67B) - DSP1RMIX Input 2 Volume + */ +#define WM2200_DSP1RMIX_VOL2_MASK 0x00FE /* DSP1RMIX_VOL2 - [7:1] */ +#define WM2200_DSP1RMIX_VOL2_SHIFT 1 /* DSP1RMIX_VOL2 - [7:1] */ +#define WM2200_DSP1RMIX_VOL2_WIDTH 7 /* DSP1RMIX_VOL2 - [7:1] */ + +/* + * R1660 (0x67C) - DSP1RMIX Input 3 Source + */ +#define WM2200_DSP1RMIX_SRC3_MASK 0x007F /* DSP1RMIX_SRC3 - [6:0] */ +#define WM2200_DSP1RMIX_SRC3_SHIFT 0 /* DSP1RMIX_SRC3 - [6:0] */ +#define WM2200_DSP1RMIX_SRC3_WIDTH 7 /* DSP1RMIX_SRC3 - [6:0] */ + +/* + * R1661 (0x67D) - DSP1RMIX Input 3 Volume + */ +#define WM2200_DSP1RMIX_VOL3_MASK 0x00FE /* DSP1RMIX_VOL3 - [7:1] */ +#define WM2200_DSP1RMIX_VOL3_SHIFT 1 /* DSP1RMIX_VOL3 - [7:1] */ +#define WM2200_DSP1RMIX_VOL3_WIDTH 7 /* DSP1RMIX_VOL3 - [7:1] */ + +/* + * R1662 (0x67E) - DSP1RMIX Input 4 Source + */ +#define WM2200_DSP1RMIX_SRC4_MASK 0x007F /* DSP1RMIX_SRC4 - [6:0] */ +#define WM2200_DSP1RMIX_SRC4_SHIFT 0 /* DSP1RMIX_SRC4 - [6:0] */ +#define WM2200_DSP1RMIX_SRC4_WIDTH 7 /* DSP1RMIX_SRC4 - [6:0] */ + +/* + * R1663 (0x67F) - DSP1RMIX Input 4 Volume + */ +#define WM2200_DSP1RMIX_VOL4_MASK 0x00FE /* DSP1RMIX_VOL4 - [7:1] */ +#define WM2200_DSP1RMIX_VOL4_SHIFT 1 /* DSP1RMIX_VOL4 - [7:1] */ +#define WM2200_DSP1RMIX_VOL4_WIDTH 7 /* DSP1RMIX_VOL4 - [7:1] */ + +/* + * R1664 (0x680) - DSP1AUX1MIX Input 1 Source + */ +#define WM2200_DSP1AUX1MIX_SRC1_MASK 0x007F /* DSP1AUX1MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX1MIX_SRC1_SHIFT 0 /* DSP1AUX1MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX1MIX_SRC1_WIDTH 7 /* DSP1AUX1MIX_SRC1 - [6:0] */ + +/* + * R1665 (0x681) - DSP1AUX2MIX Input 1 Source + */ +#define WM2200_DSP1AUX2MIX_SRC1_MASK 0x007F /* DSP1AUX2MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX2MIX_SRC1_SHIFT 0 /* DSP1AUX2MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX2MIX_SRC1_WIDTH 7 /* DSP1AUX2MIX_SRC1 - [6:0] */ + +/* + * R1666 (0x682) - DSP1AUX3MIX Input 1 Source + */ +#define WM2200_DSP1AUX3MIX_SRC1_MASK 0x007F /* DSP1AUX3MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX3MIX_SRC1_SHIFT 0 /* DSP1AUX3MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX3MIX_SRC1_WIDTH 7 /* DSP1AUX3MIX_SRC1 - [6:0] */ + +/* + * R1667 (0x683) - DSP1AUX4MIX Input 1 Source + */ +#define WM2200_DSP1AUX4MIX_SRC1_MASK 0x007F /* DSP1AUX4MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX4MIX_SRC1_SHIFT 0 /* DSP1AUX4MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX4MIX_SRC1_WIDTH 7 /* DSP1AUX4MIX_SRC1 - [6:0] */ + +/* + * R1668 (0x684) - DSP1AUX5MIX Input 1 Source + */ +#define WM2200_DSP1AUX5MIX_SRC1_MASK 0x007F /* DSP1AUX5MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX5MIX_SRC1_SHIFT 0 /* DSP1AUX5MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX5MIX_SRC1_WIDTH 7 /* DSP1AUX5MIX_SRC1 - [6:0] */ + +/* + * R1669 (0x685) - DSP1AUX6MIX Input 1 Source + */ +#define WM2200_DSP1AUX6MIX_SRC1_MASK 0x007F /* DSP1AUX6MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX6MIX_SRC1_SHIFT 0 /* DSP1AUX6MIX_SRC1 - [6:0] */ +#define WM2200_DSP1AUX6MIX_SRC1_WIDTH 7 /* DSP1AUX6MIX_SRC1 - [6:0] */ + +/* + * R1670 (0x686) - DSP2LMIX Input 1 Source + */ +#define WM2200_DSP2LMIX_SRC1_MASK 0x007F /* DSP2LMIX_SRC1 - [6:0] */ +#define WM2200_DSP2LMIX_SRC1_SHIFT 0 /* DSP2LMIX_SRC1 - [6:0] */ +#define WM2200_DSP2LMIX_SRC1_WIDTH 7 /* DSP2LMIX_SRC1 - [6:0] */ + +/* + * R1671 (0x687) - DSP2LMIX Input 1 Volume + */ +#define WM2200_DSP2LMIX_VOL1_MASK 0x00FE /* DSP2LMIX_VOL1 - [7:1] */ +#define WM2200_DSP2LMIX_VOL1_SHIFT 1 /* DSP2LMIX_VOL1 - [7:1] */ +#define WM2200_DSP2LMIX_VOL1_WIDTH 7 /* DSP2LMIX_VOL1 - [7:1] */ + +/* + * R1672 (0x688) - DSP2LMIX Input 2 Source + */ +#define WM2200_DSP2LMIX_SRC2_MASK 0x007F /* DSP2LMIX_SRC2 - [6:0] */ +#define WM2200_DSP2LMIX_SRC2_SHIFT 0 /* DSP2LMIX_SRC2 - [6:0] */ +#define WM2200_DSP2LMIX_SRC2_WIDTH 7 /* DSP2LMIX_SRC2 - [6:0] */ + +/* + * R1673 (0x689) - DSP2LMIX Input 2 Volume + */ +#define WM2200_DSP2LMIX_VOL2_MASK 0x00FE /* DSP2LMIX_VOL2 - [7:1] */ +#define WM2200_DSP2LMIX_VOL2_SHIFT 1 /* DSP2LMIX_VOL2 - [7:1] */ +#define WM2200_DSP2LMIX_VOL2_WIDTH 7 /* DSP2LMIX_VOL2 - [7:1] */ + +/* + * R1674 (0x68A) - DSP2LMIX Input 3 Source + */ +#define WM2200_DSP2LMIX_SRC3_MASK 0x007F /* DSP2LMIX_SRC3 - [6:0] */ +#define WM2200_DSP2LMIX_SRC3_SHIFT 0 /* DSP2LMIX_SRC3 - [6:0] */ +#define WM2200_DSP2LMIX_SRC3_WIDTH 7 /* DSP2LMIX_SRC3 - [6:0] */ + +/* + * R1675 (0x68B) - DSP2LMIX Input 3 Volume + */ +#define WM2200_DSP2LMIX_VOL3_MASK 0x00FE /* DSP2LMIX_VOL3 - [7:1] */ +#define WM2200_DSP2LMIX_VOL3_SHIFT 1 /* DSP2LMIX_VOL3 - [7:1] */ +#define WM2200_DSP2LMIX_VOL3_WIDTH 7 /* DSP2LMIX_VOL3 - [7:1] */ + +/* + * R1676 (0x68C) - DSP2LMIX Input 4 Source + */ +#define WM2200_DSP2LMIX_SRC4_MASK 0x007F /* DSP2LMIX_SRC4 - [6:0] */ +#define WM2200_DSP2LMIX_SRC4_SHIFT 0 /* DSP2LMIX_SRC4 - [6:0] */ +#define WM2200_DSP2LMIX_SRC4_WIDTH 7 /* DSP2LMIX_SRC4 - [6:0] */ + +/* + * R1677 (0x68D) - DSP2LMIX Input 4 Volume + */ +#define WM2200_DSP2LMIX_VOL4_MASK 0x00FE /* DSP2LMIX_VOL4 - [7:1] */ +#define WM2200_DSP2LMIX_VOL4_SHIFT 1 /* DSP2LMIX_VOL4 - [7:1] */ +#define WM2200_DSP2LMIX_VOL4_WIDTH 7 /* DSP2LMIX_VOL4 - [7:1] */ + +/* + * R1678 (0x68E) - DSP2RMIX Input 1 Source + */ +#define WM2200_DSP2RMIX_SRC1_MASK 0x007F /* DSP2RMIX_SRC1 - [6:0] */ +#define WM2200_DSP2RMIX_SRC1_SHIFT 0 /* DSP2RMIX_SRC1 - [6:0] */ +#define WM2200_DSP2RMIX_SRC1_WIDTH 7 /* DSP2RMIX_SRC1 - [6:0] */ + +/* + * R1679 (0x68F) - DSP2RMIX Input 1 Volume + */ +#define WM2200_DSP2RMIX_VOL1_MASK 0x00FE /* DSP2RMIX_VOL1 - [7:1] */ +#define WM2200_DSP2RMIX_VOL1_SHIFT 1 /* DSP2RMIX_VOL1 - [7:1] */ +#define WM2200_DSP2RMIX_VOL1_WIDTH 7 /* DSP2RMIX_VOL1 - [7:1] */ + +/* + * R1680 (0x690) - DSP2RMIX Input 2 Source + */ +#define WM2200_DSP2RMIX_SRC2_MASK 0x007F /* DSP2RMIX_SRC2 - [6:0] */ +#define WM2200_DSP2RMIX_SRC2_SHIFT 0 /* DSP2RMIX_SRC2 - [6:0] */ +#define WM2200_DSP2RMIX_SRC2_WIDTH 7 /* DSP2RMIX_SRC2 - [6:0] */ + +/* + * R1681 (0x691) - DSP2RMIX Input 2 Volume + */ +#define WM2200_DSP2RMIX_VOL2_MASK 0x00FE /* DSP2RMIX_VOL2 - [7:1] */ +#define WM2200_DSP2RMIX_VOL2_SHIFT 1 /* DSP2RMIX_VOL2 - [7:1] */ +#define WM2200_DSP2RMIX_VOL2_WIDTH 7 /* DSP2RMIX_VOL2 - [7:1] */ + +/* + * R1682 (0x692) - DSP2RMIX Input 3 Source + */ +#define WM2200_DSP2RMIX_SRC3_MASK 0x007F /* DSP2RMIX_SRC3 - [6:0] */ +#define WM2200_DSP2RMIX_SRC3_SHIFT 0 /* DSP2RMIX_SRC3 - [6:0] */ +#define WM2200_DSP2RMIX_SRC3_WIDTH 7 /* DSP2RMIX_SRC3 - [6:0] */ + +/* + * R1683 (0x693) - DSP2RMIX Input 3 Volume + */ +#define WM2200_DSP2RMIX_VOL3_MASK 0x00FE /* DSP2RMIX_VOL3 - [7:1] */ +#define WM2200_DSP2RMIX_VOL3_SHIFT 1 /* DSP2RMIX_VOL3 - [7:1] */ +#define WM2200_DSP2RMIX_VOL3_WIDTH 7 /* DSP2RMIX_VOL3 - [7:1] */ + +/* + * R1684 (0x694) - DSP2RMIX Input 4 Source + */ +#define WM2200_DSP2RMIX_SRC4_MASK 0x007F /* DSP2RMIX_SRC4 - [6:0] */ +#define WM2200_DSP2RMIX_SRC4_SHIFT 0 /* DSP2RMIX_SRC4 - [6:0] */ +#define WM2200_DSP2RMIX_SRC4_WIDTH 7 /* DSP2RMIX_SRC4 - [6:0] */ + +/* + * R1685 (0x695) - DSP2RMIX Input 4 Volume + */ +#define WM2200_DSP2RMIX_VOL4_MASK 0x00FE /* DSP2RMIX_VOL4 - [7:1] */ +#define WM2200_DSP2RMIX_VOL4_SHIFT 1 /* DSP2RMIX_VOL4 - [7:1] */ +#define WM2200_DSP2RMIX_VOL4_WIDTH 7 /* DSP2RMIX_VOL4 - [7:1] */ + +/* + * R1686 (0x696) - DSP2AUX1MIX Input 1 Source + */ +#define WM2200_DSP2AUX1MIX_SRC1_MASK 0x007F /* DSP2AUX1MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX1MIX_SRC1_SHIFT 0 /* DSP2AUX1MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX1MIX_SRC1_WIDTH 7 /* DSP2AUX1MIX_SRC1 - [6:0] */ + +/* + * R1687 (0x697) - DSP2AUX2MIX Input 1 Source + */ +#define WM2200_DSP2AUX2MIX_SRC1_MASK 0x007F /* DSP2AUX2MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX2MIX_SRC1_SHIFT 0 /* DSP2AUX2MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX2MIX_SRC1_WIDTH 7 /* DSP2AUX2MIX_SRC1 - [6:0] */ + +/* + * R1688 (0x698) - DSP2AUX3MIX Input 1 Source + */ +#define WM2200_DSP2AUX3MIX_SRC1_MASK 0x007F /* DSP2AUX3MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX3MIX_SRC1_SHIFT 0 /* DSP2AUX3MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX3MIX_SRC1_WIDTH 7 /* DSP2AUX3MIX_SRC1 - [6:0] */ + +/* + * R1689 (0x699) - DSP2AUX4MIX Input 1 Source + */ +#define WM2200_DSP2AUX4MIX_SRC1_MASK 0x007F /* DSP2AUX4MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX4MIX_SRC1_SHIFT 0 /* DSP2AUX4MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX4MIX_SRC1_WIDTH 7 /* DSP2AUX4MIX_SRC1 - [6:0] */ + +/* + * R1690 (0x69A) - DSP2AUX5MIX Input 1 Source + */ +#define WM2200_DSP2AUX5MIX_SRC1_MASK 0x007F /* DSP2AUX5MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX5MIX_SRC1_SHIFT 0 /* DSP2AUX5MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX5MIX_SRC1_WIDTH 7 /* DSP2AUX5MIX_SRC1 - [6:0] */ + +/* + * R1691 (0x69B) - DSP2AUX6MIX Input 1 Source + */ +#define WM2200_DSP2AUX6MIX_SRC1_MASK 0x007F /* DSP2AUX6MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX6MIX_SRC1_SHIFT 0 /* DSP2AUX6MIX_SRC1 - [6:0] */ +#define WM2200_DSP2AUX6MIX_SRC1_WIDTH 7 /* DSP2AUX6MIX_SRC1 - [6:0] */ + +/* + * R1792 (0x700) - GPIO CTRL 1 + */ +#define WM2200_GP1_DIR 0x8000 /* GP1_DIR */ +#define WM2200_GP1_DIR_MASK 0x8000 /* GP1_DIR */ +#define WM2200_GP1_DIR_SHIFT 15 /* GP1_DIR */ +#define WM2200_GP1_DIR_WIDTH 1 /* GP1_DIR */ +#define WM2200_GP1_PU 0x4000 /* GP1_PU */ +#define WM2200_GP1_PU_MASK 0x4000 /* GP1_PU */ +#define WM2200_GP1_PU_SHIFT 14 /* GP1_PU */ +#define WM2200_GP1_PU_WIDTH 1 /* GP1_PU */ +#define WM2200_GP1_PD 0x2000 /* GP1_PD */ +#define WM2200_GP1_PD_MASK 0x2000 /* GP1_PD */ +#define WM2200_GP1_PD_SHIFT 13 /* GP1_PD */ +#define WM2200_GP1_PD_WIDTH 1 /* GP1_PD */ +#define WM2200_GP1_POL 0x0400 /* GP1_POL */ +#define WM2200_GP1_POL_MASK 0x0400 /* GP1_POL */ +#define WM2200_GP1_POL_SHIFT 10 /* GP1_POL */ +#define WM2200_GP1_POL_WIDTH 1 /* GP1_POL */ +#define WM2200_GP1_OP_CFG 0x0200 /* GP1_OP_CFG */ +#define WM2200_GP1_OP_CFG_MASK 0x0200 /* GP1_OP_CFG */ +#define WM2200_GP1_OP_CFG_SHIFT 9 /* GP1_OP_CFG */ +#define WM2200_GP1_OP_CFG_WIDTH 1 /* GP1_OP_CFG */ +#define WM2200_GP1_DB 0x0100 /* GP1_DB */ +#define WM2200_GP1_DB_MASK 0x0100 /* GP1_DB */ +#define WM2200_GP1_DB_SHIFT 8 /* GP1_DB */ +#define WM2200_GP1_DB_WIDTH 1 /* GP1_DB */ +#define WM2200_GP1_LVL 0x0040 /* GP1_LVL */ +#define WM2200_GP1_LVL_MASK 0x0040 /* GP1_LVL */ +#define WM2200_GP1_LVL_SHIFT 6 /* GP1_LVL */ +#define WM2200_GP1_LVL_WIDTH 1 /* GP1_LVL */ +#define WM2200_GP1_FN_MASK 0x003F /* GP1_FN - [5:0] */ +#define WM2200_GP1_FN_SHIFT 0 /* GP1_FN - [5:0] */ +#define WM2200_GP1_FN_WIDTH 6 /* GP1_FN - [5:0] */ + +/* + * R1793 (0x701) - GPIO CTRL 2 + */ +#define WM2200_GP2_DIR 0x8000 /* GP2_DIR */ +#define WM2200_GP2_DIR_MASK 0x8000 /* GP2_DIR */ +#define WM2200_GP2_DIR_SHIFT 15 /* GP2_DIR */ +#define WM2200_GP2_DIR_WIDTH 1 /* GP2_DIR */ +#define WM2200_GP2_PU 0x4000 /* GP2_PU */ +#define WM2200_GP2_PU_MASK 0x4000 /* GP2_PU */ +#define WM2200_GP2_PU_SHIFT 14 /* GP2_PU */ +#define WM2200_GP2_PU_WIDTH 1 /* GP2_PU */ +#define WM2200_GP2_PD 0x2000 /* GP2_PD */ +#define WM2200_GP2_PD_MASK 0x2000 /* GP2_PD */ +#define WM2200_GP2_PD_SHIFT 13 /* GP2_PD */ +#define WM2200_GP2_PD_WIDTH 1 /* GP2_PD */ +#define WM2200_GP2_POL 0x0400 /* GP2_POL */ +#define WM2200_GP2_POL_MASK 0x0400 /* GP2_POL */ +#define WM2200_GP2_POL_SHIFT 10 /* GP2_POL */ +#define WM2200_GP2_POL_WIDTH 1 /* GP2_POL */ +#define WM2200_GP2_OP_CFG 0x0200 /* GP2_OP_CFG */ +#define WM2200_GP2_OP_CFG_MASK 0x0200 /* GP2_OP_CFG */ +#define WM2200_GP2_OP_CFG_SHIFT 9 /* GP2_OP_CFG */ +#define WM2200_GP2_OP_CFG_WIDTH 1 /* GP2_OP_CFG */ +#define WM2200_GP2_DB 0x0100 /* GP2_DB */ +#define WM2200_GP2_DB_MASK 0x0100 /* GP2_DB */ +#define WM2200_GP2_DB_SHIFT 8 /* GP2_DB */ +#define WM2200_GP2_DB_WIDTH 1 /* GP2_DB */ +#define WM2200_GP2_LVL 0x0040 /* GP2_LVL */ +#define WM2200_GP2_LVL_MASK 0x0040 /* GP2_LVL */ +#define WM2200_GP2_LVL_SHIFT 6 /* GP2_LVL */ +#define WM2200_GP2_LVL_WIDTH 1 /* GP2_LVL */ +#define WM2200_GP2_FN_MASK 0x003F /* GP2_FN - [5:0] */ +#define WM2200_GP2_FN_SHIFT 0 /* GP2_FN - [5:0] */ +#define WM2200_GP2_FN_WIDTH 6 /* GP2_FN - [5:0] */ + +/* + * R1794 (0x702) - GPIO CTRL 3 + */ +#define WM2200_GP3_DIR 0x8000 /* GP3_DIR */ +#define WM2200_GP3_DIR_MASK 0x8000 /* GP3_DIR */ +#define WM2200_GP3_DIR_SHIFT 15 /* GP3_DIR */ +#define WM2200_GP3_DIR_WIDTH 1 /* GP3_DIR */ +#define WM2200_GP3_PU 0x4000 /* GP3_PU */ +#define WM2200_GP3_PU_MASK 0x4000 /* GP3_PU */ +#define WM2200_GP3_PU_SHIFT 14 /* GP3_PU */ +#define WM2200_GP3_PU_WIDTH 1 /* GP3_PU */ +#define WM2200_GP3_PD 0x2000 /* GP3_PD */ +#define WM2200_GP3_PD_MASK 0x2000 /* GP3_PD */ +#define WM2200_GP3_PD_SHIFT 13 /* GP3_PD */ +#define WM2200_GP3_PD_WIDTH 1 /* GP3_PD */ +#define WM2200_GP3_POL 0x0400 /* GP3_POL */ +#define WM2200_GP3_POL_MASK 0x0400 /* GP3_POL */ +#define WM2200_GP3_POL_SHIFT 10 /* GP3_POL */ +#define WM2200_GP3_POL_WIDTH 1 /* GP3_POL */ +#define WM2200_GP3_OP_CFG 0x0200 /* GP3_OP_CFG */ +#define WM2200_GP3_OP_CFG_MASK 0x0200 /* GP3_OP_CFG */ +#define WM2200_GP3_OP_CFG_SHIFT 9 /* GP3_OP_CFG */ +#define WM2200_GP3_OP_CFG_WIDTH 1 /* GP3_OP_CFG */ +#define WM2200_GP3_DB 0x0100 /* GP3_DB */ +#define WM2200_GP3_DB_MASK 0x0100 /* GP3_DB */ +#define WM2200_GP3_DB_SHIFT 8 /* GP3_DB */ +#define WM2200_GP3_DB_WIDTH 1 /* GP3_DB */ +#define WM2200_GP3_LVL 0x0040 /* GP3_LVL */ +#define WM2200_GP3_LVL_MASK 0x0040 /* GP3_LVL */ +#define WM2200_GP3_LVL_SHIFT 6 /* GP3_LVL */ +#define WM2200_GP3_LVL_WIDTH 1 /* GP3_LVL */ +#define WM2200_GP3_FN_MASK 0x003F /* GP3_FN - [5:0] */ +#define WM2200_GP3_FN_SHIFT 0 /* GP3_FN - [5:0] */ +#define WM2200_GP3_FN_WIDTH 6 /* GP3_FN - [5:0] */ + +/* + * R1795 (0x703) - GPIO CTRL 4 + */ +#define WM2200_GP4_DIR 0x8000 /* GP4_DIR */ +#define WM2200_GP4_DIR_MASK 0x8000 /* GP4_DIR */ +#define WM2200_GP4_DIR_SHIFT 15 /* GP4_DIR */ +#define WM2200_GP4_DIR_WIDTH 1 /* GP4_DIR */ +#define WM2200_GP4_PU 0x4000 /* GP4_PU */ +#define WM2200_GP4_PU_MASK 0x4000 /* GP4_PU */ +#define WM2200_GP4_PU_SHIFT 14 /* GP4_PU */ +#define WM2200_GP4_PU_WIDTH 1 /* GP4_PU */ +#define WM2200_GP4_PD 0x2000 /* GP4_PD */ +#define WM2200_GP4_PD_MASK 0x2000 /* GP4_PD */ +#define WM2200_GP4_PD_SHIFT 13 /* GP4_PD */ +#define WM2200_GP4_PD_WIDTH 1 /* GP4_PD */ +#define WM2200_GP4_POL 0x0400 /* GP4_POL */ +#define WM2200_GP4_POL_MASK 0x0400 /* GP4_POL */ +#define WM2200_GP4_POL_SHIFT 10 /* GP4_POL */ +#define WM2200_GP4_POL_WIDTH 1 /* GP4_POL */ +#define WM2200_GP4_OP_CFG 0x0200 /* GP4_OP_CFG */ +#define WM2200_GP4_OP_CFG_MASK 0x0200 /* GP4_OP_CFG */ +#define WM2200_GP4_OP_CFG_SHIFT 9 /* GP4_OP_CFG */ +#define WM2200_GP4_OP_CFG_WIDTH 1 /* GP4_OP_CFG */ +#define WM2200_GP4_DB 0x0100 /* GP4_DB */ +#define WM2200_GP4_DB_MASK 0x0100 /* GP4_DB */ +#define WM2200_GP4_DB_SHIFT 8 /* GP4_DB */ +#define WM2200_GP4_DB_WIDTH 1 /* GP4_DB */ +#define WM2200_GP4_LVL 0x0040 /* GP4_LVL */ +#define WM2200_GP4_LVL_MASK 0x0040 /* GP4_LVL */ +#define WM2200_GP4_LVL_SHIFT 6 /* GP4_LVL */ +#define WM2200_GP4_LVL_WIDTH 1 /* GP4_LVL */ +#define WM2200_GP4_FN_MASK 0x003F /* GP4_FN - [5:0] */ +#define WM2200_GP4_FN_SHIFT 0 /* GP4_FN - [5:0] */ +#define WM2200_GP4_FN_WIDTH 6 /* GP4_FN - [5:0] */ + +/* + * R1799 (0x707) - ADPS1 IRQ0 + */ +#define WM2200_DSP_IRQ1 0x0002 /* DSP_IRQ1 */ +#define WM2200_DSP_IRQ1_MASK 0x0002 /* DSP_IRQ1 */ +#define WM2200_DSP_IRQ1_SHIFT 1 /* DSP_IRQ1 */ +#define WM2200_DSP_IRQ1_WIDTH 1 /* DSP_IRQ1 */ +#define WM2200_DSP_IRQ0 0x0001 /* DSP_IRQ0 */ +#define WM2200_DSP_IRQ0_MASK 0x0001 /* DSP_IRQ0 */ +#define WM2200_DSP_IRQ0_SHIFT 0 /* DSP_IRQ0 */ +#define WM2200_DSP_IRQ0_WIDTH 1 /* DSP_IRQ0 */ + +/* + * R1800 (0x708) - ADPS1 IRQ1 + */ +#define WM2200_DSP_IRQ3 0x0002 /* DSP_IRQ3 */ +#define WM2200_DSP_IRQ3_MASK 0x0002 /* DSP_IRQ3 */ +#define WM2200_DSP_IRQ3_SHIFT 1 /* DSP_IRQ3 */ +#define WM2200_DSP_IRQ3_WIDTH 1 /* DSP_IRQ3 */ +#define WM2200_DSP_IRQ2 0x0001 /* DSP_IRQ2 */ +#define WM2200_DSP_IRQ2_MASK 0x0001 /* DSP_IRQ2 */ +#define WM2200_DSP_IRQ2_SHIFT 0 /* DSP_IRQ2 */ +#define WM2200_DSP_IRQ2_WIDTH 1 /* DSP_IRQ2 */ + +/* + * R1801 (0x709) - Misc Pad Ctrl 1 + */ +#define WM2200_LDO1ENA_PD 0x8000 /* LDO1ENA_PD */ +#define WM2200_LDO1ENA_PD_MASK 0x8000 /* LDO1ENA_PD */ +#define WM2200_LDO1ENA_PD_SHIFT 15 /* LDO1ENA_PD */ +#define WM2200_LDO1ENA_PD_WIDTH 1 /* LDO1ENA_PD */ +#define WM2200_MCLK2_PD 0x2000 /* MCLK2_PD */ +#define WM2200_MCLK2_PD_MASK 0x2000 /* MCLK2_PD */ +#define WM2200_MCLK2_PD_SHIFT 13 /* MCLK2_PD */ +#define WM2200_MCLK2_PD_WIDTH 1 /* MCLK2_PD */ +#define WM2200_MCLK1_PD 0x1000 /* MCLK1_PD */ +#define WM2200_MCLK1_PD_MASK 0x1000 /* MCLK1_PD */ +#define WM2200_MCLK1_PD_SHIFT 12 /* MCLK1_PD */ +#define WM2200_MCLK1_PD_WIDTH 1 /* MCLK1_PD */ +#define WM2200_DACLRCLK1_PU 0x0400 /* DACLRCLK1_PU */ +#define WM2200_DACLRCLK1_PU_MASK 0x0400 /* DACLRCLK1_PU */ +#define WM2200_DACLRCLK1_PU_SHIFT 10 /* DACLRCLK1_PU */ +#define WM2200_DACLRCLK1_PU_WIDTH 1 /* DACLRCLK1_PU */ +#define WM2200_DACLRCLK1_PD 0x0200 /* DACLRCLK1_PD */ +#define WM2200_DACLRCLK1_PD_MASK 0x0200 /* DACLRCLK1_PD */ +#define WM2200_DACLRCLK1_PD_SHIFT 9 /* DACLRCLK1_PD */ +#define WM2200_DACLRCLK1_PD_WIDTH 1 /* DACLRCLK1_PD */ +#define WM2200_BCLK1_PU 0x0100 /* BCLK1_PU */ +#define WM2200_BCLK1_PU_MASK 0x0100 /* BCLK1_PU */ +#define WM2200_BCLK1_PU_SHIFT 8 /* BCLK1_PU */ +#define WM2200_BCLK1_PU_WIDTH 1 /* BCLK1_PU */ +#define WM2200_BCLK1_PD 0x0080 /* BCLK1_PD */ +#define WM2200_BCLK1_PD_MASK 0x0080 /* BCLK1_PD */ +#define WM2200_BCLK1_PD_SHIFT 7 /* BCLK1_PD */ +#define WM2200_BCLK1_PD_WIDTH 1 /* BCLK1_PD */ +#define WM2200_DACDAT1_PU 0x0040 /* DACDAT1_PU */ +#define WM2200_DACDAT1_PU_MASK 0x0040 /* DACDAT1_PU */ +#define WM2200_DACDAT1_PU_SHIFT 6 /* DACDAT1_PU */ +#define WM2200_DACDAT1_PU_WIDTH 1 /* DACDAT1_PU */ +#define WM2200_DACDAT1_PD 0x0020 /* DACDAT1_PD */ +#define WM2200_DACDAT1_PD_MASK 0x0020 /* DACDAT1_PD */ +#define WM2200_DACDAT1_PD_SHIFT 5 /* DACDAT1_PD */ +#define WM2200_DACDAT1_PD_WIDTH 1 /* DACDAT1_PD */ +#define WM2200_DMICDAT3_PD 0x0010 /* DMICDAT3_PD */ +#define WM2200_DMICDAT3_PD_MASK 0x0010 /* DMICDAT3_PD */ +#define WM2200_DMICDAT3_PD_SHIFT 4 /* DMICDAT3_PD */ +#define WM2200_DMICDAT3_PD_WIDTH 1 /* DMICDAT3_PD */ +#define WM2200_DMICDAT2_PD 0x0008 /* DMICDAT2_PD */ +#define WM2200_DMICDAT2_PD_MASK 0x0008 /* DMICDAT2_PD */ +#define WM2200_DMICDAT2_PD_SHIFT 3 /* DMICDAT2_PD */ +#define WM2200_DMICDAT2_PD_WIDTH 1 /* DMICDAT2_PD */ +#define WM2200_DMICDAT1_PD 0x0004 /* DMICDAT1_PD */ +#define WM2200_DMICDAT1_PD_MASK 0x0004 /* DMICDAT1_PD */ +#define WM2200_DMICDAT1_PD_SHIFT 2 /* DMICDAT1_PD */ +#define WM2200_DMICDAT1_PD_WIDTH 1 /* DMICDAT1_PD */ +#define WM2200_RSTB_PU 0x0002 /* RSTB_PU */ +#define WM2200_RSTB_PU_MASK 0x0002 /* RSTB_PU */ +#define WM2200_RSTB_PU_SHIFT 1 /* RSTB_PU */ +#define WM2200_RSTB_PU_WIDTH 1 /* RSTB_PU */ +#define WM2200_ADDR_PD 0x0001 /* ADDR_PD */ +#define WM2200_ADDR_PD_MASK 0x0001 /* ADDR_PD */ +#define WM2200_ADDR_PD_SHIFT 0 /* ADDR_PD */ +#define WM2200_ADDR_PD_WIDTH 1 /* ADDR_PD */ + +/* + * R2048 (0x800) - Interrupt Status 1 + */ +#define WM2200_DSP_IRQ0_EINT 0x0080 /* DSP_IRQ0_EINT */ +#define WM2200_DSP_IRQ0_EINT_MASK 0x0080 /* DSP_IRQ0_EINT */ +#define WM2200_DSP_IRQ0_EINT_SHIFT 7 /* DSP_IRQ0_EINT */ +#define WM2200_DSP_IRQ0_EINT_WIDTH 1 /* DSP_IRQ0_EINT */ +#define WM2200_DSP_IRQ1_EINT 0x0040 /* DSP_IRQ1_EINT */ +#define WM2200_DSP_IRQ1_EINT_MASK 0x0040 /* DSP_IRQ1_EINT */ +#define WM2200_DSP_IRQ1_EINT_SHIFT 6 /* DSP_IRQ1_EINT */ +#define WM2200_DSP_IRQ1_EINT_WIDTH 1 /* DSP_IRQ1_EINT */ +#define WM2200_DSP_IRQ2_EINT 0x0020 /* DSP_IRQ2_EINT */ +#define WM2200_DSP_IRQ2_EINT_MASK 0x0020 /* DSP_IRQ2_EINT */ +#define WM2200_DSP_IRQ2_EINT_SHIFT 5 /* DSP_IRQ2_EINT */ +#define WM2200_DSP_IRQ2_EINT_WIDTH 1 /* DSP_IRQ2_EINT */ +#define WM2200_DSP_IRQ3_EINT 0x0010 /* DSP_IRQ3_EINT */ +#define WM2200_DSP_IRQ3_EINT_MASK 0x0010 /* DSP_IRQ3_EINT */ +#define WM2200_DSP_IRQ3_EINT_SHIFT 4 /* DSP_IRQ3_EINT */ +#define WM2200_DSP_IRQ3_EINT_WIDTH 1 /* DSP_IRQ3_EINT */ +#define WM2200_GP4_EINT 0x0008 /* GP4_EINT */ +#define WM2200_GP4_EINT_MASK 0x0008 /* GP4_EINT */ +#define WM2200_GP4_EINT_SHIFT 3 /* GP4_EINT */ +#define WM2200_GP4_EINT_WIDTH 1 /* GP4_EINT */ +#define WM2200_GP3_EINT 0x0004 /* GP3_EINT */ +#define WM2200_GP3_EINT_MASK 0x0004 /* GP3_EINT */ +#define WM2200_GP3_EINT_SHIFT 2 /* GP3_EINT */ +#define WM2200_GP3_EINT_WIDTH 1 /* GP3_EINT */ +#define WM2200_GP2_EINT 0x0002 /* GP2_EINT */ +#define WM2200_GP2_EINT_MASK 0x0002 /* GP2_EINT */ +#define WM2200_GP2_EINT_SHIFT 1 /* GP2_EINT */ +#define WM2200_GP2_EINT_WIDTH 1 /* GP2_EINT */ +#define WM2200_GP1_EINT 0x0001 /* GP1_EINT */ +#define WM2200_GP1_EINT_MASK 0x0001 /* GP1_EINT */ +#define WM2200_GP1_EINT_SHIFT 0 /* GP1_EINT */ +#define WM2200_GP1_EINT_WIDTH 1 /* GP1_EINT */ + +/* + * R2049 (0x801) - Interrupt Status 1 Mask + */ +#define WM2200_IM_DSP_IRQ0_EINT 0x0080 /* IM_DSP_IRQ0_EINT */ +#define WM2200_IM_DSP_IRQ0_EINT_MASK 0x0080 /* IM_DSP_IRQ0_EINT */ +#define WM2200_IM_DSP_IRQ0_EINT_SHIFT 7 /* IM_DSP_IRQ0_EINT */ +#define WM2200_IM_DSP_IRQ0_EINT_WIDTH 1 /* IM_DSP_IRQ0_EINT */ +#define WM2200_IM_DSP_IRQ1_EINT 0x0040 /* IM_DSP_IRQ1_EINT */ +#define WM2200_IM_DSP_IRQ1_EINT_MASK 0x0040 /* IM_DSP_IRQ1_EINT */ +#define WM2200_IM_DSP_IRQ1_EINT_SHIFT 6 /* IM_DSP_IRQ1_EINT */ +#define WM2200_IM_DSP_IRQ1_EINT_WIDTH 1 /* IM_DSP_IRQ1_EINT */ +#define WM2200_IM_DSP_IRQ2_EINT 0x0020 /* IM_DSP_IRQ2_EINT */ +#define WM2200_IM_DSP_IRQ2_EINT_MASK 0x0020 /* IM_DSP_IRQ2_EINT */ +#define WM2200_IM_DSP_IRQ2_EINT_SHIFT 5 /* IM_DSP_IRQ2_EINT */ +#define WM2200_IM_DSP_IRQ2_EINT_WIDTH 1 /* IM_DSP_IRQ2_EINT */ +#define WM2200_IM_DSP_IRQ3_EINT 0x0010 /* IM_DSP_IRQ3_EINT */ +#define WM2200_IM_DSP_IRQ3_EINT_MASK 0x0010 /* IM_DSP_IRQ3_EINT */ +#define WM2200_IM_DSP_IRQ3_EINT_SHIFT 4 /* IM_DSP_IRQ3_EINT */ +#define WM2200_IM_DSP_IRQ3_EINT_WIDTH 1 /* IM_DSP_IRQ3_EINT */ +#define WM2200_IM_GP4_EINT 0x0008 /* IM_GP4_EINT */ +#define WM2200_IM_GP4_EINT_MASK 0x0008 /* IM_GP4_EINT */ +#define WM2200_IM_GP4_EINT_SHIFT 3 /* IM_GP4_EINT */ +#define WM2200_IM_GP4_EINT_WIDTH 1 /* IM_GP4_EINT */ +#define WM2200_IM_GP3_EINT 0x0004 /* IM_GP3_EINT */ +#define WM2200_IM_GP3_EINT_MASK 0x0004 /* IM_GP3_EINT */ +#define WM2200_IM_GP3_EINT_SHIFT 2 /* IM_GP3_EINT */ +#define WM2200_IM_GP3_EINT_WIDTH 1 /* IM_GP3_EINT */ +#define WM2200_IM_GP2_EINT 0x0002 /* IM_GP2_EINT */ +#define WM2200_IM_GP2_EINT_MASK 0x0002 /* IM_GP2_EINT */ +#define WM2200_IM_GP2_EINT_SHIFT 1 /* IM_GP2_EINT */ +#define WM2200_IM_GP2_EINT_WIDTH 1 /* IM_GP2_EINT */ +#define WM2200_IM_GP1_EINT 0x0001 /* IM_GP1_EINT */ +#define WM2200_IM_GP1_EINT_MASK 0x0001 /* IM_GP1_EINT */ +#define WM2200_IM_GP1_EINT_SHIFT 0 /* IM_GP1_EINT */ +#define WM2200_IM_GP1_EINT_WIDTH 1 /* IM_GP1_EINT */ + +/* + * R2050 (0x802) - Interrupt Status 2 + */ +#define WM2200_WSEQ_BUSY_EINT 0x0100 /* WSEQ_BUSY_EINT */ +#define WM2200_WSEQ_BUSY_EINT_MASK 0x0100 /* WSEQ_BUSY_EINT */ +#define WM2200_WSEQ_BUSY_EINT_SHIFT 8 /* WSEQ_BUSY_EINT */ +#define WM2200_WSEQ_BUSY_EINT_WIDTH 1 /* WSEQ_BUSY_EINT */ +#define WM2200_FLL_LOCK_EINT 0x0002 /* FLL_LOCK_EINT */ +#define WM2200_FLL_LOCK_EINT_MASK 0x0002 /* FLL_LOCK_EINT */ +#define WM2200_FLL_LOCK_EINT_SHIFT 1 /* FLL_LOCK_EINT */ +#define WM2200_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */ +#define WM2200_CLKGEN_EINT 0x0001 /* CLKGEN_EINT */ +#define WM2200_CLKGEN_EINT_MASK 0x0001 /* CLKGEN_EINT */ +#define WM2200_CLKGEN_EINT_SHIFT 0 /* CLKGEN_EINT */ +#define WM2200_CLKGEN_EINT_WIDTH 1 /* CLKGEN_EINT */ + +/* + * R2051 (0x803) - Interrupt Raw Status 2 + */ +#define WM2200_WSEQ_BUSY_STS 0x0100 /* WSEQ_BUSY_STS */ +#define WM2200_WSEQ_BUSY_STS_MASK 0x0100 /* WSEQ_BUSY_STS */ +#define WM2200_WSEQ_BUSY_STS_SHIFT 8 /* WSEQ_BUSY_STS */ +#define WM2200_WSEQ_BUSY_STS_WIDTH 1 /* WSEQ_BUSY_STS */ +#define WM2200_FLL_LOCK_STS 0x0002 /* FLL_LOCK_STS */ +#define WM2200_FLL_LOCK_STS_MASK 0x0002 /* FLL_LOCK_STS */ +#define WM2200_FLL_LOCK_STS_SHIFT 1 /* FLL_LOCK_STS */ +#define WM2200_FLL_LOCK_STS_WIDTH 1 /* FLL_LOCK_STS */ +#define WM2200_CLKGEN_STS 0x0001 /* CLKGEN_STS */ +#define WM2200_CLKGEN_STS_MASK 0x0001 /* CLKGEN_STS */ +#define WM2200_CLKGEN_STS_SHIFT 0 /* CLKGEN_STS */ +#define WM2200_CLKGEN_STS_WIDTH 1 /* CLKGEN_STS */ + +/* + * R2052 (0x804) - Interrupt Status 2 Mask + */ +#define WM2200_IM_WSEQ_BUSY_EINT 0x0100 /* IM_WSEQ_BUSY_EINT */ +#define WM2200_IM_WSEQ_BUSY_EINT_MASK 0x0100 /* IM_WSEQ_BUSY_EINT */ +#define WM2200_IM_WSEQ_BUSY_EINT_SHIFT 8 /* IM_WSEQ_BUSY_EINT */ +#define WM2200_IM_WSEQ_BUSY_EINT_WIDTH 1 /* IM_WSEQ_BUSY_EINT */ +#define WM2200_IM_FLL_LOCK_EINT 0x0002 /* IM_FLL_LOCK_EINT */ +#define WM2200_IM_FLL_LOCK_EINT_MASK 0x0002 /* IM_FLL_LOCK_EINT */ +#define WM2200_IM_FLL_LOCK_EINT_SHIFT 1 /* IM_FLL_LOCK_EINT */ +#define WM2200_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */ +#define WM2200_IM_CLKGEN_EINT 0x0001 /* IM_CLKGEN_EINT */ +#define WM2200_IM_CLKGEN_EINT_MASK 0x0001 /* IM_CLKGEN_EINT */ +#define WM2200_IM_CLKGEN_EINT_SHIFT 0 /* IM_CLKGEN_EINT */ +#define WM2200_IM_CLKGEN_EINT_WIDTH 1 /* IM_CLKGEN_EINT */ + +/* + * R2056 (0x808) - Interrupt Control + */ +#define WM2200_IM_IRQ 0x0001 /* IM_IRQ */ +#define WM2200_IM_IRQ_MASK 0x0001 /* IM_IRQ */ +#define WM2200_IM_IRQ_SHIFT 0 /* IM_IRQ */ +#define WM2200_IM_IRQ_WIDTH 1 /* IM_IRQ */ + +/* + * R2304 (0x900) - EQL_1 + */ +#define WM2200_EQL_B1_GAIN_MASK 0xF800 /* EQL_B1_GAIN - [15:11] */ +#define WM2200_EQL_B1_GAIN_SHIFT 11 /* EQL_B1_GAIN - [15:11] */ +#define WM2200_EQL_B1_GAIN_WIDTH 5 /* EQL_B1_GAIN - [15:11] */ +#define WM2200_EQL_B2_GAIN_MASK 0x07C0 /* EQL_B2_GAIN - [10:6] */ +#define WM2200_EQL_B2_GAIN_SHIFT 6 /* EQL_B2_GAIN - [10:6] */ +#define WM2200_EQL_B2_GAIN_WIDTH 5 /* EQL_B2_GAIN - [10:6] */ +#define WM2200_EQL_B3_GAIN_MASK 0x003E /* EQL_B3_GAIN - [5:1] */ +#define WM2200_EQL_B3_GAIN_SHIFT 1 /* EQL_B3_GAIN - [5:1] */ +#define WM2200_EQL_B3_GAIN_WIDTH 5 /* EQL_B3_GAIN - [5:1] */ +#define WM2200_EQL_ENA 0x0001 /* EQL_ENA */ +#define WM2200_EQL_ENA_MASK 0x0001 /* EQL_ENA */ +#define WM2200_EQL_ENA_SHIFT 0 /* EQL_ENA */ +#define WM2200_EQL_ENA_WIDTH 1 /* EQL_ENA */ + +/* + * R2305 (0x901) - EQL_2 + */ +#define WM2200_EQL_B4_GAIN_MASK 0xF800 /* EQL_B4_GAIN - [15:11] */ +#define WM2200_EQL_B4_GAIN_SHIFT 11 /* EQL_B4_GAIN - [15:11] */ +#define WM2200_EQL_B4_GAIN_WIDTH 5 /* EQL_B4_GAIN - [15:11] */ +#define WM2200_EQL_B5_GAIN_MASK 0x07C0 /* EQL_B5_GAIN - [10:6] */ +#define WM2200_EQL_B5_GAIN_SHIFT 6 /* EQL_B5_GAIN - [10:6] */ +#define WM2200_EQL_B5_GAIN_WIDTH 5 /* EQL_B5_GAIN - [10:6] */ + +/* + * R2306 (0x902) - EQL_3 + */ +#define WM2200_EQL_B1_A_MASK 0xFFFF /* EQL_B1_A - [15:0] */ +#define WM2200_EQL_B1_A_SHIFT 0 /* EQL_B1_A - [15:0] */ +#define WM2200_EQL_B1_A_WIDTH 16 /* EQL_B1_A - [15:0] */ + +/* + * R2307 (0x903) - EQL_4 + */ +#define WM2200_EQL_B1_B_MASK 0xFFFF /* EQL_B1_B - [15:0] */ +#define WM2200_EQL_B1_B_SHIFT 0 /* EQL_B1_B - [15:0] */ +#define WM2200_EQL_B1_B_WIDTH 16 /* EQL_B1_B - [15:0] */ + +/* + * R2308 (0x904) - EQL_5 + */ +#define WM2200_EQL_B1_PG_MASK 0xFFFF /* EQL_B1_PG - [15:0] */ +#define WM2200_EQL_B1_PG_SHIFT 0 /* EQL_B1_PG - [15:0] */ +#define WM2200_EQL_B1_PG_WIDTH 16 /* EQL_B1_PG - [15:0] */ + +/* + * R2309 (0x905) - EQL_6 + */ +#define WM2200_EQL_B2_A_MASK 0xFFFF /* EQL_B2_A - [15:0] */ +#define WM2200_EQL_B2_A_SHIFT 0 /* EQL_B2_A - [15:0] */ +#define WM2200_EQL_B2_A_WIDTH 16 /* EQL_B2_A - [15:0] */ + +/* + * R2310 (0x906) - EQL_7 + */ +#define WM2200_EQL_B2_B_MASK 0xFFFF /* EQL_B2_B - [15:0] */ +#define WM2200_EQL_B2_B_SHIFT 0 /* EQL_B2_B - [15:0] */ +#define WM2200_EQL_B2_B_WIDTH 16 /* EQL_B2_B - [15:0] */ + +/* + * R2311 (0x907) - EQL_8 + */ +#define WM2200_EQL_B2_C_MASK 0xFFFF /* EQL_B2_C - [15:0] */ +#define WM2200_EQL_B2_C_SHIFT 0 /* EQL_B2_C - [15:0] */ +#define WM2200_EQL_B2_C_WIDTH 16 /* EQL_B2_C - [15:0] */ + +/* + * R2312 (0x908) - EQL_9 + */ +#define WM2200_EQL_B2_PG_MASK 0xFFFF /* EQL_B2_PG - [15:0] */ +#define WM2200_EQL_B2_PG_SHIFT 0 /* EQL_B2_PG - [15:0] */ +#define WM2200_EQL_B2_PG_WIDTH 16 /* EQL_B2_PG - [15:0] */ + +/* + * R2313 (0x909) - EQL_10 + */ +#define WM2200_EQL_B3_A_MASK 0xFFFF /* EQL_B3_A - [15:0] */ +#define WM2200_EQL_B3_A_SHIFT 0 /* EQL_B3_A - [15:0] */ +#define WM2200_EQL_B3_A_WIDTH 16 /* EQL_B3_A - [15:0] */ + +/* + * R2314 (0x90A) - EQL_11 + */ +#define WM2200_EQL_B3_B_MASK 0xFFFF /* EQL_B3_B - [15:0] */ +#define WM2200_EQL_B3_B_SHIFT 0 /* EQL_B3_B - [15:0] */ +#define WM2200_EQL_B3_B_WIDTH 16 /* EQL_B3_B - [15:0] */ + +/* + * R2315 (0x90B) - EQL_12 + */ +#define WM2200_EQL_B3_C_MASK 0xFFFF /* EQL_B3_C - [15:0] */ +#define WM2200_EQL_B3_C_SHIFT 0 /* EQL_B3_C - [15:0] */ +#define WM2200_EQL_B3_C_WIDTH 16 /* EQL_B3_C - [15:0] */ + +/* + * R2316 (0x90C) - EQL_13 + */ +#define WM2200_EQL_B3_PG_MASK 0xFFFF /* EQL_B3_PG - [15:0] */ +#define WM2200_EQL_B3_PG_SHIFT 0 /* EQL_B3_PG - [15:0] */ +#define WM2200_EQL_B3_PG_WIDTH 16 /* EQL_B3_PG - [15:0] */ + +/* + * R2317 (0x90D) - EQL_14 + */ +#define WM2200_EQL_B4_A_MASK 0xFFFF /* EQL_B4_A - [15:0] */ +#define WM2200_EQL_B4_A_SHIFT 0 /* EQL_B4_A - [15:0] */ +#define WM2200_EQL_B4_A_WIDTH 16 /* EQL_B4_A - [15:0] */ + +/* + * R2318 (0x90E) - EQL_15 + */ +#define WM2200_EQL_B4_B_MASK 0xFFFF /* EQL_B4_B - [15:0] */ +#define WM2200_EQL_B4_B_SHIFT 0 /* EQL_B4_B - [15:0] */ +#define WM2200_EQL_B4_B_WIDTH 16 /* EQL_B4_B - [15:0] */ + +/* + * R2319 (0x90F) - EQL_16 + */ +#define WM2200_EQL_B4_C_MASK 0xFFFF /* EQL_B4_C - [15:0] */ +#define WM2200_EQL_B4_C_SHIFT 0 /* EQL_B4_C - [15:0] */ +#define WM2200_EQL_B4_C_WIDTH 16 /* EQL_B4_C - [15:0] */ + +/* + * R2320 (0x910) - EQL_17 + */ +#define WM2200_EQL_B4_PG_MASK 0xFFFF /* EQL_B4_PG - [15:0] */ +#define WM2200_EQL_B4_PG_SHIFT 0 /* EQL_B4_PG - [15:0] */ +#define WM2200_EQL_B4_PG_WIDTH 16 /* EQL_B4_PG - [15:0] */ + +/* + * R2321 (0x911) - EQL_18 + */ +#define WM2200_EQL_B5_A_MASK 0xFFFF /* EQL_B5_A - [15:0] */ +#define WM2200_EQL_B5_A_SHIFT 0 /* EQL_B5_A - [15:0] */ +#define WM2200_EQL_B5_A_WIDTH 16 /* EQL_B5_A - [15:0] */ + +/* + * R2322 (0x912) - EQL_19 + */ +#define WM2200_EQL_B5_B_MASK 0xFFFF /* EQL_B5_B - [15:0] */ +#define WM2200_EQL_B5_B_SHIFT 0 /* EQL_B5_B - [15:0] */ +#define WM2200_EQL_B5_B_WIDTH 16 /* EQL_B5_B - [15:0] */ + +/* + * R2323 (0x913) - EQL_20 + */ +#define WM2200_EQL_B5_PG_MASK 0xFFFF /* EQL_B5_PG - [15:0] */ +#define WM2200_EQL_B5_PG_SHIFT 0 /* EQL_B5_PG - [15:0] */ +#define WM2200_EQL_B5_PG_WIDTH 16 /* EQL_B5_PG - [15:0] */ + +/* + * R2326 (0x916) - EQR_1 + */ +#define WM2200_EQR_B1_GAIN_MASK 0xF800 /* EQR_B1_GAIN - [15:11] */ +#define WM2200_EQR_B1_GAIN_SHIFT 11 /* EQR_B1_GAIN - [15:11] */ +#define WM2200_EQR_B1_GAIN_WIDTH 5 /* EQR_B1_GAIN - [15:11] */ +#define WM2200_EQR_B2_GAIN_MASK 0x07C0 /* EQR_B2_GAIN - [10:6] */ +#define WM2200_EQR_B2_GAIN_SHIFT 6 /* EQR_B2_GAIN - [10:6] */ +#define WM2200_EQR_B2_GAIN_WIDTH 5 /* EQR_B2_GAIN - [10:6] */ +#define WM2200_EQR_B3_GAIN_MASK 0x003E /* EQR_B3_GAIN - [5:1] */ +#define WM2200_EQR_B3_GAIN_SHIFT 1 /* EQR_B3_GAIN - [5:1] */ +#define WM2200_EQR_B3_GAIN_WIDTH 5 /* EQR_B3_GAIN - [5:1] */ +#define WM2200_EQR_ENA 0x0001 /* EQR_ENA */ +#define WM2200_EQR_ENA_MASK 0x0001 /* EQR_ENA */ +#define WM2200_EQR_ENA_SHIFT 0 /* EQR_ENA */ +#define WM2200_EQR_ENA_WIDTH 1 /* EQR_ENA */ + +/* + * R2327 (0x917) - EQR_2 + */ +#define WM2200_EQR_B4_GAIN_MASK 0xF800 /* EQR_B4_GAIN - [15:11] */ +#define WM2200_EQR_B4_GAIN_SHIFT 11 /* EQR_B4_GAIN - [15:11] */ +#define WM2200_EQR_B4_GAIN_WIDTH 5 /* EQR_B4_GAIN - [15:11] */ +#define WM2200_EQR_B5_GAIN_MASK 0x07C0 /* EQR_B5_GAIN - [10:6] */ +#define WM2200_EQR_B5_GAIN_SHIFT 6 /* EQR_B5_GAIN - [10:6] */ +#define WM2200_EQR_B5_GAIN_WIDTH 5 /* EQR_B5_GAIN - [10:6] */ + +/* + * R2328 (0x918) - EQR_3 + */ +#define WM2200_EQR_B1_A_MASK 0xFFFF /* EQR_B1_A - [15:0] */ +#define WM2200_EQR_B1_A_SHIFT 0 /* EQR_B1_A - [15:0] */ +#define WM2200_EQR_B1_A_WIDTH 16 /* EQR_B1_A - [15:0] */ + +/* + * R2329 (0x919) - EQR_4 + */ +#define WM2200_EQR_B1_B_MASK 0xFFFF /* EQR_B1_B - [15:0] */ +#define WM2200_EQR_B1_B_SHIFT 0 /* EQR_B1_B - [15:0] */ +#define WM2200_EQR_B1_B_WIDTH 16 /* EQR_B1_B - [15:0] */ + +/* + * R2330 (0x91A) - EQR_5 + */ +#define WM2200_EQR_B1_PG_MASK 0xFFFF /* EQR_B1_PG - [15:0] */ +#define WM2200_EQR_B1_PG_SHIFT 0 /* EQR_B1_PG - [15:0] */ +#define WM2200_EQR_B1_PG_WIDTH 16 /* EQR_B1_PG - [15:0] */ + +/* + * R2331 (0x91B) - EQR_6 + */ +#define WM2200_EQR_B2_A_MASK 0xFFFF /* EQR_B2_A - [15:0] */ +#define WM2200_EQR_B2_A_SHIFT 0 /* EQR_B2_A - [15:0] */ +#define WM2200_EQR_B2_A_WIDTH 16 /* EQR_B2_A - [15:0] */ + +/* + * R2332 (0x91C) - EQR_7 + */ +#define WM2200_EQR_B2_B_MASK 0xFFFF /* EQR_B2_B - [15:0] */ +#define WM2200_EQR_B2_B_SHIFT 0 /* EQR_B2_B - [15:0] */ +#define WM2200_EQR_B2_B_WIDTH 16 /* EQR_B2_B - [15:0] */ + +/* + * R2333 (0x91D) - EQR_8 + */ +#define WM2200_EQR_B2_C_MASK 0xFFFF /* EQR_B2_C - [15:0] */ +#define WM2200_EQR_B2_C_SHIFT 0 /* EQR_B2_C - [15:0] */ +#define WM2200_EQR_B2_C_WIDTH 16 /* EQR_B2_C - [15:0] */ + +/* + * R2334 (0x91E) - EQR_9 + */ +#define WM2200_EQR_B2_PG_MASK 0xFFFF /* EQR_B2_PG - [15:0] */ +#define WM2200_EQR_B2_PG_SHIFT 0 /* EQR_B2_PG - [15:0] */ +#define WM2200_EQR_B2_PG_WIDTH 16 /* EQR_B2_PG - [15:0] */ + +/* + * R2335 (0x91F) - EQR_10 + */ +#define WM2200_EQR_B3_A_MASK 0xFFFF /* EQR_B3_A - [15:0] */ +#define WM2200_EQR_B3_A_SHIFT 0 /* EQR_B3_A - [15:0] */ +#define WM2200_EQR_B3_A_WIDTH 16 /* EQR_B3_A - [15:0] */ + +/* + * R2336 (0x920) - EQR_11 + */ +#define WM2200_EQR_B3_B_MASK 0xFFFF /* EQR_B3_B - [15:0] */ +#define WM2200_EQR_B3_B_SHIFT 0 /* EQR_B3_B - [15:0] */ +#define WM2200_EQR_B3_B_WIDTH 16 /* EQR_B3_B - [15:0] */ + +/* + * R2337 (0x921) - EQR_12 + */ +#define WM2200_EQR_B3_C_MASK 0xFFFF /* EQR_B3_C - [15:0] */ +#define WM2200_EQR_B3_C_SHIFT 0 /* EQR_B3_C - [15:0] */ +#define WM2200_EQR_B3_C_WIDTH 16 /* EQR_B3_C - [15:0] */ + +/* + * R2338 (0x922) - EQR_13 + */ +#define WM2200_EQR_B3_PG_MASK 0xFFFF /* EQR_B3_PG - [15:0] */ +#define WM2200_EQR_B3_PG_SHIFT 0 /* EQR_B3_PG - [15:0] */ +#define WM2200_EQR_B3_PG_WIDTH 16 /* EQR_B3_PG - [15:0] */ + +/* + * R2339 (0x923) - EQR_14 + */ +#define WM2200_EQR_B4_A_MASK 0xFFFF /* EQR_B4_A - [15:0] */ +#define WM2200_EQR_B4_A_SHIFT 0 /* EQR_B4_A - [15:0] */ +#define WM2200_EQR_B4_A_WIDTH 16 /* EQR_B4_A - [15:0] */ + +/* + * R2340 (0x924) - EQR_15 + */ +#define WM2200_EQR_B4_B_MASK 0xFFFF /* EQR_B4_B - [15:0] */ +#define WM2200_EQR_B4_B_SHIFT 0 /* EQR_B4_B - [15:0] */ +#define WM2200_EQR_B4_B_WIDTH 16 /* EQR_B4_B - [15:0] */ + +/* + * R2341 (0x925) - EQR_16 + */ +#define WM2200_EQR_B4_C_MASK 0xFFFF /* EQR_B4_C - [15:0] */ +#define WM2200_EQR_B4_C_SHIFT 0 /* EQR_B4_C - [15:0] */ +#define WM2200_EQR_B4_C_WIDTH 16 /* EQR_B4_C - [15:0] */ + +/* + * R2342 (0x926) - EQR_17 + */ +#define WM2200_EQR_B4_PG_MASK 0xFFFF /* EQR_B4_PG - [15:0] */ +#define WM2200_EQR_B4_PG_SHIFT 0 /* EQR_B4_PG - [15:0] */ +#define WM2200_EQR_B4_PG_WIDTH 16 /* EQR_B4_PG - [15:0] */ + +/* + * R2343 (0x927) - EQR_18 + */ +#define WM2200_EQR_B5_A_MASK 0xFFFF /* EQR_B5_A - [15:0] */ +#define WM2200_EQR_B5_A_SHIFT 0 /* EQR_B5_A - [15:0] */ +#define WM2200_EQR_B5_A_WIDTH 16 /* EQR_B5_A - [15:0] */ + +/* + * R2344 (0x928) - EQR_19 + */ +#define WM2200_EQR_B5_B_MASK 0xFFFF /* EQR_B5_B - [15:0] */ +#define WM2200_EQR_B5_B_SHIFT 0 /* EQR_B5_B - [15:0] */ +#define WM2200_EQR_B5_B_WIDTH 16 /* EQR_B5_B - [15:0] */ + +/* + * R2345 (0x929) - EQR_20 + */ +#define WM2200_EQR_B5_PG_MASK 0xFFFF /* EQR_B5_PG - [15:0] */ +#define WM2200_EQR_B5_PG_SHIFT 0 /* EQR_B5_PG - [15:0] */ +#define WM2200_EQR_B5_PG_WIDTH 16 /* EQR_B5_PG - [15:0] */ + +/* + * R2366 (0x93E) - HPLPF1_1 + */ +#define WM2200_LHPF1_MODE 0x0002 /* LHPF1_MODE */ +#define WM2200_LHPF1_MODE_MASK 0x0002 /* LHPF1_MODE */ +#define WM2200_LHPF1_MODE_SHIFT 1 /* LHPF1_MODE */ +#define WM2200_LHPF1_MODE_WIDTH 1 /* LHPF1_MODE */ +#define WM2200_LHPF1_ENA 0x0001 /* LHPF1_ENA */ +#define WM2200_LHPF1_ENA_MASK 0x0001 /* LHPF1_ENA */ +#define WM2200_LHPF1_ENA_SHIFT 0 /* LHPF1_ENA */ +#define WM2200_LHPF1_ENA_WIDTH 1 /* LHPF1_ENA */ + +/* + * R2367 (0x93F) - HPLPF1_2 + */ +#define WM2200_LHPF1_COEFF_MASK 0xFFFF /* LHPF1_COEFF - [15:0] */ +#define WM2200_LHPF1_COEFF_SHIFT 0 /* LHPF1_COEFF - [15:0] */ +#define WM2200_LHPF1_COEFF_WIDTH 16 /* LHPF1_COEFF - [15:0] */ + +/* + * R2370 (0x942) - HPLPF2_1 + */ +#define WM2200_LHPF2_MODE 0x0002 /* LHPF2_MODE */ +#define WM2200_LHPF2_MODE_MASK 0x0002 /* LHPF2_MODE */ +#define WM2200_LHPF2_MODE_SHIFT 1 /* LHPF2_MODE */ +#define WM2200_LHPF2_MODE_WIDTH 1 /* LHPF2_MODE */ +#define WM2200_LHPF2_ENA 0x0001 /* LHPF2_ENA */ +#define WM2200_LHPF2_ENA_MASK 0x0001 /* LHPF2_ENA */ +#define WM2200_LHPF2_ENA_SHIFT 0 /* LHPF2_ENA */ +#define WM2200_LHPF2_ENA_WIDTH 1 /* LHPF2_ENA */ + +/* + * R2371 (0x943) - HPLPF2_2 + */ +#define WM2200_LHPF2_COEFF_MASK 0xFFFF /* LHPF2_COEFF - [15:0] */ +#define WM2200_LHPF2_COEFF_SHIFT 0 /* LHPF2_COEFF - [15:0] */ +#define WM2200_LHPF2_COEFF_WIDTH 16 /* LHPF2_COEFF - [15:0] */ + +/* + * R2560 (0xA00) - DSP1 Control 1 + */ +#define WM2200_DSP1_RW_SEQUENCE_ENA 0x0001 /* DSP1_RW_SEQUENCE_ENA */ +#define WM2200_DSP1_RW_SEQUENCE_ENA_MASK 0x0001 /* DSP1_RW_SEQUENCE_ENA */ +#define WM2200_DSP1_RW_SEQUENCE_ENA_SHIFT 0 /* DSP1_RW_SEQUENCE_ENA */ +#define WM2200_DSP1_RW_SEQUENCE_ENA_WIDTH 1 /* DSP1_RW_SEQUENCE_ENA */ + +/* + * R2562 (0xA02) - DSP1 Control 2 + */ +#define WM2200_DSP1_PAGE_BASE_PM_0_MASK 0xFF00 /* DSP1_PAGE_BASE_PM - [15:8] */ +#define WM2200_DSP1_PAGE_BASE_PM_0_SHIFT 8 /* DSP1_PAGE_BASE_PM - [15:8] */ +#define WM2200_DSP1_PAGE_BASE_PM_0_WIDTH 8 /* DSP1_PAGE_BASE_PM - [15:8] */ + +/* + * R2563 (0xA03) - DSP1 Control 3 + */ +#define WM2200_DSP1_PAGE_BASE_DM_0_MASK 0xFF00 /* DSP1_PAGE_BASE_DM - [15:8] */ +#define WM2200_DSP1_PAGE_BASE_DM_0_SHIFT 8 /* DSP1_PAGE_BASE_DM - [15:8] */ +#define WM2200_DSP1_PAGE_BASE_DM_0_WIDTH 8 /* DSP1_PAGE_BASE_DM - [15:8] */ + +/* + * R2564 (0xA04) - DSP1 Control 4 + */ +#define WM2200_DSP1_PAGE_BASE_ZM_0_MASK 0xFF00 /* DSP1_PAGE_BASE_ZM - [15:8] */ +#define WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT 8 /* DSP1_PAGE_BASE_ZM - [15:8] */ +#define WM2200_DSP1_PAGE_BASE_ZM_0_WIDTH 8 /* DSP1_PAGE_BASE_ZM - [15:8] */ + +/* + * R2566 (0xA06) - DSP1 Control 5 + */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_MASK 0x3FFF /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_SHIFT 0 /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_WIDTH 14 /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */ + +/* + * R2567 (0xA07) - DSP1 Control 6 + */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_MASK 0x3FFF /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_SHIFT 0 /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_WIDTH 14 /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */ + +/* + * R2568 (0xA08) - DSP1 Control 7 + */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_MASK 0x3FFF /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_SHIFT 0 /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_WIDTH 14 /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */ + +/* + * R2569 (0xA09) - DSP1 Control 8 + */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_MASK 0x3FFF /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_SHIFT 0 /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_WIDTH 14 /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */ + +/* + * R2570 (0xA0A) - DSP1 Control 9 + */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_MASK 0x3FFF /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_SHIFT 0 /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_WIDTH 14 /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */ + +/* + * R2571 (0xA0B) - DSP1 Control 10 + */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_MASK 0x3FFF /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_SHIFT 0 /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_WIDTH 14 /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */ + +/* + * R2572 (0xA0C) - DSP1 Control 11 + */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_MASK 0x3FFF /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_SHIFT 0 /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_WIDTH 14 /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */ + +/* + * R2573 (0xA0D) - DSP1 Control 12 + */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_MASK 0x3FFF /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_SHIFT 0 /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_WIDTH 14 /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */ + +/* + * R2575 (0xA0F) - DSP1 Control 13 + */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_MASK 0x3FFF /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_SHIFT 0 /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_WIDTH 14 /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */ + +/* + * R2576 (0xA10) - DSP1 Control 14 + */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_MASK 0x3FFF /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_SHIFT 0 /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_WIDTH 14 /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */ + +/* + * R2577 (0xA11) - DSP1 Control 15 + */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_MASK 0x3FFF /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_SHIFT 0 /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_WIDTH 14 /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */ + +/* + * R2578 (0xA12) - DSP1 Control 16 + */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_MASK 0x3FFF /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_SHIFT 0 /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_WIDTH 14 /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */ + +/* + * R2579 (0xA13) - DSP1 Control 17 + */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_MASK 0x3FFF /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_SHIFT 0 /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_WIDTH 14 /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */ + +/* + * R2580 (0xA14) - DSP1 Control 18 + */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_MASK 0x3FFF /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_SHIFT 0 /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */ +#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_WIDTH 14 /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */ + +/* + * R2582 (0xA16) - DSP1 Control 19 + */ +#define WM2200_DSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ +#define WM2200_DSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ +#define WM2200_DSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ + +/* + * R2583 (0xA17) - DSP1 Control 20 + */ +#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_MASK 0x00FF /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */ +#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_SHIFT 0 /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */ +#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_WIDTH 8 /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */ + +/* + * R2584 (0xA18) - DSP1 Control 21 + */ +#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_MASK 0x003F /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */ +#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_SHIFT 0 /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */ +#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_WIDTH 6 /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */ + +/* + * R2586 (0xA1A) - DSP1 Control 22 + */ +#define WM2200_DSP1_DM_SIZE_MASK 0xFFFF /* DSP1_DM_SIZE - [15:0] */ +#define WM2200_DSP1_DM_SIZE_SHIFT 0 /* DSP1_DM_SIZE - [15:0] */ +#define WM2200_DSP1_DM_SIZE_WIDTH 16 /* DSP1_DM_SIZE - [15:0] */ + +/* + * R2587 (0xA1B) - DSP1 Control 23 + */ +#define WM2200_DSP1_PM_SIZE_MASK 0xFFFF /* DSP1_PM_SIZE - [15:0] */ +#define WM2200_DSP1_PM_SIZE_SHIFT 0 /* DSP1_PM_SIZE - [15:0] */ +#define WM2200_DSP1_PM_SIZE_WIDTH 16 /* DSP1_PM_SIZE - [15:0] */ + +/* + * R2588 (0xA1C) - DSP1 Control 24 + */ +#define WM2200_DSP1_ZM_SIZE_MASK 0xFFFF /* DSP1_ZM_SIZE - [15:0] */ +#define WM2200_DSP1_ZM_SIZE_SHIFT 0 /* DSP1_ZM_SIZE - [15:0] */ +#define WM2200_DSP1_ZM_SIZE_WIDTH 16 /* DSP1_ZM_SIZE - [15:0] */ + +/* + * R2590 (0xA1E) - DSP1 Control 25 + */ +#define WM2200_DSP1_PING_FULL 0x8000 /* DSP1_PING_FULL */ +#define WM2200_DSP1_PING_FULL_MASK 0x8000 /* DSP1_PING_FULL */ +#define WM2200_DSP1_PING_FULL_SHIFT 15 /* DSP1_PING_FULL */ +#define WM2200_DSP1_PING_FULL_WIDTH 1 /* DSP1_PING_FULL */ +#define WM2200_DSP1_PONG_FULL 0x4000 /* DSP1_PONG_FULL */ +#define WM2200_DSP1_PONG_FULL_MASK 0x4000 /* DSP1_PONG_FULL */ +#define WM2200_DSP1_PONG_FULL_SHIFT 14 /* DSP1_PONG_FULL */ +#define WM2200_DSP1_PONG_FULL_WIDTH 1 /* DSP1_PONG_FULL */ +#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_MASK 0x00FF /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */ +#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_SHIFT 0 /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */ +#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_WIDTH 8 /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */ + +/* + * R2592 (0xA20) - DSP1 Control 26 + */ +#define WM2200_DSP1_SCRATCH_0_MASK 0xFFFF /* DSP1_SCRATCH_0 - [15:0] */ +#define WM2200_DSP1_SCRATCH_0_SHIFT 0 /* DSP1_SCRATCH_0 - [15:0] */ +#define WM2200_DSP1_SCRATCH_0_WIDTH 16 /* DSP1_SCRATCH_0 - [15:0] */ + +/* + * R2593 (0xA21) - DSP1 Control 27 + */ +#define WM2200_DSP1_SCRATCH_1_MASK 0xFFFF /* DSP1_SCRATCH_1 - [15:0] */ +#define WM2200_DSP1_SCRATCH_1_SHIFT 0 /* DSP1_SCRATCH_1 - [15:0] */ +#define WM2200_DSP1_SCRATCH_1_WIDTH 16 /* DSP1_SCRATCH_1 - [15:0] */ + +/* + * R2594 (0xA22) - DSP1 Control 28 + */ +#define WM2200_DSP1_SCRATCH_2_MASK 0xFFFF /* DSP1_SCRATCH_2 - [15:0] */ +#define WM2200_DSP1_SCRATCH_2_SHIFT 0 /* DSP1_SCRATCH_2 - [15:0] */ +#define WM2200_DSP1_SCRATCH_2_WIDTH 16 /* DSP1_SCRATCH_2 - [15:0] */ + +/* + * R2595 (0xA23) - DSP1 Control 29 + */ +#define WM2200_DSP1_SCRATCH_3_MASK 0xFFFF /* DSP1_SCRATCH_3 - [15:0] */ +#define WM2200_DSP1_SCRATCH_3_SHIFT 0 /* DSP1_SCRATCH_3 - [15:0] */ +#define WM2200_DSP1_SCRATCH_3_WIDTH 16 /* DSP1_SCRATCH_3 - [15:0] */ + +/* + * R2596 (0xA24) - DSP1 Control 30 + */ +#define WM2200_DSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */ +#define WM2200_DSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */ +#define WM2200_DSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */ +#define WM2200_DSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */ +#define WM2200_DSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ +#define WM2200_DSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ +#define WM2200_DSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ +#define WM2200_DSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ +#define WM2200_DSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ +#define WM2200_DSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ +#define WM2200_DSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ +#define WM2200_DSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ +#define WM2200_DSP1_START 0x0001 /* DSP1_START */ +#define WM2200_DSP1_START_MASK 0x0001 /* DSP1_START */ +#define WM2200_DSP1_START_SHIFT 0 /* DSP1_START */ +#define WM2200_DSP1_START_WIDTH 1 /* DSP1_START */ + +/* + * R2598 (0xA26) - DSP1 Control 31 + */ +#define WM2200_DSP1_CLK_RATE_MASK 0x0018 /* DSP1_CLK_RATE - [4:3] */ +#define WM2200_DSP1_CLK_RATE_SHIFT 3 /* DSP1_CLK_RATE - [4:3] */ +#define WM2200_DSP1_CLK_RATE_WIDTH 2 /* DSP1_CLK_RATE - [4:3] */ +#define WM2200_DSP1_CLK_AVAIL 0x0004 /* DSP1_CLK_AVAIL */ +#define WM2200_DSP1_CLK_AVAIL_MASK 0x0004 /* DSP1_CLK_AVAIL */ +#define WM2200_DSP1_CLK_AVAIL_SHIFT 2 /* DSP1_CLK_AVAIL */ +#define WM2200_DSP1_CLK_AVAIL_WIDTH 1 /* DSP1_CLK_AVAIL */ +#define WM2200_DSP1_CLK_REQ_MASK 0x0003 /* DSP1_CLK_REQ - [1:0] */ +#define WM2200_DSP1_CLK_REQ_SHIFT 0 /* DSP1_CLK_REQ - [1:0] */ +#define WM2200_DSP1_CLK_REQ_WIDTH 2 /* DSP1_CLK_REQ - [1:0] */ + +/* + * R2816 (0xB00) - DSP2 Control 1 + */ +#define WM2200_DSP2_RW_SEQUENCE_ENA 0x0001 /* DSP2_RW_SEQUENCE_ENA */ +#define WM2200_DSP2_RW_SEQUENCE_ENA_MASK 0x0001 /* DSP2_RW_SEQUENCE_ENA */ +#define WM2200_DSP2_RW_SEQUENCE_ENA_SHIFT 0 /* DSP2_RW_SEQUENCE_ENA */ +#define WM2200_DSP2_RW_SEQUENCE_ENA_WIDTH 1 /* DSP2_RW_SEQUENCE_ENA */ + +/* + * R2818 (0xB02) - DSP2 Control 2 + */ +#define WM2200_DSP2_PAGE_BASE_PM_0_MASK 0xFF00 /* DSP2_PAGE_BASE_PM - [15:8] */ +#define WM2200_DSP2_PAGE_BASE_PM_0_SHIFT 8 /* DSP2_PAGE_BASE_PM - [15:8] */ +#define WM2200_DSP2_PAGE_BASE_PM_0_WIDTH 8 /* DSP2_PAGE_BASE_PM - [15:8] */ + +/* + * R2819 (0xB03) - DSP2 Control 3 + */ +#define WM2200_DSP2_PAGE_BASE_DM_0_MASK 0xFF00 /* DSP2_PAGE_BASE_DM - [15:8] */ +#define WM2200_DSP2_PAGE_BASE_DM_0_SHIFT 8 /* DSP2_PAGE_BASE_DM - [15:8] */ +#define WM2200_DSP2_PAGE_BASE_DM_0_WIDTH 8 /* DSP2_PAGE_BASE_DM - [15:8] */ + +/* + * R2820 (0xB04) - DSP2 Control 4 + */ +#define WM2200_DSP2_PAGE_BASE_ZM_0_MASK 0xFF00 /* DSP2_PAGE_BASE_ZM - [15:8] */ +#define WM2200_DSP2_PAGE_BASE_ZM_0_SHIFT 8 /* DSP2_PAGE_BASE_ZM - [15:8] */ +#define WM2200_DSP2_PAGE_BASE_ZM_0_WIDTH 8 /* DSP2_PAGE_BASE_ZM - [15:8] */ + +/* + * R2822 (0xB06) - DSP2 Control 5 + */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_MASK 0x3FFF /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_SHIFT 0 /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_WIDTH 14 /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */ + +/* + * R2823 (0xB07) - DSP2 Control 6 + */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_MASK 0x3FFF /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_SHIFT 0 /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_WIDTH 14 /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */ + +/* + * R2824 (0xB08) - DSP2 Control 7 + */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_MASK 0x3FFF /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_SHIFT 0 /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_WIDTH 14 /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */ + +/* + * R2825 (0xB09) - DSP2 Control 8 + */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_MASK 0x3FFF /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_SHIFT 0 /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_WIDTH 14 /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */ + +/* + * R2826 (0xB0A) - DSP2 Control 9 + */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_MASK 0x3FFF /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_SHIFT 0 /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_WIDTH 14 /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */ + +/* + * R2827 (0xB0B) - DSP2 Control 10 + */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_MASK 0x3FFF /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_SHIFT 0 /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_WIDTH 14 /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */ + +/* + * R2828 (0xB0C) - DSP2 Control 11 + */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_MASK 0x3FFF /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_SHIFT 0 /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_WIDTH 14 /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */ + +/* + * R2829 (0xB0D) - DSP2 Control 12 + */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_MASK 0x3FFF /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_SHIFT 0 /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_WIDTH 14 /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */ + +/* + * R2831 (0xB0F) - DSP2 Control 13 + */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_MASK 0x3FFF /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_SHIFT 0 /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_WIDTH 14 /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */ + +/* + * R2832 (0xB10) - DSP2 Control 14 + */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_MASK 0x3FFF /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_SHIFT 0 /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_WIDTH 14 /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */ + +/* + * R2833 (0xB11) - DSP2 Control 15 + */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_MASK 0x3FFF /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_SHIFT 0 /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_WIDTH 14 /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */ + +/* + * R2834 (0xB12) - DSP2 Control 16 + */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_MASK 0x3FFF /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_SHIFT 0 /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_WIDTH 14 /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */ + +/* + * R2835 (0xB13) - DSP2 Control 17 + */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_MASK 0x3FFF /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_SHIFT 0 /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_WIDTH 14 /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */ + +/* + * R2836 (0xB14) - DSP2 Control 18 + */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_MASK 0x3FFF /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_SHIFT 0 /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */ +#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_WIDTH 14 /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */ + +/* + * R2838 (0xB16) - DSP2 Control 19 + */ +#define WM2200_DSP2_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */ +#define WM2200_DSP2_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */ +#define WM2200_DSP2_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */ + +/* + * R2839 (0xB17) - DSP2 Control 20 + */ +#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_MASK 0x00FF /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */ +#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_SHIFT 0 /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */ +#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_WIDTH 8 /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */ + +/* + * R2840 (0xB18) - DSP2 Control 21 + */ +#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_MASK 0x003F /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */ +#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_SHIFT 0 /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */ +#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_WIDTH 6 /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */ + +/* + * R2842 (0xB1A) - DSP2 Control 22 + */ +#define WM2200_DSP2_DM_SIZE_MASK 0xFFFF /* DSP2_DM_SIZE - [15:0] */ +#define WM2200_DSP2_DM_SIZE_SHIFT 0 /* DSP2_DM_SIZE - [15:0] */ +#define WM2200_DSP2_DM_SIZE_WIDTH 16 /* DSP2_DM_SIZE - [15:0] */ + +/* + * R2843 (0xB1B) - DSP2 Control 23 + */ +#define WM2200_DSP2_PM_SIZE_MASK 0xFFFF /* DSP2_PM_SIZE - [15:0] */ +#define WM2200_DSP2_PM_SIZE_SHIFT 0 /* DSP2_PM_SIZE - [15:0] */ +#define WM2200_DSP2_PM_SIZE_WIDTH 16 /* DSP2_PM_SIZE - [15:0] */ + +/* + * R2844 (0xB1C) - DSP2 Control 24 + */ +#define WM2200_DSP2_ZM_SIZE_MASK 0xFFFF /* DSP2_ZM_SIZE - [15:0] */ +#define WM2200_DSP2_ZM_SIZE_SHIFT 0 /* DSP2_ZM_SIZE - [15:0] */ +#define WM2200_DSP2_ZM_SIZE_WIDTH 16 /* DSP2_ZM_SIZE - [15:0] */ + +/* + * R2846 (0xB1E) - DSP2 Control 25 + */ +#define WM2200_DSP2_PING_FULL 0x8000 /* DSP2_PING_FULL */ +#define WM2200_DSP2_PING_FULL_MASK 0x8000 /* DSP2_PING_FULL */ +#define WM2200_DSP2_PING_FULL_SHIFT 15 /* DSP2_PING_FULL */ +#define WM2200_DSP2_PING_FULL_WIDTH 1 /* DSP2_PING_FULL */ +#define WM2200_DSP2_PONG_FULL 0x4000 /* DSP2_PONG_FULL */ +#define WM2200_DSP2_PONG_FULL_MASK 0x4000 /* DSP2_PONG_FULL */ +#define WM2200_DSP2_PONG_FULL_SHIFT 14 /* DSP2_PONG_FULL */ +#define WM2200_DSP2_PONG_FULL_WIDTH 1 /* DSP2_PONG_FULL */ +#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_MASK 0x00FF /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */ +#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_SHIFT 0 /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */ +#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_WIDTH 8 /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */ + +/* + * R2848 (0xB20) - DSP2 Control 26 + */ +#define WM2200_DSP2_SCRATCH_0_MASK 0xFFFF /* DSP2_SCRATCH_0 - [15:0] */ +#define WM2200_DSP2_SCRATCH_0_SHIFT 0 /* DSP2_SCRATCH_0 - [15:0] */ +#define WM2200_DSP2_SCRATCH_0_WIDTH 16 /* DSP2_SCRATCH_0 - [15:0] */ + +/* + * R2849 (0xB21) - DSP2 Control 27 + */ +#define WM2200_DSP2_SCRATCH_1_MASK 0xFFFF /* DSP2_SCRATCH_1 - [15:0] */ +#define WM2200_DSP2_SCRATCH_1_SHIFT 0 /* DSP2_SCRATCH_1 - [15:0] */ +#define WM2200_DSP2_SCRATCH_1_WIDTH 16 /* DSP2_SCRATCH_1 - [15:0] */ + +/* + * R2850 (0xB22) - DSP2 Control 28 + */ +#define WM2200_DSP2_SCRATCH_2_MASK 0xFFFF /* DSP2_SCRATCH_2 - [15:0] */ +#define WM2200_DSP2_SCRATCH_2_SHIFT 0 /* DSP2_SCRATCH_2 - [15:0] */ +#define WM2200_DSP2_SCRATCH_2_WIDTH 16 /* DSP2_SCRATCH_2 - [15:0] */ + +/* + * R2851 (0xB23) - DSP2 Control 29 + */ +#define WM2200_DSP2_SCRATCH_3_MASK 0xFFFF /* DSP2_SCRATCH_3 - [15:0] */ +#define WM2200_DSP2_SCRATCH_3_SHIFT 0 /* DSP2_SCRATCH_3 - [15:0] */ +#define WM2200_DSP2_SCRATCH_3_WIDTH 16 /* DSP2_SCRATCH_3 - [15:0] */ + +/* + * R2852 (0xB24) - DSP2 Control 30 + */ +#define WM2200_DSP2_DBG_CLK_ENA 0x0008 /* DSP2_DBG_CLK_ENA */ +#define WM2200_DSP2_DBG_CLK_ENA_MASK 0x0008 /* DSP2_DBG_CLK_ENA */ +#define WM2200_DSP2_DBG_CLK_ENA_SHIFT 3 /* DSP2_DBG_CLK_ENA */ +#define WM2200_DSP2_DBG_CLK_ENA_WIDTH 1 /* DSP2_DBG_CLK_ENA */ +#define WM2200_DSP2_SYS_ENA 0x0004 /* DSP2_SYS_ENA */ +#define WM2200_DSP2_SYS_ENA_MASK 0x0004 /* DSP2_SYS_ENA */ +#define WM2200_DSP2_SYS_ENA_SHIFT 2 /* DSP2_SYS_ENA */ +#define WM2200_DSP2_SYS_ENA_WIDTH 1 /* DSP2_SYS_ENA */ +#define WM2200_DSP2_CORE_ENA 0x0002 /* DSP2_CORE_ENA */ +#define WM2200_DSP2_CORE_ENA_MASK 0x0002 /* DSP2_CORE_ENA */ +#define WM2200_DSP2_CORE_ENA_SHIFT 1 /* DSP2_CORE_ENA */ +#define WM2200_DSP2_CORE_ENA_WIDTH 1 /* DSP2_CORE_ENA */ +#define WM2200_DSP2_START 0x0001 /* DSP2_START */ +#define WM2200_DSP2_START_MASK 0x0001 /* DSP2_START */ +#define WM2200_DSP2_START_SHIFT 0 /* DSP2_START */ +#define WM2200_DSP2_START_WIDTH 1 /* DSP2_START */ + +/* + * R2854 (0xB26) - DSP2 Control 31 + */ +#define WM2200_DSP2_CLK_RATE_MASK 0x0018 /* DSP2_CLK_RATE - [4:3] */ +#define WM2200_DSP2_CLK_RATE_SHIFT 3 /* DSP2_CLK_RATE - [4:3] */ +#define WM2200_DSP2_CLK_RATE_WIDTH 2 /* DSP2_CLK_RATE - [4:3] */ +#define WM2200_DSP2_CLK_AVAIL 0x0004 /* DSP2_CLK_AVAIL */ +#define WM2200_DSP2_CLK_AVAIL_MASK 0x0004 /* DSP2_CLK_AVAIL */ +#define WM2200_DSP2_CLK_AVAIL_SHIFT 2 /* DSP2_CLK_AVAIL */ +#define WM2200_DSP2_CLK_AVAIL_WIDTH 1 /* DSP2_CLK_AVAIL */ +#define WM2200_DSP2_CLK_REQ_MASK 0x0003 /* DSP2_CLK_REQ - [1:0] */ +#define WM2200_DSP2_CLK_REQ_SHIFT 0 /* DSP2_CLK_REQ - [1:0] */ +#define WM2200_DSP2_CLK_REQ_WIDTH 2 /* DSP2_CLK_REQ - [1:0] */ + +#endif diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 89f2af77b1c..b9c185ce64e 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -18,6 +18,7 @@ #include <linux/gcd.h> #include <linux/gpio.h> #include <linux/i2c.h> +#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/regulator/fixed.h> #include <linux/slab.h> @@ -50,13 +51,11 @@ struct wm5100_fll { /* codec private data */ struct wm5100_priv { + struct device *dev; struct regmap *regmap; struct snd_soc_codec *codec; struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES]; - struct regulator *cpvdd; - struct regulator *dbvdd2; - struct regulator *dbvdd3; int rev; @@ -73,6 +72,7 @@ struct wm5100_priv { bool jack_detecting; bool jack_mic; int jack_mode; + int jack_flips; struct wm5100_fll fll[2]; @@ -709,6 +709,8 @@ WM5100_MIXER_CONTROLS("EQ4", WM5100_EQ4MIX_INPUT_1_SOURCE), WM5100_MIXER_CONTROLS("DRC1L", WM5100_DRC1LMIX_INPUT_1_SOURCE), WM5100_MIXER_CONTROLS("DRC1R", WM5100_DRC1RMIX_INPUT_1_SOURCE), +SND_SOC_BYTES_MASK("DRC", WM5100_DRC1_CTRL1, 5, + WM5100_DRCL_ENA | WM5100_DRCR_ENA), WM5100_MIXER_CONTROLS("LHPF1", WM5100_HPLP1MIX_INPUT_1_SOURCE), WM5100_MIXER_CONTROLS("LHPF2", WM5100_HPLP2MIX_INPUT_1_SOURCE), @@ -776,127 +778,48 @@ static int wm5100_out_ev(struct snd_soc_dapm_widget *w, return 0; } -static int wm5100_cp_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_codec *codec = w->codec; - struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); - int ret; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - ret = regulator_enable(wm5100->cpvdd); - if (ret != 0) { - dev_err(codec->dev, "Failed to enable CPVDD: %d\n", - ret); - return ret; - } - return ret; - - case SND_SOC_DAPM_POST_PMD: - ret = regulator_disable_deferred(wm5100->cpvdd, 20); - if (ret != 0) { - dev_err(codec->dev, "Failed to disable CPVDD: %d\n", - ret); - return ret; - } - return ret; - - default: - BUG(); - return 0; - } -} - -static int wm5100_dbvdd_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_codec *codec = w->codec; - struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); - struct regulator *regulator; - int ret; - - switch (w->shift) { - case 2: - regulator = wm5100->dbvdd2; - break; - case 3: - regulator = wm5100->dbvdd3; - break; - default: - BUG(); - return 0; - } - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - ret = regulator_enable(regulator); - if (ret != 0) { - dev_err(codec->dev, "Failed to enable DBVDD%d: %d\n", - w->shift, ret); - return ret; - } - return ret; - - case SND_SOC_DAPM_POST_PMD: - ret = regulator_disable(regulator); - if (ret != 0) { - dev_err(codec->dev, "Failed to enable DBVDD%d: %d\n", - w->shift, ret); - return ret; - } - return ret; - - default: - BUG(); - return 0; - } -} - -static void wm5100_log_status3(struct snd_soc_codec *codec, int val) +static void wm5100_log_status3(struct wm5100_priv *wm5100, int val) { if (val & WM5100_SPK_SHUTDOWN_WARN_EINT) - dev_crit(codec->dev, "Speaker shutdown warning\n"); + dev_crit(wm5100->dev, "Speaker shutdown warning\n"); if (val & WM5100_SPK_SHUTDOWN_EINT) - dev_crit(codec->dev, "Speaker shutdown\n"); + dev_crit(wm5100->dev, "Speaker shutdown\n"); if (val & WM5100_CLKGEN_ERR_EINT) - dev_crit(codec->dev, "SYSCLK underclocked\n"); + dev_crit(wm5100->dev, "SYSCLK underclocked\n"); if (val & WM5100_CLKGEN_ERR_ASYNC_EINT) - dev_crit(codec->dev, "ASYNCCLK underclocked\n"); + dev_crit(wm5100->dev, "ASYNCCLK underclocked\n"); } -static void wm5100_log_status4(struct snd_soc_codec *codec, int val) +static void wm5100_log_status4(struct wm5100_priv *wm5100, int val) { if (val & WM5100_AIF3_ERR_EINT) - dev_err(codec->dev, "AIF3 configuration error\n"); + dev_err(wm5100->dev, "AIF3 configuration error\n"); if (val & WM5100_AIF2_ERR_EINT) - dev_err(codec->dev, "AIF2 configuration error\n"); + dev_err(wm5100->dev, "AIF2 configuration error\n"); if (val & WM5100_AIF1_ERR_EINT) - dev_err(codec->dev, "AIF1 configuration error\n"); + dev_err(wm5100->dev, "AIF1 configuration error\n"); if (val & WM5100_CTRLIF_ERR_EINT) - dev_err(codec->dev, "Control interface error\n"); + dev_err(wm5100->dev, "Control interface error\n"); if (val & WM5100_ISRC2_UNDERCLOCKED_EINT) - dev_err(codec->dev, "ISRC2 underclocked\n"); + dev_err(wm5100->dev, "ISRC2 underclocked\n"); if (val & WM5100_ISRC1_UNDERCLOCKED_EINT) - dev_err(codec->dev, "ISRC1 underclocked\n"); + dev_err(wm5100->dev, "ISRC1 underclocked\n"); if (val & WM5100_FX_UNDERCLOCKED_EINT) - dev_err(codec->dev, "FX underclocked\n"); + dev_err(wm5100->dev, "FX underclocked\n"); if (val & WM5100_AIF3_UNDERCLOCKED_EINT) - dev_err(codec->dev, "AIF3 underclocked\n"); + dev_err(wm5100->dev, "AIF3 underclocked\n"); if (val & WM5100_AIF2_UNDERCLOCKED_EINT) - dev_err(codec->dev, "AIF2 underclocked\n"); + dev_err(wm5100->dev, "AIF2 underclocked\n"); if (val & WM5100_AIF1_UNDERCLOCKED_EINT) - dev_err(codec->dev, "AIF1 underclocked\n"); + dev_err(wm5100->dev, "AIF1 underclocked\n"); if (val & WM5100_ASRC_UNDERCLOCKED_EINT) - dev_err(codec->dev, "ASRC underclocked\n"); + dev_err(wm5100->dev, "ASRC underclocked\n"); if (val & WM5100_DAC_UNDERCLOCKED_EINT) - dev_err(codec->dev, "DAC underclocked\n"); + dev_err(wm5100->dev, "DAC underclocked\n"); if (val & WM5100_ADC_UNDERCLOCKED_EINT) - dev_err(codec->dev, "ADC underclocked\n"); + dev_err(wm5100->dev, "ADC underclocked\n"); if (val & WM5100_MIXER_UNDERCLOCKED_EINT) - dev_err(codec->dev, "Mixer underclocked\n"); + dev_err(wm5100->dev, "Mixer underclocked\n"); } static int wm5100_post_ev(struct snd_soc_dapm_widget *w, @@ -904,16 +827,17 @@ static int wm5100_post_ev(struct snd_soc_dapm_widget *w, int event) { struct snd_soc_codec *codec = w->codec; + struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); int ret; ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_3); ret &= WM5100_SPK_SHUTDOWN_WARN_STS | WM5100_SPK_SHUTDOWN_STS | WM5100_CLKGEN_ERR_STS | WM5100_CLKGEN_ERR_ASYNC_STS; - wm5100_log_status3(codec, ret); + wm5100_log_status3(wm5100, ret); ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_4); - wm5100_log_status4(codec, ret); + wm5100_log_status4(wm5100, ret); return 0; } @@ -924,18 +848,16 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", WM5100_CLOCKING_3, WM5100_SYSCLK_ENA_SHIFT, 0, SND_SOC_DAPM_SUPPLY("ASYNCCLK", WM5100_CLOCKING_6, WM5100_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), +SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0), + SND_SOC_DAPM_SUPPLY("CP1", WM5100_HP_CHARGE_PUMP_1, WM5100_CP1_ENA_SHIFT, 0, - wm5100_cp_ev, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + NULL, 0), SND_SOC_DAPM_SUPPLY("CP2", WM5100_MIC_CHARGE_PUMP_1, WM5100_CP2_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("CP2 Active", WM5100_MIC_CHARGE_PUMP_1, - WM5100_CP2_BYPASS_SHIFT, 1, wm5100_cp_ev, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), -SND_SOC_DAPM_SUPPLY("DBVDD2", SND_SOC_NOPM, 2, 0, wm5100_dbvdd_ev, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), -SND_SOC_DAPM_SUPPLY("DBVDD3", SND_SOC_NOPM, 3, 0, wm5100_dbvdd_ev, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + WM5100_CP2_BYPASS_SHIFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", WM5100_MIC_BIAS_CTRL_1, WM5100_MICB1_ENA_SHIFT, 0, NULL, 0), @@ -1146,6 +1068,9 @@ SND_SOC_DAPM_POST("Post", wm5100_post_ev), }; static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { + { "CP1", NULL, "CPVDD" }, + { "CP2 Active", NULL, "CPVDD" }, + { "IN1L", NULL, "SYSCLK" }, { "IN1R", NULL, "SYSCLK" }, { "IN2L", NULL, "SYSCLK" }, @@ -1308,10 +1233,7 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { { "PWM2", NULL, "PWM2 Driver" }, }; -static struct { - int reg; - int val; -} wm5100_reva_patches[] = { +static const __devinitdata struct reg_default wm5100_reva_patches[] = { { WM5100_AUDIO_IF_1_10, 0 }, { WM5100_AUDIO_IF_1_11, 1 }, { WM5100_AUDIO_IF_1_12, 2 }, @@ -1343,80 +1265,6 @@ static struct { { WM5100_AUDIO_IF_3_19, 1 }, }; -static int wm5100_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); - int ret, i; - - 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 = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies), - wm5100->core_supplies); - if (ret != 0) { - dev_err(codec->dev, - "Failed to enable supplies: %d\n", - ret); - return ret; - } - - if (wm5100->pdata.ldo_ena) { - gpio_set_value_cansleep(wm5100->pdata.ldo_ena, - 1); - msleep(2); - } - - regcache_cache_only(wm5100->regmap, false); - - switch (wm5100->rev) { - case 0: - regcache_cache_bypass(wm5100->regmap, true); - snd_soc_write(codec, 0x11, 0x3); - snd_soc_write(codec, 0x203, 0xc); - snd_soc_write(codec, 0x206, 0); - snd_soc_write(codec, 0x207, 0xf0); - snd_soc_write(codec, 0x208, 0x3c); - snd_soc_write(codec, 0x209, 0); - snd_soc_write(codec, 0x211, 0x20d8); - snd_soc_write(codec, 0x11, 0); - - for (i = 0; - i < ARRAY_SIZE(wm5100_reva_patches); - i++) - snd_soc_write(codec, - wm5100_reva_patches[i].reg, - wm5100_reva_patches[i].val); - regcache_cache_bypass(wm5100->regmap, false); - break; - default: - break; - } - - regcache_sync(wm5100->regmap); - } - break; - - case SND_SOC_BIAS_OFF: - regcache_cache_only(wm5100->regmap, true); - regcache_mark_dirty(wm5100->regmap); - if (wm5100->pdata.ldo_ena) - gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); - regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), - wm5100->core_supplies); - break; - } - codec->dapm.bias_level = level; - - return 0; -} - static int wm5100_dai_to_base(struct snd_soc_dai *dai) { switch (dai->id) { @@ -1944,6 +1792,8 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source, if (!Fout) { dev_dbg(codec->dev, "FLL%d disabled", fll_id); + if (fll->fout) + pm_runtime_put(codec->dev); fll->fout = 0; snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0); return 0; @@ -1988,6 +1838,8 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source, /* Clear any pending completions */ try_wait_for_completion(&fll->lock); + pm_runtime_get_sync(codec->dev); + snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA); if (i2c->irq) @@ -2022,6 +1874,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source, } if (i == timeout) { dev_err(codec->dev, "FLL%d lock timed out\n", fll_id); + pm_runtime_put(codec->dev); return -ETIMEDOUT; } @@ -2124,55 +1977,73 @@ static int wm5100_dig_vu[] = { WM5100_DAC_DIGITAL_VOLUME_6R, }; -static void wm5100_set_detect_mode(struct snd_soc_codec *codec, int the_mode) +static void wm5100_set_detect_mode(struct wm5100_priv *wm5100, int the_mode) { - struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode]; BUG_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes)); gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol); - snd_soc_update_bits(codec, WM5100_ACCESSORY_DETECT_MODE_1, - WM5100_ACCDET_BIAS_SRC_MASK | - WM5100_ACCDET_SRC, - (mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) | - mode->micd_src << WM5100_ACCDET_SRC_SHIFT); - snd_soc_update_bits(codec, WM5100_MISC_CONTROL, - WM5100_HPCOM_SRC, - mode->micd_src << WM5100_HPCOM_SRC_SHIFT); + regmap_update_bits(wm5100->regmap, WM5100_ACCESSORY_DETECT_MODE_1, + WM5100_ACCDET_BIAS_SRC_MASK | + WM5100_ACCDET_SRC, + (mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) | + mode->micd_src << WM5100_ACCDET_SRC_SHIFT); + regmap_update_bits(wm5100->regmap, WM5100_MISC_CONTROL, + WM5100_HPCOM_SRC, + mode->micd_src << WM5100_HPCOM_SRC_SHIFT); wm5100->jack_mode = the_mode; - dev_dbg(codec->dev, "Set microphone polarity to %d\n", + dev_dbg(wm5100->dev, "Set microphone polarity to %d\n", wm5100->jack_mode); } -static void wm5100_micd_irq(struct snd_soc_codec *codec) +static void wm5100_report_headphone(struct wm5100_priv *wm5100) { - struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); - int val; + dev_dbg(wm5100->dev, "Headphone detected\n"); + wm5100->jack_detecting = false; + snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE, + SND_JACK_HEADPHONE); + + /* Increase the detection rate a bit for responsiveness. */ + regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1, + WM5100_ACCDET_RATE_MASK, + 7 << WM5100_ACCDET_RATE_SHIFT); +} - val = snd_soc_read(codec, WM5100_MIC_DETECT_3); +static void wm5100_micd_irq(struct wm5100_priv *wm5100) +{ + unsigned int val; + int ret; - dev_dbg(codec->dev, "Microphone event: %x\n", val); + ret = regmap_read(wm5100->regmap, WM5100_MIC_DETECT_3, &val); + if (ret != 0) { + dev_err(wm5100->dev, "Failed to read micropone status: %d\n", + ret); + return; + } + + dev_dbg(wm5100->dev, "Microphone event: %x\n", val); if (!(val & WM5100_ACCDET_VALID)) { - dev_warn(codec->dev, "Microphone detection state invalid\n"); + dev_warn(wm5100->dev, "Microphone detection state invalid\n"); return; } /* No accessory, reset everything and report removal */ if (!(val & WM5100_ACCDET_STS)) { - dev_dbg(codec->dev, "Jack removal detected\n"); + dev_dbg(wm5100->dev, "Jack removal detected\n"); wm5100->jack_mic = false; wm5100->jack_detecting = true; + wm5100->jack_flips = 0; snd_soc_jack_report(wm5100->jack, 0, SND_JACK_LINEOUT | SND_JACK_HEADSET | SND_JACK_BTN_0); - snd_soc_update_bits(codec, WM5100_MIC_DETECT_1, - WM5100_ACCDET_RATE_MASK, - WM5100_ACCDET_RATE_MASK); + regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1, + WM5100_ACCDET_RATE_MASK, + WM5100_ACCDET_RATE_MASK); return; } @@ -2182,7 +2053,7 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec) */ if (val & 0x400) { if (wm5100->jack_detecting) { - dev_dbg(codec->dev, "Microphone detected\n"); + dev_dbg(wm5100->dev, "Microphone detected\n"); wm5100->jack_mic = true; wm5100->jack_detecting = false; snd_soc_jack_report(wm5100->jack, @@ -2191,11 +2062,11 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec) /* Increase poll rate to give better responsiveness * for buttons */ - snd_soc_update_bits(codec, WM5100_MIC_DETECT_1, - WM5100_ACCDET_RATE_MASK, - 5 << WM5100_ACCDET_RATE_SHIFT); + regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1, + WM5100_ACCDET_RATE_MASK, + 5 << WM5100_ACCDET_RATE_SHIFT); } else { - dev_dbg(codec->dev, "Mic button up\n"); + dev_dbg(wm5100->dev, "Mic button up\n"); snd_soc_jack_report(wm5100->jack, 0, SND_JACK_BTN_0); } @@ -2205,10 +2076,16 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec) /* 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. + * plain headphones and give up if neither polarity looks + * sensible. */ if (wm5100->jack_detecting && (val & 0x3f8)) { - wm5100_set_detect_mode(codec, !wm5100->jack_mode); + wm5100->jack_flips++; + + if (wm5100->jack_flips > 1) + wm5100_report_headphone(wm5100); + else + wm5100_set_detect_mode(wm5100, !wm5100->jack_mode); return; } @@ -2218,21 +2095,11 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec) */ if (val & 0x3fc) { if (wm5100->jack_mic) { - dev_dbg(codec->dev, "Mic button detected\n"); + dev_dbg(wm5100->dev, "Mic button detected\n"); snd_soc_jack_report(wm5100->jack, SND_JACK_BTN_0, SND_JACK_BTN_0); } else if (wm5100->jack_detecting) { - dev_dbg(codec->dev, "Headphone detected\n"); - wm5100->jack_detecting = false; - snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE, - SND_JACK_HEADPHONE); - - /* Increase the detection rate a bit for - * responsiveness. - */ - snd_soc_update_bits(codec, WM5100_MIC_DETECT_1, - WM5100_ACCDET_RATE_MASK, - 7 << WM5100_ACCDET_RATE_SHIFT); + wm5100_report_headphone(wm5100); } } } @@ -2244,8 +2111,9 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) if (jack) { wm5100->jack = jack; wm5100->jack_detecting = true; + wm5100->jack_flips = 0; - wm5100_set_detect_mode(codec, 0); + wm5100_set_detect_mode(wm5100, 0); /* Slowest detection rate, gives debounce for initial * detection */ @@ -2284,52 +2152,70 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) static irqreturn_t wm5100_irq(int irq, void *data) { - struct snd_soc_codec *codec = data; - struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); + struct wm5100_priv *wm5100 = data; irqreturn_t status = IRQ_NONE; - int irq_val; + unsigned int irq_val, mask_val; + int ret; - irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3); - if (irq_val < 0) { - dev_err(codec->dev, "Failed to read IRQ status 3: %d\n", - irq_val); + ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, &irq_val); + if (ret < 0) { + dev_err(wm5100->dev, "Failed to read IRQ status 3: %d\n", + ret); irq_val = 0; } - irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3_MASK); - snd_soc_write(codec, WM5100_INTERRUPT_STATUS_3, irq_val); + ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3_MASK, + &mask_val); + if (ret < 0) { + dev_err(wm5100->dev, "Failed to read IRQ mask 3: %d\n", + ret); + mask_val = 0xffff; + } + + irq_val &= ~mask_val; + + regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, irq_val); if (irq_val) status = IRQ_HANDLED; - wm5100_log_status3(codec, irq_val); + wm5100_log_status3(wm5100, irq_val); if (irq_val & WM5100_FLL1_LOCK_EINT) { - dev_dbg(codec->dev, "FLL1 locked\n"); + dev_dbg(wm5100->dev, "FLL1 locked\n"); complete(&wm5100->fll[0].lock); } if (irq_val & WM5100_FLL2_LOCK_EINT) { - dev_dbg(codec->dev, "FLL2 locked\n"); + dev_dbg(wm5100->dev, "FLL2 locked\n"); complete(&wm5100->fll[1].lock); } if (irq_val & WM5100_ACCDET_EINT) - wm5100_micd_irq(codec); + wm5100_micd_irq(wm5100); - irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4); - if (irq_val < 0) { - dev_err(codec->dev, "Failed to read IRQ status 4: %d\n", - irq_val); + ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, &irq_val); + if (ret < 0) { + dev_err(wm5100->dev, "Failed to read IRQ status 4: %d\n", + ret); irq_val = 0; } - irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4_MASK); + + ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4_MASK, + &mask_val); + if (ret < 0) { + dev_err(wm5100->dev, "Failed to read IRQ mask 4: %d\n", + ret); + mask_val = 0xffff; + } + + irq_val &= ~mask_val; if (irq_val) status = IRQ_HANDLED; - snd_soc_write(codec, WM5100_INTERRUPT_STATUS_4, irq_val); + regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, irq_val); - wm5100_log_status4(codec, irq_val); + wm5100_log_status4(wm5100, irq_val); return status; } @@ -2454,7 +2340,7 @@ static int wm5100_probe(struct snd_soc_codec *codec) { struct i2c_client *i2c = to_i2c_client(codec->dev); struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); - int ret, i, irq_flags; + int ret, i; wm5100->codec = codec; codec->control_data = wm5100->regmap; @@ -2465,9 +2351,6 @@ static int wm5100_probe(struct snd_soc_codec *codec) return ret; } - regcache_cache_only(wm5100->regmap, true); - - for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++) snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU, WM5100_OUT_VU); @@ -2478,60 +2361,10 @@ static int wm5100_probe(struct snd_soc_codec *codec) /* TODO: check if we're symmetric */ - if (i2c->irq) { - if (wm5100->pdata.irq_flags) - irq_flags = wm5100->pdata.irq_flags; - else - irq_flags = IRQF_TRIGGER_LOW; - - irq_flags |= IRQF_ONESHOT; - - if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) - ret = request_threaded_irq(i2c->irq, NULL, - wm5100_edge_irq, - irq_flags, "wm5100", codec); - else - ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq, - irq_flags, "wm5100", codec); - - if (ret != 0) { - dev_err(codec->dev, "Failed to request IRQ %d: %d\n", - i2c->irq, ret); - } else { - /* Enable default interrupts */ - snd_soc_update_bits(codec, - WM5100_INTERRUPT_STATUS_3_MASK, - WM5100_IM_SPK_SHUTDOWN_WARN_EINT | - WM5100_IM_SPK_SHUTDOWN_EINT | - WM5100_IM_ASRC2_LOCK_EINT | - WM5100_IM_ASRC1_LOCK_EINT | - WM5100_IM_FLL2_LOCK_EINT | - WM5100_IM_FLL1_LOCK_EINT | - WM5100_CLKGEN_ERR_EINT | - WM5100_CLKGEN_ERR_ASYNC_EINT, 0); - - snd_soc_update_bits(codec, - WM5100_INTERRUPT_STATUS_4_MASK, - WM5100_AIF3_ERR_EINT | - WM5100_AIF2_ERR_EINT | - WM5100_AIF1_ERR_EINT | - WM5100_CTRLIF_ERR_EINT | - WM5100_ISRC2_UNDERCLOCKED_EINT | - WM5100_ISRC1_UNDERCLOCKED_EINT | - WM5100_FX_UNDERCLOCKED_EINT | - WM5100_AIF3_UNDERCLOCKED_EINT | - WM5100_AIF2_UNDERCLOCKED_EINT | - WM5100_AIF1_UNDERCLOCKED_EINT | - WM5100_ASRC_UNDERCLOCKED_EINT | - WM5100_DAC_UNDERCLOCKED_EINT | - WM5100_ADC_UNDERCLOCKED_EINT | - WM5100_MIXER_UNDERCLOCKED_EINT, 0); - } - } else { + if (i2c->irq) snd_soc_dapm_new_controls(&codec->dapm, wm5100_dapm_widgets_noirq, ARRAY_SIZE(wm5100_dapm_widgets_noirq)); - } if (wm5100->pdata.hp_pol) { ret = gpio_request_one(wm5100->pdata.hp_pol, @@ -2543,19 +2376,9 @@ static int wm5100_probe(struct snd_soc_codec *codec) } } - /* We'll get woken up again when the system has something useful - * for us to do. - */ - if (wm5100->pdata.ldo_ena) - gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); - regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), - wm5100->core_supplies); - return 0; err_gpio: - if (i2c->irq) - free_irq(i2c->irq, codec); return ret; } @@ -2563,14 +2386,11 @@ err_gpio: static int wm5100_remove(struct snd_soc_codec *codec) { struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); - struct i2c_client *i2c = to_i2c_client(codec->dev); - wm5100_set_bias_level(codec, SND_SOC_BIAS_OFF); if (wm5100->pdata.hp_pol) { gpio_free(wm5100->pdata.hp_pol); } - if (i2c->irq) - free_irq(i2c->irq, codec); + return 0; } @@ -2587,7 +2407,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = { .set_sysclk = wm5100_set_sysclk, .set_pll = wm5100_set_fll, - .set_bias_level = wm5100_set_bias_level, .idle_bias_off = 1, .reg_cache_size = WM5100_MAX_REGISTER, .volatile_register = wm5100_soc_volatile, @@ -2626,13 +2445,15 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm5100_priv *wm5100; unsigned int reg; - int ret, i; + int ret, i, irq_flags; wm5100 = devm_kzalloc(&i2c->dev, sizeof(struct wm5100_priv), GFP_KERNEL); if (wm5100 == NULL) return -ENOMEM; + wm5100->dev = &i2c->dev; + wm5100->regmap = regmap_init_i2c(i2c, &wm5100_regmap); if (IS_ERR(wm5100->regmap)) { ret = PTR_ERR(wm5100->regmap); @@ -2652,41 +2473,21 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(wm5100->core_supplies); i++) wm5100->core_supplies[i].supply = wm5100_core_supply_names[i]; - ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm5100->core_supplies), - wm5100->core_supplies); + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(wm5100->core_supplies), + wm5100->core_supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request core supplies: %d\n", ret); goto err_regmap; } - wm5100->cpvdd = regulator_get(&i2c->dev, "CPVDD"); - if (IS_ERR(wm5100->cpvdd)) { - ret = PTR_ERR(wm5100->cpvdd); - dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret); - goto err_core; - } - - wm5100->dbvdd2 = regulator_get(&i2c->dev, "DBVDD2"); - if (IS_ERR(wm5100->dbvdd2)) { - ret = PTR_ERR(wm5100->dbvdd2); - dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret); - goto err_cpvdd; - } - - wm5100->dbvdd3 = regulator_get(&i2c->dev, "DBVDD3"); - if (IS_ERR(wm5100->dbvdd3)) { - ret = PTR_ERR(wm5100->dbvdd3); - dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret); - goto err_dbvdd2; - } - ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies), wm5100->core_supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to enable core supplies: %d\n", ret); - goto err_dbvdd3; + goto err_regmap; } if (wm5100->pdata.ldo_ena) { @@ -2712,7 +2513,7 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, ret = regmap_read(wm5100->regmap, WM5100_SOFTWARE_RESET, ®); if (ret < 0) { - dev_err(&i2c->dev, "Failed to read ID register\n"); + dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret); goto err_reset; } switch (reg) { @@ -2741,6 +2542,22 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, goto err_reset; } + switch (wm5100->rev) { + case 0: + ret = regmap_register_patch(wm5100->regmap, + wm5100_reva_patches, + ARRAY_SIZE(wm5100_reva_patches)); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register patches: %d\n", + ret); + goto err_reset; + } + break; + default: + break; + } + + wm5100_init_gpio(i2c); for (i = 0; i < ARRAY_SIZE(wm5100->pdata.gpio_defaults); i++) { @@ -2761,6 +2578,62 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, WM5100_IN1_DMIC_SUP_SHIFT)); } + if (i2c->irq) { + if (wm5100->pdata.irq_flags) + irq_flags = wm5100->pdata.irq_flags; + else + irq_flags = IRQF_TRIGGER_LOW; + + irq_flags |= IRQF_ONESHOT; + + if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) + ret = request_threaded_irq(i2c->irq, NULL, + wm5100_edge_irq, irq_flags, + "wm5100", wm5100); + else + ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq, + irq_flags, "wm5100", + wm5100); + + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", + i2c->irq, ret); + } else { + /* Enable default interrupts */ + regmap_update_bits(wm5100->regmap, + WM5100_INTERRUPT_STATUS_3_MASK, + WM5100_IM_SPK_SHUTDOWN_WARN_EINT | + WM5100_IM_SPK_SHUTDOWN_EINT | + WM5100_IM_ASRC2_LOCK_EINT | + WM5100_IM_ASRC1_LOCK_EINT | + WM5100_IM_FLL2_LOCK_EINT | + WM5100_IM_FLL1_LOCK_EINT | + WM5100_CLKGEN_ERR_EINT | + WM5100_CLKGEN_ERR_ASYNC_EINT, 0); + + regmap_update_bits(wm5100->regmap, + WM5100_INTERRUPT_STATUS_4_MASK, + WM5100_AIF3_ERR_EINT | + WM5100_AIF2_ERR_EINT | + WM5100_AIF1_ERR_EINT | + WM5100_CTRLIF_ERR_EINT | + WM5100_ISRC2_UNDERCLOCKED_EINT | + WM5100_ISRC1_UNDERCLOCKED_EINT | + WM5100_FX_UNDERCLOCKED_EINT | + WM5100_AIF3_UNDERCLOCKED_EINT | + WM5100_AIF2_UNDERCLOCKED_EINT | + WM5100_AIF1_UNDERCLOCKED_EINT | + WM5100_ASRC_UNDERCLOCKED_EINT | + WM5100_DAC_UNDERCLOCKED_EINT | + WM5100_ADC_UNDERCLOCKED_EINT | + WM5100_MIXER_UNDERCLOCKED_EINT, 0); + } + } + + pm_runtime_set_active(&i2c->dev); + pm_runtime_enable(&i2c->dev); + pm_request_idle(&i2c->dev); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm5100, wm5100_dai, ARRAY_SIZE(wm5100_dai)); @@ -2772,9 +2645,11 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, return ret; err_reset: + if (i2c->irq) + free_irq(i2c->irq, wm5100); wm5100_free_gpio(i2c); if (wm5100->pdata.reset) { - gpio_set_value_cansleep(wm5100->pdata.reset, 1); + gpio_set_value_cansleep(wm5100->pdata.reset, 0); gpio_free(wm5100->pdata.reset); } err_ldo: @@ -2785,45 +2660,78 @@ err_ldo: err_enable: regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), wm5100->core_supplies); -err_dbvdd3: - regulator_put(wm5100->dbvdd3); -err_dbvdd2: - regulator_put(wm5100->dbvdd2); -err_cpvdd: - regulator_put(wm5100->cpvdd); -err_core: - regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies), - wm5100->core_supplies); err_regmap: regmap_exit(wm5100->regmap); err: return ret; } -static __devexit int wm5100_i2c_remove(struct i2c_client *client) +static __devexit int wm5100_i2c_remove(struct i2c_client *i2c) { - struct wm5100_priv *wm5100 = i2c_get_clientdata(client); + struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); - snd_soc_unregister_codec(&client->dev); - wm5100_free_gpio(client); + snd_soc_unregister_codec(&i2c->dev); + if (i2c->irq) + free_irq(i2c->irq, wm5100); + wm5100_free_gpio(i2c); if (wm5100->pdata.reset) { - gpio_set_value_cansleep(wm5100->pdata.reset, 1); + gpio_set_value_cansleep(wm5100->pdata.reset, 0); gpio_free(wm5100->pdata.reset); } if (wm5100->pdata.ldo_ena) { gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); gpio_free(wm5100->pdata.ldo_ena); } - regulator_put(wm5100->dbvdd3); - regulator_put(wm5100->dbvdd2); - regulator_put(wm5100->cpvdd); - regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies), - wm5100->core_supplies); regmap_exit(wm5100->regmap); return 0; } +#ifdef CONFIG_PM_RUNTIME +static int wm5100_runtime_suspend(struct device *dev) +{ + struct wm5100_priv *wm5100 = dev_get_drvdata(dev); + + regcache_cache_only(wm5100->regmap, true); + regcache_mark_dirty(wm5100->regmap); + if (wm5100->pdata.ldo_ena) + gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); + regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), + wm5100->core_supplies); + + return 0; +} + +static int wm5100_runtime_resume(struct device *dev) +{ + struct wm5100_priv *wm5100 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies), + wm5100->core_supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", + ret); + return ret; + } + + if (wm5100->pdata.ldo_ena) { + gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 1); + msleep(2); + } + + regcache_cache_only(wm5100->regmap, false); + regcache_sync(wm5100->regmap); + + return 0; +} +#endif + +static struct dev_pm_ops wm5100_pm = { + SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume, + NULL) +}; + static const struct i2c_device_id wm5100_i2c_id[] = { { "wm5100", 0 }, { } @@ -2834,6 +2742,7 @@ static struct i2c_driver wm5100_i2c_driver = { .driver = { .name = "wm5100", .owner = THIS_MODULE, + .pm = &wm5100_pm, }, .probe = wm5100_i2c_probe, .remove = __devexit_p(wm5100_i2c_remove), diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 8821af70e66..a32caa72bd7 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -19,6 +19,7 @@ #include <linux/pm.h> #include <linux/i2c.h> #include <linux/slab.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> #include <linux/of_device.h> @@ -41,7 +42,7 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { /* codec private data */ struct wm8731_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; unsigned int sysclk; int sysclk_type; @@ -52,16 +53,30 @@ struct wm8731_priv { /* * wm8731 register cache - * We can't read the WM8731 register space when we are - * using 2 wire for device control, so we cache them instead. - * There is no point in caching the reset register */ -static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { - 0x0097, 0x0097, 0x0079, 0x0079, - 0x000a, 0x0008, 0x009f, 0x000a, - 0x0000, 0x0000 +static const struct reg_default wm8731_reg_defaults[] = { + { 0, 0x0097 }, + { 1, 0x0097 }, + { 2, 0x0079 }, + { 3, 0x0079 }, + { 4, 0x000a }, + { 5, 0x0008 }, + { 6, 0x009f }, + { 7, 0x000a }, + { 8, 0x0000 }, + { 9, 0x0000 }, }; +static bool wm8731_volatile(struct device *dev, unsigned int reg) +{ + return reg == WM8731_RESET; +} + +static bool wm8731_writeable(struct device *dev, unsigned int reg) +{ + return reg <= WM8731_RESET; +} + #define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0) static const char *wm8731_input_select[] = {"Line In", "Mic"}; @@ -441,7 +456,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, if (ret != 0) return ret; - snd_soc_cache_sync(codec); + regcache_sync(wm8731->regmap); } /* Clear PWROFF, gate CLKOUT, everything else as-is */ @@ -452,7 +467,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, snd_soc_write(codec, WM8731_PWR, 0xffff); regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); - codec->cache_sync = 1; + regcache_mark_dirty(wm8731->regmap); break; } codec->dapm.bias_level = level; @@ -513,7 +528,8 @@ static int wm8731_probe(struct snd_soc_codec *codec) struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); int ret = 0, i; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8731->control_type); + codec->control_data = wm8731->regmap; + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -585,9 +601,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { .suspend = wm8731_suspend, .resume = wm8731_resume, .set_bias_level = wm8731_set_bias_level, - .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, @@ -603,6 +616,19 @@ static const struct of_device_id wm8731_of_match[] = { MODULE_DEVICE_TABLE(of, wm8731_of_match); +static const struct regmap_config wm8731_regmap = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = WM8731_RESET, + .volatile_reg = wm8731_volatile, + .writeable_reg = wm8731_writeable, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8731_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults), +}; + #if defined(CONFIG_SPI_MASTER) static int __devinit wm8731_spi_probe(struct spi_device *spi) { @@ -613,20 +639,39 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi) if (wm8731 == NULL) return -ENOMEM; - wm8731->control_type = SND_SOC_SPI; + wm8731->regmap = regmap_init_spi(spi, &wm8731_regmap); + if (IS_ERR(wm8731->regmap)) { + ret = PTR_ERR(wm8731->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", + ret); + goto err; + } + spi_set_drvdata(spi, wm8731); ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8731, &wm8731_dai, 1); - if (ret < 0) - kfree(wm8731); + if (ret != 0) { + dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret); + goto err_regmap; + } + + return 0; + +err_regmap: + regmap_exit(wm8731->regmap); +err: + kfree(wm8731); return ret; } static int __devexit wm8731_spi_remove(struct spi_device *spi) { + struct wm8731_priv *wm8731 = spi_get_drvdata(spi); + snd_soc_unregister_codec(&spi->dev); - kfree(spi_get_drvdata(spi)); + regmap_exit(wm8731->regmap); + kfree(wm8731); return 0; } @@ -652,20 +697,38 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c, if (wm8731 == NULL) return -ENOMEM; + wm8731->regmap = regmap_init_i2c(i2c, &wm8731_regmap); + if (IS_ERR(wm8731->regmap)) { + ret = PTR_ERR(wm8731->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + goto err; + } + i2c_set_clientdata(i2c, wm8731); - wm8731->control_type = SND_SOC_I2C; - ret = snd_soc_register_codec(&i2c->dev, + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8731, &wm8731_dai, 1); - if (ret < 0) - kfree(wm8731); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + goto err_regmap; + } + + return 0; + +err_regmap: + regmap_exit(wm8731->regmap); +err: + kfree(wm8731); return ret; } static __devexit int wm8731_i2c_remove(struct i2c_client *client) { + struct wm8731_priv *wm8731 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + regmap_exit(wm8731->regmap); + kfree(wm8731); return 0; } diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index ff95e62c56b..4fe9d191e27 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -599,7 +599,7 @@ static int wm8737_probe(struct snd_soc_codec *codec) /* Bias level configuration will have done an extra enable */ regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); - snd_soc_add_controls(codec, wm8737_snd_controls, + snd_soc_add_codec_controls(codec, wm8737_snd_controls, ARRAY_SIZE(wm8737_snd_controls)); wm8737_add_widgets(codec); diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index b114c19f530..e27e7b62b36 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -39,6 +39,7 @@ #include <linux/pm.h> #include <linux/i2c.h> #include <linux/of_device.h> +#include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/slab.h> #include <sound/core.h> @@ -65,28 +66,86 @@ static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec, * We can't read the WM8753 register space when we * are using 2 wire for device control, so we cache them instead. */ -static const u16 wm8753_reg[] = { - 0x0000, 0x0008, 0x0000, 0x000a, - 0x000a, 0x0033, 0x0000, 0x0007, - 0x00ff, 0x00ff, 0x000f, 0x000f, - 0x007b, 0x0000, 0x0032, 0x0000, - 0x00c3, 0x00c3, 0x00c0, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0055, 0x0005, 0x0050, 0x0055, - 0x0050, 0x0055, 0x0050, 0x0055, - 0x0079, 0x0079, 0x0079, 0x0079, - 0x0079, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0097, 0x0097, 0x0000, - 0x0004, 0x0000, 0x0083, 0x0024, - 0x01ba, 0x0000, 0x0083, 0x0024, - 0x01ba, 0x0000, 0x0000, 0x0000 +static const struct reg_default wm8753_reg_defaults[] = { + { 0x00, 0x0000 }, + { 0x01, 0x0008 }, + { 0x02, 0x0000 }, + { 0x03, 0x000a }, + { 0x04, 0x000a }, + { 0x05, 0x0033 }, + { 0x06, 0x0000 }, + { 0x07, 0x0007 }, + { 0x08, 0x00ff }, + { 0x09, 0x00ff }, + { 0x0a, 0x000f }, + { 0x0b, 0x000f }, + { 0x0c, 0x007b }, + { 0x0d, 0x0000 }, + { 0x0e, 0x0032 }, + { 0x0f, 0x0000 }, + { 0x10, 0x00c3 }, + { 0x11, 0x00c3 }, + { 0x12, 0x00c0 }, + { 0x13, 0x0000 }, + { 0x14, 0x0000 }, + { 0x15, 0x0000 }, + { 0x16, 0x0000 }, + { 0x17, 0x0000 }, + { 0x18, 0x0000 }, + { 0x19, 0x0000 }, + { 0x1a, 0x0000 }, + { 0x1b, 0x0000 }, + { 0x1c, 0x0000 }, + { 0x1d, 0x0000 }, + { 0x1e, 0x0000 }, + { 0x1f, 0x0000 }, + { 0x20, 0x0055 }, + { 0x21, 0x0005 }, + { 0x22, 0x0050 }, + { 0x23, 0x0055 }, + { 0x24, 0x0050 }, + { 0x25, 0x0055 }, + { 0x26, 0x0050 }, + { 0x27, 0x0055 }, + { 0x28, 0x0079 }, + { 0x29, 0x0079 }, + { 0x2a, 0x0079 }, + { 0x2b, 0x0079 }, + { 0x2c, 0x0079 }, + { 0x2d, 0x0000 }, + { 0x2e, 0x0000 }, + { 0x2f, 0x0000 }, + { 0x30, 0x0000 }, + { 0x31, 0x0097 }, + { 0x32, 0x0097 }, + { 0x33, 0x0000 }, + { 0x34, 0x0004 }, + { 0x35, 0x0000 }, + { 0x36, 0x0083 }, + { 0x37, 0x0024 }, + { 0x38, 0x01ba }, + { 0x39, 0x0000 }, + { 0x3a, 0x0083 }, + { 0x3b, 0x0024 }, + { 0x3c, 0x01ba }, + { 0x3d, 0x0000 }, + { 0x3e, 0x0000 }, + { 0x3f, 0x0000 }, }; +static bool wm8753_volatile(struct device *dev, unsigned int reg) +{ + return reg == WM8753_RESET; +} + +static bool wm8753_writeable(struct device *dev, unsigned int reg) +{ + return reg <= WM8753_ADCTL2; +} + /* codec private data */ struct wm8753_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; unsigned int sysclk; unsigned int pcmclk; @@ -1383,25 +1442,15 @@ static void wm8753_work(struct work_struct *work) static int wm8753_suspend(struct snd_soc_codec *codec) { wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); + codec->cache_sync = 1; return 0; } static int wm8753_resume(struct snd_soc_codec *codec) { - u16 *reg_cache = codec->reg_cache; - int i; - - /* Sync reg_cache with the hardware */ - for (i = 1; i < ARRAY_SIZE(wm8753_reg); i++) { - if (i == WM8753_RESET) - continue; - - /* No point in writing hardware default values back */ - if (reg_cache[i] == wm8753_reg[i]) - continue; + struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); - snd_soc_write(codec, i, reg_cache[i]); - } + regcache_sync(wm8753->regmap); wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1423,7 +1472,8 @@ static int wm8753_probe(struct snd_soc_codec *codec) INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work); - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type); + codec->control_data = wm8753->regmap; + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -1473,9 +1523,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8753 = { .suspend = wm8753_suspend, .resume = wm8753_resume, .set_bias_level = wm8753_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8753_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8753_reg, .controls = wm8753_snd_controls, .num_controls = ARRAY_SIZE(wm8753_snd_controls), @@ -1491,30 +1538,62 @@ static const struct of_device_id wm8753_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8753_of_match); +static const struct regmap_config wm8753_regmap = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = WM8753_ADCTL2, + .writeable_reg = wm8753_writeable, + .volatile_reg = wm8753_volatile, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8753_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults), +}; + #if defined(CONFIG_SPI_MASTER) static int __devinit wm8753_spi_probe(struct spi_device *spi) { struct wm8753_priv *wm8753; int ret; - wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); + wm8753 = devm_kzalloc(&spi->dev, sizeof(struct wm8753_priv), + GFP_KERNEL); if (wm8753 == NULL) return -ENOMEM; - wm8753->control_type = SND_SOC_SPI; spi_set_drvdata(spi, wm8753); - ret = snd_soc_register_codec(&spi->dev, - &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); - if (ret < 0) - kfree(wm8753); + wm8753->regmap = regmap_init_spi(spi, &wm8753_regmap); + if (IS_ERR(wm8753->regmap)) { + ret = PTR_ERR(wm8753->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", + ret); + goto err; + } + + ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8753, + wm8753_dai, ARRAY_SIZE(wm8753_dai)); + if (ret != 0) { + dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret); + goto err_regmap; + } + + return 0; + +err_regmap: + regmap_exit(wm8753->regmap); +err: return ret; } static int __devexit wm8753_spi_remove(struct spi_device *spi) { + struct wm8753_priv *wm8753 = spi_get_drvdata(spi); + snd_soc_unregister_codec(&spi->dev); - kfree(spi_get_drvdata(spi)); + regmap_exit(wm8753->regmap); + kfree(wm8753); return 0; } @@ -1536,24 +1615,42 @@ static __devinit int wm8753_i2c_probe(struct i2c_client *i2c, struct wm8753_priv *wm8753; int ret; - wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); + wm8753 = devm_kzalloc(&i2c->dev, sizeof(struct wm8753_priv), + GFP_KERNEL); if (wm8753 == NULL) return -ENOMEM; i2c_set_clientdata(i2c, wm8753); - wm8753->control_type = SND_SOC_I2C; - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); - if (ret < 0) - kfree(wm8753); + wm8753->regmap = regmap_init_i2c(i2c, &wm8753_regmap); + if (IS_ERR(wm8753->regmap)) { + ret = PTR_ERR(wm8753->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + goto err; + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8753, + wm8753_dai, ARRAY_SIZE(wm8753_dai)); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + goto err_regmap; + } + + return 0; + +err_regmap: + regmap_exit(wm8753->regmap); +err: return ret; } static __devexit int wm8753_i2c_remove(struct i2c_client *client) { + struct wm8753_priv *wm8753 = i2c_get_clientdata(client); + snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + regmap_exit(wm8753->regmap); return 0; } diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 19374a9e5ba..a5127b4ff9e 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -580,8 +580,6 @@ static int wm8770_probe(struct snd_soc_codec *codec) wm8770 = snd_soc_codec_get_drvdata(codec); wm8770->codec = codec; - codec->dapm.idle_bias_off = 1; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8770->control_type); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); @@ -643,7 +641,7 @@ static int wm8770_probe(struct snd_soc_codec *codec) /* mute all DACs */ snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10); - snd_soc_add_controls(codec, wm8770_snd_controls, + snd_soc_add_codec_controls(codec, wm8770_snd_controls, ARRAY_SIZE(wm8770_snd_controls)); snd_soc_dapm_new_controls(&codec->dapm, wm8770_dapm_widgets, ARRAY_SIZE(wm8770_dapm_widgets)); @@ -679,6 +677,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8770 = { .suspend = wm8770_suspend, .resume = wm8770_resume, .set_bias_level = wm8770_set_bias_level, + .idle_bias_off = true, .reg_cache_size = ARRAY_SIZE(wm8770_reg_defs), .reg_word_size = sizeof (u16), .reg_cache_default = wm8770_reg_defs diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 33e97d1d8f4..a19db5a0a17 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -30,6 +30,11 @@ #include "wm8776.h" +enum wm8776_chip_type { + WM8775 = 1, + WM8776, +}; + /* codec private data */ struct wm8776_priv { enum snd_soc_control_type control_type; @@ -512,7 +517,8 @@ static __devexit int wm8776_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id wm8776_i2c_id[] = { - { "wm8776", 0 }, + { "wm8775", WM8775 }, + { "wm8776", WM8776 }, { } }; MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id); diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index d54a3ca5e19..6bd1b767b13 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -18,6 +18,7 @@ #include <linux/i2c.h> #include <linux/of_device.h> #include <linux/spi/spi.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/core.h> @@ -35,45 +36,33 @@ static const char *wm8804_supply_names[WM8804_NUM_SUPPLIES] = { "DVDD" }; -static const u8 wm8804_reg_defs[] = { - 0x05, /* R0 - RST/DEVID1 */ - 0x88, /* R1 - DEVID2 */ - 0x04, /* R2 - DEVREV */ - 0x21, /* R3 - PLL1 */ - 0xFD, /* R4 - PLL2 */ - 0x36, /* R5 - PLL3 */ - 0x07, /* R6 - PLL4 */ - 0x16, /* R7 - PLL5 */ - 0x18, /* R8 - PLL6 */ - 0xFF, /* R9 - SPDMODE */ - 0x00, /* R10 - INTMASK */ - 0x00, /* R11 - INTSTAT */ - 0x00, /* R12 - SPDSTAT */ - 0x00, /* R13 - RXCHAN1 */ - 0x00, /* R14 - RXCHAN2 */ - 0x00, /* R15 - RXCHAN3 */ - 0x00, /* R16 - RXCHAN4 */ - 0x00, /* R17 - RXCHAN5 */ - 0x00, /* R18 - SPDTX1 */ - 0x00, /* R19 - SPDTX2 */ - 0x00, /* R20 - SPDTX3 */ - 0x71, /* R21 - SPDTX4 */ - 0x0B, /* R22 - SPDTX5 */ - 0x70, /* R23 - GPO0 */ - 0x57, /* R24 - GPO1 */ - 0x00, /* R25 */ - 0x42, /* R26 - GPO2 */ - 0x06, /* R27 - AIFTX */ - 0x06, /* R28 - AIFRX */ - 0x80, /* R29 - SPDRX1 */ - 0x07, /* R30 - PWRDN */ +static const struct reg_default wm8804_reg_defaults[] = { + { 3, 0x21 }, /* R3 - PLL1 */ + { 4, 0xFD }, /* R4 - PLL2 */ + { 5, 0x36 }, /* R5 - PLL3 */ + { 6, 0x07 }, /* R6 - PLL4 */ + { 7, 0x16 }, /* R7 - PLL5 */ + { 8, 0x18 }, /* R8 - PLL6 */ + { 9, 0xFF }, /* R9 - SPDMODE */ + { 10, 0x00 }, /* R10 - INTMASK */ + { 18, 0x00 }, /* R18 - SPDTX1 */ + { 19, 0x00 }, /* R19 - SPDTX2 */ + { 20, 0x00 }, /* R20 - SPDTX3 */ + { 21, 0x71 }, /* R21 - SPDTX4 */ + { 22, 0x0B }, /* R22 - SPDTX5 */ + { 23, 0x70 }, /* R23 - GPO0 */ + { 24, 0x57 }, /* R24 - GPO1 */ + { 26, 0x42 }, /* R26 - GPO2 */ + { 27, 0x06 }, /* R27 - AIFTX */ + { 28, 0x06 }, /* R28 - AIFRX */ + { 29, 0x80 }, /* R29 - SPDRX1 */ + { 30, 0x07 }, /* R30 - PWRDN */ }; struct wm8804_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES]; struct notifier_block disable_nb[WM8804_NUM_SUPPLIES]; - struct snd_soc_codec *codec; }; static int txsrc_get(struct snd_kcontrol *kcontrol, @@ -94,7 +83,7 @@ static int wm8804_regulator_event_##n(struct notifier_block *nb, \ struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \ disable_nb[n]); \ if (event & REGULATOR_EVENT_DISABLE) { \ - wm8804->codec->cache_sync = 1; \ + regcache_mark_dirty(wm8804->regmap); \ } \ return 0; \ } @@ -176,7 +165,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol, return 0; } -static int wm8804_volatile(struct snd_soc_codec *codec, unsigned int reg) +static bool wm8804_volatile(struct device *dev, unsigned int reg) { switch (reg) { case WM8804_RST_DEVID1: @@ -189,12 +178,10 @@ static int wm8804_volatile(struct snd_soc_codec *codec, unsigned int reg) case WM8804_RXCHAN3: case WM8804_RXCHAN4: case WM8804_RXCHAN5: - return 1; + return true; default: - break; + return false; } - - return 0; } static int wm8804_reset(struct snd_soc_codec *codec) @@ -482,24 +469,6 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai, return 0; } -static void wm8804_sync_cache(struct snd_soc_codec *codec) -{ - short i; - u8 *cache; - - if (!codec->cache_sync) - return; - - codec->cache_only = 0; - cache = codec->reg_cache; - for (i = 0; i < codec->driver->reg_cache_size; i++) { - if (i == WM8804_RST_DEVID1 || cache[i] == wm8804_reg_defs[i]) - continue; - snd_soc_write(codec, i, cache[i]); - } - codec->cache_sync = 0; -} - static int wm8804_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -524,7 +493,7 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec, ret); return ret; } - wm8804_sync_cache(codec); + regcache_sync(wm8804->regmap); } /* power down the OSC and the PLL */ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9); @@ -579,11 +548,10 @@ static int wm8804_probe(struct snd_soc_codec *codec) int i, id1, id2, ret; wm8804 = snd_soc_codec_get_drvdata(codec); - wm8804->codec = codec; - codec->dapm.idle_bias_off = 1; + codec->control_data = wm8804->regmap; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, wm8804->control_type); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); return ret; @@ -636,8 +604,7 @@ static int wm8804_probe(struct snd_soc_codec *codec) id2 = (id2 << 8) | id1; - if (id2 != ((wm8804_reg_defs[WM8804_DEVID2] << 8) - | wm8804_reg_defs[WM8804_RST_DEVID1])) { + if (id2 != 0x8805) { dev_err(codec->dev, "Invalid device ID: %#x\n", id2); ret = -EINVAL; goto err_reg_enable; @@ -710,10 +677,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .suspend = wm8804_suspend, .resume = wm8804_resume, .set_bias_level = wm8804_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8804_reg_defs), - .reg_word_size = sizeof(u8), - .reg_cache_default = wm8804_reg_defs, - .volatile_register = wm8804_volatile, + .idle_bias_off = true, .controls = wm8804_snd_controls, .num_controls = ARRAY_SIZE(wm8804_snd_controls), @@ -725,30 +689,47 @@ static const struct of_device_id wm8804_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8804_of_match); +static struct regmap_config wm8804_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = WM8804_MAX_REGISTER, + .volatile_reg = wm8804_volatile, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8804_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults), +}; + #if defined(CONFIG_SPI_MASTER) static int __devinit wm8804_spi_probe(struct spi_device *spi) { struct wm8804_priv *wm8804; int ret; - wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL); + wm8804 = devm_kzalloc(&spi->dev, sizeof *wm8804, GFP_KERNEL); if (!wm8804) return -ENOMEM; - wm8804->control_type = SND_SOC_SPI; + wm8804->regmap = regmap_init_spi(spi, &wm8804_regmap_config); + if (IS_ERR(wm8804->regmap)) { + ret = PTR_ERR(wm8804->regmap); + return ret; + } + spi_set_drvdata(spi, wm8804); ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8804, &wm8804_dai, 1); - if (ret < 0) - kfree(wm8804); + return ret; } static int __devexit wm8804_spi_remove(struct spi_device *spi) { + struct wm8804_priv *wm8804 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - kfree(spi_get_drvdata(spi)); + regmap_exit(wm8804->regmap); return 0; } @@ -770,24 +751,37 @@ static __devinit int wm8804_i2c_probe(struct i2c_client *i2c, struct wm8804_priv *wm8804; int ret; - wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL); + wm8804 = devm_kzalloc(&i2c->dev, sizeof *wm8804, GFP_KERNEL); if (!wm8804) return -ENOMEM; - wm8804->control_type = SND_SOC_I2C; + wm8804->regmap = regmap_init_i2c(i2c, &wm8804_regmap_config); + if (IS_ERR(wm8804->regmap)) { + ret = PTR_ERR(wm8804->regmap); + return ret; + } + i2c_set_clientdata(i2c, wm8804); ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8804, &wm8804_dai, 1); - if (ret < 0) - kfree(wm8804); + if (ret != 0) + goto err; + + return 0; + +err: + regmap_exit(wm8804->regmap); return ret; } -static __devexit int wm8804_i2c_remove(struct i2c_client *client) +static __devexit int wm8804_i2c_remove(struct i2c_client *i2c) { - snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + struct wm8804_priv *wm8804 = i2c_get_clientdata(i2c); + + snd_soc_unregister_codec(&i2c->dev); + regmap_exit(wm8804->regmap); + return 0; } diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index f31c754c886..65d525d74c5 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/core.h> @@ -47,6 +48,7 @@ static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = { /* codec private data */ struct wm8904_priv { + struct regmap *regmap; enum wm8904_type devtype; @@ -86,517 +88,230 @@ struct wm8904_priv { int dcs_state[WM8904_NUM_DCS_CHANNELS]; }; -static const u16 wm8904_reg[WM8904_MAX_REGISTER + 1] = { - 0x8904, /* R0 - SW Reset and ID */ - 0x0000, /* R1 - Revision */ - 0x0000, /* R2 */ - 0x0000, /* R3 */ - 0x0018, /* R4 - Bias Control 0 */ - 0x0000, /* R5 - VMID Control 0 */ - 0x0000, /* R6 - Mic Bias Control 0 */ - 0x0000, /* R7 - Mic Bias Control 1 */ - 0x0001, /* R8 - Analogue DAC 0 */ - 0x9696, /* R9 - mic Filter Control */ - 0x0001, /* R10 - Analogue ADC 0 */ - 0x0000, /* R11 */ - 0x0000, /* R12 - Power Management 0 */ - 0x0000, /* R13 */ - 0x0000, /* R14 - Power Management 2 */ - 0x0000, /* R15 - Power Management 3 */ - 0x0000, /* R16 */ - 0x0000, /* R17 */ - 0x0000, /* R18 - Power Management 6 */ - 0x0000, /* R19 */ - 0x945E, /* R20 - Clock Rates 0 */ - 0x0C05, /* R21 - Clock Rates 1 */ - 0x0006, /* R22 - Clock Rates 2 */ - 0x0000, /* R23 */ - 0x0050, /* R24 - Audio Interface 0 */ - 0x000A, /* R25 - Audio Interface 1 */ - 0x00E4, /* R26 - Audio Interface 2 */ - 0x0040, /* R27 - Audio Interface 3 */ - 0x0000, /* R28 */ - 0x0000, /* R29 */ - 0x00C0, /* R30 - DAC Digital Volume Left */ - 0x00C0, /* R31 - DAC Digital Volume Right */ - 0x0000, /* R32 - DAC Digital 0 */ - 0x0008, /* R33 - DAC Digital 1 */ - 0x0000, /* R34 */ - 0x0000, /* R35 */ - 0x00C0, /* R36 - ADC Digital Volume Left */ - 0x00C0, /* R37 - ADC Digital Volume Right */ - 0x0010, /* R38 - ADC Digital 0 */ - 0x0000, /* R39 - Digital Microphone 0 */ - 0x01AF, /* R40 - DRC 0 */ - 0x3248, /* R41 - DRC 1 */ - 0x0000, /* R42 - DRC 2 */ - 0x0000, /* R43 - DRC 3 */ - 0x0085, /* R44 - Analogue Left Input 0 */ - 0x0085, /* R45 - Analogue Right Input 0 */ - 0x0044, /* R46 - Analogue Left Input 1 */ - 0x0044, /* R47 - Analogue Right Input 1 */ - 0x0000, /* R48 */ - 0x0000, /* R49 */ - 0x0000, /* R50 */ - 0x0000, /* R51 */ - 0x0000, /* R52 */ - 0x0000, /* R53 */ - 0x0000, /* R54 */ - 0x0000, /* R55 */ - 0x0000, /* R56 */ - 0x002D, /* R57 - Analogue OUT1 Left */ - 0x002D, /* R58 - Analogue OUT1 Right */ - 0x0039, /* R59 - Analogue OUT2 Left */ - 0x0039, /* R60 - Analogue OUT2 Right */ - 0x0000, /* R61 - Analogue OUT12 ZC */ - 0x0000, /* R62 */ - 0x0000, /* R63 */ - 0x0000, /* R64 */ - 0x0000, /* R65 */ - 0x0000, /* R66 */ - 0x0000, /* R67 - DC Servo 0 */ - 0x0000, /* R68 - DC Servo 1 */ - 0xAAAA, /* R69 - DC Servo 2 */ - 0x0000, /* R70 */ - 0xAAAA, /* R71 - DC Servo 4 */ - 0xAAAA, /* R72 - DC Servo 5 */ - 0x0000, /* R73 - DC Servo 6 */ - 0x0000, /* R74 - DC Servo 7 */ - 0x0000, /* R75 - DC Servo 8 */ - 0x0000, /* R76 - DC Servo 9 */ - 0x0000, /* R77 - DC Servo Readback 0 */ - 0x0000, /* R78 */ - 0x0000, /* R79 */ - 0x0000, /* R80 */ - 0x0000, /* R81 */ - 0x0000, /* R82 */ - 0x0000, /* R83 */ - 0x0000, /* R84 */ - 0x0000, /* R85 */ - 0x0000, /* R86 */ - 0x0000, /* R87 */ - 0x0000, /* R88 */ - 0x0000, /* R89 */ - 0x0000, /* R90 - Analogue HP 0 */ - 0x0000, /* R91 */ - 0x0000, /* R92 */ - 0x0000, /* R93 */ - 0x0000, /* R94 - Analogue Lineout 0 */ - 0x0000, /* R95 */ - 0x0000, /* R96 */ - 0x0000, /* R97 */ - 0x0000, /* R98 - Charge Pump 0 */ - 0x0000, /* R99 */ - 0x0000, /* R100 */ - 0x0000, /* R101 */ - 0x0000, /* R102 */ - 0x0000, /* R103 */ - 0x0004, /* R104 - Class W 0 */ - 0x0000, /* R105 */ - 0x0000, /* R106 */ - 0x0000, /* R107 */ - 0x0000, /* R108 - Write Sequencer 0 */ - 0x0000, /* R109 - Write Sequencer 1 */ - 0x0000, /* R110 - Write Sequencer 2 */ - 0x0000, /* R111 - Write Sequencer 3 */ - 0x0000, /* R112 - Write Sequencer 4 */ - 0x0000, /* R113 */ - 0x0000, /* R114 */ - 0x0000, /* R115 */ - 0x0000, /* R116 - FLL Control 1 */ - 0x0007, /* R117 - FLL Control 2 */ - 0x0000, /* R118 - FLL Control 3 */ - 0x2EE0, /* R119 - FLL Control 4 */ - 0x0004, /* R120 - FLL Control 5 */ - 0x0014, /* R121 - GPIO Control 1 */ - 0x0010, /* R122 - GPIO Control 2 */ - 0x0010, /* R123 - GPIO Control 3 */ - 0x0000, /* R124 - GPIO Control 4 */ - 0x0000, /* R125 */ - 0x0000, /* R126 - Digital Pulls */ - 0x0000, /* R127 - Interrupt Status */ - 0xFFFF, /* R128 - Interrupt Status Mask */ - 0x0000, /* R129 - Interrupt Polarity */ - 0x0000, /* R130 - Interrupt Debounce */ - 0x0000, /* R131 */ - 0x0000, /* R132 */ - 0x0000, /* R133 */ - 0x0000, /* R134 - EQ1 */ - 0x000C, /* R135 - EQ2 */ - 0x000C, /* R136 - EQ3 */ - 0x000C, /* R137 - EQ4 */ - 0x000C, /* R138 - EQ5 */ - 0x000C, /* R139 - EQ6 */ - 0x0FCA, /* R140 - EQ7 */ - 0x0400, /* R141 - EQ8 */ - 0x00D8, /* R142 - EQ9 */ - 0x1EB5, /* R143 - EQ10 */ - 0xF145, /* R144 - EQ11 */ - 0x0B75, /* R145 - EQ12 */ - 0x01C5, /* R146 - EQ13 */ - 0x1C58, /* R147 - EQ14 */ - 0xF373, /* R148 - EQ15 */ - 0x0A54, /* R149 - EQ16 */ - 0x0558, /* R150 - EQ17 */ - 0x168E, /* R151 - EQ18 */ - 0xF829, /* R152 - EQ19 */ - 0x07AD, /* R153 - EQ20 */ - 0x1103, /* R154 - EQ21 */ - 0x0564, /* R155 - EQ22 */ - 0x0559, /* R156 - EQ23 */ - 0x4000, /* R157 - EQ24 */ - 0x0000, /* R158 */ - 0x0000, /* R159 */ - 0x0000, /* R160 */ - 0x0000, /* R161 - Control Interface Test 1 */ - 0x0000, /* R162 */ - 0x0000, /* R163 */ - 0x0000, /* R164 */ - 0x0000, /* R165 */ - 0x0000, /* R166 */ - 0x0000, /* R167 */ - 0x0000, /* R168 */ - 0x0000, /* R169 */ - 0x0000, /* R170 */ - 0x0000, /* R171 */ - 0x0000, /* R172 */ - 0x0000, /* R173 */ - 0x0000, /* R174 */ - 0x0000, /* R175 */ - 0x0000, /* R176 */ - 0x0000, /* R177 */ - 0x0000, /* R178 */ - 0x0000, /* R179 */ - 0x0000, /* R180 */ - 0x0000, /* R181 */ - 0x0000, /* R182 */ - 0x0000, /* R183 */ - 0x0000, /* R184 */ - 0x0000, /* R185 */ - 0x0000, /* R186 */ - 0x0000, /* R187 */ - 0x0000, /* R188 */ - 0x0000, /* R189 */ - 0x0000, /* R190 */ - 0x0000, /* R191 */ - 0x0000, /* R192 */ - 0x0000, /* R193 */ - 0x0000, /* R194 */ - 0x0000, /* R195 */ - 0x0000, /* R196 */ - 0x0000, /* R197 */ - 0x0000, /* R198 */ - 0x0000, /* R199 */ - 0x0000, /* R200 */ - 0x0000, /* R201 */ - 0x0000, /* R202 */ - 0x0000, /* R203 */ - 0x0000, /* R204 - Analogue Output Bias 0 */ - 0x0000, /* R205 */ - 0x0000, /* R206 */ - 0x0000, /* R207 */ - 0x0000, /* R208 */ - 0x0000, /* R209 */ - 0x0000, /* R210 */ - 0x0000, /* R211 */ - 0x0000, /* R212 */ - 0x0000, /* R213 */ - 0x0000, /* R214 */ - 0x0000, /* R215 */ - 0x0000, /* R216 */ - 0x0000, /* R217 */ - 0x0000, /* R218 */ - 0x0000, /* R219 */ - 0x0000, /* R220 */ - 0x0000, /* R221 */ - 0x0000, /* R222 */ - 0x0000, /* R223 */ - 0x0000, /* R224 */ - 0x0000, /* R225 */ - 0x0000, /* R226 */ - 0x0000, /* R227 */ - 0x0000, /* R228 */ - 0x0000, /* R229 */ - 0x0000, /* R230 */ - 0x0000, /* R231 */ - 0x0000, /* R232 */ - 0x0000, /* R233 */ - 0x0000, /* R234 */ - 0x0000, /* R235 */ - 0x0000, /* R236 */ - 0x0000, /* R237 */ - 0x0000, /* R238 */ - 0x0000, /* R239 */ - 0x0000, /* R240 */ - 0x0000, /* R241 */ - 0x0000, /* R242 */ - 0x0000, /* R243 */ - 0x0000, /* R244 */ - 0x0000, /* R245 */ - 0x0000, /* R246 */ - 0x0000, /* R247 - FLL NCO Test 0 */ - 0x0019, /* R248 - FLL NCO Test 1 */ +static const struct reg_default wm8904_reg_defaults[] = { + { 4, 0x0018 }, /* R4 - Bias Control 0 */ + { 5, 0x0000 }, /* R5 - VMID Control 0 */ + { 6, 0x0000 }, /* R6 - Mic Bias Control 0 */ + { 7, 0x0000 }, /* R7 - Mic Bias Control 1 */ + { 8, 0x0001 }, /* R8 - Analogue DAC 0 */ + { 9, 0x9696 }, /* R9 - mic Filter Control */ + { 10, 0x0001 }, /* R10 - Analogue ADC 0 */ + { 12, 0x0000 }, /* R12 - Power Management 0 */ + { 14, 0x0000 }, /* R14 - Power Management 2 */ + { 15, 0x0000 }, /* R15 - Power Management 3 */ + { 18, 0x0000 }, /* R18 - Power Management 6 */ + { 19, 0x945E }, /* R20 - Clock Rates 0 */ + { 21, 0x0C05 }, /* R21 - Clock Rates 1 */ + { 22, 0x0006 }, /* R22 - Clock Rates 2 */ + { 24, 0x0050 }, /* R24 - Audio Interface 0 */ + { 25, 0x000A }, /* R25 - Audio Interface 1 */ + { 26, 0x00E4 }, /* R26 - Audio Interface 2 */ + { 27, 0x0040 }, /* R27 - Audio Interface 3 */ + { 30, 0x00C0 }, /* R30 - DAC Digital Volume Left */ + { 31, 0x00C0 }, /* R31 - DAC Digital Volume Right */ + { 32, 0x0000 }, /* R32 - DAC Digital 0 */ + { 33, 0x0008 }, /* R33 - DAC Digital 1 */ + { 36, 0x00C0 }, /* R36 - ADC Digital Volume Left */ + { 37, 0x00C0 }, /* R37 - ADC Digital Volume Right */ + { 38, 0x0010 }, /* R38 - ADC Digital 0 */ + { 39, 0x0000 }, /* R39 - Digital Microphone 0 */ + { 40, 0x01AF }, /* R40 - DRC 0 */ + { 41, 0x3248 }, /* R41 - DRC 1 */ + { 42, 0x0000 }, /* R42 - DRC 2 */ + { 43, 0x0000 }, /* R43 - DRC 3 */ + { 44, 0x0085 }, /* R44 - Analogue Left Input 0 */ + { 45, 0x0085 }, /* R45 - Analogue Right Input 0 */ + { 46, 0x0044 }, /* R46 - Analogue Left Input 1 */ + { 47, 0x0044 }, /* R47 - Analogue Right Input 1 */ + { 57, 0x002D }, /* R57 - Analogue OUT1 Left */ + { 58, 0x002D }, /* R58 - Analogue OUT1 Right */ + { 59, 0x0039 }, /* R59 - Analogue OUT2 Left */ + { 60, 0x0039 }, /* R60 - Analogue OUT2 Right */ + { 61, 0x0000 }, /* R61 - Analogue OUT12 ZC */ + { 67, 0x0000 }, /* R67 - DC Servo 0 */ + { 69, 0xAAAA }, /* R69 - DC Servo 2 */ + { 71, 0xAAAA }, /* R71 - DC Servo 4 */ + { 72, 0xAAAA }, /* R72 - DC Servo 5 */ + { 90, 0x0000 }, /* R90 - Analogue HP 0 */ + { 94, 0x0000 }, /* R94 - Analogue Lineout 0 */ + { 98, 0x0000 }, /* R98 - Charge Pump 0 */ + { 104, 0x0004 }, /* R104 - Class W 0 */ + { 108, 0x0000 }, /* R108 - Write Sequencer 0 */ + { 109, 0x0000 }, /* R109 - Write Sequencer 1 */ + { 110, 0x0000 }, /* R110 - Write Sequencer 2 */ + { 111, 0x0000 }, /* R111 - Write Sequencer 3 */ + { 112, 0x0000 }, /* R112 - Write Sequencer 4 */ + { 116, 0x0000 }, /* R116 - FLL Control 1 */ + { 117, 0x0007 }, /* R117 - FLL Control 2 */ + { 118, 0x0000 }, /* R118 - FLL Control 3 */ + { 119, 0x2EE0 }, /* R119 - FLL Control 4 */ + { 120, 0x0004 }, /* R120 - FLL Control 5 */ + { 121, 0x0014 }, /* R121 - GPIO Control 1 */ + { 122, 0x0010 }, /* R122 - GPIO Control 2 */ + { 123, 0x0010 }, /* R123 - GPIO Control 3 */ + { 124, 0x0000 }, /* R124 - GPIO Control 4 */ + { 126, 0x0000 }, /* R126 - Digital Pulls */ + { 128, 0xFFFF }, /* R128 - Interrupt Status Mask */ + { 129, 0x0000 }, /* R129 - Interrupt Polarity */ + { 130, 0x0000 }, /* R130 - Interrupt Debounce */ + { 134, 0x0000 }, /* R134 - EQ1 */ + { 135, 0x000C }, /* R135 - EQ2 */ + { 136, 0x000C }, /* R136 - EQ3 */ + { 137, 0x000C }, /* R137 - EQ4 */ + { 138, 0x000C }, /* R138 - EQ5 */ + { 139, 0x000C }, /* R139 - EQ6 */ + { 140, 0x0FCA }, /* R140 - EQ7 */ + { 141, 0x0400 }, /* R141 - EQ8 */ + { 142, 0x00D8 }, /* R142 - EQ9 */ + { 143, 0x1EB5 }, /* R143 - EQ10 */ + { 144, 0xF145 }, /* R144 - EQ11 */ + { 145, 0x0B75 }, /* R145 - EQ12 */ + { 146, 0x01C5 }, /* R146 - EQ13 */ + { 147, 0x1C58 }, /* R147 - EQ14 */ + { 148, 0xF373 }, /* R148 - EQ15 */ + { 149, 0x0A54 }, /* R149 - EQ16 */ + { 150, 0x0558 }, /* R150 - EQ17 */ + { 151, 0x168E }, /* R151 - EQ18 */ + { 152, 0xF829 }, /* R152 - EQ19 */ + { 153, 0x07AD }, /* R153 - EQ20 */ + { 154, 0x1103 }, /* R154 - EQ21 */ + { 155, 0x0564 }, /* R155 - EQ22 */ + { 156, 0x0559 }, /* R156 - EQ23 */ + { 157, 0x4000 }, /* R157 - EQ24 */ + { 161, 0x0000 }, /* R161 - Control Interface Test 1 */ + { 204, 0x0000 }, /* R204 - Analogue Output Bias 0 */ + { 247, 0x0000 }, /* R247 - FLL NCO Test 0 */ + { 248, 0x0019 }, /* R248 - FLL NCO Test 1 */ }; -static struct { - int readable; - int writable; - int vol; -} wm8904_access[] = { - { 0xFFFF, 0xFFFF, 1 }, /* R0 - SW Reset and ID */ - { 0x0000, 0x0000, 0 }, /* R1 - Revision */ - { 0x0000, 0x0000, 0 }, /* R2 */ - { 0x0000, 0x0000, 0 }, /* R3 */ - { 0x001F, 0x001F, 0 }, /* R4 - Bias Control 0 */ - { 0x0047, 0x0047, 0 }, /* R5 - VMID Control 0 */ - { 0x007F, 0x007F, 0 }, /* R6 - Mic Bias Control 0 */ - { 0xC007, 0xC007, 0 }, /* R7 - Mic Bias Control 1 */ - { 0x001E, 0x001E, 0 }, /* R8 - Analogue DAC 0 */ - { 0xFFFF, 0xFFFF, 0 }, /* R9 - mic Filter Control */ - { 0x0001, 0x0001, 0 }, /* R10 - Analogue ADC 0 */ - { 0x0000, 0x0000, 0 }, /* R11 */ - { 0x0003, 0x0003, 0 }, /* R12 - Power Management 0 */ - { 0x0000, 0x0000, 0 }, /* R13 */ - { 0x0003, 0x0003, 0 }, /* R14 - Power Management 2 */ - { 0x0003, 0x0003, 0 }, /* R15 - Power Management 3 */ - { 0x0000, 0x0000, 0 }, /* R16 */ - { 0x0000, 0x0000, 0 }, /* R17 */ - { 0x000F, 0x000F, 0 }, /* R18 - Power Management 6 */ - { 0x0000, 0x0000, 0 }, /* R19 */ - { 0x7001, 0x7001, 0 }, /* R20 - Clock Rates 0 */ - { 0x3C07, 0x3C07, 0 }, /* R21 - Clock Rates 1 */ - { 0xD00F, 0xD00F, 0 }, /* R22 - Clock Rates 2 */ - { 0x0000, 0x0000, 0 }, /* R23 */ - { 0x1FFF, 0x1FFF, 0 }, /* R24 - Audio Interface 0 */ - { 0x3DDF, 0x3DDF, 0 }, /* R25 - Audio Interface 1 */ - { 0x0F1F, 0x0F1F, 0 }, /* R26 - Audio Interface 2 */ - { 0x0FFF, 0x0FFF, 0 }, /* R27 - Audio Interface 3 */ - { 0x0000, 0x0000, 0 }, /* R28 */ - { 0x0000, 0x0000, 0 }, /* R29 */ - { 0x00FF, 0x01FF, 0 }, /* R30 - DAC Digital Volume Left */ - { 0x00FF, 0x01FF, 0 }, /* R31 - DAC Digital Volume Right */ - { 0x0FFF, 0x0FFF, 0 }, /* R32 - DAC Digital 0 */ - { 0x1E4E, 0x1E4E, 0 }, /* R33 - DAC Digital 1 */ - { 0x0000, 0x0000, 0 }, /* R34 */ - { 0x0000, 0x0000, 0 }, /* R35 */ - { 0x00FF, 0x01FF, 0 }, /* R36 - ADC Digital Volume Left */ - { 0x00FF, 0x01FF, 0 }, /* R37 - ADC Digital Volume Right */ - { 0x0073, 0x0073, 0 }, /* R38 - ADC Digital 0 */ - { 0x1800, 0x1800, 0 }, /* R39 - Digital Microphone 0 */ - { 0xDFEF, 0xDFEF, 0 }, /* R40 - DRC 0 */ - { 0xFFFF, 0xFFFF, 0 }, /* R41 - DRC 1 */ - { 0x003F, 0x003F, 0 }, /* R42 - DRC 2 */ - { 0x07FF, 0x07FF, 0 }, /* R43 - DRC 3 */ - { 0x009F, 0x009F, 0 }, /* R44 - Analogue Left Input 0 */ - { 0x009F, 0x009F, 0 }, /* R45 - Analogue Right Input 0 */ - { 0x007F, 0x007F, 0 }, /* R46 - Analogue Left Input 1 */ - { 0x007F, 0x007F, 0 }, /* R47 - Analogue Right Input 1 */ - { 0x0000, 0x0000, 0 }, /* R48 */ - { 0x0000, 0x0000, 0 }, /* R49 */ - { 0x0000, 0x0000, 0 }, /* R50 */ - { 0x0000, 0x0000, 0 }, /* R51 */ - { 0x0000, 0x0000, 0 }, /* R52 */ - { 0x0000, 0x0000, 0 }, /* R53 */ - { 0x0000, 0x0000, 0 }, /* R54 */ - { 0x0000, 0x0000, 0 }, /* R55 */ - { 0x0000, 0x0000, 0 }, /* R56 */ - { 0x017F, 0x01FF, 0 }, /* R57 - Analogue OUT1 Left */ - { 0x017F, 0x01FF, 0 }, /* R58 - Analogue OUT1 Right */ - { 0x017F, 0x01FF, 0 }, /* R59 - Analogue OUT2 Left */ - { 0x017F, 0x01FF, 0 }, /* R60 - Analogue OUT2 Right */ - { 0x000F, 0x000F, 0 }, /* R61 - Analogue OUT12 ZC */ - { 0x0000, 0x0000, 0 }, /* R62 */ - { 0x0000, 0x0000, 0 }, /* R63 */ - { 0x0000, 0x0000, 0 }, /* R64 */ - { 0x0000, 0x0000, 0 }, /* R65 */ - { 0x0000, 0x0000, 0 }, /* R66 */ - { 0x000F, 0x000F, 0 }, /* R67 - DC Servo 0 */ - { 0xFFFF, 0xFFFF, 1 }, /* R68 - DC Servo 1 */ - { 0x0F0F, 0x0F0F, 0 }, /* R69 - DC Servo 2 */ - { 0x0000, 0x0000, 0 }, /* R70 */ - { 0x007F, 0x007F, 0 }, /* R71 - DC Servo 4 */ - { 0x007F, 0x007F, 0 }, /* R72 - DC Servo 5 */ - { 0x00FF, 0x00FF, 1 }, /* R73 - DC Servo 6 */ - { 0x00FF, 0x00FF, 1 }, /* R74 - DC Servo 7 */ - { 0x00FF, 0x00FF, 1 }, /* R75 - DC Servo 8 */ - { 0x00FF, 0x00FF, 1 }, /* R76 - DC Servo 9 */ - { 0x0FFF, 0x0000, 1 }, /* R77 - DC Servo Readback 0 */ - { 0x0000, 0x0000, 0 }, /* R78 */ - { 0x0000, 0x0000, 0 }, /* R79 */ - { 0x0000, 0x0000, 0 }, /* R80 */ - { 0x0000, 0x0000, 0 }, /* R81 */ - { 0x0000, 0x0000, 0 }, /* R82 */ - { 0x0000, 0x0000, 0 }, /* R83 */ - { 0x0000, 0x0000, 0 }, /* R84 */ - { 0x0000, 0x0000, 0 }, /* R85 */ - { 0x0000, 0x0000, 0 }, /* R86 */ - { 0x0000, 0x0000, 0 }, /* R87 */ - { 0x0000, 0x0000, 0 }, /* R88 */ - { 0x0000, 0x0000, 0 }, /* R89 */ - { 0x00FF, 0x00FF, 0 }, /* R90 - Analogue HP 0 */ - { 0x0000, 0x0000, 0 }, /* R91 */ - { 0x0000, 0x0000, 0 }, /* R92 */ - { 0x0000, 0x0000, 0 }, /* R93 */ - { 0x00FF, 0x00FF, 0 }, /* R94 - Analogue Lineout 0 */ - { 0x0000, 0x0000, 0 }, /* R95 */ - { 0x0000, 0x0000, 0 }, /* R96 */ - { 0x0000, 0x0000, 0 }, /* R97 */ - { 0x0001, 0x0001, 0 }, /* R98 - Charge Pump 0 */ - { 0x0000, 0x0000, 0 }, /* R99 */ - { 0x0000, 0x0000, 0 }, /* R100 */ - { 0x0000, 0x0000, 0 }, /* R101 */ - { 0x0000, 0x0000, 0 }, /* R102 */ - { 0x0000, 0x0000, 0 }, /* R103 */ - { 0x0001, 0x0001, 0 }, /* R104 - Class W 0 */ - { 0x0000, 0x0000, 0 }, /* R105 */ - { 0x0000, 0x0000, 0 }, /* R106 */ - { 0x0000, 0x0000, 0 }, /* R107 */ - { 0x011F, 0x011F, 0 }, /* R108 - Write Sequencer 0 */ - { 0x7FFF, 0x7FFF, 0 }, /* R109 - Write Sequencer 1 */ - { 0x4FFF, 0x4FFF, 0 }, /* R110 - Write Sequencer 2 */ - { 0x003F, 0x033F, 0 }, /* R111 - Write Sequencer 3 */ - { 0x03F1, 0x0000, 0 }, /* R112 - Write Sequencer 4 */ - { 0x0000, 0x0000, 0 }, /* R113 */ - { 0x0000, 0x0000, 0 }, /* R114 */ - { 0x0000, 0x0000, 0 }, /* R115 */ - { 0x0007, 0x0007, 0 }, /* R116 - FLL Control 1 */ - { 0x3F77, 0x3F77, 0 }, /* R117 - FLL Control 2 */ - { 0xFFFF, 0xFFFF, 0 }, /* R118 - FLL Control 3 */ - { 0x7FEF, 0x7FEF, 0 }, /* R119 - FLL Control 4 */ - { 0x001B, 0x001B, 0 }, /* R120 - FLL Control 5 */ - { 0x003F, 0x003F, 0 }, /* R121 - GPIO Control 1 */ - { 0x003F, 0x003F, 0 }, /* R122 - GPIO Control 2 */ - { 0x003F, 0x003F, 0 }, /* R123 - GPIO Control 3 */ - { 0x038F, 0x038F, 0 }, /* R124 - GPIO Control 4 */ - { 0x0000, 0x0000, 0 }, /* R125 */ - { 0x00FF, 0x00FF, 0 }, /* R126 - Digital Pulls */ - { 0x07FF, 0x03FF, 1 }, /* R127 - Interrupt Status */ - { 0x03FF, 0x03FF, 0 }, /* R128 - Interrupt Status Mask */ - { 0x03FF, 0x03FF, 0 }, /* R129 - Interrupt Polarity */ - { 0x03FF, 0x03FF, 0 }, /* R130 - Interrupt Debounce */ - { 0x0000, 0x0000, 0 }, /* R131 */ - { 0x0000, 0x0000, 0 }, /* R132 */ - { 0x0000, 0x0000, 0 }, /* R133 */ - { 0x0001, 0x0001, 0 }, /* R134 - EQ1 */ - { 0x001F, 0x001F, 0 }, /* R135 - EQ2 */ - { 0x001F, 0x001F, 0 }, /* R136 - EQ3 */ - { 0x001F, 0x001F, 0 }, /* R137 - EQ4 */ - { 0x001F, 0x001F, 0 }, /* R138 - EQ5 */ - { 0x001F, 0x001F, 0 }, /* R139 - EQ6 */ - { 0xFFFF, 0xFFFF, 0 }, /* R140 - EQ7 */ - { 0xFFFF, 0xFFFF, 0 }, /* R141 - EQ8 */ - { 0xFFFF, 0xFFFF, 0 }, /* R142 - EQ9 */ - { 0xFFFF, 0xFFFF, 0 }, /* R143 - EQ10 */ - { 0xFFFF, 0xFFFF, 0 }, /* R144 - EQ11 */ - { 0xFFFF, 0xFFFF, 0 }, /* R145 - EQ12 */ - { 0xFFFF, 0xFFFF, 0 }, /* R146 - EQ13 */ - { 0xFFFF, 0xFFFF, 0 }, /* R147 - EQ14 */ - { 0xFFFF, 0xFFFF, 0 }, /* R148 - EQ15 */ - { 0xFFFF, 0xFFFF, 0 }, /* R149 - EQ16 */ - { 0xFFFF, 0xFFFF, 0 }, /* R150 - EQ17 */ - { 0xFFFF, 0xFFFF, 0 }, /* R151wm8523_dai - EQ18 */ - { 0xFFFF, 0xFFFF, 0 }, /* R152 - EQ19 */ - { 0xFFFF, 0xFFFF, 0 }, /* R153 - EQ20 */ - { 0xFFFF, 0xFFFF, 0 }, /* R154 - EQ21 */ - { 0xFFFF, 0xFFFF, 0 }, /* R155 - EQ22 */ - { 0xFFFF, 0xFFFF, 0 }, /* R156 - EQ23 */ - { 0xFFFF, 0xFFFF, 0 }, /* R157 - EQ24 */ - { 0x0000, 0x0000, 0 }, /* R158 */ - { 0x0000, 0x0000, 0 }, /* R159 */ - { 0x0000, 0x0000, 0 }, /* R160 */ - { 0x0002, 0x0002, 0 }, /* R161 - Control Interface Test 1 */ - { 0x0000, 0x0000, 0 }, /* R162 */ - { 0x0000, 0x0000, 0 }, /* R163 */ - { 0x0000, 0x0000, 0 }, /* R164 */ - { 0x0000, 0x0000, 0 }, /* R165 */ - { 0x0000, 0x0000, 0 }, /* R166 */ - { 0x0000, 0x0000, 0 }, /* R167 */ - { 0x0000, 0x0000, 0 }, /* R168 */ - { 0x0000, 0x0000, 0 }, /* R169 */ - { 0x0000, 0x0000, 0 }, /* R170 */ - { 0x0000, 0x0000, 0 }, /* R171 */ - { 0x0000, 0x0000, 0 }, /* R172 */ - { 0x0000, 0x0000, 0 }, /* R173 */ - { 0x0000, 0x0000, 0 }, /* R174 */ - { 0x0000, 0x0000, 0 }, /* R175 */ - { 0x0000, 0x0000, 0 }, /* R176 */ - { 0x0000, 0x0000, 0 }, /* R177 */ - { 0x0000, 0x0000, 0 }, /* R178 */ - { 0x0000, 0x0000, 0 }, /* R179 */ - { 0x0000, 0x0000, 0 }, /* R180 */ - { 0x0000, 0x0000, 0 }, /* R181 */ - { 0x0000, 0x0000, 0 }, /* R182 */ - { 0x0000, 0x0000, 0 }, /* R183 */ - { 0x0000, 0x0000, 0 }, /* R184 */ - { 0x0000, 0x0000, 0 }, /* R185 */ - { 0x0000, 0x0000, 0 }, /* R186 */ - { 0x0000, 0x0000, 0 }, /* R187 */ - { 0x0000, 0x0000, 0 }, /* R188 */ - { 0x0000, 0x0000, 0 }, /* R189 */ - { 0x0000, 0x0000, 0 }, /* R190 */ - { 0x0000, 0x0000, 0 }, /* R191 */ - { 0x0000, 0x0000, 0 }, /* R192 */ - { 0x0000, 0x0000, 0 }, /* R193 */ - { 0x0000, 0x0000, 0 }, /* R194 */ - { 0x0000, 0x0000, 0 }, /* R195 */ - { 0x0000, 0x0000, 0 }, /* R196 */ - { 0x0000, 0x0000, 0 }, /* R197 */ - { 0x0000, 0x0000, 0 }, /* R198 */ - { 0x0000, 0x0000, 0 }, /* R199 */ - { 0x0000, 0x0000, 0 }, /* R200 */ - { 0x0000, 0x0000, 0 }, /* R201 */ - { 0x0000, 0x0000, 0 }, /* R202 */ - { 0x0000, 0x0000, 0 }, /* R203 */ - { 0x0070, 0x0070, 0 }, /* R204 - Analogue Output Bias 0 */ - { 0x0000, 0x0000, 0 }, /* R205 */ - { 0x0000, 0x0000, 0 }, /* R206 */ - { 0x0000, 0x0000, 0 }, /* R207 */ - { 0x0000, 0x0000, 0 }, /* R208 */ - { 0x0000, 0x0000, 0 }, /* R209 */ - { 0x0000, 0x0000, 0 }, /* R210 */ - { 0x0000, 0x0000, 0 }, /* R211 */ - { 0x0000, 0x0000, 0 }, /* R212 */ - { 0x0000, 0x0000, 0 }, /* R213 */ - { 0x0000, 0x0000, 0 }, /* R214 */ - { 0x0000, 0x0000, 0 }, /* R215 */ - { 0x0000, 0x0000, 0 }, /* R216 */ - { 0x0000, 0x0000, 0 }, /* R217 */ - { 0x0000, 0x0000, 0 }, /* R218 */ - { 0x0000, 0x0000, 0 }, /* R219 */ - { 0x0000, 0x0000, 0 }, /* R220 */ - { 0x0000, 0x0000, 0 }, /* R221 */ - { 0x0000, 0x0000, 0 }, /* R222 */ - { 0x0000, 0x0000, 0 }, /* R223 */ - { 0x0000, 0x0000, 0 }, /* R224 */ - { 0x0000, 0x0000, 0 }, /* R225 */ - { 0x0000, 0x0000, 0 }, /* R226 */ - { 0x0000, 0x0000, 0 }, /* R227 */ - { 0x0000, 0x0000, 0 }, /* R228 */ - { 0x0000, 0x0000, 0 }, /* R229 */ - { 0x0000, 0x0000, 0 }, /* R230 */ - { 0x0000, 0x0000, 0 }, /* R231 */ - { 0x0000, 0x0000, 0 }, /* R232 */ - { 0x0000, 0x0000, 0 }, /* R233 */ - { 0x0000, 0x0000, 0 }, /* R234 */ - { 0x0000, 0x0000, 0 }, /* R235 */ - { 0x0000, 0x0000, 0 }, /* R236 */ - { 0x0000, 0x0000, 0 }, /* R237 */ - { 0x0000, 0x0000, 0 }, /* R238 */ - { 0x0000, 0x0000, 0 }, /* R239 */ - { 0x0000, 0x0000, 0 }, /* R240 */ - { 0x0000, 0x0000, 0 }, /* R241 */ - { 0x0000, 0x0000, 0 }, /* R242 */ - { 0x0000, 0x0000, 0 }, /* R243 */ - { 0x0000, 0x0000, 0 }, /* R244 */ - { 0x0000, 0x0000, 0 }, /* R245 */ - { 0x0000, 0x0000, 0 }, /* R246 */ - { 0x0001, 0x0001, 0 }, /* R247 - FLL NCO Test 0 */ - { 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */ -}; +static bool wm8904_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM8904_SW_RESET_AND_ID: + case WM8904_REVISION: + case WM8904_DC_SERVO_1: + case WM8904_DC_SERVO_6: + case WM8904_DC_SERVO_7: + case WM8904_DC_SERVO_8: + case WM8904_DC_SERVO_9: + case WM8904_DC_SERVO_READBACK_0: + case WM8904_INTERRUPT_STATUS: + return true; + default: + return false; + } +} -static int wm8904_volatile_register(struct snd_soc_codec *codec, unsigned int reg) +static bool wm8904_readable_register(struct device *dev, unsigned int reg) { - return wm8904_access[reg].vol; + switch (reg) { + case WM8904_SW_RESET_AND_ID: + case WM8904_REVISION: + case WM8904_BIAS_CONTROL_0: + case WM8904_VMID_CONTROL_0: + case WM8904_MIC_BIAS_CONTROL_0: + case WM8904_MIC_BIAS_CONTROL_1: + case WM8904_ANALOGUE_DAC_0: + case WM8904_MIC_FILTER_CONTROL: + case WM8904_ANALOGUE_ADC_0: + case WM8904_POWER_MANAGEMENT_0: + case WM8904_POWER_MANAGEMENT_2: + case WM8904_POWER_MANAGEMENT_3: + case WM8904_POWER_MANAGEMENT_6: + case WM8904_CLOCK_RATES_0: + case WM8904_CLOCK_RATES_1: + case WM8904_CLOCK_RATES_2: + case WM8904_AUDIO_INTERFACE_0: + case WM8904_AUDIO_INTERFACE_1: + case WM8904_AUDIO_INTERFACE_2: + case WM8904_AUDIO_INTERFACE_3: + case WM8904_DAC_DIGITAL_VOLUME_LEFT: + case WM8904_DAC_DIGITAL_VOLUME_RIGHT: + case WM8904_DAC_DIGITAL_0: + case WM8904_DAC_DIGITAL_1: + case WM8904_ADC_DIGITAL_VOLUME_LEFT: + case WM8904_ADC_DIGITAL_VOLUME_RIGHT: + case WM8904_ADC_DIGITAL_0: + case WM8904_DIGITAL_MICROPHONE_0: + case WM8904_DRC_0: + case WM8904_DRC_1: + case WM8904_DRC_2: + case WM8904_DRC_3: + case WM8904_ANALOGUE_LEFT_INPUT_0: + case WM8904_ANALOGUE_RIGHT_INPUT_0: + case WM8904_ANALOGUE_LEFT_INPUT_1: + case WM8904_ANALOGUE_RIGHT_INPUT_1: + case WM8904_ANALOGUE_OUT1_LEFT: + case WM8904_ANALOGUE_OUT1_RIGHT: + case WM8904_ANALOGUE_OUT2_LEFT: + case WM8904_ANALOGUE_OUT2_RIGHT: + case WM8904_ANALOGUE_OUT12_ZC: + case WM8904_DC_SERVO_0: + case WM8904_DC_SERVO_1: + case WM8904_DC_SERVO_2: + case WM8904_DC_SERVO_4: + case WM8904_DC_SERVO_5: + case WM8904_DC_SERVO_6: + case WM8904_DC_SERVO_7: + case WM8904_DC_SERVO_8: + case WM8904_DC_SERVO_9: + case WM8904_DC_SERVO_READBACK_0: + case WM8904_ANALOGUE_HP_0: + case WM8904_ANALOGUE_LINEOUT_0: + case WM8904_CHARGE_PUMP_0: + case WM8904_CLASS_W_0: + case WM8904_WRITE_SEQUENCER_0: + case WM8904_WRITE_SEQUENCER_1: + case WM8904_WRITE_SEQUENCER_2: + case WM8904_WRITE_SEQUENCER_3: + case WM8904_WRITE_SEQUENCER_4: + case WM8904_FLL_CONTROL_1: + case WM8904_FLL_CONTROL_2: + case WM8904_FLL_CONTROL_3: + case WM8904_FLL_CONTROL_4: + case WM8904_FLL_CONTROL_5: + case WM8904_GPIO_CONTROL_1: + case WM8904_GPIO_CONTROL_2: + case WM8904_GPIO_CONTROL_3: + case WM8904_GPIO_CONTROL_4: + case WM8904_DIGITAL_PULLS: + case WM8904_INTERRUPT_STATUS: + case WM8904_INTERRUPT_STATUS_MASK: + case WM8904_INTERRUPT_POLARITY: + case WM8904_INTERRUPT_DEBOUNCE: + case WM8904_EQ1: + case WM8904_EQ2: + case WM8904_EQ3: + case WM8904_EQ4: + case WM8904_EQ5: + case WM8904_EQ6: + case WM8904_EQ7: + case WM8904_EQ8: + case WM8904_EQ9: + case WM8904_EQ10: + case WM8904_EQ11: + case WM8904_EQ12: + case WM8904_EQ13: + case WM8904_EQ14: + case WM8904_EQ15: + case WM8904_EQ16: + case WM8904_EQ17: + case WM8904_EQ18: + case WM8904_EQ19: + case WM8904_EQ20: + case WM8904_EQ21: + case WM8904_EQ22: + case WM8904_EQ23: + case WM8904_EQ24: + case WM8904_CONTROL_INTERFACE_TEST_1: + case WM8904_ADC_TEST_0: + case WM8904_ANALOGUE_OUTPUT_BIAS_0: + case WM8904_FLL_NCO_TEST_0: + case WM8904_FLL_NCO_TEST_1: + return true; + default: + return true; + } } static int wm8904_reset(struct snd_soc_codec *codec) @@ -855,6 +570,29 @@ static const char *hpf_mode_text[] = { static const struct soc_enum hpf_mode = SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text); +static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int val; + int ret; + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + if (ret < 0) + return ret; + + if (ucontrol->value.integer.value[0]) + val = 0; + else + val = WM8904_ADC_128_OSR_TST_MODE | WM8904_ADC_BIASX1P5; + + snd_soc_update_bits(codec, WM8904_ADC_TEST_0, + WM8904_ADC_128_OSR_TST_MODE | WM8904_ADC_BIASX1P5, + val); + + return ret; +} + static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = { SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT, WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv), @@ -871,7 +609,12 @@ SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0, SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0), SOC_ENUM("High Pass Filter Mode", hpf_mode), -SOC_SINGLE("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0), +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC 128x OSR Switch", + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, + .put = wm8904_adc_osr_put, + .private_value = SOC_SINGLE_VALUE(WM8904_ANALOGUE_ADC_0, 0, 1, 0), +}, }; static const char *drc_path_text[] = { @@ -1433,11 +1176,11 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec) switch (wm8904->devtype) { case WM8904: - snd_soc_add_controls(codec, wm8904_adc_snd_controls, + snd_soc_add_codec_controls(codec, wm8904_adc_snd_controls, ARRAY_SIZE(wm8904_adc_snd_controls)); - snd_soc_add_controls(codec, wm8904_dac_snd_controls, + snd_soc_add_codec_controls(codec, wm8904_dac_snd_controls, ARRAY_SIZE(wm8904_dac_snd_controls)); - snd_soc_add_controls(codec, wm8904_snd_controls, + snd_soc_add_codec_controls(codec, wm8904_snd_controls, ARRAY_SIZE(wm8904_snd_controls)); snd_soc_dapm_new_controls(dapm, wm8904_adc_dapm_widgets, @@ -1458,7 +1201,7 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec) break; case WM8912: - snd_soc_add_controls(codec, wm8904_dac_snd_controls, + snd_soc_add_codec_controls(codec, wm8904_dac_snd_controls, ARRAY_SIZE(wm8904_dac_snd_controls)); snd_soc_dapm_new_controls(dapm, wm8904_dac_dapm_widgets, @@ -2088,32 +1831,6 @@ static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } -static void wm8904_sync_cache(struct snd_soc_codec *codec) -{ - u16 *reg_cache = codec->reg_cache; - int i; - - if (!codec->cache_sync) - return; - - codec->cache_only = 0; - - /* Sync back cached values if they're different from the - * hardware default. - */ - for (i = 1; i < codec->driver->reg_cache_size; i++) { - if (!wm8904_access[i].writable) - continue; - - if (reg_cache[i] == wm8904_reg[i]) - continue; - - snd_soc_write(codec, i, reg_cache[i]); - } - - codec->cache_sync = 0; -} - static int wm8904_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -2146,7 +1863,7 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, return ret; } - wm8904_sync_cache(codec); + regcache_sync(wm8904->regmap); /* Enable bias */ snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, @@ -2303,7 +2020,7 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec) wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts; wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts; - ret = snd_soc_add_controls(codec, &control, 1); + ret = snd_soc_add_codec_controls(codec, &control, 1); if (ret != 0) dev_err(codec->dev, "Failed to add ReTune Mobile control: %d\n", ret); @@ -2316,7 +2033,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec) int ret, i; if (!pdata) { - snd_soc_add_controls(codec, wm8904_eq_controls, + snd_soc_add_codec_controls(codec, wm8904_eq_controls, ARRAY_SIZE(wm8904_eq_controls)); return; } @@ -2344,7 +2061,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec) wm8904->drc_enum.max = pdata->num_drc_cfgs; wm8904->drc_enum.texts = wm8904->drc_texts; - ret = snd_soc_add_controls(codec, &control, 1); + ret = snd_soc_add_codec_controls(codec, &control, 1); if (ret != 0) dev_err(codec->dev, "Failed to add DRC mode control: %d\n", ret); @@ -2358,7 +2075,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec) if (pdata->num_retune_mobile_cfgs) wm8904_handle_retune_mobile_pdata(codec); else - snd_soc_add_controls(codec, wm8904_eq_controls, + snd_soc_add_codec_controls(codec, wm8904_eq_controls, ARRAY_SIZE(wm8904_eq_controls)); } @@ -2371,7 +2088,7 @@ static int wm8904_probe(struct snd_soc_codec *codec) int ret, i; codec->cache_sync = 1; - codec->dapm.idle_bias_off = 1; + codec->control_data = wm8904->regmap; switch (wm8904->devtype) { case WM8904: @@ -2385,7 +2102,7 @@ static int wm8904_probe(struct snd_soc_codec *codec) return -EINVAL; } - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -2413,7 +2130,7 @@ static int wm8904_probe(struct snd_soc_codec *codec) dev_err(codec->dev, "Failed to read ID register\n"); goto err_enable; } - if (ret != wm8904_reg[WM8904_SW_RESET_AND_ID]) { + if (ret != 0x8904) { dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret); ret = -EINVAL; goto err_enable; @@ -2519,38 +2236,62 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8904 = { .suspend = wm8904_suspend, .resume = wm8904_resume, .set_bias_level = wm8904_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8904_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8904_reg, - .volatile_register = wm8904_volatile_register, + .idle_bias_off = true, +}; + +static const struct regmap_config wm8904_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = WM8904_MAX_REGISTER, + .volatile_reg = wm8904_volatile_register, + .readable_reg = wm8904_readable_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8904_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults), }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8904_priv *wm8904; int ret; - wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL); + wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv), + GFP_KERNEL); if (wm8904 == NULL) return -ENOMEM; + wm8904->regmap = regmap_init_i2c(i2c, &wm8904_regmap); + if (IS_ERR(wm8904->regmap)) { + ret = PTR_ERR(wm8904->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + wm8904->devtype = id->driver_data; i2c_set_clientdata(i2c, wm8904); wm8904->pdata = i2c->dev.platform_data; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8904, &wm8904_dai, 1); - if (ret < 0) - kfree(wm8904); + if (ret != 0) + goto err; + + return 0; + +err: + regmap_exit(wm8904->regmap); return ret; } static __devexit int wm8904_i2c_remove(struct i2c_client *client) { + struct wm8904_priv *wm8904 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + regmap_exit(wm8904->regmap); return 0; } @@ -2571,27 +2312,22 @@ static struct i2c_driver wm8904_i2c_driver = { .remove = __devexit_p(wm8904_i2c_remove), .id_table = wm8904_i2c_id, }; -#endif static int __init wm8904_modinit(void) { int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ret = i2c_add_driver(&wm8904_i2c_driver); if (ret != 0) { printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n", ret); } -#endif return ret; } module_init(wm8904_modinit); static void __exit wm8904_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&wm8904_i2c_driver); -#endif } module_exit(wm8904_exit); diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h index 9e8c84188ba..c29a0e8131c 100644 --- a/sound/soc/codecs/wm8904.h +++ b/sound/soc/codecs/wm8904.h @@ -123,6 +123,7 @@ #define WM8904_EQ23 0x9C #define WM8904_EQ24 0x9D #define WM8904_CONTROL_INTERFACE_TEST_1 0xA1 +#define WM8904_ADC_TEST_0 0xC6 #define WM8904_ANALOGUE_OUTPUT_BIAS_0 0xCC #define WM8904_FLL_NCO_TEST_0 0xF7 #define WM8904_FLL_NCO_TEST_1 0xF8 @@ -1557,6 +1558,16 @@ #define WM8904_USER_KEY_WIDTH 1 /* USER_KEY */ /* + * R198 (0xC6) - ADC Test 0 + */ +#define WM8904_ADC_128_OSR_TST_MODE 0x0004 /* ADC_128_OSR_TST_MODE */ +#define WM8904_ADC_128_OSR_TST_MODE_SHIFT 2 /* ADC_128_OSR_TST_MODE */ +#define WM8904_ADC_128_OSR_TST_MODE_WIDTH 1 /* ADC_128_OSR_TST_MODE */ +#define WM8904_ADC_BIASX1P5 0x0001 /* ADC_BIASX1P5 */ +#define WM8904_ADC_BIASX1P5_SHIFT 0 /* ADC_BIASX1P5 */ +#define WM8904_ADC_BIASX1P5_WIDTH 1 /* ADC_BIASX1P5 */ + +/* * R204 (0xCC) - Analogue Output Bias 0 */ #define WM8904_PGA_BIAS_MASK 0x0070 /* PGA_BIAS - [6:4] */ diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 14039ea2f3e..d2883affea3 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -717,7 +717,7 @@ static int wm8940_probe(struct snd_soc_codec *codec) return ret; } - ret = snd_soc_add_controls(codec, wm8940_snd_controls, + ret = snd_soc_add_codec_controls(codec, wm8940_snd_controls, ARRAY_SIZE(wm8940_snd_controls)); if (ret) return ret; @@ -743,14 +743,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { .volatile_register = wm8940_volatile_register, }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8940_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8940_priv *wm8940; int ret; - wm8940 = kzalloc(sizeof(struct wm8940_priv), GFP_KERNEL); + wm8940 = devm_kzalloc(&i2c->dev, sizeof(struct wm8940_priv), + GFP_KERNEL); if (wm8940 == NULL) return -ENOMEM; @@ -759,15 +759,14 @@ static __devinit int wm8940_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8940, &wm8940_dai, 1); - if (ret < 0) - kfree(wm8940); + return ret; } static __devexit int wm8940_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + return 0; } @@ -786,27 +785,22 @@ static struct i2c_driver wm8940_i2c_driver = { .remove = __devexit_p(wm8940_i2c_remove), .id_table = wm8940_i2c_id, }; -#endif static int __init wm8940_modinit(void) { int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ret = i2c_add_driver(&wm8940_i2c_driver); if (ret != 0) { printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n", ret); } -#endif return ret; } module_init(wm8940_modinit); static void __exit wm8940_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&wm8940_i2c_driver); -#endif } module_exit(wm8940_exit); diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 924548182d5..61fe97433e7 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/core.h> @@ -38,7 +39,7 @@ static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = { /* codec private data */ struct wm8955_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; unsigned int mclk_rate; @@ -48,69 +49,85 @@ struct wm8955_priv { struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES]; }; -static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = { - 0x0000, /* R0 */ - 0x0000, /* R1 */ - 0x0079, /* R2 - LOUT1 volume */ - 0x0079, /* R3 - ROUT1 volume */ - 0x0000, /* R4 */ - 0x0008, /* R5 - DAC Control */ - 0x0000, /* R6 */ - 0x000A, /* R7 - Audio Interface */ - 0x0000, /* R8 - Sample Rate */ - 0x0000, /* R9 */ - 0x00FF, /* R10 - Left DAC volume */ - 0x00FF, /* R11 - Right DAC volume */ - 0x000F, /* R12 - Bass control */ - 0x000F, /* R13 - Treble control */ - 0x0000, /* R14 */ - 0x0000, /* R15 - Reset */ - 0x0000, /* R16 */ - 0x0000, /* R17 */ - 0x0000, /* R18 */ - 0x0000, /* R19 */ - 0x0000, /* R20 */ - 0x0000, /* R21 */ - 0x0000, /* R22 */ - 0x00C1, /* R23 - Additional control (1) */ - 0x0000, /* R24 - Additional control (2) */ - 0x0000, /* R25 - Power Management (1) */ - 0x0000, /* R26 - Power Management (2) */ - 0x0000, /* R27 - Additional Control (3) */ - 0x0000, /* R28 */ - 0x0000, /* R29 */ - 0x0000, /* R30 */ - 0x0000, /* R31 */ - 0x0000, /* R32 */ - 0x0000, /* R33 */ - 0x0050, /* R34 - Left out Mix (1) */ - 0x0050, /* R35 - Left out Mix (2) */ - 0x0050, /* R36 - Right out Mix (1) */ - 0x0050, /* R37 - Right Out Mix (2) */ - 0x0050, /* R38 - Mono out Mix (1) */ - 0x0050, /* R39 - Mono out Mix (2) */ - 0x0079, /* R40 - LOUT2 volume */ - 0x0079, /* R41 - ROUT2 volume */ - 0x0079, /* R42 - MONOOUT volume */ - 0x0000, /* R43 - Clocking / PLL */ - 0x0103, /* R44 - PLL Control 1 */ - 0x0024, /* R45 - PLL Control 2 */ - 0x01BA, /* R46 - PLL Control 3 */ - 0x0000, /* R47 */ - 0x0000, /* R48 */ - 0x0000, /* R49 */ - 0x0000, /* R50 */ - 0x0000, /* R51 */ - 0x0000, /* R52 */ - 0x0000, /* R53 */ - 0x0000, /* R54 */ - 0x0000, /* R55 */ - 0x0000, /* R56 */ - 0x0000, /* R57 */ - 0x0000, /* R58 */ - 0x0000, /* R59 - PLL Control 4 */ +static const struct reg_default wm8955_reg_defaults[] = { + { 2, 0x0079 }, /* R2 - LOUT1 volume */ + { 3, 0x0079 }, /* R3 - ROUT1 volume */ + { 5, 0x0008 }, /* R5 - DAC Control */ + { 7, 0x000A }, /* R7 - Audio Interface */ + { 8, 0x0000 }, /* R8 - Sample Rate */ + { 10, 0x00FF }, /* R10 - Left DAC volume */ + { 11, 0x00FF }, /* R11 - Right DAC volume */ + { 12, 0x000F }, /* R12 - Bass control */ + { 13, 0x000F }, /* R13 - Treble control */ + { 23, 0x00C1 }, /* R23 - Additional control (1) */ + { 24, 0x0000 }, /* R24 - Additional control (2) */ + { 25, 0x0000 }, /* R25 - Power Management (1) */ + { 26, 0x0000 }, /* R26 - Power Management (2) */ + { 27, 0x0000 }, /* R27 - Additional Control (3) */ + { 34, 0x0050 }, /* R34 - Left out Mix (1) */ + { 35, 0x0050 }, /* R35 - Left out Mix (2) */ + { 36, 0x0050 }, /* R36 - Right out Mix (1) */ + { 37, 0x0050 }, /* R37 - Right Out Mix (2) */ + { 38, 0x0050 }, /* R38 - Mono out Mix (1) */ + { 39, 0x0050 }, /* R39 - Mono out Mix (2) */ + { 40, 0x0079 }, /* R40 - LOUT2 volume */ + { 41, 0x0079 }, /* R41 - ROUT2 volume */ + { 42, 0x0079 }, /* R42 - MONOOUT volume */ + { 43, 0x0000 }, /* R43 - Clocking / PLL */ + { 44, 0x0103 }, /* R44 - PLL Control 1 */ + { 45, 0x0024 }, /* R45 - PLL Control 2 */ + { 46, 0x01BA }, /* R46 - PLL Control 3 */ + { 59, 0x0000 }, /* R59 - PLL Control 4 */ }; +static bool wm8955_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM8955_LOUT1_VOLUME: + case WM8955_ROUT1_VOLUME: + case WM8955_DAC_CONTROL: + case WM8955_AUDIO_INTERFACE: + case WM8955_SAMPLE_RATE: + case WM8955_LEFT_DAC_VOLUME: + case WM8955_RIGHT_DAC_VOLUME: + case WM8955_BASS_CONTROL: + case WM8955_TREBLE_CONTROL: + case WM8955_RESET: + case WM8955_ADDITIONAL_CONTROL_1: + case WM8955_ADDITIONAL_CONTROL_2: + case WM8955_POWER_MANAGEMENT_1: + case WM8955_POWER_MANAGEMENT_2: + case WM8955_ADDITIONAL_CONTROL_3: + case WM8955_LEFT_OUT_MIX_1: + case WM8955_LEFT_OUT_MIX_2: + case WM8955_RIGHT_OUT_MIX_1: + case WM8955_RIGHT_OUT_MIX_2: + case WM8955_MONO_OUT_MIX_1: + case WM8955_MONO_OUT_MIX_2: + case WM8955_LOUT2_VOLUME: + case WM8955_ROUT2_VOLUME: + case WM8955_MONOOUT_VOLUME: + case WM8955_CLOCKING_PLL: + case WM8955_PLL_CONTROL_1: + case WM8955_PLL_CONTROL_2: + case WM8955_PLL_CONTROL_3: + case WM8955_PLL_CONTROL_4: + return true; + default: + return false; + } +} + +static bool wm8955_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM8955_RESET: + return true; + default: + return false; + } +} + static int wm8955_reset(struct snd_soc_codec *codec) { return snd_soc_write(codec, WM8955_RESET, 0); @@ -527,7 +544,7 @@ SND_SOC_DAPM_OUTPUT("MONOOUT"), SND_SOC_DAPM_OUTPUT("OUT3"), }; -static const struct snd_soc_dapm_route wm8955_intercon[] = { +static const struct snd_soc_dapm_route wm8955_dapm_routes[] = { { "DACL", NULL, "SYSCLK" }, { "DACR", NULL, "SYSCLK" }, @@ -572,21 +589,6 @@ static const struct snd_soc_dapm_route wm8955_intercon[] = { { "OUT3", NULL, "OUT3 PGA" }, }; -static int wm8955_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_add_controls(codec, wm8955_snd_controls, - ARRAY_SIZE(wm8955_snd_controls)); - - snd_soc_dapm_new_controls(dapm, wm8955_dapm_widgets, - ARRAY_SIZE(wm8955_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, wm8955_intercon, - ARRAY_SIZE(wm8955_intercon)); - - return 0; -} - static int wm8955_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -765,8 +767,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); - u16 *reg_cache = codec->reg_cache; - int ret, i; + int ret; switch (level) { case SND_SOC_BIAS_ON: @@ -795,18 +796,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec, return ret; } - /* Sync back cached values if they're - * different from the hardware default. - */ - for (i = 0; i < codec->driver->reg_cache_size; i++) { - if (i == WM8955_RESET) - continue; - - if (reg_cache[i] == wm8955_reg[i]) - continue; - - snd_soc_write(codec, i, reg_cache[i]); - } + regcache_sync(wm8955->regmap); /* Enable VREF and VMID */ snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, @@ -880,8 +870,12 @@ static struct snd_soc_dai_driver wm8955_dai = { #ifdef CONFIG_PM static int wm8955_suspend(struct snd_soc_codec *codec) { + struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); + wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); + regcache_mark_dirty(wm8955->regmap); + return 0; } @@ -900,10 +894,11 @@ static int wm8955_probe(struct snd_soc_codec *codec) { struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); struct wm8955_pdata *pdata = dev_get_platdata(codec->dev); - u16 *reg_cache = codec->reg_cache; int ret, i; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type); + codec->control_data = wm8955->regmap; + + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -958,12 +953,12 @@ static int wm8955_probe(struct snd_soc_codec *codec) /* Set platform data values */ if (pdata) { if (pdata->out2_speaker) - reg_cache[WM8955_ADDITIONAL_CONTROL_2] - |= WM8955_ROUT2INV; + snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_2, + WM8955_ROUT2INV, WM8955_ROUT2INV); if (pdata->monoin_diff) - reg_cache[WM8955_MONO_OUT_MIX_1] - |= WM8955_DMEN; + snd_soc_update_bits(codec, WM8955_MONO_OUT_MIX_1, + WM8955_DMEN, WM8955_DMEN); } wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -971,7 +966,6 @@ static int wm8955_probe(struct snd_soc_codec *codec) /* Bias level configuration will have done an extra enable */ regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); - wm8955_add_widgets(codec); return 0; err_enable: @@ -996,36 +990,68 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { .suspend = wm8955_suspend, .resume = wm8955_resume, .set_bias_level = wm8955_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8955_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8955_reg, + + .controls = wm8955_snd_controls, + .num_controls = ARRAY_SIZE(wm8955_snd_controls), + .dapm_widgets = wm8955_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8955_dapm_widgets), + .dapm_routes = wm8955_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8955_dapm_routes), +}; + +static const struct regmap_config wm8955_regmap = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = WM8955_MAX_REGISTER, + .volatile_reg = wm8955_volatile, + .writeable_reg = wm8955_writeable, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8955_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults), }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8955_priv *wm8955; int ret; - wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL); + wm8955 = devm_kzalloc(&i2c->dev, sizeof(struct wm8955_priv), + GFP_KERNEL); if (wm8955 == NULL) return -ENOMEM; + wm8955->regmap = regmap_init_i2c(i2c, &wm8955_regmap); + if (IS_ERR(wm8955->regmap)) { + ret = PTR_ERR(wm8955->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + i2c_set_clientdata(i2c, wm8955); - wm8955->control_type = SND_SOC_I2C; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8955, &wm8955_dai, 1); - if (ret < 0) - kfree(wm8955); + if (ret != 0) + goto err; + + return ret; + +err: + regmap_exit(wm8955->regmap); return ret; } static __devexit int wm8955_i2c_remove(struct i2c_client *client) { + struct wm8955_priv *wm8955 = i2c_get_clientdata(client); + snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + regmap_exit(wm8955->regmap); + return 0; } @@ -1044,27 +1070,22 @@ static struct i2c_driver wm8955_i2c_driver = { .remove = __devexit_p(wm8955_i2c_remove), .id_table = wm8955_i2c_id, }; -#endif static int __init wm8955_modinit(void) { int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ret = i2c_add_driver(&wm8955_i2c_driver); if (ret != 0) { printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n", ret); } -#endif return ret; } module_init(wm8955_modinit); static void __exit wm8955_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&wm8955_i2c_driver); -#endif } module_exit(wm8955_exit); diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 40ac888faf3..1332692ef81 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -920,11 +920,11 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->dsp_active = -1; - snd_soc_add_controls(codec, wm8958_mbc_snd_controls, + snd_soc_add_codec_controls(codec, wm8958_mbc_snd_controls, ARRAY_SIZE(wm8958_mbc_snd_controls)); - snd_soc_add_controls(codec, wm8958_vss_snd_controls, + snd_soc_add_codec_controls(codec, wm8958_vss_snd_controls, ARRAY_SIZE(wm8958_vss_snd_controls)); - snd_soc_add_controls(codec, wm8958_enh_eq_snd_controls, + snd_soc_add_codec_controls(codec, wm8958_enh_eq_snd_controls, ARRAY_SIZE(wm8958_enh_eq_snd_controls)); @@ -958,7 +958,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->mbc_enum.max = pdata->num_mbc_cfgs; wm8994->mbc_enum.texts = wm8994->mbc_texts; - ret = snd_soc_add_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); if (ret != 0) dev_err(wm8994->codec->dev, "Failed to add MBC mode controls: %d\n", ret); @@ -986,7 +986,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->vss_enum.max = pdata->num_vss_cfgs; wm8994->vss_enum.texts = wm8994->vss_texts; - ret = snd_soc_add_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); if (ret != 0) dev_err(wm8994->codec->dev, "Failed to add VSS mode controls: %d\n", ret); @@ -1015,7 +1015,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) 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); + ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); if (ret != 0) dev_err(wm8994->codec->dev, "Failed to add VSS HPFmode controls: %d\n", @@ -1045,7 +1045,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) 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); + ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); if (ret != 0) dev_err(wm8994->codec->dev, "Failed to add enhanced EQ controls: %d\n", diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index e5caae32e54..840d72086d0 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -940,7 +940,7 @@ static int wm8960_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100); snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100); - snd_soc_add_controls(codec, wm8960_snd_controls, + snd_soc_add_codec_controls(codec, wm8960_snd_controls, ARRAY_SIZE(wm8960_snd_controls)); wm8960_add_widgets(codec); diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 4f20c72a0f1..05ea7c27409 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -1022,7 +1022,7 @@ static int wm8961_probe(struct snd_soc_codec *codec) wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_controls(codec, wm8961_snd_controls, + snd_soc_add_codec_controls(codec, wm8961_snd_controls, ARRAY_SIZE(wm8961_snd_controls)); snd_soc_dapm_new_controls(dapm, wm8961_dapm_widgets, ARRAY_SIZE(wm8961_dapm_widgets)); diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 0ac228b7dc0..15d467ff91b 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -20,6 +20,7 @@ #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/input.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -115,11 +116,11 @@ static struct reg_default wm8962_reg[] = { { 1, 0x049F }, /* R1 - Right Input volume */ { 2, 0x0000 }, /* R2 - HPOUTL volume */ { 3, 0x0000 }, /* R3 - HPOUTR volume */ - { 4, 0x0020 }, /* R4 - Clocking1 */ + { 5, 0x0018 }, /* R5 - ADC & DAC Control 1 */ { 6, 0x2008 }, /* R6 - ADC & DAC Control 2 */ { 7, 0x000A }, /* R7 - Audio Interface 0 */ - { 8, 0x01E4 }, /* R8 - Clocking2 */ + { 9, 0x0300 }, /* R9 - Audio Interface 1 */ { 10, 0x00C0 }, /* R10 - Left DAC volume */ { 11, 0x00C0 }, /* R11 - Right DAC volume */ @@ -128,7 +129,7 @@ static struct reg_default wm8962_reg[] = { { 15, 0x6243 }, /* R15 - Software Reset */ { 17, 0x007B }, /* R17 - ALC1 */ - { 18, 0x0000 }, /* R18 - ALC2 */ + { 19, 0x1C32 }, /* R19 - ALC3 */ { 20, 0x3200 }, /* R20 - Noise Gate */ { 21, 0x00C0 }, /* R21 - Left ADC volume */ @@ -152,10 +153,6 @@ static struct reg_default wm8962_reg[] = { { 40, 0x0000 }, /* R40 - SPKOUTL volume */ { 41, 0x0000 }, /* R41 - SPKOUTR volume */ - { 47, 0x0000 }, /* R47 - Thermal Shutdown Status */ - { 48, 0x8027 }, /* R48 - Additional Control (4) */ - { 49, 0x0010 }, /* R49 - Class D Control 1 */ - { 51, 0x0003 }, /* R51 - Class D Control 2 */ { 56, 0x0506 }, /* R56 - Clocking 4 */ @@ -167,8 +164,6 @@ static struct reg_default wm8962_reg[] = { { 64, 0x0810 }, /* R64 - DC Servo 4 */ - { 66, 0x0000 }, /* R66 - DC Servo 6 */ - { 68, 0x001B }, /* R68 - Analogue PGA Bias */ { 69, 0x0000 }, /* R69 - Analogue HP 0 */ @@ -207,8 +202,6 @@ static struct reg_default wm8962_reg[] = { { 126, 0x000D }, /* R126 - Analogue Clocking3 */ { 127, 0x0000 }, /* R127 - PLL Software Reset */ - { 129, 0x0000 }, /* R129 - PLL2 */ - { 131, 0x0000 }, /* R131 - PLL 4 */ { 136, 0x0067 }, /* R136 - PLL 9 */ @@ -303,9 +296,6 @@ static struct reg_default wm8962_reg[] = { { 516, 0x8100 }, /* R516 - GPIO 5 */ { 517, 0x8100 }, /* R517 - GPIO 6 */ - { 560, 0x0000 }, /* R560 - Interrupt Status 1 */ - { 561, 0x0000 }, /* R561 - Interrupt Status 2 */ - { 568, 0x0030 }, /* R568 - Interrupt Status 1 Mask */ { 569, 0xFFED }, /* R569 - Interrupt Status 2 Mask */ @@ -317,8 +307,6 @@ static struct reg_default wm8962_reg[] = { { 768, 0x1C00 }, /* R768 - DSP2 Power Management */ - { 1037, 0x0000 }, /* R1037 - DSP2_ExecControl */ - { 8192, 0x0000 }, /* R8192 - DSP2 Instruction RAM 0 */ { 9216, 0x0030 }, /* R9216 - DSP2 Address RAM 2 */ @@ -797,1167 +785,660 @@ static struct reg_default wm8962_reg[] = { { 21139, 0x8580 }, /* R21139 - VSS_XTS32_0 */ }; -static const struct wm8962_reg_access { - u16 read; - u16 write; - u16 vol; -} wm8962_reg_access[WM8962_MAX_REGISTER + 1] = { - [0] = { 0x00FF, 0x01FF, 0x0000 }, /* R0 - Left Input volume */ - [1] = { 0xFEFF, 0x01FF, 0x0000 }, /* R1 - Right Input volume */ - [2] = { 0x00FF, 0x01FF, 0x0000 }, /* R2 - HPOUTL volume */ - [3] = { 0x00FF, 0x01FF, 0x0000 }, /* R3 - HPOUTR volume */ - [4] = { 0x07FE, 0x07FE, 0xFFFF }, /* R4 - Clocking1 */ - [5] = { 0x007F, 0x007F, 0x0000 }, /* R5 - ADC & DAC Control 1 */ - [6] = { 0x37ED, 0x37ED, 0x0000 }, /* R6 - ADC & DAC Control 2 */ - [7] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R7 - Audio Interface 0 */ - [8] = { 0x0FEF, 0x0FEF, 0xFFFF }, /* R8 - Clocking2 */ - [9] = { 0x0B9F, 0x039F, 0x0000 }, /* R9 - Audio Interface 1 */ - [10] = { 0x00FF, 0x01FF, 0x0000 }, /* R10 - Left DAC volume */ - [11] = { 0x00FF, 0x01FF, 0x0000 }, /* R11 - Right DAC volume */ - [14] = { 0x07FF, 0x07FF, 0x0000 }, /* R14 - Audio Interface 2 */ - [15] = { 0xFFFF, 0xFFFF, 0xFFFF }, /* R15 - Software Reset */ - [17] = { 0x07FF, 0x07FF, 0x0000 }, /* R17 - ALC1 */ - [18] = { 0xF8FF, 0x00FF, 0xFFFF }, /* R18 - ALC2 */ - [19] = { 0x1DFF, 0x1DFF, 0x0000 }, /* R19 - ALC3 */ - [20] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20 - Noise Gate */ - [21] = { 0x00FF, 0x01FF, 0x0000 }, /* R21 - Left ADC volume */ - [22] = { 0x00FF, 0x01FF, 0x0000 }, /* R22 - Right ADC volume */ - [23] = { 0x0161, 0x0161, 0x0000 }, /* R23 - Additional control(1) */ - [24] = { 0x0008, 0x0008, 0x0000 }, /* R24 - Additional control(2) */ - [25] = { 0x07FE, 0x07FE, 0x0000 }, /* R25 - Pwr Mgmt (1) */ - [26] = { 0x01FB, 0x01FB, 0x0000 }, /* R26 - Pwr Mgmt (2) */ - [27] = { 0x0017, 0x0017, 0x0000 }, /* R27 - Additional Control (3) */ - [28] = { 0x001C, 0x001C, 0x0000 }, /* R28 - Anti-pop */ - - [30] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R30 - Clocking 3 */ - [31] = { 0x000F, 0x000F, 0x0000 }, /* R31 - Input mixer control (1) */ - [32] = { 0x01FF, 0x01FF, 0x0000 }, /* R32 - Left input mixer volume */ - [33] = { 0x01FF, 0x01FF, 0x0000 }, /* R33 - Right input mixer volume */ - [34] = { 0x003F, 0x003F, 0x0000 }, /* R34 - Input mixer control (2) */ - [35] = { 0x003F, 0x003F, 0x0000 }, /* R35 - Input bias control */ - [37] = { 0x001F, 0x001F, 0x0000 }, /* R37 - Left input PGA control */ - [38] = { 0x001F, 0x001F, 0x0000 }, /* R38 - Right input PGA control */ - [40] = { 0x00FF, 0x01FF, 0x0000 }, /* R40 - SPKOUTL volume */ - [41] = { 0x00FF, 0x01FF, 0x0000 }, /* R41 - SPKOUTR volume */ - - [47] = { 0x000F, 0x0000, 0xFFFF }, /* R47 - Thermal Shutdown Status */ - [48] = { 0x7EC7, 0x7E07, 0xFFFF }, /* R48 - Additional Control (4) */ - [49] = { 0x00D3, 0x00D7, 0xFFFF }, /* R49 - Class D Control 1 */ - [51] = { 0x0047, 0x0047, 0x0000 }, /* R51 - Class D Control 2 */ - [56] = { 0x001E, 0x001E, 0x0000 }, /* R56 - Clocking 4 */ - [57] = { 0x02FC, 0x02FC, 0x0000 }, /* R57 - DAC DSP Mixing (1) */ - [58] = { 0x00FC, 0x00FC, 0x0000 }, /* R58 - DAC DSP Mixing (2) */ - [60] = { 0x00CC, 0x00CC, 0x0000 }, /* R60 - DC Servo 0 */ - [61] = { 0x00DD, 0x00DD, 0x0000 }, /* R61 - DC Servo 1 */ - [64] = { 0x3F80, 0x3F80, 0x0000 }, /* R64 - DC Servo 4 */ - [66] = { 0x0780, 0x0000, 0xFFFF }, /* R66 - DC Servo 6 */ - [68] = { 0x0007, 0x0007, 0x0000 }, /* R68 - Analogue PGA Bias */ - [69] = { 0x00FF, 0x00FF, 0x0000 }, /* R69 - Analogue HP 0 */ - [71] = { 0x01FF, 0x01FF, 0x0000 }, /* R71 - Analogue HP 2 */ - [72] = { 0x0001, 0x0001, 0x0000 }, /* R72 - Charge Pump 1 */ - [82] = { 0x0001, 0x0001, 0x0000 }, /* R82 - Charge Pump B */ - [87] = { 0x00A0, 0x00A0, 0x0000 }, /* R87 - Write Sequencer Control 1 */ - [90] = { 0x007F, 0x01FF, 0x0000 }, /* R90 - Write Sequencer Control 2 */ - [93] = { 0x03F9, 0x0000, 0x0000 }, /* R93 - Write Sequencer Control 3 */ - [94] = { 0x0070, 0x0070, 0x0000 }, /* R94 - Control Interface */ - [99] = { 0x000F, 0x000F, 0x0000 }, /* R99 - Mixer Enables */ - [100] = { 0x00BF, 0x00BF, 0x0000 }, /* R100 - Headphone Mixer (1) */ - [101] = { 0x00BF, 0x00BF, 0x0000 }, /* R101 - Headphone Mixer (2) */ - [102] = { 0x01FF, 0x01FF, 0x0000 }, /* R102 - Headphone Mixer (3) */ - [103] = { 0x01FF, 0x01FF, 0x0000 }, /* R103 - Headphone Mixer (4) */ - [105] = { 0x00BF, 0x00BF, 0x0000 }, /* R105 - Speaker Mixer (1) */ - [106] = { 0x00BF, 0x00BF, 0x0000 }, /* R106 - Speaker Mixer (2) */ - [107] = { 0x01FF, 0x01FF, 0x0000 }, /* R107 - Speaker Mixer (3) */ - [108] = { 0x01FF, 0x01FF, 0x0000 }, /* R108 - Speaker Mixer (4) */ - [109] = { 0x00F0, 0x00F0, 0x0000 }, /* R109 - Speaker Mixer (5) */ - [110] = { 0x00F7, 0x00F7, 0x0000 }, /* R110 - Beep Generator (1) */ - [115] = { 0x001F, 0x001F, 0x0000 }, /* R115 - Oscillator Trim (3) */ - [116] = { 0x001F, 0x001F, 0x0000 }, /* R116 - Oscillator Trim (4) */ - [119] = { 0x00FF, 0x00FF, 0x0000 }, /* R119 - Oscillator Trim (7) */ - [124] = { 0x0079, 0x0079, 0x0000 }, /* R124 - Analogue Clocking1 */ - [125] = { 0x00DF, 0x00DF, 0x0000 }, /* R125 - Analogue Clocking2 */ - [126] = { 0x000D, 0x000D, 0x0000 }, /* R126 - Analogue Clocking3 */ - [127] = { 0x0000, 0xFFFF, 0x0000 }, /* R127 - PLL Software Reset */ - [129] = { 0x00B0, 0x00B0, 0x0000 }, /* R129 - PLL2 */ - [131] = { 0x0003, 0x0003, 0x0000 }, /* R131 - PLL 4 */ - [136] = { 0x005F, 0x005F, 0x0000 }, /* R136 - PLL 9 */ - [137] = { 0x00FF, 0x00FF, 0x0000 }, /* R137 - PLL 10 */ - [138] = { 0x00FF, 0x00FF, 0x0000 }, /* R138 - PLL 11 */ - [139] = { 0x00FF, 0x00FF, 0x0000 }, /* R139 - PLL 12 */ - [140] = { 0x005F, 0x005F, 0x0000 }, /* R140 - PLL 13 */ - [141] = { 0x00FF, 0x00FF, 0x0000 }, /* R141 - PLL 14 */ - [142] = { 0x00FF, 0x00FF, 0x0000 }, /* R142 - PLL 15 */ - [143] = { 0x00FF, 0x00FF, 0x0000 }, /* R143 - PLL 16 */ - [155] = { 0x0067, 0x0067, 0x0000 }, /* R155 - FLL Control (1) */ - [156] = { 0x01FB, 0x01FB, 0x0000 }, /* R156 - FLL Control (2) */ - [157] = { 0x0007, 0x0007, 0x0000 }, /* R157 - FLL Control (3) */ - [159] = { 0x007F, 0x007F, 0x0000 }, /* R159 - FLL Control (5) */ - [160] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R160 - FLL Control (6) */ - [161] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R161 - FLL Control (7) */ - [162] = { 0x03FF, 0x03FF, 0x0000 }, /* R162 - FLL Control (8) */ - [252] = { 0x0005, 0x0005, 0x0000 }, /* R252 - General test 1 */ - [256] = { 0x000F, 0x000F, 0x0000 }, /* R256 - DF1 */ - [257] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R257 - DF2 */ - [258] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R258 - DF3 */ - [259] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R259 - DF4 */ - [260] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R260 - DF5 */ - [261] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R261 - DF6 */ - [262] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R262 - DF7 */ - [264] = { 0x0003, 0x0003, 0x0000 }, /* R264 - LHPF1 */ - [265] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R265 - LHPF2 */ - [268] = { 0x0077, 0x0077, 0x0000 }, /* R268 - THREED1 */ - [269] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R269 - THREED2 */ - [270] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R270 - THREED3 */ - [271] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R271 - THREED4 */ - [276] = { 0x7FFF, 0x7FFF, 0x0000 }, /* R276 - DRC 1 */ - [277] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R277 - DRC 2 */ - [278] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R278 - DRC 3 */ - [279] = { 0x07FF, 0x07FF, 0x0000 }, /* R279 - DRC 4 */ - [280] = { 0x03FF, 0x03FF, 0x0000 }, /* R280 - DRC 5 */ - [285] = { 0x0003, 0x0003, 0x0000 }, /* R285 - Tloopback */ - [335] = { 0x0007, 0x0007, 0x0000 }, /* R335 - EQ1 */ - [336] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R336 - EQ2 */ - [337] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R337 - EQ3 */ - [338] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R338 - EQ4 */ - [339] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R339 - EQ5 */ - [340] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R340 - EQ6 */ - [341] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R341 - EQ7 */ - [342] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R342 - EQ8 */ - [343] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R343 - EQ9 */ - [344] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R344 - EQ10 */ - [345] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R345 - EQ11 */ - [346] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R346 - EQ12 */ - [347] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R347 - EQ13 */ - [348] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R348 - EQ14 */ - [349] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R349 - EQ15 */ - [350] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R350 - EQ16 */ - [351] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R351 - EQ17 */ - [352] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R352 - EQ18 */ - [353] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R353 - EQ19 */ - [354] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R354 - EQ20 */ - [355] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R355 - EQ21 */ - [356] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R356 - EQ22 */ - [357] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R357 - EQ23 */ - [358] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R358 - EQ24 */ - [359] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R359 - EQ25 */ - [360] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R360 - EQ26 */ - [361] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R361 - EQ27 */ - [362] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R362 - EQ28 */ - [363] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R363 - EQ29 */ - [364] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R364 - EQ30 */ - [365] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R365 - EQ31 */ - [366] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R366 - EQ32 */ - [367] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R367 - EQ33 */ - [368] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R368 - EQ34 */ - [369] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R369 - EQ35 */ - [370] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R370 - EQ36 */ - [371] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R371 - EQ37 */ - [372] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R372 - EQ38 */ - [373] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R373 - EQ39 */ - [374] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R374 - EQ40 */ - [375] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R375 - EQ41 */ - [513] = { 0x045F, 0x045F, 0x0000 }, /* R513 - GPIO 2 */ - [514] = { 0x045F, 0x045F, 0x0000 }, /* R514 - GPIO 3 */ - [516] = { 0xE75F, 0xE75F, 0x0000 }, /* R516 - GPIO 5 */ - [517] = { 0xE75F, 0xE75F, 0x0000 }, /* R517 - GPIO 6 */ - [560] = { 0x0030, 0x0030, 0xFFFF }, /* R560 - Interrupt Status 1 */ - [561] = { 0xFFED, 0xFFED, 0xFFFF }, /* R561 - Interrupt Status 2 */ - [568] = { 0x0030, 0x0030, 0x0000 }, /* R568 - Interrupt Status 1 Mask */ - [569] = { 0xFFED, 0xFFED, 0x0000 }, /* R569 - Interrupt Status 2 Mask */ - [576] = { 0x0001, 0x0001, 0x0000 }, /* R576 - Interrupt Control */ - [584] = { 0x002D, 0x002D, 0x0000 }, /* R584 - IRQ Debounce */ - [586] = { 0xC000, 0xC000, 0x0000 }, /* R586 - MICINT Source Pol */ - [768] = { 0x0001, 0x0001, 0x0000 }, /* R768 - DSP2 Power Management */ - [1037] = { 0x0000, 0x003F, 0xFFFF }, /* R1037 - DSP2_ExecControl */ - [4096] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4096 - Write Sequencer 0 */ - [4097] = { 0x00FF, 0x00FF, 0x0000 }, /* R4097 - Write Sequencer 1 */ - [4098] = { 0x070F, 0x070F, 0x0000 }, /* R4098 - Write Sequencer 2 */ - [4099] = { 0x010F, 0x010F, 0x0000 }, /* R4099 - Write Sequencer 3 */ - [4100] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4100 - Write Sequencer 4 */ - [4101] = { 0x00FF, 0x00FF, 0x0000 }, /* R4101 - Write Sequencer 5 */ - [4102] = { 0x070F, 0x070F, 0x0000 }, /* R4102 - Write Sequencer 6 */ - [4103] = { 0x010F, 0x010F, 0x0000 }, /* R4103 - Write Sequencer 7 */ - [4104] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4104 - Write Sequencer 8 */ - [4105] = { 0x00FF, 0x00FF, 0x0000 }, /* R4105 - Write Sequencer 9 */ - [4106] = { 0x070F, 0x070F, 0x0000 }, /* R4106 - Write Sequencer 10 */ - [4107] = { 0x010F, 0x010F, 0x0000 }, /* R4107 - Write Sequencer 11 */ - [4108] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4108 - Write Sequencer 12 */ - [4109] = { 0x00FF, 0x00FF, 0x0000 }, /* R4109 - Write Sequencer 13 */ - [4110] = { 0x070F, 0x070F, 0x0000 }, /* R4110 - Write Sequencer 14 */ - [4111] = { 0x010F, 0x010F, 0x0000 }, /* R4111 - Write Sequencer 15 */ - [4112] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4112 - Write Sequencer 16 */ - [4113] = { 0x00FF, 0x00FF, 0x0000 }, /* R4113 - Write Sequencer 17 */ - [4114] = { 0x070F, 0x070F, 0x0000 }, /* R4114 - Write Sequencer 18 */ - [4115] = { 0x010F, 0x010F, 0x0000 }, /* R4115 - Write Sequencer 19 */ - [4116] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4116 - Write Sequencer 20 */ - [4117] = { 0x00FF, 0x00FF, 0x0000 }, /* R4117 - Write Sequencer 21 */ - [4118] = { 0x070F, 0x070F, 0x0000 }, /* R4118 - Write Sequencer 22 */ - [4119] = { 0x010F, 0x010F, 0x0000 }, /* R4119 - Write Sequencer 23 */ - [4120] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4120 - Write Sequencer 24 */ - [4121] = { 0x00FF, 0x00FF, 0x0000 }, /* R4121 - Write Sequencer 25 */ - [4122] = { 0x070F, 0x070F, 0x0000 }, /* R4122 - Write Sequencer 26 */ - [4123] = { 0x010F, 0x010F, 0x0000 }, /* R4123 - Write Sequencer 27 */ - [4124] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4124 - Write Sequencer 28 */ - [4125] = { 0x00FF, 0x00FF, 0x0000 }, /* R4125 - Write Sequencer 29 */ - [4126] = { 0x070F, 0x070F, 0x0000 }, /* R4126 - Write Sequencer 30 */ - [4127] = { 0x010F, 0x010F, 0x0000 }, /* R4127 - Write Sequencer 31 */ - [4128] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4128 - Write Sequencer 32 */ - [4129] = { 0x00FF, 0x00FF, 0x0000 }, /* R4129 - Write Sequencer 33 */ - [4130] = { 0x070F, 0x070F, 0x0000 }, /* R4130 - Write Sequencer 34 */ - [4131] = { 0x010F, 0x010F, 0x0000 }, /* R4131 - Write Sequencer 35 */ - [4132] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4132 - Write Sequencer 36 */ - [4133] = { 0x00FF, 0x00FF, 0x0000 }, /* R4133 - Write Sequencer 37 */ - [4134] = { 0x070F, 0x070F, 0x0000 }, /* R4134 - Write Sequencer 38 */ - [4135] = { 0x010F, 0x010F, 0x0000 }, /* R4135 - Write Sequencer 39 */ - [4136] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4136 - Write Sequencer 40 */ - [4137] = { 0x00FF, 0x00FF, 0x0000 }, /* R4137 - Write Sequencer 41 */ - [4138] = { 0x070F, 0x070F, 0x0000 }, /* R4138 - Write Sequencer 42 */ - [4139] = { 0x010F, 0x010F, 0x0000 }, /* R4139 - Write Sequencer 43 */ - [4140] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4140 - Write Sequencer 44 */ - [4141] = { 0x00FF, 0x00FF, 0x0000 }, /* R4141 - Write Sequencer 45 */ - [4142] = { 0x070F, 0x070F, 0x0000 }, /* R4142 - Write Sequencer 46 */ - [4143] = { 0x010F, 0x010F, 0x0000 }, /* R4143 - Write Sequencer 47 */ - [4144] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4144 - Write Sequencer 48 */ - [4145] = { 0x00FF, 0x00FF, 0x0000 }, /* R4145 - Write Sequencer 49 */ - [4146] = { 0x070F, 0x070F, 0x0000 }, /* R4146 - Write Sequencer 50 */ - [4147] = { 0x010F, 0x010F, 0x0000 }, /* R4147 - Write Sequencer 51 */ - [4148] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4148 - Write Sequencer 52 */ - [4149] = { 0x00FF, 0x00FF, 0x0000 }, /* R4149 - Write Sequencer 53 */ - [4150] = { 0x070F, 0x070F, 0x0000 }, /* R4150 - Write Sequencer 54 */ - [4151] = { 0x010F, 0x010F, 0x0000 }, /* R4151 - Write Sequencer 55 */ - [4152] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4152 - Write Sequencer 56 */ - [4153] = { 0x00FF, 0x00FF, 0x0000 }, /* R4153 - Write Sequencer 57 */ - [4154] = { 0x070F, 0x070F, 0x0000 }, /* R4154 - Write Sequencer 58 */ - [4155] = { 0x010F, 0x010F, 0x0000 }, /* R4155 - Write Sequencer 59 */ - [4156] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4156 - Write Sequencer 60 */ - [4157] = { 0x00FF, 0x00FF, 0x0000 }, /* R4157 - Write Sequencer 61 */ - [4158] = { 0x070F, 0x070F, 0x0000 }, /* R4158 - Write Sequencer 62 */ - [4159] = { 0x010F, 0x010F, 0x0000 }, /* R4159 - Write Sequencer 63 */ - [4160] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4160 - Write Sequencer 64 */ - [4161] = { 0x00FF, 0x00FF, 0x0000 }, /* R4161 - Write Sequencer 65 */ - [4162] = { 0x070F, 0x070F, 0x0000 }, /* R4162 - Write Sequencer 66 */ - [4163] = { 0x010F, 0x010F, 0x0000 }, /* R4163 - Write Sequencer 67 */ - [4164] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4164 - Write Sequencer 68 */ - [4165] = { 0x00FF, 0x00FF, 0x0000 }, /* R4165 - Write Sequencer 69 */ - [4166] = { 0x070F, 0x070F, 0x0000 }, /* R4166 - Write Sequencer 70 */ - [4167] = { 0x010F, 0x010F, 0x0000 }, /* R4167 - Write Sequencer 71 */ - [4168] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4168 - Write Sequencer 72 */ - [4169] = { 0x00FF, 0x00FF, 0x0000 }, /* R4169 - Write Sequencer 73 */ - [4170] = { 0x070F, 0x070F, 0x0000 }, /* R4170 - Write Sequencer 74 */ - [4171] = { 0x010F, 0x010F, 0x0000 }, /* R4171 - Write Sequencer 75 */ - [4172] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4172 - Write Sequencer 76 */ - [4173] = { 0x00FF, 0x00FF, 0x0000 }, /* R4173 - Write Sequencer 77 */ - [4174] = { 0x070F, 0x070F, 0x0000 }, /* R4174 - Write Sequencer 78 */ - [4175] = { 0x010F, 0x010F, 0x0000 }, /* R4175 - Write Sequencer 79 */ - [4176] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4176 - Write Sequencer 80 */ - [4177] = { 0x00FF, 0x00FF, 0x0000 }, /* R4177 - Write Sequencer 81 */ - [4178] = { 0x070F, 0x070F, 0x0000 }, /* R4178 - Write Sequencer 82 */ - [4179] = { 0x010F, 0x010F, 0x0000 }, /* R4179 - Write Sequencer 83 */ - [4180] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4180 - Write Sequencer 84 */ - [4181] = { 0x00FF, 0x00FF, 0x0000 }, /* R4181 - Write Sequencer 85 */ - [4182] = { 0x070F, 0x070F, 0x0000 }, /* R4182 - Write Sequencer 86 */ - [4183] = { 0x010F, 0x010F, 0x0000 }, /* R4183 - Write Sequencer 87 */ - [4184] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4184 - Write Sequencer 88 */ - [4185] = { 0x00FF, 0x00FF, 0x0000 }, /* R4185 - Write Sequencer 89 */ - [4186] = { 0x070F, 0x070F, 0x0000 }, /* R4186 - Write Sequencer 90 */ - [4187] = { 0x010F, 0x010F, 0x0000 }, /* R4187 - Write Sequencer 91 */ - [4188] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4188 - Write Sequencer 92 */ - [4189] = { 0x00FF, 0x00FF, 0x0000 }, /* R4189 - Write Sequencer 93 */ - [4190] = { 0x070F, 0x070F, 0x0000 }, /* R4190 - Write Sequencer 94 */ - [4191] = { 0x010F, 0x010F, 0x0000 }, /* R4191 - Write Sequencer 95 */ - [4192] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4192 - Write Sequencer 96 */ - [4193] = { 0x00FF, 0x00FF, 0x0000 }, /* R4193 - Write Sequencer 97 */ - [4194] = { 0x070F, 0x070F, 0x0000 }, /* R4194 - Write Sequencer 98 */ - [4195] = { 0x010F, 0x010F, 0x0000 }, /* R4195 - Write Sequencer 99 */ - [4196] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4196 - Write Sequencer 100 */ - [4197] = { 0x00FF, 0x00FF, 0x0000 }, /* R4197 - Write Sequencer 101 */ - [4198] = { 0x070F, 0x070F, 0x0000 }, /* R4198 - Write Sequencer 102 */ - [4199] = { 0x010F, 0x010F, 0x0000 }, /* R4199 - Write Sequencer 103 */ - [4200] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4200 - Write Sequencer 104 */ - [4201] = { 0x00FF, 0x00FF, 0x0000 }, /* R4201 - Write Sequencer 105 */ - [4202] = { 0x070F, 0x070F, 0x0000 }, /* R4202 - Write Sequencer 106 */ - [4203] = { 0x010F, 0x010F, 0x0000 }, /* R4203 - Write Sequencer 107 */ - [4204] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4204 - Write Sequencer 108 */ - [4205] = { 0x00FF, 0x00FF, 0x0000 }, /* R4205 - Write Sequencer 109 */ - [4206] = { 0x070F, 0x070F, 0x0000 }, /* R4206 - Write Sequencer 110 */ - [4207] = { 0x010F, 0x010F, 0x0000 }, /* R4207 - Write Sequencer 111 */ - [4208] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4208 - Write Sequencer 112 */ - [4209] = { 0x00FF, 0x00FF, 0x0000 }, /* R4209 - Write Sequencer 113 */ - [4210] = { 0x070F, 0x070F, 0x0000 }, /* R4210 - Write Sequencer 114 */ - [4211] = { 0x010F, 0x010F, 0x0000 }, /* R4211 - Write Sequencer 115 */ - [4212] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4212 - Write Sequencer 116 */ - [4213] = { 0x00FF, 0x00FF, 0x0000 }, /* R4213 - Write Sequencer 117 */ - [4214] = { 0x070F, 0x070F, 0x0000 }, /* R4214 - Write Sequencer 118 */ - [4215] = { 0x010F, 0x010F, 0x0000 }, /* R4215 - Write Sequencer 119 */ - [4216] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4216 - Write Sequencer 120 */ - [4217] = { 0x00FF, 0x00FF, 0x0000 }, /* R4217 - Write Sequencer 121 */ - [4218] = { 0x070F, 0x070F, 0x0000 }, /* R4218 - Write Sequencer 122 */ - [4219] = { 0x010F, 0x010F, 0x0000 }, /* R4219 - Write Sequencer 123 */ - [4220] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4220 - Write Sequencer 124 */ - [4221] = { 0x00FF, 0x00FF, 0x0000 }, /* R4221 - Write Sequencer 125 */ - [4222] = { 0x070F, 0x070F, 0x0000 }, /* R4222 - Write Sequencer 126 */ - [4223] = { 0x010F, 0x010F, 0x0000 }, /* R4223 - Write Sequencer 127 */ - [4224] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4224 - Write Sequencer 128 */ - [4225] = { 0x00FF, 0x00FF, 0x0000 }, /* R4225 - Write Sequencer 129 */ - [4226] = { 0x070F, 0x070F, 0x0000 }, /* R4226 - Write Sequencer 130 */ - [4227] = { 0x010F, 0x010F, 0x0000 }, /* R4227 - Write Sequencer 131 */ - [4228] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4228 - Write Sequencer 132 */ - [4229] = { 0x00FF, 0x00FF, 0x0000 }, /* R4229 - Write Sequencer 133 */ - [4230] = { 0x070F, 0x070F, 0x0000 }, /* R4230 - Write Sequencer 134 */ - [4231] = { 0x010F, 0x010F, 0x0000 }, /* R4231 - Write Sequencer 135 */ - [4232] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4232 - Write Sequencer 136 */ - [4233] = { 0x00FF, 0x00FF, 0x0000 }, /* R4233 - Write Sequencer 137 */ - [4234] = { 0x070F, 0x070F, 0x0000 }, /* R4234 - Write Sequencer 138 */ - [4235] = { 0x010F, 0x010F, 0x0000 }, /* R4235 - Write Sequencer 139 */ - [4236] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4236 - Write Sequencer 140 */ - [4237] = { 0x00FF, 0x00FF, 0x0000 }, /* R4237 - Write Sequencer 141 */ - [4238] = { 0x070F, 0x070F, 0x0000 }, /* R4238 - Write Sequencer 142 */ - [4239] = { 0x010F, 0x010F, 0x0000 }, /* R4239 - Write Sequencer 143 */ - [4240] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4240 - Write Sequencer 144 */ - [4241] = { 0x00FF, 0x00FF, 0x0000 }, /* R4241 - Write Sequencer 145 */ - [4242] = { 0x070F, 0x070F, 0x0000 }, /* R4242 - Write Sequencer 146 */ - [4243] = { 0x010F, 0x010F, 0x0000 }, /* R4243 - Write Sequencer 147 */ - [4244] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4244 - Write Sequencer 148 */ - [4245] = { 0x00FF, 0x00FF, 0x0000 }, /* R4245 - Write Sequencer 149 */ - [4246] = { 0x070F, 0x070F, 0x0000 }, /* R4246 - Write Sequencer 150 */ - [4247] = { 0x010F, 0x010F, 0x0000 }, /* R4247 - Write Sequencer 151 */ - [4248] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4248 - Write Sequencer 152 */ - [4249] = { 0x00FF, 0x00FF, 0x0000 }, /* R4249 - Write Sequencer 153 */ - [4250] = { 0x070F, 0x070F, 0x0000 }, /* R4250 - Write Sequencer 154 */ - [4251] = { 0x010F, 0x010F, 0x0000 }, /* R4251 - Write Sequencer 155 */ - [4252] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4252 - Write Sequencer 156 */ - [4253] = { 0x00FF, 0x00FF, 0x0000 }, /* R4253 - Write Sequencer 157 */ - [4254] = { 0x070F, 0x070F, 0x0000 }, /* R4254 - Write Sequencer 158 */ - [4255] = { 0x010F, 0x010F, 0x0000 }, /* R4255 - Write Sequencer 159 */ - [4256] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4256 - Write Sequencer 160 */ - [4257] = { 0x00FF, 0x00FF, 0x0000 }, /* R4257 - Write Sequencer 161 */ - [4258] = { 0x070F, 0x070F, 0x0000 }, /* R4258 - Write Sequencer 162 */ - [4259] = { 0x010F, 0x010F, 0x0000 }, /* R4259 - Write Sequencer 163 */ - [4260] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4260 - Write Sequencer 164 */ - [4261] = { 0x00FF, 0x00FF, 0x0000 }, /* R4261 - Write Sequencer 165 */ - [4262] = { 0x070F, 0x070F, 0x0000 }, /* R4262 - Write Sequencer 166 */ - [4263] = { 0x010F, 0x010F, 0x0000 }, /* R4263 - Write Sequencer 167 */ - [4264] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4264 - Write Sequencer 168 */ - [4265] = { 0x00FF, 0x00FF, 0x0000 }, /* R4265 - Write Sequencer 169 */ - [4266] = { 0x070F, 0x070F, 0x0000 }, /* R4266 - Write Sequencer 170 */ - [4267] = { 0x010F, 0x010F, 0x0000 }, /* R4267 - Write Sequencer 171 */ - [4268] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4268 - Write Sequencer 172 */ - [4269] = { 0x00FF, 0x00FF, 0x0000 }, /* R4269 - Write Sequencer 173 */ - [4270] = { 0x070F, 0x070F, 0x0000 }, /* R4270 - Write Sequencer 174 */ - [4271] = { 0x010F, 0x010F, 0x0000 }, /* R4271 - Write Sequencer 175 */ - [4272] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4272 - Write Sequencer 176 */ - [4273] = { 0x00FF, 0x00FF, 0x0000 }, /* R4273 - Write Sequencer 177 */ - [4274] = { 0x070F, 0x070F, 0x0000 }, /* R4274 - Write Sequencer 178 */ - [4275] = { 0x010F, 0x010F, 0x0000 }, /* R4275 - Write Sequencer 179 */ - [4276] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4276 - Write Sequencer 180 */ - [4277] = { 0x00FF, 0x00FF, 0x0000 }, /* R4277 - Write Sequencer 181 */ - [4278] = { 0x070F, 0x070F, 0x0000 }, /* R4278 - Write Sequencer 182 */ - [4279] = { 0x010F, 0x010F, 0x0000 }, /* R4279 - Write Sequencer 183 */ - [4280] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4280 - Write Sequencer 184 */ - [4281] = { 0x00FF, 0x00FF, 0x0000 }, /* R4281 - Write Sequencer 185 */ - [4282] = { 0x070F, 0x070F, 0x0000 }, /* R4282 - Write Sequencer 186 */ - [4283] = { 0x010F, 0x010F, 0x0000 }, /* R4283 - Write Sequencer 187 */ - [4284] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4284 - Write Sequencer 188 */ - [4285] = { 0x00FF, 0x00FF, 0x0000 }, /* R4285 - Write Sequencer 189 */ - [4286] = { 0x070F, 0x070F, 0x0000 }, /* R4286 - Write Sequencer 190 */ - [4287] = { 0x010F, 0x010F, 0x0000 }, /* R4287 - Write Sequencer 191 */ - [4288] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4288 - Write Sequencer 192 */ - [4289] = { 0x00FF, 0x00FF, 0x0000 }, /* R4289 - Write Sequencer 193 */ - [4290] = { 0x070F, 0x070F, 0x0000 }, /* R4290 - Write Sequencer 194 */ - [4291] = { 0x010F, 0x010F, 0x0000 }, /* R4291 - Write Sequencer 195 */ - [4292] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4292 - Write Sequencer 196 */ - [4293] = { 0x00FF, 0x00FF, 0x0000 }, /* R4293 - Write Sequencer 197 */ - [4294] = { 0x070F, 0x070F, 0x0000 }, /* R4294 - Write Sequencer 198 */ - [4295] = { 0x010F, 0x010F, 0x0000 }, /* R4295 - Write Sequencer 199 */ - [4296] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4296 - Write Sequencer 200 */ - [4297] = { 0x00FF, 0x00FF, 0x0000 }, /* R4297 - Write Sequencer 201 */ - [4298] = { 0x070F, 0x070F, 0x0000 }, /* R4298 - Write Sequencer 202 */ - [4299] = { 0x010F, 0x010F, 0x0000 }, /* R4299 - Write Sequencer 203 */ - [4300] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4300 - Write Sequencer 204 */ - [4301] = { 0x00FF, 0x00FF, 0x0000 }, /* R4301 - Write Sequencer 205 */ - [4302] = { 0x070F, 0x070F, 0x0000 }, /* R4302 - Write Sequencer 206 */ - [4303] = { 0x010F, 0x010F, 0x0000 }, /* R4303 - Write Sequencer 207 */ - [4304] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4304 - Write Sequencer 208 */ - [4305] = { 0x00FF, 0x00FF, 0x0000 }, /* R4305 - Write Sequencer 209 */ - [4306] = { 0x070F, 0x070F, 0x0000 }, /* R4306 - Write Sequencer 210 */ - [4307] = { 0x010F, 0x010F, 0x0000 }, /* R4307 - Write Sequencer 211 */ - [4308] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4308 - Write Sequencer 212 */ - [4309] = { 0x00FF, 0x00FF, 0x0000 }, /* R4309 - Write Sequencer 213 */ - [4310] = { 0x070F, 0x070F, 0x0000 }, /* R4310 - Write Sequencer 214 */ - [4311] = { 0x010F, 0x010F, 0x0000 }, /* R4311 - Write Sequencer 215 */ - [4312] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4312 - Write Sequencer 216 */ - [4313] = { 0x00FF, 0x00FF, 0x0000 }, /* R4313 - Write Sequencer 217 */ - [4314] = { 0x070F, 0x070F, 0x0000 }, /* R4314 - Write Sequencer 218 */ - [4315] = { 0x010F, 0x010F, 0x0000 }, /* R4315 - Write Sequencer 219 */ - [4316] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4316 - Write Sequencer 220 */ - [4317] = { 0x00FF, 0x00FF, 0x0000 }, /* R4317 - Write Sequencer 221 */ - [4318] = { 0x070F, 0x070F, 0x0000 }, /* R4318 - Write Sequencer 222 */ - [4319] = { 0x010F, 0x010F, 0x0000 }, /* R4319 - Write Sequencer 223 */ - [4320] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4320 - Write Sequencer 224 */ - [4321] = { 0x00FF, 0x00FF, 0x0000 }, /* R4321 - Write Sequencer 225 */ - [4322] = { 0x070F, 0x070F, 0x0000 }, /* R4322 - Write Sequencer 226 */ - [4323] = { 0x010F, 0x010F, 0x0000 }, /* R4323 - Write Sequencer 227 */ - [4324] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4324 - Write Sequencer 228 */ - [4325] = { 0x00FF, 0x00FF, 0x0000 }, /* R4325 - Write Sequencer 229 */ - [4326] = { 0x070F, 0x070F, 0x0000 }, /* R4326 - Write Sequencer 230 */ - [4327] = { 0x010F, 0x010F, 0x0000 }, /* R4327 - Write Sequencer 231 */ - [4328] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4328 - Write Sequencer 232 */ - [4329] = { 0x00FF, 0x00FF, 0x0000 }, /* R4329 - Write Sequencer 233 */ - [4330] = { 0x070F, 0x070F, 0x0000 }, /* R4330 - Write Sequencer 234 */ - [4331] = { 0x010F, 0x010F, 0x0000 }, /* R4331 - Write Sequencer 235 */ - [4332] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4332 - Write Sequencer 236 */ - [4333] = { 0x00FF, 0x00FF, 0x0000 }, /* R4333 - Write Sequencer 237 */ - [4334] = { 0x070F, 0x070F, 0x0000 }, /* R4334 - Write Sequencer 238 */ - [4335] = { 0x010F, 0x010F, 0x0000 }, /* R4335 - Write Sequencer 239 */ - [4336] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4336 - Write Sequencer 240 */ - [4337] = { 0x00FF, 0x00FF, 0x0000 }, /* R4337 - Write Sequencer 241 */ - [4338] = { 0x070F, 0x070F, 0x0000 }, /* R4338 - Write Sequencer 242 */ - [4339] = { 0x010F, 0x010F, 0x0000 }, /* R4339 - Write Sequencer 243 */ - [4340] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4340 - Write Sequencer 244 */ - [4341] = { 0x00FF, 0x00FF, 0x0000 }, /* R4341 - Write Sequencer 245 */ - [4342] = { 0x070F, 0x070F, 0x0000 }, /* R4342 - Write Sequencer 246 */ - [4343] = { 0x010F, 0x010F, 0x0000 }, /* R4343 - Write Sequencer 247 */ - [4344] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4344 - Write Sequencer 248 */ - [4345] = { 0x00FF, 0x00FF, 0x0000 }, /* R4345 - Write Sequencer 249 */ - [4346] = { 0x070F, 0x070F, 0x0000 }, /* R4346 - Write Sequencer 250 */ - [4347] = { 0x010F, 0x010F, 0x0000 }, /* R4347 - Write Sequencer 251 */ - [4348] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4348 - Write Sequencer 252 */ - [4349] = { 0x00FF, 0x00FF, 0x0000 }, /* R4349 - Write Sequencer 253 */ - [4350] = { 0x070F, 0x070F, 0x0000 }, /* R4350 - Write Sequencer 254 */ - [4351] = { 0x010F, 0x010F, 0x0000 }, /* R4351 - Write Sequencer 255 */ - [4352] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4352 - Write Sequencer 256 */ - [4353] = { 0x00FF, 0x00FF, 0x0000 }, /* R4353 - Write Sequencer 257 */ - [4354] = { 0x070F, 0x070F, 0x0000 }, /* R4354 - Write Sequencer 258 */ - [4355] = { 0x010F, 0x010F, 0x0000 }, /* R4355 - Write Sequencer 259 */ - [4356] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4356 - Write Sequencer 260 */ - [4357] = { 0x00FF, 0x00FF, 0x0000 }, /* R4357 - Write Sequencer 261 */ - [4358] = { 0x070F, 0x070F, 0x0000 }, /* R4358 - Write Sequencer 262 */ - [4359] = { 0x010F, 0x010F, 0x0000 }, /* R4359 - Write Sequencer 263 */ - [4360] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4360 - Write Sequencer 264 */ - [4361] = { 0x00FF, 0x00FF, 0x0000 }, /* R4361 - Write Sequencer 265 */ - [4362] = { 0x070F, 0x070F, 0x0000 }, /* R4362 - Write Sequencer 266 */ - [4363] = { 0x010F, 0x010F, 0x0000 }, /* R4363 - Write Sequencer 267 */ - [4364] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4364 - Write Sequencer 268 */ - [4365] = { 0x00FF, 0x00FF, 0x0000 }, /* R4365 - Write Sequencer 269 */ - [4366] = { 0x070F, 0x070F, 0x0000 }, /* R4366 - Write Sequencer 270 */ - [4367] = { 0x010F, 0x010F, 0x0000 }, /* R4367 - Write Sequencer 271 */ - [4368] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4368 - Write Sequencer 272 */ - [4369] = { 0x00FF, 0x00FF, 0x0000 }, /* R4369 - Write Sequencer 273 */ - [4370] = { 0x070F, 0x070F, 0x0000 }, /* R4370 - Write Sequencer 274 */ - [4371] = { 0x010F, 0x010F, 0x0000 }, /* R4371 - Write Sequencer 275 */ - [4372] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4372 - Write Sequencer 276 */ - [4373] = { 0x00FF, 0x00FF, 0x0000 }, /* R4373 - Write Sequencer 277 */ - [4374] = { 0x070F, 0x070F, 0x0000 }, /* R4374 - Write Sequencer 278 */ - [4375] = { 0x010F, 0x010F, 0x0000 }, /* R4375 - Write Sequencer 279 */ - [4376] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4376 - Write Sequencer 280 */ - [4377] = { 0x00FF, 0x00FF, 0x0000 }, /* R4377 - Write Sequencer 281 */ - [4378] = { 0x070F, 0x070F, 0x0000 }, /* R4378 - Write Sequencer 282 */ - [4379] = { 0x010F, 0x010F, 0x0000 }, /* R4379 - Write Sequencer 283 */ - [4380] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4380 - Write Sequencer 284 */ - [4381] = { 0x00FF, 0x00FF, 0x0000 }, /* R4381 - Write Sequencer 285 */ - [4382] = { 0x070F, 0x070F, 0x0000 }, /* R4382 - Write Sequencer 286 */ - [4383] = { 0x010F, 0x010F, 0x0000 }, /* R4383 - Write Sequencer 287 */ - [4384] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4384 - Write Sequencer 288 */ - [4385] = { 0x00FF, 0x00FF, 0x0000 }, /* R4385 - Write Sequencer 289 */ - [4386] = { 0x070F, 0x070F, 0x0000 }, /* R4386 - Write Sequencer 290 */ - [4387] = { 0x010F, 0x010F, 0x0000 }, /* R4387 - Write Sequencer 291 */ - [4388] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4388 - Write Sequencer 292 */ - [4389] = { 0x00FF, 0x00FF, 0x0000 }, /* R4389 - Write Sequencer 293 */ - [4390] = { 0x070F, 0x070F, 0x0000 }, /* R4390 - Write Sequencer 294 */ - [4391] = { 0x010F, 0x010F, 0x0000 }, /* R4391 - Write Sequencer 295 */ - [4392] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4392 - Write Sequencer 296 */ - [4393] = { 0x00FF, 0x00FF, 0x0000 }, /* R4393 - Write Sequencer 297 */ - [4394] = { 0x070F, 0x070F, 0x0000 }, /* R4394 - Write Sequencer 298 */ - [4395] = { 0x010F, 0x010F, 0x0000 }, /* R4395 - Write Sequencer 299 */ - [4396] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4396 - Write Sequencer 300 */ - [4397] = { 0x00FF, 0x00FF, 0x0000 }, /* R4397 - Write Sequencer 301 */ - [4398] = { 0x070F, 0x070F, 0x0000 }, /* R4398 - Write Sequencer 302 */ - [4399] = { 0x010F, 0x010F, 0x0000 }, /* R4399 - Write Sequencer 303 */ - [4400] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4400 - Write Sequencer 304 */ - [4401] = { 0x00FF, 0x00FF, 0x0000 }, /* R4401 - Write Sequencer 305 */ - [4402] = { 0x070F, 0x070F, 0x0000 }, /* R4402 - Write Sequencer 306 */ - [4403] = { 0x010F, 0x010F, 0x0000 }, /* R4403 - Write Sequencer 307 */ - [4404] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4404 - Write Sequencer 308 */ - [4405] = { 0x00FF, 0x00FF, 0x0000 }, /* R4405 - Write Sequencer 309 */ - [4406] = { 0x070F, 0x070F, 0x0000 }, /* R4406 - Write Sequencer 310 */ - [4407] = { 0x010F, 0x010F, 0x0000 }, /* R4407 - Write Sequencer 311 */ - [4408] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4408 - Write Sequencer 312 */ - [4409] = { 0x00FF, 0x00FF, 0x0000 }, /* R4409 - Write Sequencer 313 */ - [4410] = { 0x070F, 0x070F, 0x0000 }, /* R4410 - Write Sequencer 314 */ - [4411] = { 0x010F, 0x010F, 0x0000 }, /* R4411 - Write Sequencer 315 */ - [4412] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4412 - Write Sequencer 316 */ - [4413] = { 0x00FF, 0x00FF, 0x0000 }, /* R4413 - Write Sequencer 317 */ - [4414] = { 0x070F, 0x070F, 0x0000 }, /* R4414 - Write Sequencer 318 */ - [4415] = { 0x010F, 0x010F, 0x0000 }, /* R4415 - Write Sequencer 319 */ - [4416] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4416 - Write Sequencer 320 */ - [4417] = { 0x00FF, 0x00FF, 0x0000 }, /* R4417 - Write Sequencer 321 */ - [4418] = { 0x070F, 0x070F, 0x0000 }, /* R4418 - Write Sequencer 322 */ - [4419] = { 0x010F, 0x010F, 0x0000 }, /* R4419 - Write Sequencer 323 */ - [4420] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4420 - Write Sequencer 324 */ - [4421] = { 0x00FF, 0x00FF, 0x0000 }, /* R4421 - Write Sequencer 325 */ - [4422] = { 0x070F, 0x070F, 0x0000 }, /* R4422 - Write Sequencer 326 */ - [4423] = { 0x010F, 0x010F, 0x0000 }, /* R4423 - Write Sequencer 327 */ - [4424] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4424 - Write Sequencer 328 */ - [4425] = { 0x00FF, 0x00FF, 0x0000 }, /* R4425 - Write Sequencer 329 */ - [4426] = { 0x070F, 0x070F, 0x0000 }, /* R4426 - Write Sequencer 330 */ - [4427] = { 0x010F, 0x010F, 0x0000 }, /* R4427 - Write Sequencer 331 */ - [4428] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4428 - Write Sequencer 332 */ - [4429] = { 0x00FF, 0x00FF, 0x0000 }, /* R4429 - Write Sequencer 333 */ - [4430] = { 0x070F, 0x070F, 0x0000 }, /* R4430 - Write Sequencer 334 */ - [4431] = { 0x010F, 0x010F, 0x0000 }, /* R4431 - Write Sequencer 335 */ - [4432] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4432 - Write Sequencer 336 */ - [4433] = { 0x00FF, 0x00FF, 0x0000 }, /* R4433 - Write Sequencer 337 */ - [4434] = { 0x070F, 0x070F, 0x0000 }, /* R4434 - Write Sequencer 338 */ - [4435] = { 0x010F, 0x010F, 0x0000 }, /* R4435 - Write Sequencer 339 */ - [4436] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4436 - Write Sequencer 340 */ - [4437] = { 0x00FF, 0x00FF, 0x0000 }, /* R4437 - Write Sequencer 341 */ - [4438] = { 0x070F, 0x070F, 0x0000 }, /* R4438 - Write Sequencer 342 */ - [4439] = { 0x010F, 0x010F, 0x0000 }, /* R4439 - Write Sequencer 343 */ - [4440] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4440 - Write Sequencer 344 */ - [4441] = { 0x00FF, 0x00FF, 0x0000 }, /* R4441 - Write Sequencer 345 */ - [4442] = { 0x070F, 0x070F, 0x0000 }, /* R4442 - Write Sequencer 346 */ - [4443] = { 0x010F, 0x010F, 0x0000 }, /* R4443 - Write Sequencer 347 */ - [4444] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4444 - Write Sequencer 348 */ - [4445] = { 0x00FF, 0x00FF, 0x0000 }, /* R4445 - Write Sequencer 349 */ - [4446] = { 0x070F, 0x070F, 0x0000 }, /* R4446 - Write Sequencer 350 */ - [4447] = { 0x010F, 0x010F, 0x0000 }, /* R4447 - Write Sequencer 351 */ - [4448] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4448 - Write Sequencer 352 */ - [4449] = { 0x00FF, 0x00FF, 0x0000 }, /* R4449 - Write Sequencer 353 */ - [4450] = { 0x070F, 0x070F, 0x0000 }, /* R4450 - Write Sequencer 354 */ - [4451] = { 0x010F, 0x010F, 0x0000 }, /* R4451 - Write Sequencer 355 */ - [4452] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4452 - Write Sequencer 356 */ - [4453] = { 0x00FF, 0x00FF, 0x0000 }, /* R4453 - Write Sequencer 357 */ - [4454] = { 0x070F, 0x070F, 0x0000 }, /* R4454 - Write Sequencer 358 */ - [4455] = { 0x010F, 0x010F, 0x0000 }, /* R4455 - Write Sequencer 359 */ - [4456] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4456 - Write Sequencer 360 */ - [4457] = { 0x00FF, 0x00FF, 0x0000 }, /* R4457 - Write Sequencer 361 */ - [4458] = { 0x070F, 0x070F, 0x0000 }, /* R4458 - Write Sequencer 362 */ - [4459] = { 0x010F, 0x010F, 0x0000 }, /* R4459 - Write Sequencer 363 */ - [4460] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4460 - Write Sequencer 364 */ - [4461] = { 0x00FF, 0x00FF, 0x0000 }, /* R4461 - Write Sequencer 365 */ - [4462] = { 0x070F, 0x070F, 0x0000 }, /* R4462 - Write Sequencer 366 */ - [4463] = { 0x010F, 0x010F, 0x0000 }, /* R4463 - Write Sequencer 367 */ - [4464] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4464 - Write Sequencer 368 */ - [4465] = { 0x00FF, 0x00FF, 0x0000 }, /* R4465 - Write Sequencer 369 */ - [4466] = { 0x070F, 0x070F, 0x0000 }, /* R4466 - Write Sequencer 370 */ - [4467] = { 0x010F, 0x010F, 0x0000 }, /* R4467 - Write Sequencer 371 */ - [4468] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4468 - Write Sequencer 372 */ - [4469] = { 0x00FF, 0x00FF, 0x0000 }, /* R4469 - Write Sequencer 373 */ - [4470] = { 0x070F, 0x070F, 0x0000 }, /* R4470 - Write Sequencer 374 */ - [4471] = { 0x010F, 0x010F, 0x0000 }, /* R4471 - Write Sequencer 375 */ - [4472] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4472 - Write Sequencer 376 */ - [4473] = { 0x00FF, 0x00FF, 0x0000 }, /* R4473 - Write Sequencer 377 */ - [4474] = { 0x070F, 0x070F, 0x0000 }, /* R4474 - Write Sequencer 378 */ - [4475] = { 0x010F, 0x010F, 0x0000 }, /* R4475 - Write Sequencer 379 */ - [4476] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4476 - Write Sequencer 380 */ - [4477] = { 0x00FF, 0x00FF, 0x0000 }, /* R4477 - Write Sequencer 381 */ - [4478] = { 0x070F, 0x070F, 0x0000 }, /* R4478 - Write Sequencer 382 */ - [4479] = { 0x010F, 0x010F, 0x0000 }, /* R4479 - Write Sequencer 383 */ - [4480] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4480 - Write Sequencer 384 */ - [4481] = { 0x00FF, 0x00FF, 0x0000 }, /* R4481 - Write Sequencer 385 */ - [4482] = { 0x070F, 0x070F, 0x0000 }, /* R4482 - Write Sequencer 386 */ - [4483] = { 0x010F, 0x010F, 0x0000 }, /* R4483 - Write Sequencer 387 */ - [4484] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4484 - Write Sequencer 388 */ - [4485] = { 0x00FF, 0x00FF, 0x0000 }, /* R4485 - Write Sequencer 389 */ - [4486] = { 0x070F, 0x070F, 0x0000 }, /* R4486 - Write Sequencer 390 */ - [4487] = { 0x010F, 0x010F, 0x0000 }, /* R4487 - Write Sequencer 391 */ - [4488] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4488 - Write Sequencer 392 */ - [4489] = { 0x00FF, 0x00FF, 0x0000 }, /* R4489 - Write Sequencer 393 */ - [4490] = { 0x070F, 0x070F, 0x0000 }, /* R4490 - Write Sequencer 394 */ - [4491] = { 0x010F, 0x010F, 0x0000 }, /* R4491 - Write Sequencer 395 */ - [4492] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4492 - Write Sequencer 396 */ - [4493] = { 0x00FF, 0x00FF, 0x0000 }, /* R4493 - Write Sequencer 397 */ - [4494] = { 0x070F, 0x070F, 0x0000 }, /* R4494 - Write Sequencer 398 */ - [4495] = { 0x010F, 0x010F, 0x0000 }, /* R4495 - Write Sequencer 399 */ - [4496] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4496 - Write Sequencer 400 */ - [4497] = { 0x00FF, 0x00FF, 0x0000 }, /* R4497 - Write Sequencer 401 */ - [4498] = { 0x070F, 0x070F, 0x0000 }, /* R4498 - Write Sequencer 402 */ - [4499] = { 0x010F, 0x010F, 0x0000 }, /* R4499 - Write Sequencer 403 */ - [4500] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4500 - Write Sequencer 404 */ - [4501] = { 0x00FF, 0x00FF, 0x0000 }, /* R4501 - Write Sequencer 405 */ - [4502] = { 0x070F, 0x070F, 0x0000 }, /* R4502 - Write Sequencer 406 */ - [4503] = { 0x010F, 0x010F, 0x0000 }, /* R4503 - Write Sequencer 407 */ - [4504] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4504 - Write Sequencer 408 */ - [4505] = { 0x00FF, 0x00FF, 0x0000 }, /* R4505 - Write Sequencer 409 */ - [4506] = { 0x070F, 0x070F, 0x0000 }, /* R4506 - Write Sequencer 410 */ - [4507] = { 0x010F, 0x010F, 0x0000 }, /* R4507 - Write Sequencer 411 */ - [4508] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4508 - Write Sequencer 412 */ - [4509] = { 0x00FF, 0x00FF, 0x0000 }, /* R4509 - Write Sequencer 413 */ - [4510] = { 0x070F, 0x070F, 0x0000 }, /* R4510 - Write Sequencer 414 */ - [4511] = { 0x010F, 0x010F, 0x0000 }, /* R4511 - Write Sequencer 415 */ - [4512] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4512 - Write Sequencer 416 */ - [4513] = { 0x00FF, 0x00FF, 0x0000 }, /* R4513 - Write Sequencer 417 */ - [4514] = { 0x070F, 0x070F, 0x0000 }, /* R4514 - Write Sequencer 418 */ - [4515] = { 0x010F, 0x010F, 0x0000 }, /* R4515 - Write Sequencer 419 */ - [4516] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4516 - Write Sequencer 420 */ - [4517] = { 0x00FF, 0x00FF, 0x0000 }, /* R4517 - Write Sequencer 421 */ - [4518] = { 0x070F, 0x070F, 0x0000 }, /* R4518 - Write Sequencer 422 */ - [4519] = { 0x010F, 0x010F, 0x0000 }, /* R4519 - Write Sequencer 423 */ - [4520] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4520 - Write Sequencer 424 */ - [4521] = { 0x00FF, 0x00FF, 0x0000 }, /* R4521 - Write Sequencer 425 */ - [4522] = { 0x070F, 0x070F, 0x0000 }, /* R4522 - Write Sequencer 426 */ - [4523] = { 0x010F, 0x010F, 0x0000 }, /* R4523 - Write Sequencer 427 */ - [4524] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4524 - Write Sequencer 428 */ - [4525] = { 0x00FF, 0x00FF, 0x0000 }, /* R4525 - Write Sequencer 429 */ - [4526] = { 0x070F, 0x070F, 0x0000 }, /* R4526 - Write Sequencer 430 */ - [4527] = { 0x010F, 0x010F, 0x0000 }, /* R4527 - Write Sequencer 431 */ - [4528] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4528 - Write Sequencer 432 */ - [4529] = { 0x00FF, 0x00FF, 0x0000 }, /* R4529 - Write Sequencer 433 */ - [4530] = { 0x070F, 0x070F, 0x0000 }, /* R4530 - Write Sequencer 434 */ - [4531] = { 0x010F, 0x010F, 0x0000 }, /* R4531 - Write Sequencer 435 */ - [4532] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4532 - Write Sequencer 436 */ - [4533] = { 0x00FF, 0x00FF, 0x0000 }, /* R4533 - Write Sequencer 437 */ - [4534] = { 0x070F, 0x070F, 0x0000 }, /* R4534 - Write Sequencer 438 */ - [4535] = { 0x010F, 0x010F, 0x0000 }, /* R4535 - Write Sequencer 439 */ - [4536] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4536 - Write Sequencer 440 */ - [4537] = { 0x00FF, 0x00FF, 0x0000 }, /* R4537 - Write Sequencer 441 */ - [4538] = { 0x070F, 0x070F, 0x0000 }, /* R4538 - Write Sequencer 442 */ - [4539] = { 0x010F, 0x010F, 0x0000 }, /* R4539 - Write Sequencer 443 */ - [4540] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4540 - Write Sequencer 444 */ - [4541] = { 0x00FF, 0x00FF, 0x0000 }, /* R4541 - Write Sequencer 445 */ - [4542] = { 0x070F, 0x070F, 0x0000 }, /* R4542 - Write Sequencer 446 */ - [4543] = { 0x010F, 0x010F, 0x0000 }, /* R4543 - Write Sequencer 447 */ - [4544] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4544 - Write Sequencer 448 */ - [4545] = { 0x00FF, 0x00FF, 0x0000 }, /* R4545 - Write Sequencer 449 */ - [4546] = { 0x070F, 0x070F, 0x0000 }, /* R4546 - Write Sequencer 450 */ - [4547] = { 0x010F, 0x010F, 0x0000 }, /* R4547 - Write Sequencer 451 */ - [4548] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4548 - Write Sequencer 452 */ - [4549] = { 0x00FF, 0x00FF, 0x0000 }, /* R4549 - Write Sequencer 453 */ - [4550] = { 0x070F, 0x070F, 0x0000 }, /* R4550 - Write Sequencer 454 */ - [4551] = { 0x010F, 0x010F, 0x0000 }, /* R4551 - Write Sequencer 455 */ - [4552] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4552 - Write Sequencer 456 */ - [4553] = { 0x00FF, 0x00FF, 0x0000 }, /* R4553 - Write Sequencer 457 */ - [4554] = { 0x070F, 0x070F, 0x0000 }, /* R4554 - Write Sequencer 458 */ - [4555] = { 0x010F, 0x010F, 0x0000 }, /* R4555 - Write Sequencer 459 */ - [4556] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4556 - Write Sequencer 460 */ - [4557] = { 0x00FF, 0x00FF, 0x0000 }, /* R4557 - Write Sequencer 461 */ - [4558] = { 0x070F, 0x070F, 0x0000 }, /* R4558 - Write Sequencer 462 */ - [4559] = { 0x010F, 0x010F, 0x0000 }, /* R4559 - Write Sequencer 463 */ - [4560] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4560 - Write Sequencer 464 */ - [4561] = { 0x00FF, 0x00FF, 0x0000 }, /* R4561 - Write Sequencer 465 */ - [4562] = { 0x070F, 0x070F, 0x0000 }, /* R4562 - Write Sequencer 466 */ - [4563] = { 0x010F, 0x010F, 0x0000 }, /* R4563 - Write Sequencer 467 */ - [4564] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4564 - Write Sequencer 468 */ - [4565] = { 0x00FF, 0x00FF, 0x0000 }, /* R4565 - Write Sequencer 469 */ - [4566] = { 0x070F, 0x070F, 0x0000 }, /* R4566 - Write Sequencer 470 */ - [4567] = { 0x010F, 0x010F, 0x0000 }, /* R4567 - Write Sequencer 471 */ - [4568] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4568 - Write Sequencer 472 */ - [4569] = { 0x00FF, 0x00FF, 0x0000 }, /* R4569 - Write Sequencer 473 */ - [4570] = { 0x070F, 0x070F, 0x0000 }, /* R4570 - Write Sequencer 474 */ - [4571] = { 0x010F, 0x010F, 0x0000 }, /* R4571 - Write Sequencer 475 */ - [4572] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4572 - Write Sequencer 476 */ - [4573] = { 0x00FF, 0x00FF, 0x0000 }, /* R4573 - Write Sequencer 477 */ - [4574] = { 0x070F, 0x070F, 0x0000 }, /* R4574 - Write Sequencer 478 */ - [4575] = { 0x010F, 0x010F, 0x0000 }, /* R4575 - Write Sequencer 479 */ - [4576] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4576 - Write Sequencer 480 */ - [4577] = { 0x00FF, 0x00FF, 0x0000 }, /* R4577 - Write Sequencer 481 */ - [4578] = { 0x070F, 0x070F, 0x0000 }, /* R4578 - Write Sequencer 482 */ - [4579] = { 0x010F, 0x010F, 0x0000 }, /* R4579 - Write Sequencer 483 */ - [4580] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4580 - Write Sequencer 484 */ - [4581] = { 0x00FF, 0x00FF, 0x0000 }, /* R4581 - Write Sequencer 485 */ - [4582] = { 0x070F, 0x070F, 0x0000 }, /* R4582 - Write Sequencer 486 */ - [4583] = { 0x010F, 0x010F, 0x0000 }, /* R4583 - Write Sequencer 487 */ - [4584] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4584 - Write Sequencer 488 */ - [4585] = { 0x00FF, 0x00FF, 0x0000 }, /* R4585 - Write Sequencer 489 */ - [4586] = { 0x070F, 0x070F, 0x0000 }, /* R4586 - Write Sequencer 490 */ - [4587] = { 0x010F, 0x010F, 0x0000 }, /* R4587 - Write Sequencer 491 */ - [4588] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4588 - Write Sequencer 492 */ - [4589] = { 0x00FF, 0x00FF, 0x0000 }, /* R4589 - Write Sequencer 493 */ - [4590] = { 0x070F, 0x070F, 0x0000 }, /* R4590 - Write Sequencer 494 */ - [4591] = { 0x010F, 0x010F, 0x0000 }, /* R4591 - Write Sequencer 495 */ - [4592] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4592 - Write Sequencer 496 */ - [4593] = { 0x00FF, 0x00FF, 0x0000 }, /* R4593 - Write Sequencer 497 */ - [4594] = { 0x070F, 0x070F, 0x0000 }, /* R4594 - Write Sequencer 498 */ - [4595] = { 0x010F, 0x010F, 0x0000 }, /* R4595 - Write Sequencer 499 */ - [4596] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4596 - Write Sequencer 500 */ - [4597] = { 0x00FF, 0x00FF, 0x0000 }, /* R4597 - Write Sequencer 501 */ - [4598] = { 0x070F, 0x070F, 0x0000 }, /* R4598 - Write Sequencer 502 */ - [4599] = { 0x010F, 0x010F, 0x0000 }, /* R4599 - Write Sequencer 503 */ - [4600] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4600 - Write Sequencer 504 */ - [4601] = { 0x00FF, 0x00FF, 0x0000 }, /* R4601 - Write Sequencer 505 */ - [4602] = { 0x070F, 0x070F, 0x0000 }, /* R4602 - Write Sequencer 506 */ - [4603] = { 0x010F, 0x010F, 0x0000 }, /* R4603 - Write Sequencer 507 */ - [4604] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4604 - Write Sequencer 508 */ - [4605] = { 0x00FF, 0x00FF, 0x0000 }, /* R4605 - Write Sequencer 509 */ - [4606] = { 0x070F, 0x070F, 0x0000 }, /* R4606 - Write Sequencer 510 */ - [4607] = { 0x010F, 0x010F, 0x0000 }, /* R4607 - Write Sequencer 511 */ - [8192] = { 0x03FF, 0x03FF, 0x0000 }, /* R8192 - DSP2 Instruction RAM 0 */ - [9216] = { 0x003F, 0x003F, 0x0000 }, /* R9216 - DSP2 Address RAM 2 */ - [9217] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9217 - DSP2 Address RAM 1 */ - [9218] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9218 - DSP2 Address RAM 0 */ - [12288] = { 0x00FF, 0x00FF, 0x0000 }, /* R12288 - DSP2 Data1 RAM 1 */ - [12289] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R12289 - DSP2 Data1 RAM 0 */ - [13312] = { 0x00FF, 0x00FF, 0x0000 }, /* R13312 - DSP2 Data2 RAM 1 */ - [13313] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R13313 - DSP2 Data2 RAM 0 */ - [14336] = { 0x00FF, 0x00FF, 0x0000 }, /* R14336 - DSP2 Data3 RAM 1 */ - [14337] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R14337 - DSP2 Data3 RAM 0 */ - [15360] = { 0x07FF, 0x07FF, 0x0000 }, /* R15360 - DSP2 Coeff RAM 0 */ - [16384] = { 0x00FF, 0x00FF, 0x0000 }, /* R16384 - RETUNEADC_SHARED_COEFF_1 */ - [16385] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16385 - RETUNEADC_SHARED_COEFF_0 */ - [16386] = { 0x00FF, 0x00FF, 0x0000 }, /* R16386 - RETUNEDAC_SHARED_COEFF_1 */ - [16387] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16387 - RETUNEDAC_SHARED_COEFF_0 */ - [16388] = { 0x00FF, 0x00FF, 0x0000 }, /* R16388 - SOUNDSTAGE_ENABLES_1 */ - [16389] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16389 - SOUNDSTAGE_ENABLES_0 */ - [16896] = { 0x00FF, 0x00FF, 0x0000 }, /* R16896 - HDBASS_AI_1 */ - [16897] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16897 - HDBASS_AI_0 */ - [16898] = { 0x00FF, 0x00FF, 0x0000 }, /* R16898 - HDBASS_AR_1 */ - [16899] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16899 - HDBASS_AR_0 */ - [16900] = { 0x00FF, 0x00FF, 0x0000 }, /* R16900 - HDBASS_B_1 */ - [16901] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16901 - HDBASS_B_0 */ - [16902] = { 0x00FF, 0x00FF, 0x0000 }, /* R16902 - HDBASS_K_1 */ - [16903] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16903 - HDBASS_K_0 */ - [16904] = { 0x00FF, 0x00FF, 0x0000 }, /* R16904 - HDBASS_N1_1 */ - [16905] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16905 - HDBASS_N1_0 */ - [16906] = { 0x00FF, 0x00FF, 0x0000 }, /* R16906 - HDBASS_N2_1 */ - [16907] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16907 - HDBASS_N2_0 */ - [16908] = { 0x00FF, 0x00FF, 0x0000 }, /* R16908 - HDBASS_N3_1 */ - [16909] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16909 - HDBASS_N3_0 */ - [16910] = { 0x00FF, 0x00FF, 0x0000 }, /* R16910 - HDBASS_N4_1 */ - [16911] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16911 - HDBASS_N4_0 */ - [16912] = { 0x00FF, 0x00FF, 0x0000 }, /* R16912 - HDBASS_N5_1 */ - [16913] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16913 - HDBASS_N5_0 */ - [16914] = { 0x00FF, 0x00FF, 0x0000 }, /* R16914 - HDBASS_X1_1 */ - [16915] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16915 - HDBASS_X1_0 */ - [16916] = { 0x00FF, 0x00FF, 0x0000 }, /* R16916 - HDBASS_X2_1 */ - [16917] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16917 - HDBASS_X2_0 */ - [16918] = { 0x00FF, 0x00FF, 0x0000 }, /* R16918 - HDBASS_X3_1 */ - [16919] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16919 - HDBASS_X3_0 */ - [16920] = { 0x00FF, 0x00FF, 0x0000 }, /* R16920 - HDBASS_ATK_1 */ - [16921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16921 - HDBASS_ATK_0 */ - [16922] = { 0x00FF, 0x00FF, 0x0000 }, /* R16922 - HDBASS_DCY_1 */ - [16923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16923 - HDBASS_DCY_0 */ - [16924] = { 0x00FF, 0x00FF, 0x0000 }, /* R16924 - HDBASS_PG_1 */ - [16925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16925 - HDBASS_PG_0 */ - [17408] = { 0x00FF, 0x00FF, 0x0000 }, /* R17408 - HPF_C_1 */ - [17409] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17409 - HPF_C_0 */ - [17920] = { 0x00FF, 0x00FF, 0x0000 }, /* R17920 - ADCL_RETUNE_C1_1 */ - [17921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17921 - ADCL_RETUNE_C1_0 */ - [17922] = { 0x00FF, 0x00FF, 0x0000 }, /* R17922 - ADCL_RETUNE_C2_1 */ - [17923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17923 - ADCL_RETUNE_C2_0 */ - [17924] = { 0x00FF, 0x00FF, 0x0000 }, /* R17924 - ADCL_RETUNE_C3_1 */ - [17925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17925 - ADCL_RETUNE_C3_0 */ - [17926] = { 0x00FF, 0x00FF, 0x0000 }, /* R17926 - ADCL_RETUNE_C4_1 */ - [17927] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17927 - ADCL_RETUNE_C4_0 */ - [17928] = { 0x00FF, 0x00FF, 0x0000 }, /* R17928 - ADCL_RETUNE_C5_1 */ - [17929] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17929 - ADCL_RETUNE_C5_0 */ - [17930] = { 0x00FF, 0x00FF, 0x0000 }, /* R17930 - ADCL_RETUNE_C6_1 */ - [17931] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17931 - ADCL_RETUNE_C6_0 */ - [17932] = { 0x00FF, 0x00FF, 0x0000 }, /* R17932 - ADCL_RETUNE_C7_1 */ - [17933] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17933 - ADCL_RETUNE_C7_0 */ - [17934] = { 0x00FF, 0x00FF, 0x0000 }, /* R17934 - ADCL_RETUNE_C8_1 */ - [17935] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17935 - ADCL_RETUNE_C8_0 */ - [17936] = { 0x00FF, 0x00FF, 0x0000 }, /* R17936 - ADCL_RETUNE_C9_1 */ - [17937] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17937 - ADCL_RETUNE_C9_0 */ - [17938] = { 0x00FF, 0x00FF, 0x0000 }, /* R17938 - ADCL_RETUNE_C10_1 */ - [17939] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17939 - ADCL_RETUNE_C10_0 */ - [17940] = { 0x00FF, 0x00FF, 0x0000 }, /* R17940 - ADCL_RETUNE_C11_1 */ - [17941] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17941 - ADCL_RETUNE_C11_0 */ - [17942] = { 0x00FF, 0x00FF, 0x0000 }, /* R17942 - ADCL_RETUNE_C12_1 */ - [17943] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17943 - ADCL_RETUNE_C12_0 */ - [17944] = { 0x00FF, 0x00FF, 0x0000 }, /* R17944 - ADCL_RETUNE_C13_1 */ - [17945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17945 - ADCL_RETUNE_C13_0 */ - [17946] = { 0x00FF, 0x00FF, 0x0000 }, /* R17946 - ADCL_RETUNE_C14_1 */ - [17947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17947 - ADCL_RETUNE_C14_0 */ - [17948] = { 0x00FF, 0x00FF, 0x0000 }, /* R17948 - ADCL_RETUNE_C15_1 */ - [17949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17949 - ADCL_RETUNE_C15_0 */ - [17950] = { 0x00FF, 0x00FF, 0x0000 }, /* R17950 - ADCL_RETUNE_C16_1 */ - [17951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17951 - ADCL_RETUNE_C16_0 */ - [17952] = { 0x00FF, 0x00FF, 0x0000 }, /* R17952 - ADCL_RETUNE_C17_1 */ - [17953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17953 - ADCL_RETUNE_C17_0 */ - [17954] = { 0x00FF, 0x00FF, 0x0000 }, /* R17954 - ADCL_RETUNE_C18_1 */ - [17955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17955 - ADCL_RETUNE_C18_0 */ - [17956] = { 0x00FF, 0x00FF, 0x0000 }, /* R17956 - ADCL_RETUNE_C19_1 */ - [17957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17957 - ADCL_RETUNE_C19_0 */ - [17958] = { 0x00FF, 0x00FF, 0x0000 }, /* R17958 - ADCL_RETUNE_C20_1 */ - [17959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17959 - ADCL_RETUNE_C20_0 */ - [17960] = { 0x00FF, 0x00FF, 0x0000 }, /* R17960 - ADCL_RETUNE_C21_1 */ - [17961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17961 - ADCL_RETUNE_C21_0 */ - [17962] = { 0x00FF, 0x00FF, 0x0000 }, /* R17962 - ADCL_RETUNE_C22_1 */ - [17963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17963 - ADCL_RETUNE_C22_0 */ - [17964] = { 0x00FF, 0x00FF, 0x0000 }, /* R17964 - ADCL_RETUNE_C23_1 */ - [17965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17965 - ADCL_RETUNE_C23_0 */ - [17966] = { 0x00FF, 0x00FF, 0x0000 }, /* R17966 - ADCL_RETUNE_C24_1 */ - [17967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17967 - ADCL_RETUNE_C24_0 */ - [17968] = { 0x00FF, 0x00FF, 0x0000 }, /* R17968 - ADCL_RETUNE_C25_1 */ - [17969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17969 - ADCL_RETUNE_C25_0 */ - [17970] = { 0x00FF, 0x00FF, 0x0000 }, /* R17970 - ADCL_RETUNE_C26_1 */ - [17971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17971 - ADCL_RETUNE_C26_0 */ - [17972] = { 0x00FF, 0x00FF, 0x0000 }, /* R17972 - ADCL_RETUNE_C27_1 */ - [17973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17973 - ADCL_RETUNE_C27_0 */ - [17974] = { 0x00FF, 0x00FF, 0x0000 }, /* R17974 - ADCL_RETUNE_C28_1 */ - [17975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17975 - ADCL_RETUNE_C28_0 */ - [17976] = { 0x00FF, 0x00FF, 0x0000 }, /* R17976 - ADCL_RETUNE_C29_1 */ - [17977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17977 - ADCL_RETUNE_C29_0 */ - [17978] = { 0x00FF, 0x00FF, 0x0000 }, /* R17978 - ADCL_RETUNE_C30_1 */ - [17979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17979 - ADCL_RETUNE_C30_0 */ - [17980] = { 0x00FF, 0x00FF, 0x0000 }, /* R17980 - ADCL_RETUNE_C31_1 */ - [17981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17981 - ADCL_RETUNE_C31_0 */ - [17982] = { 0x00FF, 0x00FF, 0x0000 }, /* R17982 - ADCL_RETUNE_C32_1 */ - [17983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17983 - ADCL_RETUNE_C32_0 */ - [18432] = { 0x00FF, 0x00FF, 0x0000 }, /* R18432 - RETUNEADC_PG2_1 */ - [18433] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18433 - RETUNEADC_PG2_0 */ - [18434] = { 0x00FF, 0x00FF, 0x0000 }, /* R18434 - RETUNEADC_PG_1 */ - [18435] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18435 - RETUNEADC_PG_0 */ - [18944] = { 0x00FF, 0x00FF, 0x0000 }, /* R18944 - ADCR_RETUNE_C1_1 */ - [18945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18945 - ADCR_RETUNE_C1_0 */ - [18946] = { 0x00FF, 0x00FF, 0x0000 }, /* R18946 - ADCR_RETUNE_C2_1 */ - [18947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18947 - ADCR_RETUNE_C2_0 */ - [18948] = { 0x00FF, 0x00FF, 0x0000 }, /* R18948 - ADCR_RETUNE_C3_1 */ - [18949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18949 - ADCR_RETUNE_C3_0 */ - [18950] = { 0x00FF, 0x00FF, 0x0000 }, /* R18950 - ADCR_RETUNE_C4_1 */ - [18951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18951 - ADCR_RETUNE_C4_0 */ - [18952] = { 0x00FF, 0x00FF, 0x0000 }, /* R18952 - ADCR_RETUNE_C5_1 */ - [18953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18953 - ADCR_RETUNE_C5_0 */ - [18954] = { 0x00FF, 0x00FF, 0x0000 }, /* R18954 - ADCR_RETUNE_C6_1 */ - [18955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18955 - ADCR_RETUNE_C6_0 */ - [18956] = { 0x00FF, 0x00FF, 0x0000 }, /* R18956 - ADCR_RETUNE_C7_1 */ - [18957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18957 - ADCR_RETUNE_C7_0 */ - [18958] = { 0x00FF, 0x00FF, 0x0000 }, /* R18958 - ADCR_RETUNE_C8_1 */ - [18959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18959 - ADCR_RETUNE_C8_0 */ - [18960] = { 0x00FF, 0x00FF, 0x0000 }, /* R18960 - ADCR_RETUNE_C9_1 */ - [18961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18961 - ADCR_RETUNE_C9_0 */ - [18962] = { 0x00FF, 0x00FF, 0x0000 }, /* R18962 - ADCR_RETUNE_C10_1 */ - [18963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18963 - ADCR_RETUNE_C10_0 */ - [18964] = { 0x00FF, 0x00FF, 0x0000 }, /* R18964 - ADCR_RETUNE_C11_1 */ - [18965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18965 - ADCR_RETUNE_C11_0 */ - [18966] = { 0x00FF, 0x00FF, 0x0000 }, /* R18966 - ADCR_RETUNE_C12_1 */ - [18967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18967 - ADCR_RETUNE_C12_0 */ - [18968] = { 0x00FF, 0x00FF, 0x0000 }, /* R18968 - ADCR_RETUNE_C13_1 */ - [18969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18969 - ADCR_RETUNE_C13_0 */ - [18970] = { 0x00FF, 0x00FF, 0x0000 }, /* R18970 - ADCR_RETUNE_C14_1 */ - [18971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18971 - ADCR_RETUNE_C14_0 */ - [18972] = { 0x00FF, 0x00FF, 0x0000 }, /* R18972 - ADCR_RETUNE_C15_1 */ - [18973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18973 - ADCR_RETUNE_C15_0 */ - [18974] = { 0x00FF, 0x00FF, 0x0000 }, /* R18974 - ADCR_RETUNE_C16_1 */ - [18975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18975 - ADCR_RETUNE_C16_0 */ - [18976] = { 0x00FF, 0x00FF, 0x0000 }, /* R18976 - ADCR_RETUNE_C17_1 */ - [18977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18977 - ADCR_RETUNE_C17_0 */ - [18978] = { 0x00FF, 0x00FF, 0x0000 }, /* R18978 - ADCR_RETUNE_C18_1 */ - [18979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18979 - ADCR_RETUNE_C18_0 */ - [18980] = { 0x00FF, 0x00FF, 0x0000 }, /* R18980 - ADCR_RETUNE_C19_1 */ - [18981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18981 - ADCR_RETUNE_C19_0 */ - [18982] = { 0x00FF, 0x00FF, 0x0000 }, /* R18982 - ADCR_RETUNE_C20_1 */ - [18983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18983 - ADCR_RETUNE_C20_0 */ - [18984] = { 0x00FF, 0x00FF, 0x0000 }, /* R18984 - ADCR_RETUNE_C21_1 */ - [18985] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18985 - ADCR_RETUNE_C21_0 */ - [18986] = { 0x00FF, 0x00FF, 0x0000 }, /* R18986 - ADCR_RETUNE_C22_1 */ - [18987] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18987 - ADCR_RETUNE_C22_0 */ - [18988] = { 0x00FF, 0x00FF, 0x0000 }, /* R18988 - ADCR_RETUNE_C23_1 */ - [18989] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18989 - ADCR_RETUNE_C23_0 */ - [18990] = { 0x00FF, 0x00FF, 0x0000 }, /* R18990 - ADCR_RETUNE_C24_1 */ - [18991] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18991 - ADCR_RETUNE_C24_0 */ - [18992] = { 0x00FF, 0x00FF, 0x0000 }, /* R18992 - ADCR_RETUNE_C25_1 */ - [18993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18993 - ADCR_RETUNE_C25_0 */ - [18994] = { 0x00FF, 0x00FF, 0x0000 }, /* R18994 - ADCR_RETUNE_C26_1 */ - [18995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18995 - ADCR_RETUNE_C26_0 */ - [18996] = { 0x00FF, 0x00FF, 0x0000 }, /* R18996 - ADCR_RETUNE_C27_1 */ - [18997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18997 - ADCR_RETUNE_C27_0 */ - [18998] = { 0x00FF, 0x00FF, 0x0000 }, /* R18998 - ADCR_RETUNE_C28_1 */ - [18999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18999 - ADCR_RETUNE_C28_0 */ - [19000] = { 0x00FF, 0x00FF, 0x0000 }, /* R19000 - ADCR_RETUNE_C29_1 */ - [19001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19001 - ADCR_RETUNE_C29_0 */ - [19002] = { 0x00FF, 0x00FF, 0x0000 }, /* R19002 - ADCR_RETUNE_C30_1 */ - [19003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19003 - ADCR_RETUNE_C30_0 */ - [19004] = { 0x00FF, 0x00FF, 0x0000 }, /* R19004 - ADCR_RETUNE_C31_1 */ - [19005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19005 - ADCR_RETUNE_C31_0 */ - [19006] = { 0x00FF, 0x00FF, 0x0000 }, /* R19006 - ADCR_RETUNE_C32_1 */ - [19007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19007 - ADCR_RETUNE_C32_0 */ - [19456] = { 0x00FF, 0x00FF, 0x0000 }, /* R19456 - DACL_RETUNE_C1_1 */ - [19457] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19457 - DACL_RETUNE_C1_0 */ - [19458] = { 0x00FF, 0x00FF, 0x0000 }, /* R19458 - DACL_RETUNE_C2_1 */ - [19459] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19459 - DACL_RETUNE_C2_0 */ - [19460] = { 0x00FF, 0x00FF, 0x0000 }, /* R19460 - DACL_RETUNE_C3_1 */ - [19461] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19461 - DACL_RETUNE_C3_0 */ - [19462] = { 0x00FF, 0x00FF, 0x0000 }, /* R19462 - DACL_RETUNE_C4_1 */ - [19463] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19463 - DACL_RETUNE_C4_0 */ - [19464] = { 0x00FF, 0x00FF, 0x0000 }, /* R19464 - DACL_RETUNE_C5_1 */ - [19465] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19465 - DACL_RETUNE_C5_0 */ - [19466] = { 0x00FF, 0x00FF, 0x0000 }, /* R19466 - DACL_RETUNE_C6_1 */ - [19467] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19467 - DACL_RETUNE_C6_0 */ - [19468] = { 0x00FF, 0x00FF, 0x0000 }, /* R19468 - DACL_RETUNE_C7_1 */ - [19469] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19469 - DACL_RETUNE_C7_0 */ - [19470] = { 0x00FF, 0x00FF, 0x0000 }, /* R19470 - DACL_RETUNE_C8_1 */ - [19471] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19471 - DACL_RETUNE_C8_0 */ - [19472] = { 0x00FF, 0x00FF, 0x0000 }, /* R19472 - DACL_RETUNE_C9_1 */ - [19473] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19473 - DACL_RETUNE_C9_0 */ - [19474] = { 0x00FF, 0x00FF, 0x0000 }, /* R19474 - DACL_RETUNE_C10_1 */ - [19475] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19475 - DACL_RETUNE_C10_0 */ - [19476] = { 0x00FF, 0x00FF, 0x0000 }, /* R19476 - DACL_RETUNE_C11_1 */ - [19477] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19477 - DACL_RETUNE_C11_0 */ - [19478] = { 0x00FF, 0x00FF, 0x0000 }, /* R19478 - DACL_RETUNE_C12_1 */ - [19479] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19479 - DACL_RETUNE_C12_0 */ - [19480] = { 0x00FF, 0x00FF, 0x0000 }, /* R19480 - DACL_RETUNE_C13_1 */ - [19481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19481 - DACL_RETUNE_C13_0 */ - [19482] = { 0x00FF, 0x00FF, 0x0000 }, /* R19482 - DACL_RETUNE_C14_1 */ - [19483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19483 - DACL_RETUNE_C14_0 */ - [19484] = { 0x00FF, 0x00FF, 0x0000 }, /* R19484 - DACL_RETUNE_C15_1 */ - [19485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19485 - DACL_RETUNE_C15_0 */ - [19486] = { 0x00FF, 0x00FF, 0x0000 }, /* R19486 - DACL_RETUNE_C16_1 */ - [19487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19487 - DACL_RETUNE_C16_0 */ - [19488] = { 0x00FF, 0x00FF, 0x0000 }, /* R19488 - DACL_RETUNE_C17_1 */ - [19489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19489 - DACL_RETUNE_C17_0 */ - [19490] = { 0x00FF, 0x00FF, 0x0000 }, /* R19490 - DACL_RETUNE_C18_1 */ - [19491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19491 - DACL_RETUNE_C18_0 */ - [19492] = { 0x00FF, 0x00FF, 0x0000 }, /* R19492 - DACL_RETUNE_C19_1 */ - [19493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19493 - DACL_RETUNE_C19_0 */ - [19494] = { 0x00FF, 0x00FF, 0x0000 }, /* R19494 - DACL_RETUNE_C20_1 */ - [19495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19495 - DACL_RETUNE_C20_0 */ - [19496] = { 0x00FF, 0x00FF, 0x0000 }, /* R19496 - DACL_RETUNE_C21_1 */ - [19497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19497 - DACL_RETUNE_C21_0 */ - [19498] = { 0x00FF, 0x00FF, 0x0000 }, /* R19498 - DACL_RETUNE_C22_1 */ - [19499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19499 - DACL_RETUNE_C22_0 */ - [19500] = { 0x00FF, 0x00FF, 0x0000 }, /* R19500 - DACL_RETUNE_C23_1 */ - [19501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19501 - DACL_RETUNE_C23_0 */ - [19502] = { 0x00FF, 0x00FF, 0x0000 }, /* R19502 - DACL_RETUNE_C24_1 */ - [19503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19503 - DACL_RETUNE_C24_0 */ - [19504] = { 0x00FF, 0x00FF, 0x0000 }, /* R19504 - DACL_RETUNE_C25_1 */ - [19505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19505 - DACL_RETUNE_C25_0 */ - [19506] = { 0x00FF, 0x00FF, 0x0000 }, /* R19506 - DACL_RETUNE_C26_1 */ - [19507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19507 - DACL_RETUNE_C26_0 */ - [19508] = { 0x00FF, 0x00FF, 0x0000 }, /* R19508 - DACL_RETUNE_C27_1 */ - [19509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19509 - DACL_RETUNE_C27_0 */ - [19510] = { 0x00FF, 0x00FF, 0x0000 }, /* R19510 - DACL_RETUNE_C28_1 */ - [19511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19511 - DACL_RETUNE_C28_0 */ - [19512] = { 0x00FF, 0x00FF, 0x0000 }, /* R19512 - DACL_RETUNE_C29_1 */ - [19513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19513 - DACL_RETUNE_C29_0 */ - [19514] = { 0x00FF, 0x00FF, 0x0000 }, /* R19514 - DACL_RETUNE_C30_1 */ - [19515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19515 - DACL_RETUNE_C30_0 */ - [19516] = { 0x00FF, 0x00FF, 0x0000 }, /* R19516 - DACL_RETUNE_C31_1 */ - [19517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19517 - DACL_RETUNE_C31_0 */ - [19518] = { 0x00FF, 0x00FF, 0x0000 }, /* R19518 - DACL_RETUNE_C32_1 */ - [19519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19519 - DACL_RETUNE_C32_0 */ - [19968] = { 0x00FF, 0x00FF, 0x0000 }, /* R19968 - RETUNEDAC_PG2_1 */ - [19969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19969 - RETUNEDAC_PG2_0 */ - [19970] = { 0x00FF, 0x00FF, 0x0000 }, /* R19970 - RETUNEDAC_PG_1 */ - [19971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19971 - RETUNEDAC_PG_0 */ - [20480] = { 0x00FF, 0x00FF, 0x0000 }, /* R20480 - DACR_RETUNE_C1_1 */ - [20481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20481 - DACR_RETUNE_C1_0 */ - [20482] = { 0x00FF, 0x00FF, 0x0000 }, /* R20482 - DACR_RETUNE_C2_1 */ - [20483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20483 - DACR_RETUNE_C2_0 */ - [20484] = { 0x00FF, 0x00FF, 0x0000 }, /* R20484 - DACR_RETUNE_C3_1 */ - [20485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20485 - DACR_RETUNE_C3_0 */ - [20486] = { 0x00FF, 0x00FF, 0x0000 }, /* R20486 - DACR_RETUNE_C4_1 */ - [20487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20487 - DACR_RETUNE_C4_0 */ - [20488] = { 0x00FF, 0x00FF, 0x0000 }, /* R20488 - DACR_RETUNE_C5_1 */ - [20489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20489 - DACR_RETUNE_C5_0 */ - [20490] = { 0x00FF, 0x00FF, 0x0000 }, /* R20490 - DACR_RETUNE_C6_1 */ - [20491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20491 - DACR_RETUNE_C6_0 */ - [20492] = { 0x00FF, 0x00FF, 0x0000 }, /* R20492 - DACR_RETUNE_C7_1 */ - [20493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20493 - DACR_RETUNE_C7_0 */ - [20494] = { 0x00FF, 0x00FF, 0x0000 }, /* R20494 - DACR_RETUNE_C8_1 */ - [20495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20495 - DACR_RETUNE_C8_0 */ - [20496] = { 0x00FF, 0x00FF, 0x0000 }, /* R20496 - DACR_RETUNE_C9_1 */ - [20497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20497 - DACR_RETUNE_C9_0 */ - [20498] = { 0x00FF, 0x00FF, 0x0000 }, /* R20498 - DACR_RETUNE_C10_1 */ - [20499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20499 - DACR_RETUNE_C10_0 */ - [20500] = { 0x00FF, 0x00FF, 0x0000 }, /* R20500 - DACR_RETUNE_C11_1 */ - [20501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20501 - DACR_RETUNE_C11_0 */ - [20502] = { 0x00FF, 0x00FF, 0x0000 }, /* R20502 - DACR_RETUNE_C12_1 */ - [20503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20503 - DACR_RETUNE_C12_0 */ - [20504] = { 0x00FF, 0x00FF, 0x0000 }, /* R20504 - DACR_RETUNE_C13_1 */ - [20505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20505 - DACR_RETUNE_C13_0 */ - [20506] = { 0x00FF, 0x00FF, 0x0000 }, /* R20506 - DACR_RETUNE_C14_1 */ - [20507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20507 - DACR_RETUNE_C14_0 */ - [20508] = { 0x00FF, 0x00FF, 0x0000 }, /* R20508 - DACR_RETUNE_C15_1 */ - [20509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20509 - DACR_RETUNE_C15_0 */ - [20510] = { 0x00FF, 0x00FF, 0x0000 }, /* R20510 - DACR_RETUNE_C16_1 */ - [20511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20511 - DACR_RETUNE_C16_0 */ - [20512] = { 0x00FF, 0x00FF, 0x0000 }, /* R20512 - DACR_RETUNE_C17_1 */ - [20513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20513 - DACR_RETUNE_C17_0 */ - [20514] = { 0x00FF, 0x00FF, 0x0000 }, /* R20514 - DACR_RETUNE_C18_1 */ - [20515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20515 - DACR_RETUNE_C18_0 */ - [20516] = { 0x00FF, 0x00FF, 0x0000 }, /* R20516 - DACR_RETUNE_C19_1 */ - [20517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20517 - DACR_RETUNE_C19_0 */ - [20518] = { 0x00FF, 0x00FF, 0x0000 }, /* R20518 - DACR_RETUNE_C20_1 */ - [20519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20519 - DACR_RETUNE_C20_0 */ - [20520] = { 0x00FF, 0x00FF, 0x0000 }, /* R20520 - DACR_RETUNE_C21_1 */ - [20521] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20521 - DACR_RETUNE_C21_0 */ - [20522] = { 0x00FF, 0x00FF, 0x0000 }, /* R20522 - DACR_RETUNE_C22_1 */ - [20523] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20523 - DACR_RETUNE_C22_0 */ - [20524] = { 0x00FF, 0x00FF, 0x0000 }, /* R20524 - DACR_RETUNE_C23_1 */ - [20525] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20525 - DACR_RETUNE_C23_0 */ - [20526] = { 0x00FF, 0x00FF, 0x0000 }, /* R20526 - DACR_RETUNE_C24_1 */ - [20527] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20527 - DACR_RETUNE_C24_0 */ - [20528] = { 0x00FF, 0x00FF, 0x0000 }, /* R20528 - DACR_RETUNE_C25_1 */ - [20529] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20529 - DACR_RETUNE_C25_0 */ - [20530] = { 0x00FF, 0x00FF, 0x0000 }, /* R20530 - DACR_RETUNE_C26_1 */ - [20531] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20531 - DACR_RETUNE_C26_0 */ - [20532] = { 0x00FF, 0x00FF, 0x0000 }, /* R20532 - DACR_RETUNE_C27_1 */ - [20533] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20533 - DACR_RETUNE_C27_0 */ - [20534] = { 0x00FF, 0x00FF, 0x0000 }, /* R20534 - DACR_RETUNE_C28_1 */ - [20535] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20535 - DACR_RETUNE_C28_0 */ - [20536] = { 0x00FF, 0x00FF, 0x0000 }, /* R20536 - DACR_RETUNE_C29_1 */ - [20537] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20537 - DACR_RETUNE_C29_0 */ - [20538] = { 0x00FF, 0x00FF, 0x0000 }, /* R20538 - DACR_RETUNE_C30_1 */ - [20539] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20539 - DACR_RETUNE_C30_0 */ - [20540] = { 0x00FF, 0x00FF, 0x0000 }, /* R20540 - DACR_RETUNE_C31_1 */ - [20541] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20541 - DACR_RETUNE_C31_0 */ - [20542] = { 0x00FF, 0x00FF, 0x0000 }, /* R20542 - DACR_RETUNE_C32_1 */ - [20543] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20543 - DACR_RETUNE_C32_0 */ - [20992] = { 0x00FF, 0x00FF, 0x0000 }, /* R20992 - VSS_XHD2_1 */ - [20993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20993 - VSS_XHD2_0 */ - [20994] = { 0x00FF, 0x00FF, 0x0000 }, /* R20994 - VSS_XHD3_1 */ - [20995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20995 - VSS_XHD3_0 */ - [20996] = { 0x00FF, 0x00FF, 0x0000 }, /* R20996 - VSS_XHN1_1 */ - [20997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20997 - VSS_XHN1_0 */ - [20998] = { 0x00FF, 0x00FF, 0x0000 }, /* R20998 - VSS_XHN2_1 */ - [20999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20999 - VSS_XHN2_0 */ - [21000] = { 0x00FF, 0x00FF, 0x0000 }, /* R21000 - VSS_XHN3_1 */ - [21001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21001 - VSS_XHN3_0 */ - [21002] = { 0x00FF, 0x00FF, 0x0000 }, /* R21002 - VSS_XLA_1 */ - [21003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21003 - VSS_XLA_0 */ - [21004] = { 0x00FF, 0x00FF, 0x0000 }, /* R21004 - VSS_XLB_1 */ - [21005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21005 - VSS_XLB_0 */ - [21006] = { 0x00FF, 0x00FF, 0x0000 }, /* R21006 - VSS_XLG_1 */ - [21007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21007 - VSS_XLG_0 */ - [21008] = { 0x00FF, 0x00FF, 0x0000 }, /* R21008 - VSS_PG2_1 */ - [21009] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21009 - VSS_PG2_0 */ - [21010] = { 0x00FF, 0x00FF, 0x0000 }, /* R21010 - VSS_PG_1 */ - [21011] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21011 - VSS_PG_0 */ - [21012] = { 0x00FF, 0x00FF, 0x0000 }, /* R21012 - VSS_XTD1_1 */ - [21013] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21013 - VSS_XTD1_0 */ - [21014] = { 0x00FF, 0x00FF, 0x0000 }, /* R21014 - VSS_XTD2_1 */ - [21015] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21015 - VSS_XTD2_0 */ - [21016] = { 0x00FF, 0x00FF, 0x0000 }, /* R21016 - VSS_XTD3_1 */ - [21017] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21017 - VSS_XTD3_0 */ - [21018] = { 0x00FF, 0x00FF, 0x0000 }, /* R21018 - VSS_XTD4_1 */ - [21019] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21019 - VSS_XTD4_0 */ - [21020] = { 0x00FF, 0x00FF, 0x0000 }, /* R21020 - VSS_XTD5_1 */ - [21021] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21021 - VSS_XTD5_0 */ - [21022] = { 0x00FF, 0x00FF, 0x0000 }, /* R21022 - VSS_XTD6_1 */ - [21023] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21023 - VSS_XTD6_0 */ - [21024] = { 0x00FF, 0x00FF, 0x0000 }, /* R21024 - VSS_XTD7_1 */ - [21025] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21025 - VSS_XTD7_0 */ - [21026] = { 0x00FF, 0x00FF, 0x0000 }, /* R21026 - VSS_XTD8_1 */ - [21027] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21027 - VSS_XTD8_0 */ - [21028] = { 0x00FF, 0x00FF, 0x0000 }, /* R21028 - VSS_XTD9_1 */ - [21029] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21029 - VSS_XTD9_0 */ - [21030] = { 0x00FF, 0x00FF, 0x0000 }, /* R21030 - VSS_XTD10_1 */ - [21031] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21031 - VSS_XTD10_0 */ - [21032] = { 0x00FF, 0x00FF, 0x0000 }, /* R21032 - VSS_XTD11_1 */ - [21033] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21033 - VSS_XTD11_0 */ - [21034] = { 0x00FF, 0x00FF, 0x0000 }, /* R21034 - VSS_XTD12_1 */ - [21035] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21035 - VSS_XTD12_0 */ - [21036] = { 0x00FF, 0x00FF, 0x0000 }, /* R21036 - VSS_XTD13_1 */ - [21037] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21037 - VSS_XTD13_0 */ - [21038] = { 0x00FF, 0x00FF, 0x0000 }, /* R21038 - VSS_XTD14_1 */ - [21039] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21039 - VSS_XTD14_0 */ - [21040] = { 0x00FF, 0x00FF, 0x0000 }, /* R21040 - VSS_XTD15_1 */ - [21041] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21041 - VSS_XTD15_0 */ - [21042] = { 0x00FF, 0x00FF, 0x0000 }, /* R21042 - VSS_XTD16_1 */ - [21043] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21043 - VSS_XTD16_0 */ - [21044] = { 0x00FF, 0x00FF, 0x0000 }, /* R21044 - VSS_XTD17_1 */ - [21045] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21045 - VSS_XTD17_0 */ - [21046] = { 0x00FF, 0x00FF, 0x0000 }, /* R21046 - VSS_XTD18_1 */ - [21047] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21047 - VSS_XTD18_0 */ - [21048] = { 0x00FF, 0x00FF, 0x0000 }, /* R21048 - VSS_XTD19_1 */ - [21049] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21049 - VSS_XTD19_0 */ - [21050] = { 0x00FF, 0x00FF, 0x0000 }, /* R21050 - VSS_XTD20_1 */ - [21051] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21051 - VSS_XTD20_0 */ - [21052] = { 0x00FF, 0x00FF, 0x0000 }, /* R21052 - VSS_XTD21_1 */ - [21053] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21053 - VSS_XTD21_0 */ - [21054] = { 0x00FF, 0x00FF, 0x0000 }, /* R21054 - VSS_XTD22_1 */ - [21055] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21055 - VSS_XTD22_0 */ - [21056] = { 0x00FF, 0x00FF, 0x0000 }, /* R21056 - VSS_XTD23_1 */ - [21057] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21057 - VSS_XTD23_0 */ - [21058] = { 0x00FF, 0x00FF, 0x0000 }, /* R21058 - VSS_XTD24_1 */ - [21059] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21059 - VSS_XTD24_0 */ - [21060] = { 0x00FF, 0x00FF, 0x0000 }, /* R21060 - VSS_XTD25_1 */ - [21061] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21061 - VSS_XTD25_0 */ - [21062] = { 0x00FF, 0x00FF, 0x0000 }, /* R21062 - VSS_XTD26_1 */ - [21063] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21063 - VSS_XTD26_0 */ - [21064] = { 0x00FF, 0x00FF, 0x0000 }, /* R21064 - VSS_XTD27_1 */ - [21065] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21065 - VSS_XTD27_0 */ - [21066] = { 0x00FF, 0x00FF, 0x0000 }, /* R21066 - VSS_XTD28_1 */ - [21067] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21067 - VSS_XTD28_0 */ - [21068] = { 0x00FF, 0x00FF, 0x0000 }, /* R21068 - VSS_XTD29_1 */ - [21069] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21069 - VSS_XTD29_0 */ - [21070] = { 0x00FF, 0x00FF, 0x0000 }, /* R21070 - VSS_XTD30_1 */ - [21071] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21071 - VSS_XTD30_0 */ - [21072] = { 0x00FF, 0x00FF, 0x0000 }, /* R21072 - VSS_XTD31_1 */ - [21073] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21073 - VSS_XTD31_0 */ - [21074] = { 0x00FF, 0x00FF, 0x0000 }, /* R21074 - VSS_XTD32_1 */ - [21075] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21075 - VSS_XTD32_0 */ - [21076] = { 0x00FF, 0x00FF, 0x0000 }, /* R21076 - VSS_XTS1_1 */ - [21077] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21077 - VSS_XTS1_0 */ - [21078] = { 0x00FF, 0x00FF, 0x0000 }, /* R21078 - VSS_XTS2_1 */ - [21079] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21079 - VSS_XTS2_0 */ - [21080] = { 0x00FF, 0x00FF, 0x0000 }, /* R21080 - VSS_XTS3_1 */ - [21081] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21081 - VSS_XTS3_0 */ - [21082] = { 0x00FF, 0x00FF, 0x0000 }, /* R21082 - VSS_XTS4_1 */ - [21083] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21083 - VSS_XTS4_0 */ - [21084] = { 0x00FF, 0x00FF, 0x0000 }, /* R21084 - VSS_XTS5_1 */ - [21085] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21085 - VSS_XTS5_0 */ - [21086] = { 0x00FF, 0x00FF, 0x0000 }, /* R21086 - VSS_XTS6_1 */ - [21087] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21087 - VSS_XTS6_0 */ - [21088] = { 0x00FF, 0x00FF, 0x0000 }, /* R21088 - VSS_XTS7_1 */ - [21089] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21089 - VSS_XTS7_0 */ - [21090] = { 0x00FF, 0x00FF, 0x0000 }, /* R21090 - VSS_XTS8_1 */ - [21091] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21091 - VSS_XTS8_0 */ - [21092] = { 0x00FF, 0x00FF, 0x0000 }, /* R21092 - VSS_XTS9_1 */ - [21093] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21093 - VSS_XTS9_0 */ - [21094] = { 0x00FF, 0x00FF, 0x0000 }, /* R21094 - VSS_XTS10_1 */ - [21095] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21095 - VSS_XTS10_0 */ - [21096] = { 0x00FF, 0x00FF, 0x0000 }, /* R21096 - VSS_XTS11_1 */ - [21097] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21097 - VSS_XTS11_0 */ - [21098] = { 0x00FF, 0x00FF, 0x0000 }, /* R21098 - VSS_XTS12_1 */ - [21099] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21099 - VSS_XTS12_0 */ - [21100] = { 0x00FF, 0x00FF, 0x0000 }, /* R21100 - VSS_XTS13_1 */ - [21101] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21101 - VSS_XTS13_0 */ - [21102] = { 0x00FF, 0x00FF, 0x0000 }, /* R21102 - VSS_XTS14_1 */ - [21103] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21103 - VSS_XTS14_0 */ - [21104] = { 0x00FF, 0x00FF, 0x0000 }, /* R21104 - VSS_XTS15_1 */ - [21105] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21105 - VSS_XTS15_0 */ - [21106] = { 0x00FF, 0x00FF, 0x0000 }, /* R21106 - VSS_XTS16_1 */ - [21107] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21107 - VSS_XTS16_0 */ - [21108] = { 0x00FF, 0x00FF, 0x0000 }, /* R21108 - VSS_XTS17_1 */ - [21109] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21109 - VSS_XTS17_0 */ - [21110] = { 0x00FF, 0x00FF, 0x0000 }, /* R21110 - VSS_XTS18_1 */ - [21111] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21111 - VSS_XTS18_0 */ - [21112] = { 0x00FF, 0x00FF, 0x0000 }, /* R21112 - VSS_XTS19_1 */ - [21113] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21113 - VSS_XTS19_0 */ - [21114] = { 0x00FF, 0x00FF, 0x0000 }, /* R21114 - VSS_XTS20_1 */ - [21115] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21115 - VSS_XTS20_0 */ - [21116] = { 0x00FF, 0x00FF, 0x0000 }, /* R21116 - VSS_XTS21_1 */ - [21117] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21117 - VSS_XTS21_0 */ - [21118] = { 0x00FF, 0x00FF, 0x0000 }, /* R21118 - VSS_XTS22_1 */ - [21119] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21119 - VSS_XTS22_0 */ - [21120] = { 0x00FF, 0x00FF, 0x0000 }, /* R21120 - VSS_XTS23_1 */ - [21121] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21121 - VSS_XTS23_0 */ - [21122] = { 0x00FF, 0x00FF, 0x0000 }, /* R21122 - VSS_XTS24_1 */ - [21123] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21123 - VSS_XTS24_0 */ - [21124] = { 0x00FF, 0x00FF, 0x0000 }, /* R21124 - VSS_XTS25_1 */ - [21125] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21125 - VSS_XTS25_0 */ - [21126] = { 0x00FF, 0x00FF, 0x0000 }, /* R21126 - VSS_XTS26_1 */ - [21127] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21127 - VSS_XTS26_0 */ - [21128] = { 0x00FF, 0x00FF, 0x0000 }, /* R21128 - VSS_XTS27_1 */ - [21129] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21129 - VSS_XTS27_0 */ - [21130] = { 0x00FF, 0x00FF, 0x0000 }, /* R21130 - VSS_XTS28_1 */ - [21131] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21131 - VSS_XTS28_0 */ - [21132] = { 0x00FF, 0x00FF, 0x0000 }, /* R21132 - VSS_XTS29_1 */ - [21133] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21133 - VSS_XTS29_0 */ - [21134] = { 0x00FF, 0x00FF, 0x0000 }, /* R21134 - VSS_XTS30_1 */ - [21135] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21135 - VSS_XTS30_0 */ - [21136] = { 0x00FF, 0x00FF, 0x0000 }, /* R21136 - VSS_XTS31_1 */ - [21137] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21137 - VSS_XTS31_0 */ - [21138] = { 0x00FF, 0x00FF, 0x0000 }, /* R21138 - VSS_XTS32_1 */ - [21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */ -}; - static bool wm8962_volatile_register(struct device *dev, unsigned int reg) { - if (wm8962_reg_access[reg].vol) - return 1; - else - return 0; + switch (reg) { + case WM8962_CLOCKING1: + case WM8962_CLOCKING2: + case WM8962_SOFTWARE_RESET: + case WM8962_ALC2: + case WM8962_THERMAL_SHUTDOWN_STATUS: + case WM8962_ADDITIONAL_CONTROL_4: + case WM8962_CLASS_D_CONTROL_1: + case WM8962_DC_SERVO_6: + case WM8962_INTERRUPT_STATUS_1: + case WM8962_INTERRUPT_STATUS_2: + case WM8962_DSP2_EXECCONTROL: + return true; + default: + return false; + } } static bool wm8962_readable_register(struct device *dev, unsigned int reg) { - if (wm8962_reg_access[reg].read) - return 1; - else - return 0; + switch (reg) { + case WM8962_LEFT_INPUT_VOLUME: + case WM8962_RIGHT_INPUT_VOLUME: + case WM8962_HPOUTL_VOLUME: + case WM8962_HPOUTR_VOLUME: + case WM8962_CLOCKING1: + case WM8962_ADC_DAC_CONTROL_1: + case WM8962_ADC_DAC_CONTROL_2: + case WM8962_AUDIO_INTERFACE_0: + case WM8962_CLOCKING2: + case WM8962_AUDIO_INTERFACE_1: + case WM8962_LEFT_DAC_VOLUME: + case WM8962_RIGHT_DAC_VOLUME: + case WM8962_AUDIO_INTERFACE_2: + case WM8962_SOFTWARE_RESET: + case WM8962_ALC1: + case WM8962_ALC2: + case WM8962_ALC3: + case WM8962_NOISE_GATE: + case WM8962_LEFT_ADC_VOLUME: + case WM8962_RIGHT_ADC_VOLUME: + case WM8962_ADDITIONAL_CONTROL_1: + case WM8962_ADDITIONAL_CONTROL_2: + case WM8962_PWR_MGMT_1: + case WM8962_PWR_MGMT_2: + case WM8962_ADDITIONAL_CONTROL_3: + case WM8962_ANTI_POP: + case WM8962_CLOCKING_3: + case WM8962_INPUT_MIXER_CONTROL_1: + case WM8962_LEFT_INPUT_MIXER_VOLUME: + case WM8962_RIGHT_INPUT_MIXER_VOLUME: + case WM8962_INPUT_MIXER_CONTROL_2: + case WM8962_INPUT_BIAS_CONTROL: + case WM8962_LEFT_INPUT_PGA_CONTROL: + case WM8962_RIGHT_INPUT_PGA_CONTROL: + case WM8962_SPKOUTL_VOLUME: + case WM8962_SPKOUTR_VOLUME: + case WM8962_THERMAL_SHUTDOWN_STATUS: + case WM8962_ADDITIONAL_CONTROL_4: + case WM8962_CLASS_D_CONTROL_1: + case WM8962_CLASS_D_CONTROL_2: + case WM8962_CLOCKING_4: + case WM8962_DAC_DSP_MIXING_1: + case WM8962_DAC_DSP_MIXING_2: + case WM8962_DC_SERVO_0: + case WM8962_DC_SERVO_1: + case WM8962_DC_SERVO_4: + case WM8962_DC_SERVO_6: + case WM8962_ANALOGUE_PGA_BIAS: + case WM8962_ANALOGUE_HP_0: + case WM8962_ANALOGUE_HP_2: + case WM8962_CHARGE_PUMP_1: + case WM8962_CHARGE_PUMP_B: + case WM8962_WRITE_SEQUENCER_CONTROL_1: + case WM8962_WRITE_SEQUENCER_CONTROL_2: + case WM8962_WRITE_SEQUENCER_CONTROL_3: + case WM8962_CONTROL_INTERFACE: + case WM8962_MIXER_ENABLES: + case WM8962_HEADPHONE_MIXER_1: + case WM8962_HEADPHONE_MIXER_2: + case WM8962_HEADPHONE_MIXER_3: + case WM8962_HEADPHONE_MIXER_4: + case WM8962_SPEAKER_MIXER_1: + case WM8962_SPEAKER_MIXER_2: + case WM8962_SPEAKER_MIXER_3: + case WM8962_SPEAKER_MIXER_4: + case WM8962_SPEAKER_MIXER_5: + case WM8962_BEEP_GENERATOR_1: + case WM8962_OSCILLATOR_TRIM_3: + case WM8962_OSCILLATOR_TRIM_4: + case WM8962_OSCILLATOR_TRIM_7: + case WM8962_ANALOGUE_CLOCKING1: + case WM8962_ANALOGUE_CLOCKING2: + case WM8962_ANALOGUE_CLOCKING3: + case WM8962_PLL_SOFTWARE_RESET: + case WM8962_PLL2: + case WM8962_PLL_4: + case WM8962_PLL_9: + case WM8962_PLL_10: + case WM8962_PLL_11: + case WM8962_PLL_12: + case WM8962_PLL_13: + case WM8962_PLL_14: + case WM8962_PLL_15: + case WM8962_PLL_16: + case WM8962_FLL_CONTROL_1: + case WM8962_FLL_CONTROL_2: + case WM8962_FLL_CONTROL_3: + case WM8962_FLL_CONTROL_5: + case WM8962_FLL_CONTROL_6: + case WM8962_FLL_CONTROL_7: + case WM8962_FLL_CONTROL_8: + case WM8962_GENERAL_TEST_1: + case WM8962_DF1: + case WM8962_DF2: + case WM8962_DF3: + case WM8962_DF4: + case WM8962_DF5: + case WM8962_DF6: + case WM8962_DF7: + case WM8962_LHPF1: + case WM8962_LHPF2: + case WM8962_THREED1: + case WM8962_THREED2: + case WM8962_THREED3: + case WM8962_THREED4: + case WM8962_DRC_1: + case WM8962_DRC_2: + case WM8962_DRC_3: + case WM8962_DRC_4: + case WM8962_DRC_5: + case WM8962_TLOOPBACK: + case WM8962_EQ1: + case WM8962_EQ2: + case WM8962_EQ3: + case WM8962_EQ4: + case WM8962_EQ5: + case WM8962_EQ6: + case WM8962_EQ7: + case WM8962_EQ8: + case WM8962_EQ9: + case WM8962_EQ10: + case WM8962_EQ11: + case WM8962_EQ12: + case WM8962_EQ13: + case WM8962_EQ14: + case WM8962_EQ15: + case WM8962_EQ16: + case WM8962_EQ17: + case WM8962_EQ18: + case WM8962_EQ19: + case WM8962_EQ20: + case WM8962_EQ21: + case WM8962_EQ22: + case WM8962_EQ23: + case WM8962_EQ24: + case WM8962_EQ25: + case WM8962_EQ26: + case WM8962_EQ27: + case WM8962_EQ28: + case WM8962_EQ29: + case WM8962_EQ30: + case WM8962_EQ31: + case WM8962_EQ32: + case WM8962_EQ33: + case WM8962_EQ34: + case WM8962_EQ35: + case WM8962_EQ36: + case WM8962_EQ37: + case WM8962_EQ38: + case WM8962_EQ39: + case WM8962_EQ40: + case WM8962_EQ41: + case WM8962_GPIO_BASE: + case WM8962_GPIO_2: + case WM8962_GPIO_3: + case WM8962_GPIO_5: + case WM8962_GPIO_6: + case WM8962_INTERRUPT_STATUS_1: + case WM8962_INTERRUPT_STATUS_2: + case WM8962_INTERRUPT_STATUS_1_MASK: + case WM8962_INTERRUPT_STATUS_2_MASK: + case WM8962_INTERRUPT_CONTROL: + case WM8962_IRQ_DEBOUNCE: + case WM8962_MICINT_SOURCE_POL: + case WM8962_DSP2_POWER_MANAGEMENT: + case WM8962_DSP2_EXECCONTROL: + case WM8962_DSP2_INSTRUCTION_RAM_0: + case WM8962_DSP2_ADDRESS_RAM_2: + case WM8962_DSP2_ADDRESS_RAM_1: + case WM8962_DSP2_ADDRESS_RAM_0: + case WM8962_DSP2_DATA1_RAM_1: + case WM8962_DSP2_DATA1_RAM_0: + case WM8962_DSP2_DATA2_RAM_1: + case WM8962_DSP2_DATA2_RAM_0: + case WM8962_DSP2_DATA3_RAM_1: + case WM8962_DSP2_DATA3_RAM_0: + case WM8962_DSP2_COEFF_RAM_0: + case WM8962_RETUNEADC_SHARED_COEFF_1: + case WM8962_RETUNEADC_SHARED_COEFF_0: + case WM8962_RETUNEDAC_SHARED_COEFF_1: + case WM8962_RETUNEDAC_SHARED_COEFF_0: + case WM8962_SOUNDSTAGE_ENABLES_1: + case WM8962_SOUNDSTAGE_ENABLES_0: + case WM8962_HDBASS_AI_1: + case WM8962_HDBASS_AI_0: + case WM8962_HDBASS_AR_1: + case WM8962_HDBASS_AR_0: + case WM8962_HDBASS_B_1: + case WM8962_HDBASS_B_0: + case WM8962_HDBASS_K_1: + case WM8962_HDBASS_K_0: + case WM8962_HDBASS_N1_1: + case WM8962_HDBASS_N1_0: + case WM8962_HDBASS_N2_1: + case WM8962_HDBASS_N2_0: + case WM8962_HDBASS_N3_1: + case WM8962_HDBASS_N3_0: + case WM8962_HDBASS_N4_1: + case WM8962_HDBASS_N4_0: + case WM8962_HDBASS_N5_1: + case WM8962_HDBASS_N5_0: + case WM8962_HDBASS_X1_1: + case WM8962_HDBASS_X1_0: + case WM8962_HDBASS_X2_1: + case WM8962_HDBASS_X2_0: + case WM8962_HDBASS_X3_1: + case WM8962_HDBASS_X3_0: + case WM8962_HDBASS_ATK_1: + case WM8962_HDBASS_ATK_0: + case WM8962_HDBASS_DCY_1: + case WM8962_HDBASS_DCY_0: + case WM8962_HDBASS_PG_1: + case WM8962_HDBASS_PG_0: + case WM8962_HPF_C_1: + case WM8962_HPF_C_0: + case WM8962_ADCL_RETUNE_C1_1: + case WM8962_ADCL_RETUNE_C1_0: + case WM8962_ADCL_RETUNE_C2_1: + case WM8962_ADCL_RETUNE_C2_0: + case WM8962_ADCL_RETUNE_C3_1: + case WM8962_ADCL_RETUNE_C3_0: + case WM8962_ADCL_RETUNE_C4_1: + case WM8962_ADCL_RETUNE_C4_0: + case WM8962_ADCL_RETUNE_C5_1: + case WM8962_ADCL_RETUNE_C5_0: + case WM8962_ADCL_RETUNE_C6_1: + case WM8962_ADCL_RETUNE_C6_0: + case WM8962_ADCL_RETUNE_C7_1: + case WM8962_ADCL_RETUNE_C7_0: + case WM8962_ADCL_RETUNE_C8_1: + case WM8962_ADCL_RETUNE_C8_0: + case WM8962_ADCL_RETUNE_C9_1: + case WM8962_ADCL_RETUNE_C9_0: + case WM8962_ADCL_RETUNE_C10_1: + case WM8962_ADCL_RETUNE_C10_0: + case WM8962_ADCL_RETUNE_C11_1: + case WM8962_ADCL_RETUNE_C11_0: + case WM8962_ADCL_RETUNE_C12_1: + case WM8962_ADCL_RETUNE_C12_0: + case WM8962_ADCL_RETUNE_C13_1: + case WM8962_ADCL_RETUNE_C13_0: + case WM8962_ADCL_RETUNE_C14_1: + case WM8962_ADCL_RETUNE_C14_0: + case WM8962_ADCL_RETUNE_C15_1: + case WM8962_ADCL_RETUNE_C15_0: + case WM8962_ADCL_RETUNE_C16_1: + case WM8962_ADCL_RETUNE_C16_0: + case WM8962_ADCL_RETUNE_C17_1: + case WM8962_ADCL_RETUNE_C17_0: + case WM8962_ADCL_RETUNE_C18_1: + case WM8962_ADCL_RETUNE_C18_0: + case WM8962_ADCL_RETUNE_C19_1: + case WM8962_ADCL_RETUNE_C19_0: + case WM8962_ADCL_RETUNE_C20_1: + case WM8962_ADCL_RETUNE_C20_0: + case WM8962_ADCL_RETUNE_C21_1: + case WM8962_ADCL_RETUNE_C21_0: + case WM8962_ADCL_RETUNE_C22_1: + case WM8962_ADCL_RETUNE_C22_0: + case WM8962_ADCL_RETUNE_C23_1: + case WM8962_ADCL_RETUNE_C23_0: + case WM8962_ADCL_RETUNE_C24_1: + case WM8962_ADCL_RETUNE_C24_0: + case WM8962_ADCL_RETUNE_C25_1: + case WM8962_ADCL_RETUNE_C25_0: + case WM8962_ADCL_RETUNE_C26_1: + case WM8962_ADCL_RETUNE_C26_0: + case WM8962_ADCL_RETUNE_C27_1: + case WM8962_ADCL_RETUNE_C27_0: + case WM8962_ADCL_RETUNE_C28_1: + case WM8962_ADCL_RETUNE_C28_0: + case WM8962_ADCL_RETUNE_C29_1: + case WM8962_ADCL_RETUNE_C29_0: + case WM8962_ADCL_RETUNE_C30_1: + case WM8962_ADCL_RETUNE_C30_0: + case WM8962_ADCL_RETUNE_C31_1: + case WM8962_ADCL_RETUNE_C31_0: + case WM8962_ADCL_RETUNE_C32_1: + case WM8962_ADCL_RETUNE_C32_0: + case WM8962_RETUNEADC_PG2_1: + case WM8962_RETUNEADC_PG2_0: + case WM8962_RETUNEADC_PG_1: + case WM8962_RETUNEADC_PG_0: + case WM8962_ADCR_RETUNE_C1_1: + case WM8962_ADCR_RETUNE_C1_0: + case WM8962_ADCR_RETUNE_C2_1: + case WM8962_ADCR_RETUNE_C2_0: + case WM8962_ADCR_RETUNE_C3_1: + case WM8962_ADCR_RETUNE_C3_0: + case WM8962_ADCR_RETUNE_C4_1: + case WM8962_ADCR_RETUNE_C4_0: + case WM8962_ADCR_RETUNE_C5_1: + case WM8962_ADCR_RETUNE_C5_0: + case WM8962_ADCR_RETUNE_C6_1: + case WM8962_ADCR_RETUNE_C6_0: + case WM8962_ADCR_RETUNE_C7_1: + case WM8962_ADCR_RETUNE_C7_0: + case WM8962_ADCR_RETUNE_C8_1: + case WM8962_ADCR_RETUNE_C8_0: + case WM8962_ADCR_RETUNE_C9_1: + case WM8962_ADCR_RETUNE_C9_0: + case WM8962_ADCR_RETUNE_C10_1: + case WM8962_ADCR_RETUNE_C10_0: + case WM8962_ADCR_RETUNE_C11_1: + case WM8962_ADCR_RETUNE_C11_0: + case WM8962_ADCR_RETUNE_C12_1: + case WM8962_ADCR_RETUNE_C12_0: + case WM8962_ADCR_RETUNE_C13_1: + case WM8962_ADCR_RETUNE_C13_0: + case WM8962_ADCR_RETUNE_C14_1: + case WM8962_ADCR_RETUNE_C14_0: + case WM8962_ADCR_RETUNE_C15_1: + case WM8962_ADCR_RETUNE_C15_0: + case WM8962_ADCR_RETUNE_C16_1: + case WM8962_ADCR_RETUNE_C16_0: + case WM8962_ADCR_RETUNE_C17_1: + case WM8962_ADCR_RETUNE_C17_0: + case WM8962_ADCR_RETUNE_C18_1: + case WM8962_ADCR_RETUNE_C18_0: + case WM8962_ADCR_RETUNE_C19_1: + case WM8962_ADCR_RETUNE_C19_0: + case WM8962_ADCR_RETUNE_C20_1: + case WM8962_ADCR_RETUNE_C20_0: + case WM8962_ADCR_RETUNE_C21_1: + case WM8962_ADCR_RETUNE_C21_0: + case WM8962_ADCR_RETUNE_C22_1: + case WM8962_ADCR_RETUNE_C22_0: + case WM8962_ADCR_RETUNE_C23_1: + case WM8962_ADCR_RETUNE_C23_0: + case WM8962_ADCR_RETUNE_C24_1: + case WM8962_ADCR_RETUNE_C24_0: + case WM8962_ADCR_RETUNE_C25_1: + case WM8962_ADCR_RETUNE_C25_0: + case WM8962_ADCR_RETUNE_C26_1: + case WM8962_ADCR_RETUNE_C26_0: + case WM8962_ADCR_RETUNE_C27_1: + case WM8962_ADCR_RETUNE_C27_0: + case WM8962_ADCR_RETUNE_C28_1: + case WM8962_ADCR_RETUNE_C28_0: + case WM8962_ADCR_RETUNE_C29_1: + case WM8962_ADCR_RETUNE_C29_0: + case WM8962_ADCR_RETUNE_C30_1: + case WM8962_ADCR_RETUNE_C30_0: + case WM8962_ADCR_RETUNE_C31_1: + case WM8962_ADCR_RETUNE_C31_0: + case WM8962_ADCR_RETUNE_C32_1: + case WM8962_ADCR_RETUNE_C32_0: + case WM8962_DACL_RETUNE_C1_1: + case WM8962_DACL_RETUNE_C1_0: + case WM8962_DACL_RETUNE_C2_1: + case WM8962_DACL_RETUNE_C2_0: + case WM8962_DACL_RETUNE_C3_1: + case WM8962_DACL_RETUNE_C3_0: + case WM8962_DACL_RETUNE_C4_1: + case WM8962_DACL_RETUNE_C4_0: + case WM8962_DACL_RETUNE_C5_1: + case WM8962_DACL_RETUNE_C5_0: + case WM8962_DACL_RETUNE_C6_1: + case WM8962_DACL_RETUNE_C6_0: + case WM8962_DACL_RETUNE_C7_1: + case WM8962_DACL_RETUNE_C7_0: + case WM8962_DACL_RETUNE_C8_1: + case WM8962_DACL_RETUNE_C8_0: + case WM8962_DACL_RETUNE_C9_1: + case WM8962_DACL_RETUNE_C9_0: + case WM8962_DACL_RETUNE_C10_1: + case WM8962_DACL_RETUNE_C10_0: + case WM8962_DACL_RETUNE_C11_1: + case WM8962_DACL_RETUNE_C11_0: + case WM8962_DACL_RETUNE_C12_1: + case WM8962_DACL_RETUNE_C12_0: + case WM8962_DACL_RETUNE_C13_1: + case WM8962_DACL_RETUNE_C13_0: + case WM8962_DACL_RETUNE_C14_1: + case WM8962_DACL_RETUNE_C14_0: + case WM8962_DACL_RETUNE_C15_1: + case WM8962_DACL_RETUNE_C15_0: + case WM8962_DACL_RETUNE_C16_1: + case WM8962_DACL_RETUNE_C16_0: + case WM8962_DACL_RETUNE_C17_1: + case WM8962_DACL_RETUNE_C17_0: + case WM8962_DACL_RETUNE_C18_1: + case WM8962_DACL_RETUNE_C18_0: + case WM8962_DACL_RETUNE_C19_1: + case WM8962_DACL_RETUNE_C19_0: + case WM8962_DACL_RETUNE_C20_1: + case WM8962_DACL_RETUNE_C20_0: + case WM8962_DACL_RETUNE_C21_1: + case WM8962_DACL_RETUNE_C21_0: + case WM8962_DACL_RETUNE_C22_1: + case WM8962_DACL_RETUNE_C22_0: + case WM8962_DACL_RETUNE_C23_1: + case WM8962_DACL_RETUNE_C23_0: + case WM8962_DACL_RETUNE_C24_1: + case WM8962_DACL_RETUNE_C24_0: + case WM8962_DACL_RETUNE_C25_1: + case WM8962_DACL_RETUNE_C25_0: + case WM8962_DACL_RETUNE_C26_1: + case WM8962_DACL_RETUNE_C26_0: + case WM8962_DACL_RETUNE_C27_1: + case WM8962_DACL_RETUNE_C27_0: + case WM8962_DACL_RETUNE_C28_1: + case WM8962_DACL_RETUNE_C28_0: + case WM8962_DACL_RETUNE_C29_1: + case WM8962_DACL_RETUNE_C29_0: + case WM8962_DACL_RETUNE_C30_1: + case WM8962_DACL_RETUNE_C30_0: + case WM8962_DACL_RETUNE_C31_1: + case WM8962_DACL_RETUNE_C31_0: + case WM8962_DACL_RETUNE_C32_1: + case WM8962_DACL_RETUNE_C32_0: + case WM8962_RETUNEDAC_PG2_1: + case WM8962_RETUNEDAC_PG2_0: + case WM8962_RETUNEDAC_PG_1: + case WM8962_RETUNEDAC_PG_0: + case WM8962_DACR_RETUNE_C1_1: + case WM8962_DACR_RETUNE_C1_0: + case WM8962_DACR_RETUNE_C2_1: + case WM8962_DACR_RETUNE_C2_0: + case WM8962_DACR_RETUNE_C3_1: + case WM8962_DACR_RETUNE_C3_0: + case WM8962_DACR_RETUNE_C4_1: + case WM8962_DACR_RETUNE_C4_0: + case WM8962_DACR_RETUNE_C5_1: + case WM8962_DACR_RETUNE_C5_0: + case WM8962_DACR_RETUNE_C6_1: + case WM8962_DACR_RETUNE_C6_0: + case WM8962_DACR_RETUNE_C7_1: + case WM8962_DACR_RETUNE_C7_0: + case WM8962_DACR_RETUNE_C8_1: + case WM8962_DACR_RETUNE_C8_0: + case WM8962_DACR_RETUNE_C9_1: + case WM8962_DACR_RETUNE_C9_0: + case WM8962_DACR_RETUNE_C10_1: + case WM8962_DACR_RETUNE_C10_0: + case WM8962_DACR_RETUNE_C11_1: + case WM8962_DACR_RETUNE_C11_0: + case WM8962_DACR_RETUNE_C12_1: + case WM8962_DACR_RETUNE_C12_0: + case WM8962_DACR_RETUNE_C13_1: + case WM8962_DACR_RETUNE_C13_0: + case WM8962_DACR_RETUNE_C14_1: + case WM8962_DACR_RETUNE_C14_0: + case WM8962_DACR_RETUNE_C15_1: + case WM8962_DACR_RETUNE_C15_0: + case WM8962_DACR_RETUNE_C16_1: + case WM8962_DACR_RETUNE_C16_0: + case WM8962_DACR_RETUNE_C17_1: + case WM8962_DACR_RETUNE_C17_0: + case WM8962_DACR_RETUNE_C18_1: + case WM8962_DACR_RETUNE_C18_0: + case WM8962_DACR_RETUNE_C19_1: + case WM8962_DACR_RETUNE_C19_0: + case WM8962_DACR_RETUNE_C20_1: + case WM8962_DACR_RETUNE_C20_0: + case WM8962_DACR_RETUNE_C21_1: + case WM8962_DACR_RETUNE_C21_0: + case WM8962_DACR_RETUNE_C22_1: + case WM8962_DACR_RETUNE_C22_0: + case WM8962_DACR_RETUNE_C23_1: + case WM8962_DACR_RETUNE_C23_0: + case WM8962_DACR_RETUNE_C24_1: + case WM8962_DACR_RETUNE_C24_0: + case WM8962_DACR_RETUNE_C25_1: + case WM8962_DACR_RETUNE_C25_0: + case WM8962_DACR_RETUNE_C26_1: + case WM8962_DACR_RETUNE_C26_0: + case WM8962_DACR_RETUNE_C27_1: + case WM8962_DACR_RETUNE_C27_0: + case WM8962_DACR_RETUNE_C28_1: + case WM8962_DACR_RETUNE_C28_0: + case WM8962_DACR_RETUNE_C29_1: + case WM8962_DACR_RETUNE_C29_0: + case WM8962_DACR_RETUNE_C30_1: + case WM8962_DACR_RETUNE_C30_0: + case WM8962_DACR_RETUNE_C31_1: + case WM8962_DACR_RETUNE_C31_0: + case WM8962_DACR_RETUNE_C32_1: + case WM8962_DACR_RETUNE_C32_0: + case WM8962_VSS_XHD2_1: + case WM8962_VSS_XHD2_0: + case WM8962_VSS_XHD3_1: + case WM8962_VSS_XHD3_0: + case WM8962_VSS_XHN1_1: + case WM8962_VSS_XHN1_0: + case WM8962_VSS_XHN2_1: + case WM8962_VSS_XHN2_0: + case WM8962_VSS_XHN3_1: + case WM8962_VSS_XHN3_0: + case WM8962_VSS_XLA_1: + case WM8962_VSS_XLA_0: + case WM8962_VSS_XLB_1: + case WM8962_VSS_XLB_0: + case WM8962_VSS_XLG_1: + case WM8962_VSS_XLG_0: + case WM8962_VSS_PG2_1: + case WM8962_VSS_PG2_0: + case WM8962_VSS_PG_1: + case WM8962_VSS_PG_0: + case WM8962_VSS_XTD1_1: + case WM8962_VSS_XTD1_0: + case WM8962_VSS_XTD2_1: + case WM8962_VSS_XTD2_0: + case WM8962_VSS_XTD3_1: + case WM8962_VSS_XTD3_0: + case WM8962_VSS_XTD4_1: + case WM8962_VSS_XTD4_0: + case WM8962_VSS_XTD5_1: + case WM8962_VSS_XTD5_0: + case WM8962_VSS_XTD6_1: + case WM8962_VSS_XTD6_0: + case WM8962_VSS_XTD7_1: + case WM8962_VSS_XTD7_0: + case WM8962_VSS_XTD8_1: + case WM8962_VSS_XTD8_0: + case WM8962_VSS_XTD9_1: + case WM8962_VSS_XTD9_0: + case WM8962_VSS_XTD10_1: + case WM8962_VSS_XTD10_0: + case WM8962_VSS_XTD11_1: + case WM8962_VSS_XTD11_0: + case WM8962_VSS_XTD12_1: + case WM8962_VSS_XTD12_0: + case WM8962_VSS_XTD13_1: + case WM8962_VSS_XTD13_0: + case WM8962_VSS_XTD14_1: + case WM8962_VSS_XTD14_0: + case WM8962_VSS_XTD15_1: + case WM8962_VSS_XTD15_0: + case WM8962_VSS_XTD16_1: + case WM8962_VSS_XTD16_0: + case WM8962_VSS_XTD17_1: + case WM8962_VSS_XTD17_0: + case WM8962_VSS_XTD18_1: + case WM8962_VSS_XTD18_0: + case WM8962_VSS_XTD19_1: + case WM8962_VSS_XTD19_0: + case WM8962_VSS_XTD20_1: + case WM8962_VSS_XTD20_0: + case WM8962_VSS_XTD21_1: + case WM8962_VSS_XTD21_0: + case WM8962_VSS_XTD22_1: + case WM8962_VSS_XTD22_0: + case WM8962_VSS_XTD23_1: + case WM8962_VSS_XTD23_0: + case WM8962_VSS_XTD24_1: + case WM8962_VSS_XTD24_0: + case WM8962_VSS_XTD25_1: + case WM8962_VSS_XTD25_0: + case WM8962_VSS_XTD26_1: + case WM8962_VSS_XTD26_0: + case WM8962_VSS_XTD27_1: + case WM8962_VSS_XTD27_0: + case WM8962_VSS_XTD28_1: + case WM8962_VSS_XTD28_0: + case WM8962_VSS_XTD29_1: + case WM8962_VSS_XTD29_0: + case WM8962_VSS_XTD30_1: + case WM8962_VSS_XTD30_0: + case WM8962_VSS_XTD31_1: + case WM8962_VSS_XTD31_0: + case WM8962_VSS_XTD32_1: + case WM8962_VSS_XTD32_0: + case WM8962_VSS_XTS1_1: + case WM8962_VSS_XTS1_0: + case WM8962_VSS_XTS2_1: + case WM8962_VSS_XTS2_0: + case WM8962_VSS_XTS3_1: + case WM8962_VSS_XTS3_0: + case WM8962_VSS_XTS4_1: + case WM8962_VSS_XTS4_0: + case WM8962_VSS_XTS5_1: + case WM8962_VSS_XTS5_0: + case WM8962_VSS_XTS6_1: + case WM8962_VSS_XTS6_0: + case WM8962_VSS_XTS7_1: + case WM8962_VSS_XTS7_0: + case WM8962_VSS_XTS8_1: + case WM8962_VSS_XTS8_0: + case WM8962_VSS_XTS9_1: + case WM8962_VSS_XTS9_0: + case WM8962_VSS_XTS10_1: + case WM8962_VSS_XTS10_0: + case WM8962_VSS_XTS11_1: + case WM8962_VSS_XTS11_0: + case WM8962_VSS_XTS12_1: + case WM8962_VSS_XTS12_0: + case WM8962_VSS_XTS13_1: + case WM8962_VSS_XTS13_0: + case WM8962_VSS_XTS14_1: + case WM8962_VSS_XTS14_0: + case WM8962_VSS_XTS15_1: + case WM8962_VSS_XTS15_0: + case WM8962_VSS_XTS16_1: + case WM8962_VSS_XTS16_0: + case WM8962_VSS_XTS17_1: + case WM8962_VSS_XTS17_0: + case WM8962_VSS_XTS18_1: + case WM8962_VSS_XTS18_0: + case WM8962_VSS_XTS19_1: + case WM8962_VSS_XTS19_0: + case WM8962_VSS_XTS20_1: + case WM8962_VSS_XTS20_0: + case WM8962_VSS_XTS21_1: + case WM8962_VSS_XTS21_0: + case WM8962_VSS_XTS22_1: + case WM8962_VSS_XTS22_0: + case WM8962_VSS_XTS23_1: + case WM8962_VSS_XTS23_0: + case WM8962_VSS_XTS24_1: + case WM8962_VSS_XTS24_0: + case WM8962_VSS_XTS25_1: + case WM8962_VSS_XTS25_0: + case WM8962_VSS_XTS26_1: + case WM8962_VSS_XTS26_0: + case WM8962_VSS_XTS27_1: + case WM8962_VSS_XTS27_0: + case WM8962_VSS_XTS28_1: + case WM8962_VSS_XTS28_0: + case WM8962_VSS_XTS29_1: + case WM8962_VSS_XTS29_0: + case WM8962_VSS_XTS30_1: + case WM8962_VSS_XTS30_0: + case WM8962_VSS_XTS31_1: + case WM8962_VSS_XTS31_0: + case WM8962_VSS_XTS32_1: + case WM8962_VSS_XTS32_0: + return true; + default: + return false; + } } static int wm8962_reset(struct wm8962_priv *wm8962) @@ -2221,6 +1702,8 @@ SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1, SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME, WM8962_RIGHT_DAC_VOLUME, 1, 127, 0, digital_tlv), SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0), +SOC_SINGLE("DAC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 5, 1, 0), +SOC_SINGLE("ADC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 8, 1, 0), SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1, 5, 1, 0), @@ -2337,65 +1820,6 @@ SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5, 4, 1, 0, inmix_tlv), }; -static int sysclk_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - unsigned long timeout; - int src; - int fll; - - /* Ignore attempts to run the event during startup */ - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) - return 0; - - src = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_SRC_MASK; - - switch (src) { - case 0: /* MCLK */ - fll = 0; - break; - case 0x200: /* FLL */ - fll = 1; - break; - default: - dev_err(codec->dev, "Unknown SYSCLK source %x\n", src); - return -EINVAL; - } - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - if (fll) { - try_wait_for_completion(&wm8962->fll_lock); - - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, - WM8962_FLL_ENA, WM8962_FLL_ENA); - - timeout = msecs_to_jiffies(5); - timeout = wait_for_completion_timeout(&wm8962->fll_lock, - timeout); - - if (wm8962->irq && timeout == 0) - dev_err(codec->dev, - "Timed out starting FLL\n"); - } - break; - - case SND_SOC_DAPM_POST_PMD: - if (fll) - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, - WM8962_FLL_ENA, 0); - break; - - default: - BUG(); - return -EINVAL; - } - - return 0; -} - static int cp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -2681,8 +2105,7 @@ SND_SOC_DAPM_INPUT("DMICDAT"), SND_SOC_DAPM_SUPPLY("MICBIAS", WM8962_PWR_MGMT_1, 1, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0), -SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event, SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0), @@ -2796,9 +2219,11 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = { { "STL", "Left", "ADCL" }, { "STL", "Right", "ADCR" }, + { "STL", NULL, "Class G" }, { "STR", "Left", "ADCL" }, { "STR", "Right", "ADCR" }, + { "STR", NULL, "Class G" }, { "DACL", NULL, "SYSCLK" }, { "DACL", NULL, "TOCLK" }, @@ -2910,13 +2335,13 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec) struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); struct snd_soc_dapm_context *dapm = &codec->dapm; - snd_soc_add_controls(codec, wm8962_snd_controls, + snd_soc_add_codec_controls(codec, wm8962_snd_controls, ARRAY_SIZE(wm8962_snd_controls)); if (pdata && pdata->spk_mono) - snd_soc_add_controls(codec, wm8962_spk_mono_controls, + snd_soc_add_codec_controls(codec, wm8962_spk_mono_controls, ARRAY_SIZE(wm8962_spk_mono_controls)); else - snd_soc_add_controls(codec, wm8962_spk_stereo_controls, + snd_soc_add_codec_controls(codec, wm8962_spk_stereo_controls, ARRAY_SIZE(wm8962_spk_stereo_controls)); @@ -2950,7 +2375,7 @@ static const int bclk_divs[] = { }; static const int sysclk_rates[] = { - 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, + 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, 3072, 6144 }; static void wm8962_configure_bclk(struct snd_soc_codec *codec) @@ -2984,6 +2409,8 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec) return; } + dev_dbg(codec->dev, "Selected sysclk ratio %d\n", sysclk_rates[i]); + snd_soc_update_bits(codec, WM8962_CLOCKING_4, WM8962_SYSCLK_RATE_MASK, clocking4); @@ -3042,9 +2469,6 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec) static int wm8962_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - int ret; - if (level == codec->dapm.bias_level) return 0; @@ -3061,51 +2485,15 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies), - wm8962->supplies); - if (ret != 0) { - dev_err(codec->dev, - "Failed to enable supplies: %d\n", - ret); - return ret; - } - - regcache_cache_only(wm8962->regmap, false); - regcache_sync(wm8962->regmap); - - snd_soc_update_bits(codec, WM8962_ANTI_POP, - WM8962_STARTUP_BIAS_ENA | - WM8962_VMID_BUF_ENA, - WM8962_STARTUP_BIAS_ENA | - WM8962_VMID_BUF_ENA); - - /* Bias enable at 2*50k for ramp */ - snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, - WM8962_VMID_SEL_MASK | - WM8962_BIAS_ENA, - WM8962_BIAS_ENA | 0x180); - - msleep(5); - } - /* VMID 2*250k */ snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, WM8962_VMID_SEL_MASK, 0x100); break; case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, - WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0); - - snd_soc_update_bits(codec, WM8962_ANTI_POP, - WM8962_STARTUP_BIAS_ENA | - WM8962_VMID_BUF_ENA, 0); - - regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), - wm8962->supplies); break; } + codec->dapm.bias_level = level; return 0; } @@ -3139,6 +2527,9 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, int adctl3 = 0; wm8962->bclk = snd_soc_params_to_bclk(params); + if (params_channels(params) == 1) + wm8962->bclk *= 2; + wm8962->lrclk = params_rate(params); for (i = 0; i < ARRAY_SIZE(sr_vals); i++) { @@ -3177,7 +2568,8 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, WM8962_SAMPLE_RATE_INT_MODE | WM8962_SAMPLE_RATE_MASK, adctl3); - wm8962_configure_bclk(codec); + if (codec->dapm.bias_level == SND_SOC_BIAS_ON) + wm8962_configure_bclk(codec); return 0; } @@ -3207,6 +2599,8 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, wm8962->sysclk_rate = freq; + wm8962_configure_bclk(codec); + return 0; } @@ -3385,8 +2779,7 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, struct _fll_div fll_div; unsigned long timeout; int ret; - int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA; - int sysclk = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_ENA; + int fll1 = 0; /* Any change? */ if (source == wm8962->fll_src && Fref == wm8962->fll_fref && @@ -3402,6 +2795,8 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0); + pm_runtime_put(codec->dev); + return 0; } @@ -3409,6 +2804,9 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, if (ret != 0) return ret; + /* Parameters good, disable so we can reprogram */ + snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0); + switch (fll_id) { case WM8962_FLL_MCLK: case WM8962_FLL_BCLK: @@ -3447,12 +2845,11 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, try_wait_for_completion(&wm8962->fll_lock); - if (sysclk) - fll1 |= WM8962_FLL_ENA; + pm_runtime_get_sync(codec->dev); snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK | - WM8962_FLL_ENA, fll1); + WM8962_FLL_ENA, fll1 | WM8962_FLL_ENA); dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); @@ -3513,14 +2910,14 @@ static struct snd_soc_dai_driver wm8962_dai = { .name = "wm8962", .playback = { .stream_name = "Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = WM8962_RATES, .formats = WM8962_FORMATS, }, .capture = { .stream_name = "Capture", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = WM8962_RATES, .formats = WM8962_FORMATS, @@ -3561,54 +2958,73 @@ static void wm8962_mic_work(struct work_struct *work) static irqreturn_t wm8962_irq(int irq, void *data) { - struct snd_soc_codec *codec = data; - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - int mask; - int active; - int reg; + struct device *dev = data; + struct wm8962_priv *wm8962 = dev_get_drvdata(dev); + unsigned int mask; + unsigned int active; + int reg, ret; - mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2_MASK); + ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2_MASK, + &mask); + if (ret != 0) { + dev_err(dev, "Failed to read interrupt mask: %d\n", + ret); + return IRQ_NONE; + } + + ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, &active); + if (ret != 0) { + dev_err(dev, "Failed to read interrupt: %d\n", ret); + return IRQ_NONE; + } - active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); active &= ~mask; if (!active) return IRQ_NONE; /* Acknowledge the interrupts */ - snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active); + ret = regmap_write(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, active); + if (ret != 0) + dev_warn(dev, "Failed to ack interrupt: %d\n", ret); if (active & WM8962_FLL_LOCK_EINT) { - dev_dbg(codec->dev, "FLL locked\n"); + dev_dbg(dev, "FLL locked\n"); complete(&wm8962->fll_lock); } if (active & WM8962_FIFOS_ERR_EINT) - dev_err(codec->dev, "FIFO error\n"); + dev_err(dev, "FIFO error\n"); if (active & WM8962_TEMP_SHUT_EINT) { - dev_crit(codec->dev, "Thermal shutdown\n"); + dev_crit(dev, "Thermal shutdown\n"); - reg = snd_soc_read(codec, WM8962_THERMAL_SHUTDOWN_STATUS); + ret = regmap_read(wm8962->regmap, + WM8962_THERMAL_SHUTDOWN_STATUS, ®); + if (ret != 0) { + dev_warn(dev, "Failed to read thermal status: %d\n", + ret); + reg = 0; + } if (reg & WM8962_TEMP_ERR_HP) - dev_crit(codec->dev, "Headphone thermal error\n"); + dev_crit(dev, "Headphone thermal error\n"); if (reg & WM8962_TEMP_WARN_HP) - dev_crit(codec->dev, "Headphone thermal warning\n"); + dev_crit(dev, "Headphone thermal warning\n"); if (reg & WM8962_TEMP_ERR_SPK) - dev_crit(codec->dev, "Speaker thermal error\n"); + dev_crit(dev, "Speaker thermal error\n"); if (reg & WM8962_TEMP_WARN_SPK) - dev_crit(codec->dev, "Speaker thermal warning\n"); + dev_crit(dev, "Speaker thermal warning\n"); } if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) { - dev_dbg(codec->dev, "Microphone event detected\n"); + dev_dbg(dev, "Microphone event detected\n"); #ifndef CONFIG_SND_SOC_WM8962_MODULE - trace_snd_soc_jack_irq(dev_name(codec->dev)); + trace_snd_soc_jack_irq(dev_name(dev)); #endif - pm_wakeup_event(codec->dev, 300); + pm_wakeup_event(dev, 300); schedule_delayed_work(&wm8962->mic_work, msecs_to_jiffies(250)); @@ -4089,7 +3505,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq, trigger | IRQF_ONESHOT, - "wm8962", codec); + "wm8962", codec->dev); if (ret != 0) { dev_err(codec->dev, "Failed to request IRQ %d: %d\n", wm8962->irq, ret); @@ -4127,20 +3543,19 @@ static int wm8962_remove(struct snd_soc_codec *codec) return 0; } -static int wm8962_soc_volatile(struct snd_soc_codec *codec, - unsigned int reg) -{ - return true; -} - - static struct snd_soc_codec_driver soc_codec_dev_wm8962 = { .probe = wm8962_probe, .remove = wm8962_remove, .set_bias_level = wm8962_set_bias_level, .set_pll = wm8962_set_fll, - .reg_cache_size = WM8962_MAX_REGISTER, - .volatile_register = wm8962_soc_volatile, + .idle_bias_off = true, +}; + +/* Improve power consumption for IN4 DC measurement mode */ +static const struct reg_default wm8962_dc_measure[] = { + { 0xfd, 0x1 }, + { 0xcc, 0x40 }, + { 0xfd, 0 }, }; static const struct regmap_config wm8962_regmap = { @@ -4155,10 +3570,10 @@ static const struct regmap_config wm8962_regmap = { .cache_type = REGCACHE_RBTREE, }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm8962_priv *wm8962; unsigned int reg; int ret, i; @@ -4212,7 +3627,7 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, } if (reg != 0x6243) { dev_err(&i2c->dev, - "Device is not a WM8962, ID %x != 0x6243\n", ret); + "Device is not a WM8962, ID %x != 0x6243\n", reg); ret = -EINVAL; goto err_regmap; } @@ -4237,7 +3652,18 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, goto err_regmap; } - regcache_cache_only(wm8962->regmap, true); + if (pdata && pdata->in4_dc_measure) { + ret = regmap_register_patch(wm8962->regmap, + wm8962_dc_measure, + ARRAY_SIZE(wm8962_dc_measure)); + if (ret != 0) + dev_err(&i2c->dev, + "Failed to configure for DC mesurement: %d\n", + ret); + } + + pm_runtime_enable(&i2c->dev); + pm_request_idle(&i2c->dev); ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8962, &wm8962_dai, 1); @@ -4269,6 +3695,65 @@ static __devexit int wm8962_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM_RUNTIME +static int wm8962_runtime_resume(struct device *dev) +{ + struct wm8962_priv *wm8962 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies), + wm8962->supplies); + if (ret != 0) { + dev_err(dev, + "Failed to enable supplies: %d\n", ret); + return ret; + } + + regcache_cache_only(wm8962->regmap, false); + regcache_sync(wm8962->regmap); + + regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP, + WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA, + WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA); + + /* Bias enable at 2*50k for ramp */ + regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1, + WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, + WM8962_BIAS_ENA | 0x180); + + msleep(5); + + /* VMID back to 2x250k for standby */ + regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1, + WM8962_VMID_SEL_MASK, 0x100); + + return 0; +} + +static int wm8962_runtime_suspend(struct device *dev) +{ + struct wm8962_priv *wm8962 = dev_get_drvdata(dev); + + regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1, + WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0); + + regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP, + WM8962_STARTUP_BIAS_ENA | + WM8962_VMID_BUF_ENA, 0); + + regcache_cache_only(wm8962->regmap, true); + + regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), + wm8962->supplies); + + return 0; +} +#endif + +static struct dev_pm_ops wm8962_pm = { + SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL) +}; + static const struct i2c_device_id wm8962_i2c_id[] = { { "wm8962", 0 }, { } @@ -4279,34 +3764,14 @@ static struct i2c_driver wm8962_i2c_driver = { .driver = { .name = "wm8962", .owner = THIS_MODULE, + .pm = &wm8962_pm, }, .probe = wm8962_i2c_probe, .remove = __devexit_p(wm8962_i2c_remove), .id_table = wm8962_i2c_id, }; -#endif - -static int __init wm8962_modinit(void) -{ - int ret; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&wm8962_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8962 I2C driver: %d\n", - ret); - } -#endif - return 0; -} -module_init(wm8962_modinit); -static void __exit wm8962_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8962_i2c_driver); -#endif -} -module_exit(wm8962_exit); +module_i2c_driver(wm8962_i2c_driver); MODULE_DESCRIPTION("ASoC WM8962 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 4af893601f0..28fe59e3ce0 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -252,7 +252,7 @@ static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { SND_SOC_DAPM_INPUT("MIC"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8971_dapm_routes[] = { /* left mixer */ {"Left Mixer", "Playback Switch", "Left DAC"}, {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, @@ -329,17 +329,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Right ADC", NULL, "Right ADC Mux"}, }; -static int wm8971_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8971_dapm_widgets, - ARRAY_SIZE(wm8971_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - return 0; -} - struct _coeff_div { u32 mclk; u32 rate; @@ -659,10 +648,6 @@ static int wm8971_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100); - snd_soc_add_controls(codec, wm8971_snd_controls, - ARRAY_SIZE(wm8971_snd_controls)); - wm8971_add_widgets(codec); - return ret; } @@ -686,16 +671,23 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8971 = { .reg_cache_size = ARRAY_SIZE(wm8971_reg), .reg_word_size = sizeof(u16), .reg_cache_default = wm8971_reg, + + .controls = wm8971_snd_controls, + .num_controls = ARRAY_SIZE(wm8971_snd_controls), + .dapm_widgets = wm8971_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8971_dapm_widgets), + .dapm_routes = wm8971_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8971_dapm_routes), }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8971_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8971_priv *wm8971; int ret; - wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL); + wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv), + GFP_KERNEL); if (wm8971 == NULL) return -ENOMEM; @@ -704,15 +696,13 @@ static __devinit int wm8971_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8971, &wm8971_dai, 1); - if (ret < 0) - kfree(wm8971); + return ret; } static __devexit int wm8971_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); return 0; } @@ -731,27 +721,22 @@ static struct i2c_driver wm8971_i2c_driver = { .remove = __devexit_p(wm8971_i2c_remove), .id_table = wm8971_i2c_id, }; -#endif static int __init wm8971_modinit(void) { int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ret = i2c_add_driver(&wm8971_i2c_driver); if (ret != 0) { printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n", ret); } -#endif return ret; } module_init(wm8971_modinit); static void __exit wm8971_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&wm8971_i2c_driver); -#endif } module_exit(wm8971_exit); diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 4a6a7b5a61b..d93c03f820c 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -48,10 +48,6 @@ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = { #define WM8974_POWER1_BIASEN 0x08 #define WM8974_POWER1_BUFIOEN 0x04 -struct wm8974_priv { - enum snd_soc_control_type control_type; -}; - #define wm8974_reset(c) snd_soc_write(c, WM8974_RESET, 0) static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" }; @@ -235,7 +231,7 @@ SND_SOC_DAPM_OUTPUT("SPKOUTP"), SND_SOC_DAPM_OUTPUT("SPKOUTN"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8974_dapm_routes[] = { /* Mono output mixer */ {"Mono Mixer", "PCM Playback Switch", "DAC"}, {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, @@ -269,17 +265,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Aux Input", NULL, "AUX"}, }; -static int wm8974_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8974_dapm_widgets, - ARRAY_SIZE(wm8974_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - return 0; -} - struct pll_ { unsigned int pre_div:1; unsigned int n:4; @@ -611,9 +596,6 @@ static int wm8974_probe(struct snd_soc_codec *codec) } wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_controls(codec, wm8974_snd_controls, - ARRAY_SIZE(wm8974_snd_controls)); - wm8974_add_widgets(codec); return ret; } @@ -634,32 +616,30 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { .reg_cache_size = ARRAY_SIZE(wm8974_reg), .reg_word_size = sizeof(u16), .reg_cache_default = wm8974_reg, + + .controls = wm8974_snd_controls, + .num_controls = ARRAY_SIZE(wm8974_snd_controls), + .dapm_widgets = wm8974_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8974_dapm_widgets), + .dapm_routes = wm8974_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8974_dapm_routes), }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8974_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct wm8974_priv *wm8974; int ret; - wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL); - if (wm8974 == NULL) - return -ENOMEM; - - i2c_set_clientdata(i2c, wm8974); - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8974, &wm8974_dai, 1); - if (ret < 0) - kfree(wm8974); + return ret; } static __devexit int wm8974_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + return 0; } @@ -678,27 +658,22 @@ static struct i2c_driver wm8974_i2c_driver = { .remove = __devexit_p(wm8974_i2c_remove), .id_table = wm8974_i2c_id, }; -#endif static int __init wm8974_modinit(void) { int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ret = i2c_add_driver(&wm8974_i2c_driver); if (ret != 0) { printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n", ret); } -#endif return ret; } module_init(wm8974_modinit); static void __exit wm8974_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&wm8974_i2c_driver); -#endif } module_exit(wm8974_exit); diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 85d514d63a4..72d5fdcd3cc 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -29,28 +30,74 @@ #include "wm8978.h" -/* wm8978 register cache. Note that register 0 is not included in the cache. */ -static const u16 wm8978_reg[WM8978_CACHEREGNUM] = { - 0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */ - 0x0050, 0x0000, 0x0140, 0x0000, /* 0x04...0x07 */ - 0x0000, 0x0000, 0x0000, 0x00ff, /* 0x08...0x0b */ - 0x00ff, 0x0000, 0x0100, 0x00ff, /* 0x0c...0x0f */ - 0x00ff, 0x0000, 0x012c, 0x002c, /* 0x10...0x13 */ - 0x002c, 0x002c, 0x002c, 0x0000, /* 0x14...0x17 */ - 0x0032, 0x0000, 0x0000, 0x0000, /* 0x18...0x1b */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 0x1c...0x1f */ - 0x0038, 0x000b, 0x0032, 0x0000, /* 0x20...0x23 */ - 0x0008, 0x000c, 0x0093, 0x00e9, /* 0x24...0x27 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 0x28...0x2b */ - 0x0033, 0x0010, 0x0010, 0x0100, /* 0x2c...0x2f */ - 0x0100, 0x0002, 0x0001, 0x0001, /* 0x30...0x33 */ - 0x0039, 0x0039, 0x0039, 0x0039, /* 0x34...0x37 */ - 0x0001, 0x0001, /* 0x38...0x3b */ +static const struct reg_default wm8978_reg_defaults[] = { + { 1, 0x0000 }, + { 2, 0x0000 }, + { 3, 0x0000 }, + { 4, 0x0050 }, + { 5, 0x0000 }, + { 6, 0x0140 }, + { 7, 0x0000 }, + { 8, 0x0000 }, + { 9, 0x0000 }, + { 10, 0x0000 }, + { 11, 0x00ff }, + { 12, 0x00ff }, + { 13, 0x0000 }, + { 14, 0x0100 }, + { 15, 0x00ff }, + { 16, 0x00ff }, + { 17, 0x0000 }, + { 18, 0x012c }, + { 19, 0x002c }, + { 20, 0x002c }, + { 21, 0x002c }, + { 22, 0x002c }, + { 23, 0x0000 }, + { 24, 0x0032 }, + { 25, 0x0000 }, + { 26, 0x0000 }, + { 27, 0x0000 }, + { 28, 0x0000 }, + { 29, 0x0000 }, + { 30, 0x0000 }, + { 31, 0x0000 }, + { 32, 0x0038 }, + { 33, 0x000b }, + { 34, 0x0032 }, + { 35, 0x0000 }, + { 36, 0x0008 }, + { 37, 0x000c }, + { 38, 0x0093 }, + { 39, 0x00e9 }, + { 40, 0x0000 }, + { 41, 0x0000 }, + { 42, 0x0000 }, + { 43, 0x0000 }, + { 44, 0x0033 }, + { 45, 0x0010 }, + { 46, 0x0010 }, + { 47, 0x0100 }, + { 48, 0x0100 }, + { 49, 0x0002 }, + { 50, 0x0001 }, + { 51, 0x0001 }, + { 52, 0x0039 }, + { 53, 0x0039 }, + { 54, 0x0039 }, + { 55, 0x0039 }, + { 56, 0x0001 }, + { 57, 0x0001 }, }; +static bool wm8978_volatile(struct device *dev, unsigned int reg) +{ + return reg == WM8978_RESET; +} + /* codec private data */ struct wm8978_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; unsigned int f_pllout; unsigned int f_mclk; unsigned int f_256fs; @@ -303,7 +350,7 @@ static const struct snd_soc_dapm_widget wm8978_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("RSPK"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8978_dapm_routes[] = { /* Output mixer */ {"Right Output Mixer", "PCM Playback Switch", "Right DAC"}, {"Right Output Mixer", "Aux Playback Switch", "RAUX"}, @@ -352,18 +399,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Left Input Mixer", "MicP Switch", "LMICP"}, }; -static int wm8978_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8978_dapm_widgets, - ARRAY_SIZE(wm8978_dapm_widgets)); - /* set up the WM8978 audio map */ - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - return 0; -} - /* PLL divisors */ struct wm8978_pll_div { u32 k; @@ -894,26 +929,23 @@ static struct snd_soc_dai_driver wm8978_dai = { static int wm8978_suspend(struct snd_soc_codec *codec) { + struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); + wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); /* Also switch PLL off */ snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0); + regcache_mark_dirty(wm8978->regmap); + return 0; } static int wm8978_resume(struct snd_soc_codec *codec) { struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec); - int i; - u16 *cache = codec->reg_cache; /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(wm8978_reg); i++) { - if (i == WM8978_RESET) - continue; - if (cache[i] != wm8978_reg[i]) - snd_soc_write(codec, i, cache[i]); - } + regcache_sync(wm8978->regmap); wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -953,7 +985,8 @@ static int wm8978_probe(struct snd_soc_codec *codec) * default hardware setting */ wm8978->sysclk = WM8978_PLL; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C); + codec->control_data = wm8978->regmap; + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -967,19 +1000,8 @@ static int wm8978_probe(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(update_reg); i++) snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100); - /* Reset the codec */ - ret = snd_soc_write(codec, WM8978_RESET, 0); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); - return ret; - } - wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_controls(codec, wm8978_snd_controls, - ARRAY_SIZE(wm8978_snd_controls)); - wm8978_add_widgets(codec); - return 0; } @@ -996,35 +1018,75 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8978 = { .suspend = wm8978_suspend, .resume = wm8978_resume, .set_bias_level = wm8978_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8978_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8978_reg, + + .controls = wm8978_snd_controls, + .num_controls = ARRAY_SIZE(wm8978_snd_controls), + .dapm_widgets = wm8978_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8978_dapm_widgets), + .dapm_routes = wm8978_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8978_dapm_routes), +}; + +static const struct regmap_config wm8978_regmap_config = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = WM8978_MAX_REGISTER, + .volatile_reg = wm8978_volatile, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8978_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults), }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8978_priv *wm8978; int ret; - wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL); + wm8978 = devm_kzalloc(&i2c->dev, sizeof(struct wm8978_priv), + GFP_KERNEL); if (wm8978 == NULL) return -ENOMEM; + wm8978->regmap = regmap_init_i2c(i2c, &wm8978_regmap_config); + if (IS_ERR(wm8978->regmap)) { + ret = PTR_ERR(wm8978->regmap); + dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + i2c_set_clientdata(i2c, wm8978); + /* Reset the codec */ + ret = regmap_write(wm8978->regmap, WM8978_RESET, 0); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); + goto err; + } + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8978, &wm8978_dai, 1); - if (ret < 0) - kfree(wm8978); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + goto err; + } + + return 0; + +err: + regmap_exit(wm8978->regmap); return ret; } static __devexit int wm8978_i2c_remove(struct i2c_client *client) { + struct wm8978_priv *wm8978 = i2c_get_clientdata(client); + snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + regmap_exit(wm8978->regmap); + return 0; } @@ -1043,27 +1105,22 @@ static struct i2c_driver wm8978_i2c_driver = { .remove = __devexit_p(wm8978_i2c_remove), .id_table = wm8978_i2c_id, }; -#endif static int __init wm8978_modinit(void) { int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ret = i2c_add_driver(&wm8978_i2c_driver); if (ret != 0) { printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n", ret); } -#endif return ret; } module_init(wm8978_modinit); static void __exit wm8978_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&wm8978_i2c_driver); -#endif } module_exit(wm8978_exit); diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h index c75525b7f15..6ae43495b7c 100644 --- a/sound/soc/codecs/wm8978.h +++ b/sound/soc/codecs/wm8978.h @@ -67,6 +67,8 @@ #define WM8978_OUT3_MIXER_CONTROL 0x38 #define WM8978_OUT4_MIXER_CONTROL 0x39 +#define WM8978_MAX_REGISTER 0x39 + #define WM8978_CACHEREGNUM 58 /* Clock divider Id's */ diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index cebde568d19..367388fdc48 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -249,9 +249,6 @@ static const char *eq5_cutoff_text[] = { static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, eq5_cutoff_text); -static const char *speaker_mode_text[] = { "Class A/B", "Class D" }; -static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); - static const char *depth_3d_text[] = { "Off", "6.67%", @@ -369,8 +366,6 @@ static const struct snd_kcontrol_new wm8983_snd_controls[] = { SOC_SINGLE_TLV("EQ5 Volume", WM8983_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv), SOC_ENUM("3D Depth", depth_3d), - - SOC_ENUM("Speaker Mode", speaker_mode) }; static const struct snd_kcontrol_new left_out_mixer[] = { diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index c0c86b3c6ad..14f666398d0 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -19,6 +19,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> #include <linux/slab.h> @@ -39,73 +40,127 @@ static const char *wm8985_supply_names[WM8985_NUM_SUPPLIES] = { "AVDD2" }; -static const u16 wm8985_reg_defs[] = { - 0x0000, /* R0 - Software Reset */ - 0x0000, /* R1 - Power management 1 */ - 0x0000, /* R2 - Power management 2 */ - 0x0000, /* R3 - Power management 3 */ - 0x0050, /* R4 - Audio Interface */ - 0x0000, /* R5 - Companding control */ - 0x0140, /* R6 - Clock Gen control */ - 0x0000, /* R7 - Additional control */ - 0x0000, /* R8 - GPIO Control */ - 0x0000, /* R9 - Jack Detect Control 1 */ - 0x0000, /* R10 - DAC Control */ - 0x00FF, /* R11 - Left DAC digital Vol */ - 0x00FF, /* R12 - Right DAC digital vol */ - 0x0000, /* R13 - Jack Detect Control 2 */ - 0x0100, /* R14 - ADC Control */ - 0x00FF, /* R15 - Left ADC Digital Vol */ - 0x00FF, /* R16 - Right ADC Digital Vol */ - 0x0000, /* R17 */ - 0x012C, /* R18 - EQ1 - low shelf */ - 0x002C, /* R19 - EQ2 - peak 1 */ - 0x002C, /* R20 - EQ3 - peak 2 */ - 0x002C, /* R21 - EQ4 - peak 3 */ - 0x002C, /* R22 - EQ5 - high shelf */ - 0x0000, /* R23 */ - 0x0032, /* R24 - DAC Limiter 1 */ - 0x0000, /* R25 - DAC Limiter 2 */ - 0x0000, /* R26 */ - 0x0000, /* R27 - Notch Filter 1 */ - 0x0000, /* R28 - Notch Filter 2 */ - 0x0000, /* R29 - Notch Filter 3 */ - 0x0000, /* R30 - Notch Filter 4 */ - 0x0000, /* R31 */ - 0x0038, /* R32 - ALC control 1 */ - 0x000B, /* R33 - ALC control 2 */ - 0x0032, /* R34 - ALC control 3 */ - 0x0000, /* R35 - Noise Gate */ - 0x0008, /* R36 - PLL N */ - 0x000C, /* R37 - PLL K 1 */ - 0x0093, /* R38 - PLL K 2 */ - 0x00E9, /* R39 - PLL K 3 */ - 0x0000, /* R40 */ - 0x0000, /* R41 - 3D control */ - 0x0000, /* R42 - OUT4 to ADC */ - 0x0000, /* R43 - Beep control */ - 0x0033, /* R44 - Input ctrl */ - 0x0010, /* R45 - Left INP PGA gain ctrl */ - 0x0010, /* R46 - Right INP PGA gain ctrl */ - 0x0100, /* R47 - Left ADC BOOST ctrl */ - 0x0100, /* R48 - Right ADC BOOST ctrl */ - 0x0002, /* R49 - Output ctrl */ - 0x0001, /* R50 - Left mixer ctrl */ - 0x0001, /* R51 - Right mixer ctrl */ - 0x0039, /* R52 - LOUT1 (HP) volume ctrl */ - 0x0039, /* R53 - ROUT1 (HP) volume ctrl */ - 0x0039, /* R54 - LOUT2 (SPK) volume ctrl */ - 0x0039, /* R55 - ROUT2 (SPK) volume ctrl */ - 0x0001, /* R56 - OUT3 mixer ctrl */ - 0x0001, /* R57 - OUT4 (MONO) mix ctrl */ - 0x0001, /* R58 */ - 0x0000, /* R59 */ - 0x0004, /* R60 - OUTPUT ctrl */ - 0x0000, /* R61 - BIAS CTRL */ - 0x0180, /* R62 */ - 0x0000 /* R63 */ +static const struct reg_default wm8985_reg_defaults[] = { + { 1, 0x0000 }, /* R1 - Power management 1 */ + { 2, 0x0000 }, /* R2 - Power management 2 */ + { 3, 0x0000 }, /* R3 - Power management 3 */ + { 4, 0x0050 }, /* R4 - Audio Interface */ + { 5, 0x0000 }, /* R5 - Companding control */ + { 6, 0x0140 }, /* R6 - Clock Gen control */ + { 7, 0x0000 }, /* R7 - Additional control */ + { 8, 0x0000 }, /* R8 - GPIO Control */ + { 9, 0x0000 }, /* R9 - Jack Detect Control 1 */ + { 10, 0x0000 }, /* R10 - DAC Control */ + { 11, 0x00FF }, /* R11 - Left DAC digital Vol */ + { 12, 0x00FF }, /* R12 - Right DAC digital vol */ + { 13, 0x0000 }, /* R13 - Jack Detect Control 2 */ + { 14, 0x0100 }, /* R14 - ADC Control */ + { 15, 0x00FF }, /* R15 - Left ADC Digital Vol */ + { 16, 0x00FF }, /* R16 - Right ADC Digital Vol */ + { 18, 0x012C }, /* R18 - EQ1 - low shelf */ + { 19, 0x002C }, /* R19 - EQ2 - peak 1 */ + { 20, 0x002C }, /* R20 - EQ3 - peak 2 */ + { 21, 0x002C }, /* R21 - EQ4 - peak 3 */ + { 22, 0x002C }, /* R22 - EQ5 - high shelf */ + { 24, 0x0032 }, /* R24 - DAC Limiter 1 */ + { 25, 0x0000 }, /* R25 - DAC Limiter 2 */ + { 27, 0x0000 }, /* R27 - Notch Filter 1 */ + { 28, 0x0000 }, /* R28 - Notch Filter 2 */ + { 29, 0x0000 }, /* R29 - Notch Filter 3 */ + { 30, 0x0000 }, /* R30 - Notch Filter 4 */ + { 32, 0x0038 }, /* R32 - ALC control 1 */ + { 33, 0x000B }, /* R33 - ALC control 2 */ + { 34, 0x0032 }, /* R34 - ALC control 3 */ + { 35, 0x0000 }, /* R35 - Noise Gate */ + { 36, 0x0008 }, /* R36 - PLL N */ + { 37, 0x000C }, /* R37 - PLL K 1 */ + { 38, 0x0093 }, /* R38 - PLL K 2 */ + { 39, 0x00E9 }, /* R39 - PLL K 3 */ + { 41, 0x0000 }, /* R41 - 3D control */ + { 42, 0x0000 }, /* R42 - OUT4 to ADC */ + { 43, 0x0000 }, /* R43 - Beep control */ + { 44, 0x0033 }, /* R44 - Input ctrl */ + { 45, 0x0010 }, /* R45 - Left INP PGA gain ctrl */ + { 46, 0x0010 }, /* R46 - Right INP PGA gain ctrl */ + { 47, 0x0100 }, /* R47 - Left ADC BOOST ctrl */ + { 48, 0x0100 }, /* R48 - Right ADC BOOST ctrl */ + { 49, 0x0002 }, /* R49 - Output ctrl */ + { 50, 0x0001 }, /* R50 - Left mixer ctrl */ + { 51, 0x0001 }, /* R51 - Right mixer ctrl */ + { 52, 0x0039 }, /* R52 - LOUT1 (HP) volume ctrl */ + { 53, 0x0039 }, /* R53 - ROUT1 (HP) volume ctrl */ + { 54, 0x0039 }, /* R54 - LOUT2 (SPK) volume ctrl */ + { 55, 0x0039 }, /* R55 - ROUT2 (SPK) volume ctrl */ + { 56, 0x0001 }, /* R56 - OUT3 mixer ctrl */ + { 57, 0x0001 }, /* R57 - OUT4 (MONO) mix ctrl */ + { 60, 0x0004 }, /* R60 - OUTPUT ctrl */ + { 61, 0x0000 }, /* R61 - BIAS CTRL */ }; +static bool wm8985_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM8985_SOFTWARE_RESET: + case WM8985_POWER_MANAGEMENT_1: + case WM8985_POWER_MANAGEMENT_2: + case WM8985_POWER_MANAGEMENT_3: + case WM8985_AUDIO_INTERFACE: + case WM8985_COMPANDING_CONTROL: + case WM8985_CLOCK_GEN_CONTROL: + case WM8985_ADDITIONAL_CONTROL: + case WM8985_GPIO_CONTROL: + case WM8985_JACK_DETECT_CONTROL_1: + case WM8985_DAC_CONTROL: + case WM8985_LEFT_DAC_DIGITAL_VOL: + case WM8985_RIGHT_DAC_DIGITAL_VOL: + case WM8985_JACK_DETECT_CONTROL_2: + case WM8985_ADC_CONTROL: + case WM8985_LEFT_ADC_DIGITAL_VOL: + case WM8985_RIGHT_ADC_DIGITAL_VOL: + case WM8985_EQ1_LOW_SHELF: + case WM8985_EQ2_PEAK_1: + case WM8985_EQ3_PEAK_2: + case WM8985_EQ4_PEAK_3: + case WM8985_EQ5_HIGH_SHELF: + case WM8985_DAC_LIMITER_1: + case WM8985_DAC_LIMITER_2: + case WM8985_NOTCH_FILTER_1: + case WM8985_NOTCH_FILTER_2: + case WM8985_NOTCH_FILTER_3: + case WM8985_NOTCH_FILTER_4: + case WM8985_ALC_CONTROL_1: + case WM8985_ALC_CONTROL_2: + case WM8985_ALC_CONTROL_3: + case WM8985_NOISE_GATE: + case WM8985_PLL_N: + case WM8985_PLL_K_1: + case WM8985_PLL_K_2: + case WM8985_PLL_K_3: + case WM8985_3D_CONTROL: + case WM8985_OUT4_TO_ADC: + case WM8985_BEEP_CONTROL: + case WM8985_INPUT_CTRL: + case WM8985_LEFT_INP_PGA_GAIN_CTRL: + case WM8985_RIGHT_INP_PGA_GAIN_CTRL: + case WM8985_LEFT_ADC_BOOST_CTRL: + case WM8985_RIGHT_ADC_BOOST_CTRL: + case WM8985_OUTPUT_CTRL0: + case WM8985_LEFT_MIXER_CTRL: + case WM8985_RIGHT_MIXER_CTRL: + case WM8985_LOUT1_HP_VOLUME_CTRL: + case WM8985_ROUT1_HP_VOLUME_CTRL: + case WM8985_LOUT2_SPK_VOLUME_CTRL: + case WM8985_ROUT2_SPK_VOLUME_CTRL: + case WM8985_OUT3_MIXER_CTRL: + case WM8985_OUT4_MONO_MIX_CTRL: + case WM8985_OUTPUT_CTRL1: + case WM8985_BIAS_CTRL: + return true; + default: + return false; + } +} + /* * latch bit 8 of these registers to ensure instant * volume updates @@ -124,7 +179,7 @@ static const int volume_update_regs[] = { }; struct wm8985_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES]; unsigned int sysclk; unsigned int bclk; @@ -428,7 +483,7 @@ static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("SPKR") }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8985_dapm_routes[] = { { "Right Output Mixer", "PCM Switch", "Right DAC" }, { "Right Output Mixer", "Aux Switch", "AUXR" }, { "Right Output Mixer", "Line Switch", "Right Boost Mixer" }, @@ -531,17 +586,6 @@ static int eqmode_put(struct snd_kcontrol *kcontrol, return 0; } -static int wm8985_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8985_dapm_widgets, - ARRAY_SIZE(wm8985_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_map, - ARRAY_SIZE(audio_map)); - return 0; -} - static int wm8985_reset(struct snd_soc_codec *codec) { return snd_soc_write(codec, WM8985_SOFTWARE_RESET, 0x0); @@ -845,25 +889,6 @@ static int wm8985_set_sysclk(struct snd_soc_dai *dai, return 0; } -static void wm8985_sync_cache(struct snd_soc_codec *codec) -{ - short i; - u16 *cache; - - if (!codec->cache_sync) - return; - codec->cache_only = 0; - /* restore cache */ - cache = codec->reg_cache; - for (i = 0; i < codec->driver->reg_cache_size; i++) { - if (i == WM8985_SOFTWARE_RESET - || cache[i] == wm8985_reg_defs[i]) - continue; - snd_soc_write(codec, i, cache[i]); - } - codec->cache_sync = 0; -} - static int wm8985_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -890,7 +915,7 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec, return ret; } - wm8985_sync_cache(codec); + regcache_sync(wm8985->regmap); /* enable anti-pop features */ snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC, @@ -933,7 +958,7 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec, snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, 0); snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, 0); - codec->cache_sync = 1; + regcache_mark_dirty(wm8985->regmap); regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies); @@ -976,11 +1001,11 @@ static int wm8985_probe(struct snd_soc_codec *codec) size_t i; struct wm8985_priv *wm8985; int ret; - u16 *cache; wm8985 = snd_soc_codec_get_drvdata(codec); + codec->control_data = wm8985->regmap; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8985->control_type); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); return ret; @@ -1009,17 +1034,13 @@ static int wm8985_probe(struct snd_soc_codec *codec) goto err_reg_enable; } - cache = codec->reg_cache; /* latch volume update bits */ for (i = 0; i < ARRAY_SIZE(volume_update_regs); ++i) - cache[volume_update_regs[i]] |= 0x100; + snd_soc_update_bits(codec, volume_update_regs[i], + 0x100, 0x100); /* enable BIASCUT */ - cache[WM8985_BIAS_CTRL] |= WM8985_BIASCUT; - codec->cache_sync = 1; - - snd_soc_add_controls(codec, wm8985_snd_controls, - ARRAY_SIZE(wm8985_snd_controls)); - wm8985_add_widgets(codec); + snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT, + WM8985_BIASCUT); wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; @@ -1068,9 +1089,25 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8985 = { .suspend = wm8985_suspend, .resume = wm8985_resume, .set_bias_level = wm8985_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8985_reg_defs), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8985_reg_defs + + .controls = wm8985_snd_controls, + .num_controls = ARRAY_SIZE(wm8985_snd_controls), + .dapm_widgets = wm8985_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8985_dapm_widgets), + .dapm_routes = wm8985_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8985_dapm_routes), +}; + +static const struct regmap_config wm8985_regmap = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = WM8985_MAX_REGISTER, + .writeable_reg = wm8985_writeable, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8985_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8985_reg_defaults), }; #if defined(CONFIG_SPI_MASTER) @@ -1079,24 +1116,39 @@ static int __devinit wm8985_spi_probe(struct spi_device *spi) struct wm8985_priv *wm8985; int ret; - wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL); + wm8985 = devm_kzalloc(&spi->dev, sizeof *wm8985, GFP_KERNEL); if (!wm8985) return -ENOMEM; - wm8985->control_type = SND_SOC_SPI; spi_set_drvdata(spi, wm8985); + wm8985->regmap = regmap_init_spi(spi, &wm8985_regmap); + if (IS_ERR(wm8985->regmap)) { + ret = PTR_ERR(wm8985->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", + ret); + goto err; + } + ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8985, &wm8985_dai, 1); - if (ret < 0) - kfree(wm8985); + if (ret != 0) + goto err; + + return 0; + +err: + regmap_exit(wm8985->regmap); return ret; } static int __devexit wm8985_spi_remove(struct spi_device *spi) { + struct wm8985_priv *wm8985 = spi_get_drvdata(spi); + snd_soc_unregister_codec(&spi->dev); - kfree(spi_get_drvdata(spi)); + regmap_exit(wm8985->regmap); + return 0; } @@ -1117,24 +1169,39 @@ static __devinit int wm8985_i2c_probe(struct i2c_client *i2c, struct wm8985_priv *wm8985; int ret; - wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL); + wm8985 = devm_kzalloc(&i2c->dev, sizeof *wm8985, GFP_KERNEL); if (!wm8985) return -ENOMEM; - wm8985->control_type = SND_SOC_I2C; i2c_set_clientdata(i2c, wm8985); + wm8985->regmap = regmap_init_i2c(i2c, &wm8985_regmap); + if (IS_ERR(wm8985->regmap)) { + ret = PTR_ERR(wm8985->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + goto err; + } + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8985, &wm8985_dai, 1); - if (ret < 0) - kfree(wm8985); + if (ret != 0) + goto err; + + return 0; + +err: + regmap_exit(wm8985->regmap); return ret; } -static __devexit int wm8985_i2c_remove(struct i2c_client *client) +static __devexit int wm8985_i2c_remove(struct i2c_client *i2c) { - snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + struct wm8985_priv *wm8985 = i2c_get_clientdata(i2c); + + snd_soc_unregister_codec(&i2c->dev); + regmap_exit(wm8985->regmap); + return 0; } diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index ab52963dd04..6cdf6a2bc28 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -33,24 +33,89 @@ * We can't read the WM8988 register space when we * are using 2 wire for device control, so we cache them instead. */ -static const u16 wm8988_reg[] = { - 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ - 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ - 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ - 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ - 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ - 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ - 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ - 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ - 0x0079, 0x0079, 0x0079, /* 40 */ +static const struct reg_default wm8988_reg_defaults[] = { + { 0, 0x0097 }, + { 1, 0x0097 }, + { 2, 0x0079 }, + { 3, 0x0079 }, + { 5, 0x0008 }, + { 7, 0x000a }, + { 8, 0x0000 }, + { 10, 0x00ff }, + { 11, 0x00ff }, + { 12, 0x000f }, + { 13, 0x000f }, + { 16, 0x0000 }, + { 17, 0x007b }, + { 18, 0x0000 }, + { 19, 0x0032 }, + { 20, 0x0000 }, + { 21, 0x00c3 }, + { 22, 0x00c3 }, + { 23, 0x00c0 }, + { 24, 0x0000 }, + { 25, 0x0000 }, + { 26, 0x0000 }, + { 27, 0x0000 }, + { 31, 0x0000 }, + { 32, 0x0000 }, + { 33, 0x0000 }, + { 34, 0x0050 }, + { 35, 0x0050 }, + { 36, 0x0050 }, + { 37, 0x0050 }, + { 40, 0x0079 }, + { 41, 0x0079 }, + { 42, 0x0079 }, }; +static bool wm8988_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM8988_LINVOL: + case WM8988_RINVOL: + case WM8988_LOUT1V: + case WM8988_ROUT1V: + case WM8988_ADCDAC: + case WM8988_IFACE: + case WM8988_SRATE: + case WM8988_LDAC: + case WM8988_RDAC: + case WM8988_BASS: + case WM8988_TREBLE: + case WM8988_RESET: + case WM8988_3D: + case WM8988_ALC1: + case WM8988_ALC2: + case WM8988_ALC3: + case WM8988_NGATE: + case WM8988_LADC: + case WM8988_RADC: + case WM8988_ADCTL1: + case WM8988_ADCTL2: + case WM8988_PWR1: + case WM8988_PWR2: + case WM8988_ADCTL3: + case WM8988_ADCIN: + case WM8988_LADCIN: + case WM8988_RADCIN: + case WM8988_LOUTM1: + case WM8988_LOUTM2: + case WM8988_ROUTM1: + case WM8988_ROUTM2: + case WM8988_LOUT2V: + case WM8988_ROUT2V: + case WM8988_LPPB: + return true; + default: + return false; + } +} + /* codec private data */ struct wm8988_priv { + struct regmap *regmap; unsigned int sysclk; - enum snd_soc_control_type control_type; struct snd_pcm_hw_constraint_list *sysclk_constraints; }; @@ -317,7 +382,7 @@ static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = { SND_SOC_DAPM_INPUT("RINPUT2"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8988_dapm_routes[] = { { "Left Line Mux", "Line 1", "LINPUT1" }, { "Left Line Mux", "Line 2", "LINPUT2" }, @@ -661,6 +726,7 @@ static int wm8988_mute(struct snd_soc_dai *dai, int mute) static int wm8988_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1; switch (level) { @@ -674,7 +740,7 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - snd_soc_cache_sync(codec); + regcache_sync(wm8988->regmap); /* VREF, VMID=2x5k */ snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); @@ -730,7 +796,10 @@ static struct snd_soc_dai_driver wm8988_dai = { static int wm8988_suspend(struct snd_soc_codec *codec) { + struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); + wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); + regcache_mark_dirty(wm8988->regmap); return 0; } @@ -743,10 +812,10 @@ static int wm8988_resume(struct snd_soc_codec *codec) static int wm8988_probe(struct snd_soc_codec *codec) { struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); - struct snd_soc_dapm_context *dapm = &codec->dapm; int ret = 0; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type); + codec->control_data = wm8988->regmap; + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -767,12 +836,6 @@ static int wm8988_probe(struct snd_soc_codec *codec) wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_controls(codec, wm8988_snd_controls, - ARRAY_SIZE(wm8988_snd_controls)); - snd_soc_dapm_new_controls(dapm, wm8988_dapm_widgets, - ARRAY_SIZE(wm8988_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - return 0; } @@ -788,9 +851,25 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { .suspend = wm8988_suspend, .resume = wm8988_resume, .set_bias_level = wm8988_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8988_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8988_reg, + + .controls = wm8988_snd_controls, + .num_controls = ARRAY_SIZE(wm8988_snd_controls), + .dapm_widgets = wm8988_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8988_dapm_widgets), + .dapm_routes = wm8988_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes), +}; + +static struct regmap_config wm8988_regmap = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = WM8988_LPPB, + .writeable_reg = wm8988_writeable, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8988_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8988_reg_defaults), }; #if defined(CONFIG_SPI_MASTER) @@ -799,24 +878,33 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) struct wm8988_priv *wm8988; int ret; - wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL); + wm8988 = devm_kzalloc(&spi->dev, sizeof(struct wm8988_priv), + GFP_KERNEL); if (wm8988 == NULL) return -ENOMEM; - wm8988->control_type = SND_SOC_SPI; + wm8988->regmap = regmap_init_spi(spi, &wm8988_regmap); + if (IS_ERR(wm8988->regmap)) { + ret = PTR_ERR(wm8988->regmap); + dev_err(&spi->dev, "Failed to init regmap: %d\n", ret); + return ret; + } + spi_set_drvdata(spi, wm8988); ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8988, &wm8988_dai, 1); - if (ret < 0) - kfree(wm8988); + if (ret != 0) + regmap_exit(wm8988->regmap); + return ret; } static int __devexit wm8988_spi_remove(struct spi_device *spi) { + struct wm8988_priv *wm8988 = spi_get_drvdata(spi); snd_soc_unregister_codec(&spi->dev); - kfree(spi_get_drvdata(spi)); + regmap_exit(wm8988->regmap); return 0; } @@ -837,24 +925,33 @@ static __devinit int wm8988_i2c_probe(struct i2c_client *i2c, struct wm8988_priv *wm8988; int ret; - wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL); + wm8988 = devm_kzalloc(&i2c->dev, sizeof(struct wm8988_priv), + GFP_KERNEL); if (wm8988 == NULL) return -ENOMEM; i2c_set_clientdata(i2c, wm8988); - wm8988->control_type = SND_SOC_I2C; + + wm8988->regmap = regmap_init_i2c(i2c, &wm8988_regmap); + if (IS_ERR(wm8988->regmap)) { + ret = PTR_ERR(wm8988->regmap); + dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); + return ret; + } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8988, &wm8988_dai, 1); - if (ret < 0) - kfree(wm8988); + if (ret != 0) + regmap_exit(wm8988->regmap); + return ret; } static __devexit int wm8988_i2c_remove(struct i2c_client *client) { + struct wm8988_priv *wm8988 = i2c_get_clientdata(client); snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + regmap_exit(wm8988->regmap); return 0; } @@ -866,7 +963,7 @@ MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id); static struct i2c_driver wm8988_i2c_driver = { .driver = { - .name = "wm8988-codec", + .name = "wm8988", .owner = THIS_MODULE, }, .probe = wm8988_i2c_probe, diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index e538edaae1f..9d242351e6e 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1356,7 +1356,7 @@ static int wm8990_probe(struct snd_soc_codec *codec) snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); - snd_soc_add_controls(codec, wm8990_snd_controls, + snd_soc_add_codec_controls(codec, wm8990_snd_controls, ARRAY_SIZE(wm8990_snd_controls)); wm8990_add_widgets(codec); diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 7ee40da8dbb..9ac31ba9b82 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1297,7 +1297,7 @@ static int wm8991_probe(struct snd_soc_codec *codec) snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8991_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); - snd_soc_add_controls(codec, wm8991_snd_controls, + snd_soc_add_codec_controls(codec, wm8991_snd_controls, ARRAY_SIZE(wm8991_snd_controls)); snd_soc_dapm_new_controls(&codec->dapm, wm8991_dapm_widgets, diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 7c7fd925db8..d256a934064 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> #include <linux/slab.h> @@ -40,134 +41,113 @@ static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = { "SPKVDD", }; -static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = { - 0x8993, /* R0 - Software Reset */ - 0x0000, /* R1 - Power Management (1) */ - 0x6000, /* R2 - Power Management (2) */ - 0x0000, /* R3 - Power Management (3) */ - 0x4050, /* R4 - Audio Interface (1) */ - 0x4000, /* R5 - Audio Interface (2) */ - 0x01C8, /* R6 - Clocking 1 */ - 0x0000, /* R7 - Clocking 2 */ - 0x0000, /* R8 - Audio Interface (3) */ - 0x0040, /* R9 - Audio Interface (4) */ - 0x0004, /* R10 - DAC CTRL */ - 0x00C0, /* R11 - Left DAC Digital Volume */ - 0x00C0, /* R12 - Right DAC Digital Volume */ - 0x0000, /* R13 - Digital Side Tone */ - 0x0300, /* R14 - ADC CTRL */ - 0x00C0, /* R15 - Left ADC Digital Volume */ - 0x00C0, /* R16 - Right ADC Digital Volume */ - 0x0000, /* R17 */ - 0x0000, /* R18 - GPIO CTRL 1 */ - 0x0010, /* R19 - GPIO1 */ - 0x0000, /* R20 - IRQ_DEBOUNCE */ - 0x0000, /* R21 */ - 0x8000, /* R22 - GPIOCTRL 2 */ - 0x0800, /* R23 - GPIO_POL */ - 0x008B, /* R24 - Left Line Input 1&2 Volume */ - 0x008B, /* R25 - Left Line Input 3&4 Volume */ - 0x008B, /* R26 - Right Line Input 1&2 Volume */ - 0x008B, /* R27 - Right Line Input 3&4 Volume */ - 0x006D, /* R28 - Left Output Volume */ - 0x006D, /* R29 - Right Output Volume */ - 0x0066, /* R30 - Line Outputs Volume */ - 0x0020, /* R31 - HPOUT2 Volume */ - 0x0079, /* R32 - Left OPGA Volume */ - 0x0079, /* R33 - Right OPGA Volume */ - 0x0003, /* R34 - SPKMIXL Attenuation */ - 0x0003, /* R35 - SPKMIXR Attenuation */ - 0x0011, /* R36 - SPKOUT Mixers */ - 0x0100, /* R37 - SPKOUT Boost */ - 0x0079, /* R38 - Speaker Volume Left */ - 0x0079, /* R39 - Speaker Volume Right */ - 0x0000, /* R40 - Input Mixer2 */ - 0x0000, /* R41 - Input Mixer3 */ - 0x0000, /* R42 - Input Mixer4 */ - 0x0000, /* R43 - Input Mixer5 */ - 0x0000, /* R44 - Input Mixer6 */ - 0x0000, /* R45 - Output Mixer1 */ - 0x0000, /* R46 - Output Mixer2 */ - 0x0000, /* R47 - Output Mixer3 */ - 0x0000, /* R48 - Output Mixer4 */ - 0x0000, /* R49 - Output Mixer5 */ - 0x0000, /* R50 - Output Mixer6 */ - 0x0000, /* R51 - HPOUT2 Mixer */ - 0x0000, /* R52 - Line Mixer1 */ - 0x0000, /* R53 - Line Mixer2 */ - 0x0000, /* R54 - Speaker Mixer */ - 0x0000, /* R55 - Additional Control */ - 0x0000, /* R56 - AntiPOP1 */ - 0x0000, /* R57 - AntiPOP2 */ - 0x0000, /* R58 - MICBIAS */ - 0x0000, /* R59 */ - 0x0000, /* R60 - FLL Control 1 */ - 0x0000, /* R61 - FLL Control 2 */ - 0x0000, /* R62 - FLL Control 3 */ - 0x2EE0, /* R63 - FLL Control 4 */ - 0x0002, /* R64 - FLL Control 5 */ - 0x2287, /* R65 - Clocking 3 */ - 0x025F, /* R66 - Clocking 4 */ - 0x0000, /* R67 - MW Slave Control */ - 0x0000, /* R68 */ - 0x0002, /* R69 - Bus Control 1 */ - 0x0000, /* R70 - Write Sequencer 0 */ - 0x0000, /* R71 - Write Sequencer 1 */ - 0x0000, /* R72 - Write Sequencer 2 */ - 0x0000, /* R73 - Write Sequencer 3 */ - 0x0000, /* R74 - Write Sequencer 4 */ - 0x0000, /* R75 - Write Sequencer 5 */ - 0x1F25, /* R76 - Charge Pump 1 */ - 0x0000, /* R77 */ - 0x0000, /* R78 */ - 0x0000, /* R79 */ - 0x0000, /* R80 */ - 0x0000, /* R81 - Class W 0 */ - 0x0000, /* R82 */ - 0x0000, /* R83 */ - 0x0000, /* R84 - DC Servo 0 */ - 0x054A, /* R85 - DC Servo 1 */ - 0x0000, /* R86 */ - 0x0000, /* R87 - DC Servo 3 */ - 0x0000, /* R88 - DC Servo Readback 0 */ - 0x0000, /* R89 - DC Servo Readback 1 */ - 0x0000, /* R90 - DC Servo Readback 2 */ - 0x0000, /* R91 */ - 0x0000, /* R92 */ - 0x0000, /* R93 */ - 0x0000, /* R94 */ - 0x0000, /* R95 */ - 0x0100, /* R96 - Analogue HP 0 */ - 0x0000, /* R97 */ - 0x0000, /* R98 - EQ1 */ - 0x000C, /* R99 - EQ2 */ - 0x000C, /* R100 - EQ3 */ - 0x000C, /* R101 - EQ4 */ - 0x000C, /* R102 - EQ5 */ - 0x000C, /* R103 - EQ6 */ - 0x0FCA, /* R104 - EQ7 */ - 0x0400, /* R105 - EQ8 */ - 0x00D8, /* R106 - EQ9 */ - 0x1EB5, /* R107 - EQ10 */ - 0xF145, /* R108 - EQ11 */ - 0x0B75, /* R109 - EQ12 */ - 0x01C5, /* R110 - EQ13 */ - 0x1C58, /* R111 - EQ14 */ - 0xF373, /* R112 - EQ15 */ - 0x0A54, /* R113 - EQ16 */ - 0x0558, /* R114 - EQ17 */ - 0x168E, /* R115 - EQ18 */ - 0xF829, /* R116 - EQ19 */ - 0x07AD, /* R117 - EQ20 */ - 0x1103, /* R118 - EQ21 */ - 0x0564, /* R119 - EQ22 */ - 0x0559, /* R120 - EQ23 */ - 0x4000, /* R121 - EQ24 */ - 0x0000, /* R122 - Digital Pulls */ - 0x0F08, /* R123 - DRC Control 1 */ - 0x0000, /* R124 - DRC Control 2 */ - 0x0080, /* R125 - DRC Control 3 */ - 0x0000, /* R126 - DRC Control 4 */ +static struct reg_default wm8993_reg_defaults[] = { + { 1, 0x0000 }, /* R1 - Power Management (1) */ + { 2, 0x6000 }, /* R2 - Power Management (2) */ + { 3, 0x0000 }, /* R3 - Power Management (3) */ + { 4, 0x4050 }, /* R4 - Audio Interface (1) */ + { 5, 0x4000 }, /* R5 - Audio Interface (2) */ + { 6, 0x01C8 }, /* R6 - Clocking 1 */ + { 7, 0x0000 }, /* R7 - Clocking 2 */ + { 8, 0x0000 }, /* R8 - Audio Interface (3) */ + { 9, 0x0040 }, /* R9 - Audio Interface (4) */ + { 10, 0x0004 }, /* R10 - DAC CTRL */ + { 11, 0x00C0 }, /* R11 - Left DAC Digital Volume */ + { 12, 0x00C0 }, /* R12 - Right DAC Digital Volume */ + { 13, 0x0000 }, /* R13 - Digital Side Tone */ + { 14, 0x0300 }, /* R14 - ADC CTRL */ + { 15, 0x00C0 }, /* R15 - Left ADC Digital Volume */ + { 16, 0x00C0 }, /* R16 - Right ADC Digital Volume */ + { 18, 0x0000 }, /* R18 - GPIO CTRL 1 */ + { 19, 0x0010 }, /* R19 - GPIO1 */ + { 20, 0x0000 }, /* R20 - IRQ_DEBOUNCE */ + { 21, 0x0000 }, /* R21 - Inputs Clamp */ + { 22, 0x8000 }, /* R22 - GPIOCTRL 2 */ + { 23, 0x0800 }, /* R23 - GPIO_POL */ + { 24, 0x008B }, /* R24 - Left Line Input 1&2 Volume */ + { 25, 0x008B }, /* R25 - Left Line Input 3&4 Volume */ + { 26, 0x008B }, /* R26 - Right Line Input 1&2 Volume */ + { 27, 0x008B }, /* R27 - Right Line Input 3&4 Volume */ + { 28, 0x006D }, /* R28 - Left Output Volume */ + { 29, 0x006D }, /* R29 - Right Output Volume */ + { 30, 0x0066 }, /* R30 - Line Outputs Volume */ + { 31, 0x0020 }, /* R31 - HPOUT2 Volume */ + { 32, 0x0079 }, /* R32 - Left OPGA Volume */ + { 33, 0x0079 }, /* R33 - Right OPGA Volume */ + { 34, 0x0003 }, /* R34 - SPKMIXL Attenuation */ + { 35, 0x0003 }, /* R35 - SPKMIXR Attenuation */ + { 36, 0x0011 }, /* R36 - SPKOUT Mixers */ + { 37, 0x0100 }, /* R37 - SPKOUT Boost */ + { 38, 0x0079 }, /* R38 - Speaker Volume Left */ + { 39, 0x0079 }, /* R39 - Speaker Volume Right */ + { 40, 0x0000 }, /* R40 - Input Mixer2 */ + { 41, 0x0000 }, /* R41 - Input Mixer3 */ + { 42, 0x0000 }, /* R42 - Input Mixer4 */ + { 43, 0x0000 }, /* R43 - Input Mixer5 */ + { 44, 0x0000 }, /* R44 - Input Mixer6 */ + { 45, 0x0000 }, /* R45 - Output Mixer1 */ + { 46, 0x0000 }, /* R46 - Output Mixer2 */ + { 47, 0x0000 }, /* R47 - Output Mixer3 */ + { 48, 0x0000 }, /* R48 - Output Mixer4 */ + { 49, 0x0000 }, /* R49 - Output Mixer5 */ + { 50, 0x0000 }, /* R50 - Output Mixer6 */ + { 51, 0x0000 }, /* R51 - HPOUT2 Mixer */ + { 52, 0x0000 }, /* R52 - Line Mixer1 */ + { 53, 0x0000 }, /* R53 - Line Mixer2 */ + { 54, 0x0000 }, /* R54 - Speaker Mixer */ + { 55, 0x0000 }, /* R55 - Additional Control */ + { 56, 0x0000 }, /* R56 - AntiPOP1 */ + { 57, 0x0000 }, /* R57 - AntiPOP2 */ + { 58, 0x0000 }, /* R58 - MICBIAS */ + { 60, 0x0000 }, /* R60 - FLL Control 1 */ + { 61, 0x0000 }, /* R61 - FLL Control 2 */ + { 62, 0x0000 }, /* R62 - FLL Control 3 */ + { 63, 0x2EE0 }, /* R63 - FLL Control 4 */ + { 64, 0x0002 }, /* R64 - FLL Control 5 */ + { 65, 0x2287 }, /* R65 - Clocking 3 */ + { 66, 0x025F }, /* R66 - Clocking 4 */ + { 67, 0x0000 }, /* R67 - MW Slave Control */ + { 69, 0x0002 }, /* R69 - Bus Control 1 */ + { 70, 0x0000 }, /* R70 - Write Sequencer 0 */ + { 71, 0x0000 }, /* R71 - Write Sequencer 1 */ + { 72, 0x0000 }, /* R72 - Write Sequencer 2 */ + { 73, 0x0000 }, /* R73 - Write Sequencer 3 */ + { 74, 0x0000 }, /* R74 - Write Sequencer 4 */ + { 75, 0x0000 }, /* R75 - Write Sequencer 5 */ + { 76, 0x1F25 }, /* R76 - Charge Pump 1 */ + { 81, 0x0000 }, /* R81 - Class W 0 */ + { 85, 0x054A }, /* R85 - DC Servo 1 */ + { 87, 0x0000 }, /* R87 - DC Servo 3 */ + { 96, 0x0100 }, /* R96 - Analogue HP 0 */ + { 98, 0x0000 }, /* R98 - EQ1 */ + { 99, 0x000C }, /* R99 - EQ2 */ + { 100, 0x000C }, /* R100 - EQ3 */ + { 101, 0x000C }, /* R101 - EQ4 */ + { 102, 0x000C }, /* R102 - EQ5 */ + { 103, 0x000C }, /* R103 - EQ6 */ + { 104, 0x0FCA }, /* R104 - EQ7 */ + { 105, 0x0400 }, /* R105 - EQ8 */ + { 106, 0x00D8 }, /* R106 - EQ9 */ + { 107, 0x1EB5 }, /* R107 - EQ10 */ + { 108, 0xF145 }, /* R108 - EQ11 */ + { 109, 0x0B75 }, /* R109 - EQ12 */ + { 110, 0x01C5 }, /* R110 - EQ13 */ + { 111, 0x1C58 }, /* R111 - EQ14 */ + { 112, 0xF373 }, /* R112 - EQ15 */ + { 113, 0x0A54 }, /* R113 - EQ16 */ + { 114, 0x0558 }, /* R114 - EQ17 */ + { 115, 0x168E }, /* R115 - EQ18 */ + { 116, 0xF829 }, /* R116 - EQ19 */ + { 117, 0x07AD }, /* R117 - EQ20 */ + { 118, 0x1103 }, /* R118 - EQ21 */ + { 119, 0x0564 }, /* R119 - EQ22 */ + { 120, 0x0559 }, /* R120 - EQ23 */ + { 121, 0x4000 }, /* R121 - EQ24 */ + { 122, 0x0000 }, /* R122 - Digital Pulls */ + { 123, 0x0F08 }, /* R123 - DRC Control 1 */ + { 124, 0x0000 }, /* R124 - DRC Control 2 */ + { 125, 0x0080 }, /* R125 - DRC Control 3 */ + { 126, 0x0000 }, /* R126 - DRC Control 4 */ }; static struct { @@ -225,9 +205,11 @@ static struct { struct wm8993_priv { struct wm_hubs_data hubs_data; + struct device *dev; + struct regmap *regmap; struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES]; struct wm8993_platform_data pdata; - enum snd_soc_control_type control_type; + struct completion fll_lock; int master; int sysclk_source; int tdm_slots; @@ -242,17 +224,137 @@ struct wm8993_priv { int fll_src; }; -static int wm8993_volatile(struct snd_soc_codec *codec, unsigned int reg) +static bool wm8993_volatile(struct device *dev, unsigned int reg) { switch (reg) { case WM8993_SOFTWARE_RESET: + case WM8993_GPIO_CTRL_1: case WM8993_DC_SERVO_0: case WM8993_DC_SERVO_READBACK_0: case WM8993_DC_SERVO_READBACK_1: case WM8993_DC_SERVO_READBACK_2: - return 1; + return true; default: - return 0; + return false; + } +} + +static bool wm8993_readable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM8993_SOFTWARE_RESET: + case WM8993_POWER_MANAGEMENT_1: + case WM8993_POWER_MANAGEMENT_2: + case WM8993_POWER_MANAGEMENT_3: + case WM8993_AUDIO_INTERFACE_1: + case WM8993_AUDIO_INTERFACE_2: + case WM8993_CLOCKING_1: + case WM8993_CLOCKING_2: + case WM8993_AUDIO_INTERFACE_3: + case WM8993_AUDIO_INTERFACE_4: + case WM8993_DAC_CTRL: + case WM8993_LEFT_DAC_DIGITAL_VOLUME: + case WM8993_RIGHT_DAC_DIGITAL_VOLUME: + case WM8993_DIGITAL_SIDE_TONE: + case WM8993_ADC_CTRL: + case WM8993_LEFT_ADC_DIGITAL_VOLUME: + case WM8993_RIGHT_ADC_DIGITAL_VOLUME: + case WM8993_GPIO_CTRL_1: + case WM8993_GPIO1: + case WM8993_IRQ_DEBOUNCE: + case WM8993_GPIOCTRL_2: + case WM8993_GPIO_POL: + case WM8993_LEFT_LINE_INPUT_1_2_VOLUME: + case WM8993_LEFT_LINE_INPUT_3_4_VOLUME: + case WM8993_RIGHT_LINE_INPUT_1_2_VOLUME: + case WM8993_RIGHT_LINE_INPUT_3_4_VOLUME: + case WM8993_LEFT_OUTPUT_VOLUME: + case WM8993_RIGHT_OUTPUT_VOLUME: + case WM8993_LINE_OUTPUTS_VOLUME: + case WM8993_HPOUT2_VOLUME: + case WM8993_LEFT_OPGA_VOLUME: + case WM8993_RIGHT_OPGA_VOLUME: + case WM8993_SPKMIXL_ATTENUATION: + case WM8993_SPKMIXR_ATTENUATION: + case WM8993_SPKOUT_MIXERS: + case WM8993_SPKOUT_BOOST: + case WM8993_SPEAKER_VOLUME_LEFT: + case WM8993_SPEAKER_VOLUME_RIGHT: + case WM8993_INPUT_MIXER2: + case WM8993_INPUT_MIXER3: + case WM8993_INPUT_MIXER4: + case WM8993_INPUT_MIXER5: + case WM8993_INPUT_MIXER6: + case WM8993_OUTPUT_MIXER1: + case WM8993_OUTPUT_MIXER2: + case WM8993_OUTPUT_MIXER3: + case WM8993_OUTPUT_MIXER4: + case WM8993_OUTPUT_MIXER5: + case WM8993_OUTPUT_MIXER6: + case WM8993_HPOUT2_MIXER: + case WM8993_LINE_MIXER1: + case WM8993_LINE_MIXER2: + case WM8993_SPEAKER_MIXER: + case WM8993_ADDITIONAL_CONTROL: + case WM8993_ANTIPOP1: + case WM8993_ANTIPOP2: + case WM8993_MICBIAS: + case WM8993_FLL_CONTROL_1: + case WM8993_FLL_CONTROL_2: + case WM8993_FLL_CONTROL_3: + case WM8993_FLL_CONTROL_4: + case WM8993_FLL_CONTROL_5: + case WM8993_CLOCKING_3: + case WM8993_CLOCKING_4: + case WM8993_MW_SLAVE_CONTROL: + case WM8993_BUS_CONTROL_1: + case WM8993_WRITE_SEQUENCER_0: + case WM8993_WRITE_SEQUENCER_1: + case WM8993_WRITE_SEQUENCER_2: + case WM8993_WRITE_SEQUENCER_3: + case WM8993_WRITE_SEQUENCER_4: + case WM8993_WRITE_SEQUENCER_5: + case WM8993_CHARGE_PUMP_1: + case WM8993_CLASS_W_0: + case WM8993_DC_SERVO_0: + case WM8993_DC_SERVO_1: + case WM8993_DC_SERVO_3: + case WM8993_DC_SERVO_READBACK_0: + case WM8993_DC_SERVO_READBACK_1: + case WM8993_DC_SERVO_READBACK_2: + case WM8993_ANALOGUE_HP_0: + case WM8993_EQ1: + case WM8993_EQ2: + case WM8993_EQ3: + case WM8993_EQ4: + case WM8993_EQ5: + case WM8993_EQ6: + case WM8993_EQ7: + case WM8993_EQ8: + case WM8993_EQ9: + case WM8993_EQ10: + case WM8993_EQ11: + case WM8993_EQ12: + case WM8993_EQ13: + case WM8993_EQ14: + case WM8993_EQ15: + case WM8993_EQ16: + case WM8993_EQ17: + case WM8993_EQ18: + case WM8993_EQ19: + case WM8993_EQ20: + case WM8993_EQ21: + case WM8993_EQ22: + case WM8993_EQ23: + case WM8993_EQ24: + case WM8993_DIGITAL_PULLS: + case WM8993_DRC_CONTROL_1: + case WM8993_DRC_CONTROL_2: + case WM8993_DRC_CONTROL_3: + case WM8993_DRC_CONTROL_4: + return true; + default: + return false; } } @@ -369,8 +471,10 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source, unsigned int Fref, unsigned int Fout) { struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); + struct i2c_client *i2c = to_i2c_client(codec->dev); u16 reg1, reg4, reg5; struct _fll_div fll_div; + unsigned int timeout; int ret; /* Any change? */ @@ -441,14 +545,22 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source, reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT; snd_soc_write(codec, WM8993_FLL_CONTROL_5, reg5); + /* If we've got an interrupt wired up make sure we get it */ + if (i2c->irq) + timeout = msecs_to_jiffies(20); + else if (Fref < 1000000) + timeout = msecs_to_jiffies(3); + else + timeout = msecs_to_jiffies(1); + + try_wait_for_completion(&wm8993->fll_lock); + /* Enable the FLL */ snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA); - /* Both overestimates */ - if (Fref < 1000000) - msleep(3); - else - msleep(1); + timeout = wait_for_completion_timeout(&wm8993->fll_lock, timeout); + if (i2c->irq && !timeout) + dev_warn(codec->dev, "Timed out waiting for FLL\n"); dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); @@ -946,6 +1058,8 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); int ret; + wm_hubs_set_bias_level(codec, level); + switch (level) { case SND_SOC_BIAS_ON: case SND_SOC_BIAS_PREPARE: @@ -963,12 +1077,10 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, if (ret != 0) return ret; - snd_soc_cache_sync(codec); + regcache_cache_only(wm8993->regmap, false); + regcache_sync(wm8993->regmap); - /* Tune DC servo configuration */ - snd_soc_write(codec, 0x44, 3); - snd_soc_write(codec, 0x56, 3); - snd_soc_write(codec, 0x44, 0); + wm_hubs_vmid_ena(codec); /* Bring up VMID with fast soft start */ snd_soc_update_bits(codec, WM8993_ANTIPOP2, @@ -1024,14 +1136,8 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec, WM8993_VMID_RAMP_MASK | WM8993_BIAS_SRC, 0); -#ifdef CONFIG_REGULATOR - /* Post 2.6.34 we will be able to get a callback when - * the regulators are disabled which we can use but - * for now just assume that the power will be cut if - * the regulator API is in use. - */ - codec->cache_sync = 1; -#endif + regcache_cache_only(wm8993->regmap, true); + regcache_mark_dirty(wm8993->regmap); regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); @@ -1378,6 +1484,45 @@ out: return 0; } +static irqreturn_t wm8993_irq(int irq, void *data) +{ + struct wm8993_priv *wm8993 = data; + int mask, val, ret; + + ret = regmap_read(wm8993->regmap, WM8993_GPIO_CTRL_1, &val); + if (ret != 0) { + dev_err(wm8993->dev, "Failed to read interrupt status: %d\n", + ret); + return IRQ_NONE; + } + + ret = regmap_read(wm8993->regmap, WM8993_GPIOCTRL_2, &mask); + if (ret != 0) { + dev_err(wm8993->dev, "Failed to read interrupt mask: %d\n", + ret); + return IRQ_NONE; + } + + /* The IRQ pin status is visible in the register too */ + val &= ~(mask | WM8993_IRQ); + if (!val) + return IRQ_NONE; + + if (val & WM8993_TEMPOK_EINT) + dev_crit(wm8993->dev, "Thermal warning\n"); + + if (val & WM8993_FLL_LOCK_EINT) { + dev_dbg(wm8993->dev, "FLL locked\n"); + complete(&wm8993->fll_lock); + } + + ret = regmap_write(wm8993->regmap, WM8993_GPIO_CTRL_1, val); + if (ret != 0) + dev_err(wm8993->dev, "Failed to ack interrupt: %d\n", ret); + + return IRQ_HANDLED; +} + static const struct snd_soc_dai_ops wm8993_ops = { .set_sysclk = wm8993_set_sysclk, .set_fmt = wm8993_set_dai_fmt, @@ -1402,6 +1547,7 @@ static struct snd_soc_dai_driver wm8993_dai = { .channels_max = 2, .rates = WM8993_RATES, .formats = WM8993_FORMATS, + .sig_bits = 24, }, .capture = { .stream_name = "Capture", @@ -1409,6 +1555,7 @@ static struct snd_soc_dai_driver wm8993_dai = { .channels_max = 2, .rates = WM8993_RATES, .formats = WM8993_FORMATS, + .sig_bits = 24, }, .ops = &wm8993_ops, .symmetric_rates = 1, @@ -1418,49 +1565,20 @@ static int wm8993_probe(struct snd_soc_codec *codec) { struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret, i, val; + int ret; wm8993->hubs_data.hp_startup_mode = 1; wm8993->hubs_data.dcs_codes_l = -2; wm8993->hubs_data.dcs_codes_r = -2; wm8993->hubs_data.series_startup = 1; - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + codec->control_data = wm8993->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } - for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++) - wm8993->supplies[i].supply = wm8993_supply_names[i]; - - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies), - wm8993->supplies); - if (ret != 0) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); - return ret; - } - - ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), - wm8993->supplies); - if (ret != 0) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - goto err_get; - } - - val = snd_soc_read(codec, WM8993_SOFTWARE_RESET); - if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) { - dev_err(codec->dev, "Invalid ID register value %x\n", val); - ret = -EINVAL; - goto err_enable; - } - - ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff); - if (ret != 0) - goto err_enable; - - codec->cache_only = 1; - /* By default we're using the output mixers */ wm8993->class_w_users = 2; @@ -1489,15 +1607,15 @@ static int wm8993_probe(struct snd_soc_codec *codec) ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); if (ret != 0) - goto err_enable; + return ret; - snd_soc_add_controls(codec, wm8993_snd_controls, + snd_soc_add_codec_controls(codec, wm8993_snd_controls, ARRAY_SIZE(wm8993_snd_controls)); if (wm8993->pdata.num_retune_configs != 0) { dev_dbg(codec->dev, "Using ReTune Mobile\n"); } else { dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n"); - snd_soc_add_controls(codec, wm8993_eq_controls, + snd_soc_add_codec_controls(codec, wm8993_eq_controls, ARRAY_SIZE(wm8993_eq_controls)); } @@ -1509,13 +1627,14 @@ static int wm8993_probe(struct snd_soc_codec *codec) wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff, wm8993->pdata.lineout2_diff); + /* If the line outputs are differential then we aren't presenting + * VMID as an output and can disable it. + */ + if (wm8993->pdata.lineout1_diff && wm8993->pdata.lineout2_diff) + codec->dapm.idle_bias_off = 1; + return 0; -err_enable: - regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); -err_get: - regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); - return ret; } static int wm8993_remove(struct snd_soc_codec *codec) @@ -1578,41 +1697,149 @@ static int wm8993_resume(struct snd_soc_codec *codec) #define wm8993_resume NULL #endif +/* Tune DC servo configuration */ +static struct reg_default wm8993_regmap_patch[] = { + { 0x44, 3 }, + { 0x56, 3 }, + { 0x44, 0 }, +}; + +static const struct regmap_config wm8993_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = WM8993_MAX_REGISTER, + .volatile_reg = wm8993_volatile, + .readable_reg = wm8993_readable, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8993_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults), +}; + static struct snd_soc_codec_driver soc_codec_dev_wm8993 = { .probe = wm8993_probe, .remove = wm8993_remove, .suspend = wm8993_suspend, .resume = wm8993_resume, .set_bias_level = wm8993_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8993_reg_defaults), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8993_reg_defaults, - .volatile_register = wm8993_volatile, }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8993_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8993_priv *wm8993; - int ret; + unsigned int reg; + int ret, i; wm8993 = devm_kzalloc(&i2c->dev, sizeof(struct wm8993_priv), GFP_KERNEL); if (wm8993 == NULL) return -ENOMEM; + wm8993->dev = &i2c->dev; + init_completion(&wm8993->fll_lock); + + wm8993->regmap = regmap_init_i2c(i2c, &wm8993_regmap); + if (IS_ERR(wm8993->regmap)) { + ret = PTR_ERR(wm8993->regmap); + dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + i2c_set_clientdata(i2c, wm8993); + for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++) + wm8993->supplies[i].supply = wm8993_supply_names[i]; + + ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8993->supplies), + wm8993->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + goto err; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies), + wm8993->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + goto err_get; + } + + ret = regmap_read(wm8993->regmap, WM8993_SOFTWARE_RESET, ®); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret); + goto err_enable; + } + + if (reg != 0x8993) { + dev_err(&i2c->dev, "Invalid ID register value %x\n", reg); + ret = -EINVAL; + goto err_enable; + } + + ret = regmap_write(wm8993->regmap, WM8993_SOFTWARE_RESET, 0xffff); + if (ret != 0) + goto err_enable; + + ret = regmap_register_patch(wm8993->regmap, wm8993_regmap_patch, + ARRAY_SIZE(wm8993_regmap_patch)); + if (ret != 0) + dev_warn(wm8993->dev, "Failed to apply regmap patch: %d\n", + ret); + + if (i2c->irq) { + /* Put GPIO1 into interrupt mode (only GPIO1 can output IRQ) */ + ret = regmap_update_bits(wm8993->regmap, WM8993_GPIO1, + WM8993_GPIO1_PD | + WM8993_GPIO1_SEL_MASK, 7); + if (ret != 0) + goto err_enable; + + ret = request_threaded_irq(i2c->irq, NULL, wm8993_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "wm8993", wm8993); + if (ret != 0) + goto err_enable; + + } + + regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); + + regcache_cache_only(wm8993->regmap, true); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8993, &wm8993_dai, 1); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + goto err_irq; + } + + return 0; + +err_irq: + if (i2c->irq) + free_irq(i2c->irq, wm8993); +err_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); +err_get: + regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); +err: + regmap_exit(wm8993->regmap); return ret; } -static __devexit int wm8993_i2c_remove(struct i2c_client *client) +static __devexit int wm8993_i2c_remove(struct i2c_client *i2c) { - snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); + struct wm8993_priv *wm8993 = i2c_get_clientdata(i2c); + + snd_soc_unregister_codec(&i2c->dev); + if (i2c->irq) + free_irq(i2c->irq, wm8993); + regmap_exit(wm8993->regmap); + regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); + regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); + return 0; } @@ -1631,30 +1858,8 @@ static struct i2c_driver wm8993_i2c_driver = { .remove = __devexit_p(wm8993_i2c_remove), .id_table = wm8993_i2c_id, }; -#endif - -static int __init wm8993_modinit(void) -{ - int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&wm8993_i2c_driver); - if (ret != 0) { - pr_err("WM8993: Unable to register I2C driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(wm8993_modinit); - -static void __exit wm8993_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8993_i2c_driver); -#endif -} -module_exit(wm8993_exit); +module_i2c_driver(wm8993_i2c_driver); MODULE_DESCRIPTION("ASoC WM8993 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8993.h b/sound/soc/codecs/wm8993.h index 2184617b961..4478b40c86e 100644 --- a/sound/soc/codecs/wm8993.h +++ b/sound/soc/codecs/wm8993.h @@ -31,6 +31,7 @@ #define WM8993_GPIO_CTRL_1 0x12 #define WM8993_GPIO1 0x13 #define WM8993_IRQ_DEBOUNCE 0x14 +#define WM8993_INPUTS_CLAMP_REG 0x15 #define WM8993_GPIOCTRL_2 0x16 #define WM8993_GPIO_POL 0x17 #define WM8993_LEFT_LINE_INPUT_1_2_VOLUME 0x18 @@ -656,6 +657,14 @@ #define WM8993_GPIO1_DB_WIDTH 1 /* GPIO1_DB */ /* + * R21 (0x15) - Inputs Clamp + */ +#define WM8993_INPUTS_CLAMP 0x0040 /* INPUTS_CLAMP */ +#define WM8993_INPUTS_CLAMP_MASK 0x0040 /* INPUTS_CLAMP */ +#define WM8993_INPUTS_CLAMP_SHIFT 7 /* INPUTS_CLAMP */ +#define WM8993_INPUTS_CLAMP_WIDTH 1 /* INPUTS_CLAMP */ + +/* * R22 (0x16) - GPIOCTRL 2 */ #define WM8993_IM_JD2_EINT 0x2000 /* IM_JD2_EINT */ diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index ec69a6c152f..9685dff44dd 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -686,14 +686,23 @@ static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + if (!wm8994->jackdet || !wm8994->jack_cb) + return; + if (wm8994->active_refcount) mode = WM1811_JACKDET_MODE_AUDIO; + if (mode == wm8994->jackdet_mode) + return; + + wm8994->jackdet_mode = mode; + + /* Always use audio mode to detect while the system is active */ + if (mode != WM1811_JACKDET_MODE_NONE) + mode = WM1811_JACKDET_MODE_AUDIO; + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, WM1811_JACKDET_MODE_MASK, mode); - - if (mode == WM1811_JACKDET_MODE_MIC) - msleep(2); } static void active_reference(struct snd_soc_codec *codec) @@ -707,15 +716,8 @@ static void active_reference(struct snd_soc_codec *codec) dev_dbg(codec->dev, "Active refcount incremented, now %d\n", wm8994->active_refcount); - if (wm8994->active_refcount == 1) { - /* If we're using jack detection go into audio mode */ - if (wm8994->jackdet && wm8994->jack_cb) { - snd_soc_update_bits(codec, WM8994_ANTIPOP_2, - WM1811_JACKDET_MODE_MASK, - WM1811_JACKDET_MODE_AUDIO); - msleep(2); - } - } + /* If we're using jack detection go into audio mode */ + wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_AUDIO); mutex_unlock(&wm8994->accdet_lock); } @@ -734,16 +736,12 @@ static void active_dereference(struct snd_soc_codec *codec) if (wm8994->active_refcount == 0) { /* Go into appropriate detection only mode */ - if (wm8994->jackdet && wm8994->jack_cb) { - if (wm8994->jack_mic || wm8994->mic_detecting) - mode = WM1811_JACKDET_MODE_MIC; - else - mode = WM1811_JACKDET_MODE_JACK; + if (wm8994->jack_mic || wm8994->mic_detecting) + mode = WM1811_JACKDET_MODE_MIC; + else + mode = WM1811_JACKDET_MODE_JACK; - snd_soc_update_bits(codec, WM8994_ANTIPOP_2, - WM1811_JACKDET_MODE_MASK, - mode); - } + wm1811_jackdet_set_mode(codec, mode); } mutex_unlock(&wm8994->accdet_lock); @@ -778,27 +776,69 @@ static void vmid_reference(struct snd_soc_codec *codec) wm8994->vmid_refcount); if (wm8994->vmid_refcount == 1) { - /* Startup bias, VMID ramp & buffer */ - snd_soc_update_bits(codec, WM8994_ANTIPOP_2, - WM8994_STARTUP_BIAS_ENA | - WM8994_VMID_BUF_ENA | - WM8994_VMID_RAMP_MASK, - WM8994_STARTUP_BIAS_ENA | - WM8994_VMID_BUF_ENA | - (0x3 << WM8994_VMID_RAMP_SHIFT)); - - /* Remove discharge for line out */ snd_soc_update_bits(codec, WM8994_ANTIPOP_1, WM8994_LINEOUT1_DISCH | WM8994_LINEOUT2_DISCH, 0); - /* Main bias enable, VMID=2x40k */ - snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, - WM8994_BIAS_ENA | - WM8994_VMID_SEL_MASK, - WM8994_BIAS_ENA | 0x2); + wm_hubs_vmid_ena(codec); + + switch (wm8994->vmid_mode) { + default: + WARN_ON(0 == "Invalid VMID mode"); + case WM8994_VMID_NORMAL: + /* Startup bias, VMID ramp & buffer */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_BIAS_SRC | + WM8994_VMID_DISCH | + WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + WM8994_VMID_RAMP_MASK, + WM8994_BIAS_SRC | + WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + (0x3 << WM8994_VMID_RAMP_SHIFT)); + + /* Main bias enable, VMID=2x40k */ + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_BIAS_ENA | + WM8994_VMID_SEL_MASK, + WM8994_BIAS_ENA | 0x2); + + msleep(50); + + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_VMID_RAMP_MASK | + WM8994_BIAS_SRC, + 0); + break; + + case WM8994_VMID_FORCE: + /* Startup bias, slow VMID ramp & buffer */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_BIAS_SRC | + WM8994_VMID_DISCH | + WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + WM8994_VMID_RAMP_MASK, + WM8994_BIAS_SRC | + WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + (0x2 << WM8994_VMID_RAMP_SHIFT)); + + /* Main bias enable, VMID=2x40k */ + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_BIAS_ENA | + WM8994_VMID_SEL_MASK, + WM8994_BIAS_ENA | 0x2); + + msleep(400); - msleep(20); + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_VMID_RAMP_MASK | + WM8994_BIAS_SRC, + 0); + break; + } } } @@ -812,30 +852,55 @@ static void vmid_dereference(struct snd_soc_codec *codec) wm8994->vmid_refcount); if (wm8994->vmid_refcount == 0) { - /* Switch over to startup biases */ + if (wm8994->hubs.lineout1_se) + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, + WM8994_LINEOUT1N_ENA | + WM8994_LINEOUT1P_ENA, + WM8994_LINEOUT1N_ENA | + WM8994_LINEOUT1P_ENA); + + if (wm8994->hubs.lineout2_se) + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, + WM8994_LINEOUT2N_ENA | + WM8994_LINEOUT2P_ENA, + WM8994_LINEOUT2N_ENA | + WM8994_LINEOUT2P_ENA); + + /* Start discharging VMID */ snd_soc_update_bits(codec, WM8994_ANTIPOP_2, WM8994_BIAS_SRC | - WM8994_STARTUP_BIAS_ENA | - WM8994_VMID_BUF_ENA | - WM8994_VMID_RAMP_MASK, + WM8994_VMID_DISCH, WM8994_BIAS_SRC | - WM8994_STARTUP_BIAS_ENA | - WM8994_VMID_BUF_ENA | - (1 << WM8994_VMID_RAMP_SHIFT)); + WM8994_VMID_DISCH); - /* Disable main biases */ - snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, - WM8994_BIAS_ENA | - WM8994_VMID_SEL_MASK, 0); + switch (wm8994->vmid_mode) { + case WM8994_VMID_FORCE: + msleep(350); + break; + default: + break; + } + + snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, + WM8994_VROI, WM8994_VROI); - /* Discharge line */ + /* Active discharge */ snd_soc_update_bits(codec, WM8994_ANTIPOP_1, WM8994_LINEOUT1_DISCH | WM8994_LINEOUT2_DISCH, WM8994_LINEOUT1_DISCH | WM8994_LINEOUT2_DISCH); - msleep(5); + msleep(150); + + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, + WM8994_LINEOUT1N_ENA | + WM8994_LINEOUT1P_ENA | + WM8994_LINEOUT2N_ENA | + WM8994_LINEOUT2P_ENA, 0); + + snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, + WM8994_VROI, 0); /* Switch off startup biases */ snd_soc_update_bits(codec, WM8994_ANTIPOP_2, @@ -843,6 +908,12 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_STARTUP_BIAS_ENA | WM8994_VMID_BUF_ENA | WM8994_VMID_RAMP_MASK, 0); + + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0); + + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_VMID_RAMP_MASK, 0); } pm_runtime_put(codec->dev); @@ -1459,17 +1530,17 @@ SND_SOC_DAPM_AIF_IN_E("AIF2DACR", NULL, 0, WM8994_POWER_MANAGEMENT_5, 12, 0, wm8958_aif_ev, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_IN("AIF2DACDAT", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIF1DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIF2DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux), SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux), SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux), -SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIF3DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0), @@ -1584,6 +1655,14 @@ static const struct snd_soc_dapm_route intercon[] = { { "TOCLK", NULL, "CLK_SYS" }, + { "AIF1DACDAT", NULL, "AIF1 Playback" }, + { "AIF2DACDAT", NULL, "AIF2 Playback" }, + { "AIF3DACDAT", NULL, "AIF3 Playback" }, + + { "AIF1 Capture", NULL, "AIF1ADCDAT" }, + { "AIF2 Capture", NULL, "AIF2ADCDAT" }, + { "AIF3 Capture", NULL, "AIF3ADCDAT" }, + /* AIF1 outputs */ { "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" }, { "AIF1ADC1L Mixer", "ADC/DMIC Switch", "ADCL Mux" }, @@ -1896,7 +1975,8 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, WM8994_FLL1_OUTDIV_MASK | WM8994_FLL1_FRATIO_MASK, reg); - snd_soc_write(codec, WM8994_FLL1_CONTROL_3 + reg_offset, fll.k); + snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_3 + reg_offset, + WM8994_FLL1_K_MASK, fll.k); snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset, WM8994_FLL1_N_MASK, @@ -2074,6 +2154,8 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; + wm_hubs_set_bias_level(codec, level); + switch (level) { case SND_SOC_BIAS_ON: break; @@ -2168,11 +2250,61 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, wm8994->cur_fw = NULL; break; } + codec->dapm.bias_level = level; return 0; } +int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode) +{ + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + switch (mode) { + case WM8994_VMID_NORMAL: + if (wm8994->hubs.lineout1_se) { + snd_soc_dapm_disable_pin(&codec->dapm, + "LINEOUT1N Driver"); + snd_soc_dapm_disable_pin(&codec->dapm, + "LINEOUT1P Driver"); + } + if (wm8994->hubs.lineout2_se) { + snd_soc_dapm_disable_pin(&codec->dapm, + "LINEOUT2N Driver"); + snd_soc_dapm_disable_pin(&codec->dapm, + "LINEOUT2P Driver"); + } + + /* Do the sync with the old mode to allow it to clean up */ + snd_soc_dapm_sync(&codec->dapm); + wm8994->vmid_mode = mode; + break; + + case WM8994_VMID_FORCE: + if (wm8994->hubs.lineout1_se) { + snd_soc_dapm_force_enable_pin(&codec->dapm, + "LINEOUT1N Driver"); + snd_soc_dapm_force_enable_pin(&codec->dapm, + "LINEOUT1P Driver"); + } + if (wm8994->hubs.lineout2_se) { + snd_soc_dapm_force_enable_pin(&codec->dapm, + "LINEOUT2N Driver"); + snd_soc_dapm_force_enable_pin(&codec->dapm, + "LINEOUT2P Driver"); + } + + wm8994->vmid_mode = mode; + snd_soc_dapm_sync(&codec->dapm); + break; + + default: + return -EINVAL; + } + + return 0; +} + static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_codec *codec = dai->codec; @@ -2654,6 +2786,7 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .channels_max = 2, .rates = WM8994_RATES, .formats = WM8994_FORMATS, + .sig_bits = 24, }, .capture = { .stream_name = "AIF1 Capture", @@ -2661,6 +2794,7 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .channels_max = 2, .rates = WM8994_RATES, .formats = WM8994_FORMATS, + .sig_bits = 24, }, .ops = &wm8994_aif1_dai_ops, }, @@ -2673,6 +2807,7 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .channels_max = 2, .rates = WM8994_RATES, .formats = WM8994_FORMATS, + .sig_bits = 24, }, .capture = { .stream_name = "AIF2 Capture", @@ -2680,6 +2815,7 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .channels_max = 2, .rates = WM8994_RATES, .formats = WM8994_FORMATS, + .sig_bits = 24, }, .probe = wm8994_aif2_probe, .ops = &wm8994_aif2_dai_ops, @@ -2693,6 +2829,7 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .channels_max = 2, .rates = WM8994_RATES, .formats = WM8994_FORMATS, + .sig_bits = 24, }, .capture = { .stream_name = "AIF3 Capture", @@ -2700,13 +2837,14 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .channels_max = 2, .rates = WM8994_RATES, .formats = WM8994_FORMATS, - }, + .sig_bits = 24, + }, .ops = &wm8994_aif3_dai_ops, } }; #ifdef CONFIG_PM -static int wm8994_suspend(struct snd_soc_codec *codec) +static int wm8994_codec_suspend(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; @@ -2740,7 +2878,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec) return 0; } -static int wm8994_resume(struct snd_soc_codec *codec) +static int wm8994_codec_resume(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; @@ -2762,8 +2900,6 @@ static int wm8994_resume(struct snd_soc_codec *codec) codec->cache_only = 0; } - wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { if (!wm8994->fll_suspend[i].out) continue; @@ -2791,6 +2927,7 @@ static int wm8994_resume(struct snd_soc_codec *codec) WM1811_JACKDET_MODE_JACK); break; } + break; case WM8958: if (wm8994->jack_cb) snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, @@ -2801,8 +2938,8 @@ static int wm8994_resume(struct snd_soc_codec *codec) return 0; } #else -#define wm8994_suspend NULL -#define wm8994_resume NULL +#define wm8994_codec_suspend NULL +#define wm8994_codec_resume NULL #endif static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) @@ -2865,7 +3002,7 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; - ret = snd_soc_add_controls(wm8994->codec, controls, + ret = snd_soc_add_codec_controls(wm8994->codec, controls, ARRAY_SIZE(controls)); if (ret != 0) dev_err(wm8994->codec->dev, @@ -2918,7 +3055,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) wm8994->drc_enum.max = pdata->num_drc_cfgs; wm8994->drc_enum.texts = wm8994->drc_texts; - ret = snd_soc_add_controls(wm8994->codec, controls, + ret = snd_soc_add_codec_controls(wm8994->codec, controls, ARRAY_SIZE(controls)); if (ret != 0) dev_err(wm8994->codec->dev, @@ -2934,7 +3071,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) if (pdata->num_retune_mobile_cfgs) wm8994_handle_retune_mobile_pdata(wm8994); else - snd_soc_add_controls(wm8994->codec, wm8994_eq_controls, + snd_soc_add_codec_controls(wm8994->codec, wm8994_eq_controls, ARRAY_SIZE(wm8994_eq_controls)); for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) { @@ -2951,8 +3088,6 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) * @codec: WM8994 codec * @jack: jack to report detection events on * @micbias: microphone bias to detect on - * @det: value to report for presence detection - * @shrt: value to report for short detection * * Enable microphone detection via IRQ on the WM8994. If GPIOs are * being used to bring out signals to the processor then only platform @@ -2963,43 +3098,63 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) * and micbias2_lvl platform data members. */ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, - int micbias, int det, int shrt) + int micbias) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_micdet *micdet; struct wm8994 *control = wm8994->wm8994; - int reg; + int reg, ret; - if (control->type != WM8994) + if (control->type != WM8994) { + dev_warn(codec->dev, "Not a WM8994\n"); return -EINVAL; + } switch (micbias) { case 1: micdet = &wm8994->micdet[0]; + if (jack) + ret = snd_soc_dapm_force_enable_pin(&codec->dapm, + "MICBIAS1"); + else + ret = snd_soc_dapm_disable_pin(&codec->dapm, + "MICBIAS1"); break; case 2: micdet = &wm8994->micdet[1]; + if (jack) + ret = snd_soc_dapm_force_enable_pin(&codec->dapm, + "MICBIAS1"); + else + ret = snd_soc_dapm_disable_pin(&codec->dapm, + "MICBIAS1"); break; default: + dev_warn(codec->dev, "Invalid MICBIAS %d\n", micbias); return -EINVAL; - } + } - dev_dbg(codec->dev, "Configuring microphone detection on %d: %x %x\n", - micbias, det, shrt); + if (ret != 0) + dev_warn(codec->dev, "Failed to configure MICBIAS%d: %d\n", + micbias, ret); + + dev_dbg(codec->dev, "Configuring microphone detection on %d %p\n", + micbias, jack); /* Store the configuration */ micdet->jack = jack; - micdet->det = det; - micdet->shrt = shrt; + micdet->detecting = true; /* If either of the jacks is set up then enable detection */ if (wm8994->micdet[0].jack || wm8994->micdet[1].jack) reg = WM8994_MICD_ENA; - else + else reg = 0; snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg); + snd_soc_dapm_sync(&codec->dapm); + return 0; } EXPORT_SYMBOL_GPL(wm8994_mic_detect); @@ -3025,20 +3180,42 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data) dev_dbg(codec->dev, "Microphone status: %x\n", reg); report = 0; - if (reg & WM8994_MIC1_DET_STS) - report |= priv->micdet[0].det; - if (reg & WM8994_MIC1_SHRT_STS) - report |= priv->micdet[0].shrt; + if (reg & WM8994_MIC1_DET_STS) { + if (priv->micdet[0].detecting) + report = SND_JACK_HEADSET; + } + if (reg & WM8994_MIC1_SHRT_STS) { + if (priv->micdet[0].detecting) + report = SND_JACK_HEADPHONE; + else + report |= SND_JACK_BTN_0; + } + if (report) + priv->micdet[0].detecting = false; + else + priv->micdet[0].detecting = true; + snd_soc_jack_report(priv->micdet[0].jack, report, - priv->micdet[0].det | priv->micdet[0].shrt); + SND_JACK_HEADSET | SND_JACK_BTN_0); report = 0; - if (reg & WM8994_MIC2_DET_STS) - report |= priv->micdet[1].det; - if (reg & WM8994_MIC2_SHRT_STS) - report |= priv->micdet[1].shrt; + if (reg & WM8994_MIC2_DET_STS) { + if (priv->micdet[1].detecting) + report = SND_JACK_HEADSET; + } + if (reg & WM8994_MIC2_SHRT_STS) { + if (priv->micdet[1].detecting) + report = SND_JACK_HEADPHONE; + else + report |= SND_JACK_BTN_0; + } + if (report) + priv->micdet[1].detecting = false; + else + priv->micdet[1].detecting = true; + snd_soc_jack_report(priv->micdet[1].jack, report, - priv->micdet[1].det | priv->micdet[1].shrt); + SND_JACK_HEADSET | SND_JACK_BTN_0); return IRQ_HANDLED; } @@ -3087,7 +3264,7 @@ static void wm8958_default_micdet(u16 status, void *data) } - if (wm8994->mic_detecting && status & 0x4) { + if (wm8994->mic_detecting && status & 0xfc) { dev_dbg(codec->dev, "Detected headphone\n"); wm8994->mic_detecting = false; @@ -3098,11 +3275,23 @@ static void wm8958_default_micdet(u16 status, void *data) /* If we have jackdet that will detect removal */ if (wm8994->jackdet) { + mutex_lock(&wm8994->accdet_lock); + snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0); wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK); + + mutex_unlock(&wm8994->accdet_lock); + + if (wm8994->pdata->jd_ext_cap) { + mutex_lock(&codec->mutex); + snd_soc_dapm_disable_pin(&codec->dapm, + "MICBIAS2"); + snd_soc_dapm_sync(&codec->dapm); + mutex_unlock(&codec->mutex); + } } } @@ -3137,6 +3326,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) struct wm8994_priv *wm8994 = data; struct snd_soc_codec *codec = wm8994->codec; int reg; + bool present; mutex_lock(&wm8994->accdet_lock); @@ -3149,11 +3339,17 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) dev_dbg(codec->dev, "JACKDET %x\n", reg); - if (reg & WM1811_JACKDET_LVL) { + present = reg & WM1811_JACKDET_LVL; + + if (present) { dev_dbg(codec->dev, "Jack detected\n"); - snd_soc_jack_report(wm8994->micdet[0].jack, - SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); + snd_soc_update_bits(codec, WM8958_MICBIAS2, + WM8958_MICB2_DISCH, 0); + + /* Disable debounce while inserted */ + snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, + WM1811_JACKDET_DB, 0); /* * Start off measument of microphone impedence to find @@ -3161,14 +3357,18 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) */ wm8994->mic_detecting = true; wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC); + snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, WM8958_MICD_ENA); } else { dev_dbg(codec->dev, "Jack not detected\n"); - snd_soc_jack_report(wm8994->micdet[0].jack, 0, - SND_JACK_MECHANICAL | SND_JACK_HEADSET | - wm8994->btn_mask); + snd_soc_update_bits(codec, WM8958_MICBIAS2, + WM8958_MICB2_DISCH, WM8958_MICB2_DISCH); + + /* Enable debounce while removed */ + snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, + WM1811_JACKDET_DB, WM1811_JACKDET_DB); wm8994->mic_detecting = false; wm8994->jack_mic = false; @@ -3179,6 +3379,28 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) mutex_unlock(&wm8994->accdet_lock); + /* If required for an external cap force MICBIAS on */ + if (wm8994->pdata->jd_ext_cap) { + mutex_lock(&codec->mutex); + + if (present) + snd_soc_dapm_force_enable_pin(&codec->dapm, + "MICBIAS2"); + else + snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2"); + + snd_soc_dapm_sync(&codec->dapm); + mutex_unlock(&codec->mutex); + } + + if (present) + snd_soc_jack_report(wm8994->micdet[0].jack, + SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); + else + snd_soc_jack_report(wm8994->micdet[0].jack, 0, + SND_JACK_MECHANICAL | SND_JACK_HEADSET | + wm8994->btn_mask); + return IRQ_HANDLED; } @@ -3221,6 +3443,7 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, } snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS"); + snd_soc_dapm_sync(&codec->dapm); wm8994->micdet[0].jack = jack; wm8994->jack_cb = cb; @@ -3251,6 +3474,9 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, * otherwise jump straight to microphone detection. */ if (wm8994->jackdet) { + snd_soc_update_bits(codec, WM8958_MICBIAS2, + WM8958_MICB2_DISCH, + WM8958_MICB2_DISCH); snd_soc_update_bits(codec, WM8994_LDO_1, WM8994_LDO1_DISCH, 0); wm1811_jackdet_set_mode(codec, @@ -3263,7 +3489,9 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, } else { snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0); + wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_NONE); snd_soc_dapm_disable_pin(&codec->dapm, "CLK_SYS"); + snd_soc_dapm_sync(&codec->dapm); } return 0; @@ -3276,17 +3504,13 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) struct snd_soc_codec *codec = wm8994->codec; int reg, count; - mutex_lock(&wm8994->accdet_lock); - /* * Jack detection may have detected a removal simulataneously * with an update of the MICDET status; if so it will have * stopped detection and we can ignore this interrupt. */ - if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) { - mutex_unlock(&wm8994->accdet_lock); + if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) return IRQ_HANDLED; - } /* We may occasionally read a detection without an impedence * range being provided - if that happens loop again. @@ -3295,7 +3519,6 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) do { reg = snd_soc_read(codec, WM8958_MIC_DETECT_3); if (reg < 0) { - mutex_unlock(&wm8994->accdet_lock); dev_err(codec->dev, "Failed to read mic detect status: %d\n", reg); @@ -3326,8 +3549,6 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) dev_warn(codec->dev, "Accessory detection with no callback\n"); out: - mutex_unlock(&wm8994->accdet_lock); - return IRQ_HANDLED; } @@ -3361,23 +3582,16 @@ static irqreturn_t wm8994_temp_shut(int irq, void *data) static int wm8994_codec_probe(struct snd_soc_codec *codec) { struct wm8994 *control = dev_get_drvdata(codec->dev->parent); - struct wm8994_priv *wm8994; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; unsigned int reg; int ret, i; + wm8994->codec = codec; codec->control_data = control->regmap; - wm8994 = devm_kzalloc(codec->dev, sizeof(struct wm8994_priv), - GFP_KERNEL); - if (wm8994 == NULL) - return -ENOMEM; - snd_soc_codec_set_drvdata(codec, wm8994); - snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); - wm8994->wm8994 = dev_get_drvdata(codec->dev->parent); - wm8994->pdata = dev_get_platdata(codec->dev->parent); wm8994->codec = codec; mutex_init(&wm8994->accdet_lock); @@ -3392,12 +3606,20 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) WM8994_IRQ_MIC1_DET; pm_runtime_enable(codec->dev); - pm_runtime_resume(codec->dev); + pm_runtime_idle(codec->dev); + + /* By default use idle_bias_off, will override for WM8994 */ + codec->dapm.idle_bias_off = 1; /* Set revision-specific configuration */ wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION); switch (control->type) { case WM8994: + /* Single ended line outputs should have VMID on. */ + if (!wm8994->pdata->lineout1_diff || + !wm8994->pdata->lineout2_diff) + codec->dapm.idle_bias_off = 0; + switch (wm8994->revision) { case 2: case 3: @@ -3415,11 +3637,14 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) case WM8958: wm8994->hubs.dcs_readback_mode = 1; + wm8994->hubs.hp_startup_mode = 1; break; case WM1811: wm8994->hubs.dcs_readback_mode = 2; wm8994->hubs.no_series_update = 1; + wm8994->hubs.hp_startup_mode = 1; + wm8994->hubs.no_cache_class_w = true; switch (wm8994->revision) { case 0: @@ -3536,6 +3761,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->fll_locked_irq = false; } + /* Make sure we can read from the GPIOs if they're inputs */ + pm_runtime_get_sync(codec->dev); + /* Remember if AIFnLRCLK is configured as a GPIO. This should be * configured on init - if a system wants to do this dynamically * at runtime we can deal with that then. @@ -3564,7 +3792,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->lrclk_shared[1] = 0; } - wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + pm_runtime_put(codec->dev); /* Latch volume updates (right only; we always do left then right). */ snd_soc_update_bits(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, @@ -3642,7 +3870,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994_handle_pdata(wm8994); wm_hubs_add_analogue_controls(codec); - snd_soc_add_controls(codec, wm8994_snd_controls, + snd_soc_add_codec_controls(codec, wm8994_snd_controls, ARRAY_SIZE(wm8994_snd_controls)); snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets, ARRAY_SIZE(wm8994_dapm_widgets)); @@ -3668,7 +3896,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) } break; case WM8958: - snd_soc_add_controls(codec, wm8958_snd_controls, + snd_soc_add_codec_controls(codec, wm8958_snd_controls, ARRAY_SIZE(wm8958_snd_controls)); snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets, ARRAY_SIZE(wm8958_dapm_widgets)); @@ -3690,7 +3918,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) break; case WM1811: - snd_soc_add_controls(codec, wm8958_snd_controls, + snd_soc_add_codec_controls(codec, wm8958_snd_controls, ARRAY_SIZE(wm8958_snd_controls)); snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets, ARRAY_SIZE(wm8958_dapm_widgets)); @@ -3819,24 +4047,27 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) return 0; } -static int wm8994_soc_volatile(struct snd_soc_codec *codec, - unsigned int reg) -{ - return true; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8994 = { .probe = wm8994_codec_probe, .remove = wm8994_codec_remove, - .suspend = wm8994_suspend, - .resume = wm8994_resume, + .suspend = wm8994_codec_suspend, + .resume = wm8994_codec_resume, .set_bias_level = wm8994_set_bias_level, - .reg_cache_size = WM8994_MAX_REGISTER, - .volatile_register = wm8994_soc_volatile, }; static int __devinit wm8994_probe(struct platform_device *pdev) { + struct wm8994_priv *wm8994; + + wm8994 = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_priv), + GFP_KERNEL); + if (wm8994 == NULL) + return -ENOMEM; + platform_set_drvdata(pdev, wm8994); + + wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); + wm8994->pdata = dev_get_platdata(pdev->dev.parent); + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994, wm8994_dai, ARRAY_SIZE(wm8994_dai)); } @@ -3847,11 +4078,43 @@ static int __devexit wm8994_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int wm8994_suspend(struct device *dev) +{ + struct wm8994_priv *wm8994 = dev_get_drvdata(dev); + + /* Drop down to power saving mode when system is suspended */ + if (wm8994->jackdet && !wm8994->active_refcount) + regmap_update_bits(wm8994->wm8994->regmap, WM8994_ANTIPOP_2, + WM1811_JACKDET_MODE_MASK, + wm8994->jackdet_mode); + + return 0; +} + +static int wm8994_resume(struct device *dev) +{ + struct wm8994_priv *wm8994 = dev_get_drvdata(dev); + + if (wm8994->jackdet && wm8994->jack_cb) + regmap_update_bits(wm8994->wm8994->regmap, WM8994_ANTIPOP_2, + WM1811_JACKDET_MODE_MASK, + WM1811_JACKDET_MODE_AUDIO); + + return 0; +} +#endif + +static const struct dev_pm_ops wm8994_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(wm8994_suspend, wm8994_resume) +}; + static struct platform_driver wm8994_codec_driver = { .driver = { - .name = "wm8994-codec", - .owner = THIS_MODULE, - }, + .name = "wm8994-codec", + .owner = THIS_MODULE, + .pm = &wm8994_pm_ops, + }, .probe = wm8994_probe, .remove = __devexit_p(wm8994_remove), }; diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index c3a42474ab1..c724112998d 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -32,13 +32,20 @@ #define WM8994_FLL_SRC_LRCLK 3 #define WM8994_FLL_SRC_BCLK 4 +enum wm8994_vmid_mode { + WM8994_VMID_NORMAL, + WM8994_VMID_FORCE, +}; + typedef void (*wm8958_micdet_cb)(u16 status, void *data); int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, - int micbias, int det, int shrt); + int micbias); int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, wm8958_micdet_cb cb, void *cb_data); +int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode); + int wm8958_aif_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); @@ -46,8 +53,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec); struct wm8994_micdet { struct snd_soc_jack *jack; - int det; - int shrt; + bool detecting; }; /* codec private data */ @@ -76,6 +82,7 @@ struct wm8994_priv { int vmid_refcount; int active_refcount; + enum wm8994_vmid_mode vmid_mode; int dac_rates[2]; int lrclk_shared[2]; @@ -123,6 +130,7 @@ struct wm8994_priv { bool jack_mic; int btn_mask; bool jackdet; + int jackdet_mode; wm8958_micdet_cb jack_cb; void *jack_cb_data; diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index c8aada597d7..28c89b094c6 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2047,7 +2047,6 @@ static int wm8995_probe(struct snd_soc_codec *codec) int i; int ret; - codec->dapm.idle_bias_off = 1; wm8995 = snd_soc_codec_get_drvdata(codec); wm8995->codec = codec; @@ -2137,7 +2136,7 @@ static int wm8995_probe(struct snd_soc_codec *codec) wm8995_update_class_w(codec); - snd_soc_add_controls(codec, wm8995_snd_controls, + snd_soc_add_codec_controls(codec, wm8995_snd_controls, ARRAY_SIZE(wm8995_snd_controls)); snd_soc_dapm_new_controls(&codec->dapm, wm8995_dapm_widgets, ARRAY_SIZE(wm8995_dapm_widgets)); @@ -2241,6 +2240,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { .suspend = wm8995_suspend, .resume = wm8995_resume, .set_bias_level = wm8995_set_bias_level, + .idle_bias_off = true, }; static struct regmap_config wm8995_regmap = { diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 61f7daa4d0e..1fd63549404 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -73,7 +73,6 @@ struct wm8996_priv { struct regulator_bulk_data supplies[WM8996_NUM_SUPPLIES]; struct notifier_block disable_nb[WM8996_NUM_SUPPLIES]; - struct regulator *cpvdd; int bg_ena; struct wm8996_pdata pdata; @@ -90,6 +89,7 @@ struct wm8996_priv { struct snd_soc_jack *jack; bool detecting; bool jack_mic; + int jack_flips; wm8996_polarity_fn polarity_cb; #ifdef CONFIG_GPIOLIB @@ -118,7 +118,6 @@ WM8996_REGULATOR_EVENT(1) WM8996_REGULATOR_EVENT(2) static struct reg_default wm8996_reg[] = { - { WM8996_SOFTWARE_RESET, 0x8996 }, { WM8996_POWER_MANAGEMENT_1, 0x0 }, { WM8996_POWER_MANAGEMENT_2, 0x0 }, { WM8996_POWER_MANAGEMENT_3, 0x0 }, @@ -153,7 +152,6 @@ static struct reg_default wm8996_reg[] = { { WM8996_CHARGE_PUMP_1, 0x1f25 }, { WM8996_CHARGE_PUMP_2, 0xab19 }, { WM8996_DC_SERVO_1, 0x0 }, - { WM8996_DC_SERVO_2, 0x0 }, { WM8996_DC_SERVO_3, 0x0 }, { WM8996_DC_SERVO_5, 0x2a2a }, { WM8996_DC_SERVO_6, 0x0 }, @@ -716,10 +714,16 @@ SOC_SINGLE("DSP2 EQ Switch", WM8996_DSP2_RX_EQ_GAINS_1, 0, 1, 0), SOC_SINGLE("DSP1 DRC TXL Switch", WM8996_DSP1_DRC_1, 0, 1, 0), SOC_SINGLE("DSP1 DRC TXR Switch", WM8996_DSP1_DRC_1, 1, 1, 0), SOC_SINGLE("DSP1 DRC RX Switch", WM8996_DSP1_DRC_1, 2, 1, 0), +SND_SOC_BYTES_MASK("DSP1 DRC", WM8996_DSP1_DRC_1, 5, + WM8996_DSP1RX_DRC_ENA | WM8996_DSP1TXL_DRC_ENA | + WM8996_DSP1TXR_DRC_ENA), SOC_SINGLE("DSP2 DRC TXL Switch", WM8996_DSP2_DRC_1, 0, 1, 0), SOC_SINGLE("DSP2 DRC TXR Switch", WM8996_DSP2_DRC_1, 1, 1, 0), SOC_SINGLE("DSP2 DRC RX Switch", WM8996_DSP2_DRC_1, 2, 1, 0), +SND_SOC_BYTES_MASK("DSP2 DRC", WM8996_DSP2_DRC_1, 5, + WM8996_DSP2RX_DRC_ENA | WM8996_DSP2TXL_DRC_ENA | + WM8996_DSP2TXR_DRC_ENA), }; static const struct snd_kcontrol_new wm8996_eq_controls[] = { @@ -792,29 +796,18 @@ static int bg_event(struct snd_soc_dapm_widget *w, static int cp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; - struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); int ret = 0; switch (event) { - case SND_SOC_DAPM_PRE_PMU: - ret = regulator_enable(wm8996->cpvdd); - if (ret != 0) - dev_err(codec->dev, "Failed to enable CPVDD: %d\n", - ret); - break; case SND_SOC_DAPM_POST_PMU: msleep(5); break; - case SND_SOC_DAPM_POST_PMD: - regulator_disable_deferred(wm8996->cpvdd, 20); - break; default: BUG(); ret = -EINVAL; } - return ret; + return 0; } static int rmv_short_event(struct snd_soc_dapm_widget *w, @@ -897,8 +890,8 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm, val = 0; mask = 0; if (wm8996->hpout_pending & HPOUT1L) { - val |= WM8996_HPOUT1L_RMV_SHORT; - mask |= WM8996_HPOUT1L_RMV_SHORT; + val |= WM8996_HPOUT1L_RMV_SHORT | WM8996_HPOUT1L_OUTP; + mask |= WM8996_HPOUT1L_RMV_SHORT | WM8996_HPOUT1L_OUTP; } else { mask |= WM8996_HPOUT1L_RMV_SHORT | WM8996_HPOUT1L_OUTP | @@ -906,8 +899,8 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm, } if (wm8996->hpout_pending & HPOUT1R) { - val |= WM8996_HPOUT1R_RMV_SHORT; - mask |= WM8996_HPOUT1R_RMV_SHORT; + val |= WM8996_HPOUT1R_RMV_SHORT | WM8996_HPOUT1R_OUTP; + mask |= WM8996_HPOUT1R_RMV_SHORT | WM8996_HPOUT1R_OUTP; } else { mask |= WM8996_HPOUT1R_RMV_SHORT | WM8996_HPOUT1R_OUTP | @@ -919,8 +912,8 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm, val = 0; mask = 0; if (wm8996->hpout_pending & HPOUT2L) { - val |= WM8996_HPOUT2L_RMV_SHORT; - mask |= WM8996_HPOUT2L_RMV_SHORT; + val |= WM8996_HPOUT2L_RMV_SHORT | WM8996_HPOUT2L_OUTP; + mask |= WM8996_HPOUT2L_RMV_SHORT | WM8996_HPOUT2L_OUTP; } else { mask |= WM8996_HPOUT2L_RMV_SHORT | WM8996_HPOUT2L_OUTP | @@ -928,8 +921,8 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm, } if (wm8996->hpout_pending & HPOUT2R) { - val |= WM8996_HPOUT2R_RMV_SHORT; - mask |= WM8996_HPOUT2R_RMV_SHORT; + val |= WM8996_HPOUT2R_RMV_SHORT | WM8996_HPOUT2R_OUTP; + mask |= WM8996_HPOUT2R_RMV_SHORT | WM8996_HPOUT2R_OUTP; } else { mask |= WM8996_HPOUT2R_RMV_SHORT | WM8996_HPOUT2R_OUTP | @@ -1116,12 +1109,12 @@ SND_SOC_DAPM_INPUT("IN2RP"), SND_SOC_DAPM_INPUT("DMIC1DAT"), SND_SOC_DAPM_INPUT("DMIC2DAT"), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8996_CHARGE_PUMP_1, 15, 0, cp_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("Bandgap", SND_SOC_NOPM, 0, 0, bg_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("LDO2", WM8996_POWER_MANAGEMENT_2, 1, 0, NULL, 0), @@ -1180,41 +1173,25 @@ SND_SOC_DAPM_DAC("DAC2R", NULL, WM8996_POWER_MANAGEMENT_5, 2, 0), SND_SOC_DAPM_DAC("DAC1L", NULL, WM8996_POWER_MANAGEMENT_5, 1, 0), SND_SOC_DAPM_DAC("DAC1R", NULL, WM8996_POWER_MANAGEMENT_5, 0, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 0, - WM8996_POWER_MANAGEMENT_4, 9, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 1, - WM8996_POWER_MANAGEMENT_4, 8, 0), - -SND_SOC_DAPM_AIF_OUT("AIF2TX1", "AIF2 Capture", 0, - WM8996_POWER_MANAGEMENT_6, 9, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX0", "AIF2 Capture", 1, - WM8996_POWER_MANAGEMENT_6, 8, 0), - -SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5, - WM8996_POWER_MANAGEMENT_4, 5, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4, - WM8996_POWER_MANAGEMENT_4, 4, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3, - WM8996_POWER_MANAGEMENT_4, 3, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2, - WM8996_POWER_MANAGEMENT_4, 2, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1, - WM8996_POWER_MANAGEMENT_4, 1, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0, - WM8996_POWER_MANAGEMENT_4, 0, 0), - -SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5, - WM8996_POWER_MANAGEMENT_6, 5, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4, - WM8996_POWER_MANAGEMENT_6, 4, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3, - WM8996_POWER_MANAGEMENT_6, 3, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2, - WM8996_POWER_MANAGEMENT_6, 2, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1, - WM8996_POWER_MANAGEMENT_6, 1, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0, - WM8996_POWER_MANAGEMENT_6, 0, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, WM8996_POWER_MANAGEMENT_4, 9, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX0", NULL, 1, WM8996_POWER_MANAGEMENT_4, 8, 0), + +SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, WM8996_POWER_MANAGEMENT_6, 9, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX0", NULL, 1, WM8996_POWER_MANAGEMENT_6, 8, 0), + +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 5, WM8996_POWER_MANAGEMENT_4, 5, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 4, WM8996_POWER_MANAGEMENT_4, 4, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 3, WM8996_POWER_MANAGEMENT_4, 3, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 2, WM8996_POWER_MANAGEMENT_4, 2, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 1, WM8996_POWER_MANAGEMENT_4, 1, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX0", NULL, 0, WM8996_POWER_MANAGEMENT_4, 0, 0), + +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 5, WM8996_POWER_MANAGEMENT_6, 5, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 4, WM8996_POWER_MANAGEMENT_6, 4, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 3, WM8996_POWER_MANAGEMENT_6, 3, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 2, WM8996_POWER_MANAGEMENT_6, 2, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 1, WM8996_POWER_MANAGEMENT_6, 1, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX0", NULL, 0, WM8996_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 */ @@ -1237,7 +1214,6 @@ SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8996_POWER_MANAGEMENT_1, 7, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8996_ANALOGUE_HP_2, 5, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8996_DC_SERVO_1, 2, 0, dcs_start, SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8996_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), @@ -1246,7 +1222,6 @@ SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8996_POWER_MANAGEMENT_1, 6, 0,NULL, 0), SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8996_ANALOGUE_HP_2, 1, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8996_DC_SERVO_1, 3, 0, dcs_start, SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8996_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), @@ -1255,7 +1230,6 @@ SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8996_POWER_MANAGEMENT_1, 5, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8996_ANALOGUE_HP_1, 5, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8996_DC_SERVO_1, 0, 0, dcs_start, SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8996_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), @@ -1264,7 +1238,6 @@ SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8996_POWER_MANAGEMENT_1, 4, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8996_ANALOGUE_HP_1, 1, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8996_DC_SERVO_1, 1, 0, dcs_start, SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8996_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), @@ -1280,6 +1253,7 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = { { "AIFCLK", NULL, "SYSCLK" }, { "SYSDSPCLK", NULL, "SYSCLK" }, { "Charge Pump", NULL, "SYSCLK" }, + { "Charge Pump", NULL, "CPVDD" }, { "MICB1", NULL, "LDO2" }, { "MICB1", NULL, "MICB1 Audio" }, @@ -1288,6 +1262,26 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = { { "MICB2", NULL, "MICB2 Audio" }, { "MICB2", NULL, "Bandgap" }, + { "AIF1RX0", NULL, "AIF1 Playback" }, + { "AIF1RX1", NULL, "AIF1 Playback" }, + { "AIF1RX2", NULL, "AIF1 Playback" }, + { "AIF1RX3", NULL, "AIF1 Playback" }, + { "AIF1RX4", NULL, "AIF1 Playback" }, + { "AIF1RX5", NULL, "AIF1 Playback" }, + + { "AIF2RX0", NULL, "AIF2 Playback" }, + { "AIF2RX1", NULL, "AIF2 Playback" }, + + { "AIF1 Capture", NULL, "AIF1TX0" }, + { "AIF1 Capture", NULL, "AIF1TX1" }, + { "AIF1 Capture", NULL, "AIF1TX2" }, + { "AIF1 Capture", NULL, "AIF1TX3" }, + { "AIF1 Capture", NULL, "AIF1TX4" }, + { "AIF1 Capture", NULL, "AIF1TX5" }, + + { "AIF2 Capture", NULL, "AIF2TX0" }, + { "AIF2 Capture", NULL, "AIF2TX1" }, + { "IN1L PGA", NULL, "IN2LN" }, { "IN1L PGA", NULL, "IN2LP" }, { "IN1L PGA", NULL, "IN1LN" }, @@ -1436,32 +1430,28 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = { { "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" }, + { "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_DCS" }, { "HPOUT2R PGA", NULL, "Charge Pump" }, { "HPOUT2R PGA", NULL, "Bandgap" }, { "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" }, + { "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_DCS" }, { "HPOUT1L PGA", NULL, "Charge Pump" }, { "HPOUT1L PGA", NULL, "Bandgap" }, { "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" }, + { "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_DCS" }, { "HPOUT1R PGA", NULL, "Charge Pump" }, { "HPOUT1R PGA", NULL, "Bandgap" }, { "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" }, + { "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_DCS" }, { "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" }, { "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" }, @@ -1720,6 +1710,7 @@ static int wm8996_reset(struct wm8996_priv *wm8996) { if (wm8996->pdata.ldo_ena > 0) { gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); + gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1); return 0; } else { return regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET, @@ -1923,7 +1914,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); - int bits, i, bclk_rate; + int bits, i, bclk_rate, best; int aifdata = 0; int lrclk = 0; int dsp = 0; @@ -1972,14 +1963,11 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream, return bits; aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits; + best = 0; 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; + if (abs(dsp_divs[i] - params_rate(params)) < + abs(dsp_divs[best] - params_rate(params))) + best = i; } dsp |= i << dsp_shift; @@ -2039,13 +2027,16 @@ static int wm8996_set_sysclk(struct snd_soc_dai *dai, } switch (wm8996->sysclk) { + case 5644800: case 6144000: snd_soc_update_bits(codec, WM8996_AIF_RATE, WM8996_SYSCLK_RATE, 0); break; + case 22579200: case 24576000: ratediv = WM8996_SYSCLK_DIV; wm8996->sysclk /= 2; + case 11289600: case 12288000: snd_soc_update_bits(codec, WM8996_AIF_RATE, WM8996_SYSCLK_RATE, WM8996_SYSCLK_RATE); @@ -2438,6 +2429,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, wm8996->jack = jack; wm8996->detecting = true; wm8996->polarity_cb = polarity_cb; + wm8996->jack_flips = 0; if (wm8996->polarity_cb) wm8996->polarity_cb(codec, 0); @@ -2553,6 +2545,19 @@ static void wm8996_hpdet_start(struct snd_soc_codec *codec) WM8996_HP_POLL, WM8996_HP_POLL); } +static void wm8996_report_headphone(struct snd_soc_codec *codec) +{ + dev_dbg(codec->dev, "Headphone detected\n"); + wm8996_hpdet_start(codec); + + /* Increase the detection rate a bit for responsiveness. */ + snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, + WM8996_MICD_RATE_MASK | + WM8996_MICD_BIAS_STARTTIME_MASK, + 7 << WM8996_MICD_RATE_SHIFT | + 7 << WM8996_MICD_BIAS_STARTTIME_SHIFT); +} + static void wm8996_micd(struct snd_soc_codec *codec) { struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); @@ -2572,6 +2577,7 @@ static void wm8996_micd(struct snd_soc_codec *codec) dev_dbg(codec->dev, "Jack removal detected\n"); wm8996->jack_mic = false; wm8996->detecting = true; + wm8996->jack_flips = 0; snd_soc_jack_report(wm8996->jack, 0, SND_JACK_LINEOUT | SND_JACK_HEADSET | SND_JACK_BTN_0); @@ -2612,9 +2618,17 @@ static void wm8996_micd(struct snd_soc_codec *codec) /* 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. + * plain headphones. If both polarities report a low + * impedence then give up and report headphones. */ if (wm8996->detecting && (val & 0x3f0)) { + wm8996->jack_flips++; + + if (wm8996->jack_flips > 1) { + wm8996_report_headphone(codec); + return; + } + reg = snd_soc_read(codec, WM8996_ACCESSORY_DETECT_MODE_2); reg ^= WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC | WM8996_MICD_BIAS_SRC; @@ -2641,17 +2655,7 @@ static void wm8996_micd(struct snd_soc_codec *codec) snd_soc_jack_report(wm8996->jack, SND_JACK_BTN_0, SND_JACK_BTN_0); } else if (wm8996->detecting) { - dev_dbg(codec->dev, "Headphone detected\n"); - wm8996_hpdet_start(codec); - - /* Increase the detection rate a bit for - * responsiveness. - */ - snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, - WM8996_MICD_RATE_MASK | - WM8996_MICD_BIAS_STARTTIME_MASK, - 7 << WM8996_MICD_RATE_SHIFT | - 7 << WM8996_MICD_BIAS_STARTTIME_SHIFT); + wm8996_report_headphone(codec); } } } @@ -2768,7 +2772,7 @@ static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec) wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts; wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts; - ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls)); + ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); if (ret != 0) dev_err(codec->dev, "Failed to add ReTune Mobile controls: %d\n", ret); @@ -2791,7 +2795,6 @@ static int wm8996_probe(struct snd_soc_codec *codec) int ret; struct wm8996_priv *wm8996 = 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; wm8996->codec = codec; @@ -2799,8 +2802,6 @@ static int wm8996_probe(struct snd_soc_codec *codec) init_completion(&wm8996->dcs_done); init_completion(&wm8996->fll_lock); - dapm->idle_bias_off = true; - codec->control_data = wm8996->regmap; ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); @@ -2966,7 +2967,7 @@ static int wm8996_probe(struct snd_soc_codec *codec) if (wm8996->pdata.num_retune_mobile_cfgs) wm8996_retune_mobile_pdata(codec); else - snd_soc_add_controls(codec, wm8996_eq_controls, + snd_soc_add_codec_controls(codec, wm8996_eq_controls, ARRAY_SIZE(wm8996_eq_controls)); /* If the TX LRCLK pins are not in LRCLK mode configure the @@ -3038,22 +3039,16 @@ static int wm8996_remove(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) regulator_unregister_notifier(wm8996->supplies[i].consumer, &wm8996->disable_nb[i]); - regulator_put(wm8996->cpvdd); regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); return 0; } -static int wm8996_soc_volatile_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - return true; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8996 = { .probe = wm8996_probe, .remove = wm8996_remove, .set_bias_level = wm8996_set_bias_level, + .idle_bias_off = true, .seq_notifier = wm8996_seq_notifier, .controls = wm8996_snd_controls, .num_controls = ARRAY_SIZE(wm8996_snd_controls), @@ -3062,12 +3057,11 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8996 = { .dapm_routes = wm8996_dapm_routes, .num_dapm_routes = ARRAY_SIZE(wm8996_dapm_routes), .set_pll = wm8996_set_fll, - .reg_cache_size = WM8996_MAX_REGISTER, - .volatile_register = wm8996_soc_volatile_register, }; #define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ - SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000) + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000) #define WM8996_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) @@ -3087,6 +3081,7 @@ static struct snd_soc_dai_driver wm8996_dai[] = { .channels_max = 6, .rates = WM8996_RATES, .formats = WM8996_FORMATS, + .sig_bits = 24, }, .capture = { .stream_name = "AIF1 Capture", @@ -3094,6 +3089,7 @@ static struct snd_soc_dai_driver wm8996_dai[] = { .channels_max = 6, .rates = WM8996_RATES, .formats = WM8996_FORMATS, + .sig_bits = 24, }, .ops = &wm8996_dai_ops, }, @@ -3105,6 +3101,7 @@ static struct snd_soc_dai_driver wm8996_dai[] = { .channels_max = 2, .rates = WM8996_RATES, .formats = WM8996_FORMATS, + .sig_bits = 24, }, .capture = { .stream_name = "AIF2 Capture", @@ -3112,6 +3109,7 @@ static struct snd_soc_dai_driver wm8996_dai[] = { .channels_max = 2, .rates = WM8996_RATES, .formats = WM8996_FORMATS, + .sig_bits = 24, }, .ops = &wm8996_dai_ops, }, @@ -3149,25 +3147,18 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) wm8996->supplies[i].supply = wm8996_supply_names[i]; - ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8996->supplies), - wm8996->supplies); + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8996->supplies), + wm8996->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); goto err_gpio; } - wm8996->cpvdd = regulator_get(&i2c->dev, "CPVDD"); - if (IS_ERR(wm8996->cpvdd)) { - ret = PTR_ERR(wm8996->cpvdd); - dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret); - goto err_get; - } - ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); - goto err_cpvdd; + goto err_gpio; } if (wm8996->pdata.ldo_ena > 0) { @@ -3188,7 +3179,7 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c, goto err_regmap; } if (reg != 0x8915) { - dev_err(&i2c->dev, "Device is not a WM8996, ID %x\n", ret); + dev_err(&i2c->dev, "Device is not a WM8996, ID %x\n", reg); ret = -EINVAL; goto err_regmap; } @@ -3229,10 +3220,6 @@ err_enable: if (wm8996->pdata.ldo_ena > 0) gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); -err_cpvdd: - regulator_put(wm8996->cpvdd); -err_get: - regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); err_gpio: if (wm8996->pdata.ldo_ena > 0) gpio_free(wm8996->pdata.ldo_ena); @@ -3247,8 +3234,6 @@ static __devexit int wm8996_i2c_remove(struct i2c_client *client) snd_soc_unregister_codec(&client->dev); wm8996_free_gpio(wm8996); - regulator_put(wm8996->cpvdd); - regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); regmap_exit(wm8996->regmap); if (wm8996->pdata.ldo_ena > 0) { gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); @@ -3273,25 +3258,7 @@ static struct i2c_driver wm8996_i2c_driver = { .id_table = wm8996_i2c_id, }; -static int __init wm8996_modinit(void) -{ - int ret; - - ret = i2c_add_driver(&wm8996_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8996 I2C driver: %d\n", - ret); - } - - return ret; -} -module_init(wm8996_modinit); - -static void __exit wm8996_exit(void) -{ - i2c_del_driver(&wm8996_i2c_driver); -} -module_exit(wm8996_exit); +module_i2c_driver(wm8996_i2c_driver); MODULE_DESCRIPTION("ASoC WM8996 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index a6bab392700..076c126ed9b 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -824,6 +824,8 @@ static const struct snd_soc_dapm_route wm9081_audio_paths[] = { static int wm9081_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); + switch (level) { case SND_SOC_BIAS_ON: break; @@ -841,6 +843,9 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: /* Initial cold start */ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + regcache_cache_only(wm9081->regmap, false); + regcache_sync(wm9081->regmap); + /* Disable LINEOUT discharge */ snd_soc_update_bits(codec, WM9081_ANTI_POP_CONTROL, WM9081_LINEOUT_DISCH, 0); @@ -892,6 +897,8 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, WM9081_ANTI_POP_CONTROL, WM9081_LINEOUT_DISCH, WM9081_LINEOUT_DISCH); + + regcache_cache_only(wm9081->regmap, true); break; } @@ -1258,7 +1265,6 @@ static int wm9081_probe(struct snd_soc_codec *codec) { struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); int ret; - u16 reg; codec->control_data = wm9081->regmap; @@ -1268,16 +1274,6 @@ static int wm9081_probe(struct snd_soc_codec *codec) return ret; } - reg = 0; - if (wm9081->pdata.irq_high) - reg |= WM9081_IRQ_POL; - if (!wm9081->pdata.irq_cmos) - reg |= WM9081_IRQ_OP_CTRL; - snd_soc_update_bits(codec, WM9081_INTERRUPT_CONTROL, - WM9081_IRQ_POL | WM9081_IRQ_OP_CTRL, reg); - - wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Enable zero cross by default */ snd_soc_update_bits(codec, WM9081_ANALOGUE_LINEOUT, WM9081_LINEOUTZC, WM9081_LINEOUTZC); @@ -1287,7 +1283,7 @@ static int wm9081_probe(struct snd_soc_codec *codec) if (!wm9081->pdata.num_retune_configs) { dev_dbg(codec->dev, "No ReTune Mobile data, using normal EQ\n"); - snd_soc_add_controls(codec, wm9081_eq_controls, + snd_soc_add_codec_controls(codec, wm9081_eq_controls, ARRAY_SIZE(wm9081_eq_controls)); } @@ -1300,38 +1296,15 @@ static int wm9081_remove(struct snd_soc_codec *codec) return 0; } -#ifdef CONFIG_PM -static int wm9081_suspend(struct snd_soc_codec *codec) -{ - wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm9081_resume(struct snd_soc_codec *codec) -{ - struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); - - regcache_sync(wm9081->regmap); - - wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define wm9081_suspend NULL -#define wm9081_resume NULL -#endif - static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { .probe = wm9081_probe, .remove = wm9081_remove, - .suspend = wm9081_suspend, - .resume = wm9081_resume, .set_sysclk = wm9081_set_sysclk, .set_bias_level = wm9081_set_bias_level, + .idle_bias_off = true, + .controls = wm9081_snd_controls, .num_controls = ARRAY_SIZE(wm9081_snd_controls), .dapm_widgets = wm9081_dapm_widgets, @@ -1395,6 +1368,16 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, memcpy(&wm9081->pdata, dev_get_platdata(&i2c->dev), sizeof(wm9081->pdata)); + reg = 0; + if (wm9081->pdata.irq_high) + reg |= WM9081_IRQ_POL; + if (!wm9081->pdata.irq_cmos) + reg |= WM9081_IRQ_OP_CTRL; + regmap_update_bits(wm9081->regmap, WM9081_INTERRUPT_CONTROL, + WM9081_IRQ_POL | WM9081_IRQ_OP_CTRL, reg); + + regcache_cache_only(wm9081->regmap, true); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm9081, &wm9081_dai, 1); if (ret < 0) @@ -1435,28 +1418,7 @@ static struct i2c_driver wm9081_i2c_driver = { }; #endif -static int __init wm9081_modinit(void) -{ - int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&wm9081_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(wm9081_modinit); - -static void __exit wm9081_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm9081_i2c_driver); -#endif -} -module_exit(wm9081_exit); - +module_i2c_driver(wm9081_i2c_driver); MODULE_DESCRIPTION("ASoC WM9081 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 41ebe0dce77..4b263b6edf1 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -25,6 +25,7 @@ #include <linux/device.h> #include <linux/i2c.h> #include <linux/delay.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/initval.h> #include <sound/soc.h> @@ -33,116 +34,51 @@ #include "wm9090.h" -static const u16 wm9090_reg_defaults[] = { - 0x9093, /* R0 - Software Reset */ - 0x0006, /* R1 - Power Management (1) */ - 0x6000, /* R2 - Power Management (2) */ - 0x0000, /* R3 - Power Management (3) */ - 0x0000, /* R4 */ - 0x0000, /* R5 */ - 0x01C0, /* R6 - Clocking 1 */ - 0x0000, /* R7 */ - 0x0000, /* R8 */ - 0x0000, /* R9 */ - 0x0000, /* R10 */ - 0x0000, /* R11 */ - 0x0000, /* R12 */ - 0x0000, /* R13 */ - 0x0000, /* R14 */ - 0x0000, /* R15 */ - 0x0000, /* R16 */ - 0x0000, /* R17 */ - 0x0000, /* R18 */ - 0x0000, /* R19 */ - 0x0000, /* R20 */ - 0x0000, /* R21 */ - 0x0003, /* R22 - IN1 Line Control */ - 0x0003, /* R23 - IN2 Line Control */ - 0x0083, /* R24 - IN1 Line Input A Volume */ - 0x0083, /* R25 - IN1 Line Input B Volume */ - 0x0083, /* R26 - IN2 Line Input A Volume */ - 0x0083, /* R27 - IN2 Line Input B Volume */ - 0x002D, /* R28 - Left Output Volume */ - 0x002D, /* R29 - Right Output Volume */ - 0x0000, /* R30 */ - 0x0000, /* R31 */ - 0x0000, /* R32 */ - 0x0000, /* R33 */ - 0x0100, /* R34 - SPKMIXL Attenuation */ - 0x0000, /* R35 */ - 0x0010, /* R36 - SPKOUT Mixers */ - 0x0140, /* R37 - ClassD3 */ - 0x0039, /* R38 - Speaker Volume Left */ - 0x0000, /* R39 */ - 0x0000, /* R40 */ - 0x0000, /* R41 */ - 0x0000, /* R42 */ - 0x0000, /* R43 */ - 0x0000, /* R44 */ - 0x0000, /* R45 - Output Mixer1 */ - 0x0000, /* R46 - Output Mixer2 */ - 0x0100, /* R47 - Output Mixer3 */ - 0x0100, /* R48 - Output Mixer4 */ - 0x0000, /* R49 */ - 0x0000, /* R50 */ - 0x0000, /* R51 */ - 0x0000, /* R52 */ - 0x0000, /* R53 */ - 0x0000, /* R54 - Speaker Mixer */ - 0x0000, /* R55 */ - 0x0000, /* R56 */ - 0x000D, /* R57 - AntiPOP2 */ - 0x0000, /* R58 */ - 0x0000, /* R59 */ - 0x0000, /* R60 */ - 0x0000, /* R61 */ - 0x0000, /* R62 */ - 0x0000, /* R63 */ - 0x0000, /* R64 */ - 0x0000, /* R65 */ - 0x0000, /* R66 */ - 0x0000, /* R67 */ - 0x0000, /* R68 */ - 0x0000, /* R69 */ - 0x0000, /* R70 - Write Sequencer 0 */ - 0x0000, /* R71 - Write Sequencer 1 */ - 0x0000, /* R72 - Write Sequencer 2 */ - 0x0000, /* R73 - Write Sequencer 3 */ - 0x0000, /* R74 - Write Sequencer 4 */ - 0x0000, /* R75 - Write Sequencer 5 */ - 0x1F25, /* R76 - Charge Pump 1 */ - 0x0000, /* R77 */ - 0x0000, /* R78 */ - 0x0000, /* R79 */ - 0x0000, /* R80 */ - 0x0000, /* R81 */ - 0x0000, /* R82 */ - 0x0000, /* R83 */ - 0x0000, /* R84 - DC Servo 0 */ - 0x054A, /* R85 - DC Servo 1 */ - 0x0000, /* R86 */ - 0x0000, /* R87 - DC Servo 3 */ - 0x0000, /* R88 - DC Servo Readback 0 */ - 0x0000, /* R89 - DC Servo Readback 1 */ - 0x0000, /* R90 - DC Servo Readback 2 */ - 0x0000, /* R91 */ - 0x0000, /* R92 */ - 0x0000, /* R93 */ - 0x0000, /* R94 */ - 0x0000, /* R95 */ - 0x0100, /* R96 - Analogue HP 0 */ - 0x0000, /* R97 */ - 0x8640, /* R98 - AGC Control 0 */ - 0xC000, /* R99 - AGC Control 1 */ - 0x0200, /* R100 - AGC Control 2 */ +static const struct reg_default wm9090_reg_defaults[] = { + { 1, 0x0006 }, /* R1 - Power Management (1) */ + { 2, 0x6000 }, /* R2 - Power Management (2) */ + { 3, 0x0000 }, /* R3 - Power Management (3) */ + { 6, 0x01C0 }, /* R6 - Clocking 1 */ + { 22, 0x0003 }, /* R22 - IN1 Line Control */ + { 23, 0x0003 }, /* R23 - IN2 Line Control */ + { 24, 0x0083 }, /* R24 - IN1 Line Input A Volume */ + { 25, 0x0083 }, /* R25 - IN1 Line Input B Volume */ + { 26, 0x0083 }, /* R26 - IN2 Line Input A Volume */ + { 27, 0x0083 }, /* R27 - IN2 Line Input B Volume */ + { 28, 0x002D }, /* R28 - Left Output Volume */ + { 29, 0x002D }, /* R29 - Right Output Volume */ + { 34, 0x0100 }, /* R34 - SPKMIXL Attenuation */ + { 35, 0x0010 }, /* R36 - SPKOUT Mixers */ + { 37, 0x0140 }, /* R37 - ClassD3 */ + { 38, 0x0039 }, /* R38 - Speaker Volume Left */ + { 45, 0x0000 }, /* R45 - Output Mixer1 */ + { 46, 0x0000 }, /* R46 - Output Mixer2 */ + { 47, 0x0100 }, /* R47 - Output Mixer3 */ + { 48, 0x0100 }, /* R48 - Output Mixer4 */ + { 54, 0x0000 }, /* R54 - Speaker Mixer */ + { 57, 0x000D }, /* R57 - AntiPOP2 */ + { 70, 0x0000 }, /* R70 - Write Sequencer 0 */ + { 71, 0x0000 }, /* R71 - Write Sequencer 1 */ + { 72, 0x0000 }, /* R72 - Write Sequencer 2 */ + { 73, 0x0000 }, /* R73 - Write Sequencer 3 */ + { 74, 0x0000 }, /* R74 - Write Sequencer 4 */ + { 75, 0x0000 }, /* R75 - Write Sequencer 5 */ + { 76, 0x1F25 }, /* R76 - Charge Pump 1 */ + { 85, 0x054A }, /* R85 - DC Servo 1 */ + { 87, 0x0000 }, /* R87 - DC Servo 3 */ + { 96, 0x0100 }, /* R96 - Analogue HP 0 */ + { 98, 0x8640 }, /* R98 - AGC Control 0 */ + { 99, 0xC000 }, /* R99 - AGC Control 1 */ + { 100, 0x0200 }, /* R100 - AGC Control 2 */ }; /* This struct is used to save the context */ struct wm9090_priv { struct wm9090_platform_data pdata; + struct regmap *regmap; }; -static int wm9090_volatile(struct snd_soc_codec *codec, unsigned int reg) +static bool wm9090_volatile(struct device *dev, unsigned int reg) { switch (reg) { case WM9090_SOFTWARE_RESET: @@ -150,10 +86,60 @@ static int wm9090_volatile(struct snd_soc_codec *codec, unsigned int reg) case WM9090_DC_SERVO_READBACK_0: case WM9090_DC_SERVO_READBACK_1: case WM9090_DC_SERVO_READBACK_2: - return 1; + return true; default: - return 0; + return false; + } +} + +static bool wm9090_readable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WM9090_SOFTWARE_RESET: + case WM9090_POWER_MANAGEMENT_1: + case WM9090_POWER_MANAGEMENT_2: + case WM9090_POWER_MANAGEMENT_3: + case WM9090_CLOCKING_1: + case WM9090_IN1_LINE_CONTROL: + case WM9090_IN2_LINE_CONTROL: + case WM9090_IN1_LINE_INPUT_A_VOLUME: + case WM9090_IN1_LINE_INPUT_B_VOLUME: + case WM9090_IN2_LINE_INPUT_A_VOLUME: + case WM9090_IN2_LINE_INPUT_B_VOLUME: + case WM9090_LEFT_OUTPUT_VOLUME: + case WM9090_RIGHT_OUTPUT_VOLUME: + case WM9090_SPKMIXL_ATTENUATION: + case WM9090_SPKOUT_MIXERS: + case WM9090_CLASSD3: + case WM9090_SPEAKER_VOLUME_LEFT: + case WM9090_OUTPUT_MIXER1: + case WM9090_OUTPUT_MIXER2: + case WM9090_OUTPUT_MIXER3: + case WM9090_OUTPUT_MIXER4: + case WM9090_SPEAKER_MIXER: + case WM9090_ANTIPOP2: + case WM9090_WRITE_SEQUENCER_0: + case WM9090_WRITE_SEQUENCER_1: + case WM9090_WRITE_SEQUENCER_2: + case WM9090_WRITE_SEQUENCER_3: + case WM9090_WRITE_SEQUENCER_4: + case WM9090_WRITE_SEQUENCER_5: + case WM9090_CHARGE_PUMP_1: + case WM9090_DC_SERVO_0: + case WM9090_DC_SERVO_1: + case WM9090_DC_SERVO_3: + case WM9090_DC_SERVO_READBACK_0: + case WM9090_DC_SERVO_READBACK_1: + case WM9090_DC_SERVO_READBACK_2: + case WM9090_ANALOGUE_HP_0: + case WM9090_AGC_CONTROL_0: + case WM9090_AGC_CONTROL_1: + case WM9090_AGC_CONTROL_2: + return true; + + default: + return false; } } @@ -447,7 +433,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_add_controls(codec, wm9090_controls, + snd_soc_add_codec_controls(codec, wm9090_controls, ARRAY_SIZE(wm9090_controls)); if (wm9090->pdata.lin1_diff) { @@ -456,7 +442,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec) } else { snd_soc_dapm_add_routes(dapm, audio_map_in1_se, ARRAY_SIZE(audio_map_in1_se)); - snd_soc_add_controls(codec, wm9090_in1_se_controls, + snd_soc_add_codec_controls(codec, wm9090_in1_se_controls, ARRAY_SIZE(wm9090_in1_se_controls)); } @@ -466,7 +452,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec) } else { snd_soc_dapm_add_routes(dapm, audio_map_in2_se, ARRAY_SIZE(audio_map_in2_se)); - snd_soc_add_controls(codec, wm9090_in2_se_controls, + snd_soc_add_codec_controls(codec, wm9090_in2_se_controls, ARRAY_SIZE(wm9090_in2_se_controls)); } @@ -492,8 +478,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec) static int wm9090_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 *reg_cache = codec->reg_cache; - int i, ret; + struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec); switch (level) { case SND_SOC_BIAS_ON: @@ -513,7 +498,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { /* Restore the register cache */ - snd_soc_cache_sync(codec); + regcache_sync(wm9090->regmap); } /* We keep VMID off during standby since the combination of @@ -537,26 +522,16 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, static int wm9090_probe(struct snd_soc_codec *codec) { + struct wm9090_priv *wm9090 = dev_get_drvdata(codec->dev); int ret; - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + codec->control_data = wm9090->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } - ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET); - if (ret < 0) - return ret; - if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) { - dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret); - return -EINVAL; - } - - ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0); - if (ret < 0) - return ret; - /* Configure some defaults; they will be written out when we * bring the bias up. */ @@ -624,16 +599,27 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9090 = { .suspend = wm9090_suspend, .resume = wm9090_resume, .set_bias_level = wm9090_set_bias_level, - .reg_cache_size = (WM9090_MAX_REGISTER + 1), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm9090_reg_defaults, - .volatile_register = wm9090_volatile, }; +static const struct regmap_config wm9090_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = WM9090_MAX_REGISTER, + .volatile_reg = wm9090_volatile, + .readable_reg = wm9090_readable, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm9090_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults), +}; + + static int wm9090_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm9090_priv *wm9090; + unsigned int reg; int ret; wm9090 = devm_kzalloc(&i2c->dev, sizeof(*wm9090), GFP_KERNEL); @@ -642,6 +628,26 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, return -ENOMEM; } + wm9090->regmap = regmap_init_i2c(i2c, &wm9090_regmap); + if (IS_ERR(wm9090->regmap)) { + ret = PTR_ERR(wm9090->regmap); + dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + + ret = regmap_read(wm9090->regmap, WM9090_SOFTWARE_RESET, ®); + if (ret < 0) + goto err; + if (reg != 0x9093) { + dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", reg); + ret = -ENODEV; + goto err; + } + + ret = regmap_write(wm9090->regmap, WM9090_SOFTWARE_RESET, 0); + if (ret < 0) + goto err; + if (i2c->dev.platform_data) memcpy(&wm9090->pdata, i2c->dev.platform_data, sizeof(wm9090->pdata)); @@ -650,6 +656,15 @@ static int wm9090_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm9090, NULL, 0); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + goto err; + } + + return 0; + +err: + regmap_exit(wm9090->regmap); return ret; } @@ -658,6 +673,7 @@ static int __devexit wm9090_i2c_remove(struct i2c_client *i2c) struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c); snd_soc_unregister_codec(&i2c->dev); + regmap_exit(wm9090->regmap); return 0; } diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 40c92ead85a..cacc6a86b46 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -351,7 +351,7 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec) if (ret) goto reset_err; - snd_soc_add_controls(codec, wm9705_snd_ac97_controls, + snd_soc_add_codec_controls(codec, wm9705_snd_ac97_controls, ARRAY_SIZE(wm9705_snd_ac97_controls)); return 0; diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index b7b31f84c10..b342ae50bcd 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -20,10 +20,9 @@ #include <sound/ac97_codec.h> #include <sound/initval.h> #include <sound/soc.h> +#include <sound/tlv.h> #include "wm9712.h" -#define WM9712_VERSION "0.4" - static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg); static int ac97_write(struct snd_soc_codec *codec, @@ -71,6 +70,9 @@ static const char *wm9712_rec_sel[] = {"Mic", "NC", "NC", "Speaker Mixer", static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"}; static const char *wm9712_diff_sel[] = {"Mic", "Line"}; +static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 2000, 0); + static const struct soc_enum wm9712_enum[] = { SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select), SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux), @@ -149,9 +151,9 @@ SOC_ENUM("Capture Volume Steps", wm9712_enum[6]), SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1), SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0), -SOC_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), -SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), -SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), +SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv), +SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv), +SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv), }; /* We have to create a fake left and right HP mixers because @@ -619,8 +621,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) { int ret = 0; - printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION); - ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); if (ret < 0) { printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); @@ -637,7 +637,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_controls(codec, wm9712_snd_ac97_controls, + snd_soc_add_codec_controls(codec, wm9712_snd_ac97_controls, ARRAY_SIZE(wm9712_snd_ac97_controls)); return 0; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 2b8479bfcd9..2d22cc70d53 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1216,7 +1216,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) reg = ac97_read(codec, AC97_CD) & 0x7fff; ac97_write(codec, AC97_CD, reg); - snd_soc_add_controls(codec, wm9713_snd_ac97_controls, + snd_soc_add_codec_controls(codec, wm9713_snd_ac97_controls, ARRAY_SIZE(wm9713_snd_ac97_controls)); return 0; diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 8a68cea4a3e..f13f2886339 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -172,7 +172,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) break; default: WARN(1, "Unknown DCS readback method\n"); - break; + return; } dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r); @@ -207,7 +207,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) /* Save the callibrated offset if we're in class W mode and * therefore don't have any analogue signal mixed in. */ - if (hubs->class_w) + if (hubs->class_w && !hubs->no_cache_class_w) hubs->class_w_dcs = dcs_cfg; } @@ -500,6 +500,36 @@ static int earpiece_event(struct snd_soc_dapm_widget *w, return 0; } +static int lineout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *control, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); + bool *flag; + + switch (w->shift) { + case WM8993_LINEOUT1N_ENA_SHIFT: + flag = &hubs->lineout1n_ena; + break; + case WM8993_LINEOUT1P_ENA_SHIFT: + flag = &hubs->lineout1p_ena; + break; + case WM8993_LINEOUT2N_ENA_SHIFT: + flag = &hubs->lineout2n_ena; + break; + case WM8993_LINEOUT2P_ENA_SHIFT: + flag = &hubs->lineout2p_ena; + break; + default: + WARN(1, "Unknown line output"); + return -EINVAL; + } + + *flag = SND_SOC_DAPM_EVENT_ON(event); + + return 0; +} + static const struct snd_kcontrol_new in1l_pga[] = { SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0), SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0), @@ -613,8 +643,6 @@ SND_SOC_DAPM_INPUT("IN2RP:VXRP"), SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0), - SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, in1l_pga, ARRAY_SIZE(in1l_pga)), SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, @@ -640,9 +668,8 @@ SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), -SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, - NULL, 0, - hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_OUT_DRV_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, earpiece_mixer, ARRAY_SIZE(earpiece_mixer)), @@ -656,10 +683,10 @@ SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0, right_speaker_boost, ARRAY_SIZE(right_speaker_boost)), SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0), -SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, - NULL, 0), -SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, - NULL, 0), +SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, + NULL, 0), +SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, + NULL, 0), SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, line1_mix, ARRAY_SIZE(line1_mix)), @@ -675,14 +702,18 @@ SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, line2p_mix, ARRAY_SIZE(line2p_mix)), -SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, - NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, - NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0, - NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, - NULL, 0), +SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, + NULL, 0, lineout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, + NULL, 0, lineout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0, + NULL, 0, lineout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, + NULL, 0, lineout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_OUTPUT("SPKOUTLP"), SND_SOC_DAPM_OUTPUT("SPKOUTLN"), @@ -836,11 +867,9 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout1_se_routes[] = { - { "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" }, - { "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, @@ -857,11 +886,9 @@ static const struct snd_soc_dapm_route lineout2_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout2_se_routes[] = { - { "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" }, - { "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, @@ -901,7 +928,7 @@ int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec) WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU, WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU); - snd_soc_add_controls(codec, analogue_snd_controls, + snd_soc_add_codec_controls(codec, analogue_snd_controls, ARRAY_SIZE(analogue_snd_controls)); snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets, @@ -949,6 +976,11 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, int jd_scthr, int jd_thr, int micbias1_lvl, int micbias2_lvl) { + struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); + + hubs->lineout1_se = !lineout1_diff; + hubs->lineout2_se = !lineout2_diff; + if (!lineout1_diff) snd_soc_update_bits(codec, WM8993_LINE_MIXER1, WM8993_LINEOUT1_MODE, @@ -958,11 +990,10 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, WM8993_LINEOUT2_MODE, WM8993_LINEOUT2_MODE); - /* If the line outputs are differential then we aren't presenting - * VMID as an output and can disable it. - */ - if (lineout1_diff && lineout2_diff) - codec->dapm.idle_bias_off = 1; + if (!lineout1_diff && !lineout2_diff) + snd_soc_update_bits(codec, WM8993_ANTIPOP1, + WM8993_LINEOUT_VMID_BUF_ENA, + WM8993_LINEOUT_VMID_BUF_ENA); if (lineout1fb) snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, @@ -984,6 +1015,69 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); +void wm_hubs_vmid_ena(struct snd_soc_codec *codec) +{ + struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); + int val = 0; + + if (hubs->lineout1_se) + val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA; + + if (hubs->lineout2_se) + val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA; + + /* Enable the line outputs while we power up */ + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, val, val); +} +EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena); + +void wm_hubs_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); + int val; + + switch (level) { + case SND_SOC_BIAS_STANDBY: + /* Clamp the inputs to VMID while we ramp to charge caps */ + snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG, + WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP); + break; + + case SND_SOC_BIAS_ON: + /* Turn off any unneded single ended outputs */ + val = 0; + + if (hubs->lineout1_se && hubs->lineout1n_ena) + val |= WM8993_LINEOUT1N_ENA; + + if (hubs->lineout1_se && hubs->lineout1p_ena) + val |= WM8993_LINEOUT1P_ENA; + + if (hubs->lineout2_se && hubs->lineout2n_ena) + val |= WM8993_LINEOUT2N_ENA; + + if (hubs->lineout2_se && hubs->lineout2p_ena) + val |= WM8993_LINEOUT2P_ENA; + + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, + WM8993_LINEOUT1N_ENA | + WM8993_LINEOUT1P_ENA | + WM8993_LINEOUT2N_ENA | + WM8993_LINEOUT2P_ENA, + val); + + /* Remove the input clamps */ + snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG, + WM8993_INPUTS_CLAMP, 0); + break; + + default: + break; + } +} +EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level); + MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index c674c7a502a..5705276f494 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h @@ -30,9 +30,18 @@ struct wm_hubs_data { int series_startup; int no_series_update; + bool no_cache_class_w; bool class_w; u16 class_w_dcs; + bool lineout1_se; + bool lineout1n_ena; + bool lineout1p_ena; + + bool lineout2_se; + bool lineout2n_ena; + bool lineout2p_ena; + bool dcs_done_irq; struct completion dcs_done; }; @@ -46,5 +55,8 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *, int micbias1_lvl, int micbias2_lvl); extern irqreturn_t wm_hubs_dcs_done(int irq, void *data); +extern void wm_hubs_vmid_ena(struct snd_soc_codec *codec); +extern void wm_hubs_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level); #endif diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index b26401f87b8..97d77b29896 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -826,7 +826,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm) } } -static u64 davinci_pcm_dmamask = 0xffffffff; +static u64 davinci_pcm_dmamask = DMA_BIT_MASK(32); static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd) { @@ -837,7 +837,7 @@ static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!card->dev->dma_mask) card->dev->dma_mask = &davinci_pcm_dmamask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = davinci_pcm_preallocate_dma_buffer(pcm, diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig index 91a28de9410..88143db7e75 100644 --- a/sound/soc/ep93xx/Kconfig +++ b/sound/soc/ep93xx/Kconfig @@ -1,6 +1,7 @@ config SND_EP93XX_SOC tristate "SoC Audio support for the Cirrus Logic EP93xx series" depends on ARCH_EP93XX && SND_SOC + select SND_SOC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to the EP93xx I2S or AC97 interfaces. diff --git a/sound/soc/ep93xx/edb93xx.c b/sound/soc/ep93xx/edb93xx.c index bae5cbbbd2b..e01cb02abd3 100644 --- a/sound/soc/ep93xx/edb93xx.c +++ b/sound/soc/ep93xx/edb93xx.c @@ -85,9 +85,7 @@ static int __devinit edb93xx_probe(struct platform_device *pdev) struct snd_soc_card *card = &snd_soc_edb93xx; int ret; - ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97, - EP93XX_SYSCON_I2SCLKDIV_ORIDE | - EP93XX_SYSCON_I2SCLKDIV_SPOL); + ret = ep93xx_i2s_acquire(); if (ret) return ret; diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c index de839044987..162dbb74f4c 100644 --- a/sound/soc/ep93xx/ep93xx-pcm.c +++ b/sound/soc/ep93xx/ep93xx-pcm.c @@ -23,6 +23,7 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/dmaengine_pcm.h> #include <mach/dma.h> #include <mach/hardware.h> @@ -52,26 +53,6 @@ static const struct snd_pcm_hardware ep93xx_pcm_hardware = { .fifo_size = 32, }; -struct ep93xx_runtime_data -{ - int pointer_bytes; - int periods; - int period_bytes; - struct dma_chan *dma_chan; - struct ep93xx_dma_data dma_data; -}; - -static void ep93xx_pcm_dma_callback(void *data) -{ - struct snd_pcm_substream *substream = data; - struct ep93xx_runtime_data *rtd = substream->runtime->private_data; - - rtd->pointer_bytes += rtd->period_bytes; - rtd->pointer_bytes %= rtd->period_bytes * rtd->periods; - - snd_pcm_period_elapsed(substream); -} - static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param) { struct ep93xx_dma_data *data = filter_param; @@ -86,98 +67,48 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param) static int ep93xx_pcm_open(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *soc_rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct ep93xx_pcm_dma_params *dma_params; - struct ep93xx_runtime_data *rtd; - dma_cap_mask_t mask; + struct ep93xx_dma_data *dma_data; int ret; - ret = snd_pcm_hw_constraint_integer(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - return ret; - snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); - rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); - if (!rtd) + dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL); + if (!dma_data) return -ENOMEM; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_cap_set(DMA_CYCLIC, mask); - dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream); - rtd->dma_data.port = dma_params->dma_port; - rtd->dma_data.name = dma_params->name; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rtd->dma_data.direction = DMA_MEM_TO_DEV; - else - rtd->dma_data.direction = DMA_DEV_TO_MEM; - - rtd->dma_chan = dma_request_channel(mask, ep93xx_pcm_dma_filter, - &rtd->dma_data); - if (!rtd->dma_chan) { - kfree(rtd); - return -EINVAL; - } - - substream->runtime->private_data = rtd; - return 0; -} + dma_data->port = dma_params->dma_port; + dma_data->name = dma_params->name; + dma_data->direction = snd_pcm_substream_to_dma_direction(substream); -static int ep93xx_pcm_close(struct snd_pcm_substream *substream) -{ - struct ep93xx_runtime_data *rtd = substream->runtime->private_data; + ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data); + if (ret) { + kfree(dma_data); + return ret; + } - dma_release_channel(rtd->dma_chan); - kfree(rtd); - return 0; -} + snd_dmaengine_pcm_set_data(substream, dma_data); -static int ep93xx_pcm_dma_submit(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct ep93xx_runtime_data *rtd = runtime->private_data; - struct dma_chan *chan = rtd->dma_chan; - struct dma_device *dma_dev = chan->device; - struct dma_async_tx_descriptor *desc; - - rtd->pointer_bytes = 0; - desc = dma_dev->device_prep_dma_cyclic(chan, runtime->dma_addr, - rtd->period_bytes * rtd->periods, - rtd->period_bytes, - rtd->dma_data.direction); - if (!desc) - return -EINVAL; - - desc->callback = ep93xx_pcm_dma_callback; - desc->callback_param = substream; - - dmaengine_submit(desc); return 0; } -static void ep93xx_pcm_dma_flush(struct snd_pcm_substream *substream) +static int ep93xx_pcm_close(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct ep93xx_runtime_data *rtd = runtime->private_data; + struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream); - dmaengine_terminate_all(rtd->dma_chan); + snd_dmaengine_pcm_close(substream); + kfree(dma_data); + return 0; } static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct ep93xx_runtime_data *rtd = runtime->private_data; - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - rtd->periods = params_periods(params); - rtd->period_bytes = params_period_bytes(params); return 0; } @@ -187,41 +118,6 @@ static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - int ret; - - ret = 0; - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = ep93xx_pcm_dma_submit(substream); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ep93xx_pcm_dma_flush(substream); - break; - - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct ep93xx_runtime_data *rtd = substream->runtime->private_data; - - /* FIXME: implement this with sub-period granularity */ - return bytes_to_frames(runtime, rtd->pointer_bytes); -} - static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -239,8 +135,8 @@ static struct snd_pcm_ops ep93xx_pcm_ops = { .ioctl = snd_pcm_lib_ioctl, .hw_params = ep93xx_pcm_hw_params, .hw_free = ep93xx_pcm_hw_free, - .trigger = ep93xx_pcm_trigger, - .pointer = ep93xx_pcm_pointer, + .trigger = snd_dmaengine_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer, .mmap = ep93xx_pcm_mmap, }; @@ -281,7 +177,7 @@ static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm) } } -static u64 ep93xx_pcm_dmamask = 0xffffffff; +static u64 ep93xx_pcm_dmamask = DMA_BIT_MASK(32); static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd) { @@ -292,7 +188,7 @@ static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!card->dev->dma_mask) card->dev->dma_mask = &ep93xx_pcm_dmamask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = ep93xx_pcm_preallocate_dma_buffer(pcm, diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c index ccae34a3f28..a193cea3cf3 100644 --- a/sound/soc/ep93xx/snappercl15.c +++ b/sound/soc/ep93xx/snappercl15.c @@ -103,9 +103,7 @@ static int __devinit snappercl15_probe(struct platform_device *pdev) struct snd_soc_card *card = &snd_soc_snappercl15; int ret; - ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97, - EP93XX_SYSCON_I2SCLKDIV_ORIDE | - EP93XX_SYSCON_I2SCLKDIV_SPOL); + ret = ep93xx_i2s_acquire(); if (ret) return ret; diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 4f59bbaba48..96bb92dd174 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -311,23 +311,23 @@ static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd) * should allocate a DMA buffer only for the streams that are valid. */ - if (pcm->streams[0].substream) { + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, fsl_dma_hardware.buffer_bytes_max, - &pcm->streams[0].substream->dma_buffer); + &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); if (ret) { dev_err(card->dev, "can't alloc playback dma buffer\n"); return ret; } } - if (pcm->streams[1].substream) { + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, fsl_dma_hardware.buffer_bytes_max, - &pcm->streams[1].substream->dma_buffer); + &pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->dma_buffer); if (ret) { dev_err(card->dev, "can't alloc capture dma buffer\n"); - snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); + snd_dma_free_pages(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); return ret; } } diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 3e066966d87..2eb407fa3b4 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -716,12 +716,12 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) } /* Trigger the machine driver's probe function. The platform driver - * name of the machine driver is taken from the /model property of the + * name of the machine driver is taken from /compatible property of the * device tree. We also pass the address of the CPU DAI driver * structure. */ - sprop = of_get_property(of_find_node_by_path("/"), "model", NULL); - /* Sometimes the model name has a "fsl," prefix, so we strip that. */ + sprop = of_get_property(of_find_node_by_path("/"), "compatible", NULL); + /* Sometimes the compatible name has a "fsl," prefix, so we strip it. */ p = strrchr(sprop, ','); if (p) sprop = p + 1; diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index e7803d34c42..9a3f7c5ab68 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/of_device.h> +#include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/of_platform.h> @@ -298,7 +299,7 @@ static struct snd_pcm_ops psc_dma_ops = { .hw_params = psc_dma_hw_params, }; -static u64 psc_dma_dmamask = 0xffffffff; +static u64 psc_dma_dmamask = DMA_BIT_MASK(32); static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; @@ -314,18 +315,18 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) if (!card->dev->dma_mask) card->dev->dma_mask = &psc_dma_dmamask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); - if (pcm->streams[0].substream) { + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, - size, &pcm->streams[0].substream->dma_buffer); + size, &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); if (rc) goto playback_alloc_err; } - if (pcm->streams[1].substream) { + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, - size, &pcm->streams[1].substream->dma_buffer); + size, &pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->dma_buffer); if (rc) goto capture_alloc_err; } @@ -336,8 +337,8 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) return 0; capture_alloc_err: - if (pcm->streams[0].substream) - snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) + snd_dma_free_pages(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); playback_alloc_err: dev_err(card->dev, "Cannot allocate buffer(s)\n"); diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 0ea4a5a96e0..afbabf427f2 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -245,7 +245,7 @@ static int get_parent_cell_index(struct device_node *np) * 'struct device' It's ugly and hackish, but it works. * * The dev_name for such devices include the bus number and I2C address. For - * example, "cs4270-codec.0-004f". + * example, "cs4270.0-004f". */ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) { @@ -267,13 +267,13 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) if (!i2c) return -ENODEV; - snprintf(buf, len, "%s-codec.%u-%04x", temp, i2c->adapter->nr, addr); + snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr); return 0; } static int get_dma_channel(struct device_node *ssi_np, - const char *compatible, + const char *name, struct snd_soc_dai_link *dai, unsigned int *dma_channel_id, unsigned int *dma_id) @@ -283,7 +283,7 @@ static int get_dma_channel(struct device_node *ssi_np, const u32 *iprop; int ret; - dma_channel_np = get_node_by_phandle_name(ssi_np, compatible, + dma_channel_np = get_node_by_phandle_name(ssi_np, name, "fsl,ssi-dma-channel"); if (!dma_channel_np) return -EINVAL; @@ -336,12 +336,8 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) const char *sprop; const u32 *iprop; - /* We are only interested in SSIs with a codec phandle in them, - * so let's make sure this SSI has one. The MPC8610 HPCD only - * knows about the CS4270 codec, so reject anything else. - */ - codec_np = get_node_by_phandle_name(np, "codec-handle", - "cirrus,cs4270"); + /* Find the codec node for this SSI. */ + codec_np = of_parse_phandle(np, "codec-handle", 0); if (!codec_np) { dev_err(dev, "invalid codec node\n"); return -EINVAL; @@ -550,7 +546,7 @@ static struct platform_driver mpc8610_hpcd_driver = { .probe = mpc8610_hpcd_probe, .remove = __devexit_p(mpc8610_hpcd_remove), .driver = { - /* The name must match the 'model' property in the device tree, + /* The name must match 'compatible' property in the device tree, * in lowercase letters. */ .name = "snd-soc-mpc8610hpcd", diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index a5d4e80a9cf..46623405a2c 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -276,7 +276,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) } static int get_dma_channel(struct device_node *ssi_np, - const char *compatible, + const char *name, struct snd_soc_dai_link *dai, unsigned int *dma_channel_id, unsigned int *dma_id) @@ -286,7 +286,7 @@ static int get_dma_channel(struct device_node *ssi_np, const u32 *iprop; int ret; - dma_channel_np = get_node_by_phandle_name(ssi_np, compatible, + dma_channel_np = get_node_by_phandle_name(ssi_np, name, "fsl,ssi-dma-channel"); if (!dma_channel_np) return -EINVAL; @@ -395,7 +395,8 @@ static int p1022_ds_probe(struct platform_device *pdev) } if (strcasecmp(sprop, "i2s-slave") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_I2S; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; @@ -412,31 +413,38 @@ static int p1022_ds_probe(struct platform_device *pdev) } mdata->clk_frequency = be32_to_cpup(iprop); } else if (strcasecmp(sprop, "i2s-master") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_I2S; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "lj-slave") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_LEFT_J; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "lj-master") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_LEFT_J; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBS_CFS; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "rj-slave") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBM_CFM; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "rj-master") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBS_CFS; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "ac97-slave") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_AC97; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBM_CFM; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "ac97-master") == 0) { - mdata->dai_format = SND_SOC_DAIFMT_AC97; + mdata->dai_format = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBS_CFS; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else { @@ -543,6 +551,11 @@ static struct platform_driver p1022_ds_driver = { .probe = p1022_ds_probe, .remove = __devexit_p(p1022_ds_remove), .driver = { + /* + * The name must match 'compatible' property in the device tree, + * in lowercase letters. + */ + .name = "snd-soc-p1022ds", .owner = THIS_MODULE, }, }; @@ -556,33 +569,6 @@ static int __init p1022_ds_init(void) { struct device_node *guts_np; struct resource res; - const char *sprop; - - /* - * Check if we're actually running on a P1022DS. Older device trees - * have a model of "fsl,P1022" and newer ones use "fsl,P1022DS", so we - * need to support both. The SSI driver uses that property to link to - * the machine driver, so have to match it. - */ - sprop = of_get_property(of_find_node_by_path("/"), "model", NULL); - if (!sprop) { - pr_err("snd-soc-p1022ds: missing /model node"); - return -ENODEV; - } - - pr_debug("snd-soc-p1022ds: board model name is %s\n", sprop); - - /* - * The name of this board, taken from the device tree. Normally, this is a* - * fixed string, but some P1022DS device trees have a /model property of - * "fsl,P1022", and others have "fsl,P1022DS". - */ - if (strcasecmp(sprop, "fsl,p1022ds") == 0) - p1022_ds_driver.driver.name = "snd-soc-p1022ds"; - else if (strcasecmp(sprop, "fsl,p1022") == 0) - p1022_ds_driver.driver.name = "snd-soc-p1022"; - else - return -ENODEV; /* Get the physical address of the global utilities registers */ guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index 738391757f2..810acaa0900 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -1,9 +1,6 @@ menuconfig SND_IMX_SOC tristate "SoC Audio for Freescale i.MX CPUs" depends on ARCH_MXC - select SND_PCM - select FIQ - select SND_SOC_AC97_BUS help Say Y or M if you want to add support for codecs attached to the i.MX SSI interface. @@ -11,10 +8,23 @@ menuconfig SND_IMX_SOC if SND_IMX_SOC +config SND_SOC_IMX_SSI + tristate + +config SND_SOC_IMX_PCM + tristate + config SND_MXC_SOC_FIQ tristate + select FIQ + select SND_SOC_IMX_PCM config SND_MXC_SOC_MX2 + select SND_SOC_DMAENGINE_PCM + tristate + select SND_SOC_IMX_PCM + +config SND_SOC_IMX_AUDMUX tristate config SND_MXC_SOC_WM1133_EV1 @@ -22,6 +32,8 @@ config SND_MXC_SOC_WM1133_EV1 depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL select SND_SOC_WM8350 select SND_MXC_SOC_FIQ + select SND_SOC_IMX_AUDMUX + select SND_SOC_IMX_SSI help Enable support for audio on the i.MX31ADS with the WM1133-EV1 PMIC board with WM8835x fitted. @@ -31,6 +43,8 @@ config SND_SOC_MX27VIS_AIC32X4 depends on MACH_IMX27_VISSTRIM_M10 && I2C select SND_SOC_TLV320AIC32X4 select SND_MXC_SOC_MX2 + select SND_SOC_IMX_AUDMUX + select SND_SOC_IMX_SSI help Say Y if you want to add support for SoC audio on Visstrim SM10 board with TLV320AIC32X4 codec. @@ -38,8 +52,11 @@ config SND_SOC_MX27VIS_AIC32X4 config SND_SOC_PHYCORE_AC97 tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" depends on MACH_PCM043 || MACH_PCA100 + select SND_SOC_AC97_BUS select SND_SOC_WM9712 select SND_MXC_SOC_FIQ + select SND_SOC_IMX_AUDMUX + select SND_SOC_IMX_SSI help Say Y if you want to add support for SoC audio on Phytec phyCORE and phyCARD boards in AC97 mode @@ -53,6 +70,8 @@ config SND_SOC_EUKREA_TLV320 depends on I2C select SND_SOC_TLV320AIC23 select SND_MXC_SOC_FIQ + select SND_SOC_IMX_AUDMUX + select SND_SOC_IMX_SSI help Enable I2S based access to the TLV320AIC23B codec attached to the SSI interface diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index d6d609ba7e2..f5db3e92d0d 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -1,11 +1,14 @@ # i.MX Platform Support -snd-soc-imx-objs := imx-ssi.o -snd-soc-imx-fiq-objs := imx-pcm-fiq.o -snd-soc-imx-mx2-objs := imx-pcm-dma-mx2.o +snd-soc-imx-ssi-objs := imx-ssi.o +snd-soc-imx-audmux-objs := imx-audmux.o -obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o -obj-$(CONFIG_SND_MXC_SOC_FIQ) += snd-soc-imx-fiq.o -obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o +obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o +obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o + +obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o +snd-soc-imx-pcm-y := imx-pcm.o +snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_FIQ) += imx-pcm-fiq.o +snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_MX2) += imx-pcm-dma-mx2.o # i.MX Machine Support snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c index 1c1fdd10f73..7d4475cfdb2 100644 --- a/sound/soc/imx/eukrea-tlv320.c +++ b/sound/soc/imx/eukrea-tlv320.c @@ -26,6 +26,7 @@ #include "../codecs/tlv320aic23.h" #include "imx-ssi.h" +#include "imx-audmux.h" #define CODEC_CLOCK 12000000 @@ -97,12 +98,43 @@ static struct platform_device *eukrea_tlv320_snd_device; static int __init eukrea_tlv320_init(void) { int ret; - - if (!machine_is_eukrea_cpuimx27() && !machine_is_eukrea_cpuimx25sd() - && !machine_is_eukrea_cpuimx35sd() - && !machine_is_eukrea_cpuimx51sd()) + int int_port = 0, ext_port; + + if (machine_is_eukrea_cpuimx27()) { + imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, + IMX_AUDMUX_V1_PCR_SYN | + IMX_AUDMUX_V1_PCR_TFSDIR | + IMX_AUDMUX_V1_PCR_TCLKDIR | + IMX_AUDMUX_V1_PCR_RFSDIR | + IMX_AUDMUX_V1_PCR_RCLKDIR | + IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | + IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | + IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) + ); + imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4, + IMX_AUDMUX_V1_PCR_SYN | + IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) + ); + } else if (machine_is_eukrea_cpuimx25sd() || + machine_is_eukrea_cpuimx35sd() || + machine_is_eukrea_cpuimx51sd()) { + ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3; + imx_audmux_v2_configure_port(int_port, + IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TCLKDIR | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port), + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port) + ); + imx_audmux_v2_configure_port(ext_port, + IMX_AUDMUX_V2_PTCR_SYN, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port) + ); + } else { /* return happy. We might run on a totally different machine */ return 0; + } eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1); if (!eukrea_tlv320_snd_device) diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/imx/imx-audmux.c new file mode 100644 index 00000000000..a839494c5ea --- /dev/null +++ b/sound/soc/imx/imx-audmux.c @@ -0,0 +1,314 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> + * + * Initial development of this code was funded by + * Phytec Messtechnik GmbH, http://www.phytec.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. + */ + +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "imx-audmux.h" + +#define DRIVER_NAME "imx-audmux" + +static struct clk *audmux_clk; +static void __iomem *audmux_base; + +#define IMX_AUDMUX_V2_PTCR(x) ((x) * 8) +#define IMX_AUDMUX_V2_PDCR(x) ((x) * 8 + 4) + +#ifdef CONFIG_DEBUG_FS +static struct dentry *audmux_debugfs_root; + +static int audmux_open_file(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +/* There is an annoying discontinuity in the SSI numbering with regard + * to the Linux number of the devices */ +static const char *audmux_port_string(int port) +{ + switch (port) { + case MX31_AUDMUX_PORT1_SSI0: + return "imx-ssi.0"; + case MX31_AUDMUX_PORT2_SSI1: + return "imx-ssi.1"; + case MX31_AUDMUX_PORT3_SSI_PINS_3: + return "SSI3"; + case MX31_AUDMUX_PORT4_SSI_PINS_4: + return "SSI4"; + case MX31_AUDMUX_PORT5_SSI_PINS_5: + return "SSI5"; + case MX31_AUDMUX_PORT6_SSI_PINS_6: + return "SSI6"; + default: + return "UNKNOWN"; + } +} + +static ssize_t audmux_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + int port = (int)file->private_data; + u32 pdcr, ptcr; + + if (!buf) + return -ENOMEM; + + if (audmux_clk) + clk_enable(audmux_clk); + + ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port)); + pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port)); + + if (audmux_clk) + clk_disable(audmux_clk); + + ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", + pdcr, ptcr); + + if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "TxFS output from %s, ", + audmux_port_string((ptcr >> 27) & 0x7)); + else + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "TxFS input, "); + + if (ptcr & IMX_AUDMUX_V2_PTCR_TCLKDIR) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "TxClk output from %s", + audmux_port_string((ptcr >> 22) & 0x7)); + else + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "TxClk input"); + + ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); + + if (ptcr & IMX_AUDMUX_V2_PTCR_SYN) { + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "Port is symmetric"); + } else { + if (ptcr & IMX_AUDMUX_V2_PTCR_RFSDIR) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "RxFS output from %s, ", + audmux_port_string((ptcr >> 17) & 0x7)); + else + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "RxFS input, "); + + if (ptcr & IMX_AUDMUX_V2_PTCR_RCLKDIR) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "RxClk output from %s", + audmux_port_string((ptcr >> 12) & 0x7)); + else + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "RxClk input"); + } + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "\nData received from %s\n", + audmux_port_string((pdcr >> 13) & 0x7)); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + + kfree(buf); + + return ret; +} + +static const struct file_operations audmux_debugfs_fops = { + .open = audmux_open_file, + .read = audmux_read_file, + .llseek = default_llseek, +}; + +static void __init audmux_debugfs_init(void) +{ + int i; + char buf[20]; + + audmux_debugfs_root = debugfs_create_dir("audmux", NULL); + if (!audmux_debugfs_root) { + pr_warning("Failed to create AUDMUX debugfs root\n"); + return; + } + + for (i = 1; i < 8; i++) { + snprintf(buf, sizeof(buf), "ssi%d", i); + if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, + (void *)i, &audmux_debugfs_fops)) + pr_warning("Failed to create AUDMUX port %d debugfs file\n", + i); + } +} + +static void __devexit audmux_debugfs_remove(void) +{ + debugfs_remove_recursive(audmux_debugfs_root); +} +#else +static inline void audmux_debugfs_init(void) +{ +} + +static inline void audmux_debugfs_remove(void) +{ +} +#endif + +enum imx_audmux_type { + IMX21_AUDMUX, + IMX31_AUDMUX, +} audmux_type; + +static struct platform_device_id imx_audmux_ids[] = { + { + .name = "imx21-audmux", + .driver_data = IMX21_AUDMUX, + }, { + .name = "imx31-audmux", + .driver_data = IMX31_AUDMUX, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, imx_audmux_ids); + +static const struct of_device_id imx_audmux_dt_ids[] = { + { .compatible = "fsl,imx21-audmux", .data = &imx_audmux_ids[0], }, + { .compatible = "fsl,imx31-audmux", .data = &imx_audmux_ids[1], }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids); + +static const uint8_t port_mapping[] = { + 0x0, 0x4, 0x8, 0x10, 0x14, 0x1c, +}; + +int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr) +{ + if (audmux_type != IMX21_AUDMUX) + return -EINVAL; + + if (!audmux_base) + return -ENOSYS; + + if (port >= ARRAY_SIZE(port_mapping)) + return -EINVAL; + + writel(pcr, audmux_base + port_mapping[port]); + + return 0; +} +EXPORT_SYMBOL_GPL(imx_audmux_v1_configure_port); + +int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, + unsigned int pdcr) +{ + if (audmux_type != IMX31_AUDMUX) + return -EINVAL; + + if (!audmux_base) + return -ENOSYS; + + if (audmux_clk) + clk_enable(audmux_clk); + + writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); + writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); + + if (audmux_clk) + clk_disable(audmux_clk); + + return 0; +} +EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port); + +static int __devinit imx_audmux_probe(struct platform_device *pdev) +{ + struct resource *res; + const struct of_device_id *of_id = + of_match_device(imx_audmux_dt_ids, &pdev->dev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + audmux_base = devm_request_and_ioremap(&pdev->dev, res); + if (!audmux_base) + return -EADDRNOTAVAIL; + + audmux_clk = clk_get(&pdev->dev, "audmux"); + if (IS_ERR(audmux_clk)) { + dev_dbg(&pdev->dev, "cannot get clock: %ld\n", + PTR_ERR(audmux_clk)); + audmux_clk = NULL; + } + + if (of_id) + pdev->id_entry = of_id->data; + audmux_type = pdev->id_entry->driver_data; + if (audmux_type == IMX31_AUDMUX) + audmux_debugfs_init(); + + return 0; +} + +static int __devexit imx_audmux_remove(struct platform_device *pdev) +{ + if (audmux_type == IMX31_AUDMUX) + audmux_debugfs_remove(); + clk_put(audmux_clk); + + return 0; +} + +static struct platform_driver imx_audmux_driver = { + .probe = imx_audmux_probe, + .remove = __devexit_p(imx_audmux_remove), + .id_table = imx_audmux_ids, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = imx_audmux_dt_ids, + } +}; + +static int __init imx_audmux_init(void) +{ + return platform_driver_register(&imx_audmux_driver); +} +subsys_initcall(imx_audmux_init); + +static void __exit imx_audmux_exit(void) +{ + platform_driver_unregister(&imx_audmux_driver); +} +module_exit(imx_audmux_exit); + +MODULE_DESCRIPTION("Freescale i.MX AUDMUX driver"); +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/sound/soc/imx/imx-audmux.h b/sound/soc/imx/imx-audmux.h new file mode 100644 index 00000000000..04ebbab8d7b --- /dev/null +++ b/sound/soc/imx/imx-audmux.h @@ -0,0 +1,60 @@ +#ifndef __IMX_AUDMUX_H +#define __IMX_AUDMUX_H + +#define MX27_AUDMUX_HPCR1_SSI0 0 +#define MX27_AUDMUX_HPCR2_SSI1 1 +#define MX27_AUDMUX_HPCR3_SSI_PINS_4 2 +#define MX27_AUDMUX_PPCR1_SSI_PINS_1 3 +#define MX27_AUDMUX_PPCR2_SSI_PINS_2 4 +#define MX27_AUDMUX_PPCR3_SSI_PINS_3 5 + +#define MX31_AUDMUX_PORT1_SSI0 0 +#define MX31_AUDMUX_PORT2_SSI1 1 +#define MX31_AUDMUX_PORT3_SSI_PINS_3 2 +#define MX31_AUDMUX_PORT4_SSI_PINS_4 3 +#define MX31_AUDMUX_PORT5_SSI_PINS_5 4 +#define MX31_AUDMUX_PORT6_SSI_PINS_6 5 + +#define MX51_AUDMUX_PORT1_SSI0 0 +#define MX51_AUDMUX_PORT2_SSI1 1 +#define MX51_AUDMUX_PORT3 2 +#define MX51_AUDMUX_PORT4 3 +#define MX51_AUDMUX_PORT5 4 +#define MX51_AUDMUX_PORT6 5 +#define MX51_AUDMUX_PORT7 6 + +/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */ +#define IMX_AUDMUX_V1_PCR_INMMASK(x) ((x) & 0xff) +#define IMX_AUDMUX_V1_PCR_INMEN (1 << 8) +#define IMX_AUDMUX_V1_PCR_TXRXEN (1 << 10) +#define IMX_AUDMUX_V1_PCR_SYN (1 << 12) +#define IMX_AUDMUX_V1_PCR_RXDSEL(x) (((x) & 0x7) << 13) +#define IMX_AUDMUX_V1_PCR_RFCSEL(x) (((x) & 0xf) << 20) +#define IMX_AUDMUX_V1_PCR_RCLKDIR (1 << 24) +#define IMX_AUDMUX_V1_PCR_RFSDIR (1 << 25) +#define IMX_AUDMUX_V1_PCR_TFCSEL(x) (((x) & 0xf) << 26) +#define IMX_AUDMUX_V1_PCR_TCLKDIR (1 << 30) +#define IMX_AUDMUX_V1_PCR_TFSDIR (1 << 31) + +/* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */ +#define IMX_AUDMUX_V2_PTCR_TFSDIR (1 << 31) +#define IMX_AUDMUX_V2_PTCR_TFSEL(x) (((x) & 0xf) << 27) +#define IMX_AUDMUX_V2_PTCR_TCLKDIR (1 << 26) +#define IMX_AUDMUX_V2_PTCR_TCSEL(x) (((x) & 0xf) << 22) +#define IMX_AUDMUX_V2_PTCR_RFSDIR (1 << 21) +#define IMX_AUDMUX_V2_PTCR_RFSEL(x) (((x) & 0xf) << 17) +#define IMX_AUDMUX_V2_PTCR_RCLKDIR (1 << 16) +#define IMX_AUDMUX_V2_PTCR_RCSEL(x) (((x) & 0xf) << 12) +#define IMX_AUDMUX_V2_PTCR_SYN (1 << 11) + +#define IMX_AUDMUX_V2_PDCR_RXDSEL(x) (((x) & 0x7) << 13) +#define IMX_AUDMUX_V2_PDCR_TXRXEN (1 << 12) +#define IMX_AUDMUX_V2_PDCR_MODE(x) (((x) & 0x3) << 8) +#define IMX_AUDMUX_V2_PDCR_INMMASK(x) ((x) & 0xff) + +int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr); + +int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, + unsigned int pdcr); + +#endif /* __IMX_AUDMUX_H */ diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c index 5780c9b9d56..e43c8fa2788 100644 --- a/sound/soc/imx/imx-pcm-dma-mx2.c +++ b/sound/soc/imx/imx-pcm-dma-mx2.c @@ -27,212 +27,54 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/dmaengine_pcm.h> #include <mach/dma.h> -#include "imx-ssi.h" - -struct imx_pcm_runtime_data { - int period_bytes; - int periods; - int dma; - unsigned long offset; - unsigned long size; - void *buf; - int period_time; - struct dma_async_tx_descriptor *desc; - struct dma_chan *dma_chan; - struct imx_dma_data dma_data; -}; - -static void audio_dma_irq(void *data) -{ - struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; - - iprtd->offset += iprtd->period_bytes; - iprtd->offset %= iprtd->period_bytes * iprtd->periods; - - snd_pcm_period_elapsed(substream); -} +#include "imx-pcm.h" static bool filter(struct dma_chan *chan, void *param) { - struct imx_pcm_runtime_data *iprtd = param; - if (!imx_dma_is_general_purpose(chan)) return false; - chan->private = &iprtd->dma_data; + chan->private = param; - return true; + return true; } -static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream, +static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); struct imx_pcm_dma_params *dma_params; - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; struct dma_slave_config slave_config; - dma_cap_mask_t mask; - enum dma_slave_buswidth buswidth; int ret; dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - iprtd->dma_data.peripheral_type = IMX_DMATYPE_SSI; - iprtd->dma_data.priority = DMA_PRIO_HIGH; - iprtd->dma_data.dma_request = dma_params->dma; - - /* Try to grab a DMA channel */ - if (!iprtd->dma_chan) { - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); - if (!iprtd->dma_chan) - return -EINVAL; - } - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - case SNDRV_PCM_FORMAT_S24_LE: - buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; - break; - default: - return 0; - } + ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config); + if (ret) + return ret; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = dma_params->dma_addr; - slave_config.dst_addr_width = buswidth; slave_config.dst_maxburst = dma_params->burstsize; } else { - slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = dma_params->dma_addr; - slave_config.src_addr_width = buswidth; slave_config.src_maxburst = dma_params->burstsize; } - ret = dmaengine_slave_config(iprtd->dma_chan, &slave_config); + ret = dmaengine_slave_config(chan, &slave_config); if (ret) return ret; - return 0; -} - -static int snd_imx_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_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; - unsigned long dma_addr; - struct dma_chan *chan; - struct imx_pcm_dma_params *dma_params; - int ret; - - dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - ret = imx_ssi_dma_alloc(substream, params); - if (ret) - return ret; - chan = iprtd->dma_chan; - - iprtd->size = params_buffer_bytes(params); - iprtd->periods = params_periods(params); - iprtd->period_bytes = params_period_bytes(params); - iprtd->offset = 0; - iprtd->period_time = HZ / (params_rate(params) / - params_period_size(params)); - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - dma_addr = runtime->dma_addr; - - iprtd->buf = (unsigned int *)substream->dma_buffer.area; - - iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr, - iprtd->period_bytes * iprtd->periods, - iprtd->period_bytes, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); - if (!iprtd->desc) { - dev_err(&chan->dev->device, "cannot prepare slave dma\n"); - return -EINVAL; - } - - iprtd->desc->callback = audio_dma_irq; - iprtd->desc->callback_param = substream; - - return 0; -} - -static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; - - if (iprtd->dma_chan) { - dma_release_channel(iprtd->dma_chan); - iprtd->dma_chan = NULL; - } - - return 0; -} - -static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct imx_pcm_dma_params *dma_params; - - dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - return 0; } -static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - dmaengine_submit(iprtd->desc); - - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - dmaengine_terminate_all(iprtd->dma_chan); - - break; - default: - return -EINVAL; - } - - return 0; -} - -static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; - - pr_debug("%s: %ld %ld\n", __func__, iprtd->offset, - bytes_to_frames(substream->runtime, iprtd->offset)); - - return bytes_to_frames(substream->runtime, iprtd->offset); -} - static struct snd_pcm_hardware snd_imx_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -254,33 +96,37 @@ static struct snd_pcm_hardware snd_imx_hardware = { static int snd_imx_open(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct imx_pcm_dma_params *dma_params; + struct imx_dma_data *dma_data; int ret; - iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); - if (iprtd == NULL) - return -ENOMEM; - runtime->private_data = iprtd; + snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); - ret = snd_pcm_hw_constraint_integer(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) { - kfree(iprtd); - return ret; + dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL); + dma_data->peripheral_type = IMX_DMATYPE_SSI; + dma_data->priority = DMA_PRIO_HIGH; + dma_data->dma_request = dma_params->dma; + + ret = snd_dmaengine_pcm_open(substream, filter, dma_data); + if (ret) { + kfree(dma_data); + return 0; } - snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); + snd_dmaengine_pcm_set_data(substream, dma_data); return 0; } static int snd_imx_close(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; + struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream); - kfree(iprtd); + snd_dmaengine_pcm_close(substream); + kfree(dma_data); return 0; } @@ -290,10 +136,8 @@ static struct snd_pcm_ops imx_pcm_ops = { .close = snd_imx_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_imx_pcm_hw_params, - .hw_free = snd_imx_pcm_hw_free, - .prepare = snd_imx_pcm_prepare, - .trigger = snd_imx_pcm_trigger, - .pointer = snd_imx_pcm_pointer, + .trigger = snd_dmaengine_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer, .mmap = snd_imx_pcm_mmap, }; @@ -305,11 +149,6 @@ 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-pcm.c b/sound/soc/imx/imx-pcm.c new file mode 100644 index 00000000000..93dc360b177 --- /dev/null +++ b/sound/soc/imx/imx-pcm.c @@ -0,0 +1,105 @@ +/* + * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de> + * + * This code is based on code copyrighted by Freescale, + * Liam Girdwood, Javier Martin and probably others. + * + * 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/dma-mapping.h> +#include <linux/module.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include "imx-pcm.h" + +int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + ret = dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); + + pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); + return ret; +} +EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap); + +static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = IMX_SSI_DMABUF_SIZE; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + buf->bytes = size; + + return 0; +} + +static u64 imx_pcm_dmamask = DMA_BIT_MASK(32); + +int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &imx_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + ret = imx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { + ret = imx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + +out: + return ret; +} +EXPORT_SYMBOL_GPL(imx_pcm_new); + +void imx_pcm_free(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} +EXPORT_SYMBOL_GPL(imx_pcm_free); diff --git a/sound/soc/imx/imx-pcm.h b/sound/soc/imx/imx-pcm.h new file mode 100644 index 00000000000..b5f5c3acf34 --- /dev/null +++ b/sound/soc/imx/imx-pcm.h @@ -0,0 +1,32 @@ +/* + * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de> + * + * This code is based on code copyrighted by Freescale, + * Liam Girdwood, Javier Martin and probably others. + * + * 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 _IMX_PCM_H +#define _IMX_PCM_H + +/* + * Do not change this as the FIQ handler depends on this size + */ +#define IMX_SSI_DMABUF_SIZE (64 * 1024) + +struct imx_pcm_dma_params { + int dma; + unsigned long dma_addr; + int burstsize; +}; + +int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma); +int imx_pcm_new(struct snd_soc_pcm_runtime *rtd); +void imx_pcm_free(struct snd_pcm *pcm); + +#endif /* _IMX_PCM_H */ diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index b6adbed6e50..4f81ed45632 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -233,6 +233,23 @@ static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, return 0; } +static int imx_ssi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct imx_pcm_dma_params *dma_data; + + /* Tx/Rx config */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dma_data = &ssi->dma_params_tx; + else + dma_data = &ssi->dma_params_rx; + + snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); + + return 0; +} + /* * Should only be called when port is inactive (i.e. SSIEN = 0), * although can be called multiple times by upper layers. @@ -242,23 +259,17 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); - struct imx_pcm_dma_params *dma_data; u32 reg, sccr; /* Tx/Rx config */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) reg = SSI_STCCR; - dma_data = &ssi->dma_params_tx; - } else { + else reg = SSI_SRCCR; - dma_data = &ssi->dma_params_rx; - } if (ssi->flags & IMX_SSI_SYN) reg = SSI_STCCR; - snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); - sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK; /* DAI data (word) size */ @@ -343,6 +354,7 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd, } static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { + .startup = imx_ssi_startup, .hw_params = imx_ssi_hw_params, .set_fmt = imx_ssi_set_dai_fmt, .set_clkdiv = imx_ssi_set_dai_clkdiv, @@ -351,94 +363,6 @@ static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { .trigger = imx_ssi_trigger, }; -int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int ret; - - ret = dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); - - pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); - return ret; -} -EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap); - -static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = IMX_SSI_DMABUF_SIZE; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - if (!buf->area) - return -ENOMEM; - buf->bytes = size; - - return 0; -} - -static u64 imx_pcm_dmamask = DMA_BIT_MASK(32); - -int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_card *card = rtd->card->snd_card; - struct snd_pcm *pcm = rtd->pcm; - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &imx_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_BIT_MASK(32); - if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { - ret = imx_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { - ret = imx_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - -out: - return ret; -} -EXPORT_SYMBOL_GPL(imx_pcm_new); - -void imx_pcm_free(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} -EXPORT_SYMBOL_GPL(imx_pcm_free); - static int imx_ssi_dai_probe(struct snd_soc_dai *dai) { struct imx_ssi *ssi = dev_get_drvdata(dai->dev); @@ -656,7 +580,7 @@ static int imx_ssi_probe(struct platform_device *pdev) ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0; ssi->dma_params_tx.dma_addr = res->start + SSI_STX0; - ssi->dma_params_tx.burstsize = 4; + ssi->dma_params_tx.burstsize = 6; ssi->dma_params_rx.burstsize = 4; res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h index 1072dfb53e4..5744e86ca87 100644 --- a/sound/soc/imx/imx-ssi.h +++ b/sound/soc/imx/imx-ssi.h @@ -187,12 +187,7 @@ #include <linux/dmaengine.h> #include <mach/dma.h> - -struct imx_pcm_dma_params { - int dma; - unsigned long dma_addr; - int burstsize; -}; +#include "imx-pcm.h" struct imx_ssi { struct platform_device *ac97_dev; @@ -218,13 +213,4 @@ struct imx_ssi { struct platform_device *soc_platform_pdev_fiq; }; -int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); -int imx_pcm_new(struct snd_soc_pcm_runtime *rtd); -void imx_pcm_free(struct snd_pcm *pcm); - -/* - * Do not change this as the FIQ handler depends on this size - */ -#define IMX_SSI_DMABUF_SIZE (64 * 1024) - #endif /* _IMX_SSI_H */ diff --git a/sound/soc/imx/mx27vis-aic32x4.c b/sound/soc/imx/mx27vis-aic32x4.c index 3c2eed9094d..f6d04ad4bb3 100644 --- a/sound/soc/imx/mx27vis-aic32x4.c +++ b/sound/soc/imx/mx27vis-aic32x4.c @@ -25,15 +25,36 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/i2c.h> +#include <linux/gpio.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> #include <sound/soc-dapm.h> +#include <sound/tlv.h> #include <asm/mach-types.h> -#include <mach/audmux.h> +#include <mach/iomux-mx27.h> #include "../codecs/tlv320aic32x4.h" #include "imx-ssi.h" +#include "imx-audmux.h" + +#define MX27VIS_AMP_GAIN 0 +#define MX27VIS_AMP_MUTE 1 + +#define MX27VIS_PIN_G0 (GPIO_PORTF + 9) +#define MX27VIS_PIN_G1 (GPIO_PORTF + 8) +#define MX27VIS_PIN_SDL (GPIO_PORTE + 5) +#define MX27VIS_PIN_SDR (GPIO_PORTF + 7) + +static int mx27vis_amp_gain; +static int mx27vis_amp_mute; + +static const int mx27vis_amp_pins[] = { + MX27VIS_PIN_G0 | GPIO_GPIO | GPIO_OUT, + MX27VIS_PIN_G1 | GPIO_GPIO | GPIO_OUT, + MX27VIS_PIN_SDL | GPIO_GPIO | GPIO_OUT, + MX27VIS_PIN_SDR | GPIO_GPIO | GPIO_OUT, +}; static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -74,6 +95,76 @@ static struct snd_soc_ops mx27vis_aic32x4_snd_ops = { .hw_params = mx27vis_aic32x4_hw_params, }; +static int mx27vis_amp_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value = ucontrol->value.integer.value[0]; + unsigned int reg = mc->reg; + int max = mc->max; + + if (value > max) + return -EINVAL; + + switch (reg) { + case MX27VIS_AMP_GAIN: + gpio_set_value(MX27VIS_PIN_G0, value & 1); + gpio_set_value(MX27VIS_PIN_G1, value >> 1); + mx27vis_amp_gain = value; + break; + case MX27VIS_AMP_MUTE: + gpio_set_value(MX27VIS_PIN_SDL, value & 1); + gpio_set_value(MX27VIS_PIN_SDR, value >> 1); + mx27vis_amp_mute = value; + break; + } + return 0; +} + +static int mx27vis_amp_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + + switch (reg) { + case MX27VIS_AMP_GAIN: + ucontrol->value.integer.value[0] = mx27vis_amp_gain; + break; + case MX27VIS_AMP_MUTE: + ucontrol->value.integer.value[0] = mx27vis_amp_mute; + break; + } + return 0; +} + +/* From 6dB to 24dB in steps of 6dB */ +static const DECLARE_TLV_DB_SCALE(mx27vis_amp_tlv, 600, 600, 0); + +static const struct snd_kcontrol_new mx27vis_aic32x4_controls[] = { + SOC_DAPM_PIN_SWITCH("External Mic"), + SOC_SINGLE_EXT_TLV("LO Ext Boost", MX27VIS_AMP_GAIN, 0, 3, 0, + mx27vis_amp_get, mx27vis_amp_set, mx27vis_amp_tlv), + SOC_DOUBLE_EXT("LO Ext Mute Switch", MX27VIS_AMP_MUTE, 0, 1, 1, 0, + mx27vis_amp_get, mx27vis_amp_set), +}; + +static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { + SND_SOC_DAPM_MIC("External Mic", NULL), +}; + +static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { + {"Mic Bias", NULL, "External Mic"}, + {"IN1_R", NULL, "Mic Bias"}, + {"IN2_R", NULL, "Mic Bias"}, + {"IN3_R", NULL, "Mic Bias"}, + {"IN1_L", NULL, "Mic Bias"}, + {"IN2_L", NULL, "Mic Bias"}, + {"IN3_L", NULL, "Mic Bias"}, +}; + static struct snd_soc_dai_link mx27vis_aic32x4_dai = { .name = "tlv320aic32x4", .stream_name = "TLV320AIC32X4", @@ -89,50 +180,66 @@ static struct snd_soc_card mx27vis_aic32x4 = { .owner = THIS_MODULE, .dai_link = &mx27vis_aic32x4_dai, .num_links = 1, + .controls = mx27vis_aic32x4_controls, + .num_controls = ARRAY_SIZE(mx27vis_aic32x4_controls), + .dapm_widgets = aic32x4_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets), + .dapm_routes = aic32x4_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), }; -static struct platform_device *mx27vis_aic32x4_snd_device; - -static int __init mx27vis_aic32x4_init(void) +static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev) { int ret; - mx27vis_aic32x4_snd_device = platform_device_alloc("soc-audio", -1); - if (!mx27vis_aic32x4_snd_device) - return -ENOMEM; - - platform_set_drvdata(mx27vis_aic32x4_snd_device, &mx27vis_aic32x4); - ret = platform_device_add(mx27vis_aic32x4_snd_device); - + mx27vis_aic32x4.dev = &pdev->dev; + ret = snd_soc_register_card(&mx27vis_aic32x4); if (ret) { - printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - platform_device_put(mx27vis_aic32x4_snd_device); + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + return ret; } /* Connect SSI0 as clock slave to SSI1 external pins */ - mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, - MXC_AUDMUX_V1_PCR_SYN | - MXC_AUDMUX_V1_PCR_TFSDIR | - MXC_AUDMUX_V1_PCR_TCLKDIR | - MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) | - MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) + imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, + IMX_AUDMUX_V1_PCR_SYN | + IMX_AUDMUX_V1_PCR_TFSDIR | + IMX_AUDMUX_V1_PCR_TCLKDIR | + IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) | + IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) ); - mxc_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1, - MXC_AUDMUX_V1_PCR_SYN | - MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) + imx_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1, + IMX_AUDMUX_V1_PCR_SYN | + IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) ); + ret = mxc_gpio_setup_multiple_pins(mx27vis_amp_pins, + ARRAY_SIZE(mx27vis_amp_pins), "MX27VIS_AMP"); + if (ret) + printk(KERN_ERR "ASoC: unable to setup gpios\n"); + return ret; } -static void __exit mx27vis_aic32x4_exit(void) +static int __devexit mx27vis_aic32x4_remove(struct platform_device *pdev) { - platform_device_unregister(mx27vis_aic32x4_snd_device); + snd_soc_unregister_card(&mx27vis_aic32x4); + + return 0; } -module_init(mx27vis_aic32x4_init); -module_exit(mx27vis_aic32x4_exit); +static struct platform_driver mx27vis_aic32x4_audio_driver = { + .driver = { + .name = "mx27vis", + .owner = THIS_MODULE, + }, + .probe = mx27vis_aic32x4_probe, + .remove = __devexit_p(mx27vis_aic32x4_remove), +}; + +module_platform_driver(mx27vis_aic32x4_audio_driver); MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:mx27vis"); diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c index 6ac12111de6..f8da6dd115e 100644 --- a/sound/soc/imx/phycore-ac97.c +++ b/sound/soc/imx/phycore-ac97.c @@ -19,6 +19,8 @@ #include <sound/soc.h> #include <asm/mach-types.h> +#include "imx-audmux.h" + static struct snd_soc_card imx_phycore; static struct snd_soc_ops imx_phycore_hifi_ops = { @@ -50,9 +52,32 @@ static int __init imx_phycore_init(void) { int ret; - if (!machine_is_pcm043() && !machine_is_pca100()) + if (machine_is_pca100()) { + imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, + IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */ + IMX_AUDMUX_V1_PCR_TFCSEL(3) | + IMX_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */ + IMX_AUDMUX_V1_PCR_RXDSEL(3)); + imx_audmux_v1_configure_port(3, + IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */ + IMX_AUDMUX_V1_PCR_TFCSEL(0) | + IMX_AUDMUX_V1_PCR_TFSDIR | + IMX_AUDMUX_V1_PCR_RXDSEL(0)); + } else if (machine_is_pcm043()) { + imx_audmux_v2_configure_port(3, + IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */ + IMX_AUDMUX_V2_PTCR_TFSEL(0) | + IMX_AUDMUX_V2_PTCR_TFSDIR, + IMX_AUDMUX_V2_PDCR_RXDSEL(0)); + imx_audmux_v2_configure_port(0, + IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */ + IMX_AUDMUX_V2_PTCR_TCSEL(3) | + IMX_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */ + IMX_AUDMUX_V2_PDCR_RXDSEL(3)); + } else { /* return happy. We might run on a totally different machine */ return 0; + } imx_phycore_snd_ac97_device = platform_device_alloc("soc-audio", -1); if (!imx_phycore_snd_ac97_device) diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/imx/wm1133-ev1.c index 37480c90e99..fe54a69073e 100644 --- a/sound/soc/imx/wm1133-ev1.c +++ b/sound/soc/imx/wm1133-ev1.c @@ -21,10 +21,9 @@ #include <sound/pcm_params.h> #include <sound/soc.h> -#include <mach/audmux.h> - #include "imx-ssi.h" #include "../codecs/wm8350.h" +#include "imx-audmux.h" /* There is a silicon mic on the board optionally connected via a solder pad * SP1. Define this to enable it. @@ -268,17 +267,17 @@ static int __init wm1133_ev1_audio_init(void) unsigned int ptcr, pdcr; /* SSI0 mastered by port 5 */ - ptcr = MXC_AUDMUX_V2_PTCR_SYN | - MXC_AUDMUX_V2_PTCR_TFSDIR | - MXC_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) | - MXC_AUDMUX_V2_PTCR_TCLKDIR | - MXC_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5); - pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5); - mxc_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, ptcr, pdcr); - - ptcr = MXC_AUDMUX_V2_PTCR_SYN; - pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0); - mxc_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5, ptcr, pdcr); + ptcr = IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) | + IMX_AUDMUX_V2_PTCR_TCLKDIR | + IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5); + pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5); + imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, ptcr, pdcr); + + ptcr = IMX_AUDMUX_V2_PTCR_SYN; + pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0); + imx_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5, ptcr, pdcr); wm1133_ev1_snd_device = platform_device_alloc("soc-audio", -1); if (!wm1133_ev1_snd_device) diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c index 0097c3b13a1..e8aaff18d7c 100644 --- a/sound/soc/jz4740/qi_lb60.c +++ b/sound/soc/jz4740/qi_lb60.c @@ -91,56 +91,52 @@ static struct snd_soc_card qi_lb60 = { .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) +static int __devinit qi_lb60_probe(struct platform_device *pdev) { + struct snd_soc_card *card = &qi_lb60; int ret; - qi_lb60_snd_device = platform_device_alloc("soc-audio", -1); - - if (!qi_lb60_snd_device) - return -ENOMEM; - ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); - if (ret) { - pr_err("qi_lb60 snd: Failed to request gpios: %d\n", ret); - goto err_device_put; - } + if (ret) + return ret; - platform_set_drvdata(qi_lb60_snd_device, &qi_lb60); + card->dev = &pdev->dev; - ret = platform_device_add(qi_lb60_snd_device); + ret = snd_soc_register_card(card); if (ret) { - pr_err("qi_lb60 snd: Failed to add snd soc device: %d\n", ret); - goto err_unset_pdata; + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + ret); + gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); } - - return 0; - -err_unset_pdata: - platform_set_drvdata(qi_lb60_snd_device, NULL); -/*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); - return ret; } -module_init(qi_lb60_init); -static void __exit qi_lb60_exit(void) +static int __devexit qi_lb60_remove(struct platform_device *pdev) { - platform_device_unregister(qi_lb60_snd_device); + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios)); + return 0; } -module_exit(qi_lb60_exit); + +static struct platform_driver qi_lb60_driver = { + .driver = { + .name = "qi-lb60-audio", + .owner = THIS_MODULE, + }, + .probe = qi_lb60_probe, + .remove = __devexit_p(qi_lb60_remove), +}; + +module_platform_driver(qi_lb60_driver); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("ALSA SoC QI LB60 Audio support"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:qi-lb60-audio"); diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index d0385402712..b9f16598324 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -55,7 +55,7 @@ static struct snd_pcm_hardware kirkwood_dma_snd_hw = { .fifo_size = 0, }; -static u64 kirkwood_dma_dmamask = 0xFFFFFFFFUL; +static u64 kirkwood_dma_dmamask = DMA_BIT_MASK(32); static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id) { @@ -324,7 +324,7 @@ static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd) if (!card->dev->dma_mask) card->dev->dma_mask = &kirkwood_dma_dmamask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = kirkwood_dma_preallocate_dma_buffer(pcm, diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c index 55d2ed3df30..80bd59c33be 100644 --- a/sound/soc/kirkwood/kirkwood-openrd.c +++ b/sound/soc/kirkwood/kirkwood-openrd.c @@ -71,41 +71,41 @@ static struct snd_soc_card openrd_client = { .num_links = ARRAY_SIZE(openrd_client_dai), }; -static struct platform_device *openrd_client_snd_device; - -static int __init openrd_client_init(void) +static int __devinit openrd_probe(struct platform_device *pdev) { + struct snd_soc_card *card = &openrd_client; int ret; - if (!machine_is_openrd_client() && !machine_is_openrd_ultimate()) - return 0; - - openrd_client_snd_device = platform_device_alloc("soc-audio", -1); - if (!openrd_client_snd_device) - return -ENOMEM; - - platform_set_drvdata(openrd_client_snd_device, - &openrd_client); - - ret = platform_device_add(openrd_client_snd_device); - if (ret) { - printk(KERN_ERR "%s: platform_device_add failed\n", __func__); - platform_device_put(openrd_client_snd_device); - } + 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; } -static void __exit openrd_client_exit(void) +static int __devexit openrd_remove(struct platform_device *pdev) { - platform_device_unregister(openrd_client_snd_device); + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + return 0; } -module_init(openrd_client_init); -module_exit(openrd_client_exit); +static struct platform_driver openrd_driver = { + .driver = { + .name = "openrd-client-audio", + .owner = THIS_MODULE, + }, + .probe = openrd_probe, + .remove = __devexit_p(openrd_remove), +}; + +module_platform_driver(openrd_driver); /* Module information */ MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); MODULE_DESCRIPTION("ALSA SoC OpenRD Client"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:soc-audio"); +MODULE_ALIAS("platform:openrd-client-audio"); diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c index b47cc4e9b74..f8983635f7e 100644 --- a/sound/soc/kirkwood/kirkwood-t5325.c +++ b/sound/soc/kirkwood/kirkwood-t5325.c @@ -80,7 +80,6 @@ static struct snd_soc_dai_link t5325_dai[] = { }, }; - static struct snd_soc_card t5325 = { .name = "t5325", .owner = THIS_MODULE, @@ -93,38 +92,40 @@ static struct snd_soc_card t5325 = { .num_dapm_routes = ARRAY_SIZE(t5325_route), }; -static struct platform_device *t5325_snd_device; - -static int __init t5325_init(void) +static int __devinit t5325_probe(struct platform_device *pdev) { + struct snd_soc_card *card = &t5325; int ret; - if (!machine_is_t5325()) - return 0; - - t5325_snd_device = platform_device_alloc("soc-audio", -1); - if (!t5325_snd_device) - return -ENOMEM; - - platform_set_drvdata(t5325_snd_device, - &t5325); - - ret = platform_device_add(t5325_snd_device); - if (ret) { - printk(KERN_ERR "%s: platform_device_add failed\n", __func__); - platform_device_put(t5325_snd_device); - } + 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; } -module_init(t5325_init); -static void __exit t5325_exit(void) +static int __devexit t5325_remove(struct platform_device *pdev) { - platform_device_unregister(t5325_snd_device); + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + return 0; } -module_exit(t5325_exit); + +static struct platform_driver t5325_driver = { + .driver = { + .name = "t5325-audio", + .owner = THIS_MODULE, + }, + .probe = t5325_probe, + .remove = __devexit_p(t5325_remove), +}; + +module_platform_driver(t5325_driver); MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); MODULE_DESCRIPTION("ALSA SoC t5325 audio client"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:t5325-audio"); diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c index 6f77eef0f13..2937e54da49 100644 --- a/sound/soc/mid-x86/mfld_machine.c +++ b/sound/soc/mid-x86/mfld_machine.c @@ -235,7 +235,7 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime) snd_soc_dapm_enable_pin(dapm, "Headphones"); snd_soc_dapm_enable_pin(dapm, "Mic"); - ret_val = snd_soc_add_controls(codec, mfld_snd_controls, + ret_val = snd_soc_add_codec_controls(codec, mfld_snd_controls, ARRAY_SIZE(mfld_snd_controls)); if (ret_val) { pr_err("soc_add_controls failed %d", ret_val); diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig index e4ba8d5f25f..99a997f19bb 100644 --- a/sound/soc/mxs/Kconfig +++ b/sound/soc/mxs/Kconfig @@ -1,7 +1,7 @@ menuconfig SND_MXS_SOC tristate "SoC Audio for Freescale MXS CPUs" depends on ARCH_MXS - select SND_PCM + select SND_SOC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to the MXS SAIF interface. diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c index 105f42a394d..6ca1f46d84a 100644 --- a/sound/soc/mxs/mxs-pcm.c +++ b/sound/soc/mxs/mxs-pcm.c @@ -34,10 +34,16 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/dmaengine_pcm.h> #include <mach/dma.h> #include "mxs-pcm.h" +struct mxs_pcm_dma_data { + struct mxs_dma_data dma_data; + struct mxs_pcm_dma_params *dma_params; +}; + static struct snd_pcm_hardware snd_mxs_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -58,21 +64,10 @@ static struct snd_pcm_hardware snd_mxs_hardware = { }; -static void audio_dma_irq(void *data) -{ - struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct mxs_pcm_runtime_data *iprtd = runtime->private_data; - - iprtd->offset += iprtd->period_bytes; - iprtd->offset %= iprtd->period_bytes * iprtd->periods; - snd_pcm_period_elapsed(substream); -} - static bool filter(struct dma_chan *chan, void *param) { - struct mxs_pcm_runtime_data *iprtd = param; - struct mxs_pcm_dma_params *dma_params = iprtd->dma_params; + struct mxs_pcm_dma_data *pcm_dma_data = param; + struct mxs_pcm_dma_params *dma_params = pcm_dma_data->dma_params; if (!mxs_dma_is_apbx(chan)) return false; @@ -80,150 +75,51 @@ static bool filter(struct dma_chan *chan, void *param) if (chan->chan_id != dma_params->chan_num) return false; - chan->private = &iprtd->dma_data; + chan->private = &pcm_dma_data->dma_data; return true; } -static int mxs_dma_alloc(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct mxs_pcm_runtime_data *iprtd = runtime->private_data; - dma_cap_mask_t mask; - - iprtd->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - iprtd->dma_data.chan_irq = iprtd->dma_params->chan_irq; - iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); - if (!iprtd->dma_chan) - return -EINVAL; - - return 0; -} - static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct mxs_pcm_runtime_data *iprtd = runtime->private_data; - unsigned long dma_addr; - struct dma_chan *chan; - int ret; - - ret = mxs_dma_alloc(substream, params); - if (ret) - return ret; - chan = iprtd->dma_chan; - - iprtd->size = params_buffer_bytes(params); - iprtd->periods = params_periods(params); - iprtd->period_bytes = params_period_bytes(params); - iprtd->offset = 0; - iprtd->period_time = HZ / (params_rate(params) / - params_period_size(params)); - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - dma_addr = runtime->dma_addr; - - iprtd->buf = substream->dma_buffer.area; - - iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr, - iprtd->period_bytes * iprtd->periods, - iprtd->period_bytes, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); - if (!iprtd->desc) { - dev_err(&chan->dev->device, "cannot prepare slave dma\n"); - return -EINVAL; - } - - iprtd->desc->callback = audio_dma_irq; - iprtd->desc->callback_param = substream; - - return 0; -} - -static int snd_mxs_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mxs_pcm_runtime_data *iprtd = runtime->private_data; - - if (iprtd->dma_chan) { - dma_release_channel(iprtd->dma_chan); - iprtd->dma_chan = NULL; - } - - return 0; -} - -static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mxs_pcm_runtime_data *iprtd = runtime->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - dmaengine_submit(iprtd->desc); - - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - dmaengine_terminate_all(iprtd->dma_chan); - - break; - default: - return -EINVAL; - } - return 0; } -static snd_pcm_uframes_t snd_mxs_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct mxs_pcm_runtime_data *iprtd = runtime->private_data; - - return bytes_to_frames(substream->runtime, iprtd->offset); -} - static int snd_mxs_open(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct mxs_pcm_runtime_data *iprtd; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mxs_pcm_dma_data *pcm_dma_data; int ret; - iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); - if (iprtd == NULL) + pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL); + if (pcm_dma_data == NULL) return -ENOMEM; - runtime->private_data = iprtd; - ret = snd_pcm_hw_constraint_integer(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) { - kfree(iprtd); + pcm_dma_data->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + pcm_dma_data->dma_data.chan_irq = pcm_dma_data->dma_params->chan_irq; + + ret = snd_dmaengine_pcm_open(substream, filter, pcm_dma_data); + if (ret) { + kfree(pcm_dma_data); return ret; } snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); + snd_dmaengine_pcm_set_data(substream, pcm_dma_data); + return 0; } static int snd_mxs_close(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct mxs_pcm_runtime_data *iprtd = runtime->private_data; + struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream); - kfree(iprtd); + snd_dmaengine_pcm_close(substream); + kfree(pcm_dma_data); return 0; } @@ -244,9 +140,8 @@ static struct snd_pcm_ops mxs_pcm_ops = { .close = snd_mxs_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_mxs_pcm_hw_params, - .hw_free = snd_mxs_pcm_hw_free, - .trigger = snd_mxs_pcm_trigger, - .pointer = snd_mxs_pcm_pointer, + .trigger = snd_dmaengine_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer, .mmap = snd_mxs_pcm_mmap, }; diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h index f55ac4f7a76..5f01a9124b3 100644 --- a/sound/soc/mxs/mxs-pcm.h +++ b/sound/soc/mxs/mxs-pcm.h @@ -19,25 +19,9 @@ #ifndef _MXS_PCM_H #define _MXS_PCM_H -#include <mach/dma.h> - struct mxs_pcm_dma_params { int chan_irq; int chan_num; }; -struct mxs_pcm_runtime_data { - int period_bytes; - int periods; - int dma; - unsigned long offset; - unsigned long size; - void *buf; - int period_time; - struct dma_async_tx_descriptor *desc; - struct dma_chan *dma_chan; - struct mxs_dma_data dma_data; - struct mxs_pcm_dma_params *dma_params; -}; - #endif diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index f204dbac11d..12be05b1688 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -630,7 +630,7 @@ static int mxs_saif_probe(struct platform_device *pdev) if (pdev->id >= ARRAY_SIZE(mxs_saif)) return -EINVAL; - saif = kzalloc(sizeof(*saif), GFP_KERNEL); + saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL); if (!saif) return -ENOMEM; @@ -655,29 +655,16 @@ static int mxs_saif_probe(struct platform_device *pdev) ret = PTR_ERR(saif->clk); dev_err(&pdev->dev, "Cannot get the clock: %d\n", ret); - goto failed_clk; + return ret; } iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) { - ret = -ENODEV; - dev_err(&pdev->dev, "failed to get io resource: %d\n", - ret); - goto failed_get_resource; - } - if (!request_mem_region(iores->start, resource_size(iores), - "mxs-saif")) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - ret = -EBUSY; - goto failed_get_resource; - } - - saif->base = ioremap(iores->start, resource_size(iores)); + saif->base = devm_request_and_ioremap(&pdev->dev, iores); if (!saif->base) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENODEV; - goto failed_ioremap; + goto failed_get_resource; } dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -685,7 +672,7 @@ static int mxs_saif_probe(struct platform_device *pdev) ret = -ENODEV; dev_err(&pdev->dev, "failed to get dma resource: %d\n", ret); - goto failed_ioremap; + goto failed_get_resource; } saif->dma_param.chan_num = dmares->start; @@ -694,14 +681,15 @@ static int mxs_saif_probe(struct platform_device *pdev) ret = saif->irq; dev_err(&pdev->dev, "failed to get irq resource: %d\n", ret); - goto failed_get_irq1; + goto failed_get_resource; } saif->dev = &pdev->dev; - ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif); + ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0, + "mxs-saif", saif); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); - goto failed_get_irq1; + goto failed_get_resource; } saif->dma_param.chan_irq = platform_get_irq(pdev, 1); @@ -709,7 +697,7 @@ static int mxs_saif_probe(struct platform_device *pdev) ret = saif->dma_param.chan_irq; dev_err(&pdev->dev, "failed to get dma irq resource: %d\n", ret); - goto failed_get_irq2; + goto failed_get_resource; } platform_set_drvdata(pdev, saif); @@ -717,7 +705,7 @@ static int mxs_saif_probe(struct platform_device *pdev) ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); - goto failed_register; + goto failed_get_resource; } saif->soc_platform_pdev = platform_device_alloc( @@ -740,36 +728,19 @@ failed_pdev_add: platform_device_put(saif->soc_platform_pdev); failed_pdev_alloc: snd_soc_unregister_dai(&pdev->dev); -failed_register: -failed_get_irq2: - free_irq(saif->irq, saif); -failed_get_irq1: - iounmap(saif->base); -failed_ioremap: - release_mem_region(iores->start, resource_size(iores)); failed_get_resource: clk_put(saif->clk); -failed_clk: - kfree(saif); return ret; } static int __devexit mxs_saif_remove(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct mxs_saif *saif = platform_get_drvdata(pdev); platform_device_unregister(saif->soc_platform_pdev); - snd_soc_unregister_dai(&pdev->dev); - - iounmap(saif->base); - release_mem_region(res->start, resource_size(res)); - free_irq(saif->irq, saif); - clk_put(saif->clk); - kfree(saif); return 0; } diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index fb1bf2581ef..e00dd0b1139 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -7,7 +7,6 @@ config SND_OMAP_SOC_DMIC config SND_OMAP_SOC_MCBSP tristate - select OMAP_MCBSP config SND_OMAP_SOC_MCPDM tristate @@ -27,7 +26,6 @@ config SND_OMAP_SOC_N810 config SND_OMAP_SOC_RX51 tristate "SoC Audio support for Nokia RX-51" depends on SND_OMAP_SOC && MACH_NOKIA_RX51 - select OMAP_MCBSP select SND_OMAP_SOC_MCBSP select SND_SOC_TLV320AIC3X select SND_SOC_TPA6130A2 @@ -97,16 +95,19 @@ config SND_OMAP_SOC_SDP3430 Say Y if you want to add support for SoC audio on Texas Instruments SDP3430. -config SND_OMAP_SOC_SDP4430 - tristate "SoC Audio support for Texas Instruments SDP4430" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_4430SDP +config SND_OMAP_SOC_OMAP_ABE_TWL6040 + tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" + depends on TWL4030_CORE && SND_OMAP_SOC && ARCH_OMAP4 select SND_OMAP_SOC_DMIC select SND_OMAP_SOC_MCPDM select SND_SOC_TWL6040 select SND_SOC_DMIC help - Say Y if you want to add support for SoC audio on Texas Instruments - SDP4430. + Say Y if you want to add support for SoC audio on OMAP boards using + ABE and twl6040 codec. This driver currently supports: + - SDP4430/Blaze boards + - PandaBoard (4430) + - PandaBoardES (4460) config SND_OMAP_SOC_OMAP4_HDMI tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 1fd723fb559..1d656bce01d 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -1,7 +1,7 @@ # OMAP Platform Support snd-soc-omap-objs := omap-pcm.o snd-soc-omap-dmic-objs := omap-dmic.o -snd-soc-omap-mcbsp-objs := omap-mcbsp.o +snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o snd-soc-omap-mcpdm-objs := omap-mcpdm.o snd-soc-omap-hdmi-objs := omap-hdmi.o @@ -20,7 +20,7 @@ snd-soc-overo-objs := overo.o snd-soc-omap3evm-objs := omap3evm.o snd-soc-am3517evm-objs := am3517evm.o snd-soc-sdp3430-objs := sdp3430.o -snd-soc-sdp4430-objs := sdp4430.o +snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-zoom2-objs := zoom2.o @@ -36,7 +36,7 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3EVM) += snd-soc-omap3evm.o obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o -obj-$(CONFIG_SND_OMAP_SOC_SDP4430) += snd-soc-sdp4430.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c index add4866d7e6..009533ab8d1 100644 --- a/sound/soc/omap/am3517evm.c +++ b/sound/soc/omap/am3517evm.c @@ -95,7 +95,7 @@ static const struct snd_soc_dapm_route audio_map[] = { static struct snd_soc_dai_link am3517evm_dai = { .name = "TLV320AIC23", .stream_name = "AIC23", - .cpu_dai_name ="omap-mcbsp-dai.0", + .cpu_dai_name = "omap-mcbsp.1", .codec_dai_name = "tlv320aic23-hifi", .platform_name = "omap-pcm-audio", .codec_name = "tlv320aic23-codec.2-001a", diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index a67f4370bc9..49fe63ce51f 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -570,7 +570,7 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_disable_pin(dapm, "AGCOUT"); /* Add virtual switch */ - ret = snd_soc_add_controls(codec, ams_delta_audio_controls, + ret = snd_soc_add_codec_controls(codec, ams_delta_audio_controls, ARRAY_SIZE(ams_delta_audio_controls)); if (ret) dev_warn(card->dev, @@ -584,7 +584,7 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link ams_delta_dai_link = { .name = "CX20442", .stream_name = "CX20442", - .cpu_dai_name ="omap-mcbsp-dai.0", + .cpu_dai_name = "omap-mcbsp.1", .codec_dai_name = "cx20442-voice", .init = ams_delta_cx20442_init, .platform_name = "omap-pcm-audio", diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c index ccae58a1339..e8357819175 100644 --- a/sound/soc/omap/igep0020.c +++ b/sound/soc/omap/igep0020.c @@ -60,7 +60,7 @@ static struct snd_soc_ops igep2_ops = { static struct snd_soc_dai_link igep2_dai = { .name = "TWL4030", .stream_name = "TWL4030", - .cpu_dai_name = "omap-mcbsp-dai.1", + .cpu_dai_name = "omap-mcbsp.2", .codec_dai_name = "twl4030-hifi", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c new file mode 100644 index 00000000000..e5f44440d1b --- /dev/null +++ b/sound/soc/omap/mcbsp.c @@ -0,0 +1,1040 @@ +/* + * sound/soc/omap/mcbsp.c + * + * Copyright (C) 2004 Nokia Corporation + * Author: Samuel Ortiz <samuel.ortiz@nokia.com> + * + * Contact: Jarkko Nikula <jarkko.nikula@bitmer.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 version 2 as + * published by the Free Software Foundation. + * + * Multichannel mode not supported. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/slab.h> + +#include <plat/mcbsp.h> + +#include "mcbsp.h" + +static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) +{ + void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; + + if (mcbsp->pdata->reg_size == 2) { + ((u16 *)mcbsp->reg_cache)[reg] = (u16)val; + __raw_writew((u16)val, addr); + } else { + ((u32 *)mcbsp->reg_cache)[reg] = val; + __raw_writel(val, addr); + } +} + +static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache) +{ + void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; + + if (mcbsp->pdata->reg_size == 2) { + return !from_cache ? __raw_readw(addr) : + ((u16 *)mcbsp->reg_cache)[reg]; + } else { + return !from_cache ? __raw_readl(addr) : + ((u32 *)mcbsp->reg_cache)[reg]; + } +} + +static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) +{ + __raw_writel(val, mcbsp->st_data->io_base_st + reg); +} + +static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg) +{ + return __raw_readl(mcbsp->st_data->io_base_st + reg); +} + +#define MCBSP_READ(mcbsp, reg) \ + omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) +#define MCBSP_WRITE(mcbsp, reg, val) \ + omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) +#define MCBSP_READ_CACHE(mcbsp, reg) \ + omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1) + +#define MCBSP_ST_READ(mcbsp, reg) \ + omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg) +#define MCBSP_ST_WRITE(mcbsp, reg, val) \ + omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val) + +static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp) +{ + dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id); + dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", + MCBSP_READ(mcbsp, DRR2)); + dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", + MCBSP_READ(mcbsp, DRR1)); + dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", + MCBSP_READ(mcbsp, DXR2)); + dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", + MCBSP_READ(mcbsp, DXR1)); + dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", + MCBSP_READ(mcbsp, SPCR2)); + dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", + MCBSP_READ(mcbsp, SPCR1)); + dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", + MCBSP_READ(mcbsp, RCR2)); + dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", + MCBSP_READ(mcbsp, RCR1)); + dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", + MCBSP_READ(mcbsp, XCR2)); + dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", + MCBSP_READ(mcbsp, XCR1)); + dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", + MCBSP_READ(mcbsp, SRGR2)); + dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", + MCBSP_READ(mcbsp, SRGR1)); + dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", + MCBSP_READ(mcbsp, PCR0)); + dev_dbg(mcbsp->dev, "***********************\n"); +} + +static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) +{ + struct omap_mcbsp *mcbsp_tx = dev_id; + u16 irqst_spcr2; + + irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2); + dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2); + + if (irqst_spcr2 & XSYNC_ERR) { + dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n", + irqst_spcr2); + /* Writing zero to XSYNC_ERR clears the IRQ */ + MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2)); + } + + return IRQ_HANDLED; +} + +static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id) +{ + struct omap_mcbsp *mcbsp_rx = dev_id; + u16 irqst_spcr1; + + irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1); + dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1); + + if (irqst_spcr1 & RSYNC_ERR) { + dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n", + irqst_spcr1); + /* Writing zero to RSYNC_ERR clears the IRQ */ + MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1)); + } + + return IRQ_HANDLED; +} + +/* + * omap_mcbsp_config simply write a config to the + * appropriate McBSP. + * You either call this function or set the McBSP registers + * by yourself before calling omap_mcbsp_start(). + */ +void omap_mcbsp_config(struct omap_mcbsp *mcbsp, + const struct omap_mcbsp_reg_cfg *config) +{ + dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n", + mcbsp->id, mcbsp->phys_base); + + /* We write the given config */ + MCBSP_WRITE(mcbsp, SPCR2, config->spcr2); + MCBSP_WRITE(mcbsp, SPCR1, config->spcr1); + MCBSP_WRITE(mcbsp, RCR2, config->rcr2); + MCBSP_WRITE(mcbsp, RCR1, config->rcr1); + MCBSP_WRITE(mcbsp, XCR2, config->xcr2); + MCBSP_WRITE(mcbsp, XCR1, config->xcr1); + MCBSP_WRITE(mcbsp, SRGR2, config->srgr2); + MCBSP_WRITE(mcbsp, SRGR1, config->srgr1); + MCBSP_WRITE(mcbsp, MCR2, config->mcr2); + MCBSP_WRITE(mcbsp, MCR1, config->mcr1); + MCBSP_WRITE(mcbsp, PCR0, config->pcr0); + if (mcbsp->pdata->has_ccr) { + MCBSP_WRITE(mcbsp, XCCR, config->xccr); + MCBSP_WRITE(mcbsp, RCCR, config->rccr); + } + /* Enable wakeup behavior */ + if (mcbsp->pdata->has_wakeup) + MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); +} + +/** + * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register + * @id - mcbsp id + * @stream - indicates the direction of data flow (rx or tx) + * + * Returns the address of mcbsp data transmit register or data receive register + * to be used by DMA for transferring/receiving data based on the value of + * @stream for the requested mcbsp given by @id + */ +static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp, + unsigned int stream) +{ + int data_reg; + + if (mcbsp->pdata->reg_size == 2) { + if (stream) + data_reg = OMAP_MCBSP_REG_DRR1; + else + data_reg = OMAP_MCBSP_REG_DXR1; + } else { + if (stream) + data_reg = OMAP_MCBSP_REG_DRR; + else + data_reg = OMAP_MCBSP_REG_DXR; + } + + return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step; +} + +static void omap_st_on(struct omap_mcbsp *mcbsp) +{ + unsigned int w; + + if (mcbsp->pdata->enable_st_clock) + mcbsp->pdata->enable_st_clock(mcbsp->id, 1); + + /* Enable McBSP Sidetone */ + w = MCBSP_READ(mcbsp, SSELCR); + MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); + + /* Enable Sidetone from Sidetone Core */ + w = MCBSP_ST_READ(mcbsp, SSELCR); + MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN); +} + +static void omap_st_off(struct omap_mcbsp *mcbsp) +{ + unsigned int w; + + w = MCBSP_ST_READ(mcbsp, SSELCR); + MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN)); + + w = MCBSP_READ(mcbsp, SSELCR); + MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); + + if (mcbsp->pdata->enable_st_clock) + mcbsp->pdata->enable_st_clock(mcbsp->id, 0); +} + +static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir) +{ + u16 val, i; + + val = MCBSP_ST_READ(mcbsp, SSELCR); + + if (val & ST_COEFFWREN) + MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); + + MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN); + + for (i = 0; i < 128; i++) + MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]); + + i = 0; + + val = MCBSP_ST_READ(mcbsp, SSELCR); + while (!(val & ST_COEFFWRDONE) && (++i < 1000)) + val = MCBSP_ST_READ(mcbsp, SSELCR); + + MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); + + if (i == 1000) + dev_err(mcbsp->dev, "McBSP FIR load error!\n"); +} + +static void omap_st_chgain(struct omap_mcbsp *mcbsp) +{ + u16 w; + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + + w = MCBSP_ST_READ(mcbsp, SSELCR); + + MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \ + ST_CH1GAIN(st_data->ch1gain)); +} + +int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + int ret = 0; + + if (!st_data) + return -ENOENT; + + spin_lock_irq(&mcbsp->lock); + if (channel == 0) + st_data->ch0gain = chgain; + else if (channel == 1) + st_data->ch1gain = chgain; + else + ret = -EINVAL; + + if (st_data->enabled) + omap_st_chgain(mcbsp); + spin_unlock_irq(&mcbsp->lock); + + return ret; +} + +int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + int ret = 0; + + if (!st_data) + return -ENOENT; + + spin_lock_irq(&mcbsp->lock); + if (channel == 0) + *chgain = st_data->ch0gain; + else if (channel == 1) + *chgain = st_data->ch1gain; + else + ret = -EINVAL; + spin_unlock_irq(&mcbsp->lock); + + return ret; +} + +static int omap_st_start(struct omap_mcbsp *mcbsp) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + + if (st_data->enabled && !st_data->running) { + omap_st_fir_write(mcbsp, st_data->taps); + omap_st_chgain(mcbsp); + + if (!mcbsp->free) { + omap_st_on(mcbsp); + st_data->running = 1; + } + } + + return 0; +} + +int omap_st_enable(struct omap_mcbsp *mcbsp) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + + if (!st_data) + return -ENODEV; + + spin_lock_irq(&mcbsp->lock); + st_data->enabled = 1; + omap_st_start(mcbsp); + spin_unlock_irq(&mcbsp->lock); + + return 0; +} + +static int omap_st_stop(struct omap_mcbsp *mcbsp) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + + if (st_data->running) { + if (!mcbsp->free) { + omap_st_off(mcbsp); + st_data->running = 0; + } + } + + return 0; +} + +int omap_st_disable(struct omap_mcbsp *mcbsp) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + int ret = 0; + + if (!st_data) + return -ENODEV; + + spin_lock_irq(&mcbsp->lock); + omap_st_stop(mcbsp); + st_data->enabled = 0; + spin_unlock_irq(&mcbsp->lock); + + return ret; +} + +int omap_st_is_enabled(struct omap_mcbsp *mcbsp) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + + if (!st_data) + return -ENODEV; + + return st_data->enabled; +} + +/* + * omap_mcbsp_set_rx_threshold configures the transmit threshold in words. + * The threshold parameter is 1 based, and it is converted (threshold - 1) + * for the THRSH2 register. + */ +void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) +{ + if (mcbsp->pdata->buffer_size == 0) + return; + + if (threshold && threshold <= mcbsp->max_tx_thres) + MCBSP_WRITE(mcbsp, THRSH2, threshold - 1); +} + +/* + * omap_mcbsp_set_rx_threshold configures the receive threshold in words. + * The threshold parameter is 1 based, and it is converted (threshold - 1) + * for the THRSH1 register. + */ +void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) +{ + if (mcbsp->pdata->buffer_size == 0) + return; + + if (threshold && threshold <= mcbsp->max_rx_thres) + MCBSP_WRITE(mcbsp, THRSH1, threshold - 1); +} + +/* + * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO + */ +u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp) +{ + u16 buffstat; + + if (mcbsp->pdata->buffer_size == 0) + return 0; + + /* Returns the number of free locations in the buffer */ + buffstat = MCBSP_READ(mcbsp, XBUFFSTAT); + + /* Number of slots are different in McBSP ports */ + return mcbsp->pdata->buffer_size - buffstat; +} + +/* + * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO + * to reach the threshold value (when the DMA will be triggered to read it) + */ +u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp) +{ + u16 buffstat, threshold; + + if (mcbsp->pdata->buffer_size == 0) + return 0; + + /* Returns the number of used locations in the buffer */ + buffstat = MCBSP_READ(mcbsp, RBUFFSTAT); + /* RX threshold */ + threshold = MCBSP_READ(mcbsp, THRSH1); + + /* Return the number of location till we reach the threshold limit */ + if (threshold <= buffstat) + return 0; + else + return threshold - buffstat; +} + +int omap_mcbsp_request(struct omap_mcbsp *mcbsp) +{ + void *reg_cache; + int err; + + reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL); + if (!reg_cache) { + return -ENOMEM; + } + + spin_lock(&mcbsp->lock); + if (!mcbsp->free) { + dev_err(mcbsp->dev, "McBSP%d is currently in use\n", + mcbsp->id); + err = -EBUSY; + goto err_kfree; + } + + mcbsp->free = false; + mcbsp->reg_cache = reg_cache; + spin_unlock(&mcbsp->lock); + + if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) + mcbsp->pdata->ops->request(mcbsp->id - 1); + + /* + * Make sure that transmitter, receiver and sample-rate generator are + * not running before activating IRQs. + */ + MCBSP_WRITE(mcbsp, SPCR1, 0); + MCBSP_WRITE(mcbsp, SPCR2, 0); + + err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, + 0, "McBSP", (void *)mcbsp); + if (err != 0) { + dev_err(mcbsp->dev, "Unable to request TX IRQ %d " + "for McBSP%d\n", mcbsp->tx_irq, + mcbsp->id); + goto err_clk_disable; + } + + if (mcbsp->rx_irq) { + err = request_irq(mcbsp->rx_irq, + omap_mcbsp_rx_irq_handler, + 0, "McBSP", (void *)mcbsp); + if (err != 0) { + dev_err(mcbsp->dev, "Unable to request RX IRQ %d " + "for McBSP%d\n", mcbsp->rx_irq, + mcbsp->id); + goto err_free_irq; + } + } + + return 0; +err_free_irq: + free_irq(mcbsp->tx_irq, (void *)mcbsp); +err_clk_disable: + if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) + mcbsp->pdata->ops->free(mcbsp->id - 1); + + /* Disable wakeup behavior */ + if (mcbsp->pdata->has_wakeup) + MCBSP_WRITE(mcbsp, WAKEUPEN, 0); + + spin_lock(&mcbsp->lock); + mcbsp->free = true; + mcbsp->reg_cache = NULL; +err_kfree: + spin_unlock(&mcbsp->lock); + kfree(reg_cache); + + return err; +} + +void omap_mcbsp_free(struct omap_mcbsp *mcbsp) +{ + void *reg_cache; + + if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) + mcbsp->pdata->ops->free(mcbsp->id - 1); + + /* Disable wakeup behavior */ + if (mcbsp->pdata->has_wakeup) + MCBSP_WRITE(mcbsp, WAKEUPEN, 0); + + if (mcbsp->rx_irq) + free_irq(mcbsp->rx_irq, (void *)mcbsp); + free_irq(mcbsp->tx_irq, (void *)mcbsp); + + reg_cache = mcbsp->reg_cache; + + /* + * Select CLKS source from internal source unconditionally before + * marking the McBSP port as free. + * If the external clock source via MCBSP_CLKS pin has been selected the + * system will refuse to enter idle if the CLKS pin source is not reset + * back to internal source. + */ + if (!cpu_class_is_omap1()) + omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); + + spin_lock(&mcbsp->lock); + if (mcbsp->free) + dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); + else + mcbsp->free = true; + mcbsp->reg_cache = NULL; + spin_unlock(&mcbsp->lock); + + if (reg_cache) + kfree(reg_cache); +} + +/* + * Here we start the McBSP, by enabling transmitter, receiver or both. + * If no transmitter or receiver is active prior calling, then sample-rate + * generator and frame sync are started. + */ +void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx) +{ + int enable_srg = 0; + u16 w; + + if (mcbsp->st_data) + omap_st_start(mcbsp); + + /* Only enable SRG, if McBSP is master */ + w = MCBSP_READ_CACHE(mcbsp, PCR0); + if (w & (FSXM | FSRM | CLKXM | CLKRM)) + enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | + MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); + + if (enable_srg) { + /* Start the sample generator */ + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); + } + + /* Enable transmitter and receiver */ + tx &= 1; + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w | tx); + + rx &= 1; + w = MCBSP_READ_CACHE(mcbsp, SPCR1); + MCBSP_WRITE(mcbsp, SPCR1, w | rx); + + /* + * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec + * REVISIT: 100us may give enough time for two CLKSRG, however + * due to some unknown PM related, clock gating etc. reason it + * is now at 500us. + */ + udelay(500); + + if (enable_srg) { + /* Start frame sync */ + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); + } + + if (mcbsp->pdata->has_ccr) { + /* Release the transmitter and receiver */ + w = MCBSP_READ_CACHE(mcbsp, XCCR); + w &= ~(tx ? XDISABLE : 0); + MCBSP_WRITE(mcbsp, XCCR, w); + w = MCBSP_READ_CACHE(mcbsp, RCCR); + w &= ~(rx ? RDISABLE : 0); + MCBSP_WRITE(mcbsp, RCCR, w); + } + + /* Dump McBSP Regs */ + omap_mcbsp_dump_reg(mcbsp); +} + +void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx) +{ + int idle; + u16 w; + + /* Reset transmitter */ + tx &= 1; + if (mcbsp->pdata->has_ccr) { + w = MCBSP_READ_CACHE(mcbsp, XCCR); + w |= (tx ? XDISABLE : 0); + MCBSP_WRITE(mcbsp, XCCR, w); + } + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); + + /* Reset receiver */ + rx &= 1; + if (mcbsp->pdata->has_ccr) { + w = MCBSP_READ_CACHE(mcbsp, RCCR); + w |= (rx ? RDISABLE : 0); + MCBSP_WRITE(mcbsp, RCCR, w); + } + w = MCBSP_READ_CACHE(mcbsp, SPCR1); + MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); + + idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | + MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); + + if (idle) { + /* Reset the sample rate generator */ + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); + } + + if (mcbsp->st_data) + omap_st_stop(mcbsp); +} + +int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id) +{ + const char *src; + + if (fck_src_id == MCBSP_CLKS_PAD_SRC) + src = "clks_ext"; + else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) + src = "clks_fclk"; + else + return -EINVAL; + + if (mcbsp->pdata->set_clk_src) + return mcbsp->pdata->set_clk_src(mcbsp->dev, mcbsp->fclk, src); + else + return -EINVAL; +} + +int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux) +{ + const char *signal, *src; + + if (mcbsp->pdata->mux_signal) + return -EINVAL; + + switch (mux) { + case CLKR_SRC_CLKR: + signal = "clkr"; + src = "clkr"; + break; + case CLKR_SRC_CLKX: + signal = "clkr"; + src = "clkx"; + break; + case FSR_SRC_FSR: + signal = "fsr"; + src = "fsr"; + break; + case FSR_SRC_FSX: + signal = "fsr"; + src = "fsx"; + break; + default: + return -EINVAL; + } + + return mcbsp->pdata->mux_signal(mcbsp->dev, signal, src); +} + +#define max_thres(m) (mcbsp->pdata->buffer_size) +#define valid_threshold(m, val) ((val) <= max_thres(m)) +#define THRESHOLD_PROP_BUILDER(prop) \ +static ssize_t prop##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ + \ + return sprintf(buf, "%u\n", mcbsp->prop); \ +} \ + \ +static ssize_t prop##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t size) \ +{ \ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ + unsigned long val; \ + int status; \ + \ + status = strict_strtoul(buf, 0, &val); \ + if (status) \ + return status; \ + \ + if (!valid_threshold(mcbsp, val)) \ + return -EDOM; \ + \ + mcbsp->prop = val; \ + return size; \ +} \ + \ +static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store); + +THRESHOLD_PROP_BUILDER(max_tx_thres); +THRESHOLD_PROP_BUILDER(max_rx_thres); + +static const char *dma_op_modes[] = { + "element", "threshold", "frame", +}; + +static ssize_t dma_op_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); + int dma_op_mode, i = 0; + ssize_t len = 0; + const char * const *s; + + dma_op_mode = mcbsp->dma_op_mode; + + for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) { + if (dma_op_mode == i) + len += sprintf(buf + len, "[%s] ", *s); + else + len += sprintf(buf + len, "%s ", *s); + } + len += sprintf(buf + len, "\n"); + + return len; +} + +static ssize_t dma_op_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); + const char * const *s; + int i = 0; + + for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) + if (sysfs_streq(buf, *s)) + break; + + if (i == ARRAY_SIZE(dma_op_modes)) + return -EINVAL; + + spin_lock_irq(&mcbsp->lock); + if (!mcbsp->free) { + size = -EBUSY; + goto unlock; + } + mcbsp->dma_op_mode = i; + +unlock: + spin_unlock_irq(&mcbsp->lock); + + return size; +} + +static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store); + +static const struct attribute *additional_attrs[] = { + &dev_attr_max_tx_thres.attr, + &dev_attr_max_rx_thres.attr, + &dev_attr_dma_op_mode.attr, + NULL, +}; + +static const struct attribute_group additional_attr_group = { + .attrs = (struct attribute **)additional_attrs, +}; + +static ssize_t st_taps_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + ssize_t status = 0; + int i; + + spin_lock_irq(&mcbsp->lock); + for (i = 0; i < st_data->nr_taps; i++) + status += sprintf(&buf[status], (i ? ", %d" : "%d"), + st_data->taps[i]); + if (i) + status += sprintf(&buf[status], "\n"); + spin_unlock_irq(&mcbsp->lock); + + return status; +} + +static ssize_t st_taps_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + int val, tmp, status, i = 0; + + spin_lock_irq(&mcbsp->lock); + memset(st_data->taps, 0, sizeof(st_data->taps)); + st_data->nr_taps = 0; + + do { + status = sscanf(buf, "%d%n", &val, &tmp); + if (status < 0 || status == 0) { + size = -EINVAL; + goto out; + } + if (val < -32768 || val > 32767) { + size = -EINVAL; + goto out; + } + st_data->taps[i++] = val; + buf += tmp; + if (*buf != ',') + break; + buf++; + } while (1); + + st_data->nr_taps = i; + +out: + spin_unlock_irq(&mcbsp->lock); + + return size; +} + +static DEVICE_ATTR(st_taps, 0644, st_taps_show, st_taps_store); + +static const struct attribute *sidetone_attrs[] = { + &dev_attr_st_taps.attr, + NULL, +}; + +static const struct attribute_group sidetone_attr_group = { + .attrs = (struct attribute **)sidetone_attrs, +}; + +static int __devinit omap_st_add(struct omap_mcbsp *mcbsp, + struct resource *res) +{ + struct omap_mcbsp_st_data *st_data; + int err; + + st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL); + if (!st_data) + return -ENOMEM; + + st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start, + resource_size(res)); + if (!st_data->io_base_st) + return -ENOMEM; + + err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group); + if (err) + return err; + + mcbsp->st_data = st_data; + return 0; +} + +/* + * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. + * 730 has only 2 McBSP, and both of them are MPU peripherals. + */ +int __devinit omap_mcbsp_init(struct platform_device *pdev) +{ + struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); + struct resource *res; + int ret = 0; + + spin_lock_init(&mcbsp->lock); + mcbsp->free = true; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); + if (!res) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(mcbsp->dev, "invalid memory resource\n"); + return -ENOMEM; + } + } + if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), + dev_name(&pdev->dev))) { + dev_err(mcbsp->dev, "memory region already claimed\n"); + return -ENODEV; + } + + mcbsp->phys_base = res->start; + mcbsp->reg_cache_size = resource_size(res); + mcbsp->io_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!mcbsp->io_base) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); + if (!res) + mcbsp->phys_dma_base = mcbsp->phys_base; + else + mcbsp->phys_dma_base = res->start; + + mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx"); + mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx"); + + /* From OMAP4 there will be a single irq line */ + if (mcbsp->tx_irq == -ENXIO) { + mcbsp->tx_irq = platform_get_irq(pdev, 0); + mcbsp->rx_irq = 0; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); + if (!res) { + dev_err(&pdev->dev, "invalid rx DMA channel\n"); + return -ENODEV; + } + /* RX DMA request number, and port address configuration */ + mcbsp->dma_data[1].name = "Audio Capture"; + mcbsp->dma_data[1].dma_req = res->start; + mcbsp->dma_data[1].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 1); + + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); + if (!res) { + dev_err(&pdev->dev, "invalid tx DMA channel\n"); + return -ENODEV; + } + /* TX DMA request number, and port address configuration */ + mcbsp->dma_data[0].name = "Audio Playback"; + mcbsp->dma_data[0].dma_req = res->start; + mcbsp->dma_data[0].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 0); + + mcbsp->fclk = clk_get(&pdev->dev, "fck"); + if (IS_ERR(mcbsp->fclk)) { + ret = PTR_ERR(mcbsp->fclk); + dev_err(mcbsp->dev, "unable to get fck: %d\n", ret); + return ret; + } + + mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; + if (mcbsp->pdata->buffer_size) { + /* + * Initially configure the maximum thresholds to a safe value. + * The McBSP FIFO usage with these values should not go under + * 16 locations. + * If the whole FIFO without safety buffer is used, than there + * is a possibility that the DMA will be not able to push the + * new data on time, causing channel shifts in runtime. + */ + mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10; + mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10; + + ret = sysfs_create_group(&mcbsp->dev->kobj, + &additional_attr_group); + if (ret) { + dev_err(mcbsp->dev, + "Unable to create additional controls\n"); + goto err_thres; + } + } else { + mcbsp->max_tx_thres = -EINVAL; + mcbsp->max_rx_thres = -EINVAL; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone"); + if (res) { + ret = omap_st_add(mcbsp, res); + if (ret) { + dev_err(mcbsp->dev, + "Unable to create sidetone controls\n"); + goto err_st; + } + } + + return 0; + +err_st: + if (mcbsp->pdata->buffer_size) + sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group); +err_thres: + clk_put(mcbsp->fclk); + return ret; +} + +void __devexit omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp) +{ + if (mcbsp->pdata->buffer_size) + sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group); + + if (mcbsp->st_data) + sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group); +} diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h new file mode 100644 index 00000000000..a944fcc9073 --- /dev/null +++ b/sound/soc/omap/mcbsp.h @@ -0,0 +1,346 @@ +/* + * sound/soc/omap/mcbsp.h + * + * OMAP Multi-Channel Buffered Serial Port + * + * Contact: Jarkko Nikula <jarkko.nikula@bitmer.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 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 __ASOC_MCBSP_H +#define __ASOC_MCBSP_H + +#include "omap-pcm.h" + +/* McBSP register numbers. Register address offset = num * reg_step */ +enum { + /* Common registers */ + OMAP_MCBSP_REG_SPCR2 = 4, + OMAP_MCBSP_REG_SPCR1, + OMAP_MCBSP_REG_RCR2, + OMAP_MCBSP_REG_RCR1, + OMAP_MCBSP_REG_XCR2, + OMAP_MCBSP_REG_XCR1, + OMAP_MCBSP_REG_SRGR2, + OMAP_MCBSP_REG_SRGR1, + OMAP_MCBSP_REG_MCR2, + OMAP_MCBSP_REG_MCR1, + OMAP_MCBSP_REG_RCERA, + OMAP_MCBSP_REG_RCERB, + OMAP_MCBSP_REG_XCERA, + OMAP_MCBSP_REG_XCERB, + OMAP_MCBSP_REG_PCR0, + OMAP_MCBSP_REG_RCERC, + OMAP_MCBSP_REG_RCERD, + OMAP_MCBSP_REG_XCERC, + OMAP_MCBSP_REG_XCERD, + OMAP_MCBSP_REG_RCERE, + OMAP_MCBSP_REG_RCERF, + OMAP_MCBSP_REG_XCERE, + OMAP_MCBSP_REG_XCERF, + OMAP_MCBSP_REG_RCERG, + OMAP_MCBSP_REG_RCERH, + OMAP_MCBSP_REG_XCERG, + OMAP_MCBSP_REG_XCERH, + + /* OMAP1-OMAP2420 registers */ + OMAP_MCBSP_REG_DRR2 = 0, + OMAP_MCBSP_REG_DRR1, + OMAP_MCBSP_REG_DXR2, + OMAP_MCBSP_REG_DXR1, + + /* OMAP2430 and onwards */ + OMAP_MCBSP_REG_DRR = 0, + OMAP_MCBSP_REG_DXR = 2, + OMAP_MCBSP_REG_SYSCON = 35, + OMAP_MCBSP_REG_THRSH2, + OMAP_MCBSP_REG_THRSH1, + OMAP_MCBSP_REG_IRQST = 40, + OMAP_MCBSP_REG_IRQEN, + OMAP_MCBSP_REG_WAKEUPEN, + OMAP_MCBSP_REG_XCCR, + OMAP_MCBSP_REG_RCCR, + OMAP_MCBSP_REG_XBUFFSTAT, + OMAP_MCBSP_REG_RBUFFSTAT, + OMAP_MCBSP_REG_SSELCR, +}; + +/* OMAP3 sidetone control registers */ +#define OMAP_ST_REG_REV 0x00 +#define OMAP_ST_REG_SYSCONFIG 0x10 +#define OMAP_ST_REG_IRQSTATUS 0x18 +#define OMAP_ST_REG_IRQENABLE 0x1C +#define OMAP_ST_REG_SGAINCR 0x24 +#define OMAP_ST_REG_SFIRCR 0x28 +#define OMAP_ST_REG_SSELCR 0x2C + +/************************** McBSP SPCR1 bit definitions ***********************/ +#define RRST BIT(0) +#define RRDY BIT(1) +#define RFULL BIT(2) +#define RSYNC_ERR BIT(3) +#define RINTM(value) (((value) & 0x3) << 4) /* bits 4:5 */ +#define ABIS BIT(6) +#define DXENA BIT(7) +#define CLKSTP(value) (((value) & 0x3) << 11) /* bits 11:12 */ +#define RJUST(value) (((value) & 0x3) << 13) /* bits 13:14 */ +#define ALB BIT(15) +#define DLB BIT(15) + +/************************** McBSP SPCR2 bit definitions ***********************/ +#define XRST BIT(0) +#define XRDY BIT(1) +#define XEMPTY BIT(2) +#define XSYNC_ERR BIT(3) +#define XINTM(value) (((value) & 0x3) << 4) /* bits 4:5 */ +#define GRST BIT(6) +#define FRST BIT(7) +#define SOFT BIT(8) +#define FREE BIT(9) + +/************************** McBSP PCR bit definitions *************************/ +#define CLKRP BIT(0) +#define CLKXP BIT(1) +#define FSRP BIT(2) +#define FSXP BIT(3) +#define DR_STAT BIT(4) +#define DX_STAT BIT(5) +#define CLKS_STAT BIT(6) +#define SCLKME BIT(7) +#define CLKRM BIT(8) +#define CLKXM BIT(9) +#define FSRM BIT(10) +#define FSXM BIT(11) +#define RIOEN BIT(12) +#define XIOEN BIT(13) +#define IDLE_EN BIT(14) + +/************************** McBSP RCR1 bit definitions ************************/ +#define RWDLEN1(value) (((value) & 0x7) << 5) /* Bits 5:7 */ +#define RFRLEN1(value) (((value) & 0x7f) << 8) /* Bits 8:14 */ + +/************************** McBSP XCR1 bit definitions ************************/ +#define XWDLEN1(value) (((value) & 0x7) << 5) /* Bits 5:7 */ +#define XFRLEN1(value) (((value) & 0x7f) << 8) /* Bits 8:14 */ + +/*************************** McBSP RCR2 bit definitions ***********************/ +#define RDATDLY(value) ((value) & 0x3) /* Bits 0:1 */ +#define RFIG BIT(2) +#define RCOMPAND(value) (((value) & 0x3) << 3) /* Bits 3:4 */ +#define RWDLEN2(value) (((value) & 0x7) << 5) /* Bits 5:7 */ +#define RFRLEN2(value) (((value) & 0x7f) << 8) /* Bits 8:14 */ +#define RPHASE BIT(15) + +/*************************** McBSP XCR2 bit definitions ***********************/ +#define XDATDLY(value) ((value) & 0x3) /* Bits 0:1 */ +#define XFIG BIT(2) +#define XCOMPAND(value) (((value) & 0x3) << 3) /* Bits 3:4 */ +#define XWDLEN2(value) (((value) & 0x7) << 5) /* Bits 5:7 */ +#define XFRLEN2(value) (((value) & 0x7f) << 8) /* Bits 8:14 */ +#define XPHASE BIT(15) + +/************************* McBSP SRGR1 bit definitions ************************/ +#define CLKGDV(value) ((value) & 0x7f) /* Bits 0:7 */ +#define FWID(value) (((value) & 0xff) << 8) /* Bits 8:15 */ + +/************************* McBSP SRGR2 bit definitions ************************/ +#define FPER(value) ((value) & 0x0fff) /* Bits 0:11 */ +#define FSGM BIT(12) +#define CLKSM BIT(13) +#define CLKSP BIT(14) +#define GSYNC BIT(15) + +/************************* McBSP MCR1 bit definitions *************************/ +#define RMCM BIT(0) +#define RCBLK(value) (((value) & 0x7) << 2) /* Bits 2:4 */ +#define RPABLK(value) (((value) & 0x3) << 5) /* Bits 5:6 */ +#define RPBBLK(value) (((value) & 0x3) << 7) /* Bits 7:8 */ + +/************************* McBSP MCR2 bit definitions *************************/ +#define XMCM(value) ((value) & 0x3) /* Bits 0:1 */ +#define XCBLK(value) (((value) & 0x7) << 2) /* Bits 2:4 */ +#define XPABLK(value) (((value) & 0x3) << 5) /* Bits 5:6 */ +#define XPBBLK(value) (((value) & 0x3) << 7) /* Bits 7:8 */ + +/*********************** McBSP XCCR bit definitions *************************/ +#define XDISABLE BIT(0) +#define XDMAEN BIT(3) +#define DILB BIT(5) +#define XFULL_CYCLE BIT(11) +#define DXENDLY(value) (((value) & 0x3) << 12) /* Bits 12:13 */ +#define PPCONNECT BIT(14) +#define EXTCLKGATE BIT(15) + +/********************** McBSP RCCR bit definitions *************************/ +#define RDISABLE BIT(0) +#define RDMAEN BIT(3) +#define RFULL_CYCLE BIT(11) + +/********************** McBSP SYSCONFIG bit definitions ********************/ +#define SOFTRST BIT(1) +#define ENAWAKEUP BIT(2) +#define SIDLEMODE(value) (((value) & 0x3) << 3) +#define CLOCKACTIVITY(value) (((value) & 0x3) << 8) + +/********************** McBSP SSELCR bit definitions ***********************/ +#define SIDETONEEN BIT(10) + +/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/ +#define ST_AUTOIDLE BIT(0) + +/********************** McBSP Sidetone SGAINCR bit definitions *************/ +#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */ +#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */ + +/********************** McBSP Sidetone SFIRCR bit definitions **************/ +#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */ + +/********************** McBSP Sidetone SSELCR bit definitions **************/ +#define ST_SIDETONEEN BIT(0) +#define ST_COEFFWREN BIT(1) +#define ST_COEFFWRDONE BIT(2) + +/********************** McBSP DMA operating modes **************************/ +#define MCBSP_DMA_MODE_ELEMENT 0 +#define MCBSP_DMA_MODE_THRESHOLD 1 +#define MCBSP_DMA_MODE_FRAME 2 + +/********************** McBSP WAKEUPEN bit definitions *********************/ +#define RSYNCERREN BIT(0) +#define RFSREN BIT(1) +#define REOFEN BIT(2) +#define RRDYEN BIT(3) +#define XSYNCERREN BIT(7) +#define XFSXEN BIT(8) +#define XEOFEN BIT(9) +#define XRDYEN BIT(10) +#define XEMPTYEOFEN BIT(14) + +/* Clock signal muxing options */ +#define CLKR_SRC_CLKR 0 /* CLKR signal is from the CLKR pin */ +#define CLKR_SRC_CLKX 1 /* CLKR signal is from the CLKX pin */ +#define FSR_SRC_FSR 2 /* FSR signal is from the FSR pin */ +#define FSR_SRC_FSX 3 /* FSR signal is from the FSX pin */ + +/* McBSP functional clock sources */ +#define MCBSP_CLKS_PRCM_SRC 0 +#define MCBSP_CLKS_PAD_SRC 1 + +/* we don't do multichannel for now */ +struct omap_mcbsp_reg_cfg { + u16 spcr2; + u16 spcr1; + u16 rcr2; + u16 rcr1; + u16 xcr2; + u16 xcr1; + u16 srgr2; + u16 srgr1; + u16 mcr2; + u16 mcr1; + u16 pcr0; + u16 rcerc; + u16 rcerd; + u16 xcerc; + u16 xcerd; + u16 rcere; + u16 rcerf; + u16 xcere; + u16 xcerf; + u16 rcerg; + u16 rcerh; + u16 xcerg; + u16 xcerh; + u16 xccr; + u16 rccr; +}; + +struct omap_mcbsp_st_data { + void __iomem *io_base_st; + bool running; + bool enabled; + s16 taps[128]; /* Sidetone filter coefficients */ + int nr_taps; /* Number of filter coefficients in use */ + s16 ch0gain; + s16 ch1gain; +}; + +struct omap_mcbsp { + struct device *dev; + struct clk *fclk; + spinlock_t lock; + unsigned long phys_base; + unsigned long phys_dma_base; + void __iomem *io_base; + u8 id; + /* + * Flags indicating is the bus already activated and configured by + * another substream + */ + int active; + int configured; + u8 free; + + int rx_irq; + int tx_irq; + + /* Protect the field .free, while checking if the mcbsp is in use */ + struct omap_mcbsp_platform_data *pdata; + struct omap_mcbsp_st_data *st_data; + struct omap_mcbsp_reg_cfg cfg_regs; + struct omap_pcm_dma_data dma_data[2]; + int dma_op_mode; + u16 max_tx_thres; + u16 max_rx_thres; + void *reg_cache; + int reg_cache_size; + + unsigned int fmt; + unsigned int in_freq; + int clk_div; + int wlen; +}; + +void omap_mcbsp_config(struct omap_mcbsp *mcbsp, + const struct omap_mcbsp_reg_cfg *config); +void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold); +void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold); +u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp); +u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp); +int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp); +int omap_mcbsp_request(struct omap_mcbsp *mcbsp); +void omap_mcbsp_free(struct omap_mcbsp *mcbsp); +void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx); +void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx); + +/* McBSP functional clock source changing function */ +int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id); + +/* McBSP signal muxing API */ +int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux); + +/* Sidetone specific API */ +int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain); +int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain); +int omap_st_enable(struct omap_mcbsp *mcbsp); +int omap_st_disable(struct omap_mcbsp *mcbsp); +int omap_st_is_enabled(struct omap_mcbsp *mcbsp); + +int __devinit omap_mcbsp_init(struct platform_device *pdev); +void __devexit omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp); + +#endif /* __ASOC_MCBSP_H */ diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 597be412f1e..abac4b69075 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -55,9 +55,8 @@ static int n810_spk_func; static int n810_jack_func; static int n810_dmic_func; -static void n810_ext_control(struct snd_soc_codec *codec) +static void n810_ext_control(struct snd_soc_dapm_context *dapm) { - struct snd_soc_dapm_context *dapm = &codec->dapm; int hp = 0, line1l = 0; switch (n810_jack_func) { @@ -102,7 +101,7 @@ static int n810_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); - n810_ext_control(codec); + n810_ext_control(&codec->dapm); return clk_enable(sys_clkout2); } @@ -142,13 +141,13 @@ static int n810_get_spk(struct snd_kcontrol *kcontrol, static int n810_set_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (n810_spk_func == ucontrol->value.integer.value[0]) return 0; n810_spk_func = ucontrol->value.integer.value[0]; - n810_ext_control(codec); + n810_ext_control(&card->dapm); return 1; } @@ -164,13 +163,13 @@ static int n810_get_jack(struct snd_kcontrol *kcontrol, static int n810_set_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (n810_jack_func == ucontrol->value.integer.value[0]) return 0; n810_jack_func = ucontrol->value.integer.value[0]; - n810_ext_control(codec); + n810_ext_control(&card->dapm); return 1; } @@ -186,13 +185,13 @@ static int n810_get_input(struct snd_kcontrol *kcontrol, static int n810_set_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (n810_dmic_func == ucontrol->value.integer.value[0]) return 0; n810_dmic_func = ucontrol->value.integer.value[0]; - n810_ext_control(codec); + n810_ext_control(&card->dapm); return 1; } @@ -276,7 +275,7 @@ static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link n810_dai = { .name = "TLV320AIC33", .stream_name = "AIC33", - .cpu_dai_name = "omap-mcbsp-dai.1", + .cpu_dai_name = "omap-mcbsp.2", .platform_name = "omap-pcm-audio", .codec_name = "tlv320aic3x-codec.2-0018", .codec_dai_name = "tlv320aic3x-hifi", diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c new file mode 100644 index 00000000000..93bb8eee22b --- /dev/null +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -0,0 +1,349 @@ +/* + * omap-abe-twl6040.c -- SoC audio for TI OMAP based boards with ABE and + * twl6040 codec + * + * Author: Misael Lopez Cruz <misael.lopez@ti.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 <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/mfd/twl6040.h> +#include <linux/platform_data/omap-abe-twl6040.h> +#include <linux/module.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/jack.h> + +#include <asm/mach-types.h> +#include <plat/hardware.h> +#include <plat/mux.h> + +#include "omap-dmic.h" +#include "omap-mcpdm.h" +#include "omap-pcm.h" +#include "../codecs/twl6040.h" + +static int omap_abe_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_codec *codec = rtd->codec; + struct snd_soc_card *card = codec->card; + struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev); + int clk_id, freq; + int ret; + + clk_id = twl6040_get_clk_id(rtd->codec); + if (clk_id == TWL6040_SYSCLK_SEL_HPPLL) + freq = pdata->mclk_freq; + else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL) + freq = 32768; + else + return -EINVAL; + + /* set the codec mclk */ + ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq, + SND_SOC_CLOCK_IN); + if (ret) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + return ret; +} + +static struct snd_soc_ops omap_abe_ops = { + .hw_params = omap_abe_hw_params, +}; + +static int omap_abe_dmic_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; + int ret = 0; + + ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS, + 19200000, SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set DMIC cpu system clock\n"); + return ret; + } + ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000, + SND_SOC_CLOCK_OUT); + if (ret < 0) { + printk(KERN_ERR "can't set DMIC output clock\n"); + return ret; + } + return 0; +} + +static struct snd_soc_ops omap_abe_dmic_ops = { + .hw_params = omap_abe_dmic_hw_params, +}; + +/* Headset jack */ +static struct snd_soc_jack hs_jack; + +/*Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin hs_jack_pins[] = { + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headset Stereophone", + .mask = SND_JACK_HEADPHONE, + }, +}; + +/* SDP4430 machine DAPM */ +static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { + /* Outputs */ + SND_SOC_DAPM_HP("Headset Stereophone", NULL), + SND_SOC_DAPM_SPK("Earphone Spk", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_SPK("Vibrator", NULL), + + /* Inputs */ + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Main Handset Mic", NULL), + SND_SOC_DAPM_MIC("Sub Handset Mic", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* Routings for outputs */ + {"Headset Stereophone", NULL, "HSOL"}, + {"Headset Stereophone", NULL, "HSOR"}, + + {"Earphone Spk", NULL, "EP"}, + + {"Ext Spk", NULL, "HFL"}, + {"Ext Spk", NULL, "HFR"}, + + {"Line Out", NULL, "AUXL"}, + {"Line Out", NULL, "AUXR"}, + + {"Vibrator", NULL, "VIBRAL"}, + {"Vibrator", NULL, "VIBRAR"}, + + /* Routings for inputs */ + {"HSMIC", NULL, "Headset Mic"}, + {"Headset Mic", NULL, "Headset Mic Bias"}, + + {"MAINMIC", NULL, "Main Handset Mic"}, + {"Main Handset Mic", NULL, "Main Mic Bias"}, + + {"SUBMIC", NULL, "Sub Handset Mic"}, + {"Sub Handset Mic", NULL, "Main Mic Bias"}, + + {"AFML", NULL, "Line In"}, + {"AFMR", NULL, "Line In"}, +}; + +static inline void twl6040_disconnect_pin(struct snd_soc_dapm_context *dapm, + int connected, char *pin) +{ + if (!connected) + snd_soc_dapm_disable_pin(dapm, pin); +} + +static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = codec->card; + struct snd_soc_dapm_context *dapm = &codec->dapm; + struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev); + int hs_trim; + int ret = 0; + + /* Disable not connected paths if not used */ + twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); + twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); + twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); + twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); + twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); + twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); + + /* + * Configure McPDM offset cancellation based on the HSOTRIM value from + * twl6040. + */ + hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM); + omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim), + TWL6040_HSF_TRIM_RIGHT(hs_trim)); + + /* Headset jack detection only if it is supported */ + if (pdata->jack_detection) { + ret = snd_soc_jack_new(codec, "Headset Jack", + SND_JACK_HEADSET, &hs_jack); + if (ret) + return ret; + + ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), + hs_jack_pins); + twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); + } + + return ret; +} + +static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Digital Mic", NULL), +}; + +static const struct snd_soc_dapm_route dmic_audio_map[] = { + {"DMic", NULL, "Digital Mic"}, + {"Digital Mic", NULL, "Digital Mic1 Bias"}, +}; + +static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + int ret; + + ret = snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets, + ARRAY_SIZE(dmic_dapm_widgets)); + if (ret) + return ret; + + return snd_soc_dapm_add_routes(dapm, dmic_audio_map, + ARRAY_SIZE(dmic_audio_map)); +} + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link twl6040_dmic_dai[] = { + { + .name = "TWL6040", + .stream_name = "TWL6040", + .cpu_dai_name = "omap-mcpdm", + .codec_dai_name = "twl6040-legacy", + .platform_name = "omap-pcm-audio", + .codec_name = "twl6040-codec", + .init = omap_abe_twl6040_init, + .ops = &omap_abe_ops, + }, + { + .name = "DMIC", + .stream_name = "DMIC Capture", + .cpu_dai_name = "omap-dmic", + .codec_dai_name = "dmic-hifi", + .platform_name = "omap-pcm-audio", + .codec_name = "dmic-codec", + .init = omap_abe_dmic_init, + .ops = &omap_abe_dmic_ops, + }, +}; + +static struct snd_soc_dai_link twl6040_only_dai[] = { + { + .name = "TWL6040", + .stream_name = "TWL6040", + .cpu_dai_name = "omap-mcpdm", + .codec_dai_name = "twl6040-legacy", + .platform_name = "omap-pcm-audio", + .codec_name = "twl6040-codec", + .init = omap_abe_twl6040_init, + .ops = &omap_abe_ops, + }, +}; + +/* Audio machine driver */ +static struct snd_soc_card omap_abe_card = { + .owner = THIS_MODULE, + + .dapm_widgets = twl6040_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), +}; + +static __devinit int omap_abe_probe(struct platform_device *pdev) +{ + struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); + struct snd_soc_card *card = &omap_abe_card; + int ret; + + card->dev = &pdev->dev; + + if (!pdata) { + dev_err(&pdev->dev, "Missing pdata\n"); + return -ENODEV; + } + + if (pdata->card_name) { + card->name = pdata->card_name; + } else { + dev_err(&pdev->dev, "Card name is not provided\n"); + return -ENODEV; + } + + if (!pdata->mclk_freq) { + dev_err(&pdev->dev, "MCLK frequency missing\n"); + return -ENODEV; + } + + if (pdata->has_dmic) { + card->dai_link = twl6040_dmic_dai; + card->num_links = ARRAY_SIZE(twl6040_dmic_dai); + } else { + card->dai_link = twl6040_only_dai; + card->num_links = ARRAY_SIZE(twl6040_only_dai); + } + + ret = snd_soc_register_card(card); + if (ret) + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", + ret); + + return ret; +} + +static int __devexit omap_abe_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 omap_abe_driver = { + .driver = { + .name = "omap-abe-twl6040", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = omap_abe_probe, + .remove = __devexit_p(omap_abe_remove), +}; + +module_platform_driver(omap_abe_driver); + +MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); +MODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:omap-abe-twl6040"); diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 0855c1cfa7f..4dcb5a7e40e 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -113,12 +113,10 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream, mutex_lock(&dmic->mutex); - if (!dai->active) { - snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24); + if (!dai->active) dmic->active = 1; - } else { + else ret = -EBUSY; - } mutex_unlock(&dmic->mutex); @@ -445,6 +443,7 @@ static struct snd_soc_dai_driver omap_dmic_dai = { .channels_max = 6, .rates = SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 24, }, .ops = &omap_dmic_dai_ops, }; diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 017371913ec..6912ac7cb62 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -25,6 +25,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/device.h> +#include <linux/pm_runtime.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -33,6 +34,7 @@ #include <plat/dma.h> #include <plat/mcbsp.h> +#include "mcbsp.h" #include "omap-mcbsp.h" #include "omap-pcm.h" @@ -46,42 +48,31 @@ .private_value = (unsigned long) &(struct soc_mixer_control) \ {.min = xmin, .max = xmax} } -struct omap_mcbsp_data { - unsigned int bus_id; - struct omap_mcbsp_reg_cfg regs; - unsigned int fmt; - /* - * Flags indicating is the bus already activated and configured by - * another substream - */ - int active; - int configured; - unsigned int in_freq; - int clk_div; - int wlen; +enum { + OMAP_MCBSP_WORD_8 = 0, + OMAP_MCBSP_WORD_12, + OMAP_MCBSP_WORD_16, + OMAP_MCBSP_WORD_20, + OMAP_MCBSP_WORD_24, + OMAP_MCBSP_WORD_32, }; -static struct omap_mcbsp_data mcbsp_data[NUM_LINKS]; - /* * Stream DMA parameters. DMA request line and port address are set runtime * since they are different between OMAP1 and later OMAPs */ -static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2]; - static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); struct omap_pcm_dma_data *dma_data; - int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); int words; dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ - if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) + if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) /* * Configure McBSP threshold based on either: * packet_size, when the sDMA is in packet mode, or @@ -91,15 +82,15 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) words = dma_data->packet_size; else words = snd_pcm_lib_period_bytes(substream) / - (mcbsp_data->wlen / 8); + (mcbsp->wlen / 8); else words = 1; /* Configure McBSP internal buffer usage */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words); + omap_mcbsp_set_tx_threshold(mcbsp, words); else - omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words); + omap_mcbsp_set_rx_threshold(mcbsp, words); } static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, @@ -109,12 +100,12 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct omap_mcbsp_data *mcbsp_data = rule->private; + struct omap_mcbsp *mcbsp = rule->private; struct snd_interval frames; int size; snd_interval_any(&frames); - size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id); + size = mcbsp->pdata->buffer_size; frames.min = size / channels->min; frames.integer = 1; @@ -124,12 +115,11 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - int bus_id = mcbsp_data->bus_id; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); int err = 0; if (!cpu_dai->active) - err = omap_mcbsp_request(bus_id); + err = omap_mcbsp_request(mcbsp); /* * OMAP3 McBSP FIFO is word structured. @@ -146,16 +136,16 @@ 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_omap34xx() || cpu_is_omap44xx()) { + if (mcbsp->pdata->buffer_size) { /* * Rule for the buffer size. We should not allow * smaller buffer than the FIFO size to avoid underruns */ snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, omap_mcbsp_hwrule_min_buffersize, - mcbsp_data, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); + mcbsp, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, @@ -168,33 +158,33 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); if (!cpu_dai->active) { - omap_mcbsp_free(mcbsp_data->bus_id); - mcbsp_data->configured = 0; + omap_mcbsp_free(mcbsp); + mcbsp->configured = 0; } } static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - mcbsp_data->active++; - omap_mcbsp_start(mcbsp_data->bus_id, play, !play); + mcbsp->active++; + omap_mcbsp_start(mcbsp, play, !play); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - omap_mcbsp_stop(mcbsp_data->bus_id, play, !play); - mcbsp_data->active--; + omap_mcbsp_stop(mcbsp, play, !play); + mcbsp->active--; break; default: err = -EINVAL; @@ -209,14 +199,14 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay( { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); u16 fifo_use; snd_pcm_sframes_t delay; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fifo_use = omap_mcbsp_get_tx_delay(mcbsp_data->bus_id); + fifo_use = omap_mcbsp_get_tx_delay(mcbsp); else - fifo_use = omap_mcbsp_get_rx_delay(mcbsp_data->bus_id); + fifo_use = omap_mcbsp_get_rx_delay(mcbsp); /* * Divide the used locations with the channel count to get the @@ -232,19 +222,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; struct omap_pcm_dma_data *dma_data; - int dma, bus_id = mcbsp_data->bus_id; int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; int pkt_size = 0; - unsigned long port; unsigned int format, div, framesize, master; - dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream]; - - dma = omap_mcbsp_dma_ch_params(bus_id, substream->stream); - port = omap_mcbsp_dma_reg_params(bus_id, substream->stream); + dma_data = &mcbsp->dma_data[substream->stream]; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -258,20 +243,17 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } - if (cpu_is_omap34xx() || cpu_is_omap44xx()) { + if (mcbsp->pdata->buffer_size) { dma_data->set_threshold = omap_mcbsp_set_threshold; /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ - if (omap_mcbsp_get_dma_op_mode(bus_id) == - MCBSP_DMA_MODE_THRESHOLD) { + if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { int period_words, max_thrsh; period_words = params_period_bytes(params) / (wlen / 8); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - max_thrsh = omap_mcbsp_get_max_tx_threshold( - mcbsp_data->bus_id); + max_thrsh = mcbsp->max_tx_thres; else - max_thrsh = omap_mcbsp_get_max_rx_threshold( - mcbsp_data->bus_id); + max_thrsh = mcbsp->max_rx_thres; /* * If the period contains less or equal number of words, * we are using the original threshold mode setup: @@ -304,15 +286,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, } } - dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback"; - dma_data->dma_req = dma; - dma_data->port_addr = port; dma_data->sync_mode = sync_mode; dma_data->packet_size = pkt_size; snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); - if (mcbsp_data->configured) { + if (mcbsp->configured) { /* McBSP already configured by another stream */ return 0; } @@ -321,7 +300,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7)); regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7)); regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7)); - format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK; + format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK; wpf = channels = params_channels(params); if (channels == 2 && (format == SND_SOC_DAIFMT_I2S || format == SND_SOC_DAIFMT_LEFT_J)) { @@ -359,10 +338,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, /* In McBSP master modes, FRAME (i.e. sample rate) is generated * by _counting_ BCLKs. Calculate frame size in BCLKs */ - master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK; + master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK; if (master == SND_SOC_DAIFMT_CBS_CFS) { - div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1; - framesize = (mcbsp_data->in_freq / div) / params_rate(params); + div = mcbsp->clk_div ? mcbsp->clk_div : 1; + framesize = (mcbsp->in_freq / div) / params_rate(params); if (framesize < wlen * channels) { printk(KERN_ERR "%s: not enough bandwidth for desired rate and " @@ -388,9 +367,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, break; } - omap_mcbsp_config(bus_id, &mcbsp_data->regs); - mcbsp_data->wlen = wlen; - mcbsp_data->configured = 1; + omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs); + mcbsp->wlen = wlen; + mcbsp->configured = 1; return 0; } @@ -402,14 +381,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; bool inv_fs = false; - if (mcbsp_data->configured) + if (mcbsp->configured) return 0; - mcbsp_data->fmt = fmt; + mcbsp->fmt = fmt; memset(regs, 0, sizeof(*regs)); /* Generic McBSP register settings */ regs->spcr2 |= XINTM(3) | FREE; @@ -504,13 +483,13 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; if (div_id != OMAP_MCBSP_CLKGDV) return -ENODEV; - mcbsp_data->clk_div = div; + mcbsp->clk_div = div; regs->srgr1 &= ~CLKGDV(0xff); regs->srgr1 |= CLKGDV(div - 1); @@ -521,28 +500,32 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { - struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; int err = 0; - if (mcbsp_data->active) { - if (freq == mcbsp_data->in_freq) + if (mcbsp->active) { + if (freq == mcbsp->in_freq) return 0; else return -EBUSY; } - /* The McBSP signal muxing functions are only available on McBSP1 */ - if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR || - clk_id == OMAP_MCBSP_CLKR_SRC_CLKX || - clk_id == OMAP_MCBSP_FSR_SRC_FSR || - clk_id == OMAP_MCBSP_FSR_SRC_FSX) - if (cpu_class_is_omap1() || mcbsp_data->bus_id != 0) - return -EINVAL; - - mcbsp_data->in_freq = freq; - regs->srgr2 &= ~CLKSM; - regs->pcr0 &= ~SCLKME; + if (clk_id == OMAP_MCBSP_SYSCLK_CLK || + clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK || + clk_id == OMAP_MCBSP_SYSCLK_CLKS_EXT || + clk_id == OMAP_MCBSP_SYSCLK_CLKX_EXT || + clk_id == OMAP_MCBSP_SYSCLK_CLKR_EXT) { + mcbsp->in_freq = freq; + regs->srgr2 &= ~CLKSM; + regs->pcr0 &= ~SCLKME; + } else if (cpu_class_is_omap1()) { + /* + * McBSP CLKR/FSR signal muxing functions are only available on + * OMAP2 or newer versions + */ + return -EINVAL; + } switch (clk_id) { case OMAP_MCBSP_SYSCLK_CLK: @@ -553,7 +536,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, err = -EINVAL; break; } - err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id, + err = omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); break; case OMAP_MCBSP_SYSCLK_CLKS_EXT: @@ -561,7 +544,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, err = 0; break; } - err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id, + err = omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PAD_SRC); break; @@ -573,24 +556,16 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, case OMAP_MCBSP_CLKR_SRC_CLKR: - if (cpu_class_is_omap1()) - break; - omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR); + err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKR); break; case OMAP_MCBSP_CLKR_SRC_CLKX: - if (cpu_class_is_omap1()) - break; - omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX); + err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKX); break; case OMAP_MCBSP_FSR_SRC_FSR: - if (cpu_class_is_omap1()) - break; - omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR); + err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSR); break; case OMAP_MCBSP_FSR_SRC_FSX: - if (cpu_class_is_omap1()) - break; - omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX); + err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSX); break; default: err = -ENODEV; @@ -610,15 +585,27 @@ static const struct snd_soc_dai_ops mcbsp_dai_ops = { .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, }; -static int mcbsp_dai_probe(struct snd_soc_dai *dai) +static int omap_mcbsp_probe(struct snd_soc_dai *dai) { - mcbsp_data[dai->id].bus_id = dai->id; - snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); + + pm_runtime_enable(mcbsp->dev); + + return 0; +} + +static int omap_mcbsp_remove(struct snd_soc_dai *dai) +{ + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); + + pm_runtime_disable(mcbsp->dev); + return 0; } static struct snd_soc_dai_driver omap_mcbsp_dai = { - .probe = mcbsp_dai_probe, + .probe = omap_mcbsp_probe, + .remove = omap_mcbsp_remove, .playback = { .channels_min = 1, .channels_max = 16, @@ -649,11 +636,13 @@ static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, return 0; } -#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(id, channel) \ +#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(channel) \ static int \ -omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ +omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ struct snd_ctl_elem_value *uc) \ { \ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ struct soc_mixer_control *mc = \ (struct soc_mixer_control *)kc->private_value; \ int max = mc->max; \ @@ -664,46 +653,44 @@ omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ return -EINVAL; \ \ /* OMAP McBSP implementation uses index values 0..4 */ \ - return omap_st_set_chgain((id)-1, channel, val); \ + return omap_st_set_chgain(mcbsp, channel, val); \ } -#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(id, channel) \ +#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(channel) \ static int \ -omap_mcbsp##id##_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ +omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ struct snd_ctl_elem_value *uc) \ { \ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ s16 chgain; \ \ - if (omap_st_get_chgain((id)-1, channel, &chgain)) \ + if (omap_st_get_chgain(mcbsp, channel, &chgain)) \ return -EAGAIN; \ \ uc->value.integer.value[0] = chgain; \ return 0; \ } -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 0) -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 1) -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 0) -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 1) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 0) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 1) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 0) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 1) +OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(0) +OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(1) +OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(0) +OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(1) static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); u8 value = ucontrol->value.integer.value[0]; - if (value == omap_st_is_enabled(mc->reg)) + if (value == omap_st_is_enabled(mcbsp)) return 0; if (value) - omap_st_enable(mc->reg); + omap_st_enable(mcbsp); else - omap_st_disable(mc->reg); + omap_st_disable(mcbsp); return 1; } @@ -711,10 +698,10 @@ static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - ucontrol->value.integer.value[0] = omap_st_is_enabled(mc->reg); + ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp); return 0; } @@ -723,12 +710,12 @@ static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = { omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume", -32768, 32767, - omap_mcbsp2_get_st_ch0_volume, - omap_mcbsp2_set_st_ch0_volume), + omap_mcbsp_get_st_ch0_volume, + omap_mcbsp_set_st_ch0_volume), OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume", -32768, 32767, - omap_mcbsp2_get_st_ch1_volume, - omap_mcbsp2_set_st_ch1_volume), + omap_mcbsp_get_st_ch1_volume, + omap_mcbsp_set_st_ch1_volume), }; static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = { @@ -736,25 +723,30 @@ static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = { omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume", -32768, 32767, - omap_mcbsp3_get_st_ch0_volume, - omap_mcbsp3_set_st_ch0_volume), + omap_mcbsp_get_st_ch0_volume, + omap_mcbsp_set_st_ch0_volume), OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume", -32768, 32767, - omap_mcbsp3_get_st_ch1_volume, - omap_mcbsp3_set_st_ch1_volume), + omap_mcbsp_get_st_ch1_volume, + omap_mcbsp_set_st_ch1_volume), }; -int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id) +int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd) { - if (!cpu_is_omap34xx()) + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + + if (!mcbsp->st_data) return -ENODEV; - switch (mcbsp_id) { - case 1: /* McBSP 2 */ - return snd_soc_add_controls(codec, omap_mcbsp2_st_controls, + switch (cpu_dai->id) { + case 2: /* McBSP 2 */ + return snd_soc_add_dai_controls(cpu_dai, + omap_mcbsp2_st_controls, ARRAY_SIZE(omap_mcbsp2_st_controls)); - case 2: /* McBSP 3 */ - return snd_soc_add_controls(codec, omap_mcbsp3_st_controls, + case 3: /* McBSP 3 */ + return snd_soc_add_dai_controls(cpu_dai, + omap_mcbsp3_st_controls, ARRAY_SIZE(omap_mcbsp3_st_controls)); default: break; @@ -766,18 +758,51 @@ EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); static __devinit int asoc_mcbsp_probe(struct platform_device *pdev) { - return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai); + struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct omap_mcbsp *mcbsp; + int ret; + + if (!pdata) { + dev_err(&pdev->dev, "missing platform data.\n"); + return -EINVAL; + } + mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL); + if (!mcbsp) + return -ENOMEM; + + mcbsp->id = pdev->id; + mcbsp->pdata = pdata; + mcbsp->dev = &pdev->dev; + platform_set_drvdata(pdev, mcbsp); + + ret = omap_mcbsp_init(pdev); + if (!ret) + return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai); + + return ret; } static int __devexit asoc_mcbsp_remove(struct platform_device *pdev) { + struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); + snd_soc_unregister_dai(&pdev->dev); + + if (mcbsp->pdata->ops && mcbsp->pdata->ops->free) + mcbsp->pdata->ops->free(mcbsp->id); + + omap_mcbsp_sysfs_remove(mcbsp); + + clk_put(mcbsp->fclk); + + platform_set_drvdata(pdev, NULL); + return 0; } static struct platform_driver asoc_mcbsp_driver = { .driver = { - .name = "omap-mcbsp-dai", + .name = "omap-mcbsp", .owner = THIS_MODULE, }, diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index 65cde9d3807..f877b16f19c 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h @@ -59,6 +59,6 @@ enum omap_mcbsp_div { #define NUM_LINKS 5 #endif -int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id); +int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd); #endif diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 0e25df4fa9e..39705561131 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -419,12 +419,14 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = { .channels_max = 5, .rates = OMAP_MCPDM_RATES, .formats = OMAP_MCPDM_FORMATS, + .sig_bits = 24, }, .capture = { .channels_min = 1, .channels_max = 3, .rates = OMAP_MCPDM_RATES, .formats = OMAP_MCPDM_FORMATS, + .sig_bits = 24, }, .ops = &omap_mcpdm_dai_ops, }; diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h index f95fe306417..b92248cbd47 100644 --- a/sound/soc/omap/omap-pcm.h +++ b/sound/soc/omap/omap-pcm.h @@ -25,6 +25,8 @@ #ifndef __OMAP_PCM_H__ #define __OMAP_PCM_H__ +struct snd_pcm_substream; + struct omap_pcm_dma_data { char *name; /* stream identifier */ int dma_req; /* DMA request line */ diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index 3357dcc47ed..2830dfd0566 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c @@ -91,7 +91,7 @@ static struct snd_soc_ops omap3beagle_ops = { static struct snd_soc_dai_link omap3beagle_dai = { .name = "TWL4030", .stream_name = "TWL4030", - .cpu_dai_name = "omap-mcbsp-dai.1", + .cpu_dai_name = "omap-mcbsp.2", .platform_name = "omap-pcm-audio", .codec_dai_name = "twl4030-hifi", .codec_name = "twl4030-codec", diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c index 071fcb09b8b..3d468c9179d 100644 --- a/sound/soc/omap/omap3evm.c +++ b/sound/soc/omap/omap3evm.c @@ -58,7 +58,7 @@ static struct snd_soc_ops omap3evm_ops = { static struct snd_soc_dai_link omap3evm_dai = { .name = "TWL4030", .stream_name = "TWL4030", - .cpu_dai_name = "omap-mcbsp-dai.1", + .cpu_dai_name = "omap-mcbsp.2", .codec_dai_name = "twl4030-hifi", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index 07794bd1095..4c3a0978578 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -208,7 +208,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = { { .name = "PCM1773", .stream_name = "HiFi Out", - .cpu_dai_name = "omap-mcbsp-dai.1", + .cpu_dai_name = "omap-mcbsp.2", .codec_dai_name = "twl4030-hifi", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", @@ -219,7 +219,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = { }, { .name = "TWL4030", .stream_name = "Line/Mic In", - .cpu_dai_name = "omap-mcbsp-dai.3", + .cpu_dai_name = "omap-mcbsp.4", .codec_dai_name = "twl4030-hifi", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index d859b597e7e..b1a9d64cbc5 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -96,7 +96,7 @@ static const struct snd_soc_dapm_route audio_map[] = { static struct snd_soc_dai_link osk_dai = { .name = "TLV320AIC23", .stream_name = "AIC23", - .cpu_dai_name = "omap-mcbsp-dai.0", + .cpu_dai_name = "omap-mcbsp.1", .codec_dai_name = "tlv320aic23-hifi", .platform_name = "omap-pcm-audio", .codec_name = "tlv320aic23-codec", diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c index 2ee889c5025..6ac3e0c3c28 100644 --- a/sound/soc/omap/overo.c +++ b/sound/soc/omap/overo.c @@ -60,7 +60,7 @@ static struct snd_soc_ops overo_ops = { static struct snd_soc_dai_link overo_dai = { .name = "TWL4030", .stream_name = "TWL4030", - .cpu_dai_name = "omap-mcbsp-dai.1", + .cpu_dai_name = "omap-mcbsp.2", .codec_dai_name = "twl4030-hifi", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index fada6ef43ee..2712dd232b6 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -59,9 +59,8 @@ static int rx51_spk_func; static int rx51_dmic_func; static int rx51_jack_func; -static void rx51_ext_control(struct snd_soc_codec *codec) +static void rx51_ext_control(struct snd_soc_dapm_context *dapm) { - struct snd_soc_dapm_context *dapm = &codec->dapm; int hp = 0, hs = 0, tvout = 0; switch (rx51_jack_func) { @@ -102,11 +101,11 @@ static int rx51_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = rtd->card; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); - rx51_ext_control(codec); + rx51_ext_control(&card->dapm); return 0; } @@ -138,13 +137,13 @@ static int rx51_get_spk(struct snd_kcontrol *kcontrol, static int rx51_set_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (rx51_spk_func == ucontrol->value.integer.value[0]) return 0; rx51_spk_func = ucontrol->value.integer.value[0]; - rx51_ext_control(codec); + rx51_ext_control(&card->dapm); return 1; } @@ -184,13 +183,13 @@ static int rx51_get_input(struct snd_kcontrol *kcontrol, static int rx51_set_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (rx51_dmic_func == ucontrol->value.integer.value[0]) return 0; rx51_dmic_func = ucontrol->value.integer.value[0]; - rx51_ext_control(codec); + rx51_ext_control(&card->dapm); return 1; } @@ -206,13 +205,13 @@ static int rx51_get_jack(struct snd_kcontrol *kcontrol, static int rx51_set_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (rx51_jack_func == ucontrol->value.integer.value[0]) return 0; rx51_jack_func = ucontrol->value.integer.value[0]; - rx51_ext_control(codec); + rx51_ext_control(&card->dapm); return 1; } @@ -297,7 +296,7 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "LINE1R"); /* Add RX-51 specific controls */ - err = snd_soc_add_controls(codec, aic34_rx51_controls, + err = snd_soc_add_card_controls(rtd->card, aic34_rx51_controls, ARRAY_SIZE(aic34_rx51_controls)); if (err < 0) return err; @@ -314,7 +313,7 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) return err; snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42); - err = omap_mcbsp_st_add_controls(codec, 1); + err = omap_mcbsp_st_add_controls(rtd); if (err < 0) return err; @@ -335,7 +334,7 @@ static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm) { int err; - err = snd_soc_add_controls(dapm->codec, aic34_rx51_controlsb, + err = snd_soc_add_card_controls(dapm->card, aic34_rx51_controlsb, ARRAY_SIZE(aic34_rx51_controlsb)); if (err < 0) return err; @@ -354,7 +353,7 @@ static struct snd_soc_dai_link rx51_dai[] = { { .name = "TLV320AIC34", .stream_name = "AIC34", - .cpu_dai_name = "omap-mcbsp-dai.1", + .cpu_dai_name = "omap-mcbsp.2", .codec_dai_name = "tlv320aic3x-hifi", .platform_name = "omap-pcm-audio", .codec_name = "tlv320aic3x-codec.2-0018", diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index 2c850662ea7..0e283226e2b 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -187,7 +187,7 @@ static struct snd_soc_dai_link sdp3430_dai[] = { { .name = "TWL4030 I2S", .stream_name = "TWL4030 Audio", - .cpu_dai_name = "omap-mcbsp-dai.1", + .cpu_dai_name = "omap-mcbsp.2", .codec_dai_name = "twl4030-hifi", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", @@ -199,7 +199,7 @@ static struct snd_soc_dai_link sdp3430_dai[] = { { .name = "TWL4030 PCM", .stream_name = "TWL4030 Voice", - .cpu_dai_name = "omap-mcbsp-dai.2", + .cpu_dai_name = "omap-mcbsp.3", .codec_dai_name = "twl4030-voice", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c deleted file mode 100644 index 175ba9a04ed..00000000000 --- a/sound/soc/omap/sdp4430.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * sdp4430.c -- SoC audio for TI OMAP4430 SDP - * - * Author: Misael Lopez Cruz <x0052729@ti.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 <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/mfd/twl6040.h> -#include <linux/module.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/jack.h> - -#include <asm/mach-types.h> -#include <plat/hardware.h> -#include <plat/mux.h> - -#include "omap-dmic.h" -#include "omap-mcpdm.h" -#include "omap-pcm.h" -#include "../codecs/twl6040.h" - -static int sdp4430_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; - int clk_id, freq; - int ret; - - clk_id = twl6040_get_clk_id(rtd->codec); - if (clk_id == TWL6040_SYSCLK_SEL_HPPLL) - freq = 38400000; - else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL) - freq = 32768; - else - return -EINVAL; - - /* set the codec mclk */ - ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq, - SND_SOC_CLOCK_IN); - if (ret) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - return ret; -} - -static struct snd_soc_ops sdp4430_ops = { - .hw_params = sdp4430_hw_params, -}; - -static int sdp4430_dmic_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; - int ret = 0; - - ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS, - 19200000, SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set DMIC cpu system clock\n"); - return ret; - } - ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000, - SND_SOC_CLOCK_OUT); - if (ret < 0) { - printk(KERN_ERR "can't set DMIC output clock\n"); - return ret; - } - return 0; -} - -static struct snd_soc_ops sdp4430_dmic_ops = { - .hw_params = sdp4430_dmic_hw_params, -}; - -/* Headset jack */ -static struct snd_soc_jack hs_jack; - -/*Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin hs_jack_pins[] = { - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headset Stereophone", - .mask = SND_JACK_HEADPHONE, - }, -}; - -/* SDP4430 machine DAPM */ -static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Ext Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_HP("Headset Stereophone", NULL), - SND_SOC_DAPM_SPK("Earphone Spk", NULL), - SND_SOC_DAPM_INPUT("FM Stereo In"), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* External Mics: MAINMIC, SUBMIC with bias*/ - {"MAINMIC", NULL, "Main Mic Bias"}, - {"SUBMIC", NULL, "Main Mic Bias"}, - {"Main Mic Bias", NULL, "Ext Mic"}, - - /* External Speakers: HFL, HFR */ - {"Ext Spk", NULL, "HFL"}, - {"Ext Spk", NULL, "HFR"}, - - /* Headset Mic: HSMIC with bias */ - {"HSMIC", NULL, "Headset Mic Bias"}, - {"Headset Mic Bias", NULL, "Headset Mic"}, - - /* Headset Stereophone (Headphone): HSOL, HSOR */ - {"Headset Stereophone", NULL, "HSOL"}, - {"Headset Stereophone", NULL, "HSOR"}, - - /* Earphone speaker */ - {"Earphone Spk", NULL, "EP"}, - - /* Aux/FM Stereo In: AFML, AFMR */ - {"AFML", NULL, "FM Stereo In"}, - {"AFMR", NULL, "FM Stereo In"}, -}; - -static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - int ret, hs_trim; - - /* - * Configure McPDM offset cancellation based on the HSOTRIM value from - * twl6040. - */ - hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM); - omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim), - TWL6040_HSF_TRIM_RIGHT(hs_trim)); - - /* Headset jack detection */ - ret = snd_soc_jack_new(codec, "Headset Jack", - SND_JACK_HEADSET, &hs_jack); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); - - if (machine_is_omap_4430sdp()) - twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); - else - snd_soc_jack_report(&hs_jack, SND_JACK_HEADSET, SND_JACK_HEADSET); - - return ret; -} - -static const struct snd_soc_dapm_widget sdp4430_dmic_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Digital Mic", NULL), -}; - -static const struct snd_soc_dapm_route dmic_audio_map[] = { - {"DMic", NULL, "Digital Mic1 Bias"}, - {"Digital Mic1 Bias", NULL, "Digital Mic"}, -}; - -static int sdp4430_dmic_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; - - ret = snd_soc_dapm_new_controls(dapm, sdp4430_dmic_dapm_widgets, - ARRAY_SIZE(sdp4430_dmic_dapm_widgets)); - if (ret) - return ret; - - return snd_soc_dapm_add_routes(dapm, dmic_audio_map, - ARRAY_SIZE(dmic_audio_map)); -} - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link sdp4430_dai[] = { - { - .name = "TWL6040", - .stream_name = "TWL6040", - .cpu_dai_name = "omap-mcpdm", - .codec_dai_name = "twl6040-legacy", - .platform_name = "omap-pcm-audio", - .codec_name = "twl6040-codec", - .init = sdp4430_twl6040_init, - .ops = &sdp4430_ops, - }, - { - .name = "DMIC", - .stream_name = "DMIC Capture", - .cpu_dai_name = "omap-dmic", - .codec_dai_name = "dmic-hifi", - .platform_name = "omap-pcm-audio", - .codec_name = "dmic-codec", - .init = sdp4430_dmic_init, - .ops = &sdp4430_dmic_ops, - }, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_sdp4430 = { - .name = "SDP4430", - .owner = THIS_MODULE, - .dai_link = sdp4430_dai, - .num_links = ARRAY_SIZE(sdp4430_dai), - - .dapm_widgets = sdp4430_twl6040_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sdp4430_twl6040_dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), -}; - -static struct platform_device *sdp4430_snd_device; - -static int __init sdp4430_soc_init(void) -{ - int ret; - - if (!machine_is_omap_4430sdp()) - return -ENODEV; - printk(KERN_INFO "SDP4430 SoC init\n"); - - sdp4430_snd_device = platform_device_alloc("soc-audio", -1); - if (!sdp4430_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430); - - ret = platform_device_add(sdp4430_snd_device); - if (ret) - goto err; - - return 0; - -err: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(sdp4430_snd_device); - return ret; -} -module_init(sdp4430_soc_init); - -static void __exit sdp4430_soc_exit(void) -{ - platform_device_unregister(sdp4430_snd_device); -} -module_exit(sdp4430_soc_exit); - -MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>"); -MODULE_DESCRIPTION("ALSA SoC SDP4430"); -MODULE_LICENSE("GPL"); - diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index 981616d61f6..920e0d9e03d 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -131,7 +131,7 @@ static struct snd_soc_dai_link zoom2_dai[] = { { .name = "TWL4030 I2S", .stream_name = "TWL4030 Audio", - .cpu_dai_name = "omap-mcbsp-dai.1", + .cpu_dai_name = "omap-mcbsp.2", .codec_dai_name = "twl4030-hifi", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", @@ -143,7 +143,7 @@ static struct snd_soc_dai_link zoom2_dai[] = { { .name = "TWL4030 PCM", .stream_name = "TWL4030 Voice", - .cpu_dai_name = "omap-mcbsp-dai.2", + .cpu_dai_name = "omap-mcbsp.3", .codec_dai_name = "twl4030-voice", .platform_name = "omap-pcm-audio", .codec_name = "twl4030-codec", diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index bc21944851c..863367ad89c 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -45,10 +45,8 @@ static int corgi_jack_func; static int corgi_spk_func; -static void corgi_ext_control(struct snd_soc_codec *codec) +static void corgi_ext_control(struct snd_soc_dapm_context *dapm) { - struct snd_soc_dapm_context *dapm = &codec->dapm; - /* set up jack connection */ switch (corgi_jack_func) { case CORGI_HP: @@ -104,7 +102,7 @@ static int corgi_startup(struct snd_pcm_substream *substream) mutex_lock(&codec->mutex); /* check the jack status at stream startup */ - corgi_ext_control(codec); + corgi_ext_control(&codec->dapm); mutex_unlock(&codec->mutex); @@ -173,13 +171,13 @@ static int corgi_get_jack(struct snd_kcontrol *kcontrol, static int corgi_set_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (corgi_jack_func == ucontrol->value.integer.value[0]) return 0; corgi_jack_func = ucontrol->value.integer.value[0]; - corgi_ext_control(codec); + corgi_ext_control(&card->dapm); return 1; } @@ -193,13 +191,13 @@ static int corgi_get_spk(struct snd_kcontrol *kcontrol, static int corgi_set_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (corgi_spk_func == ucontrol->value.integer.value[0]) return 0; corgi_spk_func = ucontrol->value.integer.value[0]; - corgi_ext_control(codec); + corgi_ext_control(&card->dapm); return 1; } diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 3f7a8ecb972..aace19e0fe2 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -411,7 +411,7 @@ static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "VINR"); /* Add magician specific controls */ - err = snd_soc_add_controls(codec, uda1380_magician_controls, + err = snd_soc_add_codec_controls(codec, uda1380_magician_controls, ARRAY_SIZE(uda1380_magician_controls)); if (err < 0) return err; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index fd0ed10c6fe..d2cc8173503 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -43,10 +43,8 @@ static int poodle_jack_func; static int poodle_spk_func; -static void poodle_ext_control(struct snd_soc_codec *codec) +static void poodle_ext_control(struct snd_soc_dapm_context *dapm) { - struct snd_soc_dapm_context *dapm = &codec->dapm; - /* set up jack connection */ if (poodle_jack_func == POODLE_HP) { /* set = unmute headphone */ @@ -81,7 +79,7 @@ static int poodle_startup(struct snd_pcm_substream *substream) mutex_lock(&codec->mutex); /* check the jack status at stream startup */ - poodle_ext_control(codec); + poodle_ext_control(&codec->dapm); mutex_unlock(&codec->mutex); @@ -152,13 +150,13 @@ static int poodle_get_jack(struct snd_kcontrol *kcontrol, static int poodle_set_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (poodle_jack_func == ucontrol->value.integer.value[0]) return 0; poodle_jack_func = ucontrol->value.integer.value[0]; - poodle_ext_control(codec); + poodle_ext_control(&card->dapm); return 1; } @@ -172,13 +170,13 @@ static int poodle_get_spk(struct snd_kcontrol *kcontrol, static int poodle_set_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (poodle_spk_func == ucontrol->value.integer.value[0]) return 0; poodle_spk_func = ucontrol->value.integer.value[0]; - poodle_ext_control(codec); + poodle_ext_control(&card->dapm); return 1; } diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index a57cfbc038e..fd04ce13903 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -668,6 +668,38 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, return 0; } +static void pxa_ssp_set_running_bit(struct snd_pcm_substream *substream, + struct ssp_device *ssp, int value) +{ + uint32_t sscr0 = pxa_ssp_read_reg(ssp, SSCR0); + uint32_t sscr1 = pxa_ssp_read_reg(ssp, SSCR1); + uint32_t sspsp = pxa_ssp_read_reg(ssp, SSPSP); + uint32_t sssr = pxa_ssp_read_reg(ssp, SSSR); + + if (value && (sscr0 & SSCR0_SSE)) + pxa_ssp_write_reg(ssp, SSCR0, sscr0 & ~SSCR0_SSE); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (value) + sscr1 |= SSCR1_TSRE; + else + sscr1 &= ~SSCR1_TSRE; + } else { + if (value) + sscr1 |= SSCR1_RSRE; + else + sscr1 &= ~SSCR1_RSRE; + } + + pxa_ssp_write_reg(ssp, SSCR1, sscr1); + + if (value) { + pxa_ssp_write_reg(ssp, SSSR, sssr); + pxa_ssp_write_reg(ssp, SSPSP, sspsp); + pxa_ssp_write_reg(ssp, SSCR0, sscr0 | SSCR0_SSE); + } +} + static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { @@ -681,42 +713,21 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, pxa_ssp_enable(ssp); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); + pxa_ssp_set_running_bit(substream, ssp, 1); val = pxa_ssp_read_reg(ssp, SSSR); pxa_ssp_write_reg(ssp, SSSR, val); break; case SNDRV_PCM_TRIGGER_START: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); - pxa_ssp_enable(ssp); + pxa_ssp_set_running_bit(substream, ssp, 1); break; case SNDRV_PCM_TRIGGER_STOP: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); + pxa_ssp_set_running_bit(substream, ssp, 0); break; case SNDRV_PCM_TRIGGER_SUSPEND: pxa_ssp_disable(ssp); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); + pxa_ssp_set_running_bit(substream, ssp, 0); break; default: @@ -764,7 +775,8 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai) #define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 837ff341fd6..4800d5fe568 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -103,7 +103,7 @@ static int pxa2xx_ac97_resume(struct snd_soc_dai *dai) #define pxa2xx_ac97_resume NULL #endif -static int pxa2xx_ac97_probe(struct snd_soc_dai *dai) +static int __devinit pxa2xx_ac97_probe(struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev)); } @@ -179,7 +179,7 @@ static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = { * There is only 1 physical AC97 interface for pxa2xx, but it * has extra fifo's that can be used for aux DACs and ADCs. */ -static struct snd_soc_dai_driver pxa_ac97_dai[] = { +static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { { .name = "pxa2xx-ac97", .ac97_control = 1, @@ -244,13 +244,13 @@ static __devinit int pxa2xx_ac97_dev_probe(struct platform_device *pdev) * driver to do interesting things with the clocking to get us up * and running. */ - return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai, - ARRAY_SIZE(pxa_ac97_dai)); + return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai_driver, + ARRAY_SIZE(pxa_ac97_dai_driver)); } static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev) { - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai)); + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai_driver)); return 0; } diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c index ba1545188ec..08370659549 100644 --- a/sound/soc/pxa/raumfeld.c +++ b/sound/soc/pxa/raumfeld.c @@ -232,7 +232,7 @@ static struct snd_soc_ops raumfeld_ak4104_ops = { .cpu_dai_name = "pxa-ssp-dai.0", \ .platform_name = "pxa-pcm-audio", \ .codec_dai_name = "cs4270-hifi", \ - .codec_name = "cs4270-codec.0-0048", \ + .codec_name = "cs4270.0-0048", \ .ops = &raumfeld_cs4270_ops, \ } diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 90c5245c474..fc052d8247f 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -44,10 +44,8 @@ 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) +static void spitz_ext_control(struct snd_soc_dapm_context *dapm) { - struct snd_soc_dapm_context *dapm = &codec->dapm; - if (spitz_spk_func == SPITZ_SPK_ON) snd_soc_dapm_enable_pin(dapm, "Ext Spk"); else @@ -113,7 +111,7 @@ static int spitz_startup(struct snd_pcm_substream *substream) mutex_lock(&codec->mutex); /* check the jack status at stream startup */ - spitz_ext_control(codec); + spitz_ext_control(&codec->dapm); mutex_unlock(&codec->mutex); @@ -173,13 +171,13 @@ static int spitz_get_jack(struct snd_kcontrol *kcontrol, static int spitz_set_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (spitz_jack_func == ucontrol->value.integer.value[0]) return 0; spitz_jack_func = ucontrol->value.integer.value[0]; - spitz_ext_control(codec); + spitz_ext_control(&card->dapm); return 1; } @@ -193,13 +191,13 @@ static int spitz_get_spk(struct snd_kcontrol *kcontrol, static int spitz_set_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); if (spitz_spk_func == ucontrol->value.integer.value[0]) return 0; spitz_spk_func = ucontrol->value.integer.value[0]; - spitz_ext_control(codec); + spitz_ext_control(&card->dapm); return 1; } diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 564ef08a89f..2aec63f3706 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -197,7 +197,7 @@ static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "MONOOUT"); /* add tosa specific controls */ - err = snd_soc_add_controls(codec, tosa_controls, + err = snd_soc_add_codec_controls(codec, tosa_controls, ARRAY_SIZE(tosa_controls)); if (err < 0) return err; diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c index 43c014f362f..716da861c62 100644 --- a/sound/soc/s6000/s6000-pcm.c +++ b/sound/soc/s6000/s6000-pcm.c @@ -435,7 +435,8 @@ static void s6000_pcm_free(struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *runtime = pcm->private_data; struct s6000_pcm_dma_params *params = - snd_soc_dai_get_dma_data(runtime->cpu_dai, pcm->streams[0].substream); + snd_soc_dai_get_dma_data(runtime->cpu_dai, + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream); free_irq(params->irq, pcm); snd_pcm_lib_preallocate_free_for_all(pcm); @@ -451,7 +452,7 @@ static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime) int res; params = snd_soc_dai_get_dma_data(runtime->cpu_dai, - pcm->streams[0].substream); + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream); if (!card->dev->dma_mask) card->dev->dma_mask = &s6000_pcm_dmamask; diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 7b9bf93e370..3d04c1fa678 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -4,7 +4,7 @@ * Evolved from s3c2443-ac97.c * * Copyright (c) 2010 Samsung Electronics Co. Ltd - * Author: Jaswinder Singh <jassi.brar@samsung.com> + * Author: Jaswinder Singh <jassisinghbrar@gmail.com> * Credits: Graeme Gregory, Sean Choi * * This program is free software; you can redistribute it and/or modify @@ -511,7 +511,7 @@ static struct platform_driver s3c_ac97_driver = { module_platform_driver(s3c_ac97_driver); -MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>"); +MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>"); MODULE_DESCRIPTION("AC97 driver for the Samsung SoC"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:samsung-ac97"); diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index e4ba17ce6b3..ddc6cde14e2 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -411,7 +411,7 @@ static int dma_new(struct snd_soc_pcm_runtime *rtd) if (!card->dev->dma_mask) card->dev->dma_mask = &dma_mask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = preallocate_dma_buffer(pcm, diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 87a874dc7a3..6ac7b8281a0 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -3,7 +3,7 @@ * ALSA SoC Audio Layer - Samsung I2S Controller driver * * Copyright (c) 2010 Samsung Electronics Co. Ltd. - * Jaswinder Singh <jassi.brar@samsung.com> + * Jaswinder Singh <jassisinghbrar@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -559,6 +559,17 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, mod |= MOD_DC1_EN; break; case 2: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + i2s->dma_playback.dma_size = 4; + else + i2s->dma_capture.dma_size = 4; + break; + case 1: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + i2s->dma_playback.dma_size = 2; + else + i2s->dma_capture.dma_size = 2; + break; default: dev_err(&i2s->pdev->dev, "%d channels not supported\n", @@ -761,15 +772,13 @@ static int i2s_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_PUSH: local_irq_save(flags); - if (capture) + if (capture) { i2s_rxctrl(i2s, 0); - else - i2s_txctrl(i2s, 0); - - if (capture) i2s_fifo(i2s, FIC_RXFLUSH); - else + } else { + i2s_txctrl(i2s, 0); i2s_fifo(i2s, FIC_TXFLUSH); + } local_irq_restore(flags); break; @@ -965,7 +974,7 @@ struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS; if (!sec) { - i2s->i2s_dai_drv.capture.channels_min = 2; + i2s->i2s_dai_drv.capture.channels_min = 1; i2s->i2s_dai_drv.capture.channels_max = 2; i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES; i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; @@ -1143,7 +1152,7 @@ static struct platform_driver samsung_i2s_driver = { module_platform_driver(samsung_i2s_driver); /* Module information */ -MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>"); +MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>"); MODULE_DESCRIPTION("Samsung I2S Interface"); MODULE_ALIAS("platform:samsung-i2s"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h index 8e15f6a616d..d420a7ca56c 100644 --- a/sound/soc/samsung/i2s.h +++ b/sound/soc/samsung/i2s.h @@ -3,7 +3,7 @@ * ALSA SoC Audio Layer - Samsung I2S Controller driver * * Copyright (c) 2010 Samsung Electronics Co. Ltd. - * Jaswinder Singh <jassi.brar@samsung.com> + * Jaswinder Singh <jassisinghbrar@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 9dd818bde06..e7416851bf7 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -189,6 +189,9 @@ static int littlemill_late_probe(struct snd_soc_card *card) /* This will check device compatibility itself */ wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL); + /* As will this */ + wm8994_mic_detect(codec, &littlemill_headset, 1); + return 0; } diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index d23b19a59d8..321d51134e4 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -296,7 +296,7 @@ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) if (ret) return ret; - ret = snd_soc_add_controls(codec, neo1973_gta02_wm8753_controls, + ret = snd_soc_add_card_controls(codec->card, neo1973_gta02_wm8753_controls, ARRAY_SIZE(neo1973_gta02_wm8753_controls)); if (ret) return ret; @@ -328,7 +328,7 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) return ret; /* add neo1973 specific controls */ - ret = snd_soc_add_controls(codec, neo1973_wm8753_controls, + ret = snd_soc_add_card_controls(rtd->card, neo1973_wm8753_controls, ARRAY_SIZE(neo1973_wm8753_controls)); if (ret) return ret; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 56780206c00..b7b2a1f9142 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -3,7 +3,7 @@ * ALSA SoC Audio Layer - S3C PCM-Controller driver * * Copyright (c) 2009 Samsung Electronics Co. Ltd - * Author: Jaswinder Singh <jassi.brar@samsung.com> + * Author: Jaswinder Singh <jassisinghbrar@gmail.com> * based upon I2S drivers by Ben Dooks. * * This program is free software; you can redistribute it and/or modify @@ -639,7 +639,7 @@ static struct platform_driver s3c_pcm_driver = { module_platform_driver(s3c_pcm_driver); /* Module information */ -MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>"); +MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>"); MODULE_DESCRIPTION("S3C PCM Controller Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:samsung-pcm"); diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c index a253bcc1646..656d5afe4ca 100644 --- a/sound/soc/samsung/s3c24xx_simtec.c +++ b/sound/soc/samsung/s3c24xx_simtec.c @@ -134,18 +134,18 @@ static const struct snd_kcontrol_new amp_unmute_controls[] = { void simtec_audio_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = rtd->card; if (pdata->amp_gpio > 0) { pr_debug("%s: adding amp routes\n", __func__); - snd_soc_add_controls(codec, amp_unmute_controls, + snd_soc_add_card_controls(card, amp_unmute_controls, ARRAY_SIZE(amp_unmute_controls)); } if (pdata->amp_gain[0] > 0) { pr_debug("%s: adding amp controls\n", __func__); - snd_soc_add_controls(codec, amp_gain_controls, + snd_soc_add_card_controls(card, amp_gain_controls, ARRAY_SIZE(amp_gain_controls)); } } diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index bff8758e7f2..ade2809cf39 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -2,7 +2,7 @@ * smdk_wm8580.c * * Copyright (c) 2009 Samsung Electronics Co. Ltd - * Author: Jaswinder Singh <jassi.brar@samsung.com> + * Author: Jaswinder Singh <jassisinghbrar@gmail.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -253,6 +253,6 @@ static void __exit smdk_audio_exit(void) } module_exit(smdk_audio_exit); -MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com"); +MODULE_AUTHOR("Jaswinder Singh, jassisinghbrar@gmail.com"); MODULE_DESCRIPTION("ALSA SoC SMDK WM8580"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c index 8e26a730fcd..55b2ca7f329 100644 --- a/sound/soc/samsung/smdk_wm9713.c +++ b/sound/soc/samsung/smdk_wm9713.c @@ -2,7 +2,7 @@ * smdk_wm9713.c -- SoC audio for SMDK * * Copyright 2010 Samsung Electronics Co. Ltd. - * Author: Jaswinder Singh Brar <jassi.brar@samsung.com> + * Author: Jaswinder Singh Brar <jassisinghbrar@gmail.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -103,6 +103,6 @@ module_init(smdk_init); module_exit(smdk_exit); /* Module information */ -MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar@samsung.com"); +MODULE_AUTHOR("Jaswinder Singh Brar, jassisinghbrar@gmail.com"); MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index ea4a82d0116..378cc5b056d 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -13,8 +13,11 @@ */ #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/io.h> +#include <linux/scatterlist.h> +#include <linux/sh_dma.h> #include <linux/slab.h> #include <linux/module.h> #include <sound/soc.h> @@ -53,6 +56,7 @@ /* DO_FMT */ /* DI_FMT */ +#define CR_BWS_MASK (0x3 << 20) /* FSI2 */ #define CR_BWS_24 (0x0 << 20) /* FSI2 */ #define CR_BWS_16 (0x1 << 20) /* FSI2 */ #define CR_BWS_20 (0x2 << 20) /* FSI2 */ @@ -68,6 +72,15 @@ #define CR_TDM (0x4 << 4) #define CR_TDM_D (0x5 << 4) +/* OUT_DMAC */ +/* IN_DMAC */ +#define VDMD_MASK (0x3 << 4) +#define VDMD_FRONT (0x0 << 4) /* Package in front */ +#define VDMD_BACK (0x1 << 4) /* Package in back */ +#define VDMD_STREAM (0x2 << 4) /* Stream mode(16bit * 2) */ + +#define DMA_ON (0x1 << 0) + /* DOFF_CTL */ /* DIFF_CTL */ #define IRQ_HALF 0x00100000 @@ -116,7 +129,7 @@ #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) -typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int enable); +typedef int (*set_rate_func)(struct device *dev, int rate, int enable); /* * FSI driver use below type name for variable @@ -159,22 +172,41 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena * struct */ +struct fsi_stream_handler; struct fsi_stream { - struct snd_pcm_substream *substream; + /* + * these are initialized by fsi_stream_init() + */ + struct snd_pcm_substream *substream; int fifo_sample_capa; /* sample capacity of FSI FIFO */ int buff_sample_capa; /* sample capacity of ALSA buffer */ int buff_sample_pos; /* sample position of ALSA buffer */ int period_samples; /* sample number / 1 period */ int period_pos; /* current period position */ - + int sample_width; /* sample width */ int uerr_num; int oerr_num; + + /* + * thse are initialized by fsi_handler_init() + */ + struct fsi_stream_handler *handler; + struct fsi_priv *priv; + + /* + * these are for DMAEngine + */ + struct dma_chan *chan; + struct sh_dmae_slave slave; /* see fsi_handler_init() */ + struct tasklet_struct tasklet; + dma_addr_t dma; }; struct fsi_priv { void __iomem *base; struct fsi_master *master; + struct sh_fsi_port_info *info; struct fsi_stream playback; struct fsi_stream capture; @@ -189,6 +221,20 @@ struct fsi_priv { long rate; }; +struct fsi_stream_handler { + int (*init)(struct fsi_priv *fsi, struct fsi_stream *io); + int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io); + int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io); + int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); + int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); + void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io, + int enable); +}; +#define fsi_stream_handler_call(io, func, args...) \ + (!(io) ? -ENODEV : \ + !((io)->handler->func) ? 0 : \ + (io)->handler->func(args)) + struct fsi_core { int ver; @@ -205,10 +251,11 @@ struct fsi_master { struct fsi_priv fsia; struct fsi_priv fsib; struct fsi_core *core; - struct sh_fsi_platform_info *info; spinlock_t lock; }; +static int fsi_stream_is_play(struct fsi_priv *fsi, struct fsi_stream *io); + /* * basic read write function */ @@ -295,6 +342,11 @@ static int fsi_is_spdif(struct fsi_priv *fsi) return fsi->spdif; } +static int fsi_is_play(struct snd_pcm_substream *substream) +{ + return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; +} + static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -317,44 +369,25 @@ static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) return fsi_get_priv_frm_dai(fsi_get_dai(substream)); } -static set_rate_func fsi_get_info_set_rate(struct fsi_master *master) +static set_rate_func fsi_get_info_set_rate(struct fsi_priv *fsi) { - if (!master->info) + if (!fsi->info) return NULL; - return master->info->set_rate; + return fsi->info->set_rate; } static u32 fsi_get_info_flags(struct fsi_priv *fsi) { - int is_porta = fsi_is_port_a(fsi); - struct fsi_master *master = fsi_get_master(fsi); - - if (!master->info) + if (!fsi->info) return 0; - return is_porta ? master->info->porta_flags : - master->info->portb_flags; -} - -static inline int fsi_stream_is_play(int stream) -{ - return stream == SNDRV_PCM_STREAM_PLAYBACK; -} - -static inline int fsi_is_play(struct snd_pcm_substream *substream) -{ - return fsi_stream_is_play(substream->stream); + return fsi->info->flags; } -static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi, - int is_play) -{ - return is_play ? &fsi->playback : &fsi->capture; -} - -static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) +static u32 fsi_get_port_shift(struct fsi_priv *fsi, struct fsi_stream *io) { + int is_play = fsi_stream_is_play(fsi, io); int is_porta = fsi_is_port_a(fsi); u32 shift; @@ -376,26 +409,81 @@ static int fsi_sample2frame(struct fsi_priv *fsi, int samples) return samples / fsi->chan_num; } +static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, + struct fsi_stream *io) +{ + int is_play = fsi_stream_is_play(fsi, io); + u32 status; + int frames; + + status = is_play ? + fsi_reg_read(fsi, DOFF_ST) : + fsi_reg_read(fsi, DIFF_ST); + + frames = 0x1ff & (status >> 8); + + return fsi_frame2sample(fsi, frames); +} + +static void fsi_count_fifo_err(struct fsi_priv *fsi) +{ + u32 ostatus = fsi_reg_read(fsi, DOFF_ST); + u32 istatus = fsi_reg_read(fsi, DIFF_ST); + + if (ostatus & ERR_OVER) + fsi->playback.oerr_num++; + + if (ostatus & ERR_UNDER) + fsi->playback.uerr_num++; + + if (istatus & ERR_OVER) + fsi->capture.oerr_num++; + + if (istatus & ERR_UNDER) + fsi->capture.uerr_num++; + + fsi_reg_write(fsi, DOFF_ST, 0); + fsi_reg_write(fsi, DIFF_ST, 0); +} + +/* + * fsi_stream_xx() function + */ +static inline int fsi_stream_is_play(struct fsi_priv *fsi, + struct fsi_stream *io) +{ + return &fsi->playback == io; +} + +static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi, + struct snd_pcm_substream *substream) +{ + return fsi_is_play(substream) ? &fsi->playback : &fsi->capture; +} + static int fsi_stream_is_working(struct fsi_priv *fsi, - int is_play) + struct fsi_stream *io) { - struct fsi_stream *io = fsi_get_stream(fsi, is_play); struct fsi_master *master = fsi_get_master(fsi); unsigned long flags; int ret; spin_lock_irqsave(&master->lock, flags); - ret = !!io->substream; + ret = !!(io->substream && io->substream->runtime); spin_unlock_irqrestore(&master->lock, flags); return ret; } -static void fsi_stream_push(struct fsi_priv *fsi, - int is_play, +static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io) +{ + return io->priv; +} + +static void fsi_stream_init(struct fsi_priv *fsi, + struct fsi_stream *io, struct snd_pcm_substream *substream) { - struct fsi_stream *io = fsi_get_stream(fsi, is_play); struct snd_pcm_runtime *runtime = substream->runtime; struct fsi_master *master = fsi_get_master(fsi); unsigned long flags; @@ -406,14 +494,15 @@ static void fsi_stream_push(struct fsi_priv *fsi, io->buff_sample_pos = 0; io->period_samples = fsi_frame2sample(fsi, runtime->period_size); io->period_pos = 0; + io->sample_width = samples_to_bytes(runtime, 1); io->oerr_num = -1; /* ignore 1st err */ io->uerr_num = -1; /* ignore 1st err */ + fsi_stream_handler_call(io, init, fsi, io); spin_unlock_irqrestore(&master->lock, flags); } -static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) +static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io) { - struct fsi_stream *io = fsi_get_stream(fsi, is_play); struct snd_soc_dai *dai = fsi_get_dai(io->substream); struct fsi_master *master = fsi_get_master(fsi); unsigned long flags; @@ -426,127 +515,87 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) if (io->uerr_num > 0) dev_err(dai->dev, "under_run = %d\n", io->uerr_num); + fsi_stream_handler_call(io, quit, fsi, io); io->substream = NULL; io->buff_sample_capa = 0; io->buff_sample_pos = 0; io->period_samples = 0; io->period_pos = 0; + io->sample_width = 0; io->oerr_num = 0; io->uerr_num = 0; spin_unlock_irqrestore(&master->lock, flags); } -static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, int is_play) +static int fsi_stream_transfer(struct fsi_stream *io) { - u32 status; - int frames; - - status = is_play ? - fsi_reg_read(fsi, DOFF_ST) : - fsi_reg_read(fsi, DIFF_ST); - - frames = 0x1ff & (status >> 8); - - return fsi_frame2sample(fsi, frames); -} - -static void fsi_count_fifo_err(struct fsi_priv *fsi) -{ - u32 ostatus = fsi_reg_read(fsi, DOFF_ST); - u32 istatus = fsi_reg_read(fsi, DIFF_ST); - - if (ostatus & ERR_OVER) - fsi->playback.oerr_num++; - - if (ostatus & ERR_UNDER) - fsi->playback.uerr_num++; - - if (istatus & ERR_OVER) - fsi->capture.oerr_num++; - - if (istatus & ERR_UNDER) - fsi->capture.uerr_num++; + struct fsi_priv *fsi = fsi_stream_to_priv(io); + if (!fsi) + return -EIO; - fsi_reg_write(fsi, DOFF_ST, 0); - fsi_reg_write(fsi, DIFF_ST, 0); + return fsi_stream_handler_call(io, transfer, fsi, io); } -/* - * dma function - */ +#define fsi_stream_start(fsi, io)\ + fsi_stream_handler_call(io, start_stop, fsi, io, 1) -static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream) -{ - int is_play = fsi_stream_is_play(stream); - struct fsi_stream *io = fsi_get_stream(fsi, is_play); - struct snd_pcm_runtime *runtime = io->substream->runtime; +#define fsi_stream_stop(fsi, io)\ + fsi_stream_handler_call(io, start_stop, fsi, io, 0) - return runtime->dma_area + - samples_to_bytes(runtime, io->buff_sample_pos); -} - -static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num) +static int fsi_stream_probe(struct fsi_priv *fsi) { - u16 *start; - int i; - - start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK); + struct fsi_stream *io; + int ret1, ret2; - for (i = 0; i < num; i++) - fsi_reg_write(fsi, DODT, ((u32)*(start + i) << 8)); -} - -static void fsi_dma_soft_pop16(struct fsi_priv *fsi, int num) -{ - u16 *start; - int i; + io = &fsi->playback; + ret1 = fsi_stream_handler_call(io, probe, fsi, io); - start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE); + io = &fsi->capture; + ret2 = fsi_stream_handler_call(io, probe, fsi, io); + if (ret1 < 0) + return ret1; + if (ret2 < 0) + return ret2; - for (i = 0; i < num; i++) - *(start + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8); + return 0; } -static void fsi_dma_soft_push32(struct fsi_priv *fsi, int num) +static int fsi_stream_remove(struct fsi_priv *fsi) { - u32 *start; - int i; + struct fsi_stream *io; + int ret1, ret2; - start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK); - - - for (i = 0; i < num; i++) - fsi_reg_write(fsi, DODT, *(start + i)); -} + io = &fsi->playback; + ret1 = fsi_stream_handler_call(io, remove, fsi, io); -static void fsi_dma_soft_pop32(struct fsi_priv *fsi, int num) -{ - u32 *start; - int i; + io = &fsi->capture; + ret2 = fsi_stream_handler_call(io, remove, fsi, io); - start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE); + if (ret1 < 0) + return ret1; + if (ret2 < 0) + return ret2; - for (i = 0; i < num; i++) - *(start + i) = fsi_reg_read(fsi, DIDT); + return 0; } /* * irq function */ -static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) +static void fsi_irq_enable(struct fsi_priv *fsi, struct fsi_stream *io) { - u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play)); + u32 data = AB_IO(1, fsi_get_port_shift(fsi, io)); struct fsi_master *master = fsi_get_master(fsi); fsi_core_mask_set(master, imsk, data, data); fsi_core_mask_set(master, iemsk, data, data); } -static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) +static void fsi_irq_disable(struct fsi_priv *fsi, struct fsi_stream *io) { - u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play)); + u32 data = AB_IO(1, fsi_get_port_shift(fsi, io)); struct fsi_master *master = fsi_get_master(fsi); fsi_core_mask_set(master, imsk, data, 0); @@ -563,8 +612,8 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi) u32 data = 0; struct fsi_master *master = fsi_get_master(fsi); - data |= AB_IO(1, fsi_get_port_shift(fsi, 0)); - data |= AB_IO(1, fsi_get_port_shift(fsi, 1)); + data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->playback)); + data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->capture)); /* clear interrupt factor */ fsi_core_mask_set(master, int_st, data, 0); @@ -600,11 +649,14 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, long rate, int enable) { struct fsi_master *master = fsi_get_master(fsi); - set_rate_func set_rate = fsi_get_info_set_rate(master); + set_rate_func set_rate = fsi_get_info_set_rate(fsi); int fsi_ver = master->core->ver; int ret; - ret = set_rate(dev, fsi_is_port_a(fsi), rate, enable); + if (!set_rate) + return 0; + + ret = set_rate(dev, rate, enable); if (ret < 0) /* error */ return ret; @@ -671,96 +723,64 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, return ret; } -#define fsi_port_start(f, i) __fsi_port_clk_ctrl(f, i, 1) -#define fsi_port_stop(f, i) __fsi_port_clk_ctrl(f, i, 0) -static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int is_play, int enable) +/* + * pio data transfer handler + */ +static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples) { - struct fsi_master *master = fsi_get_master(fsi); - u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; + u16 *buf = (u16 *)_buf; + int i; - if (enable) - fsi_irq_enable(fsi, is_play); - else - fsi_irq_disable(fsi, is_play); + for (i = 0; i < samples; i++) + fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8)); +} - if (fsi_is_clk_master(fsi)) - fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); +static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples) +{ + u16 *buf = (u16 *)_buf; + int i; + + for (i = 0; i < samples; i++) + *(buf + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8); } -/* - * ctrl function - */ -static void fsi_fifo_init(struct fsi_priv *fsi, - int is_play, - struct device *dev) +static void fsi_pio_push32(struct fsi_priv *fsi, u8 *_buf, int samples) { - struct fsi_master *master = fsi_get_master(fsi); - struct fsi_stream *io = fsi_get_stream(fsi, is_play); - u32 shift, i; - int frame_capa; + u32 *buf = (u32 *)_buf; + int i; - /* get on-chip RAM capacity */ - shift = fsi_master_read(master, FIFO_SZ); - shift >>= fsi_get_port_shift(fsi, is_play); - shift &= FIFO_SZ_MASK; - frame_capa = 256 << shift; - dev_dbg(dev, "fifo = %d words\n", frame_capa); + for (i = 0; i < samples; i++) + fsi_reg_write(fsi, DODT, *(buf + i)); +} - /* - * The maximum number of sample data varies depending - * on the number of channels selected for the format. - * - * FIFOs are used in 4-channel units in 3-channel mode - * and in 8-channel units in 5- to 7-channel mode - * meaning that more FIFOs than the required size of DPRAM - * are used. - * - * ex) if 256 words of DP-RAM is connected - * 1 channel: 256 (256 x 1 = 256) - * 2 channels: 128 (128 x 2 = 256) - * 3 channels: 64 ( 64 x 3 = 192) - * 4 channels: 64 ( 64 x 4 = 256) - * 5 channels: 32 ( 32 x 5 = 160) - * 6 channels: 32 ( 32 x 6 = 192) - * 7 channels: 32 ( 32 x 7 = 224) - * 8 channels: 32 ( 32 x 8 = 256) - */ - for (i = 1; i < fsi->chan_num; i <<= 1) - frame_capa >>= 1; - dev_dbg(dev, "%d channel %d store\n", - fsi->chan_num, frame_capa); +static void fsi_pio_pop32(struct fsi_priv *fsi, u8 *_buf, int samples) +{ + u32 *buf = (u32 *)_buf; + int i; - io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa); + for (i = 0; i < samples; i++) + *(buf + i) = fsi_reg_read(fsi, DIDT); +} - /* - * set interrupt generation factor - * clear FIFO - */ - if (is_play) { - fsi_reg_write(fsi, DOFF_CTL, IRQ_HALF); - fsi_reg_mask_set(fsi, DOFF_CTL, FIFO_CLR, FIFO_CLR); - } else { - fsi_reg_write(fsi, DIFF_CTL, IRQ_HALF); - fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); - } +static u8 *fsi_pio_get_area(struct fsi_priv *fsi, struct fsi_stream *io) +{ + struct snd_pcm_runtime *runtime = io->substream->runtime; + + return runtime->dma_area + + samples_to_bytes(runtime, io->buff_sample_pos); } -static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) +static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, + void (*run16)(struct fsi_priv *fsi, u8 *buf, int samples), + void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples), + int samples) { struct snd_pcm_runtime *runtime; - struct snd_pcm_substream *substream = NULL; - int is_play = fsi_stream_is_play(stream); - struct fsi_stream *io = fsi_get_stream(fsi, is_play); - int sample_residues; - int sample_width; - int samples; - int samples_max; + struct snd_pcm_substream *substream; + u8 *buf; int over_period; - void (*fn)(struct fsi_priv *fsi, int size); - if (!fsi || - !io->substream || - !io->substream->runtime) + if (!fsi_stream_is_working(fsi, io)) return -EINVAL; over_period = 0; @@ -780,60 +800,19 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) io->buff_sample_pos = 0; } - /* get 1 sample data width */ - sample_width = samples_to_bytes(runtime, 1); + buf = fsi_pio_get_area(fsi, io); - /* get number of residue samples */ - sample_residues = io->buff_sample_capa - io->buff_sample_pos; - - if (is_play) { - /* - * for play-back - * - * samples_max : number of FSI fifo free samples space - * samples : number of ALSA residue samples - */ - samples_max = io->fifo_sample_capa; - samples_max -= fsi_get_current_fifo_samples(fsi, is_play); - - samples = sample_residues; - - switch (sample_width) { - case 2: - fn = fsi_dma_soft_push16; - break; - case 4: - fn = fsi_dma_soft_push32; - break; - default: - return -EINVAL; - } - } else { - /* - * for capture - * - * samples_max : number of ALSA free samples space - * samples : number of samples in FSI fifo - */ - samples_max = sample_residues; - samples = fsi_get_current_fifo_samples(fsi, is_play); - - switch (sample_width) { - case 2: - fn = fsi_dma_soft_pop16; - break; - case 4: - fn = fsi_dma_soft_pop32; - break; - default: - return -EINVAL; - } + switch (io->sample_width) { + case 2: + run16(fsi, buf, samples); + break; + case 4: + run32(fsi, buf, samples); + break; + default: + return -EINVAL; } - samples = min(samples, samples_max); - - fn(fsi, samples); - /* update buff_sample_pos */ io->buff_sample_pos += samples; @@ -843,16 +822,66 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) return 0; } -static int fsi_data_pop(struct fsi_priv *fsi) +static int fsi_pio_pop(struct fsi_priv *fsi, struct fsi_stream *io) +{ + int sample_residues; /* samples in FSI fifo */ + int sample_space; /* ALSA free samples space */ + int samples; + + sample_residues = fsi_get_current_fifo_samples(fsi, io); + sample_space = io->buff_sample_capa - io->buff_sample_pos; + + samples = min(sample_residues, sample_space); + + return fsi_pio_transfer(fsi, io, + fsi_pio_pop16, + fsi_pio_pop32, + samples); +} + +static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io) { - return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_CAPTURE); + int sample_residues; /* ALSA residue samples */ + int sample_space; /* FSI fifo free samples space */ + int samples; + + sample_residues = io->buff_sample_capa - io->buff_sample_pos; + sample_space = io->fifo_sample_capa - + fsi_get_current_fifo_samples(fsi, io); + + samples = min(sample_residues, sample_space); + + return fsi_pio_transfer(fsi, io, + fsi_pio_push16, + fsi_pio_push32, + samples); } -static int fsi_data_push(struct fsi_priv *fsi) +static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, + int enable) { - return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_PLAYBACK); + struct fsi_master *master = fsi_get_master(fsi); + u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; + + if (enable) + fsi_irq_enable(fsi, io); + else + fsi_irq_disable(fsi, io); + + if (fsi_is_clk_master(fsi)) + fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); } +static struct fsi_stream_handler fsi_pio_push_handler = { + .transfer = fsi_pio_push, + .start_stop = fsi_pio_start_stop, +}; + +static struct fsi_stream_handler fsi_pio_pop_handler = { + .transfer = fsi_pio_pop, + .start_stop = fsi_pio_start_stop, +}; + static irqreturn_t fsi_interrupt(int irq, void *data) { struct fsi_master *master = data; @@ -863,13 +892,13 @@ static irqreturn_t fsi_interrupt(int irq, void *data) fsi_master_mask_set(master, SOFT_RST, IR, IR); if (int_st & AB_IO(1, AO_SHIFT)) - fsi_data_push(&master->fsia); + fsi_stream_transfer(&master->fsia.playback); if (int_st & AB_IO(1, BO_SHIFT)) - fsi_data_push(&master->fsib); + fsi_stream_transfer(&master->fsib.playback); if (int_st & AB_IO(1, AI_SHIFT)) - fsi_data_pop(&master->fsia); + fsi_stream_transfer(&master->fsia.capture); if (int_st & AB_IO(1, BI_SHIFT)) - fsi_data_pop(&master->fsib); + fsi_stream_transfer(&master->fsib.capture); fsi_count_fifo_err(&master->fsia); fsi_count_fifo_err(&master->fsib); @@ -881,11 +910,271 @@ static irqreturn_t fsi_interrupt(int irq, void *data) } /* + * dma data transfer handler + */ +static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) +{ + struct snd_pcm_runtime *runtime = io->substream->runtime; + struct snd_soc_dai *dai = fsi_get_dai(io->substream); + enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? + DMA_TO_DEVICE : DMA_FROM_DEVICE; + + io->dma = dma_map_single(dai->dev, runtime->dma_area, + snd_pcm_lib_buffer_bytes(io->substream), dir); + return 0; +} + +static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io) +{ + struct snd_soc_dai *dai = fsi_get_dai(io->substream); + enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? + DMA_TO_DEVICE : DMA_FROM_DEVICE; + + dma_unmap_single(dai->dev, io->dma, + snd_pcm_lib_buffer_bytes(io->substream), dir); + return 0; +} + +static void fsi_dma_complete(void *data) +{ + struct fsi_stream *io = (struct fsi_stream *)data; + struct fsi_priv *fsi = fsi_stream_to_priv(io); + struct snd_pcm_runtime *runtime = io->substream->runtime; + struct snd_soc_dai *dai = fsi_get_dai(io->substream); + enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? + DMA_TO_DEVICE : DMA_FROM_DEVICE; + + dma_sync_single_for_cpu(dai->dev, io->dma, + samples_to_bytes(runtime, io->period_samples), dir); + + io->buff_sample_pos += io->period_samples; + io->period_pos++; + + if (io->period_pos >= runtime->periods) { + io->period_pos = 0; + io->buff_sample_pos = 0; + } + + fsi_count_fifo_err(fsi); + fsi_stream_transfer(io); + + snd_pcm_period_elapsed(io->substream); +} + +static dma_addr_t fsi_dma_get_area(struct fsi_stream *io) +{ + struct snd_pcm_runtime *runtime = io->substream->runtime; + + return io->dma + samples_to_bytes(runtime, io->buff_sample_pos); +} + +static void fsi_dma_do_tasklet(unsigned long data) +{ + struct fsi_stream *io = (struct fsi_stream *)data; + struct fsi_priv *fsi = fsi_stream_to_priv(io); + struct dma_chan *chan; + struct snd_soc_dai *dai; + struct dma_async_tx_descriptor *desc; + struct scatterlist sg; + struct snd_pcm_runtime *runtime; + enum dma_data_direction dir; + dma_cookie_t cookie; + int is_play = fsi_stream_is_play(fsi, io); + int len; + dma_addr_t buf; + + if (!fsi_stream_is_working(fsi, io)) + return; + + dai = fsi_get_dai(io->substream); + chan = io->chan; + runtime = io->substream->runtime; + dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + len = samples_to_bytes(runtime, io->period_samples); + buf = fsi_dma_get_area(io); + + dma_sync_single_for_device(dai->dev, io->dma, len, dir); + + sg_init_table(&sg, 1); + sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)), + len , offset_in_page(buf)); + sg_dma_address(&sg) = buf; + sg_dma_len(&sg) = len; + + desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir, + DMA_PREP_INTERRUPT | + DMA_CTRL_ACK); + if (!desc) { + dev_err(dai->dev, "device_prep_slave_sg() fail\n"); + return; + } + + desc->callback = fsi_dma_complete; + desc->callback_param = io; + + cookie = desc->tx_submit(desc); + if (cookie < 0) { + dev_err(dai->dev, "tx_submit() fail\n"); + return; + } + + dma_async_issue_pending(chan); + + /* + * FIXME + * + * In DMAEngine case, codec and FSI cannot be started simultaneously + * since FSI is using tasklet. + * Therefore, in capture case, probably FSI FIFO will have got + * overflow error in this point. + * in that case, DMA cannot start transfer until error was cleared. + */ + if (!is_play) { + if (ERR_OVER & fsi_reg_read(fsi, DIFF_ST)) { + fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); + fsi_reg_write(fsi, DIFF_ST, 0); + } + } +} + +static bool fsi_dma_filter(struct dma_chan *chan, void *param) +{ + struct sh_dmae_slave *slave = param; + + chan->private = slave; + + return true; +} + +static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) +{ + tasklet_schedule(&io->tasklet); + + return 0; +} + +static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, + int start) +{ + u32 bws; + u32 dma; + + switch (io->sample_width * start) { + case 2: + bws = CR_BWS_16; + dma = VDMD_STREAM | DMA_ON; + break; + case 4: + bws = CR_BWS_24; + dma = VDMD_BACK | DMA_ON; + break; + default: + bws = 0; + dma = 0; + } + + fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws); + fsi_reg_write(fsi, OUT_DMAC, dma); +} + +static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) +{ + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave); + if (!io->chan) + return -EIO; + + tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io); + + return 0; +} + +static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) +{ + tasklet_kill(&io->tasklet); + + fsi_stream_stop(fsi, io); + + if (io->chan) + dma_release_channel(io->chan); + + io->chan = NULL; + return 0; +} + +static struct fsi_stream_handler fsi_dma_push_handler = { + .init = fsi_dma_init, + .quit = fsi_dma_quit, + .probe = fsi_dma_probe, + .transfer = fsi_dma_transfer, + .remove = fsi_dma_remove, + .start_stop = fsi_dma_push_start_stop, +}; + +/* * dai ops */ +static void fsi_fifo_init(struct fsi_priv *fsi, + struct fsi_stream *io, + struct device *dev) +{ + struct fsi_master *master = fsi_get_master(fsi); + int is_play = fsi_stream_is_play(fsi, io); + u32 shift, i; + int frame_capa; + + /* get on-chip RAM capacity */ + shift = fsi_master_read(master, FIFO_SZ); + shift >>= fsi_get_port_shift(fsi, io); + shift &= FIFO_SZ_MASK; + frame_capa = 256 << shift; + dev_dbg(dev, "fifo = %d words\n", frame_capa); + + /* + * The maximum number of sample data varies depending + * on the number of channels selected for the format. + * + * FIFOs are used in 4-channel units in 3-channel mode + * and in 8-channel units in 5- to 7-channel mode + * meaning that more FIFOs than the required size of DPRAM + * are used. + * + * ex) if 256 words of DP-RAM is connected + * 1 channel: 256 (256 x 1 = 256) + * 2 channels: 128 (128 x 2 = 256) + * 3 channels: 64 ( 64 x 3 = 192) + * 4 channels: 64 ( 64 x 4 = 256) + * 5 channels: 32 ( 32 x 5 = 160) + * 6 channels: 32 ( 32 x 6 = 192) + * 7 channels: 32 ( 32 x 7 = 224) + * 8 channels: 32 ( 32 x 8 = 256) + */ + for (i = 1; i < fsi->chan_num; i <<= 1) + frame_capa >>= 1; + dev_dbg(dev, "%d channel %d store\n", + fsi->chan_num, frame_capa); + + io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa); + + /* + * set interrupt generation factor + * clear FIFO + */ + if (is_play) { + fsi_reg_write(fsi, DOFF_CTL, IRQ_HALF); + fsi_reg_mask_set(fsi, DOFF_CTL, FIFO_CLR, FIFO_CLR); + } else { + fsi_reg_write(fsi, DIFF_CTL, IRQ_HALF); + fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); + } +} static int fsi_hw_startup(struct fsi_priv *fsi, - int is_play, + struct fsi_stream *io, struct device *dev) { struct fsi_master *master = fsi_get_master(fsi); @@ -934,17 +1223,16 @@ static int fsi_hw_startup(struct fsi_priv *fsi, } /* irq clear */ - fsi_irq_disable(fsi, is_play); + fsi_irq_disable(fsi, io); fsi_irq_clear_status(fsi); /* fifo init */ - fsi_fifo_init(fsi, is_play, dev); + fsi_fifo_init(fsi, io, dev); return 0; } static void fsi_hw_shutdown(struct fsi_priv *fsi, - int is_play, struct device *dev) { if (fsi_is_clk_master(fsi)) @@ -955,18 +1243,16 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsi_priv *fsi = fsi_get_priv(substream); - int is_play = fsi_is_play(substream); - return fsi_hw_startup(fsi, is_play, dai->dev); + return fsi_hw_startup(fsi, fsi_stream_get(fsi, substream), dai->dev); } static void fsi_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsi_priv *fsi = fsi_get_priv(substream); - int is_play = fsi_is_play(substream); - fsi_hw_shutdown(fsi, is_play, dai->dev); + fsi_hw_shutdown(fsi, dai->dev); fsi->rate = 0; } @@ -974,18 +1260,19 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct fsi_priv *fsi = fsi_get_priv(substream); - int is_play = fsi_is_play(substream); + struct fsi_stream *io = fsi_stream_get(fsi, substream); int ret = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - fsi_stream_push(fsi, is_play, substream); - ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); - fsi_port_start(fsi, is_play); + fsi_stream_init(fsi, io, substream); + ret = fsi_stream_transfer(io); + if (0 == ret) + fsi_stream_start(fsi, io); break; case SNDRV_PCM_TRIGGER_STOP: - fsi_port_stop(fsi, is_play); - fsi_stream_pop(fsi, is_play); + fsi_stream_stop(fsi, io); + fsi_stream_quit(fsi, io); break; } @@ -1036,8 +1323,7 @@ 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); + set_rate_func set_rate = fsi_get_info_set_rate(fsi); u32 flags = fsi_get_info_flags(fsi); int ret; @@ -1151,7 +1437,7 @@ static int fsi_hw_free(struct snd_pcm_substream *substream) static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) { struct fsi_priv *fsi = fsi_get_priv(substream); - struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream)); + struct fsi_stream *io = fsi_stream_get(fsi, substream); return fsi_sample2frame(fsi, io->buff_sample_pos); } @@ -1239,11 +1525,24 @@ static struct snd_soc_platform_driver fsi_soc_platform = { /* * platform function */ +static void fsi_handler_init(struct fsi_priv *fsi) +{ + fsi->playback.handler = &fsi_pio_push_handler; /* default PIO */ + fsi->playback.priv = fsi; + fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */ + fsi->capture.priv = fsi; + + if (fsi->info->tx_id) { + fsi->playback.slave.slave_id = fsi->info->tx_id; + fsi->playback.handler = &fsi_dma_push_handler; + } +} static int fsi_probe(struct platform_device *pdev) { struct fsi_master *master; const struct platform_device_id *id_entry; + struct sh_fsi_platform_info *info = pdev->dev.platform_data; struct resource *res; unsigned int irq; int ret; @@ -1278,17 +1577,30 @@ static int fsi_probe(struct platform_device *pdev) /* master setting */ master->irq = irq; - master->info = pdev->dev.platform_data; master->core = (struct fsi_core *)id_entry->driver_data; spin_lock_init(&master->lock); /* FSI A setting */ master->fsia.base = master->base; master->fsia.master = master; + master->fsia.info = &info->port_a; + fsi_handler_init(&master->fsia); + ret = fsi_stream_probe(&master->fsia); + if (ret < 0) { + dev_err(&pdev->dev, "FSIA stream probe failed\n"); + goto exit_iounmap; + } /* FSI B setting */ master->fsib.base = master->base + 0x40; master->fsib.master = master; + master->fsib.info = &info->port_b; + fsi_handler_init(&master->fsib); + ret = fsi_stream_probe(&master->fsib); + if (ret < 0) { + dev_err(&pdev->dev, "FSIB stream probe failed\n"); + goto exit_fsia; + } pm_runtime_enable(&pdev->dev); dev_set_drvdata(&pdev->dev, master); @@ -1297,7 +1609,7 @@ static int fsi_probe(struct platform_device *pdev) id_entry->name, master); if (ret) { dev_err(&pdev->dev, "irq request err\n"); - goto exit_iounmap; + goto exit_fsib; } ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform); @@ -1319,6 +1631,10 @@ exit_snd_soc: snd_soc_unregister_platform(&pdev->dev); exit_free_irq: free_irq(irq, master); +exit_fsib: + fsi_stream_remove(&master->fsib); +exit_fsia: + fsi_stream_remove(&master->fsia); exit_iounmap: iounmap(master->base); pm_runtime_disable(&pdev->dev); @@ -1341,6 +1657,9 @@ static int fsi_remove(struct platform_device *pdev) snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); snd_soc_unregister_platform(&pdev->dev); + fsi_stream_remove(&master->fsia); + fsi_stream_remove(&master->fsib); + iounmap(master->base); kfree(master); @@ -1348,30 +1667,29 @@ static int fsi_remove(struct platform_device *pdev) } static void __fsi_suspend(struct fsi_priv *fsi, - int is_play, + struct fsi_stream *io, struct device *dev) { - if (!fsi_stream_is_working(fsi, is_play)) + if (!fsi_stream_is_working(fsi, io)) return; - fsi_port_stop(fsi, is_play); - fsi_hw_shutdown(fsi, is_play, dev); + fsi_stream_stop(fsi, io); + fsi_hw_shutdown(fsi, dev); } static void __fsi_resume(struct fsi_priv *fsi, - int is_play, + struct fsi_stream *io, struct device *dev) { - if (!fsi_stream_is_working(fsi, is_play)) + if (!fsi_stream_is_working(fsi, io)) return; - fsi_hw_startup(fsi, is_play, dev); + fsi_hw_startup(fsi, io, dev); if (fsi_is_clk_master(fsi) && fsi->rate) fsi_set_master_clk(dev, fsi, fsi->rate, 1); - fsi_port_start(fsi, is_play); - + fsi_stream_start(fsi, io); } static int fsi_suspend(struct device *dev) @@ -1380,11 +1698,11 @@ static int fsi_suspend(struct device *dev) struct fsi_priv *fsia = &master->fsia; struct fsi_priv *fsib = &master->fsib; - __fsi_suspend(fsia, 1, dev); - __fsi_suspend(fsia, 0, dev); + __fsi_suspend(fsia, &fsia->playback, dev); + __fsi_suspend(fsia, &fsia->capture, dev); - __fsi_suspend(fsib, 1, dev); - __fsi_suspend(fsib, 0, dev); + __fsi_suspend(fsib, &fsib->playback, dev); + __fsi_suspend(fsib, &fsib->capture, dev); return 0; } @@ -1395,32 +1713,18 @@ static int fsi_resume(struct device *dev) struct fsi_priv *fsia = &master->fsia; struct fsi_priv *fsib = &master->fsib; - __fsi_resume(fsia, 1, dev); - __fsi_resume(fsia, 0, dev); + __fsi_resume(fsia, &fsia->playback, dev); + __fsi_resume(fsia, &fsia->capture, dev); - __fsi_resume(fsib, 1, dev); - __fsi_resume(fsib, 0, dev); + __fsi_resume(fsib, &fsib->playback, dev); + __fsi_resume(fsib, &fsib->capture, dev); return 0; } -static int fsi_runtime_nop(struct device *dev) -{ - /* Runtime PM callback shared between ->runtime_suspend() - * and ->runtime_resume(). Simply returns success. - * - * This driver re-initializes all registers after - * pm_runtime_get_sync() anyway so there is no need - * to save and restore registers here. - */ - return 0; -} - static struct dev_pm_ops fsi_pm_ops = { .suspend = fsi_suspend, .resume = fsi_resume, - .runtime_suspend = fsi_runtime_nop, - .runtime_resume = fsi_runtime_nop, }; static struct fsi_core fsi1_core = { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 92cee24ed2d..a4deebc0801 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -277,8 +277,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) codec->debugfs_codec_root = debugfs_create_dir(codec->name, debugfs_card_root); if (!codec->debugfs_codec_root) { - printk(KERN_WARNING - "ASoC: Failed to create codec debugfs directory\n"); + dev_warn(codec->dev, "Failed to create codec debugfs directory\n"); return; } @@ -291,8 +290,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) codec->debugfs_codec_root, codec, &codec_reg_fops); if (!codec->debugfs_reg) - printk(KERN_WARNING - "ASoC: Failed to create codec register debugfs file\n"); + dev_warn(codec->dev, "Failed to create codec register debugfs file\n"); snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); } @@ -302,6 +300,27 @@ static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) debugfs_remove_recursive(codec->debugfs_codec_root); } +static void soc_init_platform_debugfs(struct snd_soc_platform *platform) +{ + struct dentry *debugfs_card_root = platform->card->debugfs_card_root; + + platform->debugfs_platform_root = debugfs_create_dir(platform->name, + debugfs_card_root); + if (!platform->debugfs_platform_root) { + dev_warn(platform->dev, + "Failed to create platform debugfs directory\n"); + return; + } + + snd_soc_dapm_debugfs_init(&platform->dapm, + platform->debugfs_platform_root); +} + +static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) +{ + debugfs_remove_recursive(platform->debugfs_platform_root); +} + static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -435,6 +454,14 @@ static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) { } +static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform) +{ +} + +static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) +{ +} + static inline void soc_init_card_debugfs(struct snd_soc_card *card) { } @@ -546,18 +573,20 @@ int snd_soc_suspend(struct device *dev) } for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; + struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai; if (card->rtd[i].dai_link->ignore_suspend) continue; - if (driver->playback.stream_name != NULL) - snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name, - SND_SOC_DAPM_STREAM_SUSPEND); + snd_soc_dapm_stream_event(&card->rtd[i], + SNDRV_PCM_STREAM_PLAYBACK, + codec_dai, + SND_SOC_DAPM_STREAM_SUSPEND); - if (driver->capture.stream_name != NULL) - snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name, - SND_SOC_DAPM_STREAM_SUSPEND); + snd_soc_dapm_stream_event(&card->rtd[i], + SNDRV_PCM_STREAM_CAPTURE, + codec_dai, + SND_SOC_DAPM_STREAM_SUSPEND); } /* suspend all CODECs */ @@ -660,18 +689,18 @@ static void soc_resume_deferred(struct work_struct *work) } for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; + struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai; if (card->rtd[i].dai_link->ignore_suspend) continue; - if (driver->playback.stream_name != NULL) - snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name, - SND_SOC_DAPM_STREAM_RESUME); + snd_soc_dapm_stream_event(&card->rtd[i], + SNDRV_PCM_STREAM_PLAYBACK, codec_dai, + SND_SOC_DAPM_STREAM_RESUME); - if (driver->capture.stream_name != NULL) - snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name, - SND_SOC_DAPM_STREAM_RESUME); + snd_soc_dapm_stream_event(&card->rtd[i], + SNDRV_PCM_STREAM_CAPTURE, codec_dai, + SND_SOC_DAPM_STREAM_RESUME); } /* unmute any active DACs */ @@ -904,7 +933,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) if (codec_dai->driver->remove) { err = codec_dai->driver->remove(codec_dai); if (err < 0) - printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name); + pr_err("asoc: failed to remove %s: %d\n", + codec_dai->name, err); } codec_dai->probed = 0; list_del(&codec_dai->card_list); @@ -916,12 +946,14 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) if (platform->driver->remove) { err = platform->driver->remove(platform); if (err < 0) - printk(KERN_ERR "asoc: failed to remove %s\n", platform->name); + pr_err("asoc: failed to remove %s: %d\n", + platform->name, err); } /* Make sure all DAPM widgets are freed */ snd_soc_dapm_free(&platform->dapm); + soc_cleanup_platform_debugfs(platform); platform->probed = 0; list_del(&platform->card_list); module_put(platform->dev->driver->owner); @@ -938,7 +970,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) if (cpu_dai->driver->remove) { err = cpu_dai->driver->remove(cpu_dai); if (err < 0) - printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name); + pr_err("asoc: failed to remove %s: %d\n", + cpu_dai->name, err); } cpu_dai->probed = 0; list_del(&cpu_dai->card_list); @@ -980,6 +1013,7 @@ static int soc_probe_codec(struct snd_soc_card *card, { int ret = 0; const struct snd_soc_codec_driver *driver = codec->driver; + struct snd_soc_dai *dai; codec->card = card; codec->dapm.card = card; @@ -994,6 +1028,14 @@ static int soc_probe_codec(struct snd_soc_card *card, snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, driver->num_dapm_widgets); + /* Create DAPM widgets for each DAI stream */ + list_for_each_entry(dai, &dai_list, list) { + if (dai->dev != codec->dev) + continue; + + snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); + } + codec->dapm.idle_bias_off = driver->idle_bias_off; if (driver->probe) { @@ -1007,7 +1049,7 @@ static int soc_probe_codec(struct snd_soc_card *card, } if (driver->controls) - snd_soc_add_controls(codec, driver->controls, + snd_soc_add_codec_controls(codec, driver->controls, driver->num_controls); if (driver->dapm_routes) snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, @@ -1039,6 +1081,8 @@ static int soc_probe_platform(struct snd_soc_card *card, if (!try_module_get(platform->dev->driver->owner)) return -ENODEV; + soc_init_platform_debugfs(platform); + if (driver->dapm_widgets) snd_soc_dapm_new_controls(&platform->dapm, driver->dapm_widgets, driver->num_dapm_widgets); @@ -1068,6 +1112,7 @@ static int soc_probe_platform(struct snd_soc_card *card, return 0; err_probe: + soc_cleanup_platform_debugfs(platform); module_put(platform->dev->driver->owner); return ret; @@ -1183,8 +1228,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) 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); + pr_err("asoc: failed to probe CPU DAI %s: %d\n", + cpu_dai->name, ret); module_put(cpu_dai->dev->driver->owner); return ret; } @@ -1215,8 +1260,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) if (codec_dai->driver->probe) { ret = codec_dai->driver->probe(codec_dai); if (ret < 0) { - printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n", - codec_dai->name); + pr_err("asoc: failed to probe CODEC DAI %s: %d\n", + codec_dai->name, ret); return ret; } } @@ -1236,12 +1281,13 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) ret = device_create_file(rtd->dev, &dev_attr_pmdown_time); if (ret < 0) - printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n"); + pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret); /* create the pcm */ ret = soc_new_pcm(rtd, num); if (ret < 0) { - printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name); + pr_err("asoc: can't create pcm %s :%d\n", + dai_link->stream_name, ret); return ret; } @@ -1274,7 +1320,7 @@ static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) ret = soc_ac97_dev_register(rtd->codec); if (ret < 0) { - printk(KERN_ERR "asoc: AC97 device register failed\n"); + pr_err("asoc: AC97 device register failed:%d\n", ret); return ret; } @@ -1414,8 +1460,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, card->owner, 0, &card->snd_card); if (ret < 0) { - printk(KERN_ERR "asoc: can't create sound card for card %s\n", - card->name); + pr_err("asoc: can't create sound card for card %s: %d\n", + card->name, ret); mutex_unlock(&card->mutex); return; } @@ -1468,13 +1514,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) } } - /* We should have a non-codec control add function but we don't */ + snd_soc_dapm_link_dai_widgets(card); + 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); + snd_soc_add_card_controls(card, card->controls, card->num_controls); if (card->dapm_routes) snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, @@ -1488,14 +1531,14 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) if (dai_link->dai_fmt) { ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai, dai_link->dai_fmt); - if (ret != 0) + if (ret != 0 && ret != -ENOTSUPP) dev_warn(card->rtd[i].codec_dai->dev, "Failed to set DAI format: %d\n", ret); ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai, dai_link->dai_fmt); - if (ret != 0) + if (ret != 0 && ret != -ENOTSUPP) dev_warn(card->rtd[i].cpu_dai->dev, "Failed to set DAI format: %d\n", ret); @@ -1538,7 +1581,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) ret = snd_card_register(card->snd_card); if (ret < 0) { - printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name); + pr_err("asoc: failed to register soundcard for %s: %d\n", + card->name, ret); goto probe_aux_dev_err; } @@ -1547,7 +1591,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) for (i = 0; i < card->num_rtd; i++) { ret = soc_register_ac97_dai_link(&card->rtd[i]); if (ret < 0) { - printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name); + pr_err("asoc: failed to register AC97 %s: %d\n", + card->name, ret); while (--i >= 0) soc_unregister_ac97_dai_link(card->rtd[i].codec); goto probe_aux_dev_err; @@ -1600,6 +1645,10 @@ static int soc_probe(struct platform_device *pdev) if (!card) return -EINVAL; + dev_warn(&pdev->dev, + "ASoC machine %s should use snd_soc_register_card()\n", + card->name); + /* Bodge while we unpick instantiation */ card->dev = &pdev->dev; @@ -1637,7 +1686,6 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) snd_soc_dapm_free(&card->dapm); - kfree(card->rtd); snd_card_free(card->snd_card); return 0; @@ -1676,7 +1724,10 @@ EXPORT_SYMBOL_GPL(snd_soc_poweroff); const struct dev_pm_ops snd_soc_pm_ops = { .suspend = snd_soc_suspend, .resume = snd_soc_resume, + .freeze = snd_soc_suspend, + .thaw = snd_soc_resume, .poweroff = snd_soc_poweroff, + .restore = snd_soc_resume, }; EXPORT_SYMBOL_GPL(snd_soc_pm_ops); @@ -1880,23 +1931,28 @@ EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw); int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, unsigned int mask, unsigned int value) { - int change; + bool change; unsigned int old, new; int ret; - ret = snd_soc_read(codec, reg); - if (ret < 0) - return ret; - - old = ret; - new = (old & ~mask) | (value & mask); - change = old != new; - if (change) { - ret = snd_soc_write(codec, reg, new); + if (codec->using_regmap) { + ret = regmap_update_bits_check(codec->control_data, reg, + mask, value, &change); + } else { + ret = snd_soc_read(codec, reg); if (ret < 0) return ret; + + old = ret; + new = (old & ~mask) | (value & mask); + change = old != new; + if (change) + ret = snd_soc_write(codec, reg, new); } + if (ret < 0) + return ret; + return change; } EXPORT_SYMBOL_GPL(snd_soc_update_bits); @@ -1987,7 +2043,7 @@ EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); * Returns 0 for success, else error. */ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, - void *data, char *long_name, + void *data, const char *long_name, const char *prefix) { struct snd_kcontrol_new template; @@ -2022,9 +2078,28 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, } EXPORT_SYMBOL_GPL(snd_soc_cnew); +static int snd_soc_add_controls(struct snd_card *card, struct device *dev, + const struct snd_kcontrol_new *controls, int num_controls, + const char *prefix, void *data) +{ + int err, i; + + for (i = 0; i < num_controls; i++) { + const struct snd_kcontrol_new *control = &controls[i]; + err = snd_ctl_add(card, snd_soc_cnew(control, data, + control->name, prefix)); + if (err < 0) { + dev_err(dev, "Failed to add %s: %d\n", control->name, err); + return err; + } + } + + return 0; +} + /** - * snd_soc_add_controls - add an array of controls to a codec. - * Convienience function to add a list of controls. Many codecs were + * snd_soc_add_codec_controls - add an array of controls to a codec. + * Convenience function to add a list of controls. Many codecs were * duplicating this code. * * @codec: codec to add controls to @@ -2033,31 +2108,19 @@ EXPORT_SYMBOL_GPL(snd_soc_cnew); * * Return 0 for success, else error. */ -int snd_soc_add_controls(struct snd_soc_codec *codec, +int snd_soc_add_codec_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, int num_controls) { struct snd_card *card = codec->card->snd_card; - int err, i; - - for (i = 0; i < num_controls; i++) { - const struct snd_kcontrol_new *control = &controls[i]; - err = snd_ctl_add(card, snd_soc_cnew(control, codec, - control->name, - codec->name_prefix)); - if (err < 0) { - dev_err(codec->dev, "%s: Failed to add %s: %d\n", - codec->name, control->name, err); - return err; - } - } - return 0; + return snd_soc_add_controls(card, codec->dev, controls, num_controls, + codec->name_prefix, codec); } -EXPORT_SYMBOL_GPL(snd_soc_add_controls); +EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls); /** * snd_soc_add_platform_controls - add an array of controls to a platform. - * Convienience function to add a list of controls. + * Convenience function to add a list of controls. * * @platform: platform to add controls to * @controls: array of controls to add @@ -2069,23 +2132,53 @@ int snd_soc_add_platform_controls(struct snd_soc_platform *platform, const struct snd_kcontrol_new *controls, int num_controls) { struct snd_card *card = platform->card->snd_card; - int err, i; - - for (i = 0; i < num_controls; i++) { - const struct snd_kcontrol_new *control = &controls[i]; - err = snd_ctl_add(card, snd_soc_cnew(control, platform, - control->name, NULL)); - if (err < 0) { - dev_err(platform->dev, "Failed to add %s %d\n",control->name, err); - return err; - } - } - return 0; + return snd_soc_add_controls(card, platform->dev, controls, num_controls, + NULL, platform); } EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls); /** + * snd_soc_add_card_controls - add an array of controls to a SoC card. + * Convenience function to add a list of controls. + * + * @soc_card: SoC card to add controls to + * @controls: array of controls to add + * @num_controls: number of elements in the array + * + * Return 0 for success, else error. + */ +int snd_soc_add_card_controls(struct snd_soc_card *soc_card, + const struct snd_kcontrol_new *controls, int num_controls) +{ + struct snd_card *card = soc_card->snd_card; + + return snd_soc_add_controls(card, soc_card->dev, controls, num_controls, + NULL, soc_card); +} +EXPORT_SYMBOL_GPL(snd_soc_add_card_controls); + +/** + * snd_soc_add_dai_controls - add an array of controls to a DAI. + * Convienience function to add a list of controls. + * + * @dai: DAI to add controls to + * @controls: array of controls to add + * @num_controls: number of elements in the array + * + * Return 0 for success, else error. + */ +int snd_soc_add_dai_controls(struct snd_soc_dai *dai, + const struct snd_kcontrol_new *controls, int num_controls) +{ + struct snd_card *card = dai->card->snd_card; + + return snd_soc_add_controls(card, dai->dev, controls, num_controls, + NULL, dai); +} +EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); + +/** * snd_soc_info_enum_double - enumerated double mixer info callback * @kcontrol: mixer control * @uinfo: control element information @@ -2651,6 +2744,115 @@ int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx); +int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_bytes *params = (void *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = params->num_regs * codec->val_bytes; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_bytes_info); + +int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int ret; + + if (codec->using_regmap) + ret = regmap_raw_read(codec->control_data, params->base, + ucontrol->value.bytes.data, + params->num_regs * codec->val_bytes); + else + ret = -EINVAL; + + /* Hide any masked bytes to ensure consistent data reporting */ + if (ret == 0 && params->mask) { + switch (codec->val_bytes) { + case 1: + ucontrol->value.bytes.data[0] &= ~params->mask; + break; + case 2: + ((u16 *)(&ucontrol->value.bytes.data))[0] + &= ~params->mask; + break; + case 4: + ((u32 *)(&ucontrol->value.bytes.data))[0] + &= ~params->mask; + break; + default: + return -EINVAL; + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_bytes_get); + +int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes *params = (void *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int ret, len; + unsigned int val; + void *data; + + if (!codec->using_regmap) + return -EINVAL; + + data = ucontrol->value.bytes.data; + len = params->num_regs * codec->val_bytes; + + /* + * If we've got a mask then we need to preserve the register + * bits. We shouldn't modify the incoming data so take a + * copy. + */ + if (params->mask) { + ret = regmap_read(codec->control_data, params->base, &val); + if (ret != 0) + return ret; + + val &= params->mask; + + data = kmemdup(data, len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + switch (codec->val_bytes) { + case 1: + ((u8 *)data)[0] &= ~params->mask; + ((u8 *)data)[0] |= val; + break; + case 2: + ((u16 *)data)[0] &= cpu_to_be16(~params->mask); + ((u16 *)data)[0] |= cpu_to_be16(val); + break; + case 4: + ((u32 *)data)[0] &= cpu_to_be32(~params->mask); + ((u32 *)data)[0] |= cpu_to_be32(val); + break; + default: + return -EINVAL; + } + } + + ret = regmap_raw_write(codec->control_data, params->base, + data, len); + + if (params->mask) + kfree(data); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_bytes_put); + /** * snd_soc_dai_set_sysclk - configure DAI system or master clock. * @dai: DAI @@ -2768,10 +2970,11 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll); */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->driver && dai->driver->ops->set_fmt) - return dai->driver->ops->set_fmt(dai, fmt); - else + if (dai->driver == NULL) return -EINVAL; + if (dai->driver->ops->set_fmt == NULL) + return -ENOTSUPP; + return dai->driver->ops->set_fmt(dai, fmt); } EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); @@ -2875,7 +3078,8 @@ int snd_soc_register_card(struct snd_soc_card *card) */ if (!!link->codec_name == !!link->codec_of_node) { dev_err(card->dev, - "Neither/both codec name/of_node are set\n"); + "Neither/both codec name/of_node are set for %s\n", + link->name); return -EINVAL; } @@ -2885,7 +3089,7 @@ int snd_soc_register_card(struct snd_soc_card *card) */ if (link->platform_name && link->platform_of_node) { dev_err(card->dev, - "Both platform name/of_node are set\n"); + "Both platform name/of_node are set for %s\n", link->name); return -EINVAL; } @@ -2895,7 +3099,8 @@ int snd_soc_register_card(struct snd_soc_card *card) */ if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) { dev_err(card->dev, - "Neither/both cpu_dai name/of_node are set\n"); + "Neither/both cpu_dai name/of_node are set for %s\n", + link->name); return -EINVAL; } } @@ -2906,9 +3111,10 @@ int snd_soc_register_card(struct snd_soc_card *card) soc_init_card_debugfs(card); - card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * - (card->num_links + card->num_aux_devs), - GFP_KERNEL); + card->rtd = devm_kzalloc(card->dev, + sizeof(struct snd_soc_pcm_runtime) * + (card->num_links + card->num_aux_devs), + GFP_KERNEL); if (card->rtd == NULL) return -ENOMEM; card->rtd_aux = &card->rtd[card->num_links]; @@ -3002,7 +3208,7 @@ static inline char *fmt_multiple_name(struct device *dev, struct snd_soc_dai_driver *dai_drv) { if (dai_drv->name == NULL) { - printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n", + pr_err("asoc: error - multiple DAI %s registered with no name\n", dev_name(dev)); return NULL; } @@ -3177,6 +3383,7 @@ int snd_soc_register_platform(struct device *dev, platform->dapm.dev = dev; platform->dapm.platform = platform; platform->dapm.stream_event = platform_drv->stream_event; + mutex_init(&platform->mutex); mutex_lock(&client_mutex); list_add(&platform->list, &platform_list); @@ -3285,6 +3492,7 @@ int snd_soc_register_codec(struct device *dev, codec->volatile_register = codec_drv->volatile_register; codec->readable_register = codec_drv->readable_register; codec->writable_register = codec_drv->writable_register; + codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time; codec->dapm.bias_level = SND_SOC_BIAS_OFF; codec->dapm.dev = dev; codec->dapm.codec = codec; @@ -3473,8 +3681,7 @@ static int __init snd_soc_init(void) #ifdef CONFIG_DEBUG_FS snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) { - printk(KERN_WARNING - "ASoC: Failed to create debugfs directory\n"); + pr_warn("ASoC: Failed to create debugfs directory\n"); snd_soc_debugfs_root = NULL; } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1315663c1c0..6241490fff3 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -14,19 +14,13 @@ * dynamic configuration of codec internal audio paths and active * DACs/ADCs. * o Platform power domain - can support external components i.e. amps and - * mic/meadphone insertion events. + * mic/headphone insertion events. * o Automatic Mic Bias support * o Jack insertion power event initiation - e.g. hp insertion will enable * sinks, dacs, etc - * o Delayed powerdown of audio susbsystem to reduce pops between a quick + * o Delayed power down of audio subsystem to reduce pops between a quick * device reopen. * - * Todo: - * o DAPM power change sequencing - allow for configurable per - * codec sequences. - * o Support for analogue bias optimisation. - * o Support for reduced codec oversampling rates. - * o Support for reduced codec bias currents. */ #include <linux/module.h> @@ -40,6 +34,7 @@ #include <linux/jiffies.h> #include <linux/debugfs.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -55,7 +50,9 @@ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 0, [snd_soc_dapm_supply] = 1, + [snd_soc_dapm_regulator_supply] = 1, [snd_soc_dapm_micbias] = 2, + [snd_soc_dapm_dai] = 3, [snd_soc_dapm_aif_in] = 3, [snd_soc_dapm_aif_out] = 3, [snd_soc_dapm_mic] = 4, @@ -90,6 +87,8 @@ static int dapm_down_seq[] = { [snd_soc_dapm_value_mux] = 9, [snd_soc_dapm_aif_in] = 10, [snd_soc_dapm_aif_out] = 10, + [snd_soc_dapm_dai] = 10, + [snd_soc_dapm_regulator_supply] = 11, [snd_soc_dapm_supply] = 11, [snd_soc_dapm_post] = 12, }; @@ -172,6 +171,19 @@ static inline struct snd_soc_card *dapm_get_soc_card( return NULL; } +static void dapm_reset(struct snd_soc_card *card) +{ + struct snd_soc_dapm_widget *w; + + memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); + + list_for_each_entry(w, &card->widgets, list) { + w->power_checked = false; + w->inputs = -1; + w->outputs = -1; + } +} + static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) { if (w->codec) @@ -197,21 +209,28 @@ static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, unsigned short reg, unsigned int mask, unsigned int value) { - int change; + bool change; unsigned int old, new; int ret; - ret = soc_widget_read(w, reg); - if (ret < 0) - return ret; - - old = ret; - new = (old & ~mask) | (value & mask); - change = old != new; - if (change) { - ret = soc_widget_write(w, reg, new); + if (w->codec && w->codec->using_regmap) { + ret = regmap_update_bits_check(w->codec->control_data, + reg, mask, value, &change); + if (ret != 0) + return ret; + } else { + ret = soc_widget_read(w, reg); if (ret < 0) return ret; + + old = ret; + new = (old & ~mask) | (value & mask); + change = old != new; + if (change) { + ret = soc_widget_write(w, reg, new); + if (ret < 0) + return ret; + } } return change; @@ -345,8 +364,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_micbias: case snd_soc_dapm_vmid: case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai: case snd_soc_dapm_hp: case snd_soc_dapm_mic: case snd_soc_dapm_spk: @@ -504,17 +525,17 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) * for widgets so cut the prefix off * the front of the widget name. */ - snprintf(path->long_name, name_len, "%s %s", - w->name + prefix_len, + snprintf((char *)path->long_name, name_len, + "%s %s", w->name + prefix_len, w->kcontrol_news[i].name); break; case snd_soc_dapm_mixer_named_ctl: - snprintf(path->long_name, name_len, "%s", - w->kcontrol_news[i].name); + snprintf((char *)path->long_name, name_len, + "%s", w->kcontrol_news[i].name); break; } - path->long_name[name_len - 1] = '\0'; + ((char *)path->long_name)[name_len - 1] = '\0'; path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], wlist, path->long_name, @@ -548,7 +569,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) struct snd_soc_dapm_widget_list *wlist; int shared, wlistentries; size_t wlistsize; - char *name; + const char *name; if (w->num_kcontrols != 1) { dev_err(dapm->dev, @@ -673,12 +694,18 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) DAPM_UPDATE_STAT(widget, path_checks); - if (widget->id == snd_soc_dapm_supply) + switch (widget->id) { + case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: return 0; + default: + break; + } switch (widget->id) { case snd_soc_dapm_adc: case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai: if (widget->active) { widget->outputs = snd_soc_dapm_suspend_check(widget); return widget->outputs; @@ -738,13 +765,19 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) DAPM_UPDATE_STAT(widget, path_checks); - if (widget->id == snd_soc_dapm_supply) + switch (widget->id) { + case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: return 0; + default: + break; + } /* active stream ? */ switch (widget->id) { case snd_soc_dapm_dac: case snd_soc_dapm_aif_in: + case snd_soc_dapm_dai: if (widget->active) { widget->inputs = snd_soc_dapm_suspend_check(widget); return widget->inputs; @@ -821,6 +854,19 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(dapm_reg_event); +/* + * Handler for regulator supply widget. + */ +int dapm_regulator_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + return regulator_enable(w->priv); + else + return regulator_disable_deferred(w->priv, w->shift); +} +EXPORT_SYMBOL_GPL(dapm_regulator_event); + static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) { if (w->power_checked) @@ -851,6 +897,13 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) return out != 0 && in != 0; } +static int dapm_dai_check_power(struct snd_soc_dapm_widget *w) +{ + DAPM_UPDATE_STAT(w, power_checks); + + return w->active; +} + /* Check to see if an ADC has power */ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) { @@ -1251,7 +1304,7 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) dev_err(d->dev, "Failed to turn off bias: %d\n", ret); if (d->dev) - pm_runtime_put_sync(d->dev); + pm_runtime_put(d->dev); } /* If we just powered up then move to active bias */ @@ -1301,6 +1354,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, } switch (w->id) { case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: /* Supplies can't affect their outputs, only their inputs */ break; default: @@ -1373,13 +1427,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) } } - memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); - - list_for_each_entry(w, &card->widgets, list) { - w->power_checked = false; - w->inputs = -1; - w->outputs = -1; - } + dapm_reset(card); /* Check which widgets we need to power and store them in * lists indicating if they should be powered up or down. We @@ -1400,10 +1448,15 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) /* Supplies and micbiases only bring the * context up to STANDBY as unless something * else is active and passing audio they - * generally don't require full power. + * generally don't require full power. Signal + * generators are virtual pins and have no + * power impact themselves. */ switch (w->id) { + case snd_soc_dapm_siggen: + break; case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: case snd_soc_dapm_micbias: if (d->target_bias_level < SND_SOC_BIAS_STANDBY) d->target_bias_level = SND_SOC_BIAS_STANDBY; @@ -1475,6 +1528,12 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) &async_domain); async_synchronize_full_domain(&async_domain); + /* do we need to notify any clients that DAPM event is complete */ + list_for_each_entry(d, &card->dapm_list, list) { + if (d->stream_event) + d->stream_event(d, event); + } + pop_dbg(dapm->dev, card->pop_time, "DAPM sequencing finished, waiting %dms\n", card->pop_time); pop_wait(card->pop_time); @@ -1510,8 +1569,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, out = is_connected_output_ep(w); dapm_clear_walk(w->dapm); - ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", - w->name, w->power ? "On" : "Off", in, out); + ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", + w->name, w->power ? "On" : "Off", + w->force ? " (forced)" : "", in, out); if (w->reg >= 0) ret += snprintf(buf + ret, PAGE_SIZE - ret, @@ -1607,7 +1667,7 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); if (!dapm->debugfs_dapm) { - printk(KERN_WARNING + dev_warn(dapm->dev, "Failed to create DAPM debugfs directory\n"); return; } @@ -1659,9 +1719,8 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) #endif /* test and update the power status of a mux widget */ -static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int change, - int mux, struct soc_enum *e) +int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) { struct snd_soc_dapm_path *path; int found = 0; @@ -1671,9 +1730,6 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, widget->id != snd_soc_dapm_value_mux) return -ENODEV; - if (!change) - return 0; - /* find dapm widget path assoc with kcontrol */ list_for_each_entry(path, &widget->dapm->card->paths, list) { if (path->kcontrol != kcontrol) @@ -1702,9 +1758,10 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, return 0; } +EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); /* test and update the power status of a mixer or switch widget */ -static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, +int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, int connect) { struct snd_soc_dapm_path *path; @@ -1733,6 +1790,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, return 0; } +EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); /* show dapm widget status in sys fs */ static ssize_t dapm_widget_show(struct device *dev, @@ -1762,6 +1820,7 @@ static ssize_t dapm_widget_show(struct device *dev, case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: if (w->name) count += sprintf(buf + count, "%s: %s\n", w->name, w->power ? "On":"Off"); @@ -1869,10 +1928,12 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, return -EINVAL; } + if (w->connected != status) + dapm_mark_dirty(w, "pin configuration"); + w->connected = status; if (status == 0) w->force = 0; - dapm_mark_dirty(w, "pin configuration"); return 0; } @@ -2000,8 +2061,10 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, case snd_soc_dapm_pre: case snd_soc_dapm_post: case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai: list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); @@ -2315,7 +2378,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - dapm_mixer_update_power(widget, kcontrol, connect); + snd_soc_dapm_mixer_update_power(widget, kcontrol, connect); widget->dapm->update = NULL; } @@ -2406,7 +2469,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - dapm_mux_update_power(widget, kcontrol, change, mux, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); widget->dapm->update = NULL; } @@ -2467,8 +2530,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, widget->value = ucontrol->value.enumerated.item[0]; - dapm_mux_update_power(widget, kcontrol, change, - widget->value, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); } } @@ -2571,7 +2633,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - dapm_mux_update_power(widget, kcontrol, change, mux, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); widget->dapm->update = NULL; } @@ -2611,15 +2673,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch); int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); const char *pin = (const char *)kcontrol->private_value; - mutex_lock(&codec->mutex); + mutex_lock(&card->mutex); ucontrol->value.integer.value[0] = - snd_soc_dapm_get_pin_status(&codec->dapm, pin); + snd_soc_dapm_get_pin_status(&card->dapm, pin); - mutex_unlock(&codec->mutex); + mutex_unlock(&card->mutex); return 0; } @@ -2634,41 +2696,48 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch); int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); const char *pin = (const char *)kcontrol->private_value; - mutex_lock(&codec->mutex); + mutex_lock(&card->mutex); if (ucontrol->value.integer.value[0]) - snd_soc_dapm_enable_pin(&codec->dapm, pin); + snd_soc_dapm_enable_pin(&card->dapm, pin); else - snd_soc_dapm_disable_pin(&codec->dapm, pin); + snd_soc_dapm_disable_pin(&card->dapm, pin); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_sync(&card->dapm); - mutex_unlock(&codec->mutex); + mutex_unlock(&card->mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); -/** - * snd_soc_dapm_new_control - create new dapm control - * @dapm: DAPM context - * @widget: widget template - * - * Creates a new dapm control based upon the template. - * - * Returns 0 for success else error. - */ -int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget) +static struct snd_soc_dapm_widget * +snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget) { struct snd_soc_dapm_widget *w; size_t name_len; + int ret; if ((w = dapm_cnew_widget(widget)) == NULL) - return -ENOMEM; + return NULL; + + switch (w->id) { + case snd_soc_dapm_regulator_supply: + w->priv = devm_regulator_get(dapm->dev, w->name); + if (IS_ERR(w->priv)) { + ret = PTR_ERR(w->priv); + dev_err(dapm->dev, "Failed to request %s: %d\n", + w->name, ret); + return NULL; + } + break; + default: + break; + } name_len = strlen(widget->name) + 1; if (dapm->codec && dapm->codec->name_prefix) @@ -2676,13 +2745,13 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->name = kmalloc(name_len, GFP_KERNEL); if (w->name == NULL) { kfree(w); - return -ENOMEM; + return NULL; } if (dapm->codec && dapm->codec->name_prefix) - snprintf(w->name, name_len, "%s %s", + snprintf((char *)w->name, name_len, "%s %s", dapm->codec->name_prefix, widget->name); else - snprintf(w->name, name_len, "%s", widget->name); + snprintf((char *)w->name, name_len, "%s", widget->name); switch (w->id) { case snd_soc_dapm_switch: @@ -2715,8 +2784,12 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: w->power_check = dapm_supply_check_power; break; + case snd_soc_dapm_dai: + w->power_check = dapm_dai_check_power; + break; default: w->power_check = dapm_always_on_check_power; break; @@ -2734,9 +2807,8 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, /* machine layer set ups unconnected pins and insertions */ w->connected = 1; - return 0; + return w; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); /** * snd_soc_dapm_new_controls - create new dapm controls @@ -2752,15 +2824,16 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, int num) { - int i, ret; + struct snd_soc_dapm_widget *w; + int i; for (i = 0; i < num; i++) { - ret = snd_soc_dapm_new_control(dapm, widget); - if (ret < 0) { + w = snd_soc_dapm_new_control(dapm, widget); + if (!w) { dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s: %d\n", - widget->name, ret); - return ret; + "ASoC: Failed to create DAPM control %s\n", + widget->name); + return -ENOMEM; } widget++; } @@ -2768,40 +2841,140 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); -static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, - const char *stream, int event) +int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, + struct snd_soc_dai *dai) { + struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; - list_for_each_entry(w, &dapm->card->widgets, list) - { - if (!w->sname || w->dapm != dapm) + WARN_ON(dapm->dev != dai->dev); + + memset(&template, 0, sizeof(template)); + template.reg = SND_SOC_NOPM; + + if (dai->driver->playback.stream_name) { + template.id = snd_soc_dapm_dai; + template.name = dai->driver->playback.stream_name; + template.sname = dai->driver->playback.stream_name; + + dev_dbg(dai->dev, "adding %s widget\n", + template.name); + + w = snd_soc_dapm_new_control(dapm, &template); + if (!w) { + dev_err(dapm->dev, "Failed to create %s widget\n", + dai->driver->playback.stream_name); + } + + w->priv = dai; + dai->playback_widget = w; + } + + if (dai->driver->capture.stream_name) { + template.id = snd_soc_dapm_dai; + template.name = dai->driver->capture.stream_name; + template.sname = dai->driver->capture.stream_name; + + dev_dbg(dai->dev, "adding %s widget\n", + template.name); + + w = snd_soc_dapm_new_control(dapm, &template); + if (!w) { + dev_err(dapm->dev, "Failed to create %s widget\n", + dai->driver->capture.stream_name); + } + + w->priv = dai; + dai->capture_widget = w; + } + + return 0; +} + +int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) +{ + struct snd_soc_dapm_widget *dai_w, *w; + struct snd_soc_dai *dai; + struct snd_soc_dapm_route r; + + memset(&r, 0, sizeof(r)); + + /* For each DAI widget... */ + list_for_each_entry(dai_w, &card->widgets, list) { + if (dai_w->id != snd_soc_dapm_dai) continue; - dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", - w->name, w->sname, stream, event); - if (strstr(w->sname, stream)) { - dapm_mark_dirty(w, "stream event"); - switch(event) { - case SND_SOC_DAPM_STREAM_START: - w->active = 1; - break; - case SND_SOC_DAPM_STREAM_STOP: - w->active = 0; - break; - case SND_SOC_DAPM_STREAM_SUSPEND: - case SND_SOC_DAPM_STREAM_RESUME: - case SND_SOC_DAPM_STREAM_PAUSE_PUSH: - case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: - break; + + dai = dai_w->priv; + + /* ...find all widgets with the same stream and link them */ + list_for_each_entry(w, &card->widgets, list) { + if (w->dapm != dai_w->dapm) + continue; + + if (w->id == snd_soc_dapm_dai) + continue; + + if (!w->sname) + continue; + + if (dai->driver->playback.stream_name && + strstr(w->sname, + dai->driver->playback.stream_name)) { + r.source = dai->playback_widget->name; + r.sink = w->name; + dev_dbg(dai->dev, "%s -> %s\n", + r.source, r.sink); + + snd_soc_dapm_add_route(w->dapm, &r); + } + + if (dai->driver->capture.stream_name && + strstr(w->sname, + dai->driver->capture.stream_name)) { + r.source = w->name; + r.sink = dai->capture_widget->name; + dev_dbg(dai->dev, "%s -> %s\n", + r.source, r.sink); + + snd_soc_dapm_add_route(w->dapm, &r); } } } - dapm_power_widgets(dapm, event); + return 0; +} - /* do we need to notify any clients that DAPM stream is complete */ - if (dapm->stream_event) - dapm->stream_event(dapm, event); +static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, + int stream, struct snd_soc_dai *dai, + int event) +{ + struct snd_soc_dapm_widget *w; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + w = dai->playback_widget; + else + w = dai->capture_widget; + + if (!w) + return; + + dapm_mark_dirty(w, "stream event"); + + switch (event) { + case SND_SOC_DAPM_STREAM_START: + w->active = 1; + break; + case SND_SOC_DAPM_STREAM_STOP: + w->active = 0; + break; + case SND_SOC_DAPM_STREAM_SUSPEND: + case SND_SOC_DAPM_STREAM_RESUME: + case SND_SOC_DAPM_STREAM_PAUSE_PUSH: + case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: + break; + } + + dapm_power_widgets(dapm, event); } /** @@ -2815,16 +2988,13 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, * * Returns 0 for success else error. */ -int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, - const char *stream, int event) +int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, + struct snd_soc_dai *dai, int event) { struct snd_soc_codec *codec = rtd->codec; - if (stream == NULL) - return 0; - mutex_lock(&codec->mutex); - soc_dapm_stream_event(&codec->dapm, stream, event); + soc_dapm_stream_event(&codec->dapm, stream, dai, event); mutex_unlock(&codec->mutex); return 0; } diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c new file mode 100644 index 00000000000..4420b7030c8 --- /dev/null +++ b/sound/soc/soc-dmaengine-pcm.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2012, Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Based on: + * imx-pcm-dma-mx2.c, Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de> + * mxs-pcm.c, Copyright (C) 2011 Freescale Semiconductor, Inc. + * ep93xx-pcm.c, Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> + * Copyright (C) 2006 Applied Data Systems + * + * 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. + * + * 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. + * + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/dmaengine.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include <sound/dmaengine_pcm.h> + +struct dmaengine_pcm_runtime_data { + struct dma_chan *dma_chan; + + unsigned int pos; + + void *data; +}; + +static inline struct dmaengine_pcm_runtime_data *substream_to_prtd( + const struct snd_pcm_substream *substream) +{ + return substream->runtime->private_data; +} + +/** + * snd_dmaengine_pcm_set_data - Set dmaengine substream private data + * @substream: PCM substream + * @data: Data to set + */ +void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + + prtd->data = data; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_data); + +/** + * snd_dmaengine_pcm_get_data - Get dmaeinge substream private data + * @substream: PCM substream + * + * Returns the data previously set with snd_dmaengine_pcm_set_data + */ +void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + + return prtd->data; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data); + +struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + + return prtd->dma_chan; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_chan); + +/** + * snd_hwparams_to_dma_slave_config - Convert hw_params to dma_slave_config + * @substream: PCM substream + * @params: hw_params + * @slave_config: DMA slave config + * + * This function can be used to initialize a dma_slave_config from a substream + * and hw_params in a dmaengine based PCM driver implementation. + */ +int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, + const struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config) +{ + enum dma_slave_buswidth buswidth; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; + break; + case SNDRV_PCM_FORMAT_S16_LE: + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + default: + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config->direction = DMA_MEM_TO_DEV; + slave_config->dst_addr_width = buswidth; + } else { + slave_config->direction = DMA_DEV_TO_MEM; + slave_config->src_addr_width = buswidth; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); + +static void dmaengine_pcm_dma_complete(void *arg) +{ + struct snd_pcm_substream *substream = arg; + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + + prtd->pos += snd_pcm_lib_period_bytes(substream); + if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream)) + prtd->pos = 0; + + snd_pcm_period_elapsed(substream); +} + +static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + struct dma_chan *chan = prtd->dma_chan; + struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction direction; + + direction = snd_pcm_substream_to_dma_direction(substream); + + prtd->pos = 0; + desc = chan->device->device_prep_dma_cyclic(chan, + substream->runtime->dma_addr, + snd_pcm_lib_buffer_bytes(substream), + snd_pcm_lib_period_bytes(substream), direction); + + if (!desc) + return -ENOMEM; + + desc->callback = dmaengine_pcm_dma_complete; + desc->callback_param = substream; + dmaengine_submit(desc); + + return 0; +} + +/** + * snd_dmaengine_pcm_trigger - dmaengine based PCM trigger implementation + * @substream: PCM substream + * @cmd: Trigger command + * + * Returns 0 on success, a negative error code otherwise. + * + * This function can be used as the PCM trigger callback for dmaengine based PCM + * driver implementations. + */ +int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ret = dmaengine_pcm_prepare_and_submit(substream); + if (ret) + return ret; + dma_async_issue_pending(prtd->dma_chan); + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + dmaengine_resume(prtd->dma_chan); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dmaengine_pause(prtd->dma_chan); + break; + case SNDRV_PCM_TRIGGER_STOP: + dmaengine_terminate_all(prtd->dma_chan); + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger); + +/** + * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation + * @substream: PCM substream + * + * This function can be used as the PCM pointer callback for dmaengine based PCM + * driver implementations. + */ +snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + return bytes_to_frames(substream->runtime, prtd->pos); +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); + +static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd, + dma_filter_fn filter_fn, void *filter_data) +{ + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_CYCLIC, mask); + prtd->dma_chan = dma_request_channel(mask, filter_fn, filter_data); + + if (!prtd->dma_chan) + return -ENXIO; + + return 0; +} + +/** + * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream + * @substream: PCM substream + * @filter_fn: Filter function used to request the DMA channel + * @filter_data: Data passed to the DMA filter function + * + * Returns 0 on success, a negative error code otherwise. + * + * This function will request a DMA channel using the passed filter function and + * data. The function should usually be called from the pcm open callback. + * + * Note that this function will use private_data field of the substream's + * runtime. So it is not availabe to your pcm driver implementation. If you need + * to keep additional data attached to a substream use + * snd_dmaeinge_pcm_{set,get}_data. + */ +int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, + dma_filter_fn filter_fn, void *filter_data) +{ + struct dmaengine_pcm_runtime_data *prtd; + int ret; + + ret = snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); + if (!prtd) + return -ENOMEM; + + ret = dmaengine_pcm_request_channel(prtd, filter_fn, filter_data); + if (ret < 0) { + kfree(prtd); + return ret; + } + + substream->runtime->private_data = prtd; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); + +/** + * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream + * @substream: PCM substream + */ +int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + + dma_release_channel(prtd->dma_chan); + kfree(prtd); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index c8610cbf34a..4d8dc6a27d4 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -114,6 +114,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, enum snd_soc_control_type control) { struct regmap_config config; + int ret; memset(&config, 0, sizeof(config)); codec->write = hw_write; @@ -140,6 +141,12 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, case SND_SOC_REGMAP: /* Device has made its own regmap arrangements */ + codec->using_regmap = true; + + ret = regmap_get_val_bytes(codec->control_data); + /* Errors are legitimate for non-integer byte multiples */ + if (ret > 0) + codec->val_bytes = ret; break; default: diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index cdc860a5ff3..0ad8dcacd2f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -63,6 +63,41 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, } /* + * List of sample sizes that might go over the bus for parameter + * application. There ought to be a wildcard sample size for things + * like the DAC/ADC resolution to use but there isn't right now. + */ +static int sample_sizes[] = { + 24, 32, +}; + +static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret, i, bits; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + bits = dai->driver->playback.sig_bits; + else + bits = dai->driver->capture.sig_bits; + + if (!bits) + return; + + for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) { + if (bits >= sample_sizes[i]) + continue; + + ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, + sample_sizes[i], bits); + if (ret != 0) + dev_warn(dai->dev, + "Failed to set MSB %d/%d: %d\n", + bits, sample_sizes[i], ret); + } +} + +/* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls * startup for the cpu DAI, platform, machine and codec DAI. @@ -88,8 +123,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->startup) { ret = cpu_dai->driver->ops->startup(substream, cpu_dai); if (ret < 0) { - printk(KERN_ERR "asoc: can't open interface %s\n", - cpu_dai->name); + dev_err(cpu_dai->dev, "can't open interface %s: %d\n", + cpu_dai->name, ret); goto out; } } @@ -97,7 +132,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) 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); + dev_err(platform->dev, "can't open platform %s: %d\n", + platform->name, ret); goto platform_err; } } @@ -105,8 +141,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai); if (ret < 0) { - printk(KERN_ERR "asoc: can't open codec %s\n", - codec_dai->name); + dev_err(codec_dai->dev, "can't open codec %s: %d\n", + codec_dai->name, ret); goto codec_dai_err; } } @@ -114,7 +150,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { ret = rtd->dai_link->ops->startup(substream); if (ret < 0) { - printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name); + pr_err("asoc: %s startup failed: %d\n", + rtd->dai_link->name, ret); goto machine_err; } } @@ -187,6 +224,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto config_err; } + soc_pcm_apply_msb(substream, codec_dai); + soc_pcm_apply_msb(substream, cpu_dai); + /* Symmetry only applies if we've already got an active stream. */ if (cpu_dai->active) { ret = soc_pcm_apply_symmetry(substream, cpu_dai); @@ -267,9 +307,8 @@ static void close_delayed_work(struct work_struct *work) /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { codec_dai->pop_wait = 0; - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->playback.stream_name, - SND_SOC_DAPM_STREAM_STOP); + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, + codec_dai, SND_SOC_DAPM_STREAM_STOP); } mutex_unlock(&rtd->pcm_mutex); @@ -329,12 +368,13 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) cpu_dai->runtime = NULL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (codec->ignore_pmdown_time || + if (!rtd->pmdown_time || codec->ignore_pmdown_time || rtd->dai_link->ignore_pmdown_time) { /* powered down playback stream now */ snd_soc_dapm_stream_event(rtd, - codec_dai->driver->playback.stream_name, - SND_SOC_DAPM_STREAM_STOP); + SNDRV_PCM_STREAM_PLAYBACK, + codec_dai, + SND_SOC_DAPM_STREAM_STOP); } else { /* start delayed pop wq here for playback streams */ codec_dai->pop_wait = 1; @@ -343,9 +383,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) } } else { /* capture streams can be powered down now */ - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->capture.stream_name, - SND_SOC_DAPM_STREAM_STOP); + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, + codec_dai, SND_SOC_DAPM_STREAM_STOP); } mutex_unlock(&rtd->pcm_mutex); @@ -375,7 +414,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream); if (ret < 0) { - printk(KERN_ERR "asoc: machine prepare error\n"); + pr_err("asoc: machine prepare error: %d\n", ret); goto out; } } @@ -383,7 +422,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) 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"); + dev_err(platform->dev, "platform prepare error: %d\n", + ret); goto out; } } @@ -391,7 +431,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); if (ret < 0) { - printk(KERN_ERR "asoc: codec DAI prepare error\n"); + dev_err(codec_dai->dev, "DAI prepare error: %d\n", + ret); goto out; } } @@ -399,7 +440,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->prepare) { ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); if (ret < 0) { - printk(KERN_ERR "asoc: cpu DAI prepare error\n"); + dev_err(cpu_dai->dev, "DAI prepare error: %d\n", + ret); goto out; } } @@ -411,14 +453,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) cancel_delayed_work(&rtd->delayed_work); } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->playback.stream_name, - SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->capture.stream_name, - SND_SOC_DAPM_STREAM_START); + snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai, + SND_SOC_DAPM_STREAM_START); snd_soc_dai_digital_mute(codec_dai, 0); @@ -446,7 +482,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { - printk(KERN_ERR "asoc: machine hw_params failed\n"); + pr_err("asoc: machine hw_params failed: %d\n", ret); goto out; } } @@ -454,8 +490,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (codec_dai->driver->ops->hw_params) { ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); if (ret < 0) { - printk(KERN_ERR "asoc: can't set codec %s hw params\n", - codec_dai->name); + dev_err(codec_dai->dev, "can't set %s hw params: %d\n", + codec_dai->name, ret); goto codec_err; } } @@ -463,8 +499,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (cpu_dai->driver->ops->hw_params) { ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); if (ret < 0) { - printk(KERN_ERR "asoc: interface %s hw params failed\n", - cpu_dai->name); + dev_err(cpu_dai->dev, "%s hw params failed: %d\n", + cpu_dai->name, ret); goto interface_err; } } @@ -472,8 +508,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, 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", - platform->name); + dev_err(platform->dev, "%s hw params failed: %d\n", + platform->name, ret); goto platform_err; } } diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 4220bb0f273..60053709e41 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -89,14 +89,32 @@ static struct snd_soc_platform_driver dummy_platform = { .ops = &dummy_dma_ops, }; +static struct snd_soc_codec_driver dummy_codec; +static struct snd_soc_dai_driver dummy_dai = { + .name = "snd-soc-dummy-dai", +}; + static __devinit int snd_soc_dummy_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &dummy_platform); + int ret; + + ret = snd_soc_register_codec(&pdev->dev, &dummy_codec, &dummy_dai, 1); + if (ret < 0) + return ret; + + ret = snd_soc_register_platform(&pdev->dev, &dummy_platform); + if (ret < 0) { + snd_soc_unregister_codec(&pdev->dev); + return ret; + } + + return ret; } static __devexit int snd_soc_dummy_remove(struct platform_device *pdev) { snd_soc_unregister_platform(&pdev->dev); + snd_soc_unregister_codec(&pdev->dev); return 0; } diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index 4a0e805c4ed..e45ccd851f6 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -18,6 +18,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <sound/core.h> #include <sound/jack.h> @@ -34,8 +35,13 @@ #define DRV_NAME "tegra-alc5632" +#define GPIO_HP_DET BIT(0) + struct tegra_alc5632 { struct tegra_asoc_utils_data util_data; + struct platform_device *pcm_dev; + int gpio_requested; + int gpio_hp_det; }; static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream, @@ -85,24 +91,18 @@ static struct snd_soc_jack_pin tegra_alc5632_hs_jack_pins[] = { }, }; +static struct snd_soc_jack_gpio tegra_alc5632_hp_jack_gpio = { + .name = "Headset detection", + .report = SND_JACK_HEADSET, + .debounce_time = 150, + .invert = 1, +}; + static const struct snd_soc_dapm_widget tegra_alc5632_dapm_widgets[] = { SND_SOC_DAPM_SPK("Int Spk", NULL), SND_SOC_DAPM_HP("Headset Stereophone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_soc_dapm_route tegra_alc5632_audio_map[] = { - /* Internal Speaker */ - {"Int Spk", NULL, "SPKOUT"}, - {"Int Spk", NULL, "SPKOUTN"}, - - /* Headset Mic */ - {"MIC1", NULL, "MICBIAS1"}, - {"MICBIAS1", NULL, "Headset Mic"}, - - /* Headset Stereophone */ - {"Headset Stereophone", NULL, "HPR"}, - {"Headset Stereophone", NULL, "HPL"}, + SND_SOC_DAPM_MIC("Digital Mic", NULL), }; static const struct snd_kcontrol_new tegra_alc5632_controls[] = { @@ -113,6 +113,8 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; + struct device_node *np = codec->card->dev->of_node; + struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(codec->card); snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, &tegra_alc5632_hs_jack); @@ -120,6 +122,16 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) ARRAY_SIZE(tegra_alc5632_hs_jack_pins), tegra_alc5632_hs_jack_pins); + machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); + + if (gpio_is_valid(machine->gpio_hp_det)) { + tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det; + snd_soc_jack_add_gpios(&tegra_alc5632_hs_jack, + 1, + &tegra_alc5632_hp_jack_gpio); + machine->gpio_requested |= GPIO_HP_DET; + } + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); return 0; @@ -128,9 +140,7 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_dai_link tegra_alc5632_dai = { .name = "ALC5632", .stream_name = "ALC5632 PCM", - .codec_name = "alc5632.0-001e", .platform_name = "tegra-pcm-audio", - .cpu_dai_name = "tegra-i2s.0", .codec_dai_name = "alc5632-hifi", .init = tegra_alc5632_asoc_init, .ops = &tegra_alc5632_asoc_ops, @@ -148,8 +158,6 @@ static struct snd_soc_card snd_soc_tegra_alc5632 = { .num_controls = ARRAY_SIZE(tegra_alc5632_controls), .dapm_widgets = tegra_alc5632_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(tegra_alc5632_dapm_widgets), - .dapm_routes = tegra_alc5632_audio_map, - .num_dapm_routes = ARRAY_SIZE(tegra_alc5632_audio_map), .fully_routed = true, }; @@ -163,45 +171,111 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev) sizeof(struct tegra_alc5632), GFP_KERNEL); if (!alc5632) { dev_err(&pdev->dev, "Can't allocate tegra_alc5632\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } - ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev); - if (ret) - return ret; - card->dev = &pdev->dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, alc5632); + alc5632->pcm_dev = ERR_PTR(-EINVAL); + + if (!(pdev->dev.of_node)) { + dev_err(&pdev->dev, "Must be instantiated using device tree\n"); + ret = -EINVAL; + goto err; + } + + ret = snd_soc_of_parse_card_name(card, "nvidia,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); + if (ret) + goto err; + + tegra_alc5632_dai.codec_of_node = of_parse_phandle( + pdev->dev.of_node, "nvidia,audio-codec", 0); + + if (!tegra_alc5632_dai.codec_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,audio-codec' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_alc5632_dai.cpu_dai_of_node = of_parse_phandle( + pdev->dev.of_node, "nvidia,i2s-controller", 0); + if (!tegra_alc5632_dai.cpu_dai_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,i2s-controller' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + alc5632->pcm_dev = platform_device_register_simple( + "tegra-pcm-audio", -1, NULL, 0); + if (IS_ERR(alc5632->pcm_dev)) { + dev_err(&pdev->dev, + "Can't instantiate tegra-pcm-audio\n"); + ret = PTR_ERR(alc5632->pcm_dev); + goto err; + } + + ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev); + if (ret) + goto err_unregister; + ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); - tegra_asoc_utils_fini(&alc5632->util_data); - return ret; + goto err_fini_utils; } return 0; + +err_fini_utils: + tegra_asoc_utils_fini(&alc5632->util_data); +err_unregister: + if (!IS_ERR(alc5632->pcm_dev)) + platform_device_unregister(alc5632->pcm_dev); +err: + return ret; } static int __devexit tegra_alc5632_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card); + struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card); + + if (machine->gpio_requested & GPIO_HP_DET) + snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, + 1, + &tegra_alc5632_hp_jack_gpio); + machine->gpio_requested = 0; snd_soc_unregister_card(card); - tegra_asoc_utils_fini(&alc5632->util_data); + tegra_asoc_utils_fini(&machine->util_data); + if (!IS_ERR(machine->pcm_dev)) + platform_device_unregister(machine->pcm_dev); return 0; } +static const struct of_device_id tegra_alc5632_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra-audio-alc5632", }, + {}, +}; + static struct platform_driver tegra_alc5632_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, + .of_match_table = tegra_alc5632_of_match, }, .probe = tegra_alc5632_probe, .remove = __devexit_p(tegra_alc5632_remove), @@ -212,3 +286,4 @@ MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>"); MODULE_DESCRIPTION("Tegra+ALC5632 machine ASoC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_alc5632_of_match); diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index c22431516ab..8b4457137c7 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -336,7 +336,7 @@ static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!card->dev->dma_mask) card->dev->dma_mask = &tegra_dma_mask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = tegra_pcm_preallocate_dma_buffer(pcm, diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 4dd051bdf4f..c6500d00053 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -1112,17 +1112,7 @@ static struct spi_driver at73c213_driver = { .remove = __devexit_p(snd_at73c213_remove), }; -static int __init at73c213_init(void) -{ - return spi_register_driver(&at73c213_driver); -} -module_init(at73c213_init); - -static void __exit at73c213_exit(void) -{ - spi_unregister_driver(&at73c213_driver); -} -module_exit(at73c213_exit); +module_spi_driver(at73c213_driver); MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>"); MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC"); diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index 8af92e3e9c1..fc8cc823e43 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify @@ -29,7 +28,7 @@ #include <sound/initval.h> MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>"); -MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver, version 0.3.0"); +MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver"); MODULE_LICENSE("GPL v2"); MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}"); diff --git a/sound/usb/6fire/chip.h b/sound/usb/6fire/chip.h index d11e5cb520f..bde02d105a5 100644 --- a/sound/usb/6fire/chip.h +++ b/sound/usb/6fire/chip.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c index c994daa57af..6c3d531a250 100644 --- a/sound/usb/6fire/comm.c +++ b/sound/usb/6fire/comm.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h index edc5dc84b88..d2af0a5ddcf 100644 --- a/sound/usb/6fire/comm.h +++ b/sound/usb/6fire/comm.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/common.h b/sound/usb/6fire/common.h index 7dbeb4a3783..b6eb03ed1c2 100644 --- a/sound/usb/6fire/common.h +++ b/sound/usb/6fire/common.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index ac828eff1a6..07ed914d5e7 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -5,9 +5,12 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * + * Thanks to: + * - Holger Ruckdeschel: he found out how to control individual channel + * volumes and introduced mute switch + * * 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 @@ -16,6 +19,7 @@ #include <linux/interrupt.h> #include <sound/control.h> +#include <sound/tlv.h> #include "control.h" #include "comm.h" @@ -25,26 +29,6 @@ static char *opt_coax_texts[2] = { "Optical", "Coax" }; static char *line_phono_texts[2] = { "Line", "Phono" }; /* - * calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$ - * this is done because the linear values cause rapid degredation - * of volume in the uppermost region. - */ -static const u8 log_volume_table[128] = { - 0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34, - 0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43, - 0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, - 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56, - 0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, - 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, - 0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68, - 0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, - 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, - 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, - 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, - 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, - 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f }; - -/* * data that needs to be sent to device. sets up card internal stuff. * values dumped from windows driver and filtered by trial'n'error. */ @@ -59,7 +43,7 @@ init_data[] = { { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 }, { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 }, { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 }, - { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, + { 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 }, { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 }, { 0 } /* TERMINATING ENTRY */ @@ -70,20 +54,47 @@ static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; +static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0); +static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500); + enum { DIGITAL_THRU_ONLY_SAMPLERATE = 3 }; -static void usb6fire_control_master_vol_update(struct control_runtime *rt) +static void usb6fire_control_output_vol_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; - if (comm_rt) { - /* set volume */ - comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f - - log_volume_table[rt->master_vol]); - /* unmute */ - comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00); - } + int i; + + if (comm_rt) + for (i = 0; i < 6; i++) + if (!(rt->ovol_updated & (1 << i))) { + comm_rt->write8(comm_rt, 0x12, 0x0f + i, + 180 - rt->output_vol[i]); + rt->ovol_updated |= 1 << i; + } +} + +static void usb6fire_control_output_mute_update(struct control_runtime *rt) +{ + struct comm_runtime *comm_rt = rt->chip->comm; + + if (comm_rt) + comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute); +} + +static void usb6fire_control_input_vol_update(struct control_runtime *rt) +{ + struct comm_runtime *comm_rt = rt->chip->comm; + int i; + + if (comm_rt) + for (i = 0; i < 2; i++) + if (!(rt->ivol_updated & (1 << i))) { + comm_rt->write8(comm_rt, 0x12, 0x1c + i, + rt->input_vol[i] & 0x3f); + rt->ivol_updated |= 1 << i; + } } static void usb6fire_control_line_phono_update(struct control_runtime *rt) @@ -165,34 +176,147 @@ static int usb6fire_control_streaming_update(struct control_runtime *rt) return -EINVAL; } -static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, +static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; + uinfo->count = 2; uinfo->value.integer.min = 0; - uinfo->value.integer.max = 127; + uinfo->value.integer.max = 180; return 0; } -static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol, +static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + unsigned int ch = kcontrol->private_value; int changed = 0; - if (rt->master_vol != ucontrol->value.integer.value[0]) { - rt->master_vol = ucontrol->value.integer.value[0]; - usb6fire_control_master_vol_update(rt); + + if (ch > 4) { + snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); + return -EINVAL; + } + + if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) { + rt->output_vol[ch] = ucontrol->value.integer.value[0]; + rt->ovol_updated &= ~(1 << ch); changed = 1; } + if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) { + rt->output_vol[ch + 1] = ucontrol->value.integer.value[1]; + rt->ovol_updated &= ~(2 << ch); + changed = 1; + } + + if (changed) + usb6fire_control_output_vol_update(rt); + return changed; } -static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol, +static int usb6fire_control_output_vol_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->master_vol; + unsigned int ch = kcontrol->private_value; + + if (ch > 4) { + snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = rt->output_vol[ch]; + ucontrol->value.integer.value[1] = rt->output_vol[ch + 1]; + return 0; +} + +static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + unsigned int ch = kcontrol->private_value; + u8 old = rt->output_mute; + u8 value = 0; + + if (ch > 4) { + snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); + return -EINVAL; + } + + rt->output_mute &= ~(3 << ch); + if (ucontrol->value.integer.value[0]) + value |= 1; + if (ucontrol->value.integer.value[1]) + value |= 2; + rt->output_mute |= value << ch; + + if (rt->output_mute != old) + usb6fire_control_output_mute_update(rt); + + return rt->output_mute != old; +} + +static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + unsigned int ch = kcontrol->private_value; + u8 value = rt->output_mute >> ch; + + if (ch > 4) { + snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = 1 & value; + value >>= 1; + ucontrol->value.integer.value[1] = 1 & value; + + return 0; +} + +static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 30; + return 0; +} + +static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + int changed = 0; + + if (rt->input_vol[0] != ucontrol->value.integer.value[0]) { + rt->input_vol[0] = ucontrol->value.integer.value[0] - 15; + rt->ivol_updated &= ~(1 << 0); + changed = 1; + } + if (rt->input_vol[1] != ucontrol->value.integer.value[1]) { + rt->input_vol[1] = ucontrol->value.integer.value[1] - 15; + rt->ivol_updated &= ~(1 << 1); + changed = 1; + } + + if (changed) + usb6fire_control_input_vol_update(rt); + + return changed; +} + +static int usb6fire_control_input_vol_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->input_vol[0] + 15; + ucontrol->value.integer.value[1] = rt->input_vol[1] + 15; + return 0; } @@ -287,18 +411,83 @@ static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, return 0; } -static struct __devinitdata snd_kcontrol_new elements[] = { +static struct __devinitdata snd_kcontrol_new vol_elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", + .name = "Analog Playback Volume", .index = 0, + .private_value = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = usb6fire_control_output_vol_info, + .get = usb6fire_control_output_vol_get, + .put = usb6fire_control_output_vol_put, + .tlv = { .p = tlv_output } + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Volume", + .index = 1, + .private_value = 2, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = usb6fire_control_output_vol_info, + .get = usb6fire_control_output_vol_get, + .put = usb6fire_control_output_vol_put, + .tlv = { .p = tlv_output } + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Volume", + .index = 2, + .private_value = 4, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = usb6fire_control_output_vol_info, + .get = usb6fire_control_output_vol_get, + .put = usb6fire_control_output_vol_put, + .tlv = { .p = tlv_output } + }, + {} +}; + +static struct __devinitdata snd_kcontrol_new mute_elements[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Switch", + .index = 0, + .private_value = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_stereo_info, + .get = usb6fire_control_output_mute_get, + .put = usb6fire_control_output_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Switch", + .index = 1, + .private_value = 2, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = usb6fire_control_master_vol_info, - .get = usb6fire_control_master_vol_get, - .put = usb6fire_control_master_vol_put + .info = snd_ctl_boolean_stereo_info, + .get = usb6fire_control_output_mute_get, + .put = usb6fire_control_output_mute_put, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Switch", + .index = 2, + .private_value = 4, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_stereo_info, + .get = usb6fire_control_output_mute_get, + .put = usb6fire_control_output_mute_put, + }, + {} +}; + +static struct __devinitdata snd_kcontrol_new elements[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line/Phono Capture Route", .index = 0, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -324,9 +513,54 @@ static struct __devinitdata snd_kcontrol_new elements[] = { .get = usb6fire_control_digital_thru_get, .put = usb6fire_control_digital_thru_put }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Capture Volume", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = usb6fire_control_input_vol_info, + .get = usb6fire_control_input_vol_get, + .put = usb6fire_control_input_vol_put, + .tlv = { .p = tlv_input } + }, {} }; +static int usb6fire_control_add_virtual( + struct control_runtime *rt, + struct snd_card *card, + char *name, + struct snd_kcontrol_new *elems) +{ + int ret; + int i; + struct snd_kcontrol *vmaster = + snd_ctl_make_virtual_master(name, tlv_output); + struct snd_kcontrol *control; + + if (!vmaster) + return -ENOMEM; + ret = snd_ctl_add(card, vmaster); + if (ret < 0) + return ret; + + i = 0; + while (elems[i].name) { + control = snd_ctl_new1(&elems[i], rt); + if (!control) + return -ENOMEM; + ret = snd_ctl_add(card, control); + if (ret < 0) + return ret; + ret = snd_ctl_add_slave(vmaster, control); + if (ret < 0) + return ret; + i++; + } + return 0; +} + int __devinit usb6fire_control_init(struct sfire_chip *chip) { int i; @@ -352,9 +586,26 @@ 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_output_vol_update(rt); + usb6fire_control_output_mute_update(rt); + usb6fire_control_input_vol_update(rt); usb6fire_control_streaming_update(rt); + ret = usb6fire_control_add_virtual(rt, chip->card, + "Master Playback Volume", vol_elements); + if (ret) { + snd_printk(KERN_ERR PREFIX "cannot add control.\n"); + kfree(rt); + return ret; + } + ret = usb6fire_control_add_virtual(rt, chip->card, + "Master Playback Switch", mute_elements); + if (ret) { + snd_printk(KERN_ERR PREFIX "cannot add control.\n"); + kfree(rt); + return ret; + } + i = 0; while (elements[i].name) { ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt)); diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index 8f5aeead2e3..9a596d95474 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify @@ -44,7 +43,11 @@ struct control_runtime { bool line_phono_switch; bool digital_thru_switch; bool usb_streaming; - u8 master_vol; + u8 output_vol[6]; + u8 ovol_updated; + u8 output_mute; + s8 input_vol[2]; + u8 ivol_updated; }; int __devinit usb6fire_control_init(struct sfire_chip *chip); diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 3b5f517a397..6f9715ab32f 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c index 13f4509dce2..f0e5179b242 100644 --- a/sound/usb/6fire/midi.c +++ b/sound/usb/6fire/midi.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h index 97a7bf66913..5114eccc1d8 100644 --- a/sound/usb/6fire/midi.h +++ b/sound/usb/6fire/midi.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index d144cdb2f15..c97d05f0e96 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h index 2bee8137400..3104301b257 100644 --- a/sound/usb/6fire/pcm.h +++ b/sound/usb/6fire/pcm.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk <torsten.schenk@zoho.com> * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 3efc21c3d67..ff77b28f3da 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -106,6 +106,7 @@ config SND_USB_6FIRE select BITREVERSE select SND_RAWMIDI select SND_PCM + select SND_VMASTER help Say Y here to include support for TerraTec 6fire DMX USB interface. diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0220b0f335b..0eed6115c2d 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -695,6 +695,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) { struct audioformat *fp; + int *rate_list; int count = 0, needs_knot = 0; int err; @@ -708,7 +709,8 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, if (!needs_knot) return 0; - subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); + subs->rate_list.list = rate_list = + kmalloc(sizeof(int) * count, GFP_KERNEL); if (!subs->rate_list.list) return -ENOMEM; subs->rate_list.count = count; @@ -717,7 +719,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, list_for_each_entry(fp, &subs->fmt_list, list) { int i; for (i = 0; i < fp->nr_rates; i++) - subs->rate_list.list[count++] = fp->rate_table[i]; + rate_list[count++] = fp->rate_table[i]; } err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &subs->rate_list); diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 6ffb3713b60..520ef96d7c7 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -80,7 +80,7 @@ static int usX2Y_urb_capt_retire(struct snd_usX2Y_substream *subs) cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ snd_printk(KERN_ERR "active frame status %i. " - "Most propably some hardware problem.\n", + "Most probably some hardware problem.\n", urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } @@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, { snd_printk(KERN_ERR "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" -"Most propably some urb of usb-frame %i is still missing.\n" +"Most probably some urb of usb-frame %i is still missing.\n" "Cause could be too long delays in usb-hcd interrupt handling.\n", usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index a51340f6f2d..8e40b6e67e9 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -74,7 +74,7 @@ static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs) } for (i = 0; i < nr_of_packs(); i++) { if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ - snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); + snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride; |