aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_auto_parser.c2
-rw-r--r--sound/pci/hda/hda_beep.h2
-rw-r--r--sound/pci/hda/hda_bind.c14
-rw-r--r--sound/pci/hda/hda_codec.c2
-rw-r--r--sound/pci/hda/hda_codec.h534
-rw-r--r--sound/pci/hda/hda_controller.c36
-rw-r--r--sound/pci/hda/hda_controller.h20
-rw-r--r--sound/pci/hda/hda_eld.c2
-rw-r--r--sound/pci/hda/hda_generic.c2
-rw-r--r--sound/pci/hda/hda_hwdep.c2
-rw-r--r--sound/pci/hda/hda_intel.c112
-rw-r--r--sound/pci/hda/hda_jack.c2
-rw-r--r--sound/pci/hda/hda_proc.c2
-rw-r--r--sound/pci/hda/hda_sysfs.c2
-rw-r--r--sound/pci/hda/hda_tegra.c20
-rw-r--r--sound/pci/hda/patch_analog.c2
-rw-r--r--sound/pci/hda/patch_ca0110.c2
-rw-r--r--sound/pci/hda/patch_ca0132.c1617
-rw-r--r--sound/pci/hda/patch_cirrus.c2
-rw-r--r--sound/pci/hda/patch_cmedia.c2
-rw-r--r--sound/pci/hda/patch_conexant.c3
-rw-r--r--sound/pci/hda/patch_hdmi.c2
-rw-r--r--sound/pci/hda/patch_realtek.c29
-rw-r--r--sound/pci/hda/patch_si3054.c2
-rw-r--r--sound/pci/hda/patch_sigmatel.c22
-rw-r--r--sound/pci/hda/patch_via.c2
26 files changed, 1498 insertions, 941 deletions
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index b9a6b66aeb0e..df0d636145f8 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -13,7 +13,7 @@
#include <linux/export.h>
#include <linux/sort.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index d1a6a9c1329a..f1457c6b3969 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -9,7 +9,7 @@
#ifndef __SOUND_HDA_BEEP_H
#define __SOUND_HDA_BEEP_H
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#define HDA_BEEP_MODE_OFF 0
#define HDA_BEEP_MODE_ON 1
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
index d361bb77ca00..9174f1b3a987 100644
--- a/sound/pci/hda/hda_bind.c
+++ b/sound/pci/hda/hda_bind.c
@@ -11,7 +11,7 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
/*
@@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev)
hda_codec_patch_t patch;
int err;
+ if (codec->bus->core.ext_ops) {
+ if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach))
+ return -EINVAL;
+ return codec->bus->core.ext_ops->hdev_attach(&codec->core);
+ }
+
if (WARN_ON(!codec->preset))
return -EINVAL;
@@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
+ if (codec->bus->core.ext_ops) {
+ if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
+ return -EINVAL;
+ return codec->bus->core.ext_ops->hdev_detach(&codec->core);
+ }
+
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
snd_hda_codec_cleanup_for_unbind(codec);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 26d348b47867..0957813939e5 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -27,7 +27,7 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include <sound/asoundef.h>
#include <sound/tlv.h>
#include <sound/initval.h>
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
deleted file mode 100644
index 0d98bb9068b1..000000000000
--- a/sound/pci/hda/hda_codec.h
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __SOUND_HDA_CODEC_H
-#define __SOUND_HDA_CODEC_H
-
-#include <linux/kref.h>
-#include <linux/mod_devicetable.h>
-#include <sound/info.h>
-#include <sound/control.h>
-#include <sound/pcm.h>
-#include <sound/hwdep.h>
-#include <sound/hdaudio.h>
-#include <sound/hda_verbs.h>
-#include <sound/hda_regmap.h>
-
-/*
- * Structures
- */
-
-struct hda_bus;
-struct hda_beep;
-struct hda_codec;
-struct hda_pcm;
-struct hda_pcm_stream;
-
-/*
- * codec bus
- *
- * each controller needs to creata a hda_bus to assign the accessor.
- * A hda_bus contains several codecs in the list codec_list.
- */
-struct hda_bus {
- struct hdac_bus core;
-
- struct snd_card *card;
-
- struct pci_dev *pci;
- const char *modelname;
-
- struct mutex prepare_mutex;
-
- /* assigned PCMs */
- DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
-
- /* misc op flags */
- unsigned int needs_damn_long_delay :1;
- unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */
- /* status for codec/controller */
- unsigned int shutdown :1; /* being unloaded */
- unsigned int response_reset:1; /* controller was reset */
- unsigned int in_reset:1; /* during reset operation */
- unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
-
- int primary_dig_out_type; /* primary digital out PCM type */
- unsigned int mixer_assigned; /* codec addr for mixer name */
-};
-
-/* from hdac_bus to hda_bus */
-#define to_hda_bus(bus) container_of(bus, struct hda_bus, core)
-
-/*
- * codec preset
- *
- * Known codecs have the patch to build and set up the controls/PCMs
- * better than the generic parser.
- */
-typedef int (*hda_codec_patch_t)(struct hda_codec *);
-
-#define HDA_CODEC_ID_SKIP_PROBE 0x00000001
-#define HDA_CODEC_ID_GENERIC_HDMI 0x00000101
-#define HDA_CODEC_ID_GENERIC 0x00000201
-
-#define HDA_CODEC_REV_ENTRY(_vid, _rev, _name, _patch) \
- { .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
- .api_version = HDA_DEV_LEGACY, \
- .driver_data = (unsigned long)(_patch) }
-#define HDA_CODEC_ENTRY(_vid, _name, _patch) \
- HDA_CODEC_REV_ENTRY(_vid, 0, _name, _patch)
-
-struct hda_codec_driver {
- struct hdac_driver core;
- const struct hda_device_id *id;
-};
-
-int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
- struct module *owner);
-#define hda_codec_driver_register(drv) \
- __hda_codec_driver_register(drv, KBUILD_MODNAME, THIS_MODULE)
-void hda_codec_driver_unregister(struct hda_codec_driver *drv);
-#define module_hda_codec_driver(drv) \
- module_driver(drv, hda_codec_driver_register, \
- hda_codec_driver_unregister)
-
-/* ops set by the preset patch */
-struct hda_codec_ops {
- int (*build_controls)(struct hda_codec *codec);
- int (*build_pcms)(struct hda_codec *codec);
- int (*init)(struct hda_codec *codec);
- void (*free)(struct hda_codec *codec);
- void (*unsol_event)(struct hda_codec *codec, unsigned int res);
- void (*set_power_state)(struct hda_codec *codec, hda_nid_t fg,
- unsigned int power_state);
-#ifdef CONFIG_PM
- int (*suspend)(struct hda_codec *codec);
- int (*resume)(struct hda_codec *codec);
- int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);
-#endif
- void (*reboot_notify)(struct hda_codec *codec);
- void (*stream_pm)(struct hda_codec *codec, hda_nid_t nid, bool on);
-};
-
-/* PCM callbacks */
-struct hda_pcm_ops {
- int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec,
- struct snd_pcm_substream *substream);
- int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec,
- struct snd_pcm_substream *substream);
- int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec,
- unsigned int stream_tag, unsigned int format,
- struct snd_pcm_substream *substream);
- int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
- struct snd_pcm_substream *substream);
- unsigned int (*get_delay)(struct hda_pcm_stream *info,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream);
-};
-
-/* PCM information for each substream */
-struct hda_pcm_stream {
- unsigned int substreams; /* number of substreams, 0 = not exist*/
- unsigned int channels_min; /* min. number of channels */
- unsigned int channels_max; /* max. number of channels */
- hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */
- u32 rates; /* supported rates */
- u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */
- unsigned int maxbps; /* supported max. bit per sample */
- const struct snd_pcm_chmap_elem *chmap; /* chmap to override */
- struct hda_pcm_ops ops;
-};
-
-/* PCM types */
-enum {
- HDA_PCM_TYPE_AUDIO,
- HDA_PCM_TYPE_SPDIF,
- HDA_PCM_TYPE_HDMI,
- HDA_PCM_TYPE_MODEM,
- HDA_PCM_NTYPES
-};
-
-#define SNDRV_PCM_INVALID_DEVICE (-1)
-/* for PCM creation */
-struct hda_pcm {
- char *name;
- struct hda_pcm_stream stream[2];
- unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */
- int device; /* device number to assign */
- struct snd_pcm *pcm; /* assigned PCM instance */
- bool own_chmap; /* codec driver provides own channel maps */
- /* private: */
- struct hda_codec *codec;
- struct kref kref;
- struct list_head list;
-};
-
-/* codec information */
-struct hda_codec {
- struct hdac_device core;
- struct hda_bus *bus;
- struct snd_card *card;
- unsigned int addr; /* codec addr*/
- u32 probe_id; /* overridden id for probing */
-
- /* detected preset */
- const struct hda_device_id *preset;
- const char *modelname; /* model name for preset */
-
- /* set by patch */
- struct hda_codec_ops patch_ops;
-
- /* PCM to create, set by patch_ops.build_pcms callback */
- struct list_head pcm_list_head;
-
- /* codec specific info */
- void *spec;
-
- /* beep device */
- struct hda_beep *beep;
- unsigned int beep_mode;
-
- /* widget capabilities cache */
- u32 *wcaps;
-
- struct snd_array mixers; /* list of assigned mixer elements */
- struct snd_array nids; /* list of mapped mixer elements */
-
- struct list_head conn_list; /* linked-list of connection-list */
-
- struct mutex spdif_mutex;
- struct mutex control_mutex;
- struct snd_array spdif_out;
- unsigned int spdif_in_enable; /* SPDIF input enable? */
- const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
- struct snd_array init_pins; /* initial (BIOS) pin configurations */
- struct snd_array driver_pins; /* pin configs set by codec parser */
- struct snd_array cvt_setups; /* audio convert setups */
-
- struct mutex user_mutex;
-#ifdef CONFIG_SND_HDA_RECONFIG
- struct snd_array init_verbs; /* additional init verbs */
- struct snd_array hints; /* additional hints */
- struct snd_array user_pins; /* default pin configs to override */
-#endif
-
-#ifdef CONFIG_SND_HDA_HWDEP
- struct snd_hwdep *hwdep; /* assigned hwdep device */
-#endif
-
- /* misc flags */
- unsigned int in_freeing:1; /* being released */
- unsigned int registered:1; /* codec was registered */
- unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
- * status change
- * (e.g. Realtek codecs)
- */
- unsigned int pin_amp_workaround:1; /* pin out-amp takes index
- * (e.g. Conexant codecs)
- */
- unsigned int single_adc_amp:1; /* adc in-amp takes no index
- * (e.g. CX20549 codec)
- */
- unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
- unsigned int pins_shutup:1; /* pins are shut up */
- unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
- unsigned int no_jack_detect:1; /* Machine has no jack-detection */
- unsigned int inv_eapd:1; /* broken h/w: inverted EAPD control */
- unsigned int inv_jack_detect:1; /* broken h/w: inverted detection bit */
- unsigned int pcm_format_first:1; /* PCM format must be set first */
- unsigned int cached_write:1; /* write only to caches */
- unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
- unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
- unsigned int power_save_node:1; /* advanced PM for each widget */
- unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */
- unsigned int force_pin_prefix:1; /* Add location prefix */
- unsigned int link_down_at_suspend:1; /* link down at runtime suspend */
-#ifdef CONFIG_PM
- unsigned long power_on_acct;
- unsigned long power_off_acct;
- unsigned long power_jiffies;
-#endif
-
- /* filter the requested power state per nid */
- unsigned int (*power_filter)(struct hda_codec *codec, hda_nid_t nid,
- unsigned int power_state);
-
- /* codec-specific additional proc output */
- void (*proc_widget_hook)(struct snd_info_buffer *buffer,
- struct hda_codec *codec, hda_nid_t nid);
-
- /* jack detection */
- struct snd_array jacktbl;
- unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */
- struct delayed_work jackpoll_work;
-
- /* jack detection */
- struct snd_array jacks;
-
- int depop_delay; /* depop delay in ms, -1 for default delay time */
-
- /* fix-up list */
- int fixup_id;
- const struct hda_fixup *fixup_list;
- const char *fixup_name;
-
- /* additional init verbs */
- struct snd_array verbs;
-};
-
-#define dev_to_hda_codec(_dev) container_of(_dev, struct hda_codec, core.dev)
-#define hda_codec_dev(_dev) (&(_dev)->core.dev)
-
-#define list_for_each_codec(c, bus) \
- list_for_each_entry(c, &(bus)->core.codec_list, core.list)
-#define list_for_each_codec_safe(c, n, bus) \
- list_for_each_entry_safe(c, n, &(bus)->core.codec_list, core.list)
-
-/* snd_hda_codec_read/write optional flags */
-#define HDA_RW_NO_RESPONSE_FALLBACK (1 << 0)
-
-/*
- * constructors
- */
-int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
- unsigned int codec_addr, struct hda_codec **codecp);
-int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
- unsigned int codec_addr, struct hda_codec *codec);
-int snd_hda_codec_configure(struct hda_codec *codec);
-int snd_hda_codec_update_widgets(struct hda_codec *codec);
-
-/*
- * low level functions
- */
-static inline unsigned int
-snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
- int flags,
- unsigned int verb, unsigned int parm)
-{
- return snd_hdac_codec_read(&codec->core, nid, flags, verb, parm);
-}
-
-static inline int
-snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
- unsigned int verb, unsigned int parm)
-{
- return snd_hdac_codec_write(&codec->core, nid, flags, verb, parm);
-}
-
-#define snd_hda_param_read(codec, nid, param) \
- snd_hdac_read_parm(&(codec)->core, nid, param)
-#define snd_hda_get_sub_nodes(codec, nid, start_nid) \
- snd_hdac_get_sub_nodes(&(codec)->core, nid, start_nid)
-int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
- hda_nid_t *conn_list, int max_conns);
-static inline int
-snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
-{
- return snd_hda_get_connections(codec, nid, NULL, 0);
-}
-
-#define snd_hda_get_raw_connections(codec, nid, list, max_conns) \
- snd_hdac_get_connections(&(codec)->core, nid, list, max_conns)
-#define snd_hda_get_num_raw_conns(codec, nid) \
- snd_hdac_get_connections(&(codec)->core, nid, NULL, 0);
-
-int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
- const hda_nid_t **listp);
-int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
- const hda_nid_t *list);
-int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
- hda_nid_t nid, int recursive);
-unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid);
-int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
- u8 *dev_list, int max_devices);
-int snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid);
-int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id);
-
-struct hda_verb {
- hda_nid_t nid;
- u32 verb;
- u32 param;
-};
-
-void snd_hda_sequence_write(struct hda_codec *codec,
- const struct hda_verb *seq);
-
-/* unsolicited event */
-static inline void
-snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
-{
- snd_hdac_bus_queue_event(&bus->core, res, res_ex);
-}
-
-/* cached write */
-static inline int
-snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
- int flags, unsigned int verb, unsigned int parm)
-{
- return snd_hdac_regmap_write(&codec->core, nid, verb, parm);
-}
-
-/* the struct for codec->pin_configs */
-struct hda_pincfg {
- hda_nid_t nid;
- unsigned char ctrl; /* original pin control value */
- unsigned char target; /* target pin control value */
- unsigned int cfg; /* default configuration */
-};
-
-unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid);
-int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid,
- unsigned int cfg);
-int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
- hda_nid_t nid, unsigned int cfg); /* for hwdep */
-void snd_hda_shutup_pins(struct hda_codec *codec);
-
-/* SPDIF controls */
-struct hda_spdif_out {
- hda_nid_t nid; /* Converter nid values relate to */
- unsigned int status; /* IEC958 status bits */
- unsigned short ctls; /* SPDIF control bits */
-};
-struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
- hda_nid_t nid);
-void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx);
-void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid);
-
-/*
- * Mixer
- */
-int snd_hda_codec_build_controls(struct hda_codec *codec);
-
-/*
- * PCM
- */
-int snd_hda_codec_parse_pcms(struct hda_codec *codec);
-int snd_hda_codec_build_pcms(struct hda_codec *codec);
-
-__printf(2, 3)
-struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
- const char *fmt, ...);
-
-static inline void snd_hda_codec_pcm_get(struct hda_pcm *pcm)
-{
- kref_get(&pcm->kref);
-}
-void snd_hda_codec_pcm_put(struct hda_pcm *pcm);
-
-int snd_hda_codec_prepare(struct hda_codec *codec,
- struct hda_pcm_stream *hinfo,
- unsigned int stream,
- unsigned int format,
- struct snd_pcm_substream *substream);
-void snd_hda_codec_cleanup(struct hda_codec *codec,
- struct hda_pcm_stream *hinfo,
- struct snd_pcm_substream *substream);
-
-void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
- u32 stream_tag,
- int channel_id, int format);
-void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
- int do_now);
-#define snd_hda_codec_cleanup_stream(codec, nid) \
- __snd_hda_codec_cleanup_stream(codec, nid, 0)
-
-#define snd_hda_query_supported_pcm(codec, nid, ratesp, fmtsp, bpsp) \
- snd_hdac_query_supported_pcm(&(codec)->core, nid, ratesp, fmtsp, bpsp)
-#define snd_hda_is_supported_format(codec, nid, fmt) \
- snd_hdac_is_supported_format(&(codec)->core, nid, fmt)
-
-extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[];
-
-int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
- struct hda_pcm *cpcm);
-
-/*
- * Misc
- */
-void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
-void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
- unsigned int power_state);
-
-int snd_hda_lock_devices(struct hda_bus *bus);
-void snd_hda_unlock_devices(struct hda_bus *bus);
-void snd_hda_bus_reset(struct hda_bus *bus);
-void snd_hda_bus_reset_codecs(struct hda_bus *bus);
-
-int snd_hda_codec_set_name(struct hda_codec *codec, const char *name);
-
-/*
- * power management
- */
-extern const struct dev_pm_ops hda_codec_driver_pm;
-
-static inline
-int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
-{
-#ifdef CONFIG_PM
- if (codec->patch_ops.check_power_status)
- return codec->patch_ops.check_power_status(codec, nid);
-#endif
- return 0;
-}
-
-/*
- * power saving
- */
-#define snd_hda_power_up(codec) snd_hdac_power_up(&(codec)->core)
-#define snd_hda_power_up_pm(codec) snd_hdac_power_up_pm(&(codec)->core)
-#define snd_hda_power_down(codec) snd_hdac_power_down(&(codec)->core)
-#define snd_hda_power_down_pm(codec) snd_hdac_power_down_pm(&(codec)->core)
-#ifdef CONFIG_PM
-void snd_hda_set_power_save(struct hda_bus *bus, int delay);
-void snd_hda_update_power_acct(struct hda_codec *codec);
-#else
-static inline void snd_hda_set_power_save(struct hda_bus *bus, int delay) {}
-#endif
-
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
-/*
- * patch firmware
- */
-int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);
-#endif
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-int snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
- unsigned int size,
- struct snd_dma_buffer *bufp);
-void snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start);
-void snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
- struct snd_dma_buffer *dmab);
-#else
-static inline int
-snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
- unsigned int size,
- struct snd_dma_buffer *bufp)
-{
- return -ENOSYS;
-}
-static inline void
-snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) {}
-static inline void
-snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
- struct snd_dma_buffer *dmab) {}
-#endif
-
-#endif /* __SOUND_HDA_CODEC_H */
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index a12e594d4e3b..fe2506672a72 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -130,8 +130,9 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
azx_dev->core.bufsize = 0;
azx_dev->core.period_bytes = 0;
azx_dev->core.format_val = 0;
- ret = chip->ops->substream_alloc_pages(chip, substream,
- params_buffer_bytes(hw_params));
+ ret = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+
unlock:
dsp_unlock(azx_dev);
return ret;
@@ -141,7 +142,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx_dev *azx_dev = get_azx_dev(substream);
- struct azx *chip = apcm->chip;
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
int err;
@@ -152,7 +152,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
- err = chip->ops->substream_free_pages(chip, substream);
+ err = snd_pcm_lib_free_pages(substream);
azx_stream(azx_dev)->prepared = 0;
dsp_unlock(azx_dev);
return err;
@@ -732,6 +732,7 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
int pcm_dev = cpcm->device;
unsigned int size;
int s, err;
+ int type = SNDRV_DMA_TYPE_DEV_SG;
list_for_each_entry(apcm, &chip->pcm_list, list) {
if (apcm->pcm->device == pcm_dev) {
@@ -770,7 +771,9 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
if (size > MAX_PREALLOC_SIZE)
size = MAX_PREALLOC_SIZE;
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+ if (chip->uc_buffer)
+ type = SNDRV_DMA_TYPE_DEV_UC_SG;
+ snd_pcm_lib_preallocate_pages_for_all(pcm, type,
chip->card->dev,
size, MAX_PREALLOC_SIZE);
return 0;
@@ -1220,27 +1223,6 @@ void snd_hda_bus_reset(struct hda_bus *bus)
bus->in_reset = 0;
}
-static int get_jackpoll_interval(struct azx *chip)
-{
- int i;
- unsigned int j;
-
- if (!chip->jackpoll_ms)
- return 0;
-
- i = chip->jackpoll_ms[chip->dev_index];
- if (i == 0)
- return 0;
- if (i < 50 || i > 60000)
- j = 0;
- else
- j = msecs_to_jiffies(i);
- if (j == 0)
- dev_warn(chip->card->dev,
- "jackpoll_ms value out of range: %d\n", i);
- return j;
-}
-
/* HD-audio bus initialization */
int azx_bus_init(struct azx *chip, const char *model,
const struct hdac_io_ops *io_ops)
@@ -1323,7 +1305,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec);
if (err < 0)
continue;
- codec->jackpoll_interval = get_jackpoll_interval(chip);
+ codec->jackpoll_interval = chip->jackpoll_interval;
codec->beep_mode = chip->beep_mode;
codecs++;
}
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index a68e75b00ea3..c95097bb5a0c 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -20,7 +20,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include <sound/hda_register.h>
#define AZX_MAX_CODECS HDA_MAX_CODECS
@@ -76,7 +76,6 @@ struct azx_dev {
* when link position is not greater than FIFO size
*/
unsigned int insufficient:1;
- unsigned int wc_marked:1;
};
#define azx_stream(dev) (&(dev)->core)
@@ -88,11 +87,6 @@ struct azx;
struct hda_controller_ops {
/* Disable msi if supported, PCI only */
int (*disable_msi_reset_irq)(struct azx *);
- int (*substream_alloc_pages)(struct azx *chip,
- struct snd_pcm_substream *substream,
- size_t size);
- int (*substream_free_pages)(struct azx *chip,
- struct snd_pcm_substream *substream);
void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
struct vm_area_struct *area);
/* Check if current position is acceptable */
@@ -127,7 +121,7 @@ struct azx {
int capture_streams;
int capture_index_offset;
int num_streams;
- const int *jackpoll_ms; /* per-card jack poll interval */
+ int jackpoll_interval; /* jack poll interval in jiffies */
/* Register interaction. */
const struct hda_controller_ops *ops;
@@ -160,6 +154,7 @@ struct azx {
unsigned int msi:1;
unsigned int probing:1; /* codec probing phase */
unsigned int snoop:1;
+ unsigned int uc_buffer:1; /* non-cached pages for stream buffers */
unsigned int align_buffer_size:1;
unsigned int region_requested:1;
unsigned int disabled:1; /* disabled by vga_switcheroo */
@@ -175,11 +170,10 @@ struct azx {
#define azx_bus(chip) (&(chip)->bus.core)
#define bus_to_azx(_bus) container_of(_bus, struct azx, bus.core)
-#ifdef CONFIG_X86
-#define azx_snoop(chip) ((chip)->snoop)
-#else
-#define azx_snoop(chip) true
-#endif
+static inline bool azx_snoop(struct azx *chip)
+{
+ return !IS_ENABLED(CONFIG_X86) || chip->snoop;
+}
/*
* macros for easy use
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index ba7fe9b6655c..806b12ed44a2 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -27,7 +27,7 @@
#include <sound/core.h>
#include <asm/unaligned.h>
#include <sound/hda_chmap.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
enum eld_versions {
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 579984ecdec3..276150f29cda 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -32,7 +32,7 @@
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/tlv.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index cc009a4a3d1d..268bba6ec985 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -23,7 +23,7 @@
#include <linux/compat.h>
#include <linux/nospec.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include <sound/hda_hwdep.h>
#include <sound/minors.h>
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index aa4c672dbaf7..d8eb2b5f51ae 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -63,7 +63,7 @@
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include <linux/firmware.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_controller.h"
#include "hda_intel.h"
@@ -399,61 +399,6 @@ static char *driver_short_names[] = {
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
-#ifdef CONFIG_X86
-static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
-{
- int pages;
-
- if (azx_snoop(chip))
- return;
- if (!dmab || !dmab->area || !dmab->bytes)
- return;
-
-#ifdef CONFIG_SND_DMA_SGBUF
- if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
- struct snd_sg_buf *sgbuf = dmab->private_data;
- if (chip->driver_type == AZX_DRIVER_CMEDIA)
- return; /* deal with only CORB/RIRB buffers */
- if (on)
- set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
- else
- set_pages_array_wb(sgbuf->page_table, sgbuf->pages);
- return;
- }
-#endif
-
- pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
- if (on)
- set_memory_wc((unsigned long)dmab->area, pages);
- else
- set_memory_wb((unsigned long)dmab->area, pages);
-}
-
-static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
- bool on)
-{
- __mark_pages_wc(chip, buf, on);
-}
-static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
- struct snd_pcm_substream *substream, bool on)
-{
- if (azx_dev->wc_marked != on) {
- __mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on);
- azx_dev->wc_marked = on;
- }
-}
-#else
-/* NOP for other archs */
-static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
- bool on)
-{
-}
-static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
- struct snd_pcm_substream *substream, bool on)
-{
-}
-#endif
-
static int azx_acquire_irq(struct azx *chip, int do_disconnect);
static void set_default_power_save(struct azx *chip);
@@ -1678,6 +1623,7 @@ static void azx_check_snoop_available(struct azx *chip)
dev_info(chip->card->dev, "Force to %s mode by module option\n",
snoop ? "snoop" : "non-snoop");
chip->snoop = snoop;
+ chip->uc_buffer = !snoop;
return;
}
@@ -1698,8 +1644,12 @@ static void azx_check_snoop_available(struct azx *chip)
snoop = false;
chip->snoop = snoop;
- if (!snoop)
+ if (!snoop) {
dev_info(chip->card->dev, "Force to non-snoop mode\n");
+ /* C-Media requires non-cached pages only for CORB/RIRB */
+ if (chip->driver_type != AZX_DRIVER_CMEDIA)
+ chip->uc_buffer = true;
+ }
}
static void azx_probe_work(struct work_struct *work)
@@ -1767,7 +1717,8 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
chip->driver_type = driver_caps & 0xff;
check_msi(chip);
chip->dev_index = dev;
- chip->jackpoll_ms = jackpoll_ms;
+ if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000)
+ chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]);
INIT_LIST_HEAD(&chip->pcm_list);
INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
INIT_LIST_HEAD(&hda->list);
@@ -2090,55 +2041,24 @@ static int dma_alloc_pages(struct hdac_bus *bus,
struct snd_dma_buffer *buf)
{
struct azx *chip = bus_to_azx(bus);
- int err;
- err = snd_dma_alloc_pages(type,
- bus->dev,
- size, buf);
- if (err < 0)
- return err;
- mark_pages_wc(chip, buf, true);
- return 0;
+ if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV)
+ type = SNDRV_DMA_TYPE_DEV_UC;
+ return snd_dma_alloc_pages(type, bus->dev, size, buf);
}
static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
{
- struct azx *chip = bus_to_azx(bus);
-
- mark_pages_wc(chip, buf, false);
snd_dma_free_pages(buf);
}
-static int substream_alloc_pages(struct azx *chip,
- struct snd_pcm_substream *substream,
- size_t size)
-{
- struct azx_dev *azx_dev = get_azx_dev(substream);
- int ret;
-
- mark_runtime_wc(chip, azx_dev, substream, false);
- ret = snd_pcm_lib_malloc_pages(substream, size);
- if (ret < 0)
- return ret;
- mark_runtime_wc(chip, azx_dev, substream, true);
- return 0;
-}
-
-static int substream_free_pages(struct azx *chip,
- struct snd_pcm_substream *substream)
-{
- struct azx_dev *azx_dev = get_azx_dev(substream);
- mark_runtime_wc(chip, azx_dev, substream, false);
- return snd_pcm_lib_free_pages(substream);
-}
-
static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
#ifdef CONFIG_X86
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
- if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA)
+ if (chip->uc_buffer)
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
#endif
}
@@ -2156,8 +2076,6 @@ static const struct hdac_io_ops pci_hda_io_ops = {
static const struct hda_controller_ops pci_hda_ops = {
.disable_msi_reset_irq = disable_msi_reset_irq,
- .substream_alloc_pages = substream_alloc_pages,
- .substream_free_pages = substream_free_pages,
.pcm_mmap_prepare = pcm_mmap_prepare,
.position_check = azx_position_check,
.link_power = azx_intel_link_power,
@@ -2257,8 +2175,12 @@ static struct snd_pci_quirk power_save_blacklist[] = {
/* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */
SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0),
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+ SND_PCI_QUIRK(0x1028, 0x0497, "Dell Precision T3600", 0),
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
/* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0),
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+ SND_PCI_QUIRK(0x8086, 0x2040, "Intel DZ77BH-55K", 0),
/* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */
SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0),
/* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index a33234e04d4f..c499727920e6 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -15,7 +15,7 @@
#include <sound/core.h>
#include <sound/control.h>
#include <sound/jack.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index c6b778b2580c..a65740419650 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -25,7 +25,7 @@
#include <linux/slab.h>
#include <sound/core.h>
#include <linux/module.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
static int dump_coef = -1;
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c
index 6ec79c58d48d..c154b19a0c45 100644
--- a/sound/pci/hda/hda_sysfs.c
+++ b/sound/pci/hda/hda_sysfs.c
@@ -14,7 +14,7 @@
#include <linux/string.h>
#include <linux/export.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include <sound/hda_hwdep.h>
#include <sound/minors.h>
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 0621920f7617..dd7d4242d6d2 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -35,7 +35,7 @@
#include <sound/core.h>
#include <sound/initval.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_controller.h"
/* Defines for Nvidia Tegra HDA support */
@@ -99,19 +99,6 @@ static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
snd_dma_free_pages(buf);
}
-static int substream_alloc_pages(struct azx *chip,
- struct snd_pcm_substream *substream,
- size_t size)
-{
- return snd_pcm_lib_malloc_pages(substream, size);
-}
-
-static int substream_free_pages(struct azx *chip,
- struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
/*
* Register access ops. Tegra HDA register access is DWORD only.
*/
@@ -180,10 +167,7 @@ static const struct hdac_io_ops hda_tegra_io_ops = {
.dma_free_pages = dma_free_pages,
};
-static const struct hda_controller_ops hda_tegra_ops = {
- .substream_alloc_pages = substream_alloc_pages,
- .substream_free_pages = substream_free_pages,
-};
+static const struct hda_controller_ops hda_tegra_ops; /* nothing special */
static void hda_tegra_init(struct hda_tegra *hda)
{
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index fd476fb40e1b..ebfd0be885b3 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -24,7 +24,7 @@
#include <linux/module.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index c2d9ee9cfdc0..21d0f0610913 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -22,7 +22,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 0166a3d7cd55..0a24037184c3 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -31,8 +31,9 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/pci.h>
+#include <asm/io.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
@@ -81,12 +82,12 @@
#define SCP_GET 1
#define EFX_FILE "ctefx.bin"
-#define SBZ_EFX_FILE "ctefx-sbz.bin"
+#define DESKTOP_EFX_FILE "ctefx-desktop.bin"
#define R3DI_EFX_FILE "ctefx-r3di.bin"
#ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP
MODULE_FIRMWARE(EFX_FILE);
-MODULE_FIRMWARE(SBZ_EFX_FILE);
+MODULE_FIRMWARE(DESKTOP_EFX_FILE);
MODULE_FIRMWARE(R3DI_EFX_FILE);
#endif
@@ -152,7 +153,10 @@ enum {
XBASS_XOVER,
EQ_PRESET_ENUM,
SMART_VOLUME_ENUM,
- MIC_BOOST_ENUM
+ MIC_BOOST_ENUM,
+ AE5_HEADPHONE_GAIN_ENUM,
+ AE5_SOUND_FILTER_ENUM,
+ ZXR_HEADPHONE_GAIN
#define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID)
};
@@ -666,6 +670,65 @@ static const struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = {
}
};
+/* Values for ca0113_mmio_command_set for selecting output. */
+#define AE5_CA0113_OUT_SET_COMMANDS 6
+struct ae5_ca0113_output_set {
+ unsigned int group[AE5_CA0113_OUT_SET_COMMANDS];
+ unsigned int target[AE5_CA0113_OUT_SET_COMMANDS];
+ unsigned int vals[AE5_CA0113_OUT_SET_COMMANDS];
+};
+
+static const struct ae5_ca0113_output_set ae5_ca0113_output_presets[] = {
+ { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+ .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+ .vals = { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f }
+ },
+ { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+ .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+ .vals = { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 }
+ },
+ { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+ .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+ .vals = { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f }
+ }
+};
+
+/* ae5 ca0113 command sequences to set headphone gain levels. */
+#define AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS 4
+struct ae5_headphone_gain_set {
+ char *name;
+ unsigned int vals[AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS];
+};
+
+static const struct ae5_headphone_gain_set ae5_headphone_gain_presets[] = {
+ { .name = "Low (16-31",
+ .vals = { 0xff, 0x2c, 0xf5, 0x32 }
+ },
+ { .name = "Medium (32-149",
+ .vals = { 0x38, 0xa8, 0x3e, 0x4c }
+ },
+ { .name = "High (150-600",
+ .vals = { 0xff, 0xff, 0xff, 0x7f }
+ }
+};
+
+struct ae5_filter_set {
+ char *name;
+ unsigned int val;
+};
+
+static const struct ae5_filter_set ae5_filter_presets[] = {
+ { .name = "Slow Roll Off",
+ .val = 0xa0
+ },
+ { .name = "Minimum Phase",
+ .val = 0xc0
+ },
+ { .name = "Fast Roll Off",
+ .val = 0x80
+ }
+};
+
enum hda_cmd_vendor_io {
/* for DspIO node */
VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000,
@@ -685,6 +748,9 @@ enum hda_cmd_vendor_io {
VENDOR_CHIPIO_DATA_LOW = 0x300,
VENDOR_CHIPIO_DATA_HIGH = 0x400,
+ VENDOR_CHIPIO_8051_WRITE_DIRECT = 0x500,
+ VENDOR_CHIPIO_8051_READ_DIRECT = 0xD00,
+
VENDOR_CHIPIO_GET_PARAMETER = 0xF00,
VENDOR_CHIPIO_STATUS = 0xF01,
VENDOR_CHIPIO_HIC_POST_READ = 0x702,
@@ -692,6 +758,9 @@ enum hda_cmd_vendor_io {
VENDOR_CHIPIO_8051_DATA_WRITE = 0x707,
VENDOR_CHIPIO_8051_DATA_READ = 0xF07,
+ VENDOR_CHIPIO_8051_PMEM_READ = 0xF08,
+ VENDOR_CHIPIO_8051_IRAM_WRITE = 0x709,
+ VENDOR_CHIPIO_8051_IRAM_READ = 0xF09,
VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE = 0x70A,
VENDOR_CHIPIO_CT_EXTENSIONS_GET = 0xF0A,
@@ -798,6 +867,12 @@ enum control_param_id {
* impedance is selected*/
CONTROL_PARAM_PORTD_160OHM_GAIN = 10,
+ /*
+ * This control param name was found in the 8051 memory, and makes
+ * sense given the fact the AE-5 uses it and has the ASI flag set.
+ */
+ CONTROL_PARAM_ASI = 23,
+
/* Stream Control */
/* Select stream with the given ID */
@@ -955,7 +1030,11 @@ struct ca0132_spec {
long eq_preset_val;
unsigned int tlv[4];
struct hda_vmaster_mute_hook vmaster_mute;
-
+ /* AE-5 Control values */
+ unsigned char ae5_headphone_gain_val;
+ unsigned char ae5_filter_val;
+ /* ZxR Control Values */
+ unsigned char zxr_gain_set;
struct hda_codec *codec;
struct delayed_work unsol_hp_work;
@@ -995,8 +1074,11 @@ enum {
QUIRK_ALIENWARE,
QUIRK_ALIENWARE_M17XR4,
QUIRK_SBZ,
+ QUIRK_ZXR,
+ QUIRK_ZXR_DBPRO,
QUIRK_R3DI,
QUIRK_R3D,
+ QUIRK_AE5,
};
static const struct hda_pintbl alienware_pincfgs[] = {
@@ -1028,6 +1110,21 @@ static const struct hda_pintbl sbz_pincfgs[] = {
{}
};
+/* Sound Blaster ZxR pin configs taken from Windows Driver */
+static const struct hda_pintbl zxr_pincfgs[] = {
+ { 0x0b, 0x01047110 }, /* Port G -- Lineout FRONT L/R */
+ { 0x0c, 0x414510f0 }, /* SPDIF Out 1 - Disabled*/
+ { 0x0d, 0x014510f0 }, /* Digital Out */
+ { 0x0e, 0x41c520f0 }, /* SPDIF In - Disabled*/
+ { 0x0f, 0x0122711f }, /* Port A -- BackPanel HP */
+ { 0x10, 0x01017111 }, /* Port D -- Center/LFE */
+ { 0x11, 0x01017114 }, /* Port B -- LineMicIn2 / Rear L/R */
+ { 0x12, 0x01a271f0 }, /* Port C -- LineIn1 */
+ { 0x13, 0x908700f0 }, /* What U Hear In*/
+ { 0x18, 0x50d000f0 }, /* N/A */
+ {}
+};
+
/* Recon3D pin configs taken from Windows Driver */
static const struct hda_pintbl r3d_pincfgs[] = {
{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
@@ -1043,6 +1140,21 @@ static const struct hda_pintbl r3d_pincfgs[] = {
{}
};
+/* Sound Blaster AE-5 pin configs taken from Windows Driver */
+static const struct hda_pintbl ae5_pincfgs[] = {
+ { 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
+ { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
+ { 0x0d, 0x014510f0 }, /* Digital Out */
+ { 0x0e, 0x01c510f0 }, /* SPDIF In */
+ { 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */
+ { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
+ { 0x11, 0x01a170ff }, /* Port B -- LineMicIn2 / Rear Headphone */
+ { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
+ { 0x13, 0x908700f0 }, /* What U Hear In*/
+ { 0x18, 0x50d000f0 }, /* N/A */
+ {}
+};
+
/* Recon3D integrated pin configs taken from Windows Driver */
static const struct hda_pintbl r3di_pincfgs[] = {
{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
@@ -1069,6 +1181,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
+ SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5),
{}
};
@@ -1454,6 +1567,20 @@ static void chipio_set_conn_rate(struct hda_codec *codec,
}
/*
+ * Writes to the 8051's internal address space directly instead of indirectly,
+ * giving access to the special function registers located at addresses
+ * 0x80-0xFF.
+ */
+static void chipio_8051_write_direct(struct hda_codec *codec,
+ unsigned int addr, unsigned int data)
+{
+ unsigned int verb;
+
+ verb = VENDOR_CHIPIO_8051_WRITE_DIRECT | data;
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, verb, addr);
+}
+
+/*
* Enable clocks.
*/
static void chipio_enable_clocks(struct hda_codec *codec)
@@ -3088,7 +3215,9 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
}
/*
- * Setup GPIO for the other variants of Core3D.
+ * ca0113 related functions. The ca0113 acts as the HDA bus for the pci-e
+ * based cards, and has a second mmio region, region2, that's used for special
+ * commands.
*/
/*
@@ -3096,8 +3225,11 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
* the mmio address 0x320 is used to set GPIO pins. The format for the data
* The first eight bits are just the number of the pin. So far, I've only seen
* this number go to 7.
+ * AE-5 note: The AE-5 seems to use pins 2 and 3 to somehow set the color value
+ * of the on-card LED. It seems to use pin 2 for data, then toggles 3 to on and
+ * then off to send that bit.
*/
-static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
+static void ca0113_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
bool enable)
{
struct ca0132_spec *spec = codec->spec;
@@ -3110,6 +3242,89 @@ static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
}
/*
+ * Special pci region2 commands that are only used by the AE-5. They follow
+ * a set format, and require reads at certain points to seemingly 'clear'
+ * the response data. My first tests didn't do these reads, and would cause
+ * the card to get locked up until the memory was read. These commands
+ * seem to work with three distinct values that I've taken to calling group,
+ * target-id, and value.
+ */
+static void ca0113_mmio_command_set(struct hda_codec *codec, unsigned int group,
+ unsigned int target, unsigned int value)
+{
+ struct ca0132_spec *spec = codec->spec;
+ unsigned int write_val;
+
+ writel(0x0000007e, spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+ writel(0x0000005a, spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+
+ writel(0x00800005, spec->mem_base + 0x20c);
+ writel(group, spec->mem_base + 0x804);
+
+ writel(0x00800005, spec->mem_base + 0x20c);
+ write_val = (target & 0xff);
+ write_val |= (value << 8);
+
+
+ writel(write_val, spec->mem_base + 0x204);
+ /*
+ * Need delay here or else it goes too fast and works inconsistently.
+ */
+ msleep(20);
+
+ readl(spec->mem_base + 0x860);
+ readl(spec->mem_base + 0x854);
+ readl(spec->mem_base + 0x840);
+
+ writel(0x00800004, spec->mem_base + 0x20c);
+ writel(0x00000000, spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+}
+
+/*
+ * This second type of command is used for setting the sound filter type.
+ */
+static void ca0113_mmio_command_set_type2(struct hda_codec *codec,
+ unsigned int group, unsigned int target, unsigned int value)
+{
+ struct ca0132_spec *spec = codec->spec;
+ unsigned int write_val;
+
+ writel(0x0000007e, spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+ writel(0x0000005a, spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+
+ writel(0x00800003, spec->mem_base + 0x20c);
+ writel(group, spec->mem_base + 0x804);
+
+ writel(0x00800005, spec->mem_base + 0x20c);
+ write_val = (target & 0xff);
+ write_val |= (value << 8);
+
+
+ writel(write_val, spec->mem_base + 0x204);
+ msleep(20);
+ readl(spec->mem_base + 0x860);
+ readl(spec->mem_base + 0x854);
+ readl(spec->mem_base + 0x840);
+
+ writel(0x00800004, spec->mem_base + 0x20c);
+ writel(0x00000000, spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+ readl(spec->mem_base + 0x210);
+}
+
+/*
+ * Setup GPIO for the other variants of Core3D.
+ */
+
+/*
* Sets up the GPIO pins so that they are discoverable. If this isn't done,
* the card shows as having no GPIO pins.
*/
@@ -3119,6 +3334,7 @@ static void ca0132_gpio_init(struct hda_codec *codec)
switch (spec->quirk) {
case QUIRK_SBZ:
+ case QUIRK_AE5:
snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23);
@@ -3928,6 +4144,138 @@ exit:
return err < 0 ? err : 0;
}
+static int ae5_headphone_gain_set(struct hda_codec *codec, long val);
+static int zxr_headphone_gain_set(struct hda_codec *codec, long val);
+static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
+
+static void ae5_mmio_select_out(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+ unsigned int i;
+
+ for (i = 0; i < AE5_CA0113_OUT_SET_COMMANDS; i++)
+ ca0113_mmio_command_set(codec,
+ ae5_ca0113_output_presets[spec->cur_out_type].group[i],
+ ae5_ca0113_output_presets[spec->cur_out_type].target[i],
+ ae5_ca0113_output_presets[spec->cur_out_type].vals[i]);
+}
+
+/*
+ * These are the commands needed to setup output on each of the different card
+ * types.
+ */
+static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+ unsigned int tmp;
+
+ switch (spec->cur_out_type) {
+ case SPEAKER_OUT:
+ switch (spec->quirk) {
+ case QUIRK_SBZ:
+ ca0113_mmio_gpio_set(codec, 7, false);
+ ca0113_mmio_gpio_set(codec, 4, true);
+ ca0113_mmio_gpio_set(codec, 1, true);
+ chipio_set_control_param(codec, 0x0d, 0x18);
+ break;
+ case QUIRK_ZXR:
+ ca0113_mmio_gpio_set(codec, 2, true);
+ ca0113_mmio_gpio_set(codec, 3, true);
+ ca0113_mmio_gpio_set(codec, 5, false);
+ zxr_headphone_gain_set(codec, 0);
+ chipio_set_control_param(codec, 0x0d, 0x24);
+ break;
+ case QUIRK_R3DI:
+ chipio_set_control_param(codec, 0x0d, 0x24);
+ r3di_gpio_out_set(codec, R3DI_LINE_OUT);
+ break;
+ case QUIRK_R3D:
+ chipio_set_control_param(codec, 0x0d, 0x24);
+ ca0113_mmio_gpio_set(codec, 1, true);
+ break;
+ case QUIRK_AE5:
+ ae5_mmio_select_out(codec);
+ ae5_headphone_gain_set(codec, 2);
+ tmp = FLOAT_ZERO;
+ dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+ dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+ chipio_set_control_param(codec, 0x0d, 0xa4);
+ chipio_write(codec, 0x18b03c, 0x00000012);
+ break;
+ }
+ break;
+ case HEADPHONE_OUT:
+ switch (spec->quirk) {
+ case QUIRK_SBZ:
+ ca0113_mmio_gpio_set(codec, 7, true);
+ ca0113_mmio_gpio_set(codec, 4, true);
+ ca0113_mmio_gpio_set(codec, 1, false);
+ chipio_set_control_param(codec, 0x0d, 0x12);
+ break;
+ case QUIRK_ZXR:
+ ca0113_mmio_gpio_set(codec, 2, false);
+ ca0113_mmio_gpio_set(codec, 3, false);
+ ca0113_mmio_gpio_set(codec, 5, true);
+ zxr_headphone_gain_set(codec, spec->zxr_gain_set);
+ chipio_set_control_param(codec, 0x0d, 0x21);
+ break;
+ case QUIRK_R3DI:
+ chipio_set_control_param(codec, 0x0d, 0x21);
+ r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT);
+ break;
+ case QUIRK_R3D:
+ chipio_set_control_param(codec, 0x0d, 0x21);
+ ca0113_mmio_gpio_set(codec, 0x1, false);
+ break;
+ case QUIRK_AE5:
+ ae5_mmio_select_out(codec);
+ ae5_headphone_gain_set(codec,
+ spec->ae5_headphone_gain_val);
+ tmp = FLOAT_ONE;
+ dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+ dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+ chipio_set_control_param(codec, 0x0d, 0xa1);
+ chipio_write(codec, 0x18b03c, 0x00000012);
+ break;
+ }
+ break;
+ case SURROUND_OUT:
+ switch (spec->quirk) {
+ case QUIRK_SBZ:
+ ca0113_mmio_gpio_set(codec, 7, false);
+ ca0113_mmio_gpio_set(codec, 4, true);
+ ca0113_mmio_gpio_set(codec, 1, true);
+ chipio_set_control_param(codec, 0x0d, 0x18);
+ break;
+ case QUIRK_ZXR:
+ ca0113_mmio_gpio_set(codec, 2, true);
+ ca0113_mmio_gpio_set(codec, 3, true);
+ ca0113_mmio_gpio_set(codec, 5, false);
+ zxr_headphone_gain_set(codec, 0);
+ chipio_set_control_param(codec, 0x0d, 0x24);
+ break;
+ case QUIRK_R3DI:
+ chipio_set_control_param(codec, 0x0d, 0x24);
+ r3di_gpio_out_set(codec, R3DI_LINE_OUT);
+ break;
+ case QUIRK_R3D:
+ ca0113_mmio_gpio_set(codec, 1, true);
+ chipio_set_control_param(codec, 0x0d, 0x24);
+ break;
+ case QUIRK_AE5:
+ ae5_mmio_select_out(codec);
+ ae5_headphone_gain_set(codec, 2);
+ tmp = FLOAT_ZERO;
+ dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+ dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+ chipio_set_control_param(codec, 0x0d, 0xa4);
+ chipio_write(codec, 0x18b03c, 0x00000012);
+ break;
+ }
+ break;
+ }
+}
+
/*
* This function behaves similarly to the ca0132_select_out funciton above,
* except with a few differences. It adds the ability to select the current
@@ -3978,26 +4326,11 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
if (err < 0)
goto exit;
+ ca0132_alt_select_out_quirk_handler(codec);
+
switch (spec->cur_out_type) {
case SPEAKER_OUT:
codec_dbg(codec, "%s speaker\n", __func__);
- /*speaker out config*/
- switch (spec->quirk) {
- case QUIRK_SBZ:
- ca0132_mmio_gpio_set(codec, 7, false);
- ca0132_mmio_gpio_set(codec, 4, true);
- ca0132_mmio_gpio_set(codec, 1, true);
- chipio_set_control_param(codec, 0x0D, 0x18);
- break;
- case QUIRK_R3DI:
- chipio_set_control_param(codec, 0x0D, 0x24);
- r3di_gpio_out_set(codec, R3DI_LINE_OUT);
- break;
- case QUIRK_R3D:
- chipio_set_control_param(codec, 0x0D, 0x24);
- ca0132_mmio_gpio_set(codec, 1, true);
- break;
- }
/* disable headphone node */
pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
@@ -4021,23 +4354,6 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
break;
case HEADPHONE_OUT:
codec_dbg(codec, "%s hp\n", __func__);
- /* Headphone out config*/
- switch (spec->quirk) {
- case QUIRK_SBZ:
- ca0132_mmio_gpio_set(codec, 7, true);
- ca0132_mmio_gpio_set(codec, 4, true);
- ca0132_mmio_gpio_set(codec, 1, false);
- chipio_set_control_param(codec, 0x0D, 0x12);
- break;
- case QUIRK_R3DI:
- chipio_set_control_param(codec, 0x0D, 0x21);
- r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT);
- break;
- case QUIRK_R3D:
- chipio_set_control_param(codec, 0x0D, 0x21);
- ca0132_mmio_gpio_set(codec, 0x1, false);
- break;
- }
snd_hda_codec_write(codec, spec->out_pins[0], 0,
AC_VERB_SET_EAPD_BTLENABLE, 0x00);
@@ -4067,23 +4383,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
break;
case SURROUND_OUT:
codec_dbg(codec, "%s surround\n", __func__);
- /* Surround out config*/
- switch (spec->quirk) {
- case QUIRK_SBZ:
- ca0132_mmio_gpio_set(codec, 7, false);
- ca0132_mmio_gpio_set(codec, 4, true);
- ca0132_mmio_gpio_set(codec, 1, true);
- chipio_set_control_param(codec, 0x0D, 0x18);
- break;
- case QUIRK_R3DI:
- chipio_set_control_param(codec, 0x0D, 0x24);
- r3di_gpio_out_set(codec, R3DI_LINE_OUT);
- break;
- case QUIRK_R3D:
- ca0132_mmio_gpio_set(codec, 1, true);
- chipio_set_control_param(codec, 0x0D, 0x24);
- break;
- }
+
/* enable line out node */
pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -4108,14 +4408,21 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
snd_hda_set_pin_ctl(codec, spec->out_pins[3],
pin_ctl | PIN_OUT);
- if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
- dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE);
- else
- dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT);
+ dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT);
break;
}
+ /*
+ * Surround always sets it's scp command to req 0x04 to FLOAT_EIGHT.
+ * With this set though, X_BASS cannot be enabled. So, if we have OutFX
+ * enabled, we need to make sure X_BASS is off, otherwise everything
+ * sounds all muffled. Running ca0132_effects_set with X_BASS as the
+ * effect should sort this out.
+ */
+ if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
+ ca0132_effects_set(codec, X_BASS,
+ spec->effects_switch[X_BASS - EFFECT_START_NID]);
- /* run through the output dsp commands for line-out */
+ /* run through the output dsp commands for the selected output. */
for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) {
err = dspio_set_uint_param(codec,
alt_out_presets[spec->cur_out_type].mids[i],
@@ -4152,7 +4459,6 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work)
static void ca0132_set_dmic(struct hda_codec *codec, int enable);
static int ca0132_mic_boost_set(struct hda_codec *codec, long val);
-static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
static void resume_mic1(struct hda_codec *codec, unsigned int oldval);
static int stop_mic1(struct hda_codec *codec);
static int ca0132_cvoice_switch_set(struct hda_codec *codec);
@@ -4341,13 +4647,20 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
switch (spec->quirk) {
case QUIRK_SBZ:
case QUIRK_R3D:
- ca0132_mmio_gpio_set(codec, 0, false);
+ ca0113_mmio_gpio_set(codec, 0, false);
+ tmp = FLOAT_THREE;
+ break;
+ case QUIRK_ZXR:
tmp = FLOAT_THREE;
break;
case QUIRK_R3DI:
r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
tmp = FLOAT_ONE;
break;
+ case QUIRK_AE5:
+ ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00);
+ tmp = FLOAT_THREE;
+ break;
default:
tmp = FLOAT_ONE;
break;
@@ -4362,10 +4675,19 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
chipio_set_stream_control(codec, 0x03, 1);
chipio_set_stream_control(codec, 0x04, 1);
-
- if (spec->quirk == QUIRK_SBZ) {
+ switch (spec->quirk) {
+ case QUIRK_SBZ:
chipio_write(codec, 0x18B098, 0x0000000C);
chipio_write(codec, 0x18B09C, 0x0000000C);
+ break;
+ case QUIRK_ZXR:
+ chipio_write(codec, 0x18B098, 0x0000000C);
+ chipio_write(codec, 0x18B09C, 0x000000CC);
+ break;
+ case QUIRK_AE5:
+ chipio_write(codec, 0x18B098, 0x0000000C);
+ chipio_write(codec, 0x18B09C, 0x0000004C);
+ break;
}
ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
break;
@@ -4374,11 +4696,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
switch (spec->quirk) {
case QUIRK_SBZ:
case QUIRK_R3D:
- ca0132_mmio_gpio_set(codec, 0, false);
+ ca0113_mmio_gpio_set(codec, 0, false);
break;
case QUIRK_R3DI:
r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
break;
+ case QUIRK_AE5:
+ ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00);
+ break;
}
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
@@ -4389,11 +4714,13 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
tmp = FLOAT_ZERO;
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
- if (spec->quirk == QUIRK_SBZ) {
+ switch (spec->quirk) {
+ case QUIRK_SBZ:
+ case QUIRK_AE5:
chipio_write(codec, 0x18B098, 0x00000000);
chipio_write(codec, 0x18B09C, 0x00000000);
+ break;
}
-
chipio_set_stream_control(codec, 0x03, 1);
chipio_set_stream_control(codec, 0x04, 1);
break;
@@ -4401,14 +4728,18 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
switch (spec->quirk) {
case QUIRK_SBZ:
case QUIRK_R3D:
- ca0132_mmio_gpio_set(codec, 0, true);
- ca0132_mmio_gpio_set(codec, 5, false);
+ ca0113_mmio_gpio_set(codec, 0, true);
+ ca0113_mmio_gpio_set(codec, 5, false);
tmp = FLOAT_THREE;
break;
case QUIRK_R3DI:
r3di_gpio_mic_set(codec, R3DI_FRONT_MIC);
tmp = FLOAT_ONE;
break;
+ case QUIRK_AE5:
+ ca0113_mmio_command_set(codec, 0x48, 0x28, 0x3f);
+ tmp = FLOAT_THREE;
+ break;
default:
tmp = FLOAT_ONE;
break;
@@ -4424,9 +4755,15 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
chipio_set_stream_control(codec, 0x03, 1);
chipio_set_stream_control(codec, 0x04, 1);
- if (spec->quirk == QUIRK_SBZ) {
+ switch (spec->quirk) {
+ case QUIRK_SBZ:
chipio_write(codec, 0x18B098, 0x0000000C);
chipio_write(codec, 0x18B09C, 0x000000CC);
+ break;
+ case QUIRK_AE5:
+ chipio_write(codec, 0x18B098, 0x0000000C);
+ chipio_write(codec, 0x18B09C, 0x0000004C);
+ break;
}
ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
break;
@@ -4435,7 +4772,6 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
snd_hda_power_down_pm(codec);
return 0;
-
}
/*
@@ -4507,6 +4843,8 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
/* if PE if off, turn off out effects. */
if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
val = 0;
+ if (spec->cur_out_type == SURROUND_OUT && nid == X_BASS)
+ val = 0;
}
/* for in effect, qualify with CrystalVoice */
@@ -4520,7 +4858,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
val = 0;
/* If Voice Focus on SBZ, set to two channel. */
- if ((nid == VOICE_FOCUS) && (spec->quirk == QUIRK_SBZ)
+ if ((nid == VOICE_FOCUS) && (spec->use_pci_mmio)
&& (spec->cur_mic_type != REAR_LINE_IN)) {
if (spec->effects_switch[CRYSTAL_VOICE -
EFFECT_START_NID]) {
@@ -4539,7 +4877,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
* For SBZ noise reduction, there's an extra command
* to module ID 0x47. No clue why.
*/
- if ((nid == NOISE_REDUCTION) && (spec->quirk == QUIRK_SBZ)
+ if ((nid == NOISE_REDUCTION) && (spec->use_pci_mmio)
&& (spec->cur_mic_type != REAR_LINE_IN)) {
if (spec->effects_switch[CRYSTAL_VOICE -
EFFECT_START_NID]) {
@@ -4678,6 +5016,27 @@ static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val)
return ret;
}
+static int ae5_headphone_gain_set(struct hda_codec *codec, long val)
+{
+ unsigned int i;
+
+ for (i = 0; i < 4; i++)
+ ca0113_mmio_command_set(codec, 0x48, 0x11 + i,
+ ae5_headphone_gain_presets[val].vals[i]);
+ return 0;
+}
+
+/*
+ * gpio pin 1 is a relay that switches on/off, apparently setting the headphone
+ * amplifier to handle a 600 ohm load.
+ */
+static int zxr_headphone_gain_set(struct hda_codec *codec, long val)
+{
+ ca0113_mmio_gpio_set(codec, 1, val);
+
+ return 0;
+}
+
static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -4942,6 +5301,112 @@ static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol,
return 1;
}
+/*
+ * Sound BlasterX AE-5 Headphone Gain Controls.
+ */
+#define AE5_HEADPHONE_GAIN_MAX 3
+static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ char *sfx = " Ohms)";
+ char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX;
+ if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX)
+ uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1;
+ sprintf(namestr, "%s %s",
+ ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
+ sfx);
+ strcpy(uinfo->value.enumerated.name, namestr);
+ return 0;
+}
+
+static int ae5_headphone_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ca0132_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->ae5_headphone_gain_val;
+ return 0;
+}
+
+static int ae5_headphone_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ca0132_spec *spec = codec->spec;
+ int sel = ucontrol->value.enumerated.item[0];
+ unsigned int items = AE5_HEADPHONE_GAIN_MAX;
+
+ if (sel >= items)
+ return 0;
+
+ codec_dbg(codec, "ae5_headphone_gain: boost=%d\n",
+ sel);
+
+ spec->ae5_headphone_gain_val = sel;
+
+ if (spec->out_enum_val == HEADPHONE_OUT)
+ ae5_headphone_gain_set(codec, spec->ae5_headphone_gain_val);
+
+ return 1;
+}
+
+/*
+ * Sound BlasterX AE-5 sound filter enumerated control.
+ */
+#define AE5_SOUND_FILTER_MAX 3
+
+static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX;
+ if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX)
+ uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1;
+ sprintf(namestr, "%s",
+ ae5_filter_presets[uinfo->value.enumerated.item].name);
+ strcpy(uinfo->value.enumerated.name, namestr);
+ return 0;
+}
+
+static int ae5_sound_filter_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ca0132_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->ae5_filter_val;
+ return 0;
+}
+
+static int ae5_sound_filter_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ca0132_spec *spec = codec->spec;
+ int sel = ucontrol->value.enumerated.item[0];
+ unsigned int items = AE5_SOUND_FILTER_MAX;
+
+ if (sel >= items)
+ return 0;
+
+ codec_dbg(codec, "ae5_sound_filter: %s\n",
+ ae5_filter_presets[sel].name);
+
+ spec->ae5_filter_val = sel;
+
+ ca0113_mmio_command_set_type2(codec, 0x48, 0x07,
+ ae5_filter_presets[sel].val);
+
+ return 1;
+}
/*
* Input Select Control for alternative ca0132 codecs. This exists because
@@ -5330,6 +5795,16 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
goto exit;
}
+ if (nid == ZXR_HEADPHONE_GAIN) {
+ spec->zxr_gain_set = *valp;
+ if (spec->cur_out_type == HEADPHONE_OUT)
+ changed = zxr_headphone_gain_set(codec, *valp);
+ else
+ changed = 0;
+
+ goto exit;
+ }
+
exit:
snd_hda_power_down(codec);
return changed;
@@ -5705,6 +6180,50 @@ static int ca0132_alt_add_mic_boost_enum(struct hda_codec *codec)
}
/*
+ * Add headphone gain enumerated control for the AE-5. This switches between
+ * three modes, low, medium, and high. When non-headphone outputs are selected,
+ * it is automatically set to high. This is the same behavior as Windows.
+ */
+static int ae5_add_headphone_gain_enum(struct hda_codec *codec)
+{
+ struct snd_kcontrol_new knew =
+ HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain",
+ AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_OUTPUT);
+ knew.info = ae5_headphone_gain_info;
+ knew.get = ae5_headphone_gain_get;
+ knew.put = ae5_headphone_gain_put;
+ return snd_hda_ctl_add(codec, AE5_HEADPHONE_GAIN_ENUM,
+ snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Add sound filter enumerated control for the AE-5. This adds three different
+ * settings: Slow Roll Off, Minimum Phase, and Fast Roll Off. From what I've
+ * read into it, it changes the DAC's interpolation filter.
+ */
+static int ae5_add_sound_filter_enum(struct hda_codec *codec)
+{
+ struct snd_kcontrol_new knew =
+ HDA_CODEC_MUTE_MONO("AE-5: Sound Filter",
+ AE5_SOUND_FILTER_ENUM, 1, 0, HDA_OUTPUT);
+ knew.info = ae5_sound_filter_info;
+ knew.get = ae5_sound_filter_get;
+ knew.put = ae5_sound_filter_put;
+ return snd_hda_ctl_add(codec, AE5_SOUND_FILTER_ENUM,
+ snd_ctl_new1(&knew, codec));
+}
+
+static int zxr_add_headphone_gain_switch(struct hda_codec *codec)
+{
+ struct snd_kcontrol_new knew =
+ CA0132_CODEC_MUTE_MONO("ZxR: 600 Ohm Gain",
+ ZXR_HEADPHONE_GAIN, 1, HDA_OUTPUT);
+
+ return snd_hda_ctl_add(codec, ZXR_HEADPHONE_GAIN,
+ snd_ctl_new1(&knew, codec));
+}
+
+/*
* Need to create slave controls for the alternate codecs that have surround
* capabilities.
*/
@@ -5847,7 +6366,8 @@ static int ca0132_build_controls(struct hda_codec *codec)
NULL, ca0132_alt_slave_pfxs,
"Playback Switch",
true, &spec->vmaster_mute.sw_kctl);
-
+ if (err < 0)
+ return err;
}
/* Add in and out effects controls.
@@ -5855,8 +6375,8 @@ static int ca0132_build_controls(struct hda_codec *codec)
*/
num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
for (i = 0; i < num_fx; i++) {
- /* SBZ and R3D break if Echo Cancellation is used. */
- if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D) {
+ /* Desktop cards break if Echo Cancellation is used. */
+ if (spec->use_pci_mmio) {
if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
OUT_EFFECTS_COUNT))
continue;
@@ -5874,8 +6394,14 @@ static int ca0132_build_controls(struct hda_codec *codec)
* prefix, and change PlayEnhancement and CrystalVoice to match.
*/
if (spec->use_alt_controls) {
- ca0132_alt_add_svm_enum(codec);
- add_ca0132_alt_eq_presets(codec);
+ err = ca0132_alt_add_svm_enum(codec);
+ if (err < 0)
+ return err;
+
+ err = add_ca0132_alt_eq_presets(codec);
+ if (err < 0)
+ return err;
+
err = add_fx_switch(codec, PLAY_ENHANCEMENT,
"Enable OutFX", 0);
if (err < 0)
@@ -5912,7 +6438,9 @@ static int ca0132_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
}
- add_voicefx(codec);
+ err = add_voicefx(codec);
+ if (err < 0)
+ return err;
/*
* If the codec uses alt_functions, you need the enumerated controls
@@ -5920,9 +6448,36 @@ static int ca0132_build_controls(struct hda_codec *codec)
* setting control.
*/
if (spec->use_alt_functions) {
- ca0132_alt_add_output_enum(codec);
- ca0132_alt_add_input_enum(codec);
- ca0132_alt_add_mic_boost_enum(codec);
+ err = ca0132_alt_add_output_enum(codec);
+ if (err < 0)
+ return err;
+ err = ca0132_alt_add_mic_boost_enum(codec);
+ if (err < 0)
+ return err;
+ /*
+ * ZxR only has microphone input, there is no front panel
+ * header on the card, and aux-in is handled by the DBPro board.
+ */
+ if (spec->quirk != QUIRK_ZXR) {
+ err = ca0132_alt_add_input_enum(codec);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ if (spec->quirk == QUIRK_AE5) {
+ err = ae5_add_headphone_gain_enum(codec);
+ if (err < 0)
+ return err;
+ err = ae5_add_sound_filter_enum(codec);
+ if (err < 0)
+ return err;
+ }
+
+ if (spec->quirk == QUIRK_ZXR) {
+ err = zxr_add_headphone_gain_switch(codec);
+ if (err < 0)
+ return err;
}
#ifdef ENABLE_TUNING_CONTROLS
add_tuning_ctls(codec);
@@ -5955,6 +6510,27 @@ static int ca0132_build_controls(struct hda_codec *codec)
return 0;
}
+static int dbpro_build_controls(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+ int err = 0;
+
+ if (spec->dig_out) {
+ err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
+ spec->dig_out);
+ if (err < 0)
+ return err;
+ }
+
+ if (spec->dig_in) {
+ err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
/*
* PCM
*/
@@ -6058,6 +6634,40 @@ static int ca0132_build_pcms(struct hda_codec *codec)
return 0;
}
+static int dbpro_build_pcms(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+ struct hda_pcm *info;
+
+ info = snd_hda_codec_pcm_new(codec, "CA0132 Alt Analog");
+ if (!info)
+ return -ENOMEM;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
+
+
+ if (!spec->dig_out && !spec->dig_in)
+ return 0;
+
+ info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
+ if (!info)
+ return -ENOMEM;
+ info->pcm_type = HDA_PCM_TYPE_SPDIF;
+ if (spec->dig_out) {
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ ca0132_pcm_digital_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
+ }
+ if (spec->dig_in) {
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+ ca0132_pcm_digital_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
+ }
+
+ return 0;
+}
+
static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
{
if (pin) {
@@ -6238,69 +6848,48 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec)
}
/*
- * Recon3D r3d_setup_defaults sub functions.
+ * Creates a dummy stream to bind the output to. This seems to have to be done
+ * after changing the main outputs source and destination streams.
*/
-
-static void r3d_dsp_scp_startup(struct hda_codec *codec)
+static void ca0132_alt_create_dummy_stream(struct hda_codec *codec)
{
- unsigned int tmp;
-
- tmp = 0x00000000;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
-
- tmp = 0x00000001;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
-
- tmp = 0x00000004;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
- tmp = 0x00000005;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
- tmp = 0x00000000;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-}
+ struct ca0132_spec *spec = codec->spec;
+ unsigned int stream_format;
-static void r3d_dsp_initial_mic_setup(struct hda_codec *codec)
-{
- unsigned int tmp;
+ stream_format = snd_hdac_calc_stream_format(48000, 2,
+ SNDRV_PCM_FORMAT_S32_LE, 32, 0);
- /* Mic 1 Setup */
- chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
- chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
- /* This ConnPointID is unique to Recon3Di. Haven't seen it elsewhere */
- chipio_set_conn_rate(codec, 0x0F, SR_96_000);
- tmp = FLOAT_ONE;
- dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+ snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id,
+ 0, stream_format);
- /* Mic 2 Setup, even though it isn't connected on SBZ */
- chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
- chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
- chipio_set_conn_rate(codec, 0x0F, SR_96_000);
- tmp = FLOAT_ZERO;
- dspio_set_uint_param(codec, 0x80, 0x01, tmp);
+ snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
}
/*
- * Initialize Sound Blaster Z analog microphones.
+ * Initialize mic for non-chromebook ca0132 implementations.
*/
-static void sbz_init_analog_mics(struct hda_codec *codec)
+static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
{
+ struct ca0132_spec *spec = codec->spec;
unsigned int tmp;
/* Mic 1 Setup */
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
- tmp = FLOAT_THREE;
+ if (spec->quirk == QUIRK_R3DI) {
+ chipio_set_conn_rate(codec, 0x0F, SR_96_000);
+ tmp = FLOAT_ONE;
+ } else
+ tmp = FLOAT_THREE;
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
- /* Mic 2 Setup, even though it isn't connected on SBZ */
+ /* Mic 2 setup (not present on desktop cards) */
chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
+ if (spec->quirk == QUIRK_R3DI)
+ chipio_set_conn_rate(codec, 0x0F, SR_96_000);
tmp = FLOAT_ZERO;
dspio_set_uint_param(codec, 0x80, 0x01, tmp);
-
}
/*
@@ -6333,7 +6922,6 @@ static void sbz_connect_streams(struct hda_codec *codec)
codec_dbg(codec, "Connect Streams exited, mutex released.\n");
mutex_unlock(&spec->chipio_mutex);
-
}
/*
@@ -6360,19 +6948,29 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
chipio_set_stream_channels(codec, 0x0C, 6);
chipio_set_stream_control(codec, 0x0C, 1);
/* No clue what these control */
- chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0);
- chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1);
- chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2);
- chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3);
- chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4);
- chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5);
- chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6);
- chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7);
- chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8);
- chipio_write_no_mutex(codec, 0x190054, 0x0001edc9);
- chipio_write_no_mutex(codec, 0x190058, 0x0001eaca);
- chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb);
-
+ if (spec->quirk == QUIRK_SBZ) {
+ chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0);
+ chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1);
+ chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2);
+ chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3);
+ chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4);
+ chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5);
+ chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6);
+ chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7);
+ chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8);
+ chipio_write_no_mutex(codec, 0x190054, 0x0001edc9);
+ chipio_write_no_mutex(codec, 0x190058, 0x0001eaca);
+ chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb);
+ } else if (spec->quirk == QUIRK_ZXR) {
+ chipio_write_no_mutex(codec, 0x190038, 0x000140c2);
+ chipio_write_no_mutex(codec, 0x19003c, 0x000141c3);
+ chipio_write_no_mutex(codec, 0x190040, 0x000150c4);
+ chipio_write_no_mutex(codec, 0x190044, 0x000151c5);
+ chipio_write_no_mutex(codec, 0x190050, 0x000142c8);
+ chipio_write_no_mutex(codec, 0x190054, 0x000143c9);
+ chipio_write_no_mutex(codec, 0x190058, 0x000152ca);
+ chipio_write_no_mutex(codec, 0x19005c, 0x000153cb);
+ }
chipio_write_no_mutex(codec, 0x19042c, 0x00000001);
codec_dbg(codec, "Startup Data exited, mutex released.\n");
@@ -6380,35 +6978,56 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
}
/*
- * Sound Blaster Z uses these after DSP is loaded. Weird SCP commands
- * without a 0x20 source like normal.
+ * Custom DSP SCP commands where the src value is 0x00 instead of 0x20. This is
+ * done after the DSP is loaded.
*/
-static void sbz_dsp_scp_startup(struct hda_codec *codec)
+static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec)
{
- unsigned int tmp;
-
- tmp = 0x00000003;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
- tmp = 0x00000000;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
-
- tmp = 0x00000001;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
-
- tmp = 0x00000004;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
- tmp = 0x00000005;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
- tmp = 0x00000000;
- dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+ struct ca0132_spec *spec = codec->spec;
+ unsigned int tmp, i;
+ /*
+ * Gotta run these twice, or else mic works inconsistently. Not clear
+ * why this is, but multiple tests have confirmed it.
+ */
+ for (i = 0; i < 2; i++) {
+ switch (spec->quirk) {
+ case QUIRK_SBZ:
+ case QUIRK_AE5:
+ tmp = 0x00000003;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+ tmp = 0x00000000;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
+ tmp = 0x00000001;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
+ tmp = 0x00000004;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+ tmp = 0x00000005;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+ tmp = 0x00000000;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+ break;
+ case QUIRK_R3D:
+ case QUIRK_R3DI:
+ tmp = 0x00000000;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
+ tmp = 0x00000001;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
+ tmp = 0x00000004;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+ tmp = 0x00000005;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+ tmp = 0x00000000;
+ dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+ break;
+ }
+ msleep(100);
+ }
}
-static void sbz_dsp_initial_mic_setup(struct hda_codec *codec)
+static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
{
+ struct ca0132_spec *spec = codec->spec;
unsigned int tmp;
chipio_set_stream_control(codec, 0x03, 0);
@@ -6423,8 +7042,161 @@ static void sbz_dsp_initial_mic_setup(struct hda_codec *codec)
chipio_set_stream_control(codec, 0x03, 1);
chipio_set_stream_control(codec, 0x04, 1);
- chipio_write(codec, 0x18b098, 0x0000000c);
- chipio_write(codec, 0x18b09C, 0x0000000c);
+ switch (spec->quirk) {
+ case QUIRK_SBZ:
+ chipio_write(codec, 0x18b098, 0x0000000c);
+ chipio_write(codec, 0x18b09C, 0x0000000c);
+ break;
+ case QUIRK_AE5:
+ chipio_write(codec, 0x18b098, 0x0000000c);
+ chipio_write(codec, 0x18b09c, 0x0000004c);
+ break;
+ }
+}
+
+static void ae5_post_dsp_register_set(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ chipio_8051_write_direct(codec, 0x93, 0x10);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2);
+
+ writeb(0xff, spec->mem_base + 0x304);
+ writeb(0xff, spec->mem_base + 0x304);
+ writeb(0xff, spec->mem_base + 0x304);
+ writeb(0xff, spec->mem_base + 0x304);
+ writeb(0x00, spec->mem_base + 0x100);
+ writeb(0xff, spec->mem_base + 0x304);
+ writeb(0x00, spec->mem_base + 0x100);
+ writeb(0xff, spec->mem_base + 0x304);
+ writeb(0x00, spec->mem_base + 0x100);
+ writeb(0xff, spec->mem_base + 0x304);
+ writeb(0x00, spec->mem_base + 0x100);
+ writeb(0xff, spec->mem_base + 0x304);
+
+ ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x3f);
+ ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
+ ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+}
+
+static void ae5_post_dsp_param_setup(struct hda_codec *codec)
+{
+ /*
+ * Param3 in the 8051's memory is represented by the ascii string 'mch'
+ * which seems to be 'multichannel'. This is also mentioned in the
+ * AE-5's registry values in Windows.
+ */
+ chipio_set_control_param(codec, 3, 0);
+ /*
+ * I believe ASI is 'audio serial interface' and that it's used to
+ * change colors on the external LED strip connected to the AE-5.
+ */
+ chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1);
+
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83);
+ chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x92);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0xfa);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_DATA_WRITE, 0x22);
+}
+
+static void ae5_post_dsp_pll_setup(struct hda_codec *codec)
+{
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x41);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc8);
+
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x45);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcc);
+
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x40);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcb);
+
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7);
+
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x51);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PLL_PMU_WRITE, 0x8d);
+}
+
+static void ae5_post_dsp_stream_setup(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ mutex_lock(&spec->chipio_mutex);
+
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81);
+
+ chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000);
+
+ chipio_set_stream_channels(codec, 0x0C, 6);
+ chipio_set_stream_control(codec, 0x0C, 1);
+
+ chipio_set_stream_source_dest(codec, 0x5, 0x43, 0x0);
+
+ chipio_set_stream_source_dest(codec, 0x18, 0x9, 0xd0);
+ chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000);
+ chipio_set_stream_channels(codec, 0x18, 6);
+ chipio_set_stream_control(codec, 0x18, 1);
+
+ chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4);
+
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7);
+
+ ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80);
+
+ mutex_unlock(&spec->chipio_mutex);
+}
+
+static void ae5_post_dsp_startup_data(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ mutex_lock(&spec->chipio_mutex);
+
+ chipio_write_no_mutex(codec, 0x189000, 0x0001f101);
+ chipio_write_no_mutex(codec, 0x189004, 0x0001f101);
+ chipio_write_no_mutex(codec, 0x189024, 0x00014004);
+ chipio_write_no_mutex(codec, 0x189028, 0x0002000f);
+
+ ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
+ chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
+ ca0113_mmio_command_set(codec, 0x48, 0x0b, 0x12);
+ ca0113_mmio_command_set(codec, 0x48, 0x04, 0x00);
+ ca0113_mmio_command_set(codec, 0x48, 0x06, 0x48);
+ ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
+ ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+ ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+ ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+ ca0113_mmio_gpio_set(codec, 0, true);
+ ca0113_mmio_gpio_set(codec, 1, true);
+ ca0113_mmio_command_set(codec, 0x48, 0x07, 0x80);
+
+ chipio_write_no_mutex(codec, 0x18b03c, 0x00000012);
+
+ ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+ ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+
+ mutex_unlock(&spec->chipio_mutex);
}
/*
@@ -6485,9 +7257,8 @@ static void r3d_setup_defaults(struct hda_codec *codec)
if (spec->dsp_state != DSP_DOWNLOADED)
return;
- r3d_dsp_scp_startup(codec);
-
- r3d_dsp_initial_mic_setup(codec);
+ ca0132_alt_dsp_scp_startup(codec);
+ ca0132_alt_init_analog_mics(codec);
/*remove DSP headroom*/
tmp = FLOAT_ZERO;
@@ -6523,19 +7294,16 @@ static void r3d_setup_defaults(struct hda_codec *codec)
static void sbz_setup_defaults(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- unsigned int tmp, stream_format;
+ unsigned int tmp;
int num_fx;
int idx, i;
if (spec->dsp_state != DSP_DOWNLOADED)
return;
- sbz_dsp_scp_startup(codec);
-
- sbz_init_analog_mics(codec);
-
+ ca0132_alt_dsp_scp_startup(codec);
+ ca0132_alt_init_analog_mics(codec);
sbz_connect_streams(codec);
-
sbz_chipio_startup_data(codec);
chipio_set_stream_control(codec, 0x03, 1);
@@ -6561,8 +7329,7 @@ static void sbz_setup_defaults(struct hda_codec *codec)
/* Set speaker source? */
dspio_set_uint_param(codec, 0x32, 0x00, tmp);
- sbz_dsp_initial_mic_setup(codec);
-
+ ca0132_alt_dsp_initial_mic_setup(codec);
/* out, in effects + voicefx */
num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
@@ -6575,23 +7342,74 @@ static void sbz_setup_defaults(struct hda_codec *codec)
}
}
- /*
- * Have to make a stream to bind the sound output to, otherwise
- * you'll get dead audio. Before I did this, it would bind to an
- * audio input, and would never work
- */
- stream_format = snd_hdac_calc_stream_format(48000, 2,
- SNDRV_PCM_FORMAT_S32_LE, 32, 0);
+ ca0132_alt_create_dummy_stream(codec);
+}
- snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id,
- 0, stream_format);
+/*
+ * Setup default parameters for the Sound BlasterX AE-5 DSP.
+ */
+static void ae5_setup_defaults(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+ unsigned int tmp;
+ int num_fx;
+ int idx, i;
- snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
+ if (spec->dsp_state != DSP_DOWNLOADED)
+ return;
- snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id,
- 0, stream_format);
+ ca0132_alt_dsp_scp_startup(codec);
+ ca0132_alt_init_analog_mics(codec);
+ chipio_set_stream_control(codec, 0x03, 1);
+ chipio_set_stream_control(codec, 0x04, 1);
- snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
+ /* New, unknown SCP req's */
+ tmp = FLOAT_ZERO;
+ dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+ dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+ dspio_set_uint_param(codec, 0x80, 0x0d, tmp);
+ dspio_set_uint_param(codec, 0x80, 0x0e, tmp);
+
+ ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
+ ca0113_mmio_gpio_set(codec, 0, false);
+ ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
+
+ /* Internal loopback off */
+ tmp = FLOAT_ONE;
+ dspio_set_uint_param(codec, 0x37, 0x08, tmp);
+ dspio_set_uint_param(codec, 0x37, 0x10, tmp);
+
+ /*remove DSP headroom*/
+ tmp = FLOAT_ZERO;
+ dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
+
+ /* set WUH source */
+ tmp = FLOAT_TWO;
+ dspio_set_uint_param(codec, 0x31, 0x00, tmp);
+ chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
+
+ /* Set speaker source? */
+ dspio_set_uint_param(codec, 0x32, 0x00, tmp);
+
+ ca0132_alt_dsp_initial_mic_setup(codec);
+ ae5_post_dsp_register_set(codec);
+ ae5_post_dsp_param_setup(codec);
+ ae5_post_dsp_pll_setup(codec);
+ ae5_post_dsp_stream_setup(codec);
+ ae5_post_dsp_startup_data(codec);
+
+ /* out, in effects + voicefx */
+ num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
+ for (idx = 0; idx < num_fx; idx++) {
+ for (i = 0; i <= ca0132_effects[idx].params; i++) {
+ dspio_set_uint_param(codec,
+ ca0132_effects[idx].mid,
+ ca0132_effects[idx].reqs[i],
+ ca0132_effects[idx].def_vals[i]);
+ }
+ }
+
+ ca0132_alt_create_dummy_stream(codec);
}
/*
@@ -6673,12 +7491,14 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
*/
switch (spec->quirk) {
case QUIRK_SBZ:
- if (request_firmware(&fw_entry, SBZ_EFX_FILE,
+ case QUIRK_R3D:
+ case QUIRK_AE5:
+ if (request_firmware(&fw_entry, DESKTOP_EFX_FILE,
codec->card->dev) != 0) {
- codec_dbg(codec, "SBZ alt firmware not detected. ");
+ codec_dbg(codec, "Desktop firmware not found.");
spec->alt_firmware_present = false;
} else {
- codec_dbg(codec, "Sound Blaster Z firmware selected.");
+ codec_dbg(codec, "Desktop firmware selected.");
spec->alt_firmware_present = true;
}
break;
@@ -6921,6 +7741,14 @@ static void ca0132_init_chip(struct hda_codec *codec)
spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1;
spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0;
+ /*
+ * The ZxR doesn't have a front panel header, and it's line-in is on
+ * the daughter board. So, there is no input enum control, and we need
+ * to make sure that spec->in_enum_val is set properly.
+ */
+ if (spec->quirk == QUIRK_ZXR)
+ spec->in_enum_val = REAR_MIC;
+
#ifdef ENABLE_TUNING_CONTROLS
ca0132_init_tuning_defaults(codec);
#endif
@@ -6948,11 +7776,11 @@ static void sbz_region2_exit(struct hda_codec *codec)
for (i = 0; i < 8; i++)
writeb(0xb3, spec->mem_base + 0x304);
- ca0132_mmio_gpio_set(codec, 0, false);
- ca0132_mmio_gpio_set(codec, 1, false);
- ca0132_mmio_gpio_set(codec, 4, true);
- ca0132_mmio_gpio_set(codec, 5, false);
- ca0132_mmio_gpio_set(codec, 7, false);
+ ca0113_mmio_gpio_set(codec, 0, false);
+ ca0113_mmio_gpio_set(codec, 1, false);
+ ca0113_mmio_gpio_set(codec, 4, true);
+ ca0113_mmio_gpio_set(codec, 5, false);
+ ca0113_mmio_gpio_set(codec, 7, false);
}
static void sbz_set_pin_ctl_default(struct hda_codec *codec)
@@ -6995,6 +7823,16 @@ static void sbz_gpio_shutdown_commands(struct hda_codec *codec, int dir,
AC_VERB_SET_GPIO_DATA, data);
}
+static void zxr_dbpro_power_state_shutdown(struct hda_codec *codec)
+{
+ hda_nid_t pins[7] = {0x05, 0x0c, 0x09, 0x0e, 0x08, 0x11, 0x01};
+ unsigned int i;
+
+ for (i = 0; i < 7; i++)
+ snd_hda_codec_write(codec, pins[i], 0,
+ AC_VERB_SET_POWER_STATE, 0x03);
+}
+
static void sbz_exit_chip(struct hda_codec *codec)
{
chipio_set_stream_control(codec, 0x03, 0);
@@ -7037,6 +7875,61 @@ static void r3d_exit_chip(struct hda_codec *codec)
snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5b);
}
+static void ae5_exit_chip(struct hda_codec *codec)
+{
+ chipio_set_stream_control(codec, 0x03, 0);
+ chipio_set_stream_control(codec, 0x04, 0);
+
+ ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+ ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+ ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+ ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00);
+ ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
+ ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x00);
+ ca0113_mmio_gpio_set(codec, 0, false);
+ ca0113_mmio_gpio_set(codec, 1, false);
+
+ snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+ snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+
+ chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+
+ chipio_set_stream_control(codec, 0x18, 0);
+ chipio_set_stream_control(codec, 0x0c, 0);
+
+ snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83);
+}
+
+static void zxr_exit_chip(struct hda_codec *codec)
+{
+ chipio_set_stream_control(codec, 0x03, 0);
+ chipio_set_stream_control(codec, 0x04, 0);
+ chipio_set_stream_control(codec, 0x14, 0);
+ chipio_set_stream_control(codec, 0x0C, 0);
+
+ chipio_set_conn_rate(codec, 0x41, SR_192_000);
+ chipio_set_conn_rate(codec, 0x91, SR_192_000);
+
+ chipio_write(codec, 0x18a020, 0x00000083);
+
+ snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+ snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+
+ ca0132_clear_unsolicited(codec);
+ sbz_set_pin_ctl_default(codec);
+ snd_hda_codec_write(codec, 0x0B, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+
+ ca0113_mmio_gpio_set(codec, 5, false);
+ ca0113_mmio_gpio_set(codec, 2, false);
+ ca0113_mmio_gpio_set(codec, 3, false);
+ ca0113_mmio_gpio_set(codec, 0, false);
+ ca0113_mmio_gpio_set(codec, 4, true);
+ ca0113_mmio_gpio_set(codec, 0, true);
+ ca0113_mmio_gpio_set(codec, 5, true);
+ ca0113_mmio_gpio_set(codec, 2, false);
+ ca0113_mmio_gpio_set(codec, 3, false);
+}
+
static void ca0132_exit_chip(struct hda_codec *codec)
{
/* put any chip cleanup stuffs here. */
@@ -7140,11 +8033,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec)
writel(0x00820680, spec->mem_base + 0x01C);
writel(0x00820680, spec->mem_base + 0x01C);
- snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc);
- snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd);
- snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe);
- snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff);
-
chipio_write(codec, 0x18b0a4, 0x000000c2);
snd_hda_codec_write(codec, 0x11, 0,
@@ -7153,12 +8041,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec)
static void r3d_pre_dsp_setup(struct hda_codec *codec)
{
-
- snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc);
- snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd);
- snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe);
- snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff);
-
chipio_write(codec, 0x18b0a4, 0x000000c2);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
@@ -7205,23 +8087,116 @@ static void ca0132_mmio_init(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- writel(0x00000000, spec->mem_base + 0x400);
- writel(0x00000000, spec->mem_base + 0x408);
- writel(0x00000000, spec->mem_base + 0x40C);
- writel(0x00880680, spec->mem_base + 0x01C);
- writel(0x00000083, spec->mem_base + 0xC0C);
+ if (spec->quirk == QUIRK_AE5)
+ writel(0x00000001, spec->mem_base + 0x400);
+ else
+ writel(0x00000000, spec->mem_base + 0x400);
+
+ if (spec->quirk == QUIRK_AE5)
+ writel(0x00000001, spec->mem_base + 0x408);
+ else
+ writel(0x00000000, spec->mem_base + 0x408);
+
+ if (spec->quirk == QUIRK_AE5)
+ writel(0x00000001, spec->mem_base + 0x40c);
+ else
+ writel(0x00000000, spec->mem_base + 0x40C);
+
+ if (spec->quirk == QUIRK_ZXR)
+ writel(0x00880640, spec->mem_base + 0x01C);
+ else
+ writel(0x00880680, spec->mem_base + 0x01C);
+
+ if (spec->quirk == QUIRK_AE5)
+ writel(0x00000080, spec->mem_base + 0xC0C);
+ else
+ writel(0x00000083, spec->mem_base + 0xC0C);
+
writel(0x00000030, spec->mem_base + 0xC00);
writel(0x00000000, spec->mem_base + 0xC04);
+
+ if (spec->quirk == QUIRK_AE5)
+ writel(0x00000000, spec->mem_base + 0xC0C);
+ else
+ writel(0x00000003, spec->mem_base + 0xC0C);
+
writel(0x00000003, spec->mem_base + 0xC0C);
writel(0x00000003, spec->mem_base + 0xC0C);
writel(0x00000003, spec->mem_base + 0xC0C);
- writel(0x00000003, spec->mem_base + 0xC0C);
- writel(0x000000C1, spec->mem_base + 0xC08);
+
+ if (spec->quirk == QUIRK_AE5)
+ writel(0x00000001, spec->mem_base + 0xC08);
+ else
+ writel(0x000000C1, spec->mem_base + 0xC08);
+
writel(0x000000F1, spec->mem_base + 0xC08);
writel(0x00000001, spec->mem_base + 0xC08);
writel(0x000000C7, spec->mem_base + 0xC08);
writel(0x000000C1, spec->mem_base + 0xC08);
writel(0x00000080, spec->mem_base + 0xC04);
+
+ if (spec->quirk == QUIRK_AE5) {
+ writel(0x00000000, spec->mem_base + 0x42c);
+ writel(0x00000000, spec->mem_base + 0x46c);
+ writel(0x00000000, spec->mem_base + 0x4ac);
+ writel(0x00000000, spec->mem_base + 0x4ec);
+ writel(0x00000000, spec->mem_base + 0x43c);
+ writel(0x00000000, spec->mem_base + 0x47c);
+ writel(0x00000000, spec->mem_base + 0x4bc);
+ writel(0x00000000, spec->mem_base + 0x4fc);
+ writel(0x00000600, spec->mem_base + 0x100);
+ writel(0x00000014, spec->mem_base + 0x410);
+ writel(0x0000060f, spec->mem_base + 0x100);
+ writel(0x0000070f, spec->mem_base + 0x100);
+ writel(0x00000aff, spec->mem_base + 0x830);
+ writel(0x00000000, spec->mem_base + 0x86c);
+ writel(0x0000006b, spec->mem_base + 0x800);
+ writel(0x00000001, spec->mem_base + 0x86c);
+ writel(0x0000006b, spec->mem_base + 0x800);
+ writel(0x00000057, spec->mem_base + 0x804);
+ writel(0x00800000, spec->mem_base + 0x20c);
+ }
+}
+
+/*
+ * This function writes to some SFR's, does some region2 writes, and then
+ * eventually resets the codec with the 0x7ff verb. Not quite sure why it does
+ * what it does.
+ */
+static void ae5_register_set(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ chipio_8051_write_direct(codec, 0x93, 0x10);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2);
+
+ writeb(0x0f, spec->mem_base + 0x304);
+ writeb(0x0f, spec->mem_base + 0x304);
+ writeb(0x0f, spec->mem_base + 0x304);
+ writeb(0x0f, spec->mem_base + 0x304);
+ writeb(0x0e, spec->mem_base + 0x100);
+ writeb(0x1f, spec->mem_base + 0x304);
+ writeb(0x0c, spec->mem_base + 0x100);
+ writeb(0x3f, spec->mem_base + 0x304);
+ writeb(0x08, spec->mem_base + 0x100);
+ writeb(0x7f, spec->mem_base + 0x304);
+ writeb(0x00, spec->mem_base + 0x100);
+ writeb(0xff, spec->mem_base + 0x304);
+
+ ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
+
+ chipio_8051_write_direct(codec, 0x90, 0x00);
+ chipio_8051_write_direct(codec, 0x90, 0x10);
+
+ ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+
+ chipio_write(codec, 0x18b0a4, 0x000000c2);
+
+ snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00);
+ snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00);
}
/*
@@ -7257,6 +8232,21 @@ static void ca0132_alt_init(struct hda_codec *codec)
snd_hda_sequence_write(codec, spec->chip_init_verbs);
snd_hda_sequence_write(codec, spec->desktop_init_verbs);
break;
+ case QUIRK_AE5:
+ ca0132_gpio_init(codec);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x49);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_PLL_PMU_WRITE, 0x88);
+ chipio_write(codec, 0x18b030, 0x00000020);
+ snd_hda_sequence_write(codec, spec->chip_init_verbs);
+ snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+ ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+ break;
+ case QUIRK_ZXR:
+ snd_hda_sequence_write(codec, spec->chip_init_verbs);
+ snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+ break;
}
}
@@ -7298,6 +8288,9 @@ static int ca0132_init(struct hda_codec *codec)
snd_hda_power_up_pm(codec);
+ if (spec->quirk == QUIRK_AE5)
+ ae5_register_set(codec);
+
ca0132_init_unsol(codec);
ca0132_init_params(codec);
ca0132_init_flags(codec);
@@ -7317,8 +8310,12 @@ static int ca0132_init(struct hda_codec *codec)
r3d_setup_defaults(codec);
break;
case QUIRK_SBZ:
+ case QUIRK_ZXR:
sbz_setup_defaults(codec);
break;
+ case QUIRK_AE5:
+ ae5_setup_defaults(codec);
+ break;
default:
ca0132_setup_defaults(codec);
ca0132_init_analog_mic2(codec);
@@ -7372,6 +8369,21 @@ static int ca0132_init(struct hda_codec *codec)
return 0;
}
+static int dbpro_init(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ unsigned int i;
+
+ init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
+ init_input(codec, cfg->dig_in_pin, spec->dig_in);
+
+ for (i = 0; i < spec->num_inputs; i++)
+ init_input(codec, spec->input_pins[i], spec->adcs[i]);
+
+ return 0;
+}
+
static void ca0132_free(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
@@ -7382,9 +8394,15 @@ static void ca0132_free(struct hda_codec *codec)
case QUIRK_SBZ:
sbz_exit_chip(codec);
break;
+ case QUIRK_ZXR:
+ zxr_exit_chip(codec);
+ break;
case QUIRK_R3D:
r3d_exit_chip(codec);
break;
+ case QUIRK_AE5:
+ ae5_exit_chip(codec);
+ break;
case QUIRK_R3DI:
r3di_gpio_shutdown(codec);
break;
@@ -7400,6 +8418,16 @@ static void ca0132_free(struct hda_codec *codec)
kfree(codec->spec);
}
+static void dbpro_free(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ zxr_dbpro_power_state_shutdown(codec);
+
+ kfree(spec->spec_init_verbs);
+ kfree(codec->spec);
+}
+
static void ca0132_reboot_notify(struct hda_codec *codec)
{
codec->patch_ops.free(codec);
@@ -7414,6 +8442,13 @@ static const struct hda_codec_ops ca0132_patch_ops = {
.reboot_notify = ca0132_reboot_notify,
};
+static const struct hda_codec_ops dbpro_patch_ops = {
+ .build_controls = dbpro_build_controls,
+ .build_pcms = dbpro_build_pcms,
+ .init = dbpro_init,
+ .free = dbpro_free,
+};
+
static void ca0132_config(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
@@ -7432,9 +8467,33 @@ static void ca0132_config(struct hda_codec *codec)
switch (spec->quirk) {
case QUIRK_ALIENWARE:
- codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n");
+ codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__);
snd_hda_apply_pincfgs(codec, alienware_pincfgs);
+ break;
+ case QUIRK_SBZ:
+ codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
+ snd_hda_apply_pincfgs(codec, sbz_pincfgs);
+ break;
+ case QUIRK_ZXR:
+ codec_dbg(codec, "%s: QUIRK_ZXR applied.\n", __func__);
+ snd_hda_apply_pincfgs(codec, zxr_pincfgs);
+ break;
+ case QUIRK_R3D:
+ codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__);
+ snd_hda_apply_pincfgs(codec, r3d_pincfgs);
+ break;
+ case QUIRK_R3DI:
+ codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__);
+ snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+ break;
+ case QUIRK_AE5:
+ codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__);
+ snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+ break;
+ }
+ switch (spec->quirk) {
+ case QUIRK_ALIENWARE:
spec->num_outputs = 2;
spec->out_pins[0] = 0x0b; /* speaker out */
spec->out_pins[1] = 0x0f;
@@ -7454,15 +8513,6 @@ static void ca0132_config(struct hda_codec *codec)
break;
case QUIRK_SBZ:
case QUIRK_R3D:
- if (spec->quirk == QUIRK_SBZ) {
- codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
- snd_hda_apply_pincfgs(codec, sbz_pincfgs);
- }
- if (spec->quirk == QUIRK_R3D) {
- codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__);
- snd_hda_apply_pincfgs(codec, r3d_pincfgs);
- }
-
spec->num_outputs = 2;
spec->out_pins[0] = 0x0B; /* Line out */
spec->out_pins[1] = 0x0F; /* Rear headphone out */
@@ -7487,10 +8537,62 @@ static void ca0132_config(struct hda_codec *codec)
spec->multiout.dig_out_nid = spec->dig_out;
spec->dig_in = 0x09;
break;
- case QUIRK_R3DI:
- codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__);
- snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+ case QUIRK_ZXR:
+ spec->num_outputs = 2;
+ spec->out_pins[0] = 0x0B; /* Line out */
+ spec->out_pins[1] = 0x0F; /* Rear headphone out */
+ spec->out_pins[2] = 0x10; /* Center/LFE */
+ spec->out_pins[3] = 0x11; /* Rear surround */
+ spec->shared_out_nid = 0x2;
+ spec->unsol_tag_hp = spec->out_pins[1];
+ spec->unsol_tag_front_hp = spec->out_pins[2];
+ spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
+ spec->adcs[1] = 0x8; /* Not connected, no front mic */
+ spec->adcs[2] = 0xa; /* what u hear */
+
+ spec->num_inputs = 2;
+ spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+ spec->input_pins[1] = 0x13; /* What U Hear */
+ spec->shared_mic_nid = 0x7;
+ spec->unsol_tag_amic1 = spec->input_pins[0];
+ break;
+ case QUIRK_ZXR_DBPRO:
+ spec->adcs[0] = 0x8; /* ZxR DBPro Aux In */
+
+ spec->num_inputs = 1;
+ spec->input_pins[0] = 0x11; /* RCA Line-in */
+
+ spec->dig_out = 0x05;
+ spec->multiout.dig_out_nid = spec->dig_out;
+
+ spec->dig_in = 0x09;
+ break;
+ case QUIRK_AE5:
+ spec->num_outputs = 2;
+ spec->out_pins[0] = 0x0B; /* Line out */
+ spec->out_pins[1] = 0x11; /* Rear headphone out */
+ spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/
+ spec->out_pins[3] = 0x0F; /* Rear surround */
+ spec->shared_out_nid = 0x2;
+ spec->unsol_tag_hp = spec->out_pins[1];
+ spec->unsol_tag_front_hp = spec->out_pins[2];
+
+ spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
+ spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */
+ spec->adcs[2] = 0xa; /* what u hear */
+
+ spec->num_inputs = 2;
+ spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+ spec->input_pins[1] = 0x13; /* What U Hear */
+ spec->shared_mic_nid = 0x7;
+ spec->unsol_tag_amic1 = spec->input_pins[0];
+
+ /* SPDIF I/O */
+ spec->dig_out = 0x05;
+ spec->multiout.dig_out_nid = spec->dig_out;
+ break;
+ case QUIRK_R3DI:
spec->num_outputs = 2;
spec->out_pins[0] = 0x0B; /* Line out */
spec->out_pins[1] = 0x0F; /* Rear headphone out */
@@ -7547,7 +8649,11 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
struct ca0132_spec *spec = codec->spec;
spec->chip_init_verbs = ca0132_init_verbs0;
- if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D)
+ /*
+ * Since desktop cards use pci_mmio, this can be used to determine
+ * whether or not to use these verbs instead of a separate bool.
+ */
+ if (spec->use_pci_mmio)
spec->desktop_init_verbs = ca0132_init_verbs1;
spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
sizeof(struct hda_verb),
@@ -7579,6 +8685,29 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
return 0;
}
+/*
+ * The Sound Blaster ZxR shares the same PCI subsystem ID as some regular
+ * Sound Blaster Z cards. However, they have different HDA codec subsystem
+ * ID's. So, we check for the ZxR's subsystem ID, as well as the DBPro
+ * daughter boards ID.
+ */
+static void sbz_detect_quirk(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ switch (codec->core.subsystem_id) {
+ case 0x11020033:
+ spec->quirk = QUIRK_ZXR;
+ break;
+ case 0x1102003f:
+ spec->quirk = QUIRK_ZXR_DBPRO;
+ break;
+ default:
+ spec->quirk = QUIRK_SBZ;
+ break;
+ }
+}
+
static int patch_ca0132(struct hda_codec *codec)
{
struct ca0132_spec *spec;
@@ -7593,10 +8722,6 @@ static int patch_ca0132(struct hda_codec *codec)
codec->spec = spec;
spec->codec = codec;
- codec->patch_ops = ca0132_patch_ops;
- codec->pcm_format_first = 1;
- codec->no_sticky_stream = 1;
-
/* Detect codec quirk */
quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks);
if (quirk)
@@ -7604,6 +8729,18 @@ static int patch_ca0132(struct hda_codec *codec)
else
spec->quirk = QUIRK_NONE;
+ if (spec->quirk == QUIRK_SBZ)
+ sbz_detect_quirk(codec);
+
+ if (spec->quirk == QUIRK_ZXR_DBPRO)
+ codec->patch_ops = dbpro_patch_ops;
+ else
+ codec->patch_ops = ca0132_patch_ops;
+
+ codec->pcm_format_first = 1;
+ codec->no_sticky_stream = 1;
+
+
spec->dsp_state = DSP_DOWNLOAD_INIT;
spec->num_mixers = 1;
@@ -7613,6 +8750,12 @@ static int patch_ca0132(struct hda_codec *codec)
spec->mixers[0] = desktop_mixer;
snd_hda_codec_set_name(codec, "Sound Blaster Z");
break;
+ case QUIRK_ZXR:
+ spec->mixers[0] = desktop_mixer;
+ snd_hda_codec_set_name(codec, "Sound Blaster ZxR");
+ break;
+ case QUIRK_ZXR_DBPRO:
+ break;
case QUIRK_R3D:
spec->mixers[0] = desktop_mixer;
snd_hda_codec_set_name(codec, "Recon3D");
@@ -7621,6 +8764,10 @@ static int patch_ca0132(struct hda_codec *codec)
spec->mixers[0] = r3di_mixer;
snd_hda_codec_set_name(codec, "Recon3Di");
break;
+ case QUIRK_AE5:
+ spec->mixers[0] = desktop_mixer;
+ snd_hda_codec_set_name(codec, "Sound BlasterX AE-5");
+ break;
default:
spec->mixers[0] = ca0132_mixer;
break;
@@ -7630,6 +8777,8 @@ static int patch_ca0132(struct hda_codec *codec)
switch (spec->quirk) {
case QUIRK_SBZ:
case QUIRK_R3D:
+ case QUIRK_AE5:
+ case QUIRK_ZXR:
spec->use_alt_controls = true;
spec->use_alt_functions = true;
spec->use_pci_mmio = true;
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index a7f91be45194..64fa5a82bb9f 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -23,7 +23,7 @@
#include <linux/module.h>
#include <sound/core.h>
#include <sound/tlv.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 1b2195dd2b26..52642ba3e2c0 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -25,7 +25,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index cfd4e4f97f8f..950e02e71766 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -27,7 +27,7 @@
#include <sound/core.h>
#include <sound/jack.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"
@@ -943,6 +943,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
+ SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index cb587dce67a9..67099cbb6be2 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -41,7 +41,7 @@
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
#include <sound/hda_chmap.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_jack.h"
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 3ac7ba9b342d..fa61674a5605 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -32,7 +32,7 @@
#include <linux/input.h>
#include <sound/core.h>
#include <sound/jack.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
@@ -6843,6 +6843,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x21, 0x0221101f}),
SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
{0x14, 0x90170110},
+ {0x19, 0x02a11030},
+ {0x1a, 0x02a11040},
+ {0x1b, 0x01011020},
+ {0x21, 0x0221101f}),
+ SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
+ {0x14, 0x90170110},
{0x19, 0x02a11020},
{0x1a, 0x02a11030},
{0x21, 0x0221101f}),
@@ -7738,6 +7744,8 @@ enum {
ALC662_FIXUP_ASUS_Nx50,
ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
ALC668_FIXUP_ASUS_Nx51,
+ ALC668_FIXUP_MIC_COEF,
+ ALC668_FIXUP_ASUS_G751,
ALC891_FIXUP_HEADSET_MODE,
ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
ALC662_FIXUP_ACER_VERITON,
@@ -8007,6 +8015,23 @@ static const struct hda_fixup alc662_fixups[] = {
.chained = true,
.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
},
+ [ALC668_FIXUP_MIC_COEF] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
+ {}
+ },
+ },
+ [ALC668_FIXUP_ASUS_G751] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x16, 0x0421101f }, /* HP */
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC668_FIXUP_MIC_COEF
+ },
[ALC891_FIXUP_HEADSET_MODE] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode,
@@ -8080,6 +8105,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
+ SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
@@ -8184,6 +8210,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
{.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
{.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
+ {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
{.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index f63acb1b965c..c49d25bcd7f2 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -27,7 +27,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
/* si3054 verbs */
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 046705b4691a..1b6ecfb01759 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -32,7 +32,7 @@
#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_beep.h"
@@ -77,6 +77,7 @@ enum {
STAC_DELL_M6_BOTH,
STAC_DELL_EQ,
STAC_ALIENWARE_M17X,
+ STAC_ELO_VUPOINT_15MX,
STAC_92HD89XX_HP_FRONT_JACK,
STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
STAC_92HD73XX_ASUS_MOBO,
@@ -1879,6 +1880,18 @@ static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec,
codec->no_jack_detect = 1;
}
+
+static void stac92hd73xx_disable_automute(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+
+ spec->gen.suppress_auto_mute = 1;
+}
+
static const struct hda_fixup stac92hd73xx_fixups[] = {
[STAC_92HD73XX_REF] = {
.type = HDA_FIXUP_FUNC,
@@ -1904,6 +1917,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = stac92hd73xx_fixup_alienware_m17x,
},
+ [STAC_ELO_VUPOINT_15MX] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = stac92hd73xx_disable_automute,
+ },
[STAC_92HD73XX_INTEL] = {
.type = HDA_FIXUP_PINS,
.v.pins = intel_dg45id_pin_configs,
@@ -1942,6 +1959,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = {
{ .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
{ .id = STAC_DELL_EQ, .name = "dell-eq" },
{ .id = STAC_ALIENWARE_M17X, .name = "alienware" },
+ { .id = STAC_ELO_VUPOINT_15MX, .name = "elo-vupoint-15mx" },
{ .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
{}
};
@@ -1991,6 +2009,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
"Alienware M17x", STAC_ALIENWARE_M17X),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
"Alienware M17x R3", STAC_DELL_EQ),
+ SND_PCI_QUIRK(0x1059, 0x1011,
+ "ELO VuPoint 15MX", STAC_ELO_VUPOINT_15MX),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927,
"HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 6b9617aee0e6..9f6f13e25145 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -52,7 +52,7 @@
#include <linux/module.h>
#include <sound/core.h>
#include <sound/asoundef.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"