diff options
Diffstat (limited to 'kernel/sound/pci/hda')
34 files changed, 2555 insertions, 3621 deletions
diff --git a/kernel/sound/pci/hda/Kconfig b/kernel/sound/pci/hda/Kconfig index a5ed1c181..e94cfd5c6 100644 --- a/kernel/sound/pci/hda/Kconfig +++ b/kernel/sound/pci/hda/Kconfig @@ -4,7 +4,7 @@ config SND_HDA tristate select SND_PCM select SND_VMASTER - select SND_KCTL_JACK + select SND_JACK if INPUT=y || INPUT=SND select SND_HDA_CORE config SND_HDA_INTEL @@ -38,22 +38,6 @@ config SND_HDA_TEGRA if SND_HDA -config SND_HDA_DSP_LOADER - bool - -config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" - range 0 32768 - default 64 - help - Specifies the default pre-allocated buffer-size in kB for the - HD-audio driver. A larger buffer (e.g. 2048) is preferred - for systems using PulseAudio. The default 64 is chosen just - for compatibility reasons. - - Note that the pre-allocation size can be changed dynamically - via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. - config SND_HDA_HWDEP bool "Build hwdep interface for HD-audio driver" select SND_HWDEP @@ -87,14 +71,6 @@ config SND_HDA_INPUT_BEEP_MODE Set 1 to always enable the digital beep interface for HD-audio by default. -config SND_HDA_INPUT_JACK - bool "Support jack plugging notification via input layer" - depends on INPUT=y || INPUT=SND - select SND_JACK - help - Say Y here to enable the jack plugging notification via - input layer. - config SND_HDA_PATCH_LOADER bool "Support initialization patch loading for HD-audio" select FW_LOADER @@ -156,11 +132,6 @@ config SND_HDA_CODEC_HDMI comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m -config SND_HDA_I915 - bool - default y - depends on DRM_I915 - config SND_HDA_CODEC_CIRRUS tristate "Build Cirrus Logic codec support" select SND_HDA_GENERIC diff --git a/kernel/sound/pci/hda/Makefile b/kernel/sound/pci/hda/Makefile index af78fb33a..6d83c6e03 100644 --- a/kernel/sound/pci/hda/Makefile +++ b/kernel/sound/pci/hda/Makefile @@ -1,16 +1,16 @@ snd-hda-intel-objs := hda_intel.o -snd-hda-controller-objs := hda_controller.o snd-hda-tegra-objs := hda_tegra.o -# for haswell power well -snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o -snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o +snd-hda-codec-y += hda_controller.o +snd-hda-codec-$(CONFIG_SND_PROC_FS) += hda_proc.o + snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o # for trace-points CFLAGS_hda_controller.o := -I$(src) +CFLAGS_hda_intel.o := -I$(src) snd-hda-codec-generic-objs := hda_generic.o snd-hda-codec-realtek-objs := patch_realtek.o @@ -27,7 +27,6 @@ snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o # common driver obj-$(CONFIG_SND_HDA) := snd-hda-codec.o -obj-$(CONFIG_SND_HDA) += snd-hda-controller.o # codec drivers obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o diff --git a/kernel/sound/pci/hda/hda_auto_parser.c b/kernel/sound/pci/hda/hda_auto_parser.c index 03b7399bb..7f57a145a 100644 --- a/kernel/sound/pci/hda/hda_auto_parser.c +++ b/kernel/sound/pci/hda/hda_auto_parser.c @@ -887,11 +887,32 @@ EXPORT_SYMBOL_GPL(snd_hda_apply_fixup); static bool pin_config_match(struct hda_codec *codec, const struct hda_pintbl *pins) { - for (; pins->nid; pins++) { - u32 def_conf = snd_hda_codec_get_pincfg(codec, pins->nid); - if (pins->val != def_conf) + int i; + + for (i = 0; i < codec->init_pins.used; i++) { + struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); + hda_nid_t nid = pin->nid; + u32 cfg = pin->cfg; + const struct hda_pintbl *t_pins; + int found; + + t_pins = pins; + found = 0; + for (; t_pins->nid; t_pins++) { + if (t_pins->nid == nid) { + found = 1; + if (t_pins->val == cfg) + break; + else if ((cfg & 0xf0000000) == 0x40000000 && (t_pins->val & 0xf0000000) == 0x40000000) + break; + else + return false; + } + } + if (!found && (cfg & 0xf0000000) != 0x40000000) return false; } + return true; } diff --git a/kernel/sound/pci/hda/hda_beep.c b/kernel/sound/pci/hda/hda_beep.c index 3364dc0fd..c397e7da0 100644 --- a/kernel/sound/pci/hda/hda_beep.c +++ b/kernel/sound/pci/hda/hda_beep.c @@ -1,7 +1,7 @@ /* * Digital Beep Input Interface for HD-audio codec * - * Author: Matthew Ranostay <mranostay@embeddedalley.com> + * Author: Matt Ranostay <mranostay@gmail.com> * Copyright (c) 2008 Embedded Alley Solutions Inc * * This driver is free software; you can redistribute it and/or modify diff --git a/kernel/sound/pci/hda/hda_beep.h b/kernel/sound/pci/hda/hda_beep.h index 46524ff7e..1052ad380 100644 --- a/kernel/sound/pci/hda/hda_beep.h +++ b/kernel/sound/pci/hda/hda_beep.h @@ -1,7 +1,7 @@ /* * Digital Beep Input Interface for HD-audio codec * - * Author: Matthew Ranostay <mranostay@embeddedalley.com> + * Author: Matt Ranostay <mranostay@gmail.com> * Copyright (c) 2008 Embedded Alley Solutions Inc * * This driver is free software; you can redistribute it and/or modify diff --git a/kernel/sound/pci/hda/hda_bind.c b/kernel/sound/pci/hda/hda_bind.c index 00aa31c5f..6efadbfb3 100644 --- a/kernel/sound/pci/hda/hda_bind.c +++ b/kernel/sound/pci/hda/hda_bind.c @@ -15,29 +15,22 @@ #include "hda_local.h" /* - * find a matching codec preset + * find a matching codec id */ static int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv) { struct hda_codec *codec = container_of(dev, struct hda_codec, core); struct hda_codec_driver *driver = container_of(drv, struct hda_codec_driver, core); - const struct hda_codec_preset *preset; + const struct hda_device_id *list; /* check probe_id instead of vendor_id if set */ u32 id = codec->probe_id ? codec->probe_id : codec->core.vendor_id; + u32 rev_id = codec->core.revision_id; - for (preset = driver->preset; preset->id; preset++) { - u32 mask = preset->mask; - - if (preset->afg && preset->afg != codec->core.afg) - continue; - if (preset->mfg && preset->mfg != codec->core.mfg) - continue; - if (!mask) - mask = ~0; - if (preset->id == (id & mask) && - (!preset->rev || preset->rev == codec->core.revision_id)) { - codec->preset = preset; + for (list = driver->id; list->vendor_id; list++) { + if (list->vendor_id == id && + (!list->rev_id || list->rev_id == rev_id)) { + codec->preset = list; return 1; } } @@ -53,26 +46,45 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) codec->patch_ops.unsol_event(codec, ev); } -/* reset the codec name from the preset */ -static int codec_refresh_name(struct hda_codec *codec, const char *name) +/** + * snd_hda_codec_set_name - set the codec name + * @codec: the HDA codec + * @name: name string to set + */ +int snd_hda_codec_set_name(struct hda_codec *codec, const char *name) { - if (name) { - kfree(codec->core.chip_name); - codec->core.chip_name = kstrdup(name, GFP_KERNEL); + int err; + + if (!name) + return 0; + err = snd_hdac_device_set_chip_name(&codec->core, name); + if (err < 0) + return err; + + /* update the mixer name */ + if (!*codec->card->mixername || + codec->bus->mixer_assigned >= codec->core.addr) { + snprintf(codec->card->mixername, + sizeof(codec->card->mixername), "%s %s", + codec->core.vendor_name, codec->core.chip_name); + codec->bus->mixer_assigned = codec->core.addr; } - return codec->core.chip_name ? 0 : -ENOMEM; + + return 0; } +EXPORT_SYMBOL_GPL(snd_hda_codec_set_name); static int hda_codec_driver_probe(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); struct module *owner = dev->driver->owner; + hda_codec_patch_t patch; int err; if (WARN_ON(!codec->preset)) return -EINVAL; - err = codec_refresh_name(codec, codec->preset->name); + err = snd_hda_codec_set_name(codec, codec->preset->name); if (err < 0) goto error; err = snd_hdac_regmap_init(&codec->core); @@ -84,9 +96,12 @@ static int hda_codec_driver_probe(struct device *dev) goto error; } - err = codec->preset->patch(codec); - if (err < 0) - goto error_module; + patch = (hda_codec_patch_t)codec->preset->driver_data; + if (patch) { + err = patch(codec); + if (err < 0) + goto error_module; + } err = snd_hda_codec_build_pcms(codec); if (err < 0) @@ -159,15 +174,40 @@ static inline bool codec_probed(struct hda_codec *codec) return device_attach(hda_codec_dev(codec)) > 0 && codec->preset; } +/* try to auto-load codec module */ +static void request_codec_module(struct hda_codec *codec) +{ +#ifdef MODULE + char modalias[32]; + const char *mod = NULL; + + switch (codec->probe_id) { + case HDA_CODEC_ID_GENERIC_HDMI: +#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI) + mod = "snd-hda-codec-hdmi"; +#endif + break; + case HDA_CODEC_ID_GENERIC: +#if IS_MODULE(CONFIG_SND_HDA_GENERIC) + mod = "snd-hda-codec-generic"; +#endif + break; + default: + snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias)); + mod = modalias; + break; + } + + if (mod) + request_module(mod); +#endif /* MODULE */ +} + /* try to auto-load and bind the codec module */ static void codec_bind_module(struct hda_codec *codec) { #ifdef MODULE - request_module("snd-hda-codec-id:%08x", codec->core.vendor_id); - if (codec_probed(codec)) - return; - request_module("snd-hda-codec-id:%04x*", - (codec->core.vendor_id >> 16) & 0xffff); + request_codec_module(codec); if (codec_probed(codec)) return; #endif @@ -204,17 +244,13 @@ static int codec_bind_generic(struct hda_codec *codec) if (is_likely_hdmi_codec(codec)) { codec->probe_id = HDA_CODEC_ID_GENERIC_HDMI; -#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI) - request_module("snd-hda-codec-hdmi"); -#endif + request_codec_module(codec); if (codec_probed(codec)) return 0; } codec->probe_id = HDA_CODEC_ID_GENERIC; -#if IS_MODULE(CONFIG_SND_HDA_GENERIC) - request_module("snd-hda-codec-generic"); -#endif + request_codec_module(codec); if (codec_probed(codec)) return 0; return -ENODEV; @@ -259,11 +295,6 @@ int snd_hda_codec_configure(struct hda_codec *codec) } } - /* audio codec should override the mixer name */ - if (codec->core.afg || !*codec->card->mixername) - snprintf(codec->card->mixername, - sizeof(codec->card->mixername), "%s %s", - codec->core.vendor_name, codec->core.chip_name); return 0; error: diff --git a/kernel/sound/pci/hda/hda_codec.c b/kernel/sound/pci/hda/hda_codec.c index 36e8f1236..83741887f 100644 --- a/kernel/sound/pci/hda/hda_codec.c +++ b/kernel/sound/pci/hda/hda_codec.c @@ -53,76 +53,6 @@ #define codec_has_clkstop(codec) \ ((codec)->core.power_caps & AC_PWRST_CLKSTOP) -/** - * snd_hda_get_jack_location - Give a location string of the jack - * @cfg: pin default config value - * - * Parse the pin default config value and returns the string of the - * jack location, e.g. "Rear", "Front", etc. - */ -const char *snd_hda_get_jack_location(u32 cfg) -{ - static char *bases[7] = { - "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", - }; - static unsigned char specials_idx[] = { - 0x07, 0x08, - 0x17, 0x18, 0x19, - 0x37, 0x38 - }; - static char *specials[] = { - "Rear Panel", "Drive Bar", - "Riser", "HDMI", "ATAPI", - "Mobile-In", "Mobile-Out" - }; - int i; - cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; - if ((cfg & 0x0f) < 7) - return bases[cfg & 0x0f]; - for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { - if (cfg == specials_idx[i]) - return specials[i]; - } - return "UNKNOWN"; -} -EXPORT_SYMBOL_GPL(snd_hda_get_jack_location); - -/** - * snd_hda_get_jack_connectivity - Give a connectivity string of the jack - * @cfg: pin default config value - * - * Parse the pin default config value and returns the string of the - * jack connectivity, i.e. external or internal connection. - */ -const char *snd_hda_get_jack_connectivity(u32 cfg) -{ - static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; - - return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; -} -EXPORT_SYMBOL_GPL(snd_hda_get_jack_connectivity); - -/** - * snd_hda_get_jack_type - Give a type string of the jack - * @cfg: pin default config value - * - * Parse the pin default config value and returns the string of the - * jack type, i.e. the purpose of the jack, such as Line-Out or CD. - */ -const char *snd_hda_get_jack_type(u32 cfg) -{ - static char *jack_types[16] = { - "Line Out", "Speaker", "HP Out", "CD", - "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", - "Line In", "Aux", "Mic", "Telephony", - "SPDIF In", "Digital In", "Reserved", "Other" - }; - - return jack_types[(cfg & AC_DEFCFG_DEVICE) - >> AC_DEFCFG_DEVICE_SHIFT]; -} -EXPORT_SYMBOL_GPL(snd_hda_get_jack_type); - /* * Send and receive a verb - passed to exec_verb override for hdac_device */ @@ -146,11 +76,11 @@ static int codec_exec_verb(struct hdac_device *dev, unsigned int cmd, bus->no_response_fallback = 0; mutex_unlock(&bus->core.cmd_mutex); snd_hda_power_down_pm(codec); - if (!codec_in_pm(codec) && res && err < 0 && bus->rirb_error) { + if (!codec_in_pm(codec) && res && err == -EAGAIN) { if (bus->response_reset) { codec_dbg(codec, "resetting BUS due to fatal communication error\n"); - bus->ops.bus_reset(bus); + snd_hda_bus_reset(bus); } goto again; } @@ -161,50 +91,6 @@ static int codec_exec_verb(struct hdac_device *dev, unsigned int cmd, } /** - * snd_hda_codec_read - send a command and get the response - * @codec: the HDA codec - * @nid: NID to send the command - * @flags: optional bit flags - * @verb: the verb to send - * @parm: the parameter for the verb - * - * Send a single command and read the corresponding response. - * - * Returns the obtained response value, or -1 for an error. - */ -unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, - int flags, - unsigned int verb, unsigned int parm) -{ - unsigned int cmd = snd_hdac_make_cmd(&codec->core, nid, verb, parm); - unsigned int res; - if (snd_hdac_exec_verb(&codec->core, cmd, flags, &res)) - return -1; - return res; -} -EXPORT_SYMBOL_GPL(snd_hda_codec_read); - -/** - * snd_hda_codec_write - send a single command without waiting for response - * @codec: the HDA codec - * @nid: NID to send the command - * @flags: optional bit flags - * @verb: the verb to send - * @parm: the parameter for the verb - * - * Send a single command without waiting for response. - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags, - unsigned int verb, unsigned int parm) -{ - unsigned int cmd = snd_hdac_make_cmd(&codec->core, nid, verb, parm); - return snd_hdac_exec_verb(&codec->core, cmd, flags, NULL); -} -EXPORT_SYMBOL_GPL(snd_hda_codec_write); - -/** * snd_hda_sequence_write - sequence writes * @codec: the HDA codec * @seq: VERB array to send @@ -437,7 +323,7 @@ static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid) return 0; parm = snd_hdac_read_parm_uncached(&codec->core, nid, AC_PAR_DEVLIST_LEN); - if (parm == -1 && codec->bus->rirb_error) + if (parm == -1) parm = 0; return parm & AC_DEV_LIST_LEN_MASK; } @@ -467,10 +353,9 @@ int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, devices = 0; while (devices < dev_len) { - parm = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_DEVICE_LIST, devices); - if (parm == -1 && codec->bus->rirb_error) - break; + if (snd_hdac_read(&codec->core, nid, + AC_VERB_GET_DEVICE_LIST, devices, &parm)) + break; /* error */ for (i = 0; i < 8; i++) { dev_list[devices] = (u8)parm; @@ -484,96 +369,6 @@ int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, } /* - * destructor - */ -static void snd_hda_bus_free(struct hda_bus *bus) -{ - if (!bus) - return; - if (bus->ops.private_free) - bus->ops.private_free(bus); - snd_hdac_bus_exit(&bus->core); - kfree(bus); -} - -static int snd_hda_bus_dev_free(struct snd_device *device) -{ - snd_hda_bus_free(device->device_data); - return 0; -} - -static int snd_hda_bus_dev_disconnect(struct snd_device *device) -{ - struct hda_bus *bus = device->device_data; - bus->shutdown = 1; - return 0; -} - -/* hdac_bus_ops translations */ -static int _hda_bus_command(struct hdac_bus *_bus, unsigned int cmd) -{ - struct hda_bus *bus = container_of(_bus, struct hda_bus, core); - return bus->ops.command(bus, cmd); -} - -static int _hda_bus_get_response(struct hdac_bus *_bus, unsigned int addr, - unsigned int *res) -{ - struct hda_bus *bus = container_of(_bus, struct hda_bus, core); - *res = bus->ops.get_response(bus, addr); - return bus->rirb_error ? -EIO : 0; -} - -static const struct hdac_bus_ops bus_ops = { - .command = _hda_bus_command, - .get_response = _hda_bus_get_response, -}; - -/** - * snd_hda_bus_new - create a HDA bus - * @card: the card entry - * @busp: the pointer to store the created bus instance - * - * Returns 0 if successful, or a negative error code. - */ -int snd_hda_bus_new(struct snd_card *card, - struct hda_bus **busp) -{ - struct hda_bus *bus; - int err; - static struct snd_device_ops dev_ops = { - .dev_disconnect = snd_hda_bus_dev_disconnect, - .dev_free = snd_hda_bus_dev_free, - }; - - if (busp) - *busp = NULL; - - bus = kzalloc(sizeof(*bus), GFP_KERNEL); - if (!bus) - return -ENOMEM; - - err = snd_hdac_bus_init(&bus->core, card->dev, &bus_ops); - if (err < 0) { - kfree(bus); - return err; - } - - bus->card = card; - mutex_init(&bus->prepare_mutex); - - err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); - if (err < 0) { - snd_hda_bus_free(bus); - return err; - } - if (busp) - *busp = bus; - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_bus_new); - -/* * read widget caps for each widget and store in cache */ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) @@ -950,6 +745,7 @@ void snd_hda_codec_register(struct hda_codec *codec) return; if (device_is_registered(hda_codec_dev(codec))) { snd_hda_register_beep_device(codec); + snd_hdac_link_power(&codec->core, true); pm_runtime_enable(hda_codec_dev(codec)); /* it was powered up in snd_hda_codec_new(), now all done */ snd_hda_power_down(codec); @@ -977,6 +773,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) codec->in_freeing = 1; snd_hdac_device_unregister(&codec->core); + snd_hdac_link_power(&codec->core, false); put_device(hda_codec_dev(codec)); return 0; } @@ -1064,7 +861,7 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { - err = -ENODEV; + err = -ENOMEM; goto error; } } @@ -1114,7 +911,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) hda_nid_t fg; int err; - err = snd_hdac_refresh_widgets(&codec->core); + err = snd_hdac_refresh_widget_sysfs(&codec->core); if (err < 0) return err; @@ -3223,6 +3020,7 @@ static int hda_codec_runtime_suspend(struct device *dev) if (codec_has_clkstop(codec) && codec_has_epss(codec) && (state & AC_PWRST_CLK_STOP_OK)) snd_hdac_codec_link_down(&codec->core); + snd_hdac_link_power(&codec->core, false); return 0; } @@ -3230,6 +3028,7 @@ static int hda_codec_runtime_resume(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); + snd_hdac_link_power(&codec->core, true); snd_hdac_codec_link_up(&codec->core); hda_call_codec_resume(codec); pm_runtime_mark_last_busy(dev); @@ -3259,8 +3058,7 @@ static int add_std_chmaps(struct hda_codec *codec) struct snd_pcm_chmap *chmap; const struct snd_pcm_chmap_elem *elem; - if (!pcm || !pcm->pcm || pcm->own_chmap || - !hinfo->substreams) + if (!pcm->pcm || pcm->own_chmap || !hinfo->substreams) continue; elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps; err = snd_pcm_add_chmap_ctls(pcm->pcm, str, elem, @@ -3313,311 +3111,6 @@ int snd_hda_codec_build_controls(struct hda_codec *codec) } /* - * stream formats - */ -struct hda_rate_tbl { - unsigned int hz; - unsigned int alsa_bits; - unsigned int hda_fmt; -}; - -/* rate = base * mult / div */ -#define HDA_RATE(base, mult, div) \ - (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ - (((div) - 1) << AC_FMT_DIV_SHIFT)) - -static struct hda_rate_tbl rate_bits[] = { - /* rate in Hz, ALSA rate bitmask, HDA format value */ - - /* autodetected value used in snd_hda_query_supported_pcm */ - { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) }, - { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) }, - { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) }, - { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) }, - { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) }, - { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) }, - { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) }, - { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) }, - { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) }, - { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) }, - { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) }, -#define AC_PAR_PCM_RATE_BITS 11 - /* up to bits 10, 384kHZ isn't supported properly */ - - /* not autodetected value */ - { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) }, - - { 0 } /* terminator */ -}; - -/** - * snd_hda_calc_stream_format - calculate format bitset - * @codec: HD-audio codec - * @rate: the sample rate - * @channels: the number of channels - * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) - * @maxbps: the max. bps - * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant) - * - * Calculate the format bitset from the given rate, channels and th PCM format. - * - * Return zero if invalid. - */ -unsigned int snd_hda_calc_stream_format(struct hda_codec *codec, - unsigned int rate, - unsigned int channels, - unsigned int format, - unsigned int maxbps, - unsigned short spdif_ctls) -{ - int i; - unsigned int val = 0; - - for (i = 0; rate_bits[i].hz; i++) - if (rate_bits[i].hz == rate) { - val = rate_bits[i].hda_fmt; - break; - } - if (!rate_bits[i].hz) { - codec_dbg(codec, "invalid rate %d\n", rate); - return 0; - } - - if (channels == 0 || channels > 8) { - codec_dbg(codec, "invalid channels %d\n", channels); - return 0; - } - val |= channels - 1; - - switch (snd_pcm_format_width(format)) { - case 8: - val |= AC_FMT_BITS_8; - break; - case 16: - val |= AC_FMT_BITS_16; - break; - case 20: - case 24: - case 32: - if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) - val |= AC_FMT_BITS_32; - else if (maxbps >= 24) - val |= AC_FMT_BITS_24; - else - val |= AC_FMT_BITS_20; - break; - default: - codec_dbg(codec, "invalid format width %d\n", - snd_pcm_format_width(format)); - return 0; - } - - if (spdif_ctls & AC_DIG1_NONAUDIO) - val |= AC_FMT_TYPE_NON_PCM; - - return val; -} -EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format); - -static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val = 0; - if (nid != codec->core.afg && - (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) - val = snd_hda_param_read(codec, nid, AC_PAR_PCM); - if (!val || val == -1) - val = snd_hda_param_read(codec, codec->core.afg, AC_PAR_PCM); - if (!val || val == -1) - return 0; - return val; -} - -static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (!streams || streams == -1) - streams = snd_hda_param_read(codec, codec->core.afg, AC_PAR_STREAM); - if (!streams || streams == -1) - return 0; - return streams; -} - -/** - * snd_hda_query_supported_pcm - query the supported PCM rates and formats - * @codec: the HDA codec - * @nid: NID to query - * @ratesp: the pointer to store the detected rate bitflags - * @formatsp: the pointer to store the detected formats - * @bpsp: the pointer to store the detected format widths - * - * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp - * or @bsps argument is ignored. - * - * Returns 0 if successful, otherwise a negative error code. - */ -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp) -{ - unsigned int i, val, wcaps; - - wcaps = get_wcaps(codec, nid); - val = query_pcm_param(codec, nid); - - if (ratesp) { - u32 rates = 0; - for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) { - if (val & (1 << i)) - rates |= rate_bits[i].alsa_bits; - } - if (rates == 0) { - codec_err(codec, - "rates == 0 (nid=0x%x, val=0x%x, ovrd=%i)\n", - nid, val, - (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); - return -EIO; - } - *ratesp = rates; - } - - if (formatsp || bpsp) { - u64 formats = 0; - unsigned int streams, bps; - - streams = query_stream_param(codec, nid); - if (!streams) - return -EIO; - - bps = 0; - if (streams & AC_SUPFMT_PCM) { - if (val & AC_SUPPCM_BITS_8) { - formats |= SNDRV_PCM_FMTBIT_U8; - bps = 8; - } - if (val & AC_SUPPCM_BITS_16) { - formats |= SNDRV_PCM_FMTBIT_S16_LE; - bps = 16; - } - if (wcaps & AC_WCAP_DIGITAL) { - if (val & AC_SUPPCM_BITS_32) - formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; - if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) - formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (val & AC_SUPPCM_BITS_24) - bps = 24; - else if (val & AC_SUPPCM_BITS_20) - bps = 20; - } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24| - AC_SUPPCM_BITS_32)) { - formats |= SNDRV_PCM_FMTBIT_S32_LE; - if (val & AC_SUPPCM_BITS_32) - bps = 32; - else if (val & AC_SUPPCM_BITS_24) - bps = 24; - else if (val & AC_SUPPCM_BITS_20) - bps = 20; - } - } -#if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */ - if (streams & AC_SUPFMT_FLOAT32) { - formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; - if (!bps) - bps = 32; - } -#endif - if (streams == AC_SUPFMT_AC3) { - /* should be exclusive */ - /* temporary hack: we have still no proper support - * for the direct AC3 stream... - */ - formats |= SNDRV_PCM_FMTBIT_U8; - bps = 8; - } - if (formats == 0) { - codec_err(codec, - "formats == 0 (nid=0x%x, val=0x%x, ovrd=%i, streams=0x%x)\n", - nid, val, - (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, - streams); - return -EIO; - } - if (formatsp) - *formatsp = formats; - if (bpsp) - *bpsp = bps; - } - - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_query_supported_pcm); - -/** - * snd_hda_is_supported_format - Check the validity of the format - * @codec: HD-audio codec - * @nid: NID to check - * @format: the HD-audio format value to check - * - * Check whether the given node supports the format value. - * - * Returns 1 if supported, 0 if not. - */ -int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, - unsigned int format) -{ - int i; - unsigned int val = 0, rate, stream; - - val = query_pcm_param(codec, nid); - if (!val) - return 0; - - rate = format & 0xff00; - for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) - if (rate_bits[i].hda_fmt == rate) { - if (val & (1 << i)) - break; - return 0; - } - if (i >= AC_PAR_PCM_RATE_BITS) - return 0; - - stream = query_stream_param(codec, nid); - if (!stream) - return 0; - - if (stream & AC_SUPFMT_PCM) { - switch (format & 0xf0) { - case 0x00: - if (!(val & AC_SUPPCM_BITS_8)) - return 0; - break; - case 0x10: - if (!(val & AC_SUPPCM_BITS_16)) - return 0; - break; - case 0x20: - if (!(val & AC_SUPPCM_BITS_20)) - return 0; - break; - case 0x30: - if (!(val & AC_SUPPCM_BITS_24)) - return 0; - break; - case 0x40: - if (!(val & AC_SUPPCM_BITS_32)) - return 0; - break; - default: - return 0; - } - } else { - /* FIXME: check for float32 and AC3? */ - } - - return 1; -} -EXPORT_SYMBOL_GPL(snd_hda_is_supported_format); - -/* * PCM stuff */ static int hda_pcm_default_open_close(struct hda_pcm_stream *hinfo, @@ -3829,14 +3322,9 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) struct hda_pcm *cpcm; int dev, err; - if (snd_BUG_ON(!bus->ops.attach_pcm)) - return -EINVAL; - err = snd_hda_codec_parse_pcms(codec); - if (err < 0) { - snd_hda_codec_reset(codec); + if (err < 0) return err; - } /* attach a new PCM streams */ list_for_each_entry(cpcm, &codec->pcm_list_head, list) { @@ -3849,7 +3337,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) if (dev < 0) continue; /* no fatal error */ cpcm->device = dev; - err = bus->ops.attach_pcm(bus, codec, cpcm); + err = snd_hda_attach_pcm_stream(bus, codec, cpcm); if (err < 0) { codec_err(codec, "cannot attach PCM stream %d for codec #%d\n", @@ -3916,6 +3404,9 @@ static void codec_set_power_save(struct hda_codec *codec, int delay) { struct device *dev = hda_codec_dev(codec); + if (delay == 0 && codec->auto_runtime_pm) + delay = 3000; + if (delay > 0) { pm_runtime_set_autosuspend_delay(dev, delay); pm_runtime_use_autosuspend(dev); @@ -4519,10 +4010,10 @@ int snd_hda_add_imux_item(struct hda_codec *codec, EXPORT_SYMBOL_GPL(snd_hda_add_imux_item); /** - * snd_hda_bus_reset - Reset the bus + * snd_hda_bus_reset_codecs - Reset the bus * @bus: HD-audio bus */ -void snd_hda_bus_reset(struct hda_bus *bus) +void snd_hda_bus_reset_codecs(struct hda_bus *bus) { struct hda_codec *codec; @@ -4537,7 +4028,6 @@ void snd_hda_bus_reset(struct hda_bus *bus) #endif } } -EXPORT_SYMBOL_GPL(snd_hda_bus_reset); /** * snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer diff --git a/kernel/sound/pci/hda/hda_codec.h b/kernel/sound/pci/hda/hda_codec.h index 9075ac28d..373fcad84 100644 --- a/kernel/sound/pci/hda/hda_codec.h +++ b/kernel/sound/pci/hda/hda_codec.h @@ -22,6 +22,7 @@ #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> @@ -40,32 +41,6 @@ struct hda_codec; struct hda_pcm; struct hda_pcm_stream; -/* bus operators */ -struct hda_bus_ops { - /* send a single command */ - int (*command)(struct hda_bus *bus, unsigned int cmd); - /* get a response from the last command */ - unsigned int (*get_response)(struct hda_bus *bus, unsigned int addr); - /* free the private data */ - void (*private_free)(struct hda_bus *); - /* attach a PCM stream */ - int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, - struct hda_pcm *pcm); - /* reset bus for retry verb */ - void (*bus_reset)(struct hda_bus *bus); -#ifdef CONFIG_SND_HDA_DSP_LOADER - /* prepare DSP transfer */ - int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format, - unsigned int byte_size, - struct snd_dma_buffer *bufp); - /* start/stop DSP transfer */ - void (*load_dsp_trigger)(struct hda_bus *bus, bool start); - /* clean up DSP transfer */ - void (*load_dsp_cleanup)(struct hda_bus *bus, - struct snd_dma_buffer *dmab); -#endif -}; - /* * codec bus * @@ -77,10 +52,8 @@ struct hda_bus { struct snd_card *card; - void *private_data; struct pci_dev *pci; const char *modelname; - struct hda_bus_ops ops; struct mutex prepare_mutex; @@ -92,37 +65,38 @@ struct hda_bus { unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */ /* status for codec/controller */ unsigned int shutdown :1; /* being unloaded */ - unsigned int rirb_error:1; /* error in codec communication */ 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. */ -struct hda_codec_preset { - unsigned int id; - unsigned int mask; - unsigned int subs; - unsigned int subs_mask; - unsigned int rev; - hda_nid_t afg, mfg; - const char *name; - int (*patch)(struct hda_codec *codec); -}; +typedef int (*hda_codec_patch_t)(struct hda_codec *); #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_codec_preset *preset; + const struct hda_device_id *id; }; int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, @@ -213,7 +187,7 @@ struct hda_codec { u32 probe_id; /* overridden id for probing */ /* detected preset */ - const struct hda_codec_preset *preset; + const struct hda_device_id *preset; const char *modelname; /* model name for preset */ /* set by patch */ @@ -281,6 +255,7 @@ struct hda_codec { 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 */ #ifdef CONFIG_PM unsigned long power_on_acct; unsigned long power_off_acct; @@ -300,10 +275,8 @@ struct hda_codec { unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */ struct delayed_work jackpoll_work; -#ifdef CONFIG_SND_HDA_INPUT_JACK /* jack detection */ struct snd_array jacks; -#endif int depop_delay; /* depop delay in ms, -1 for default delay time */ @@ -328,7 +301,6 @@ struct hda_codec { /* * constructors */ -int snd_hda_bus_new(struct snd_card *card, struct hda_bus **busp); 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_configure(struct hda_codec *codec); @@ -337,11 +309,21 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec); /* * low level functions */ -unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, +static inline unsigned int +snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int flags, - unsigned int verb, unsigned int parm); -int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags, - unsigned int verb, unsigned int parm); + 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) \ @@ -367,8 +349,6 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, hda_nid_t nid, int recursive); int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, u8 *dev_list, int max_devices); -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp); struct hda_verb { hda_nid_t nid; @@ -460,17 +440,17 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, int do_now); #define snd_hda_codec_cleanup_stream(codec, nid) \ __snd_hda_codec_cleanup_stream(codec, nid, 0) -unsigned int snd_hda_calc_stream_format(struct hda_codec *codec, - unsigned int rate, - unsigned int channels, - unsigned int format, - unsigned int maxbps, - unsigned short spdif_ctls); -int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, - unsigned int format); + +#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 */ @@ -481,6 +461,9 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, 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 @@ -498,13 +481,6 @@ int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid) } /* - * get widget information - */ -const char *snd_hda_get_jack_connectivity(u32 cfg); -const char *snd_hda_get_jack_type(u32 cfg); -const char *snd_hda_get_jack_location(u32 cfg); - -/* * power saving */ #define snd_hda_power_up(codec) snd_hdac_power_up(&(codec)->core) @@ -526,24 +502,12 @@ int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf); #endif #ifdef CONFIG_SND_HDA_DSP_LOADER -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 codec->bus->ops.load_dsp_prepare(codec->bus, format, size, bufp); -} -static inline void -snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) -{ - return codec->bus->ops.load_dsp_trigger(codec->bus, start); -} -static inline void -snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec, - struct snd_dma_buffer *dmab) -{ - return codec->bus->ops.load_dsp_cleanup(codec->bus, dmab); -} +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, diff --git a/kernel/sound/pci/hda/hda_controller.c b/kernel/sound/pci/hda/hda_controller.c index 26ce99059..22dbfa563 100644 --- a/kernel/sound/pci/hda/hda_controller.c +++ b/kernel/sound/pci/hda/hda_controller.c @@ -32,229 +32,29 @@ #include "hda_controller.h" #define CREATE_TRACE_POINTS -#include "hda_intel_trace.h" +#include "hda_controller_trace.h" /* DSP lock helpers */ -#ifdef CONFIG_SND_HDA_DSP_LOADER -#define dsp_lock_init(dev) mutex_init(&(dev)->dsp_mutex) -#define dsp_lock(dev) mutex_lock(&(dev)->dsp_mutex) -#define dsp_unlock(dev) mutex_unlock(&(dev)->dsp_mutex) -#define dsp_is_locked(dev) ((dev)->locked) -#else -#define dsp_lock_init(dev) do {} while (0) -#define dsp_lock(dev) do {} while (0) -#define dsp_unlock(dev) do {} while (0) -#define dsp_is_locked(dev) 0 -#endif - -/* - * AZX stream operations. - */ - -/* start a stream */ -static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) -{ - /* - * Before stream start, initialize parameter - */ - azx_dev->insufficient = 1; - - /* enable SIE */ - azx_writel(chip, INTCTL, - azx_readl(chip, INTCTL) | (1 << azx_dev->index)); - /* set DMA start and interrupt mask */ - azx_sd_writeb(chip, azx_dev, SD_CTL, - azx_sd_readb(chip, azx_dev, SD_CTL) | - SD_CTL_DMA_START | SD_INT_MASK); -} - -/* stop DMA */ -static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev) -{ - azx_sd_writeb(chip, azx_dev, SD_CTL, - azx_sd_readb(chip, azx_dev, SD_CTL) & - ~(SD_CTL_DMA_START | SD_INT_MASK)); - azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ -} - -/* stop a stream */ -void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) -{ - azx_stream_clear(chip, azx_dev); - /* disable SIE */ - azx_writel(chip, INTCTL, - azx_readl(chip, INTCTL) & ~(1 << azx_dev->index)); -} -EXPORT_SYMBOL_GPL(azx_stream_stop); - -/* reset stream */ -static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev) -{ - unsigned char val; - int timeout; - - azx_stream_clear(chip, azx_dev); - - azx_sd_writeb(chip, azx_dev, SD_CTL, - azx_sd_readb(chip, azx_dev, SD_CTL) | - SD_CTL_STREAM_RESET); - udelay(3); - timeout = 300; - while (!((val = azx_sd_readb(chip, azx_dev, SD_CTL)) & - SD_CTL_STREAM_RESET) && --timeout) - ; - val &= ~SD_CTL_STREAM_RESET; - azx_sd_writeb(chip, azx_dev, SD_CTL, val); - udelay(3); - - timeout = 300; - /* waiting for hardware to report that the stream is out of reset */ - while (((val = azx_sd_readb(chip, azx_dev, SD_CTL)) & - SD_CTL_STREAM_RESET) && --timeout) - ; - - /* reset first position - may not be synced with hw at this time */ - *azx_dev->posbuf = 0; -} - -/* - * set up the SD for streaming - */ -static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) -{ - unsigned int val; - /* make sure the run bit is zero for SD */ - azx_stream_clear(chip, azx_dev); - /* program the stream_tag */ - val = azx_sd_readl(chip, azx_dev, SD_CTL); - val = (val & ~SD_CTL_STREAM_TAG_MASK) | - (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT); - if (!azx_snoop(chip)) - val |= SD_CTL_TRAFFIC_PRIO; - azx_sd_writel(chip, azx_dev, SD_CTL, val); - - /* program the length of samples in cyclic buffer */ - azx_sd_writel(chip, azx_dev, SD_CBL, azx_dev->bufsize); - - /* program the stream format */ - /* this value needs to be the same as the one programmed */ - azx_sd_writew(chip, azx_dev, SD_FORMAT, azx_dev->format_val); - - /* program the stream LVI (last valid index) of the BDL */ - azx_sd_writew(chip, azx_dev, SD_LVI, azx_dev->frags - 1); - - /* program the BDL address */ - /* lower BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); - /* upper BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPU, - upper_32_bits(azx_dev->bdl.addr)); - - /* enable the position buffer */ - if (chip->get_position[0] != azx_get_pos_lpib || - chip->get_position[1] != azx_get_pos_lpib) { - if (!(azx_readl(chip, DPLBASE) & AZX_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, - (u32)chip->posbuf.addr | AZX_DPLBASE_ENABLE); - } - - /* set the interrupt enable bits in the descriptor control register */ - azx_sd_writel(chip, azx_dev, SD_CTL, - azx_sd_readl(chip, azx_dev, SD_CTL) | SD_INT_MASK); - - return 0; -} +#define dsp_lock(dev) snd_hdac_dsp_lock(azx_stream(dev)) +#define dsp_unlock(dev) snd_hdac_dsp_unlock(azx_stream(dev)) +#define dsp_is_locked(dev) snd_hdac_stream_is_locked(azx_stream(dev)) /* assign a stream for the PCM */ static inline struct azx_dev * azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) { - int dev, i, nums; - struct azx_dev *res = NULL; - /* make a non-zero unique key for the substream */ - int key = (substream->pcm->device << 16) | (substream->number << 2) | - (substream->stream + 1); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dev = chip->playback_index_offset; - nums = chip->playback_streams; - } else { - dev = chip->capture_index_offset; - nums = chip->capture_streams; - } - for (i = 0; i < nums; i++, dev++) { - struct azx_dev *azx_dev = &chip->azx_dev[dev]; - dsp_lock(azx_dev); - if (!azx_dev->opened && !dsp_is_locked(azx_dev)) { - if (azx_dev->assigned_key == key) { - azx_dev->opened = 1; - azx_dev->assigned_key = key; - dsp_unlock(azx_dev); - return azx_dev; - } - if (!res || - (chip->driver_caps & AZX_DCAPS_REVERSE_ASSIGN)) - res = azx_dev; - } - dsp_unlock(azx_dev); - } - if (res) { - dsp_lock(res); - res->opened = 1; - res->assigned_key = key; - dsp_unlock(res); - } - return res; + struct hdac_stream *s; + + s = snd_hdac_stream_assign(azx_bus(chip), substream); + if (!s) + return NULL; + return stream_to_azx_dev(s); } /* release the assigned stream */ static inline void azx_release_device(struct azx_dev *azx_dev) { - azx_dev->opened = 0; -} - -static cycle_t azx_cc_read(const struct cyclecounter *cc) -{ - struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc); - struct snd_pcm_substream *substream = azx_dev->substream; - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - - return azx_readl(chip, WALLCLK); -} - -static void azx_timecounter_init(struct snd_pcm_substream *substream, - bool force, cycle_t last) -{ - struct azx_dev *azx_dev = get_azx_dev(substream); - struct timecounter *tc = &azx_dev->azx_tc; - struct cyclecounter *cc = &azx_dev->azx_cc; - u64 nsec; - - cc->read = azx_cc_read; - cc->mask = CLOCKSOURCE_MASK(32); - - /* - * Converting from 24 MHz to ns means applying a 125/3 factor. - * To avoid any saturation issues in intermediate operations, - * the 125 factor is applied first. The division is applied - * last after reading the timecounter value. - * Applying the 1/3 factor as part of the multiplication - * requires at least 20 bits for a decent precision, however - * overflows occur after about 4 hours or less, not a option. - */ - - cc->mult = 125; /* saturation after 195 years */ - cc->shift = 0; - - nsec = 0; /* audio time is elapsed time since trigger */ - timecounter_init(tc, cc, nsec); - if (force) - /* - * force timecounter to use predefined value, - * used for synchronized starts - */ - tc->cycle_last = last; + snd_hdac_stream_release(azx_stream(azx_dev)); } static inline struct hda_pcm_stream * @@ -285,119 +85,6 @@ static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream, } /* - * set up a BDL entry - */ -static int setup_bdle(struct azx *chip, - struct snd_dma_buffer *dmab, - struct azx_dev *azx_dev, u32 **bdlp, - int ofs, int size, int with_ioc) -{ - u32 *bdl = *bdlp; - - while (size > 0) { - dma_addr_t addr; - int chunk; - - if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES) - return -EINVAL; - - addr = snd_sgbuf_get_addr(dmab, ofs); - /* program the address field of the BDL entry */ - bdl[0] = cpu_to_le32((u32)addr); - bdl[1] = cpu_to_le32(upper_32_bits(addr)); - /* program the size field of the BDL entry */ - chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size); - /* one BDLE cannot cross 4K boundary on CTHDA chips */ - if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) { - u32 remain = 0x1000 - (ofs & 0xfff); - if (chunk > remain) - chunk = remain; - } - bdl[2] = cpu_to_le32(chunk); - /* program the IOC to enable interrupt - * only when the whole fragment is processed - */ - size -= chunk; - bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); - bdl += 4; - azx_dev->frags++; - ofs += chunk; - } - *bdlp = bdl; - return ofs; -} - -/* - * set up BDL entries - */ -static int azx_setup_periods(struct azx *chip, - struct snd_pcm_substream *substream, - struct azx_dev *azx_dev) -{ - u32 *bdl; - int i, ofs, periods, period_bytes; - int pos_adj = 0; - - /* reset BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); - azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); - - period_bytes = azx_dev->period_bytes; - periods = azx_dev->bufsize / period_bytes; - - /* program the initial BDL entries */ - bdl = (u32 *)azx_dev->bdl.area; - ofs = 0; - azx_dev->frags = 0; - - if (chip->bdl_pos_adj) - pos_adj = chip->bdl_pos_adj[chip->dev_index]; - if (!azx_dev->no_period_wakeup && pos_adj > 0) { - struct snd_pcm_runtime *runtime = substream->runtime; - int pos_align = pos_adj; - pos_adj = (pos_adj * runtime->rate + 47999) / 48000; - if (!pos_adj) - pos_adj = pos_align; - else - pos_adj = ((pos_adj + pos_align - 1) / pos_align) * - pos_align; - pos_adj = frames_to_bytes(runtime, pos_adj); - if (pos_adj >= period_bytes) { - dev_warn(chip->card->dev,"Too big adjustment %d\n", - pos_adj); - pos_adj = 0; - } else { - ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), - azx_dev, - &bdl, ofs, pos_adj, true); - if (ofs < 0) - goto error; - } - } else - pos_adj = 0; - - for (i = 0; i < periods; i++) { - if (i == periods - 1 && pos_adj) - ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), - azx_dev, &bdl, ofs, - period_bytes - pos_adj, 0); - else - ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), - azx_dev, &bdl, ofs, - period_bytes, - !azx_dev->no_period_wakeup); - if (ofs < 0) - goto error; - } - return 0; - - error: - dev_err(chip->card->dev, "Too many BDL entries: buffer=%d, period=%d\n", - azx_dev->bufsize, period_bytes); - return -EINVAL; -} - -/* * PCM ops */ @@ -407,13 +94,9 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); - unsigned long flags; + trace_azx_pcm_close(chip, azx_dev); mutex_lock(&chip->open_mutex); - spin_lock_irqsave(&chip->reg_lock, flags); - azx_dev->substream = NULL; - azx_dev->running = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); azx_release_device(azx_dev); if (hinfo->ops.close) hinfo->ops.close(hinfo, apcm->codec, substream); @@ -428,18 +111,23 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx *chip = apcm->chip; + struct azx_dev *azx_dev = get_azx_dev(substream); int ret; - dsp_lock(get_azx_dev(substream)); - if (dsp_is_locked(get_azx_dev(substream))) { + trace_azx_pcm_hw_params(chip, azx_dev); + dsp_lock(azx_dev); + if (dsp_is_locked(azx_dev)) { ret = -EBUSY; goto unlock; } + 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)); unlock: - dsp_unlock(get_azx_dev(substream)); + dsp_unlock(azx_dev); return ret; } @@ -453,19 +141,13 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) /* reset BDL address */ dsp_lock(azx_dev); - if (!dsp_is_locked(azx_dev)) { - azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); - azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); - azx_sd_writel(chip, azx_dev, SD_CTL, 0); - azx_dev->bufsize = 0; - azx_dev->period_bytes = 0; - azx_dev->format_val = 0; - } + if (!dsp_is_locked(azx_dev)) + snd_hdac_stream_cleanup(azx_stream(azx_dev)); snd_hda_codec_cleanup(apcm->codec, hinfo, substream); err = chip->ops->substream_free_pages(chip, substream); - azx_dev->prepared = 0; + azx_stream(azx_dev)->prepared = 0; dsp_unlock(azx_dev); return err; } @@ -477,21 +159,21 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) struct azx_dev *azx_dev = get_azx_dev(substream); struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int bufsize, period_bytes, format_val, stream_tag; + unsigned int format_val, stream_tag; int err; struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid); unsigned short ctls = spdif ? spdif->ctls : 0; + trace_azx_pcm_prepare(chip, azx_dev); dsp_lock(azx_dev); if (dsp_is_locked(azx_dev)) { err = -EBUSY; goto unlock; } - azx_stream_reset(chip, azx_dev); - format_val = snd_hda_calc_stream_format(apcm->codec, - runtime->rate, + snd_hdac_stream_reset(azx_stream(azx_dev)); + format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, hinfo->maxbps, @@ -504,55 +186,23 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } - bufsize = snd_pcm_lib_buffer_bytes(substream); - period_bytes = snd_pcm_lib_period_bytes(substream); - - dev_dbg(chip->card->dev, "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", - bufsize, format_val); - - if (bufsize != azx_dev->bufsize || - period_bytes != azx_dev->period_bytes || - format_val != azx_dev->format_val || - runtime->no_period_wakeup != azx_dev->no_period_wakeup) { - azx_dev->bufsize = bufsize; - azx_dev->period_bytes = period_bytes; - azx_dev->format_val = format_val; - azx_dev->no_period_wakeup = runtime->no_period_wakeup; - err = azx_setup_periods(chip, substream, azx_dev); - if (err < 0) - goto unlock; - } + err = snd_hdac_stream_set_params(azx_stream(azx_dev), format_val); + if (err < 0) + goto unlock; - /* when LPIB delay correction gives a small negative value, - * we ignore it; currently set the threshold statically to - * 64 frames - */ - if (runtime->period_size > 64) - azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64); - else - azx_dev->delay_negative_threshold = 0; - - /* wallclk has 24Mhz clock source */ - azx_dev->period_wallclk = (((runtime->period_size * 24000) / - runtime->rate) * 1000); - azx_setup_controller(chip, azx_dev); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - azx_dev->fifo_size = - azx_sd_readw(chip, azx_dev, SD_FIFOSIZE) + 1; - else - azx_dev->fifo_size = 0; + snd_hdac_stream_setup(azx_stream(azx_dev)); - stream_tag = azx_dev->stream_tag; + stream_tag = azx_dev->core.stream_tag; /* CA-IBG chips need the playback stream starting from 1 */ if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) && stream_tag > chip->capture_streams) stream_tag -= chip->capture_streams; err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag, - azx_dev->format_val, substream); + azx_dev->core.format_val, substream); unlock: if (!err) - azx_dev->prepared = 1; + azx_stream(azx_dev)->prepared = 1; dsp_unlock(azx_dev); return err; } @@ -561,28 +211,36 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx *chip = apcm->chip; + struct hdac_bus *bus = azx_bus(chip); struct azx_dev *azx_dev; struct snd_pcm_substream *s; - int rstart = 0, start, nsync = 0, sbits = 0; - int nwait, timeout; + struct hdac_stream *hstr; + bool start; + int sbits = 0; + int sync_reg; azx_dev = get_azx_dev(substream); trace_azx_pcm_trigger(chip, azx_dev, cmd); - if (dsp_is_locked(azx_dev) || !azx_dev->prepared) + hstr = azx_stream(azx_dev); + if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) + sync_reg = AZX_REG_OLD_SSYNC; + else + sync_reg = AZX_REG_SSYNC; + + if (dsp_is_locked(azx_dev) || !hstr->prepared) return -EPIPE; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - rstart = 1; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: - start = 1; + start = true; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: - start = 0; + start = false; break; default: return -EINVAL; @@ -592,115 +250,55 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (s->pcm->card != substream->pcm->card) continue; azx_dev = get_azx_dev(s); - sbits |= 1 << azx_dev->index; - nsync++; + sbits |= 1 << azx_dev->core.index; snd_pcm_trigger_done(s, substream); } - spin_lock(&chip->reg_lock); + spin_lock(&bus->reg_lock); /* first, set SYNC bits of corresponding streams */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) | sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits); + snd_hdac_stream_sync_trigger(hstr, true, sbits, sync_reg); snd_pcm_group_for_each_entry(s, substream) { if (s->pcm->card != substream->pcm->card) continue; azx_dev = get_azx_dev(s); if (start) { - azx_dev->start_wallclk = azx_readl(chip, WALLCLK); - if (!rstart) - azx_dev->start_wallclk -= - azx_dev->period_wallclk; - azx_stream_start(chip, azx_dev); + azx_dev->insufficient = 1; + snd_hdac_stream_start(azx_stream(azx_dev), true); } else { - azx_stream_stop(chip, azx_dev); + snd_hdac_stream_stop(azx_stream(azx_dev)); } - azx_dev->running = start; } - spin_unlock(&chip->reg_lock); - if (start) { - /* wait until all FIFOs get ready */ - for (timeout = 5000; timeout; timeout--) { - nwait = 0; - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_dev = get_azx_dev(s); - if (!(azx_sd_readb(chip, azx_dev, SD_STS) & - SD_STS_FIFO_READY)) - nwait++; - } - if (!nwait) - break; - cpu_relax(); - } - } else { - /* wait until all RUN bits are cleared */ - for (timeout = 5000; timeout; timeout--) { - nwait = 0; - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_dev = get_azx_dev(s); - if (azx_sd_readb(chip, azx_dev, SD_CTL) & - SD_CTL_DMA_START) - nwait++; - } - if (!nwait) - break; - cpu_relax(); - } - } - spin_lock(&chip->reg_lock); + spin_unlock(&bus->reg_lock); + + snd_hdac_stream_sync(hstr, start, sbits); + + spin_lock(&bus->reg_lock); /* reset SYNC bits */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) & ~sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); - if (start) { - azx_timecounter_init(substream, 0, 0); - snd_pcm_gettime(substream->runtime, &substream->runtime->trigger_tstamp); - substream->runtime->trigger_tstamp_latched = true; - - if (nsync > 1) { - cycle_t cycle_last; - - /* same start cycle for master and group */ - azx_dev = get_azx_dev(substream); - cycle_last = azx_dev->azx_tc.cycle_last; - - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_timecounter_init(s, 1, cycle_last); - } - } - } - spin_unlock(&chip->reg_lock); + snd_hdac_stream_sync_trigger(hstr, false, sbits, sync_reg); + if (start) + snd_hdac_stream_timecounter_init(hstr, sbits); + spin_unlock(&bus->reg_lock); return 0; } unsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev) { - return azx_sd_readl(chip, azx_dev, SD_LPIB); + return snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev)); } EXPORT_SYMBOL_GPL(azx_get_pos_lpib); unsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev) { - return le32_to_cpu(*azx_dev->posbuf); + return snd_hdac_stream_get_pos_posbuf(azx_stream(azx_dev)); } EXPORT_SYMBOL_GPL(azx_get_pos_posbuf); unsigned int azx_get_position(struct azx *chip, struct azx_dev *azx_dev) { - struct snd_pcm_substream *substream = azx_dev->substream; + struct snd_pcm_substream *substream = azx_dev->core.substream; unsigned int pos; int stream = substream->stream; int delay = 0; @@ -710,7 +308,7 @@ unsigned int azx_get_position(struct azx *chip, else /* use the position buffer as default */ pos = azx_get_pos_posbuf(chip, azx_dev); - if (pos >= azx_dev->bufsize) + if (pos >= azx_dev->core.bufsize) pos = 0; if (substream->runtime) { @@ -752,7 +350,7 @@ static int azx_get_time_info(struct snd_pcm_substream *substream, snd_pcm_gettime(substream->runtime, system_ts); - nsec = timecounter_read(&azx_dev->azx_tc); + nsec = timecounter_read(&azx_dev->core.tc); nsec = div_u64(nsec, 3); /* can be optimized */ if (audio_tstamp_config->report_delay) nsec = azx_adjust_codec_delay(substream, nsec); @@ -802,17 +400,18 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) struct azx *chip = apcm->chip; struct azx_dev *azx_dev; struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; int err; int buff_step; snd_hda_codec_pcm_get(apcm->info); mutex_lock(&chip->open_mutex); azx_dev = azx_assign_device(chip, substream); + trace_azx_pcm_open(chip, azx_dev); if (azx_dev == NULL) { err = -EBUSY; goto unlock; } + runtime->private_data = azx_dev; runtime->hw = azx_pcm_hw; runtime->hw.channels_min = hinfo->channels_min; runtime->hw.channels_max = hinfo->channels_max; @@ -874,12 +473,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; } - spin_lock_irqsave(&chip->reg_lock, flags); - azx_dev->substream = substream; - azx_dev->running = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); - - runtime->private_data = azx_dev; snd_pcm_set_sync(substream); mutex_unlock(&chip->open_mutex); return 0; @@ -928,10 +521,11 @@ static void azx_pcm_free(struct snd_pcm *pcm) #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) -static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, - struct hda_pcm *cpcm) +int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, + struct hda_pcm *cpcm) { - struct azx *chip = bus->private_data; + struct hdac_bus *bus = &_bus->core; + struct azx *chip = bus_to_azx(bus); struct snd_pcm *pcm; struct azx_pcm *apcm; int pcm_dev = cpcm->device; @@ -979,89 +573,6 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, return 0; } -/* - * CORB / RIRB interface - */ -static int azx_alloc_cmd_io(struct azx *chip) -{ - /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - return chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, - PAGE_SIZE, &chip->rb); -} - -static void azx_init_cmd_io(struct azx *chip) -{ - int timeout; - - spin_lock_irq(&chip->reg_lock); - /* CORB set up */ - chip->corb.addr = chip->rb.addr; - chip->corb.buf = (u32 *)chip->rb.area; - azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); - azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr)); - - /* set the corb size to 256 entries (ULI requires explicitly) */ - azx_writeb(chip, CORBSIZE, 0x02); - /* set the corb write pointer to 0 */ - azx_writew(chip, CORBWP, 0); - - /* reset the corb hw read pointer */ - azx_writew(chip, CORBRP, AZX_CORBRP_RST); - if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) { - for (timeout = 1000; timeout > 0; timeout--) { - if ((azx_readw(chip, CORBRP) & AZX_CORBRP_RST) == AZX_CORBRP_RST) - break; - udelay(1); - } - if (timeout <= 0) - dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n", - azx_readw(chip, CORBRP)); - - azx_writew(chip, CORBRP, 0); - for (timeout = 1000; timeout > 0; timeout--) { - if (azx_readw(chip, CORBRP) == 0) - break; - udelay(1); - } - if (timeout <= 0) - dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n", - azx_readw(chip, CORBRP)); - } - - /* enable corb dma */ - azx_writeb(chip, CORBCTL, AZX_CORBCTL_RUN); - - /* RIRB set up */ - chip->rirb.addr = chip->rb.addr + 2048; - chip->rirb.buf = (u32 *)(chip->rb.area + 2048); - chip->rirb.wp = chip->rirb.rp = 0; - memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds)); - azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); - azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); - - /* set the rirb size to 256 entries (ULI requires explicitly) */ - azx_writeb(chip, RIRBSIZE, 0x02); - /* reset the rirb hw write pointer */ - azx_writew(chip, RIRBWP, AZX_RIRBWP_RST); - /* set N=1, get RIRB response interrupt for new entry */ - if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) - azx_writew(chip, RINTCNT, 0xc0); - else - azx_writew(chip, RINTCNT, 1); - /* enable rirb dma and response irq */ - azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN); - spin_unlock_irq(&chip->reg_lock); -} - -static void azx_free_cmd_io(struct azx *chip) -{ - spin_lock_irq(&chip->reg_lock); - /* disable ringbuffer DMAs */ - azx_writeb(chip, RIRBCTL, 0); - azx_writeb(chip, CORBCTL, 0); - spin_unlock_irq(&chip->reg_lock); -} - static unsigned int azx_command_addr(u32 cmd) { unsigned int addr = cmd >> 28; @@ -1074,92 +585,12 @@ static unsigned int azx_command_addr(u32 cmd) return addr; } -/* send a command */ -static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) -{ - struct azx *chip = bus->private_data; - unsigned int addr = azx_command_addr(val); - unsigned int wp, rp; - - spin_lock_irq(&chip->reg_lock); - - /* add command to corb */ - wp = azx_readw(chip, CORBWP); - if (wp == 0xffff) { - /* something wrong, controller likely turned to D3 */ - spin_unlock_irq(&chip->reg_lock); - return -EIO; - } - wp++; - wp %= AZX_MAX_CORB_ENTRIES; - - rp = azx_readw(chip, CORBRP); - if (wp == rp) { - /* oops, it's full */ - spin_unlock_irq(&chip->reg_lock); - return -EAGAIN; - } - - chip->rirb.cmds[addr]++; - chip->corb.buf[wp] = cpu_to_le32(val); - azx_writew(chip, CORBWP, wp); - - spin_unlock_irq(&chip->reg_lock); - - return 0; -} - -#define AZX_RIRB_EX_UNSOL_EV (1<<4) - -/* retrieve RIRB entry - called from interrupt handler */ -static void azx_update_rirb(struct azx *chip) -{ - unsigned int rp, wp; - unsigned int addr; - u32 res, res_ex; - - wp = azx_readw(chip, RIRBWP); - if (wp == 0xffff) { - /* something wrong, controller likely turned to D3 */ - return; - } - - if (wp == chip->rirb.wp) - return; - chip->rirb.wp = wp; - - while (chip->rirb.rp != wp) { - chip->rirb.rp++; - chip->rirb.rp %= AZX_MAX_RIRB_ENTRIES; - - rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ - res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); - res = le32_to_cpu(chip->rirb.buf[rp]); - addr = res_ex & 0xf; - if ((addr >= AZX_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) { - dev_err(chip->card->dev, "spurious response %#x:%#x, rp = %d, wp = %d", - res, res_ex, - chip->rirb.rp, wp); - snd_BUG(); - } else if (res_ex & AZX_RIRB_EX_UNSOL_EV) - snd_hda_queue_unsol_event(chip->bus, res, res_ex); - else if (chip->rirb.cmds[addr]) { - chip->rirb.res[addr] = res; - smp_wmb(); - chip->rirb.cmds[addr]--; - } else if (printk_ratelimit()) { - dev_err(chip->card->dev, "spurious response %#x:%#x, last cmd=%#08x\n", - res, res_ex, - chip->last_cmd[addr]); - } - } -} - /* receive a response */ -static unsigned int azx_rirb_get_response(struct hda_bus *bus, - unsigned int addr) +static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, + unsigned int *res) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(bus); + struct hda_bus *hbus = &chip->bus; unsigned long timeout; unsigned long loopcounter; int do_poll = 0; @@ -1168,22 +599,21 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, timeout = jiffies + msecs_to_jiffies(1000); for (loopcounter = 0;; loopcounter++) { - if (chip->polling_mode || do_poll) { - spin_lock_irq(&chip->reg_lock); - azx_update_rirb(chip); - spin_unlock_irq(&chip->reg_lock); - } - if (!chip->rirb.cmds[addr]) { - smp_rmb(); - bus->rirb_error = 0; - + spin_lock_irq(&bus->reg_lock); + if (chip->polling_mode || do_poll) + snd_hdac_bus_update_rirb(bus); + if (!bus->rirb.cmds[addr]) { if (!do_poll) chip->poll_count = 0; - return chip->rirb.res[addr]; /* the last value */ + if (res) + *res = bus->rirb.res[addr]; /* the last value */ + spin_unlock_irq(&bus->reg_lock); + return 0; } + spin_unlock_irq(&bus->reg_lock); if (time_after(jiffies, timeout)) break; - if (bus->needs_damn_long_delay || loopcounter > 3000) + if (hbus->needs_damn_long_delay || loopcounter > 3000) msleep(2); /* temporary workaround */ else { udelay(10); @@ -1191,13 +621,13 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, } } - if (bus->no_response_fallback) - return -1; + if (hbus->no_response_fallback) + return -EIO; if (!chip->polling_mode && chip->poll_count < 2) { dev_dbg(chip->card->dev, "azx_get_response timeout, polling the codec once: last cmd=0x%08x\n", - chip->last_cmd[addr]); + bus->last_cmd[addr]); do_poll = 1; chip->poll_count++; goto again; @@ -1207,7 +637,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (!chip->polling_mode) { dev_warn(chip->card->dev, "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n", - chip->last_cmd[addr]); + bus->last_cmd[addr]); chip->polling_mode = 1; goto again; } @@ -1215,12 +645,10 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (chip->msi) { dev_warn(chip->card->dev, "No response from codec, disabling MSI: last cmd=0x%08x\n", - chip->last_cmd[addr]); - if (chip->ops->disable_msi_reset_irq(chip) && - chip->ops->disable_msi_reset_irq(chip) < 0) { - bus->rirb_error = 1; - return -1; - } + bus->last_cmd[addr]); + if (chip->ops->disable_msi_reset_irq && + chip->ops->disable_msi_reset_irq(chip) < 0) + return -EIO; goto again; } @@ -1229,28 +657,24 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, * phase, this is likely an access to a non-existing codec * slot. Better to return an error and reset the system. */ - return -1; + return -EIO; } /* a fatal communication error; need either to reset or to fallback * to the single_cmd mode */ - bus->rirb_error = 1; - if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) { - bus->response_reset = 1; - return -1; /* give a chance to retry */ + if (hbus->allow_bus_reset && !hbus->response_reset && !hbus->in_reset) { + hbus->response_reset = 1; + return -EAGAIN; /* give a chance to retry */ } dev_err(chip->card->dev, "azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n", - chip->last_cmd[addr]); + bus->last_cmd[addr]); chip->single_cmd = 1; - bus->response_reset = 0; - /* release CORB/RIRB */ - azx_free_cmd_io(chip); - /* disable unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_UNSOL); - return -1; + hbus->response_reset = 0; + snd_hdac_bus_stop_cmd_io(bus); + return -EIO; } /* @@ -1272,7 +696,7 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) /* check IRV busy bit */ if (azx_readw(chip, IRS) & AZX_IRS_VALID) { /* reuse rirb.res as the response return value */ - chip->rirb.res[addr] = azx_readl(chip, IR); + azx_bus(chip)->rirb.res[addr] = azx_readl(chip, IR); return 0; } udelay(1); @@ -1280,18 +704,18 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) if (printk_ratelimit()) dev_dbg(chip->card->dev, "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS)); - chip->rirb.res[addr] = -1; + azx_bus(chip)->rirb.res[addr] = -1; return -EIO; } /* send a command */ -static int azx_single_send_cmd(struct hda_bus *bus, u32 val) +static int azx_single_send_cmd(struct hdac_bus *bus, u32 val) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(bus); unsigned int addr = azx_command_addr(val); int timeout = 50; - bus->rirb_error = 0; + bus->last_cmd[azx_command_addr(val)] = val; while (timeout--) { /* check ICB busy bit */ if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) { @@ -1313,11 +737,12 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) } /* receive a response */ -static unsigned int azx_single_get_response(struct hda_bus *bus, - unsigned int addr) +static int azx_single_get_response(struct hdac_bus *bus, unsigned int addr, + unsigned int *res) { - struct azx *chip = bus->private_data; - return chip->rirb.res[addr]; + if (res) + *res = bus->rirb.res[addr]; + return 0; } /* @@ -1328,32 +753,48 @@ static unsigned int azx_single_get_response(struct hda_bus *bus, */ /* send a command */ -static int azx_send_cmd(struct hda_bus *bus, unsigned int val) +static int azx_send_cmd(struct hdac_bus *bus, unsigned int val) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(bus); if (chip->disabled) return 0; - chip->last_cmd[azx_command_addr(val)] = val; if (chip->single_cmd) return azx_single_send_cmd(bus, val); else - return azx_corb_send_cmd(bus, val); + return snd_hdac_bus_send_cmd(bus, val); } /* get a response */ -static unsigned int azx_get_response(struct hda_bus *bus, - unsigned int addr) +static int azx_get_response(struct hdac_bus *bus, unsigned int addr, + unsigned int *res) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(bus); + if (chip->disabled) return 0; if (chip->single_cmd) - return azx_single_get_response(bus, addr); + return azx_single_get_response(bus, addr, res); + else + return azx_rirb_get_response(bus, addr, res); +} + +static int azx_link_power(struct hdac_bus *bus, bool enable) +{ + struct azx *chip = bus_to_azx(bus); + + if (chip->ops->link_power) + return chip->ops->link_power(chip, enable); else - return azx_rirb_get_response(bus, addr); + return -EINVAL; } +static const struct hdac_bus_ops bus_core_ops = { + .command = azx_send_cmd, + .get_response = azx_get_response, + .link_power = azx_link_power, +}; + #ifdef CONFIG_SND_HDA_DSP_LOADER /* * DSP loading code (e.g. for CA0132) @@ -1363,339 +804,132 @@ static unsigned int azx_get_response(struct hda_bus *bus, static struct azx_dev * azx_get_dsp_loader_dev(struct azx *chip) { - return &chip->azx_dev[chip->playback_index_offset]; + struct hdac_bus *bus = azx_bus(chip); + struct hdac_stream *s; + + list_for_each_entry(s, &bus->stream_list, list) + if (s->index == chip->playback_index_offset) + return stream_to_azx_dev(s); + + return NULL; } -static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format, - unsigned int byte_size, - struct snd_dma_buffer *bufp) +int snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format, + unsigned int byte_size, + struct snd_dma_buffer *bufp) { - u32 *bdl; - struct azx *chip = bus->private_data; + struct hdac_bus *bus = &codec->bus->core; + struct azx *chip = bus_to_azx(bus); struct azx_dev *azx_dev; + struct hdac_stream *hstr; + bool saved = false; int err; azx_dev = azx_get_dsp_loader_dev(chip); - - dsp_lock(azx_dev); - spin_lock_irq(&chip->reg_lock); - if (azx_dev->running || azx_dev->locked) { - spin_unlock_irq(&chip->reg_lock); - err = -EBUSY; - goto unlock; + hstr = azx_stream(azx_dev); + spin_lock_irq(&bus->reg_lock); + if (hstr->opened) { + chip->saved_azx_dev = *azx_dev; + saved = true; } - azx_dev->prepared = 0; - chip->saved_azx_dev = *azx_dev; - azx_dev->locked = 1; - spin_unlock_irq(&chip->reg_lock); - - err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV_SG, - byte_size, bufp); - if (err < 0) - goto err_alloc; - - azx_dev->bufsize = byte_size; - azx_dev->period_bytes = byte_size; - azx_dev->format_val = format; - - azx_stream_reset(chip, azx_dev); - - /* reset BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); - azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); - - azx_dev->frags = 0; - bdl = (u32 *)azx_dev->bdl.area; - err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0); - if (err < 0) - goto error; + spin_unlock_irq(&bus->reg_lock); - azx_setup_controller(chip, azx_dev); - dsp_unlock(azx_dev); - return azx_dev->stream_tag; + err = snd_hdac_dsp_prepare(hstr, format, byte_size, bufp); + if (err < 0) { + spin_lock_irq(&bus->reg_lock); + if (saved) + *azx_dev = chip->saved_azx_dev; + spin_unlock_irq(&bus->reg_lock); + return err; + } - error: - chip->ops->dma_free_pages(chip, bufp); - err_alloc: - spin_lock_irq(&chip->reg_lock); - if (azx_dev->opened) - *azx_dev = chip->saved_azx_dev; - azx_dev->locked = 0; - spin_unlock_irq(&chip->reg_lock); - unlock: - dsp_unlock(azx_dev); + hstr->prepared = 0; return err; } +EXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_prepare); -static void azx_load_dsp_trigger(struct hda_bus *bus, bool start) +void snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) { - struct azx *chip = bus->private_data; + struct hdac_bus *bus = &codec->bus->core; + struct azx *chip = bus_to_azx(bus); struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); - if (start) - azx_stream_start(chip, azx_dev); - else - azx_stream_stop(chip, azx_dev); - azx_dev->running = start; + snd_hdac_dsp_trigger(azx_stream(azx_dev), start); } +EXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_trigger); -static void azx_load_dsp_cleanup(struct hda_bus *bus, - struct snd_dma_buffer *dmab) +void snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec, + struct snd_dma_buffer *dmab) { - struct azx *chip = bus->private_data; + struct hdac_bus *bus = &codec->bus->core; + struct azx *chip = bus_to_azx(bus); struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); + struct hdac_stream *hstr = azx_stream(azx_dev); - if (!dmab->area || !azx_dev->locked) + if (!dmab->area || !hstr->locked) return; - dsp_lock(azx_dev); - /* reset BDL address */ - azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); - azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); - azx_sd_writel(chip, azx_dev, SD_CTL, 0); - azx_dev->bufsize = 0; - azx_dev->period_bytes = 0; - azx_dev->format_val = 0; - - chip->ops->dma_free_pages(chip, dmab); - dmab->area = NULL; - - spin_lock_irq(&chip->reg_lock); - if (azx_dev->opened) + snd_hdac_dsp_cleanup(hstr, dmab); + spin_lock_irq(&bus->reg_lock); + if (hstr->opened) *azx_dev = chip->saved_azx_dev; - azx_dev->locked = 0; - spin_unlock_irq(&chip->reg_lock); - dsp_unlock(azx_dev); + hstr->locked = false; + spin_unlock_irq(&bus->reg_lock); } +EXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_cleanup); #endif /* CONFIG_SND_HDA_DSP_LOADER */ -int azx_alloc_stream_pages(struct azx *chip) -{ - int i, err; - - for (i = 0; i < chip->num_streams; i++) { - dsp_lock_init(&chip->azx_dev[i]); - /* allocate memory for the BDL for each stream */ - err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, - BDL_SIZE, - &chip->azx_dev[i].bdl); - if (err < 0) - return -ENOMEM; - } - /* allocate memory for the position buffer */ - err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, - chip->num_streams * 8, &chip->posbuf); - if (err < 0) - return -ENOMEM; - - /* allocate CORB/RIRB */ - err = azx_alloc_cmd_io(chip); - if (err < 0) - return err; - return 0; -} -EXPORT_SYMBOL_GPL(azx_alloc_stream_pages); - -void azx_free_stream_pages(struct azx *chip) -{ - int i; - if (chip->azx_dev) { - for (i = 0; i < chip->num_streams; i++) - if (chip->azx_dev[i].bdl.area) - chip->ops->dma_free_pages( - chip, &chip->azx_dev[i].bdl); - } - if (chip->rb.area) - chip->ops->dma_free_pages(chip, &chip->rb); - if (chip->posbuf.area) - chip->ops->dma_free_pages(chip, &chip->posbuf); -} -EXPORT_SYMBOL_GPL(azx_free_stream_pages); - /* - * Lowlevel interface + * reset and start the controller registers */ - -/* enter link reset */ -void azx_enter_link_reset(struct azx *chip) -{ - unsigned long timeout; - - /* reset controller */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_RESET); - - timeout = jiffies + msecs_to_jiffies(100); - while ((azx_readb(chip, GCTL) & AZX_GCTL_RESET) && - time_before(jiffies, timeout)) - usleep_range(500, 1000); -} -EXPORT_SYMBOL_GPL(azx_enter_link_reset); - -/* exit link reset */ -static void azx_exit_link_reset(struct azx *chip) -{ - unsigned long timeout; - - azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | AZX_GCTL_RESET); - - timeout = jiffies + msecs_to_jiffies(100); - while (!azx_readb(chip, GCTL) && - time_before(jiffies, timeout)) - usleep_range(500, 1000); -} - -/* reset codec link */ -static int azx_reset(struct azx *chip, bool full_reset) -{ - if (!full_reset) - goto __skip; - - /* clear STATESTS */ - azx_writew(chip, STATESTS, STATESTS_INT_MASK); - - /* reset controller */ - azx_enter_link_reset(chip); - - /* delay for >= 100us for codec PLL to settle per spec - * Rev 0.9 section 5.5.1 - */ - usleep_range(500, 1000); - - /* Bring controller out of reset */ - azx_exit_link_reset(chip); - - /* Brent Chartrand said to wait >= 540us for codecs to initialize */ - usleep_range(1000, 1200); - - __skip: - /* check to see if controller is ready */ - if (!azx_readb(chip, GCTL)) { - dev_dbg(chip->card->dev, "azx_reset: controller not ready!\n"); - return -EBUSY; - } - - /* Accept unsolicited responses */ - if (!chip->single_cmd) - azx_writel(chip, GCTL, azx_readl(chip, GCTL) | - AZX_GCTL_UNSOL); - - /* detect codecs */ - if (!chip->codec_mask) { - chip->codec_mask = azx_readw(chip, STATESTS); - dev_dbg(chip->card->dev, "codec_mask = 0x%x\n", - chip->codec_mask); - } - - return 0; -} - -/* enable interrupts */ -static void azx_int_enable(struct azx *chip) -{ - /* enable controller CIE and GIE */ - azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) | - AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); -} - -/* disable interrupts */ -static void azx_int_disable(struct azx *chip) -{ - int i; - - /* disable interrupts in stream descriptor */ - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_sd_writeb(chip, azx_dev, SD_CTL, - azx_sd_readb(chip, azx_dev, SD_CTL) & - ~SD_INT_MASK); - } - - /* disable SIE for all streams */ - azx_writeb(chip, INTCTL, 0); - - /* disable controller CIE and GIE */ - azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) & - ~(AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN)); -} - -/* clear interrupts */ -static void azx_int_clear(struct azx *chip) +void azx_init_chip(struct azx *chip, bool full_reset) { - int i; - - /* clear stream status */ - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); + if (snd_hdac_bus_init_chip(azx_bus(chip), full_reset)) { + /* correct RINTCNT for CXT */ + if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) + azx_writew(chip, RINTCNT, 0xc0); } - - /* clear STATESTS */ - azx_writew(chip, STATESTS, STATESTS_INT_MASK); - - /* clear rirb status */ - azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); - - /* clear int status */ - azx_writel(chip, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM); } +EXPORT_SYMBOL_GPL(azx_init_chip); -/* - * reset and start the controller registers - */ -void azx_init_chip(struct azx *chip, bool full_reset) +void azx_stop_all_streams(struct azx *chip) { - if (chip->initialized) - return; + struct hdac_bus *bus = azx_bus(chip); + struct hdac_stream *s; - /* reset controller */ - azx_reset(chip, full_reset); - - /* initialize interrupts */ - azx_int_clear(chip); - azx_int_enable(chip); - - /* initialize the codec command I/O */ - if (!chip->single_cmd) - azx_init_cmd_io(chip); - - /* program the position buffer */ - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); - azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr)); - - chip->initialized = 1; + list_for_each_entry(s, &bus->stream_list, list) + snd_hdac_stream_stop(s); } -EXPORT_SYMBOL_GPL(azx_init_chip); +EXPORT_SYMBOL_GPL(azx_stop_all_streams); void azx_stop_chip(struct azx *chip) { - if (!chip->initialized) - return; - - /* disable interrupts */ - azx_int_disable(chip); - azx_int_clear(chip); - - /* disable CORB/RIRB */ - azx_free_cmd_io(chip); - - /* disable position buffer */ - azx_writel(chip, DPLBASE, 0); - azx_writel(chip, DPUBASE, 0); - - chip->initialized = 0; + snd_hdac_bus_stop_chip(azx_bus(chip)); } EXPORT_SYMBOL_GPL(azx_stop_chip); /* * interrupt handler */ +static void stream_update(struct hdac_bus *bus, struct hdac_stream *s) +{ + struct azx *chip = bus_to_azx(bus); + struct azx_dev *azx_dev = stream_to_azx_dev(s); + + /* check whether this IRQ is really acceptable */ + if (!chip->ops->position_check || + chip->ops->position_check(chip, azx_dev)) { + spin_unlock(&bus->reg_lock); + snd_pcm_period_elapsed(azx_stream(azx_dev)->substream); + spin_lock(&bus->reg_lock); + } +} + irqreturn_t azx_interrupt(int irq, void *dev_id) { struct azx *chip = dev_id; - struct azx_dev *azx_dev; + struct hdac_bus *bus = azx_bus(chip); u32 status; - u8 sd_status; - int i; #ifdef CONFIG_PM if (azx_has_pm_runtime(chip)) @@ -1703,36 +937,20 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) return IRQ_NONE; #endif - spin_lock(&chip->reg_lock); + spin_lock(&bus->reg_lock); if (chip->disabled) { - spin_unlock(&chip->reg_lock); + spin_unlock(&bus->reg_lock); return IRQ_NONE; } status = azx_readl(chip, INTSTS); if (status == 0 || status == 0xffffffff) { - spin_unlock(&chip->reg_lock); + spin_unlock(&bus->reg_lock); return IRQ_NONE; } - for (i = 0; i < chip->num_streams; i++) { - azx_dev = &chip->azx_dev[i]; - if (status & azx_dev->sd_int_sta_mask) { - sd_status = azx_sd_readb(chip, azx_dev, SD_STS); - azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); - if (!azx_dev->substream || !azx_dev->running || - !(sd_status & SD_INT_COMPLETE)) - continue; - /* check whether this IRQ is really acceptable */ - if (!chip->ops->position_check || - chip->ops->position_check(chip, azx_dev)) { - spin_unlock(&chip->reg_lock); - snd_pcm_period_elapsed(azx_dev->substream); - spin_lock(&chip->reg_lock); - } - } - } + snd_hdac_bus_handle_stream_irq(bus, status, stream_update); /* clear rirb int */ status = azx_readb(chip, RIRBSTS); @@ -1740,12 +958,12 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) if (status & RIRB_INT_RESPONSE) { if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY) udelay(80); - azx_update_rirb(chip); + snd_hdac_bus_update_rirb(bus); } azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } - spin_unlock(&chip->reg_lock); + spin_unlock(&bus->reg_lock); return IRQ_HANDLED; } @@ -1762,29 +980,31 @@ static int probe_codec(struct azx *chip, int addr) { unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; - unsigned int res; + struct hdac_bus *bus = azx_bus(chip); + int err; + unsigned int res = -1; - mutex_lock(&chip->bus->core.cmd_mutex); + mutex_lock(&bus->cmd_mutex); chip->probing = 1; - azx_send_cmd(chip->bus, cmd); - res = azx_get_response(chip->bus, addr); + azx_send_cmd(bus, cmd); + err = azx_get_response(bus, addr, &res); chip->probing = 0; - mutex_unlock(&chip->bus->core.cmd_mutex); - if (res == -1) + mutex_unlock(&bus->cmd_mutex); + if (err < 0 || res == -1) return -EIO; dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr); return 0; } -static void azx_bus_reset(struct hda_bus *bus) +void snd_hda_bus_reset(struct hda_bus *bus) { - struct azx *chip = bus->private_data; + struct azx *chip = bus_to_azx(&bus->core); bus->in_reset = 1; azx_stop_chip(chip); azx_init_chip(chip, true); - if (chip->initialized) - snd_hda_bus_reset(chip->bus); + if (bus->core.chip_init) + snd_hda_bus_reset_codecs(bus); bus->in_reset = 0; } @@ -1809,39 +1029,40 @@ static int get_jackpoll_interval(struct azx *chip) return j; } -static struct hda_bus_ops bus_ops = { - .command = azx_send_cmd, - .get_response = azx_get_response, - .attach_pcm = azx_attach_pcm_stream, - .bus_reset = azx_bus_reset, -#ifdef CONFIG_SND_HDA_DSP_LOADER - .load_dsp_prepare = azx_load_dsp_prepare, - .load_dsp_trigger = azx_load_dsp_trigger, - .load_dsp_cleanup = azx_load_dsp_cleanup, -#endif -}; - /* HD-audio bus initialization */ -int azx_bus_create(struct azx *chip, const char *model) +int azx_bus_init(struct azx *chip, const char *model, + const struct hdac_io_ops *io_ops) { - struct hda_bus *bus; + struct hda_bus *bus = &chip->bus; int err; - err = snd_hda_bus_new(chip->card, &bus); + err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops, + io_ops); if (err < 0) return err; - chip->bus = bus; - bus->private_data = chip; + bus->card = chip->card; + mutex_init(&bus->prepare_mutex); bus->pci = chip->pci; bus->modelname = model; - bus->ops = bus_ops; + bus->mixer_assigned = -1; + bus->core.snoop = azx_snoop(chip); + if (chip->get_position[0] != azx_get_pos_lpib || + chip->get_position[1] != azx_get_pos_lpib) + bus->core.use_posbuf = true; + if (chip->bdl_pos_adj) + bus->core.bdl_pos_adj = chip->bdl_pos_adj[chip->dev_index]; + if (chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR) + bus->core.corbrp_self_clear = true; if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); bus->needs_damn_long_delay = 1; } + if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) + bus->core.align_bdle_4k = true; + /* AMD chipsets often cause the communication stalls upon certain * sequence like the pin-detection. It seems that forcing the synced * access works around the stall. Grrr... @@ -1854,12 +1075,12 @@ int azx_bus_create(struct azx *chip, const char *model) return 0; } -EXPORT_SYMBOL_GPL(azx_bus_create); +EXPORT_SYMBOL_GPL(azx_bus_init); /* Probe codecs */ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) { - struct hda_bus *bus = chip->bus; + struct hdac_bus *bus = azx_bus(chip); int c, codecs, err; codecs = 0; @@ -1868,14 +1089,14 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) /* First try to probe all given codec slots */ for (c = 0; c < max_slots; c++) { - if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { + if ((bus->codec_mask & (1 << c)) & chip->codec_probe_mask) { if (probe_codec(chip, c) < 0) { /* Some BIOSen give you wrong codec addresses * that don't exist */ dev_warn(chip->card->dev, "Codec #%d probe error; disabling it...\n", c); - chip->codec_mask &= ~(1 << c); + bus->codec_mask &= ~(1 << c); /* More badly, accessing to a non-existing * codec often screws up the controller chip, * and disturbs the further communications. @@ -1891,9 +1112,9 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) /* Then create codec instances */ for (c = 0; c < max_slots; c++) { - if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { + if ((bus->codec_mask & (1 << c)) & chip->codec_probe_mask) { struct hda_codec *codec; - err = snd_hda_codec_new(bus, bus->card, c, &codec); + err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec); if (err < 0) continue; codec->jackpoll_interval = get_jackpoll_interval(chip); @@ -1913,40 +1134,39 @@ EXPORT_SYMBOL_GPL(azx_probe_codecs); int azx_codec_configure(struct azx *chip) { struct hda_codec *codec; - list_for_each_codec(codec, chip->bus) { + list_for_each_codec(codec, &chip->bus) { snd_hda_codec_configure(codec); } return 0; } EXPORT_SYMBOL_GPL(azx_codec_configure); - -static bool is_input_stream(struct azx *chip, unsigned char index) +static int stream_direction(struct azx *chip, unsigned char index) { - return (index >= chip->capture_index_offset && - index < chip->capture_index_offset + chip->capture_streams); + if (index >= chip->capture_index_offset && + index < chip->capture_index_offset + chip->capture_streams) + return SNDRV_PCM_STREAM_CAPTURE; + return SNDRV_PCM_STREAM_PLAYBACK; } /* initialize SD streams */ -int azx_init_stream(struct azx *chip) +int azx_init_streams(struct azx *chip) { int i; - int in_stream_tag = 0; - int out_stream_tag = 0; + int stream_tags[2] = { 0, 0 }; /* initialize each stream (aka device) * assign the starting bdl address to each stream (device) * and initialize */ for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); - /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ - azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); - /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ - azx_dev->sd_int_sta_mask = 1 << i; - azx_dev->index = i; + struct azx_dev *azx_dev = kzalloc(sizeof(*azx_dev), GFP_KERNEL); + int dir, tag; + + if (!azx_dev) + return -ENOMEM; + dir = stream_direction(chip, i); /* stream tag must be unique throughout * the stream direction group, * valid values 1...15 @@ -1954,17 +1174,26 @@ int azx_init_stream(struct azx *chip) * AZX_DCAPS_SEPARATE_STREAM_TAG is used */ if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) - azx_dev->stream_tag = - is_input_stream(chip, i) ? - ++in_stream_tag : - ++out_stream_tag; + tag = ++stream_tags[dir]; else - azx_dev->stream_tag = i + 1; + tag = i + 1; + snd_hdac_stream_init(azx_bus(chip), azx_stream(azx_dev), + i, dir, tag); } return 0; } -EXPORT_SYMBOL_GPL(azx_init_stream); +EXPORT_SYMBOL_GPL(azx_init_streams); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Common HDA driver functions"); +void azx_free_streams(struct azx *chip) +{ + struct hdac_bus *bus = azx_bus(chip); + struct hdac_stream *s; + + while (!list_empty(&bus->stream_list)) { + s = list_first_entry(&bus->stream_list, struct hdac_stream, list); + list_del(&s->list); + kfree(stream_to_azx_dev(s)); + } +} +EXPORT_SYMBOL_GPL(azx_free_streams); diff --git a/kernel/sound/pci/hda/hda_controller.h b/kernel/sound/pci/hda/hda_controller.h index 0efdb094d..7b635d68c 100644 --- a/kernel/sound/pci/hda/hda_controller.h +++ b/kernel/sound/pci/hda/hda_controller.h @@ -21,135 +21,10 @@ #include <sound/pcm.h> #include <sound/initval.h> #include "hda_codec.h" +#include <sound/hda_register.h> -/* - * registers - */ -#define AZX_REG_GCAP 0x00 -#define AZX_GCAP_64OK (1 << 0) /* 64bit address support */ -#define AZX_GCAP_NSDO (3 << 1) /* # of serial data out signals */ -#define AZX_GCAP_BSS (31 << 3) /* # of bidirectional streams */ -#define AZX_GCAP_ISS (15 << 8) /* # of input streams */ -#define AZX_GCAP_OSS (15 << 12) /* # of output streams */ -#define AZX_REG_VMIN 0x02 -#define AZX_REG_VMAJ 0x03 -#define AZX_REG_OUTPAY 0x04 -#define AZX_REG_INPAY 0x06 -#define AZX_REG_GCTL 0x08 -#define AZX_GCTL_RESET (1 << 0) /* controller reset */ -#define AZX_GCTL_FCNTRL (1 << 1) /* flush control */ -#define AZX_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ -#define AZX_REG_WAKEEN 0x0c -#define AZX_REG_STATESTS 0x0e -#define AZX_REG_GSTS 0x10 -#define AZX_GSTS_FSTS (1 << 1) /* flush status */ -#define AZX_REG_INTCTL 0x20 -#define AZX_REG_INTSTS 0x24 -#define AZX_REG_WALLCLK 0x30 /* 24Mhz source */ -#define AZX_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ -#define AZX_REG_SSYNC 0x38 -#define AZX_REG_CORBLBASE 0x40 -#define AZX_REG_CORBUBASE 0x44 -#define AZX_REG_CORBWP 0x48 -#define AZX_REG_CORBRP 0x4a -#define AZX_CORBRP_RST (1 << 15) /* read pointer reset */ -#define AZX_REG_CORBCTL 0x4c -#define AZX_CORBCTL_RUN (1 << 1) /* enable DMA */ -#define AZX_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ -#define AZX_REG_CORBSTS 0x4d -#define AZX_CORBSTS_CMEI (1 << 0) /* memory error indication */ -#define AZX_REG_CORBSIZE 0x4e - -#define AZX_REG_RIRBLBASE 0x50 -#define AZX_REG_RIRBUBASE 0x54 -#define AZX_REG_RIRBWP 0x58 -#define AZX_RIRBWP_RST (1 << 15) /* write pointer reset */ -#define AZX_REG_RINTCNT 0x5a -#define AZX_REG_RIRBCTL 0x5c -#define AZX_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ -#define AZX_RBCTL_DMA_EN (1 << 1) /* enable DMA */ -#define AZX_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ -#define AZX_REG_RIRBSTS 0x5d -#define AZX_RBSTS_IRQ (1 << 0) /* response irq */ -#define AZX_RBSTS_OVERRUN (1 << 2) /* overrun irq */ -#define AZX_REG_RIRBSIZE 0x5e - -#define AZX_REG_IC 0x60 -#define AZX_REG_IR 0x64 -#define AZX_REG_IRS 0x68 -#define AZX_IRS_VALID (1<<1) -#define AZX_IRS_BUSY (1<<0) - -#define AZX_REG_DPLBASE 0x70 -#define AZX_REG_DPUBASE 0x74 -#define AZX_DPLBASE_ENABLE 0x1 /* Enable position buffer */ - -/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ -enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; - -/* stream register offsets from stream base */ -#define AZX_REG_SD_CTL 0x00 -#define AZX_REG_SD_STS 0x03 -#define AZX_REG_SD_LPIB 0x04 -#define AZX_REG_SD_CBL 0x08 -#define AZX_REG_SD_LVI 0x0c -#define AZX_REG_SD_FIFOW 0x0e -#define AZX_REG_SD_FIFOSIZE 0x10 -#define AZX_REG_SD_FORMAT 0x12 -#define AZX_REG_SD_BDLPL 0x18 -#define AZX_REG_SD_BDLPU 0x1c - -/* PCI space */ -#define AZX_PCIREG_TCSEL 0x44 - -/* - * other constants - */ - -/* max number of fragments - we may use more if allocating more pages for BDL */ -#define BDL_SIZE 4096 -#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) -#define AZX_MAX_FRAG 32 -/* max buffer size - no h/w limit, you can increase as you like */ -#define AZX_MAX_BUF_SIZE (1024*1024*1024) - -/* RIRB int mask: overrun[2], response[0] */ -#define RIRB_INT_RESPONSE 0x01 -#define RIRB_INT_OVERRUN 0x04 -#define RIRB_INT_MASK 0x05 - -/* STATESTS int mask: S3,SD2,SD1,SD0 */ -#define AZX_MAX_CODECS 8 +#define AZX_MAX_CODECS HDA_MAX_CODECS #define AZX_DEFAULT_CODECS 4 -#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) - -/* SD_CTL bits */ -#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ -#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ -#define SD_CTL_STRIPE (3 << 16) /* stripe control */ -#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */ -#define SD_CTL_DIR (1 << 19) /* bi-directional stream */ -#define SD_CTL_STREAM_TAG_MASK (0xf << 20) -#define SD_CTL_STREAM_TAG_SHIFT 20 - -/* SD_CTL and SD_STS */ -#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ -#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ -#define SD_INT_COMPLETE 0x04 /* completion interrupt */ -#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ - SD_INT_COMPLETE) - -/* SD_STS */ -#define SD_STS_FIFO_READY 0x20 /* FIFO ready */ - -/* INTCTL and INTSTS */ -#define AZX_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define AZX_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define AZX_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ - -/* below are so far hardcoded - should read registers in future */ -#define AZX_MAX_CORB_ENTRIES 256 -#define AZX_MAX_RIRB_ENTRIES 256 /* driver quirks (capabilities) */ /* bits 0-7 are used for indicating driver type */ @@ -183,40 +58,10 @@ enum { AZX_SNOOP_TYPE_NVIDIA, }; -/* HD Audio class code */ -#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 - struct azx_dev { - struct snd_dma_buffer bdl; /* BDL buffer */ - u32 *posbuf; /* position buffer pointer */ - - unsigned int bufsize; /* size of the play buffer in bytes */ - unsigned int period_bytes; /* size of the period in bytes */ - unsigned int frags; /* number for period in the play buffer */ - unsigned int fifo_size; /* FIFO size */ - unsigned long start_wallclk; /* start + minimum wallclk */ - unsigned long period_wallclk; /* wallclk for period */ - - void __iomem *sd_addr; /* stream descriptor pointer */ - - u32 sd_int_sta_mask; /* stream int status mask */ - - /* pcm support */ - struct snd_pcm_substream *substream; /* assigned substream, - * set in PCM open - */ - unsigned int format_val; /* format value to be set in the - * controller and the codec - */ - unsigned char stream_tag; /* assigned stream */ - unsigned char index; /* stream index */ - int assigned_key; /* last device# key assigned to */ - - unsigned int opened:1; - unsigned int running:1; + struct hdac_stream core; + unsigned int irq_pending:1; - unsigned int prepared:1; - unsigned int locked:1; /* * For VIA: * A flag to ensure DMA position is 0 @@ -224,50 +69,17 @@ struct azx_dev { */ unsigned int insufficient:1; unsigned int wc_marked:1; - unsigned int no_period_wakeup:1; - - struct timecounter azx_tc; - struct cyclecounter azx_cc; - - int delay_negative_threshold; - -#ifdef CONFIG_SND_HDA_DSP_LOADER - /* Allows dsp load to have sole access to the playback stream. */ - struct mutex dsp_mutex; -#endif }; -/* CORB/RIRB */ -struct azx_rb { - u32 *buf; /* CORB/RIRB buffer - * Each CORB entry is 4byte, RIRB is 8byte - */ - dma_addr_t addr; /* physical address of CORB/RIRB buffer */ - /* for RIRB */ - unsigned short rp, wp; /* read/write pointers */ - int cmds[AZX_MAX_CODECS]; /* number of pending requests */ - u32 res[AZX_MAX_CODECS]; /* last read value */ -}; +#define azx_stream(dev) (&(dev)->core) +#define stream_to_azx_dev(s) container_of(s, struct azx_dev, core) struct azx; /* Functions to read/write to hda registers. */ struct hda_controller_ops { - /* Register Access */ - void (*reg_writel)(u32 value, u32 __iomem *addr); - u32 (*reg_readl)(u32 __iomem *addr); - void (*reg_writew)(u16 value, u16 __iomem *addr); - u16 (*reg_readw)(u16 __iomem *addr); - void (*reg_writeb)(u8 value, u8 __iomem *addr); - u8 (*reg_readb)(u8 __iomem *addr); /* Disable msi if supported, PCI only */ int (*disable_msi_reset_irq)(struct azx *); - /* Allocation ops */ - int (*dma_alloc_pages)(struct azx *chip, - int type, - size_t size, - struct snd_dma_buffer *buf); - void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf); int (*substream_alloc_pages)(struct azx *chip, struct snd_pcm_substream *substream, size_t size); @@ -277,6 +89,8 @@ struct hda_controller_ops { struct vm_area_struct *area); /* Check if current position is acceptable */ int (*position_check)(struct azx *chip, struct azx_dev *azx_dev); + /* enable/disable the link power */ + int (*link_power)(struct azx *chip, bool enable); }; struct azx_pcm { @@ -291,6 +105,8 @@ typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *); typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos); struct azx { + struct hda_bus bus; + struct snd_card *card; struct pci_dev *pci; int dev_index; @@ -312,35 +128,16 @@ struct azx { azx_get_pos_callback_t get_position[2]; azx_get_delay_callback_t get_delay[2]; - /* pci resources */ - unsigned long addr; - void __iomem *remap_addr; - int irq; - /* locks */ - spinlock_t reg_lock; struct mutex open_mutex; /* Prevents concurrent open/close operations */ - /* streams (x num_streams) */ - struct azx_dev *azx_dev; - /* PCM */ struct list_head pcm_list; /* azx_pcm list */ /* HD codec */ - unsigned short codec_mask; int codec_probe_mask; /* copied from probe_mask option */ - struct hda_bus *bus; unsigned int beep_mode; - /* CORB/RIRB */ - struct azx_rb corb; - struct azx_rb rirb; - - /* CORB/RIRB and position buffers */ - struct snd_dma_buffer rb; - struct snd_dma_buffer posbuf; - #ifdef CONFIG_SND_HDA_PATCH_LOADER const struct firmware *fw; #endif @@ -349,7 +146,6 @@ struct azx { const int *bdl_pos_adj; int poll_count; unsigned int running:1; - unsigned int initialized:1; unsigned int single_cmd:1; unsigned int polling_mode:1; unsigned int msi:1; @@ -357,16 +153,16 @@ struct azx { unsigned int snoop:1; unsigned int align_buffer_size:1; unsigned int region_requested:1; - unsigned int disabled:1; /* disabled by VGA-switcher */ - - /* for debugging */ - unsigned int last_cmd[AZX_MAX_CODECS]; + unsigned int disabled:1; /* disabled by vga_switcheroo */ #ifdef CONFIG_SND_HDA_DSP_LOADER struct azx_dev saved_azx_dev; #endif }; +#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 @@ -378,30 +174,17 @@ struct azx { */ #define azx_writel(chip, reg, value) \ - ((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg)) + snd_hdac_chip_writel(azx_bus(chip), reg, value) #define azx_readl(chip, reg) \ - ((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg)) + snd_hdac_chip_readl(azx_bus(chip), reg) #define azx_writew(chip, reg, value) \ - ((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg)) + snd_hdac_chip_writew(azx_bus(chip), reg, value) #define azx_readw(chip, reg) \ - ((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg)) + snd_hdac_chip_readw(azx_bus(chip), reg) #define azx_writeb(chip, reg, value) \ - ((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg)) + snd_hdac_chip_writeb(azx_bus(chip), reg, value) #define azx_readb(chip, reg) \ - ((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg)) - -#define azx_sd_writel(chip, dev, reg, value) \ - ((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_readl(chip, dev, reg) \ - ((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_writew(chip, dev, reg, value) \ - ((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_readw(chip, dev, reg) \ - ((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_writeb(chip, dev, reg, value) \ - ((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_readb(chip, dev, reg) \ - ((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg)) + snd_hdac_chip_readb(azx_bus(chip), reg) #define azx_has_pm_runtime(chip) \ ((chip)->driver_caps & AZX_DCAPS_PM_RUNTIME) @@ -416,22 +199,27 @@ unsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev); unsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev); /* Stream control. */ -void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev); +void azx_stop_all_streams(struct azx *chip); /* Allocation functions. */ -int azx_alloc_stream_pages(struct azx *chip); -void azx_free_stream_pages(struct azx *chip); +#define azx_alloc_stream_pages(chip) \ + snd_hdac_bus_alloc_stream_pages(azx_bus(chip)) +#define azx_free_stream_pages(chip) \ + snd_hdac_bus_free_stream_pages(azx_bus(chip)) /* Low level azx interface */ void azx_init_chip(struct azx *chip, bool full_reset); void azx_stop_chip(struct azx *chip); -void azx_enter_link_reset(struct azx *chip); +#define azx_enter_link_reset(chip) \ + snd_hdac_bus_enter_link_reset(azx_bus(chip)) irqreturn_t azx_interrupt(int irq, void *dev_id); /* Codec interface */ -int azx_bus_create(struct azx *chip, const char *model); +int azx_bus_init(struct azx *chip, const char *model, + const struct hdac_io_ops *io_ops); int azx_probe_codecs(struct azx *chip, unsigned int max_slots); int azx_codec_configure(struct azx *chip); -int azx_init_stream(struct azx *chip); +int azx_init_streams(struct azx *chip); +void azx_free_streams(struct azx *chip); #endif /* __SOUND_HDA_CONTROLLER_H */ diff --git a/kernel/sound/pci/hda/hda_controller_trace.h b/kernel/sound/pci/hda/hda_controller_trace.h new file mode 100644 index 000000000..3e18d99bf --- /dev/null +++ b/kernel/sound/pci/hda/hda_controller_trace.h @@ -0,0 +1,98 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hda_controller +#define TRACE_INCLUDE_FILE hda_controller_trace + +#if !defined(_TRACE_HDA_CONTROLLER_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HDA_CONTROLLER_H + +#include <linux/tracepoint.h> + +struct azx; +struct azx_dev; + +TRACE_EVENT(azx_pcm_trigger, + + TP_PROTO(struct azx *chip, struct azx_dev *dev, int cmd), + + TP_ARGS(chip, dev, cmd), + + TP_STRUCT__entry( + __field( int, card ) + __field( int, idx ) + __field( int, cmd ) + ), + + TP_fast_assign( + __entry->card = (chip)->card->number; + __entry->idx = (dev)->core.index; + __entry->cmd = cmd; + ), + + TP_printk("[%d:%d] cmd=%d", __entry->card, __entry->idx, __entry->cmd) +); + +TRACE_EVENT(azx_get_position, + + TP_PROTO(struct azx *chip, struct azx_dev *dev, unsigned int pos, unsigned int delay), + + TP_ARGS(chip, dev, pos, delay), + + TP_STRUCT__entry( + __field( int, card ) + __field( int, idx ) + __field( unsigned int, pos ) + __field( unsigned int, delay ) + ), + + TP_fast_assign( + __entry->card = (chip)->card->number; + __entry->idx = (dev)->core.index; + __entry->pos = pos; + __entry->delay = delay; + ), + + TP_printk("[%d:%d] pos=%u, delay=%u", __entry->card, __entry->idx, __entry->pos, __entry->delay) +); + +DECLARE_EVENT_CLASS(azx_pcm, + TP_PROTO(struct azx *chip, struct azx_dev *azx_dev), + + TP_ARGS(chip, azx_dev), + + TP_STRUCT__entry( + __field( unsigned char, stream_tag ) + ), + + TP_fast_assign( + __entry->stream_tag = (azx_dev)->core.stream_tag; + ), + + TP_printk("stream_tag: %d", __entry->stream_tag) +); + +DEFINE_EVENT(azx_pcm, azx_pcm_open, + TP_PROTO(struct azx *chip, struct azx_dev *azx_dev), + TP_ARGS(chip, azx_dev) +); + +DEFINE_EVENT(azx_pcm, azx_pcm_close, + TP_PROTO(struct azx *chip, struct azx_dev *azx_dev), + TP_ARGS(chip, azx_dev) +); + +DEFINE_EVENT(azx_pcm, azx_pcm_hw_params, + TP_PROTO(struct azx *chip, struct azx_dev *azx_dev), + TP_ARGS(chip, azx_dev) +); + +DEFINE_EVENT(azx_pcm, azx_pcm_prepare, + TP_PROTO(struct azx *chip, struct azx_dev *azx_dev), + TP_ARGS(chip, azx_dev) +); + +#endif /* _TRACE_HDA_CONTROLLER_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include <trace/define_trace.h> diff --git a/kernel/sound/pci/hda/hda_eld.c b/kernel/sound/pci/hda/hda_eld.c index 0e6d7534f..563984dd2 100644 --- a/kernel/sound/pci/hda/hda_eld.c +++ b/kernel/sound/pci/hda/hda_eld.c @@ -42,7 +42,7 @@ enum cea_edid_versions { CEA_EDID_VER_RESERVED = 4, }; -static char *cea_speaker_allocation_names[] = { +static const char * const cea_speaker_allocation_names[] = { /* 0 */ "FL/FR", /* 1 */ "LFE", /* 2 */ "FC", @@ -56,7 +56,7 @@ static char *cea_speaker_allocation_names[] = { /* 10 */ "FCH", }; -static char *eld_connection_type_names[4] = { +static const char * const eld_connection_type_names[4] = { "HDMI", "DisplayPort", "2-reserved", @@ -94,7 +94,7 @@ enum cea_audio_coding_xtypes { AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, }; -static char *cea_audio_coding_type_names[] = { +static const char * const cea_audio_coding_type_names[] = { /* 0 */ "undefined", /* 1 */ "LPCM", /* 2 */ "AC-3", @@ -448,7 +448,7 @@ void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e) hdmi_show_short_audio_desc(codec, e->sad + i); } -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS static void hdmi_print_sad_info(int i, struct cea_sad *a, struct snd_info_buffer *buffer) @@ -482,14 +482,14 @@ void snd_hdmi_print_eld_info(struct hdmi_eld *eld, struct parsed_hdmi_eld *e = &eld->info; char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; - static char *eld_version_names[32] = { + static const char * const eld_version_names[32] = { "reserved", "reserved", "CEA-861D or below", [3 ... 30] = "reserved", [31] = "partial" }; - static char *cea_edid_version_names[8] = { + static const char * const cea_edid_version_names[8] = { "no CEA EDID Timing Extension block present", "CEA-861", "CEA-861-A", @@ -586,7 +586,7 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld, } } } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ /* update PCM info based on ELD */ void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, diff --git a/kernel/sound/pci/hda/hda_generic.c b/kernel/sound/pci/hda/hda_generic.c index 5bc7f2e27..5c4fa8eba 100644 --- a/kernel/sound/pci/hda/hda_generic.c +++ b/kernel/sound/pci/hda/hda_generic.c @@ -771,9 +771,6 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps; unsigned int mask, val; - if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) - return; - caps = query_amp_caps(codec, nid, dir); val = get_amp_val_to_activate(codec, nid, dir, caps, enable); mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); @@ -784,12 +781,22 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, update_amp(codec, nid, dir, idx, mask, val); } +static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int idx_to_check, + bool enable) +{ + /* check whether the given amp is still used by others */ + if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) + return; + activate_amp(codec, nid, dir, idx, idx_to_check, enable); +} + static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, int i, bool enable) { hda_nid_t nid = path->path[i]; init_amp(codec, nid, HDA_OUTPUT, 0); - activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); + check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); } static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, @@ -817,9 +824,16 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, * when aa-mixer is available, we need to enable the path as well */ for (n = 0; n < nums; n++) { - if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid)) - continue; - activate_amp(codec, nid, HDA_INPUT, n, idx, enable); + if (n != idx) { + if (conn[n] != spec->mixer_merge_nid) + continue; + /* when aamix is disabled, force to off */ + if (!add_aamix) { + activate_amp(codec, nid, HDA_INPUT, n, n, false); + continue; + } + } + check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable); } } @@ -1580,6 +1594,12 @@ static bool map_singles(struct hda_codec *codec, int outs, return found; } +static inline bool has_aamix_out_paths(struct hda_gen_spec *spec) +{ + return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || + spec->aamix_out_paths[2]; +} + /* create a new path including aamix if available, and return its index */ static int check_aamix_out_path(struct hda_codec *codec, int path_idx) { @@ -2422,25 +2442,51 @@ static void update_aamix_paths(struct hda_codec *codec, bool do_mix, } } +/* re-initialize the output paths; only called from loopback_mixing_put() */ +static void update_output_paths(struct hda_codec *codec, int num_outs, + const int *paths) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + int i; + + for (i = 0; i < num_outs; i++) { + path = snd_hda_get_path_from_idx(codec, paths[i]); + if (path) + snd_hda_activate_path(codec, path, path->active, + spec->aamix_mode); + } +} + static int loopback_mixing_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_gen_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int val = ucontrol->value.enumerated.item[0]; if (val == spec->aamix_mode) return 0; spec->aamix_mode = val; - update_aamix_paths(codec, val, spec->out_paths[0], - spec->aamix_out_paths[0], - spec->autocfg.line_out_type); - update_aamix_paths(codec, val, spec->hp_paths[0], - spec->aamix_out_paths[1], - AUTO_PIN_HP_OUT); - update_aamix_paths(codec, val, spec->speaker_paths[0], - spec->aamix_out_paths[2], - AUTO_PIN_SPEAKER_OUT); + if (has_aamix_out_paths(spec)) { + update_aamix_paths(codec, val, spec->out_paths[0], + spec->aamix_out_paths[0], + cfg->line_out_type); + update_aamix_paths(codec, val, spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + update_aamix_paths(codec, val, spec->speaker_paths[0], + spec->aamix_out_paths[2], + AUTO_PIN_SPEAKER_OUT); + } else { + update_output_paths(codec, cfg->line_outs, spec->out_paths); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + update_output_paths(codec, cfg->hp_outs, spec->hp_paths); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + update_output_paths(codec, cfg->speaker_outs, + spec->speaker_paths); + } return 1; } @@ -2458,12 +2504,13 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec) if (!spec->mixer_nid) return 0; - if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || - spec->aamix_out_paths[2])) - return 0; if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) return -ENOMEM; spec->have_aamix_ctl = 1; + /* if no explicit aamix path is present (e.g. for Realtek codecs), + * enable aamix as default -- just for compatibility + */ + spec->aamix_mode = !has_aamix_out_paths(spec); return 0; } @@ -3998,9 +4045,9 @@ static void pin_power_callback(struct hda_codec *codec, struct hda_jack_callback *jack, bool on) { - if (jack && jack->tbl->nid) + if (jack && jack->nid) sync_power_state_change(codec, - set_pin_power_jack(codec, jack->tbl->nid, on)); + set_pin_power_jack(codec, jack->nid, on)); } /* callback only doing power up -- called at first */ @@ -5172,7 +5219,7 @@ static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, int err = 0; mutex_lock(&spec->pcm_mutex); - if (!spec->indep_hp_enabled) + if (spec->indep_hp && !spec->indep_hp_enabled) err = -EBUSY; else spec->active_streams |= 1 << STREAM_INDEP_HP; @@ -5664,6 +5711,8 @@ static void init_aamix_paths(struct hda_codec *codec) if (!spec->have_aamix_ctl) return; + if (!has_aamix_out_paths(spec)) + return; update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0], spec->aamix_out_paths[0], spec->autocfg.line_out_type); @@ -5877,13 +5926,14 @@ error: return err; } -static const struct hda_codec_preset snd_hda_preset_generic[] = { - { .id = HDA_CODEC_ID_GENERIC, .patch = snd_hda_parse_generic_codec }, +static const struct hda_device_id snd_hda_id_generic[] = { + HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec), {} /* terminator */ }; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic); static struct hda_codec_driver generic_driver = { - .preset = snd_hda_preset_generic, + .id = snd_hda_id_generic, }; module_hda_codec_driver(generic_driver); diff --git a/kernel/sound/pci/hda/hda_i915.c b/kernel/sound/pci/hda/hda_i915.c deleted file mode 100644 index 3052a2b09..000000000 --- a/kernel/sound/pci/hda/hda_i915.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * hda_i915.c - routines for Haswell HDA controller power well support - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/component.h> -#include <drm/i915_component.h> -#include <sound/core.h> -#include "hda_controller.h" -#include "hda_intel.h" - -/* Intel HSW/BDW display HDA controller Extended Mode registers. - * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display - * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N - * The values will be lost when the display power well is disabled. - */ -#define AZX_REG_EM4 0x100c -#define AZX_REG_EM5 0x1010 - -int hda_display_power(struct hda_intel *hda, bool enable) -{ - struct i915_audio_component *acomp = &hda->audio_component; - - if (!acomp->ops) - return -ENODEV; - - dev_dbg(&hda->chip.pci->dev, "display power %s\n", - enable ? "enable" : "disable"); - if (enable) - acomp->ops->get_power(acomp->dev); - else - acomp->ops->put_power(acomp->dev); - - return 0; -} - -void haswell_set_bclk(struct hda_intel *hda) -{ - int cdclk_freq; - unsigned int bclk_m, bclk_n; - struct i915_audio_component *acomp = &hda->audio_component; - struct pci_dev *pci = hda->chip.pci; - - /* Only Haswell/Broadwell need set BCLK */ - if (pci->device != 0x0a0c && pci->device != 0x0c0c - && pci->device != 0x0d0c && pci->device != 0x160c) - return; - - if (!acomp->ops) - return; - - cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); - switch (cdclk_freq) { - case 337500: - bclk_m = 16; - bclk_n = 225; - break; - - case 450000: - default: /* default CDCLK 450MHz */ - bclk_m = 4; - bclk_n = 75; - break; - - case 540000: - bclk_m = 4; - bclk_n = 90; - break; - - case 675000: - bclk_m = 8; - bclk_n = 225; - break; - } - - azx_writew(&hda->chip, EM4, bclk_m); - azx_writew(&hda->chip, EM5, bclk_n); -} - -static int hda_component_master_bind(struct device *dev) -{ - struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - struct i915_audio_component *acomp = &hda->audio_component; - int ret; - - ret = component_bind_all(dev, acomp); - if (ret < 0) - return ret; - - if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power && - acomp->ops->put_power && acomp->ops->get_cdclk_freq))) { - ret = -EINVAL; - goto out_unbind; - } - - /* - * Atm, we don't support dynamic unbinding initiated by the child - * component, so pin its containing module until we unbind. - */ - if (!try_module_get(acomp->ops->owner)) { - ret = -ENODEV; - goto out_unbind; - } - - return 0; - -out_unbind: - component_unbind_all(dev, acomp); - - return ret; -} - -static void hda_component_master_unbind(struct device *dev) -{ - struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - struct i915_audio_component *acomp = &hda->audio_component; - - module_put(acomp->ops->owner); - component_unbind_all(dev, acomp); - WARN_ON(acomp->ops || acomp->dev); -} - -static const struct component_master_ops hda_component_master_ops = { - .bind = hda_component_master_bind, - .unbind = hda_component_master_unbind, -}; - -static int hda_component_master_match(struct device *dev, void *data) -{ - /* i915 is the only supported component */ - return !strcmp(dev->driver->name, "i915"); -} - -int hda_i915_init(struct hda_intel *hda) -{ - struct component_match *match = NULL; - struct device *dev = &hda->chip.pci->dev; - struct i915_audio_component *acomp = &hda->audio_component; - int ret; - - component_match_add(dev, &match, hda_component_master_match, hda); - ret = component_master_add_with_match(dev, &hda_component_master_ops, - match); - if (ret < 0) - goto out_err; - - /* - * Atm, we don't support deferring the component binding, so make sure - * i915 is loaded and that the binding successfully completes. - */ - request_module("i915"); - - if (!acomp->ops) { - ret = -ENODEV; - goto out_master_del; - } - - dev_dbg(dev, "bound to i915 component master\n"); - - return 0; -out_master_del: - component_master_del(dev, &hda_component_master_ops); -out_err: - dev_err(dev, "failed to add i915 component master (%d)\n", ret); - - return ret; -} - -int hda_i915_exit(struct hda_intel *hda) -{ - struct device *dev = &hda->chip.pci->dev; - - component_master_del(dev, &hda_component_master_ops); - - return 0; -} diff --git a/kernel/sound/pci/hda/hda_intel.c b/kernel/sound/pci/hda/hda_intel.c index 44dfc7b92..2ff692dd2 100644 --- a/kernel/sound/pci/hda/hda_intel.c +++ b/kernel/sound/pci/hda/hda_intel.c @@ -57,6 +57,8 @@ #endif #include <sound/core.h> #include <sound/initval.h> +#include <sound/hdaudio.h> +#include <sound/hda_i915.h> #include <linux/vgaarb.h> #include <linux/vga_switcheroo.h> #include <linux/firmware.h> @@ -64,6 +66,9 @@ #include "hda_controller.h" #include "hda_intel.h" +#define CREATE_TRACE_POINTS +#include "hda_intel_trace.h" + /* position fix mode */ enum { POS_FIX_AUTO, @@ -85,6 +90,8 @@ enum { #define NVIDIA_HDA_ENABLE_COHBIT 0x01 /* Defines for Intel SCH HDA snoop control */ +#define INTEL_HDA_CGCTL 0x48 +#define INTEL_HDA_CGCTL_MISCBDCGE (0x1 << 6) #define INTEL_SCH_HDA_DEVC 0x78 #define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) @@ -166,7 +173,7 @@ MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " #ifdef CONFIG_PM static int param_set_xint(const char *val, const struct kernel_param *kp); -static struct kernel_param_ops param_ops_xint = { +static const struct kernel_param_ops param_ops_xint = { .set = param_set_xint, .get = param_get_int, }; @@ -307,6 +314,10 @@ enum { (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\ AZX_DCAPS_I915_POWERWELL) +#define AZX_DCAPS_INTEL_BROXTON \ + (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\ + AZX_DCAPS_I915_POWERWELL) + /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB |\ @@ -329,10 +340,11 @@ enum { #define AZX_DCAPS_PRESET_CTHDA \ (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB |\ + AZX_DCAPS_NO_64BIT |\ AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF) /* - * VGA-switcher support + * vga_switcheroo support */ #ifdef SUPPORT_VGA_SWITCHEROO #define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo) @@ -345,6 +357,11 @@ enum { ((pci)->device == 0x0d0c) || \ ((pci)->device == 0x160c)) +#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170) +#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70) +#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) +#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) + static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", @@ -496,11 +513,54 @@ static void azx_init_pci(struct azx *chip) } } +/* + * In BXT-P A0, HD-Audio DMA requests is later than expected, + * and makes an audio stream sensitive to system latencies when + * 24/32 bits are playing. + * Adjusting threshold of DMA fifo to force the DMA request + * sooner to improve latency tolerance at the expense of power. + */ +static void bxt_reduce_dma_latency(struct azx *chip) +{ + u32 val; + + val = azx_readl(chip, SKL_EM4L); + val &= (0x3 << 20); + azx_writel(chip, SKL_EM4L, val); +} + +static void hda_intel_init_chip(struct azx *chip, bool full_reset) +{ + struct hdac_bus *bus = azx_bus(chip); + struct pci_dev *pci = chip->pci; + u32 val; + + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + snd_hdac_set_codec_wakeup(bus, true); + if (IS_SKL_PLUS(pci)) { + pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); + val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; + pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); + } + azx_init_chip(chip, full_reset); + if (IS_SKL_PLUS(pci)) { + pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); + val = val | INTEL_HDA_CGCTL_MISCBDCGE; + pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); + } + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + snd_hdac_set_codec_wakeup(bus, false); + + /* reduce dma latency to avoid noise */ + if (IS_BXT(pci)) + bxt_reduce_dma_latency(chip); +} + /* calculate runtime delay from LPIB */ static int azx_get_delay_from_lpib(struct azx *chip, struct azx_dev *azx_dev, unsigned int pos) { - struct snd_pcm_substream *substream = azx_dev->substream; + struct snd_pcm_substream *substream = azx_dev->core.substream; int stream = substream->stream; unsigned int lpib_pos = azx_get_pos_lpib(chip, azx_dev); int delay; @@ -510,16 +570,16 @@ static int azx_get_delay_from_lpib(struct azx *chip, struct azx_dev *azx_dev, else delay = lpib_pos - pos; if (delay < 0) { - if (delay >= azx_dev->delay_negative_threshold) + if (delay >= azx_dev->core.delay_negative_threshold) delay = 0; else - delay += azx_dev->bufsize; + delay += azx_dev->core.bufsize; } - if (delay >= azx_dev->period_bytes) { + if (delay >= azx_dev->core.period_bytes) { dev_info(chip->card->dev, "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", - delay, azx_dev->period_bytes); + delay, azx_dev->core.period_bytes); delay = 0; chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; chip->get_delay[stream] = NULL; @@ -548,6 +608,14 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) return 0; } +/* Enable/disable i915 display power for the link */ +static int azx_intel_link_power(struct azx *chip, bool enable) +{ + struct hdac_bus *bus = azx_bus(chip); + + return snd_hdac_display_power(bus, enable); +} + /* * Check whether the current DMA position is acceptable for updating * periods. Returns non-zero if it's OK. @@ -559,13 +627,13 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) */ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) { - struct snd_pcm_substream *substream = azx_dev->substream; + struct snd_pcm_substream *substream = azx_dev->core.substream; int stream = substream->stream; u32 wallclk; unsigned int pos; - wallclk = azx_readl(chip, WALLCLK) - azx_dev->start_wallclk; - if (wallclk < (azx_dev->period_wallclk * 2) / 3) + wallclk = azx_readl(chip, WALLCLK) - azx_dev->core.start_wallclk; + if (wallclk < (azx_dev->core.period_wallclk * 2) / 3) return -1; /* bogus (too early) interrupt */ if (chip->get_position[stream]) @@ -576,6 +644,9 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) dev_info(chip->card->dev, "Invalid position buffer, using LPIB read method instead.\n"); chip->get_position[stream] = azx_get_pos_lpib; + if (chip->get_position[0] == azx_get_pos_lpib && + chip->get_position[1] == azx_get_pos_lpib) + azx_bus(chip)->use_posbuf = false; pos = azx_get_pos_lpib(chip, azx_dev); chip->get_delay[stream] = NULL; } else { @@ -585,17 +656,17 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) } } - if (pos >= azx_dev->bufsize) + if (pos >= azx_dev->core.bufsize) pos = 0; - if (WARN_ONCE(!azx_dev->period_bytes, + if (WARN_ONCE(!azx_dev->core.period_bytes, "hda-intel: zero azx_dev->period_bytes")) return -1; /* this shouldn't happen! */ - if (wallclk < (azx_dev->period_wallclk * 5) / 4 && - pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) + if (wallclk < (azx_dev->core.period_wallclk * 5) / 4 && + pos % azx_dev->core.period_bytes > azx_dev->core.period_bytes / 2) /* NG - it's below the first next period boundary */ return chip->bdl_pos_adj[chip->dev_index] ? 0 : -1; - azx_dev->start_wallclk += wallclk; + azx_dev->core.start_wallclk += wallclk; return 1; /* OK, it's fine */ } @@ -606,7 +677,9 @@ static void azx_irq_pending_work(struct work_struct *work) { struct hda_intel *hda = container_of(work, struct hda_intel, irq_pending_work); struct azx *chip = &hda->chip; - int i, pending, ok; + struct hdac_bus *bus = azx_bus(chip); + struct hdac_stream *s; + int pending, ok; if (!hda->irq_pending_warned) { dev_info(chip->card->dev, @@ -617,25 +690,25 @@ static void azx_irq_pending_work(struct work_struct *work) for (;;) { pending = 0; - spin_lock_irq(&chip->reg_lock); - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; + spin_lock_irq(&bus->reg_lock); + list_for_each_entry(s, &bus->stream_list, list) { + struct azx_dev *azx_dev = stream_to_azx_dev(s); if (!azx_dev->irq_pending || - !azx_dev->substream || - !azx_dev->running) + !s->substream || + !s->running) continue; ok = azx_position_ok(chip, azx_dev); if (ok > 0) { azx_dev->irq_pending = 0; - spin_unlock(&chip->reg_lock); - snd_pcm_period_elapsed(azx_dev->substream); - spin_lock(&chip->reg_lock); + spin_unlock(&bus->reg_lock); + snd_pcm_period_elapsed(s->substream); + spin_lock(&bus->reg_lock); } else if (ok < 0) { pending = 0; /* too early */ } else pending++; } - spin_unlock_irq(&chip->reg_lock); + spin_unlock_irq(&bus->reg_lock); if (!pending) return; msleep(1); @@ -645,16 +718,21 @@ static void azx_irq_pending_work(struct work_struct *work) /* clear irq_pending flags and assure no on-going workq */ static void azx_clear_irq_pending(struct azx *chip) { - int i; + struct hdac_bus *bus = azx_bus(chip); + struct hdac_stream *s; - spin_lock_irq(&chip->reg_lock); - for (i = 0; i < chip->num_streams; i++) - chip->azx_dev[i].irq_pending = 0; - spin_unlock_irq(&chip->reg_lock); + spin_lock_irq(&bus->reg_lock); + list_for_each_entry(s, &bus->stream_list, list) { + struct azx_dev *azx_dev = stream_to_azx_dev(s); + azx_dev->irq_pending = 0; + } + spin_unlock_irq(&bus->reg_lock); } static int azx_acquire_irq(struct azx *chip, int do_disconnect) { + struct hdac_bus *bus = azx_bus(chip); + if (request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, KBUILD_MODNAME, chip)) { @@ -665,7 +743,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) snd_card_disconnect(chip->card); return -1; } - chip->irq = chip->pci->irq; + bus->irq = chip->pci->irq; pci_intx(chip->pci, !chip->msi); return 0; } @@ -678,8 +756,8 @@ static unsigned int azx_via_get_position(struct azx *chip, unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; unsigned int fifo_size; - link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); - if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + link_pos = snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev)); + if (azx_dev->core.substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* Playback, no problem using link position */ return link_pos; } @@ -688,13 +766,14 @@ static unsigned int azx_via_get_position(struct azx *chip, /* For new chipset, * use mod to get the DMA position just like old chipset */ - mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); - mod_dma_pos %= azx_dev->period_bytes; + mod_dma_pos = le32_to_cpu(*azx_dev->core.posbuf); + mod_dma_pos %= azx_dev->core.period_bytes; /* azx_dev->fifo_size can't get FIFO size of in stream. * Get from base address + offset. */ - fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); + fifo_size = readw(azx_bus(chip)->remap_addr + + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); if (azx_dev->insufficient) { /* Link position never gather than FIFO size */ @@ -705,20 +784,20 @@ static unsigned int azx_via_get_position(struct azx *chip, } if (link_pos <= fifo_size) - mini_pos = azx_dev->bufsize + link_pos - fifo_size; + mini_pos = azx_dev->core.bufsize + link_pos - fifo_size; else mini_pos = link_pos - fifo_size; /* Find nearest previous boudary */ - mod_mini_pos = mini_pos % azx_dev->period_bytes; - mod_link_pos = link_pos % azx_dev->period_bytes; + mod_mini_pos = mini_pos % azx_dev->core.period_bytes; + mod_link_pos = link_pos % azx_dev->core.period_bytes; if (mod_link_pos >= fifo_size) bound_pos = link_pos - mod_link_pos; else if (mod_dma_pos >= mod_mini_pos) bound_pos = mini_pos - mod_mini_pos; else { - bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; - if (bound_pos >= azx_dev->bufsize) + bound_pos = mini_pos - mod_mini_pos + azx_dev->core.period_bytes; + if (bound_pos >= azx_dev->core.bufsize) bound_pos = 0; } @@ -760,9 +839,9 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) mutex_lock(&card_list_lock); list_for_each_entry(hda, &card_list, list) { chip = &hda->chip; - if (!chip->bus || chip->disabled) + if (!hda->probe_continued || chip->disabled) continue; - snd_hda_set_power_save(chip->bus, power_save * 1000); + snd_hda_set_power_save(&chip->bus, power_save * 1000); } mutex_unlock(&card_list_lock); return 0; @@ -772,6 +851,50 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) #define azx_del_card_list(chip) /* NOP */ #endif /* CONFIG_PM */ +/* Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK + * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) + * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: + * BCLK = CDCLK * M / N + * The values will be lost when the display power well is disabled and need to + * be restored to avoid abnormal playback speed. + */ +static void haswell_set_bclk(struct hda_intel *hda) +{ + struct azx *chip = &hda->chip; + int cdclk_freq; + unsigned int bclk_m, bclk_n; + + if (!hda->need_i915_power) + return; + + cdclk_freq = snd_hdac_get_display_clk(azx_bus(chip)); + switch (cdclk_freq) { + case 337500: + bclk_m = 16; + bclk_n = 225; + break; + + case 450000: + default: /* default CDCLK 450MHz */ + bclk_m = 4; + bclk_n = 75; + break; + + case 540000: + bclk_m = 4; + bclk_n = 90; + break; + + case 675000: + bclk_m = 8; + bclk_n = 225; + break; + } + + azx_writew(chip, HSW_EM4, bclk_m); + azx_writew(chip, HSW_EM5, bclk_n); +} + #if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO) /* * power management @@ -781,28 +904,33 @@ static int azx_suspend(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; + struct hdac_bus *bus; if (!card) return 0; chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); - if (chip->disabled || hda->init_failed) + if (chip->disabled || hda->init_failed || !chip->running) return 0; + bus = azx_bus(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); azx_clear_irq_pending(chip); azx_stop_chip(chip); azx_enter_link_reset(chip); - if (chip->irq >= 0) { - free_irq(chip->irq, chip); - chip->irq = -1; + if (bus->irq >= 0) { + free_irq(bus->irq, chip); + bus->irq = -1; } if (chip->msi) pci_disable_msi(chip->pci); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_display_power(hda, false); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL + && hda->need_i915_power) + snd_hdac_display_power(bus, false); + + trace_azx_suspend(chip); return 0; } @@ -818,11 +946,12 @@ static int azx_resume(struct device *dev) chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); - if (chip->disabled || hda->init_failed) + if (chip->disabled || hda->init_failed || !chip->running) return 0; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(hda, true); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL + && hda->need_i915_power) { + snd_hdac_display_power(azx_bus(chip), true); haswell_set_bclk(hda); } if (chip->msi) @@ -832,13 +961,40 @@ static int azx_resume(struct device *dev) return -EIO; azx_init_pci(chip); - azx_init_chip(chip, true); + hda_intel_init_chip(chip, true); snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + trace_azx_resume(chip); return 0; } #endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */ +#ifdef CONFIG_PM_SLEEP +/* put codec down to D3 at hibernation for Intel SKL+; + * otherwise BIOS may still access the codec and screw up the driver + */ +static int azx_freeze_noirq(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + + if (IS_SKL_PLUS(pci)) + pci_set_power_state(pci, PCI_D3hot); + + return 0; +} + +static int azx_thaw_noirq(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + + if (IS_SKL_PLUS(pci)) + pci_set_power_state(pci, PCI_D0); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + #ifdef CONFIG_PM static int azx_runtime_suspend(struct device *dev) { @@ -864,9 +1020,11 @@ static int azx_runtime_suspend(struct device *dev) azx_stop_chip(chip); azx_enter_link_reset(chip); azx_clear_irq_pending(chip); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_display_power(hda, false); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL + && hda->need_i915_power) + snd_hdac_display_power(azx_bus(chip), false); + trace_azx_runtime_suspend(chip); return 0; } @@ -875,7 +1033,7 @@ static int azx_runtime_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; - struct hda_bus *bus; + struct hdac_bus *bus; struct hda_codec *codec; int status; @@ -891,19 +1049,25 @@ static int azx_runtime_resume(struct device *dev) return 0; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(hda, true); - haswell_set_bclk(hda); + bus = azx_bus(chip); + if (hda->need_i915_power) { + snd_hdac_display_power(bus, true); + haswell_set_bclk(hda); + } else { + /* toggle codec wakeup bit for STATESTS read */ + snd_hdac_set_codec_wakeup(bus, true); + snd_hdac_set_codec_wakeup(bus, false); + } } /* Read STATESTS before controller reset */ status = azx_readw(chip, STATESTS); azx_init_pci(chip); - azx_init_chip(chip, true); + hda_intel_init_chip(chip, true); - bus = chip->bus; - if (status && bus) { - list_for_each_codec(codec, bus) + if (status) { + list_for_each_codec(codec, &chip->bus) if (status & (1 << codec->addr)) schedule_delayed_work(&codec->jackpoll_work, codec->jackpoll_interval); @@ -913,6 +1077,7 @@ static int azx_runtime_resume(struct device *dev) azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & ~STATESTS_INT_MASK); + trace_azx_runtime_resume(chip); return 0; } @@ -931,7 +1096,7 @@ static int azx_runtime_idle(struct device *dev) return 0; if (!power_save_controller || !azx_has_pm_runtime(chip) || - chip->bus->core.codec_powered) + azx_bus(chip)->codec_powered || !chip->running) return -EBUSY; return 0; @@ -939,6 +1104,10 @@ static int azx_runtime_idle(struct device *dev) static const struct dev_pm_ops azx_pm = { SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume) +#ifdef CONFIG_PM_SLEEP + .freeze_noirq = azx_freeze_noirq, + .thaw_noirq = azx_thaw_noirq, +#endif SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) }; @@ -969,7 +1138,7 @@ static void azx_vs_set_state(struct pci_dev *pci, if (chip->disabled == disabled) return; - if (!chip->bus) { + if (!hda->probe_continued) { chip->disabled = disabled; if (!disabled) { dev_info(chip->card->dev, @@ -980,21 +1149,21 @@ static void azx_vs_set_state(struct pci_dev *pci, } } } else { - dev_info(chip->card->dev, "%s via VGA-switcheroo\n", + dev_info(chip->card->dev, "%s via vga_switcheroo\n", disabled ? "Disabling" : "Enabling"); if (disabled) { pm_runtime_put_sync_suspend(card->dev); azx_suspend(card->dev); - /* when we get suspended by vga switcheroo we end up in D3cold, + /* when we get suspended by vga_switcheroo we end up in D3cold, * however we have no ACPI handle, so pci/acpi can't put us there, * put ourselves there */ pci->current_state = PCI_D3cold; chip->disabled = true; - if (snd_hda_lock_devices(chip->bus)) + if (snd_hda_lock_devices(&chip->bus)) dev_warn(chip->card->dev, "Cannot lock devices!\n"); } else { - snd_hda_unlock_devices(chip->bus); + snd_hda_unlock_devices(&chip->bus); pm_runtime_get_noresume(card->dev); chip->disabled = false; azx_resume(card->dev); @@ -1011,11 +1180,11 @@ static bool azx_vs_can_switch(struct pci_dev *pci) wait_for_completion(&hda->probe_wait); if (hda->init_failed) return false; - if (chip->disabled || !chip->bus) + if (chip->disabled || !hda->probe_continued) return true; - if (snd_hda_lock_devices(chip->bus)) + if (snd_hda_lock_devices(&chip->bus)) return false; - snd_hda_unlock_devices(chip->bus); + snd_hda_unlock_devices(&chip->bus); return true; } @@ -1025,7 +1194,7 @@ static void init_vga_switcheroo(struct azx *chip) struct pci_dev *p = get_bound_vga(chip->pci); if (p) { dev_info(chip->card->dev, - "Handle VGA-switcheroo audio client\n"); + "Handle vga_switcheroo audio client\n"); hda->use_vga_switcheroo = 1; pci_dev_put(p); } @@ -1047,8 +1216,7 @@ static int register_vga_switcheroo(struct azx *chip) * is there any machine with two switchable HDMI audio controllers? */ err = vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops, - VGA_SWITCHEROO_DIS, - chip->bus != NULL); + VGA_SWITCHEROO_DIS); if (err < 0) return err; hda->vga_switcheroo_registered = 1; @@ -1071,7 +1239,7 @@ static int azx_free(struct azx *chip) { struct pci_dev *pci = chip->pci; struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - int i; + struct hdac_bus *bus = azx_bus(chip); if (azx_has_pm_runtime(chip) && chip->running) pm_runtime_get_noresume(&pci->dev); @@ -1082,42 +1250,54 @@ static int azx_free(struct azx *chip) complete_all(&hda->probe_wait); if (use_vga_switcheroo(hda)) { - if (chip->disabled && chip->bus) - snd_hda_unlock_devices(chip->bus); + if (chip->disabled && hda->probe_continued) + snd_hda_unlock_devices(&chip->bus); if (hda->vga_switcheroo_registered) vga_switcheroo_unregister_client(chip->pci); } - if (chip->initialized) { + if (bus->chip_init) { azx_clear_irq_pending(chip); - for (i = 0; i < chip->num_streams; i++) - azx_stream_stop(chip, &chip->azx_dev[i]); + azx_stop_all_streams(chip); azx_stop_chip(chip); } - if (chip->irq >= 0) - free_irq(chip->irq, (void*)chip); + if (bus->irq >= 0) + free_irq(bus->irq, (void*)chip); if (chip->msi) pci_disable_msi(chip->pci); - iounmap(chip->remap_addr); + iounmap(bus->remap_addr); azx_free_stream_pages(chip); + azx_free_streams(chip); + snd_hdac_bus_exit(bus); + if (chip->region_requested) pci_release_regions(chip->pci); + pci_disable_device(chip->pci); - kfree(chip->azx_dev); #ifdef CONFIG_SND_HDA_PATCH_LOADER release_firmware(chip->fw); #endif + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(hda, false); - hda_i915_exit(hda); + if (hda->need_i915_power) + snd_hdac_display_power(bus, false); + snd_hdac_i915_exit(bus); } kfree(hda); return 0; } +static int azx_dev_disconnect(struct snd_device *device) +{ + struct azx *chip = device->device_data; + + chip->bus.shutdown = 1; + return 0; +} + static int azx_dev_free(struct snd_device *device) { return azx_free(device->device_data); @@ -1125,7 +1305,7 @@ static int azx_dev_free(struct snd_device *device) #ifdef SUPPORT_VGA_SWITCHEROO /* - * Check of disabled HDMI controller by vga-switcheroo + * Check of disabled HDMI controller by vga_switcheroo */ static struct pci_dev *get_bound_vga(struct pci_dev *pci) { @@ -1284,9 +1464,9 @@ static void check_probe_mask(struct azx *chip, int dev) /* check forced option */ if (chip->codec_probe_mask != -1 && (chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) { - chip->codec_mask = chip->codec_probe_mask & 0xff; + azx_bus(chip)->codec_mask = chip->codec_probe_mask & 0xff; dev_info(chip->card->dev, "codec_mask forced to 0x%x\n", - chip->codec_mask); + (int)azx_bus(chip)->codec_mask); } } @@ -1373,12 +1553,15 @@ static void azx_probe_work(struct work_struct *work) /* * constructor */ +static const struct hdac_io_ops pci_hda_io_ops; +static const struct hda_controller_ops pci_hda_ops; + static int azx_create(struct snd_card *card, struct pci_dev *pci, int dev, unsigned int driver_caps, - const struct hda_controller_ops *hda_ops, struct azx **rchip) { static struct snd_device_ops ops = { + .dev_disconnect = azx_dev_disconnect, .dev_free = azx_dev_free, }; struct hda_intel *hda; @@ -1398,12 +1581,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, } chip = &hda->chip; - spin_lock_init(&chip->reg_lock); mutex_init(&chip->open_mutex); chip->card = card; chip->pci = pci; - chip->ops = hda_ops; - chip->irq = -1; + chip->ops = &pci_hda_ops; chip->driver_caps = driver_caps; chip->driver_type = driver_caps & 0xff; check_msi(chip); @@ -1435,6 +1616,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, } chip->bdl_pos_adj = bdl_pos_adj; + err = azx_bus_init(chip, model[dev], &pci_hda_io_ops); + if (err < 0) { + kfree(hda); + pci_disable_device(pci); + return err; + } + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { dev_err(card->dev, "Error creating device [card]!\n"); @@ -1455,6 +1643,7 @@ static int azx_first_init(struct azx *chip) int dev = chip->dev_index; struct pci_dev *pci = chip->pci; struct snd_card *card = chip->card; + struct hdac_bus *bus = azx_bus(chip); int err; unsigned short gcap; unsigned int dma_bits = 64; @@ -1474,9 +1663,9 @@ static int azx_first_init(struct azx *chip) return err; chip->region_requested = 1; - chip->addr = pci_resource_start(pci, 0); - chip->remap_addr = pci_ioremap_bar(pci, 0); - if (chip->remap_addr == NULL) { + bus->addr = pci_resource_start(pci, 0); + bus->remap_addr = pci_ioremap_bar(pci, 0); + if (bus->remap_addr == NULL) { dev_err(card->dev, "ioremap error\n"); return -ENXIO; } @@ -1494,7 +1683,7 @@ static int azx_first_init(struct azx *chip) return -EBUSY; pci_set_master(pci); - synchronize_irq(chip->irq); + synchronize_irq(bus->irq); gcap = azx_readw(chip, GCAP); dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); @@ -1536,11 +1725,11 @@ static int azx_first_init(struct azx *chip) /* allow 64bit DMA address if supported by H/W */ if (!(gcap & AZX_GCAP_64OK)) dma_bits = 32; - if (!pci_set_dma_mask(pci, DMA_BIT_MASK(dma_bits))) { - pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(dma_bits)); + if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) { + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits)); } else { - pci_set_dma_mask(pci, DMA_BIT_MASK(32)); - pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)); + dma_set_mask(&pci->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)); } /* read number of streams from GCAP register instead of using @@ -1571,17 +1760,15 @@ static int azx_first_init(struct azx *chip) chip->capture_index_offset = 0; chip->playback_index_offset = chip->capture_streams; chip->num_streams = chip->playback_streams + chip->capture_streams; - chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), - GFP_KERNEL); - if (!chip->azx_dev) - return -ENOMEM; - err = azx_alloc_stream_pages(chip); + /* initialize streams */ + err = azx_init_streams(chip); if (err < 0) return err; - /* initialize streams */ - azx_init_stream(chip); + err = azx_alloc_stream_pages(chip); + if (err < 0) + return err; /* initialize chip */ azx_init_pci(chip); @@ -1593,10 +1780,10 @@ static int azx_first_init(struct azx *chip) haswell_set_bclk(hda); } - azx_init_chip(chip, (probe_only[dev] & 2) == 0); + hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0); /* codec detection */ - if (!chip->codec_mask) { + if (!azx_bus(chip)->codec_mask) { dev_err(card->dev, "no codecs found!\n"); return -ENODEV; } @@ -1606,7 +1793,7 @@ static int azx_first_init(struct azx *chip) sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx irq %i", - card->shortname, chip->addr, chip->irq); + card->shortname, bus->addr, bus->irq); return 0; } @@ -1675,10 +1862,11 @@ static u8 pci_azx_readb(u8 __iomem *addr) static int disable_msi_reset_irq(struct azx *chip) { + struct hdac_bus *bus = azx_bus(chip); int err; - free_irq(chip->irq, chip); - chip->irq = -1; + free_irq(bus->irq, chip); + bus->irq = -1; pci_disable_msi(chip->pci); chip->msi = 0; err = azx_acquire_irq(chip, 1); @@ -1689,15 +1877,16 @@ static int disable_msi_reset_irq(struct azx *chip) } /* DMA page allocation helpers. */ -static int dma_alloc_pages(struct azx *chip, +static int dma_alloc_pages(struct hdac_bus *bus, int type, size_t size, struct snd_dma_buffer *buf) { + struct azx *chip = bus_to_azx(bus); int err; err = snd_dma_alloc_pages(type, - chip->card->dev, + bus->dev, size, buf); if (err < 0) return err; @@ -1705,8 +1894,10 @@ static int dma_alloc_pages(struct azx *chip, return 0; } -static void dma_free_pages(struct azx *chip, struct snd_dma_buffer *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); } @@ -1719,9 +1910,6 @@ static int substream_alloc_pages(struct azx *chip, int ret; mark_runtime_wc(chip, azx_dev, substream, false); - azx_dev->bufsize = 0; - azx_dev->period_bytes = 0; - azx_dev->format_val = 0; ret = snd_pcm_lib_malloc_pages(substream, size); if (ret < 0) return ret; @@ -1748,20 +1936,24 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream, #endif } -static const struct hda_controller_ops pci_hda_ops = { +static const struct hdac_io_ops pci_hda_io_ops = { .reg_writel = pci_azx_writel, .reg_readl = pci_azx_readl, .reg_writew = pci_azx_writew, .reg_readw = pci_azx_readw, .reg_writeb = pci_azx_writeb, .reg_readb = pci_azx_readb, - .disable_msi_reset_irq = disable_msi_reset_irq, .dma_alloc_pages = dma_alloc_pages, .dma_free_pages = dma_free_pages, +}; + +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, }; static int azx_probe(struct pci_dev *pci, @@ -1788,8 +1980,7 @@ static int azx_probe(struct pci_dev *pci, return err; } - err = azx_create(card, pci, dev, pci_id->driver_data, - &pci_hda_ops, &chip); + err = azx_create(card, pci, dev, pci_id->driver_data, &chip); if (err < 0) goto out_free; card->private_data = chip; @@ -1799,7 +1990,7 @@ static int azx_probe(struct pci_dev *pci, err = register_vga_switcheroo(chip); if (err < 0) { - dev_err(card->dev, "Error registering VGA-switcheroo client\n"); + dev_err(card->dev, "Error registering vga_switcheroo client\n"); goto out_free; } @@ -1851,14 +2042,24 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { static int azx_probe_continue(struct azx *chip) { struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct hdac_bus *bus = azx_bus(chip); struct pci_dev *pci = chip->pci; int dev = chip->dev_index; int err; - /* Request power well for Haswell HDA controller and codec */ + hda->probe_continued = 1; + + /* Request display power well for the HDA controller or codec. For + * Haswell/Broadwell, both the display HDA controller and codec need + * this power. For other platforms, like Baytrail/Braswell, only the + * display codec needs the power and it can be released after probe. + */ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { -#ifdef CONFIG_SND_HDA_I915 - err = hda_i915_init(hda); + /* HSW/BDW controllers need this power */ + if (CONTROLLER_IN_GPU(pci)) + hda->need_i915_power = 1; + + err = snd_hdac_i915_init(bus); if (err < 0) { /* if the controller is bound only with HDMI/DP * (for HSW and BDW), we need to abort the probe; @@ -1870,18 +2071,16 @@ static int azx_probe_continue(struct azx *chip) else goto skip_i915; } - err = hda_display_power(hda, true); + + err = snd_hdac_display_power(bus, true); if (err < 0) { dev_err(chip->card->dev, "Cannot turn on display power on i915\n"); - goto out_free; + goto i915_power_fail; } -#endif } -#ifdef CONFIG_SND_HDA_I915 skip_i915: -#endif err = azx_first_init(chip); if (err < 0) goto out_free; @@ -1891,17 +2090,13 @@ static int azx_probe_continue(struct azx *chip) #endif /* create codec instances */ - err = azx_bus_create(chip, model[dev]); - if (err < 0) - goto out_free; - err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]); if (err < 0) goto out_free; #ifdef CONFIG_SND_HDA_PATCH_LOADER if (chip->fw) { - err = snd_hda_load_patch(chip->bus, chip->fw->size, + err = snd_hda_load_patch(&chip->bus, chip->fw->size, chip->fw->data); if (err < 0) goto out_free; @@ -1923,11 +2118,16 @@ static int azx_probe_continue(struct azx *chip) chip->running = 1; azx_add_card_list(chip); - snd_hda_set_power_save(chip->bus, power_save * 1000); + snd_hda_set_power_save(&chip->bus, power_save * 1000); if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo) pm_runtime_put_noidle(&pci->dev); out_free: + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL + && !hda->need_i915_power) + snd_hdac_display_power(bus, false); + +i915_power_fail: if (err < 0) hda->init_failed = 1; complete_all(&hda->probe_wait); @@ -1937,9 +2137,17 @@ out_free: static void azx_remove(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); + struct azx *chip; + struct hda_intel *hda; + + if (card) { + /* cancel the pending probing work */ + chip = card->private_data; + hda = container_of(chip, struct hda_intel, chip); + cancel_work_sync(&hda->probe_work); - if (card) snd_card_free(card); + } } static void azx_shutdown(struct pci_dev *pci) @@ -1976,6 +2184,11 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, { PCI_DEVICE(0x8086, 0x8d21), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + /* Lewisburg */ + { PCI_DEVICE(0x8086, 0xa1f0), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE(0x8086, 0xa270), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, @@ -1991,6 +2204,9 @@ static const struct pci_device_id azx_ids[] = { /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + /* Broxton-P(Apollolake) */ + { PCI_DEVICE(0x8086, 0x5a98), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0a0c), .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, @@ -2156,11 +2372,13 @@ static const struct pci_device_id azx_ids[] = { .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | + AZX_DCAPS_NO_64BIT | AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, #else /* this entry seems still valid -- i.e. without emu20kx chip */ { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | + AZX_DCAPS_NO_64BIT | AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, #endif /* CM8888 */ diff --git a/kernel/sound/pci/hda/hda_intel.h b/kernel/sound/pci/hda/hda_intel.h index d5231f721..ff0c4d617 100644 --- a/kernel/sound/pci/hda/hda_intel.h +++ b/kernel/sound/pci/hda/hda_intel.h @@ -16,7 +16,6 @@ #ifndef __SOUND_HDA_INTEL_H #define __SOUND_HDA_INTEL_H -#include <drm/i915_component.h> #include "hda_controller.h" struct hda_intel { @@ -34,8 +33,9 @@ struct hda_intel { /* extra flags */ unsigned int irq_pending_warned:1; + unsigned int probe_continued:1; - /* VGA-switcheroo setup */ + /* vga_switcheroo setup */ unsigned int use_vga_switcheroo:1; unsigned int vga_switcheroo_registered:1; unsigned int init_failed:1; /* delayed init failed */ @@ -43,29 +43,7 @@ struct hda_intel { /* secondary power domain for hdmi audio under vga device */ struct dev_pm_domain hdmi_pm_domain; - /* i915 component interface */ - struct i915_audio_component audio_component; + bool need_i915_power:1; /* the hda controller needs i915 power */ }; -#ifdef CONFIG_SND_HDA_I915 -int hda_display_power(struct hda_intel *hda, bool enable); -void haswell_set_bclk(struct hda_intel *hda); -int hda_i915_init(struct hda_intel *hda); -int hda_i915_exit(struct hda_intel *hda); -#else -static inline int hda_display_power(struct hda_intel *hda, bool enable) -{ - return 0; -} -static inline void haswell_set_bclk(struct hda_intel *hda) { return; } -static inline int hda_i915_init(struct hda_intel *hda) -{ - return -ENODEV; -} -static inline int hda_i915_exit(struct hda_intel *hda) -{ - return 0; -} -#endif - #endif diff --git a/kernel/sound/pci/hda/hda_intel_trace.h b/kernel/sound/pci/hda/hda_intel_trace.h index 7b5e4c2cf..0922d8b1b 100644 --- a/kernel/sound/pci/hda/hda_intel_trace.h +++ b/kernel/sound/pci/hda/hda_intel_trace.h @@ -7,52 +7,43 @@ #include <linux/tracepoint.h> -struct azx; -struct azx_dev; +DECLARE_EVENT_CLASS(hda_pm, + TP_PROTO(struct azx *chip), -TRACE_EVENT(azx_pcm_trigger, - - TP_PROTO(struct azx *chip, struct azx_dev *dev, int cmd), - - TP_ARGS(chip, dev, cmd), + TP_ARGS(chip), TP_STRUCT__entry( - __field( int, card ) - __field( int, idx ) - __field( int, cmd ) + __field(int, dev_index) ), TP_fast_assign( - __entry->card = (chip)->card->number; - __entry->idx = (dev)->index; - __entry->cmd = cmd; + __entry->dev_index = (chip)->dev_index; ), - TP_printk("[%d:%d] cmd=%d", __entry->card, __entry->idx, __entry->cmd) + TP_printk("card index: %d", __entry->dev_index) ); -TRACE_EVENT(azx_get_position, - - TP_PROTO(struct azx *chip, struct azx_dev *dev, unsigned int pos, unsigned int delay), - - TP_ARGS(chip, dev, pos, delay), +DEFINE_EVENT(hda_pm, azx_suspend, + TP_PROTO(struct azx *chip), + TP_ARGS(chip) +); - TP_STRUCT__entry( - __field( int, card ) - __field( int, idx ) - __field( unsigned int, pos ) - __field( unsigned int, delay ) - ), +DEFINE_EVENT(hda_pm, azx_resume, + TP_PROTO(struct azx *chip), + TP_ARGS(chip) +); - TP_fast_assign( - __entry->card = (chip)->card->number; - __entry->idx = (dev)->index; - __entry->pos = pos; - __entry->delay = delay; - ), +#ifdef CONFIG_PM +DEFINE_EVENT(hda_pm, azx_runtime_suspend, + TP_PROTO(struct azx *chip), + TP_ARGS(chip) +); - TP_printk("[%d:%d] pos=%u, delay=%u", __entry->card, __entry->idx, __entry->pos, __entry->delay) +DEFINE_EVENT(hda_pm, azx_runtime_resume, + TP_PROTO(struct azx *chip), + TP_ARGS(chip) ); +#endif #endif /* _TRACE_HDA_INTEL_H */ diff --git a/kernel/sound/pci/hda/hda_jack.c b/kernel/sound/pci/hda/hda_jack.c index d7cfe7b8c..a33234e04 100644 --- a/kernel/sound/pci/hda/hda_jack.c +++ b/kernel/sound/pci/hda/hda_jack.c @@ -132,11 +132,11 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec) for (i = 0; i < codec->jacktbl.used; i++, jack++) { struct hda_jack_callback *cb, *next; -#ifdef CONFIG_SND_HDA_INPUT_JACK + /* free jack instances manually when clearing/reconfiguring */ if (!codec->bus->shutdown && jack->jack) snd_device_free(codec->card, jack->jack); -#endif + for (cb = jack->callback; cb; cb = next) { next = cb->next; kfree(cb); @@ -259,7 +259,7 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, if (!callback) return ERR_PTR(-ENOMEM); callback->func = func; - callback->tbl = jack; + callback->nid = jack->nid; callback->next = jack->callback; jack->callback = callback; } @@ -337,20 +337,15 @@ void snd_hda_jack_report_sync(struct hda_codec *codec) jack = codec->jacktbl.list; for (i = 0; i < codec->jacktbl.used; i++, jack++) if (jack->nid) { - if (!jack->kctl || jack->block_report) + if (!jack->jack || jack->block_report) continue; state = get_jack_plug_state(jack->pin_sense); - snd_kctl_jack_report(codec->card, jack->kctl, state); -#ifdef CONFIG_SND_HDA_INPUT_JACK - if (jack->jack) - snd_jack_report(jack->jack, - state ? jack->type : 0); -#endif + snd_jack_report(jack->jack, + state ? jack->type : 0); } } EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); -#ifdef CONFIG_SND_HDA_INPUT_JACK /* guess the jack type from the pin-config */ static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) { @@ -377,100 +372,53 @@ static void hda_free_jack_priv(struct snd_jack *jack) jacks->nid = 0; jacks->jack = NULL; } -#endif /** * snd_hda_jack_add_kctl - Add a kctl for the given pin * @codec: the HDA codec * @nid: pin NID to assign * @name: string name for the jack - * @idx: index number for the jack * @phantom_jack: flag to deal as a phantom jack * * This assigns a jack-detection kctl to the given pin. The kcontrol * will have the given name and index. */ -static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, int idx, bool phantom_jack) +int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, + const char *name, bool phantom_jack) { struct hda_jack_tbl *jack; - struct snd_kcontrol *kctl; - int err, state; + int err, state, type; jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) return 0; - if (jack->kctl) + if (jack->jack) return 0; /* already created */ - kctl = snd_kctl_jack_new(name, idx, codec); - if (!kctl) - return -ENOMEM; - err = snd_hda_ctl_add(codec, nid, kctl); + + type = get_input_jack_type(codec, nid); + err = snd_jack_new(codec->card, name, type, + &jack->jack, true, phantom_jack); if (err < 0) return err; - jack->kctl = kctl; - jack->phantom_jack = !!phantom_jack; + jack->phantom_jack = !!phantom_jack; + jack->type = type; + jack->jack->private_data = jack; + jack->jack->private_free = hda_free_jack_priv; state = snd_hda_jack_detect(codec, nid); - snd_kctl_jack_report(codec->card, kctl, state); -#ifdef CONFIG_SND_HDA_INPUT_JACK - if (!phantom_jack) { - jack->type = get_input_jack_type(codec, nid); - err = snd_jack_new(codec->card, name, jack->type, - &jack->jack); - if (err < 0) - return err; - jack->jack->private_data = jack; - jack->jack->private_free = hda_free_jack_priv; - snd_jack_report(jack->jack, state ? jack->type : 0); - } -#endif - return 0; -} + snd_jack_report(jack->jack, state ? jack->type : 0); -/** - * snd_hda_jack_add_kctl - Add a jack kctl for the given pin - * @codec: the HDA codec - * @nid: pin NID - * @name: the name string for the jack ctl - * @idx: the ctl index for the jack ctl - * - * This is a simple helper calling __snd_hda_jack_add_kctl(). - */ -int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, int idx) -{ - return __snd_hda_jack_add_kctl(codec, nid, name, idx, false); + return 0; } EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl); -/* get the unique index number for the given kctl name */ -static int get_unique_index(struct hda_codec *codec, const char *name, int idx) -{ - struct hda_jack_tbl *jack; - int i, len = strlen(name); - again: - jack = codec->jacktbl.list; - for (i = 0; i < codec->jacktbl.used; i++, jack++) { - /* jack->kctl.id contains "XXX Jack" name string with index */ - if (jack->kctl && - !strncmp(name, jack->kctl->id.name, len) && - !strcmp(" Jack", jack->kctl->id.name + len) && - jack->kctl->id.index == idx) { - idx++; - goto again; - } - } - return idx; -} - static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, const struct auto_pin_cfg *cfg, const char *base_name) { unsigned int def_conf, conn; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - int idx, err; + int err; bool phantom_jack; if (!nid) @@ -482,16 +430,14 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || !is_jack_detectable(codec, nid); - if (base_name) { + if (base_name) strlcpy(name, base_name, sizeof(name)); - idx = 0; - } else - snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); + else + snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); if (phantom_jack) /* Example final name: "Internal Mic Phantom Jack" */ strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); - idx = get_unique_index(codec, name, idx); - err = __snd_hda_jack_add_kctl(codec, nid, name, idx, phantom_jack); + err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack); if (err < 0) return err; diff --git a/kernel/sound/pci/hda/hda_jack.h b/kernel/sound/pci/hda/hda_jack.h index b279e327a..e9814c016 100644 --- a/kernel/sound/pci/hda/hda_jack.h +++ b/kernel/sound/pci/hda/hda_jack.h @@ -21,7 +21,7 @@ struct hda_jack_callback; typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callback *); struct hda_jack_callback { - struct hda_jack_tbl *tbl; + hda_nid_t nid; hda_jack_callback_fn func; unsigned int private_data; /* arbitrary data */ struct hda_jack_callback *next; @@ -39,11 +39,8 @@ struct hda_jack_tbl { unsigned int block_report:1; /* in a transitional state - do not report to userspace */ hda_nid_t gating_jack; /* valid when gating jack plugged */ hda_nid_t gated_jack; /* gated is dependent on this jack */ - struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */ -#ifdef CONFIG_SND_HDA_INPUT_JACK int type; struct snd_jack *jack; -#endif }; struct hda_jack_tbl * @@ -85,7 +82,7 @@ static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, int idx); + const char *name, bool phantom_jack); int snd_hda_jack_add_kctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg); diff --git a/kernel/sound/pci/hda/hda_local.h b/kernel/sound/pci/hda/hda_local.h index bed66c314..d0e066e4c 100644 --- a/kernel/sound/pci/hda/hda_local.h +++ b/kernel/sound/pci/hda/hda_local.h @@ -330,7 +330,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, /* * generic proc interface */ -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS int snd_hda_codec_proc_new(struct hda_codec *codec); #else static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } @@ -681,12 +681,7 @@ static inline bool snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid, unsigned int target_state) { - unsigned int state = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_POWER_STATE, 0); - if (state & AC_PWRST_ERROR) - return true; - state = (state >> 4) & 0x0f; - return (state == target_state); + return snd_hdac_check_power_state(&codec->core, nid, target_state); } unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, @@ -777,7 +772,7 @@ int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, unsigned char *buf, int *eld_size, bool rev3_or_later); -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS void snd_hdmi_print_eld_info(struct hdmi_eld *eld, struct snd_info_buffer *buffer); void snd_hdmi_write_eld_info(struct hdmi_eld *eld, diff --git a/kernel/sound/pci/hda/hda_proc.c b/kernel/sound/pci/hda/hda_proc.c index baaf7ed06..033aa8436 100644 --- a/kernel/sound/pci/hda/hda_proc.c +++ b/kernel/sound/pci/hda/hda_proc.c @@ -36,24 +36,9 @@ MODULE_PARM_DESC(dump_coef, "Dump processing coefficients in codec proc file (-1 #define param_read(codec, nid, parm) \ snd_hdac_read_parm_uncached(&(codec)->core, nid, parm) -static char *bits_names(unsigned int bits, char *names[], int size) -{ - int i, n; - static char buf[128]; - - for (i = 0, n = 0; i < size; i++) { - if (bits & (1U<<i) && names[i]) - n += snprintf(buf + n, sizeof(buf) - n, " %s", - names[i]); - } - buf[n] = '\0'; - - return buf; -} - static const char *get_wid_type_name(unsigned int wid_value) { - static char *names[16] = { + static const char * const names[16] = { [AC_WID_AUD_OUT] = "Audio Output", [AC_WID_AUD_IN] = "Audio Input", [AC_WID_AUD_MIX] = "Audio Mixer", @@ -241,7 +226,7 @@ static void print_pcm_caps(struct snd_info_buffer *buffer, static const char *get_jack_connection(u32 cfg) { - static char *names[16] = { + static const char * const names[16] = { "Unknown", "1/8", "1/4", "ATAPI", "RCA", "Optical","Digital", "Analog", "DIN", "XLR", "RJ11", "Comb", @@ -256,7 +241,7 @@ static const char *get_jack_connection(u32 cfg) static const char *get_jack_color(u32 cfg) { - static char *names[16] = { + static const char * const names[16] = { "Unknown", "Black", "Grey", "Blue", "Green", "Red", "Orange", "Yellow", "Purple", "Pink", NULL, NULL, @@ -269,11 +254,74 @@ static const char *get_jack_color(u32 cfg) return "UNKNOWN"; } +/* + * Parse the pin default config value and returns the string of the + * jack location, e.g. "Rear", "Front", etc. + */ +static const char *get_jack_location(u32 cfg) +{ + static const char * const bases[7] = { + "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", + }; + static const unsigned char specials_idx[] = { + 0x07, 0x08, + 0x17, 0x18, 0x19, + 0x37, 0x38 + }; + static const char * const specials[] = { + "Rear Panel", "Drive Bar", + "Riser", "HDMI", "ATAPI", + "Mobile-In", "Mobile-Out" + }; + int i; + + cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; + if ((cfg & 0x0f) < 7) + return bases[cfg & 0x0f]; + for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { + if (cfg == specials_idx[i]) + return specials[i]; + } + return "UNKNOWN"; +} + +/* + * Parse the pin default config value and returns the string of the + * jack connectivity, i.e. external or internal connection. + */ +static const char *get_jack_connectivity(u32 cfg) +{ + static const char * const jack_locations[4] = { + "Ext", "Int", "Sep", "Oth" + }; + + return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; +} + +/* + * Parse the pin default config value and returns the string of the + * jack type, i.e. the purpose of the jack, such as Line-Out or CD. + */ +static const char *get_jack_type(u32 cfg) +{ + static const char * const jack_types[16] = { + "Line Out", "Speaker", "HP Out", "CD", + "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", + "Line In", "Aux", "Mic", "Telephony", + "SPDIF In", "Digital In", "Reserved", "Other" + }; + + return jack_types[(cfg & AC_DEFCFG_DEVICE) + >> AC_DEFCFG_DEVICE_SHIFT]; +} + static void print_pin_caps(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid, int *supports_vref) { - static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; + static const char * const jack_conns[4] = { + "Jack", "N/A", "Fixed", "Both" + }; unsigned int caps, val; caps = param_read(codec, nid, AC_PAR_PIN_CAP); @@ -340,9 +388,9 @@ static void print_pin_caps(struct snd_info_buffer *buffer, caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], - snd_hda_get_jack_type(caps), - snd_hda_get_jack_connectivity(caps), - snd_hda_get_jack_location(caps)); + get_jack_type(caps), + get_jack_connectivity(caps), + get_jack_location(caps)); snd_iprintf(buffer, " Conn = %s, Color = %s\n", get_jack_connection(caps), get_jack_color(caps)); @@ -478,7 +526,7 @@ static const char *get_pwr_state(u32 state) static void print_power_state(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { - static char *names[] = { + static const char * const names[] = { [ilog2(AC_PWRST_D0SUP)] = "D0", [ilog2(AC_PWRST_D1SUP)] = "D1", [ilog2(AC_PWRST_D2SUP)] = "D2", @@ -492,9 +540,16 @@ static void print_power_state(struct snd_info_buffer *buffer, int sup = param_read(codec, nid, AC_PAR_POWER_STATE); int pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); - if (sup != -1) - snd_iprintf(buffer, " Power states: %s\n", - bits_names(sup, names, ARRAY_SIZE(names))); + if (sup != -1) { + int i; + + snd_iprintf(buffer, " Power states: "); + for (i = 0; i < ARRAY_SIZE(names); i++) { + if (sup & (1U << i)) + snd_iprintf(buffer, " %s", names[i]); + } + snd_iprintf(buffer, "\n"); + } snd_iprintf(buffer, " Power: setting=%s, actual=%s", get_pwr_state(pwr & AC_PWRST_SETTING), diff --git a/kernel/sound/pci/hda/hda_sysfs.c b/kernel/sound/pci/hda/hda_sysfs.c index a6e3d9b51..64e0d1d81 100644 --- a/kernel/sound/pci/hda/hda_sysfs.c +++ b/kernel/sound/pci/hda/hda_sysfs.c @@ -595,8 +595,7 @@ static void parse_model_mode(char *buf, struct hda_bus *bus, static void parse_chip_name_mode(char *buf, struct hda_bus *bus, struct hda_codec **codecp) { - kfree((*codecp)->core.chip_name); - (*codecp)->core.chip_name = kstrdup(buf, GFP_KERNEL); + snd_hda_codec_set_name(*codecp, buf); } #define DEFINE_PARSE_ID_MODE(name) \ diff --git a/kernel/sound/pci/hda/hda_tegra.c b/kernel/sound/pci/hda/hda_tegra.c index 2e4fd5c56..58c0aad37 100644 --- a/kernel/sound/pci/hda/hda_tegra.c +++ b/kernel/sound/pci/hda/hda_tegra.c @@ -73,6 +73,7 @@ struct hda_tegra { struct clk *hda2codec_2x_clk; struct clk *hda2hdmi_clk; void __iomem *regs; + struct work_struct probe_work; }; #ifdef CONFIG_PM @@ -87,13 +88,13 @@ MODULE_PARM_DESC(power_save, /* * DMA page allocation ops. */ -static int dma_alloc_pages(struct azx *chip, int type, size_t size, +static int dma_alloc_pages(struct hdac_bus *bus, int type, size_t size, struct snd_dma_buffer *buf) { - return snd_dma_alloc_pages(type, chip->card->dev, size, buf); + return snd_dma_alloc_pages(type, bus->dev, size, buf); } -static void dma_free_pages(struct azx *chip, struct snd_dma_buffer *buf) +static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) { snd_dma_free_pages(buf); } @@ -102,11 +103,6 @@ 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); - - azx_dev->bufsize = 0; - azx_dev->period_bytes = 0; - azx_dev->format_val = 0; return snd_pcm_lib_malloc_pages(substream, size); } @@ -173,7 +169,7 @@ static u8 hda_tegra_readb(u8 *addr) return (v >> shift) & 0xff; } -static const struct hda_controller_ops hda_tegra_ops = { +static const struct hdac_io_ops hda_tegra_io_ops = { .reg_writel = hda_tegra_writel, .reg_readl = hda_tegra_readl, .reg_writew = hda_tegra_writew, @@ -182,6 +178,9 @@ static const struct hda_controller_ops hda_tegra_ops = { .reg_readb = hda_tegra_readb, .dma_alloc_pages = dma_alloc_pages, .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, }; @@ -282,21 +281,31 @@ static const struct dev_pm_ops hda_tegra_pm = { SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) }; +static int hda_tegra_dev_disconnect(struct snd_device *device) +{ + struct azx *chip = device->device_data; + + chip->bus.shutdown = 1; + return 0; +} + /* * destructor */ static int hda_tegra_dev_free(struct snd_device *device) { - int i; struct azx *chip = device->device_data; + struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); - if (chip->initialized) { - for (i = 0; i < chip->num_streams; i++) - azx_stream_stop(chip, &chip->azx_dev[i]); + cancel_work_sync(&hda->probe_work); + if (azx_bus(chip)->chip_init) { + azx_stop_all_streams(chip); azx_stop_chip(chip); } azx_free_stream_pages(chip); + azx_free_streams(chip); + snd_hdac_bus_exit(azx_bus(chip)); return 0; } @@ -304,31 +313,40 @@ static int hda_tegra_dev_free(struct snd_device *device) static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) { struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); + struct hdac_bus *bus = azx_bus(chip); struct device *dev = hda->dev; struct resource *res; int err; hda->hda_clk = devm_clk_get(dev, "hda"); - if (IS_ERR(hda->hda_clk)) + if (IS_ERR(hda->hda_clk)) { + dev_err(dev, "failed to get hda clock\n"); return PTR_ERR(hda->hda_clk); + } hda->hda2codec_2x_clk = devm_clk_get(dev, "hda2codec_2x"); - if (IS_ERR(hda->hda2codec_2x_clk)) + if (IS_ERR(hda->hda2codec_2x_clk)) { + dev_err(dev, "failed to get hda2codec_2x clock\n"); return PTR_ERR(hda->hda2codec_2x_clk); + } hda->hda2hdmi_clk = devm_clk_get(dev, "hda2hdmi"); - if (IS_ERR(hda->hda2hdmi_clk)) + if (IS_ERR(hda->hda2hdmi_clk)) { + dev_err(dev, "failed to get hda2hdmi clock\n"); return PTR_ERR(hda->hda2hdmi_clk); + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hda->regs = devm_ioremap_resource(dev, res); if (IS_ERR(hda->regs)) return PTR_ERR(hda->regs); - chip->remap_addr = hda->regs + HDA_BAR0; - chip->addr = res->start + HDA_BAR0; + bus->remap_addr = hda->regs + HDA_BAR0; + bus->addr = res->start + HDA_BAR0; err = hda_tegra_enable_clocks(hda); - if (err) + if (err) { + dev_err(dev, "failed to get enable clocks\n"); return err; + } hda_tegra_init(hda); @@ -337,6 +355,7 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) { + struct hdac_bus *bus = azx_bus(chip); struct snd_card *card = chip->card; int err; unsigned short gcap; @@ -354,9 +373,9 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) irq_id); return err; } - chip->irq = irq_id; + bus->irq = irq_id; - synchronize_irq(chip->irq); + synchronize_irq(bus->irq); gcap = azx_readw(chip, GCAP); dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); @@ -374,23 +393,26 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) chip->capture_index_offset = 0; chip->playback_index_offset = chip->capture_streams; chip->num_streams = chip->playback_streams + chip->capture_streams; - chip->azx_dev = devm_kcalloc(card->dev, chip->num_streams, - sizeof(*chip->azx_dev), GFP_KERNEL); - if (!chip->azx_dev) - return -ENOMEM; - err = azx_alloc_stream_pages(chip); - if (err < 0) + /* initialize streams */ + err = azx_init_streams(chip); + if (err < 0) { + dev_err(card->dev, "failed to initialize streams: %d\n", err); return err; + } - /* initialize streams */ - azx_init_stream(chip); + err = azx_alloc_stream_pages(chip); + if (err < 0) { + dev_err(card->dev, "failed to allocate stream pages: %d\n", + err); + return err; + } /* initialize chip */ azx_init_chip(chip, 1); /* codec detection */ - if (!chip->codec_mask) { + if (!bus->codec_mask) { dev_err(card->dev, "no codecs found!\n"); return -ENODEV; } @@ -399,7 +421,7 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) strcpy(card->shortname, "tegra-hda"); snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx irq %i", - card->shortname, chip->addr, chip->irq); + card->shortname, bus->addr, bus->irq); return 0; } @@ -407,12 +429,15 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) /* * constructor */ + +static void hda_tegra_probe_work(struct work_struct *work); + static int hda_tegra_create(struct snd_card *card, unsigned int driver_caps, - const struct hda_controller_ops *hda_ops, struct hda_tegra *hda) { static struct snd_device_ops ops = { + .dev_disconnect = hda_tegra_dev_disconnect, .dev_free = hda_tegra_dev_free, }; struct azx *chip; @@ -420,11 +445,9 @@ static int hda_tegra_create(struct snd_card *card, chip = &hda->chip; - spin_lock_init(&chip->reg_lock); mutex_init(&chip->open_mutex); chip->card = card; - chip->ops = hda_ops; - chip->irq = -1; + chip->ops = &hda_tegra_ops; chip->driver_caps = driver_caps; chip->driver_type = driver_caps & 0xff; chip->dev_index = 0; @@ -435,6 +458,12 @@ static int hda_tegra_create(struct snd_card *card, chip->single_cmd = false; chip->snoop = true; + INIT_WORK(&hda->probe_work, hda_tegra_probe_work); + + err = azx_bus_init(chip, NULL, &hda_tegra_io_ops); + if (err < 0) + return err; + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { dev_err(card->dev, "Error creating device\n"); @@ -452,11 +481,12 @@ MODULE_DEVICE_TABLE(of, hda_tegra_match); static int hda_tegra_probe(struct platform_device *pdev) { + const unsigned int driver_flags = AZX_DCAPS_RIRB_DELAY | + AZX_DCAPS_CORBRP_SELF_CLEAR; struct snd_card *card; struct azx *chip; struct hda_tegra *hda; int err; - const unsigned int driver_flags = AZX_DCAPS_RIRB_DELAY; hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); if (!hda) @@ -471,22 +501,33 @@ static int hda_tegra_probe(struct platform_device *pdev) return err; } - err = hda_tegra_create(card, driver_flags, &hda_tegra_ops, hda); + err = hda_tegra_create(card, driver_flags, hda); if (err < 0) goto out_free; card->private_data = chip; dev_set_drvdata(&pdev->dev, card); + schedule_work(&hda->probe_work); + + return 0; + +out_free: + snd_card_free(card); + return err; +} + +static void hda_tegra_probe_work(struct work_struct *work) +{ + struct hda_tegra *hda = container_of(work, struct hda_tegra, probe_work); + struct azx *chip = &hda->chip; + struct platform_device *pdev = to_platform_device(hda->dev); + int err; err = hda_tegra_first_init(chip, pdev); if (err < 0) goto out_free; /* create codec instances */ - err = azx_bus_create(chip, NULL); - if (err < 0) - goto out_free; - err = azx_probe_codecs(chip, 0); if (err < 0) goto out_free; @@ -500,13 +541,10 @@ static int hda_tegra_probe(struct platform_device *pdev) goto out_free; chip->running = 1; - snd_hda_set_power_save(chip->bus, power_save * 1000); - - return 0; + snd_hda_set_power_save(&chip->bus, power_save * 1000); -out_free: - snd_card_free(card); - return err; + out_free: + return; /* no error return from async probe */ } static int hda_tegra_remove(struct platform_device *pdev) diff --git a/kernel/sound/pci/hda/patch_analog.c b/kernel/sound/pci/hda/patch_analog.c index 231f89029..e0fb8c6d1 100644 --- a/kernel/sound/pci/hda/patch_analog.c +++ b/kernel/sound/pci/hda/patch_analog.c @@ -205,8 +205,6 @@ static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp) if (err < 0) return err; - codec->patch_ops = ad198x_auto_patch_ops; - return 0; } @@ -223,6 +221,7 @@ static int alloc_ad_spec(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; snd_hda_gen_spec_init(&spec->gen); + codec->patch_ops = ad198x_auto_patch_ops; return 0; } @@ -1166,32 +1165,31 @@ static int patch_ad1882(struct hda_codec *codec) /* * patch entries */ -static const struct hda_codec_preset snd_hda_preset_analog[] = { - { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 }, - { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, - { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 }, - { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, - { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 }, - { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 }, - { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, - { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, - { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 }, - { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, - { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, - { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, - { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 }, - { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 }, - { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 }, +static const struct hda_device_id snd_hda_id_analog[] = { + HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884), + HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882), + HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884), + HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884), + HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884), + HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884), + HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981), + HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983), + HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884), + HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a), + HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988), + HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988), + HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882), + HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988), + HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:11d4*"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Analog Devices HD-audio codec"); static struct hda_codec_driver analog_driver = { - .preset = snd_hda_preset_analog, + .id = snd_hda_id_analog, }; module_hda_codec_driver(analog_driver); diff --git a/kernel/sound/pci/hda/patch_ca0110.c b/kernel/sound/pci/hda/patch_ca0110.c index 447302695..c2d9ee9cf 100644 --- a/kernel/sound/pci/hda/patch_ca0110.c +++ b/kernel/sound/pci/hda/patch_ca0110.c @@ -63,6 +63,7 @@ static int patch_ca0110(struct hda_codec *codec) return -ENOMEM; snd_hda_gen_spec_init(spec); codec->spec = spec; + codec->patch_ops = ca0110_patch_ops; spec->multi_cap_vol = 1; codec->bus->needs_damn_long_delay = 1; @@ -71,8 +72,6 @@ static int patch_ca0110(struct hda_codec *codec) if (err < 0) goto error; - codec->patch_ops = ca0110_patch_ops; - return 0; error: @@ -84,22 +83,19 @@ static int patch_ca0110(struct hda_codec *codec) /* * patch entries */ -static const struct hda_codec_preset snd_hda_preset_ca0110[] = { - { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 }, - { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 }, - { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 }, +static const struct hda_device_id snd_hda_id_ca0110[] = { + HDA_CODEC_ENTRY(0x1102000a, "CA0110-IBG", patch_ca0110), + HDA_CODEC_ENTRY(0x1102000b, "CA0110-IBG", patch_ca0110), + HDA_CODEC_ENTRY(0x1102000d, "SB0880 X-Fi", patch_ca0110), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:1102000a"); -MODULE_ALIAS("snd-hda-codec-id:1102000b"); -MODULE_ALIAS("snd-hda-codec-id:1102000d"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0110); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec"); static struct hda_codec_driver ca0110_driver = { - .preset = snd_hda_preset_ca0110, + .id = snd_hda_id_ca0110, }; module_hda_codec_driver(ca0110_driver); diff --git a/kernel/sound/pci/hda/patch_ca0132.c b/kernel/sound/pci/hda/patch_ca0132.c index 4a4e7b282..9ceb2bc36 100644 --- a/kernel/sound/pci/hda/patch_ca0132.c +++ b/kernel/sound/pci/hda/patch_ca0132.c @@ -43,8 +43,6 @@ #define FLOAT_TWO 0x40000000 #define FLOAT_MINUS_5 0xc0a00000 -#define UNSOL_TAG_HP 0x10 -#define UNSOL_TAG_AMIC1 0x12 #define UNSOL_TAG_DSP 0x16 #define DSP_DMA_WRITE_BUFLEN_INIT (1UL<<18) @@ -703,8 +701,8 @@ struct ca0132_spec { unsigned int num_mixers; const struct hda_verb *base_init_verbs; const struct hda_verb *base_exit_verbs; - const struct hda_verb *init_verbs[5]; - unsigned int num_init_verbs; /* exclude base init verbs */ + const struct hda_verb *chip_init_verbs; + struct hda_verb *spec_init_verbs; struct auto_pin_cfg autocfg; /* Nodes configurations */ @@ -719,6 +717,8 @@ struct ca0132_spec { unsigned int num_inputs; hda_nid_t shared_mic_nid; hda_nid_t shared_out_nid; + hda_nid_t unsol_tag_hp; + hda_nid_t unsol_tag_amic1; /* chip access */ struct mutex chipio_mutex; /* chip access mutex */ @@ -748,6 +748,7 @@ struct ca0132_spec { struct hda_codec *codec; struct delayed_work unsol_hp_work; + int quirk; #ifdef ENABLE_TUNING_CONTROLS long cur_ctl_vals[TUNING_CTLS_COUNT]; @@ -755,6 +756,34 @@ struct ca0132_spec { }; /* + * CA0132 quirks table + */ +enum { + QUIRK_NONE, + QUIRK_ALIENWARE, +}; + +static const struct hda_pintbl alienware_pincfgs[] = { + { 0x0b, 0x90170110 }, /* Builtin Speaker */ + { 0x0c, 0x411111f0 }, /* N/A */ + { 0x0d, 0x411111f0 }, /* N/A */ + { 0x0e, 0x411111f0 }, /* N/A */ + { 0x0f, 0x0321101f }, /* HP */ + { 0x10, 0x411111f0 }, /* Headset? disabled for now */ + { 0x11, 0x03a11021 }, /* Mic */ + { 0x12, 0xd5a30140 }, /* Builtin Mic */ + { 0x13, 0x411111f0 }, /* N/A */ + { 0x18, 0x411111f0 }, /* N/A */ + {} +}; + +static const struct snd_pci_quirk ca0132_quirks[] = { + SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE), + SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE), + {} +}; + +/* * CA0132 codec access */ static unsigned int codec_send_command(struct hda_codec *codec, hda_nid_t nid, @@ -2052,11 +2081,8 @@ static int dma_convert_to_hda_format(struct hda_codec *codec, { unsigned int format_val; - format_val = snd_hda_calc_stream_format(codec, - sample_rate, - channels, - SNDRV_PCM_FORMAT_S32_LE, - 32, 0); + format_val = snd_hdac_calc_stream_format(sample_rate, + channels, SNDRV_PCM_FORMAT_S32_LE, 32, 0); if (hda_format) *hda_format = (unsigned short)format_val; @@ -2648,13 +2674,13 @@ static bool dspload_wait_loaded(struct hda_codec *codec) do { if (dspload_is_loaded(codec)) { - pr_info("ca0132 DOWNLOAD OK :-) DSP IS RUNNING.\n"); + codec_info(codec, "ca0132 DSP downloaded and running\n"); return true; } msleep(20); } while (time_before(jiffies, timeout)); - pr_err("ca0132 DOWNLOAD FAILED!!! DSP IS NOT RUNNING.\n"); + codec_err(codec, "ca0132 failed to download DSP\n"); return false; } @@ -3136,7 +3162,7 @@ static int ca0132_select_out(struct hda_codec *codec) auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; if (auto_jack) - jack_present = snd_hda_jack_detect(codec, spec->out_pins[1]); + jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_hp); else jack_present = spec->vnode_lswitch[VNID_HP_SEL - VNODE_START_NID]; @@ -3227,7 +3253,7 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work) struct hda_jack_tbl *jack; ca0132_select_out(spec->codec); - jack = snd_hda_jack_tbl_get(spec->codec, UNSOL_TAG_HP); + jack = snd_hda_jack_tbl_get(spec->codec, spec->unsol_tag_hp); if (jack) { jack->block_report = 0; snd_hda_jack_report_sync(spec->codec); @@ -3298,7 +3324,7 @@ static int ca0132_select_mic(struct hda_codec *codec) auto_jack = spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID]; if (auto_jack) - jack_present = snd_hda_jack_detect(codec, spec->input_pins[0]); + jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_amic1); else jack_present = spec->vnode_lswitch[VNID_AMIC1_SEL - VNODE_START_NID]; @@ -4350,7 +4376,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) dsp_os_image = (struct dsp_image_seg *)(fw_entry->data); if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) { - pr_err("ca0132 dspload_image failed.\n"); + codec_err(codec, "ca0132 DSP load image failed\n"); goto exit_download; } @@ -4401,13 +4427,16 @@ static void ca0132_process_dsp_response(struct hda_codec *codec, static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) { struct ca0132_spec *spec = codec->spec; + struct hda_jack_tbl *tbl; /* Delay enabling the HP amp, to let the mic-detection * state machine run. */ cancel_delayed_work_sync(&spec->unsol_hp_work); schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500)); - cb->tbl->block_report = 1; + tbl = snd_hda_jack_tbl_get(codec, cb->nid); + if (tbl) + tbl->block_report = 1; } static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb) @@ -4417,8 +4446,9 @@ static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb) static void ca0132_init_unsol(struct hda_codec *codec) { - snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_HP, hp_callback); - snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_AMIC1, + struct ca0132_spec *spec = codec->spec; + snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_hp, hp_callback); + snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_amic1, amic_callback); snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP, ca0132_process_dsp_response); @@ -4479,17 +4509,6 @@ static struct hda_verb ca0132_init_verbs0[] = { {} }; -static struct hda_verb ca0132_init_verbs1[] = { - {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_HP}, - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_AMIC1}, - /* config EAPD */ - {0x0b, 0x78D, 0x00}, - /*{0x0b, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/ - /*{0x10, 0x78D, 0x02},*/ - /*{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/ - {} -}; - static void ca0132_init_chip(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -4569,8 +4588,8 @@ static int ca0132_init(struct hda_codec *codec) init_input(codec, cfg->dig_in_pin, spec->dig_in); - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); + snd_hda_sequence_write(codec, spec->chip_init_verbs); + snd_hda_sequence_write(codec, spec->spec_init_verbs); ca0132_select_out(codec); ca0132_select_mic(codec); @@ -4591,6 +4610,7 @@ static void ca0132_free(struct hda_codec *codec) snd_hda_sequence_write(codec, spec->base_exit_verbs); ca0132_exit_chip(codec); snd_hda_power_down(codec); + kfree(spec->spec_init_verbs); kfree(codec->spec); } @@ -4615,36 +4635,106 @@ static void ca0132_config(struct hda_codec *codec) spec->multiout.num_dacs = 3; spec->multiout.max_channels = 2; - spec->num_outputs = 2; - spec->out_pins[0] = 0x0b; /* speaker out */ - spec->out_pins[1] = 0x10; /* headphone out */ - spec->shared_out_nid = 0x2; + if (spec->quirk == QUIRK_ALIENWARE) { + codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n"); + snd_hda_apply_pincfgs(codec, alienware_pincfgs); + + spec->num_outputs = 2; + spec->out_pins[0] = 0x0b; /* speaker out */ + spec->out_pins[1] = 0x0f; + spec->shared_out_nid = 0x2; + spec->unsol_tag_hp = 0x0f; + + spec->adcs[0] = 0x7; /* digital mic / analog mic1 */ + spec->adcs[1] = 0x8; /* analog mic2 */ + spec->adcs[2] = 0xa; /* what u hear */ + + spec->num_inputs = 3; + spec->input_pins[0] = 0x12; + spec->input_pins[1] = 0x11; + spec->input_pins[2] = 0x13; + spec->shared_mic_nid = 0x7; + spec->unsol_tag_amic1 = 0x11; + } else { + spec->num_outputs = 2; + spec->out_pins[0] = 0x0b; /* speaker out */ + spec->out_pins[1] = 0x10; /* headphone out */ + spec->shared_out_nid = 0x2; + spec->unsol_tag_hp = spec->out_pins[1]; + + spec->adcs[0] = 0x7; /* digital mic / analog mic1 */ + spec->adcs[1] = 0x8; /* analog mic2 */ + spec->adcs[2] = 0xa; /* what u hear */ + + spec->num_inputs = 3; + spec->input_pins[0] = 0x12; + spec->input_pins[1] = 0x11; + spec->input_pins[2] = 0x13; + 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; + cfg->dig_out_pins[0] = 0x0c; + cfg->dig_outs = 1; + cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF; + spec->dig_in = 0x09; + cfg->dig_in_pin = 0x0e; + cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; + } +} - spec->num_inputs = 3; - spec->adcs[0] = 0x7; /* digital mic / analog mic1 */ - spec->adcs[1] = 0x8; /* analog mic2 */ - spec->adcs[2] = 0xa; /* what u hear */ - spec->shared_mic_nid = 0x7; +static int ca0132_prepare_verbs(struct hda_codec *codec) +{ +/* Verbs + terminator (an empty element) */ +#define NUM_SPEC_VERBS 4 + struct ca0132_spec *spec = codec->spec; + + spec->chip_init_verbs = ca0132_init_verbs0; + spec->spec_init_verbs = kzalloc(sizeof(struct hda_verb) * NUM_SPEC_VERBS, GFP_KERNEL); + if (!spec->spec_init_verbs) + return -ENOMEM; - spec->input_pins[0] = 0x12; - spec->input_pins[1] = 0x11; - spec->input_pins[2] = 0x13; + /* HP jack autodetection */ + spec->spec_init_verbs[0].nid = spec->unsol_tag_hp; + spec->spec_init_verbs[0].param = AC_VERB_SET_UNSOLICITED_ENABLE; + spec->spec_init_verbs[0].verb = AC_USRSP_EN | spec->unsol_tag_hp; - /* SPDIF I/O */ - spec->dig_out = 0x05; - spec->multiout.dig_out_nid = spec->dig_out; - cfg->dig_out_pins[0] = 0x0c; - cfg->dig_outs = 1; - cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF; - spec->dig_in = 0x09; - cfg->dig_in_pin = 0x0e; - cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; + /* MIC1 jack autodetection */ + spec->spec_init_verbs[1].nid = spec->unsol_tag_amic1; + spec->spec_init_verbs[1].param = AC_VERB_SET_UNSOLICITED_ENABLE; + spec->spec_init_verbs[1].verb = AC_USRSP_EN | spec->unsol_tag_amic1; + + /* config EAPD */ + spec->spec_init_verbs[2].nid = 0x0b; + spec->spec_init_verbs[2].param = 0x78D; + spec->spec_init_verbs[2].verb = 0x00; + + /* Previously commented configuration */ + /* + spec->spec_init_verbs[3].nid = 0x0b; + spec->spec_init_verbs[3].param = AC_VERB_SET_EAPD_BTLENABLE; + spec->spec_init_verbs[3].verb = 0x02; + + spec->spec_init_verbs[4].nid = 0x10; + spec->spec_init_verbs[4].param = 0x78D; + spec->spec_init_verbs[4].verb = 0x02; + + spec->spec_init_verbs[5].nid = 0x10; + spec->spec_init_verbs[5].param = AC_VERB_SET_EAPD_BTLENABLE; + spec->spec_init_verbs[5].verb = 0x02; + */ + + /* Terminator: spec->spec_init_verbs[NUM_SPEC_VERBS-1] */ + return 0; } static int patch_ca0132(struct hda_codec *codec) { struct ca0132_spec *spec; int err; + const struct snd_pci_quirk *quirk; codec_dbg(codec, "patch_ca0132\n"); @@ -4654,15 +4744,23 @@ 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) + spec->quirk = quirk->value; + else + spec->quirk = QUIRK_NONE; + spec->dsp_state = DSP_DOWNLOAD_INIT; spec->num_mixers = 1; spec->mixers[0] = ca0132_mixer; spec->base_init_verbs = ca0132_base_init_verbs; spec->base_exit_verbs = ca0132_base_exit_verbs; - spec->init_verbs[0] = ca0132_init_verbs0; - spec->init_verbs[1] = ca0132_init_verbs1; - spec->num_init_verbs = 2; INIT_DELAYED_WORK(&spec->unsol_hp_work, ca0132_unsol_hp_delayed); @@ -4670,13 +4768,13 @@ static int patch_ca0132(struct hda_codec *codec) ca0132_config(codec); - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + err = ca0132_prepare_verbs(codec); if (err < 0) return err; - codec->patch_ops = ca0132_patch_ops; - codec->pcm_format_first = 1; - codec->no_sticky_stream = 1; + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; return 0; } @@ -4684,18 +4782,17 @@ static int patch_ca0132(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_ca0132[] = { - { .id = 0x11020011, .name = "CA0132", .patch = patch_ca0132 }, +static struct hda_device_id snd_hda_id_ca0132[] = { + HDA_CODEC_ENTRY(0x11020011, "CA0132", patch_ca0132), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:11020011"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0132); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Creative Sound Core3D codec"); static struct hda_codec_driver ca0132_driver = { - .preset = snd_hda_preset_ca0132, + .id = snd_hda_id_ca0132, }; module_hda_codec_driver(ca0132_driver); diff --git a/kernel/sound/pci/hda/patch_cirrus.c b/kernel/sound/pci/hda/patch_cirrus.c index 3a24f7739..c1c855a6c 100644 --- a/kernel/sound/pci/hda/patch_cirrus.c +++ b/kernel/sound/pci/hda/patch_cirrus.c @@ -570,6 +570,7 @@ static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid) return NULL; codec->spec = spec; spec->vendor_nid = vendor_nid; + codec->power_save_node = 1; snd_hda_gen_spec_init(&spec->gen); return spec; @@ -584,6 +585,7 @@ static int patch_cs420x(struct hda_codec *codec) if (!spec) return -ENOMEM; + codec->patch_ops = cs_patch_ops; spec->gen.automute_hook = cs_automute; codec->single_adc_amp = 1; @@ -595,8 +597,6 @@ static int patch_cs420x(struct hda_codec *codec) if (err < 0) goto error; - codec->patch_ops = cs_patch_ops; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -614,6 +614,7 @@ enum { CS4208_MAC_AUTO, CS4208_MBA6, CS4208_MBP11, + CS4208_MACMINI, CS4208_GPIO0, }; @@ -621,6 +622,7 @@ static const struct hda_model_fixup cs4208_models[] = { { .id = CS4208_GPIO0, .name = "gpio0" }, { .id = CS4208_MBA6, .name = "mba6" }, { .id = CS4208_MBP11, .name = "mbp11" }, + { .id = CS4208_MACMINI, .name = "macmini" }, {} }; @@ -632,8 +634,10 @@ static const struct snd_pci_quirk cs4208_fixup_tbl[] = { /* codec SSID matching */ static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11), + SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI), SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6), SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6), + SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11), {} /* terminator */ }; @@ -665,6 +669,24 @@ static void cs4208_fixup_mac(struct hda_codec *codec, snd_hda_apply_fixup(codec, action); } +/* MacMini 7,1 has the inverted jack detection */ +static void cs4208_fixup_macmini(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const struct hda_pintbl pincfgs[] = { + { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */ + { 0x21, 0x004be140 }, /* SPDIF: disable detect */ + { } + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + /* HP pin (0x10) has an inverted detection */ + codec->inv_jack_detect = 1; + /* disable the bogus Mic and SPDIF jack detections */ + snd_hda_apply_pincfgs(codec, pincfgs); + } +} + static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -708,6 +730,12 @@ static const struct hda_fixup cs4208_fixups[] = { .chained = true, .chain_id = CS4208_GPIO0, }, + [CS4208_MACMINI] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs4208_fixup_macmini, + .chained = true, + .chain_id = CS4208_GPIO0, + }, [CS4208_GPIO0] = { .type = HDA_FIXUP_FUNC, .v.func = cs4208_fixup_gpio0, @@ -738,6 +766,7 @@ static int patch_cs4208(struct hda_codec *codec) if (!spec) return -ENOMEM; + codec->patch_ops = cs_patch_ops; spec->gen.automute_hook = cs_automute; /* exclude NID 0x10 (HP) from output volumes due to different steps */ spec->gen.out_vol_mask = 1ULL << 0x10; @@ -756,8 +785,6 @@ static int patch_cs4208(struct hda_codec *codec) if (err < 0) goto error; - codec->patch_ops = cs_patch_ops; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -1148,6 +1175,7 @@ static int patch_cs4210(struct hda_codec *codec) if (!spec) return -ENOMEM; + codec->patch_ops = cs421x_patch_ops; spec->gen.automute_hook = cs_automute; snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl, @@ -1165,8 +1193,6 @@ static int patch_cs4210(struct hda_codec *codec) if (err < 0) goto error; - codec->patch_ops = cs421x_patch_ops; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -1185,11 +1211,12 @@ static int patch_cs4213(struct hda_codec *codec) if (!spec) return -ENOMEM; + codec->patch_ops = cs421x_patch_ops; + err = cs421x_parse_auto_config(codec); if (err < 0) goto error; - codec->patch_ops = cs421x_patch_ops; return 0; error: @@ -1201,26 +1228,21 @@ static int patch_cs4213(struct hda_codec *codec) /* * patch entries */ -static const struct hda_codec_preset snd_hda_preset_cirrus[] = { - { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, - { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, - { .id = 0x10134208, .name = "CS4208", .patch = patch_cs4208 }, - { .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 }, - { .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 }, +static const struct hda_device_id snd_hda_id_cirrus[] = { + HDA_CODEC_ENTRY(0x10134206, "CS4206", patch_cs420x), + HDA_CODEC_ENTRY(0x10134207, "CS4207", patch_cs420x), + HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208), + HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210), + HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:10134206"); -MODULE_ALIAS("snd-hda-codec-id:10134207"); -MODULE_ALIAS("snd-hda-codec-id:10134208"); -MODULE_ALIAS("snd-hda-codec-id:10134210"); -MODULE_ALIAS("snd-hda-codec-id:10134213"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); static struct hda_codec_driver cirrus_driver = { - .preset = snd_hda_preset_cirrus, + .id = snd_hda_id_cirrus, }; module_hda_codec_driver(cirrus_driver); diff --git a/kernel/sound/pci/hda/patch_cmedia.c b/kernel/sound/pci/hda/patch_cmedia.c index 617d9012e..1b2195dd2 100644 --- a/kernel/sound/pci/hda/patch_cmedia.c +++ b/kernel/sound/pci/hda/patch_cmedia.c @@ -57,6 +57,7 @@ static int patch_cmi9880(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; + codec->patch_ops = cmi_auto_patch_ops; cfg = &spec->gen.autocfg; snd_hda_gen_spec_init(&spec->gen); @@ -67,7 +68,6 @@ static int patch_cmi9880(struct hda_codec *codec) if (err < 0) goto error; - codec->patch_ops = cmi_auto_patch_ops; return 0; error: @@ -86,6 +86,7 @@ static int patch_cmi8888(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; + codec->patch_ops = cmi_auto_patch_ops; cfg = &spec->gen.autocfg; snd_hda_gen_spec_init(&spec->gen); @@ -112,7 +113,6 @@ static int patch_cmi8888(struct hda_codec *codec) } } - codec->patch_ops = cmi_auto_patch_ops; return 0; error: @@ -123,22 +123,19 @@ static int patch_cmi8888(struct hda_codec *codec) /* * patch entries */ -static const struct hda_codec_preset snd_hda_preset_cmedia[] = { - { .id = 0x13f68888, .name = "CMI8888", .patch = patch_cmi8888 }, - { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 }, - { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 }, +static const struct hda_device_id snd_hda_id_cmedia[] = { + HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888), + HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880), + HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:13f68888"); -MODULE_ALIAS("snd-hda-codec-id:13f69880"); -MODULE_ALIAS("snd-hda-codec-id:434d4980"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("C-Media HD-audio codec"); static struct hda_codec_driver cmedia_driver = { - .preset = snd_hda_preset_cmedia, + .id = snd_hda_id_cmedia, }; module_hda_codec_driver(cmedia_driver); diff --git a/kernel/sound/pci/hda/patch_conexant.c b/kernel/sound/pci/hda/patch_conexant.c index 06cc9d57b..ef198903c 100644 --- a/kernel/sound/pci/hda/patch_conexant.c +++ b/kernel/sound/pci/hda/patch_conexant.c @@ -819,6 +819,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, 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), SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), @@ -871,6 +872,7 @@ static int patch_conexant_auto(struct hda_codec *codec) return -ENOMEM; snd_hda_gen_spec_init(&spec->gen); codec->spec = spec; + codec->patch_ops = cx_auto_patch_ops; cx_auto_parse_beep(codec); cx_auto_parse_eapd(codec); @@ -929,8 +931,6 @@ static int patch_conexant_auto(struct hda_codec *codec) if (err < 0) goto error; - codec->patch_ops = cx_auto_patch_ops; - /* Some laptops with Conexant chips show stalls in S3 resume, * which falls into the single-cmd mode. * Better to make reset, then. @@ -954,100 +954,45 @@ static int patch_conexant_auto(struct hda_codec *codec) /* */ -static const struct hda_codec_preset snd_hda_preset_conexant[] = { - { .id = 0x14f15045, .name = "CX20549 (Venice)", - .patch = patch_conexant_auto }, - { .id = 0x14f15047, .name = "CX20551 (Waikiki)", - .patch = patch_conexant_auto }, - { .id = 0x14f15051, .name = "CX20561 (Hermosa)", - .patch = patch_conexant_auto }, - { .id = 0x14f15066, .name = "CX20582 (Pebble)", - .patch = patch_conexant_auto }, - { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", - .patch = patch_conexant_auto }, - { .id = 0x14f15068, .name = "CX20584", - .patch = patch_conexant_auto }, - { .id = 0x14f15069, .name = "CX20585", - .patch = patch_conexant_auto }, - { .id = 0x14f1506c, .name = "CX20588", - .patch = patch_conexant_auto }, - { .id = 0x14f1506e, .name = "CX20590", - .patch = patch_conexant_auto }, - { .id = 0x14f15097, .name = "CX20631", - .patch = patch_conexant_auto }, - { .id = 0x14f15098, .name = "CX20632", - .patch = patch_conexant_auto }, - { .id = 0x14f150a1, .name = "CX20641", - .patch = patch_conexant_auto }, - { .id = 0x14f150a2, .name = "CX20642", - .patch = patch_conexant_auto }, - { .id = 0x14f150ab, .name = "CX20651", - .patch = patch_conexant_auto }, - { .id = 0x14f150ac, .name = "CX20652", - .patch = patch_conexant_auto }, - { .id = 0x14f150b8, .name = "CX20664", - .patch = patch_conexant_auto }, - { .id = 0x14f150b9, .name = "CX20665", - .patch = patch_conexant_auto }, - { .id = 0x14f150f1, .name = "CX20721", - .patch = patch_conexant_auto }, - { .id = 0x14f150f2, .name = "CX20722", - .patch = patch_conexant_auto }, - { .id = 0x14f150f3, .name = "CX20723", - .patch = patch_conexant_auto }, - { .id = 0x14f150f4, .name = "CX20724", - .patch = patch_conexant_auto }, - { .id = 0x14f1510f, .name = "CX20751/2", - .patch = patch_conexant_auto }, - { .id = 0x14f15110, .name = "CX20751/2", - .patch = patch_conexant_auto }, - { .id = 0x14f15111, .name = "CX20753/4", - .patch = patch_conexant_auto }, - { .id = 0x14f15113, .name = "CX20755", - .patch = patch_conexant_auto }, - { .id = 0x14f15114, .name = "CX20756", - .patch = patch_conexant_auto }, - { .id = 0x14f15115, .name = "CX20757", - .patch = patch_conexant_auto }, - { .id = 0x14f151d7, .name = "CX20952", - .patch = patch_conexant_auto }, +static const struct hda_device_id snd_hda_id_conexant[] = { + HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15066, "CX20582 (Pebble)", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15067, "CX20583 (Pebble HSF)", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15068, "CX20584", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15069, "CX20585", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f1506c, "CX20588", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f1506e, "CX20590", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15097, "CX20631", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15098, "CX20632", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150a1, "CX20641", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150a2, "CX20642", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150ab, "CX20651", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15111, "CX20753/4", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15113, "CX20755", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15114, "CX20756", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f15115, "CX20757", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f151d7, "CX20952", patch_conexant_auto), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:14f15045"); -MODULE_ALIAS("snd-hda-codec-id:14f15047"); -MODULE_ALIAS("snd-hda-codec-id:14f15051"); -MODULE_ALIAS("snd-hda-codec-id:14f15066"); -MODULE_ALIAS("snd-hda-codec-id:14f15067"); -MODULE_ALIAS("snd-hda-codec-id:14f15068"); -MODULE_ALIAS("snd-hda-codec-id:14f15069"); -MODULE_ALIAS("snd-hda-codec-id:14f1506c"); -MODULE_ALIAS("snd-hda-codec-id:14f1506e"); -MODULE_ALIAS("snd-hda-codec-id:14f15097"); -MODULE_ALIAS("snd-hda-codec-id:14f15098"); -MODULE_ALIAS("snd-hda-codec-id:14f150a1"); -MODULE_ALIAS("snd-hda-codec-id:14f150a2"); -MODULE_ALIAS("snd-hda-codec-id:14f150ab"); -MODULE_ALIAS("snd-hda-codec-id:14f150ac"); -MODULE_ALIAS("snd-hda-codec-id:14f150b8"); -MODULE_ALIAS("snd-hda-codec-id:14f150b9"); -MODULE_ALIAS("snd-hda-codec-id:14f150f1"); -MODULE_ALIAS("snd-hda-codec-id:14f150f2"); -MODULE_ALIAS("snd-hda-codec-id:14f150f3"); -MODULE_ALIAS("snd-hda-codec-id:14f150f4"); -MODULE_ALIAS("snd-hda-codec-id:14f1510f"); -MODULE_ALIAS("snd-hda-codec-id:14f15110"); -MODULE_ALIAS("snd-hda-codec-id:14f15111"); -MODULE_ALIAS("snd-hda-codec-id:14f15113"); -MODULE_ALIAS("snd-hda-codec-id:14f15114"); -MODULE_ALIAS("snd-hda-codec-id:14f15115"); -MODULE_ALIAS("snd-hda-codec-id:14f151d7"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_conexant); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Conexant HD-audio codec"); static struct hda_codec_driver conexant_driver = { - .preset = snd_hda_preset_conexant, + .id = snd_hda_id_conexant, }; module_hda_codec_driver(conexant_driver); diff --git a/kernel/sound/pci/hda/patch_hdmi.c b/kernel/sound/pci/hda/patch_hdmi.c index 225b78b4e..70c945603 100644 --- a/kernel/sound/pci/hda/patch_hdmi.c +++ b/kernel/sound/pci/hda/patch_hdmi.c @@ -37,6 +37,8 @@ #include <sound/jack.h> #include <sound/asoundef.h> #include <sound/tlv.h> +#include <sound/hdaudio.h> +#include <sound/hda_i915.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_jack.h" @@ -48,8 +50,9 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); #define is_haswell(codec) ((codec)->core.vendor_id == 0x80862807) #define is_broadwell(codec) ((codec)->core.vendor_id == 0x80862808) #define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809) +#define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a) #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \ - || is_skylake(codec)) + || is_skylake(codec) || is_broxton(codec)) #define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882) #define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883) @@ -86,7 +89,7 @@ struct hdmi_spec_per_pin { bool non_pcm; bool chmap_set; /* channel-map override by ALSA API? */ unsigned char chmap[8]; /* ALSA API channel-map */ -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS struct snd_info_entry *proc_entry; #endif }; @@ -144,6 +147,9 @@ struct hdmi_spec { */ struct hda_multi_out multiout; struct hda_pcm_stream pcm_playback; + + /* i915/powerwell (Haswell+/Valleyview+) specific */ + struct i915_audio_component_audio_ops i915_audio_ops; }; @@ -432,7 +438,8 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, eld = &per_pin->sink_eld; mutex_lock(&per_pin->lock); - if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) { + if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) || + eld->eld_size > ELD_MAX_SIZE) { mutex_unlock(&per_pin->lock); snd_BUG(); return -EINVAL; @@ -548,7 +555,7 @@ static void hdmi_set_channel_count(struct hda_codec *codec, * ELD proc files */ -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS static void print_eld_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { @@ -591,8 +598,8 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index) static void eld_proc_free(struct hdmi_spec_per_pin *per_pin) { - if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) { - snd_device_free(per_pin->codec->card, per_pin->proc_entry); + if (!per_pin->codec->bus->shutdown) { + snd_info_free_entry(per_pin->proc_entry); per_pin->proc_entry = NULL; } } @@ -1177,7 +1184,7 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid) static void jack_callback(struct hda_codec *codec, struct hda_jack_callback *jack) { - check_presence_and_report(codec, jack->tbl->nid); + check_presence_and_report(codec, jack->nid); } static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -1770,6 +1777,16 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) return non_pcm; } +/* There is a fixed mapping between audio pin node and display port + * on current Intel platforms: + * Pin Widget 5 - PORT B (port = 1 in i915 driver) + * Pin Widget 6 - PORT C (port = 2 in i915 driver) + * Pin Widget 7 - PORT D (port = 3 in i915 driver) + */ +static int intel_pin2port(hda_nid_t pin_nid) +{ + return pin_nid - 4; +} /* * HDMI callbacks @@ -1786,6 +1803,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, int pin_idx = hinfo_to_pin_index(codec, hinfo); struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; + struct snd_pcm_runtime *runtime = substream->runtime; + struct i915_audio_component *acomp = codec->bus->core.audio_component; bool non_pcm; int pinctl; @@ -1802,6 +1821,13 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx); } + /* Call sync_audio_rate to set the N/CTS/M manually if necessary */ + /* Todo: add DP1.2 MST audio support later */ + if (acomp && acomp->ops && acomp->ops->sync_audio_rate) + acomp->ops->sync_audio_rate(acomp->dev, + intel_pin2port(pin_nid), + runtime->rate); + non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); mutex_lock(&per_pin->lock); per_pin->channels = substream->runtime->channels; @@ -2049,9 +2075,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hda_pcm *info; struct hda_pcm_stream *pstr; - struct hdmi_spec_per_pin *per_pin; - per_pin = get_pin(spec, pin_idx); info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx); if (!info) return -ENOMEM; @@ -2074,14 +2098,17 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); int pcmdev = get_pcm_rec(spec, pin_idx)->device; + bool phantom_jack; if (pcmdev > 0) sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); - if (!is_jack_detectable(codec, per_pin->pin_nid)) + phantom_jack = !is_jack_detectable(codec, per_pin->pin_nid); + if (phantom_jack) strncat(hdmi_str, " Phantom", sizeof(hdmi_str) - strlen(hdmi_str) - 1); - return snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, 0); + return snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, + phantom_jack); } static int generic_hdmi_build_controls(struct hda_codec *codec) @@ -2193,6 +2220,9 @@ static void generic_hdmi_free(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int pin_idx; + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) + snd_hdac_i915_register_notifier(NULL); + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); @@ -2318,6 +2348,20 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, snd_hda_codec_set_power_to_all(codec, fg, power_state); } +static void intel_pin_eld_notify(void *audio_ptr, int port) +{ + struct hda_codec *codec = audio_ptr; + int pin_nid = port + 0x04; + + /* skip notification during system suspend (but not in runtime PM); + * the state will be updated at resume + */ + if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) + return; + + check_presence_and_report(codec, pin_nid); +} + static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -2335,8 +2379,22 @@ static int patch_generic_hdmi(struct hda_codec *codec) intel_haswell_fixup_enable_dp12(codec); } - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) + /* For Valleyview/Cherryview, only the display codec is in the display + * power well and can use link_power ops to request/release the power. + * For Haswell/Broadwell, the controller is also in the power well and + * can cover the codec power request, and so need not set this flag. + * For previous platforms, there is no such power well feature. + */ + if (is_valleyview_plus(codec) || is_skylake(codec) || + is_broxton(codec)) + codec->core.link_power_control = 1; + + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { codec->depop_delay = 0; + spec->i915_audio_ops.audio_ptr = codec; + spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify; + snd_hdac_i915_register_notifier(&spec->i915_audio_ops); + } if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; @@ -2349,6 +2407,10 @@ static int patch_generic_hdmi(struct hda_codec *codec) codec->dp_mst = true; } + /* Enable runtime pm for HDMI audio codec of HSW/BDW/SKL/BYT/BSW */ + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) + codec->auto_runtime_pm = 1; + generic_hdmi_init_per_pins(codec); init_channel_allocations(); @@ -2530,7 +2592,7 @@ static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hdmi_spec *spec = codec->spec; struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL; - switch (codec->preset->id) { + switch (codec->preset->vendor_id) { case 0x10de0002: case 0x10de0003: case 0x10de0005: @@ -2848,7 +2910,7 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) snd_pcm_alt_chmaps, 8, 0, &chmap); if (err < 0) return err; - switch (codec->preset->id) { + switch (codec->preset->vendor_id) { case 0x10de0002: case 0x10de0003: case 0x10de0005: @@ -2923,6 +2985,171 @@ static int patch_nvhdmi(struct hda_codec *codec) } /* + * The HDA codec on NVIDIA Tegra contains two scratch registers that are + * accessed using vendor-defined verbs. These registers can be used for + * interoperability between the HDA and HDMI drivers. + */ + +/* Audio Function Group node */ +#define NVIDIA_AFG_NID 0x01 + +/* + * The SCRATCH0 register is used to notify the HDMI codec of changes in audio + * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to + * be raised in the HDMI codec. The remainder of the bits is arbitrary. This + * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an + * additional bit (at position 30) to signal the validity of the format. + * + * | 31 | 30 | 29 16 | 15 0 | + * +---------+-------+--------+--------+ + * | TRIGGER | VALID | UNUSED | FORMAT | + * +-----------------------------------| + * + * Note that for the trigger bit to take effect it needs to change value + * (i.e. it needs to be toggled). + */ +#define NVIDIA_GET_SCRATCH0 0xfa6 +#define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7 +#define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8 +#define NVIDIA_SET_SCRATCH0_BYTE2 0xfa9 +#define NVIDIA_SET_SCRATCH0_BYTE3 0xfaa +#define NVIDIA_SCRATCH_TRIGGER (1 << 7) +#define NVIDIA_SCRATCH_VALID (1 << 6) + +#define NVIDIA_GET_SCRATCH1 0xfab +#define NVIDIA_SET_SCRATCH1_BYTE0 0xfac +#define NVIDIA_SET_SCRATCH1_BYTE1 0xfad +#define NVIDIA_SET_SCRATCH1_BYTE2 0xfae +#define NVIDIA_SET_SCRATCH1_BYTE3 0xfaf + +/* + * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0, + * the format is invalidated so that the HDMI codec can be disabled. + */ +static void tegra_hdmi_set_format(struct hda_codec *codec, unsigned int format) +{ + unsigned int value; + + /* bits [31:30] contain the trigger and valid bits */ + value = snd_hda_codec_read(codec, NVIDIA_AFG_NID, 0, + NVIDIA_GET_SCRATCH0, 0); + value = (value >> 24) & 0xff; + + /* bits [15:0] are used to store the HDA format */ + snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + NVIDIA_SET_SCRATCH0_BYTE0, + (format >> 0) & 0xff); + snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + NVIDIA_SET_SCRATCH0_BYTE1, + (format >> 8) & 0xff); + + /* bits [16:24] are unused */ + snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + NVIDIA_SET_SCRATCH0_BYTE2, 0); + + /* + * Bit 30 signals that the data is valid and hence that HDMI audio can + * be enabled. + */ + if (format == 0) + value &= ~NVIDIA_SCRATCH_VALID; + else + value |= NVIDIA_SCRATCH_VALID; + + /* + * Whenever the trigger bit is toggled, an interrupt is raised in the + * HDMI codec. The HDMI driver will use that as trigger to update its + * configuration. + */ + value ^= NVIDIA_SCRATCH_TRIGGER; + + snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + NVIDIA_SET_SCRATCH0_BYTE3, value); +} + +static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + int err; + + err = generic_hdmi_playback_pcm_prepare(hinfo, codec, stream_tag, + format, substream); + if (err < 0) + return err; + + /* notify the HDMI codec of the format change */ + tegra_hdmi_set_format(codec, format); + + return 0; +} + +static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + /* invalidate the format in the HDMI codec */ + tegra_hdmi_set_format(codec, 0); + + return generic_hdmi_playback_pcm_cleanup(hinfo, codec, substream); +} + +static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type) +{ + struct hdmi_spec *spec = codec->spec; + unsigned int i; + + for (i = 0; i < spec->num_pins; i++) { + struct hda_pcm *pcm = get_pcm_rec(spec, i); + + if (pcm->pcm_type == type) + return pcm; + } + + return NULL; +} + +static int tegra_hdmi_build_pcms(struct hda_codec *codec) +{ + struct hda_pcm_stream *stream; + struct hda_pcm *pcm; + int err; + + err = generic_hdmi_build_pcms(codec); + if (err < 0) + return err; + + pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI); + if (!pcm) + return -ENODEV; + + /* + * Override ->prepare() and ->cleanup() operations to notify the HDMI + * codec about format changes. + */ + stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK]; + stream->ops.prepare = tegra_hdmi_pcm_prepare; + stream->ops.cleanup = tegra_hdmi_pcm_cleanup; + + return 0; +} + +static int patch_tegra_hdmi(struct hda_codec *codec) +{ + int err; + + err = patch_generic_hdmi(codec); + if (err) + return err; + + codec->patch_ops.build_pcms = tegra_hdmi_build_pcms; + + return 0; +} + +/* * ATI/AMD-specific implementations */ @@ -3291,133 +3518,77 @@ static int patch_via_hdmi(struct hda_codec *codec) /* * patch entries */ -static const struct hda_codec_preset snd_hda_preset_hdmi[] = { -{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, -{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, -{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, -{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi }, -{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, -{ .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, -{ .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, -{ .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, -{ .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, -{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi }, -{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi }, +static const struct hda_device_id snd_hda_id_hdmi[] = { +HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI", patch_atihdmi), +HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI", patch_atihdmi), +HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI", patch_atihdmi), +HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI", patch_atihdmi), +HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI", patch_nvhdmi_8ch_7x), +HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi), /* 17 is known to be absent */ -{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0028, .name = "Tegra12x HDMI", .patch = patch_nvhdmi }, -{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, -{ .id = 0x10de0070, .name = "GPU 70 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0071, .name = "GPU 71 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0072, .name = "GPU 72 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de007d, .name = "GPU 7d HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, -{ .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi }, -{ .id = 0x11069f81, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi }, -{ .id = 0x11069f84, .name = "VX11 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x11069f85, .name = "VX11 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862807, .name = "Haswell HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862808, .name = "Broadwell HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862809, .name = "Skylake HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862882, .name = "Valleyview2 HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862883, .name = "Braswell HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, +HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP", patch_tegra_hdmi), +HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI", patch_nvhdmi_2ch), +HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch), +HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi), +HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi), +HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI", patch_generic_hdmi), /* special ID for generic HDMI */ -{ .id = HDA_CODEC_ID_GENERIC_HDMI, .patch = patch_generic_hdmi }, +HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:1002793c"); -MODULE_ALIAS("snd-hda-codec-id:10027919"); -MODULE_ALIAS("snd-hda-codec-id:1002791a"); -MODULE_ALIAS("snd-hda-codec-id:1002aa01"); -MODULE_ALIAS("snd-hda-codec-id:10951390"); -MODULE_ALIAS("snd-hda-codec-id:10951392"); -MODULE_ALIAS("snd-hda-codec-id:10de0002"); -MODULE_ALIAS("snd-hda-codec-id:10de0003"); -MODULE_ALIAS("snd-hda-codec-id:10de0005"); -MODULE_ALIAS("snd-hda-codec-id:10de0006"); -MODULE_ALIAS("snd-hda-codec-id:10de0007"); -MODULE_ALIAS("snd-hda-codec-id:10de000a"); -MODULE_ALIAS("snd-hda-codec-id:10de000b"); -MODULE_ALIAS("snd-hda-codec-id:10de000c"); -MODULE_ALIAS("snd-hda-codec-id:10de000d"); -MODULE_ALIAS("snd-hda-codec-id:10de0010"); -MODULE_ALIAS("snd-hda-codec-id:10de0011"); -MODULE_ALIAS("snd-hda-codec-id:10de0012"); -MODULE_ALIAS("snd-hda-codec-id:10de0013"); -MODULE_ALIAS("snd-hda-codec-id:10de0014"); -MODULE_ALIAS("snd-hda-codec-id:10de0015"); -MODULE_ALIAS("snd-hda-codec-id:10de0016"); -MODULE_ALIAS("snd-hda-codec-id:10de0018"); -MODULE_ALIAS("snd-hda-codec-id:10de0019"); -MODULE_ALIAS("snd-hda-codec-id:10de001a"); -MODULE_ALIAS("snd-hda-codec-id:10de001b"); -MODULE_ALIAS("snd-hda-codec-id:10de001c"); -MODULE_ALIAS("snd-hda-codec-id:10de0028"); -MODULE_ALIAS("snd-hda-codec-id:10de0040"); -MODULE_ALIAS("snd-hda-codec-id:10de0041"); -MODULE_ALIAS("snd-hda-codec-id:10de0042"); -MODULE_ALIAS("snd-hda-codec-id:10de0043"); -MODULE_ALIAS("snd-hda-codec-id:10de0044"); -MODULE_ALIAS("snd-hda-codec-id:10de0051"); -MODULE_ALIAS("snd-hda-codec-id:10de0060"); -MODULE_ALIAS("snd-hda-codec-id:10de0067"); -MODULE_ALIAS("snd-hda-codec-id:10de0070"); -MODULE_ALIAS("snd-hda-codec-id:10de0071"); -MODULE_ALIAS("snd-hda-codec-id:10de0072"); -MODULE_ALIAS("snd-hda-codec-id:10de007d"); -MODULE_ALIAS("snd-hda-codec-id:10de8001"); -MODULE_ALIAS("snd-hda-codec-id:11069f80"); -MODULE_ALIAS("snd-hda-codec-id:11069f81"); -MODULE_ALIAS("snd-hda-codec-id:11069f84"); -MODULE_ALIAS("snd-hda-codec-id:11069f85"); -MODULE_ALIAS("snd-hda-codec-id:17e80047"); -MODULE_ALIAS("snd-hda-codec-id:80860054"); -MODULE_ALIAS("snd-hda-codec-id:80862801"); -MODULE_ALIAS("snd-hda-codec-id:80862802"); -MODULE_ALIAS("snd-hda-codec-id:80862803"); -MODULE_ALIAS("snd-hda-codec-id:80862804"); -MODULE_ALIAS("snd-hda-codec-id:80862805"); -MODULE_ALIAS("snd-hda-codec-id:80862806"); -MODULE_ALIAS("snd-hda-codec-id:80862807"); -MODULE_ALIAS("snd-hda-codec-id:80862808"); -MODULE_ALIAS("snd-hda-codec-id:80862809"); -MODULE_ALIAS("snd-hda-codec-id:80862880"); -MODULE_ALIAS("snd-hda-codec-id:80862882"); -MODULE_ALIAS("snd-hda-codec-id:80862883"); -MODULE_ALIAS("snd-hda-codec-id:808629fb"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("HDMI HD-audio codec"); @@ -3426,7 +3597,7 @@ MODULE_ALIAS("snd-hda-codec-nvhdmi"); MODULE_ALIAS("snd-hda-codec-atihdmi"); static struct hda_codec_driver hdmi_driver = { - .preset = snd_hda_preset_hdmi, + .id = snd_hda_id_hdmi, }; module_hda_codec_driver(hdmi_driver); diff --git a/kernel/sound/pci/hda/patch_realtek.c b/kernel/sound/pci/hda/patch_realtek.c index 6fe862594..c2430b36e 100644 --- a/kernel/sound/pci/hda/patch_realtek.c +++ b/kernel/sound/pci/hda/patch_realtek.c @@ -67,6 +67,10 @@ enum { ALC_HEADSET_TYPE_OMTP, }; +enum { + ALC_KEY_MICMUTE_INDEX, +}; + struct alc_customize_define { unsigned int sku_cfg; unsigned char port_connectivity; @@ -111,6 +115,7 @@ struct alc_spec { void (*power_hook)(struct hda_codec *codec); #endif void (*shutup)(struct hda_codec *codec); + void (*reboot_notify)(struct hda_codec *codec); int init_amp; int codec_variant; /* flag for other variants */ @@ -122,6 +127,7 @@ struct alc_spec { unsigned int pll_coef_idx, pll_coef_bit; unsigned int coef0; struct input_dev *kb_dev; + u8 alc_mute_keycode_map[1]; }; /* @@ -276,7 +282,7 @@ static void alc_update_knob_master(struct hda_codec *codec, uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (!uctl) return; - val = snd_hda_codec_read(codec, jack->tbl->nid, 0, + val = snd_hda_codec_read(codec, jack->nid, 0, AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); val &= HDA_AMP_VOLMASK; uctl->value.integer.value[0] = val; @@ -321,6 +327,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0292: alc_update_coef_idx(codec, 0x4, 1<<15, 0); break; + case 0x10ec0225: case 0x10ec0233: case 0x10ec0255: case 0x10ec0256: @@ -773,6 +780,25 @@ static inline void alc_shutup(struct hda_codec *codec) snd_hda_shutup_pins(codec); } +static void alc_reboot_notify(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec && spec->reboot_notify) + spec->reboot_notify(codec); + else + alc_shutup(codec); +} + +/* power down codec to D3 at reboot/shutdown; set as reboot_notify ops */ +static void alc_d3_at_reboot(struct hda_codec *codec) +{ + snd_hda_codec_set_power_to_all(codec, codec->core.afg, AC_PWRST_D3); + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + msleep(10); +} + #define alc_free snd_hda_gen_free #ifdef CONFIG_PM @@ -818,21 +844,11 @@ static const struct hda_codec_ops alc_patch_ops = { .suspend = alc_suspend, .check_power_status = snd_hda_gen_check_power_status, #endif - .reboot_notify = alc_shutup, + .reboot_notify = alc_reboot_notify, }; -/* replace the codec chip_name with the given string */ -static int alc_codec_rename(struct hda_codec *codec, const char *name) -{ - kfree(codec->core.chip_name); - codec->core.chip_name = kstrdup(name, GFP_KERNEL); - if (!codec->core.chip_name) { - alc_free(codec); - return -ENOMEM; - } - return 0; -} +#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name) /* * Rename codecs appropriately from COEF value or subvendor id @@ -885,6 +901,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { { 0x10ec0899, 0x1028, 0, "ALC3861" }, { 0x10ec0298, 0x1028, 0, "ALC3266" }, { 0x10ec0256, 0x1028, 0, "ALC3246" }, + { 0x10ec0225, 0x1028, 0, "ALC3253" }, { 0x10ec0670, 0x1025, 0, "ALC669X" }, { 0x10ec0676, 0x1025, 0, "ALC679X" }, { 0x10ec0282, 0x1043, 0, "ALC3229" }, @@ -1003,6 +1020,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) codec->single_adc_amp = 1; /* FIXME: do we need this for all Realtek codec models? */ codec->spdif_status_reset = 1; + codec->patch_ops = alc_patch_ops; err = alc_codec_rename_from_preset(codec); if (err < 0) { @@ -1447,6 +1465,8 @@ static int patch_alc880(struct hda_codec *codec) spec->gen.need_dac_fix = 1; spec->gen.beep_nid = 0x01; + codec->patch_ops.unsol_event = alc880_unsol_event; + snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, alc880_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -1459,10 +1479,6 @@ static int patch_alc880(struct hda_codec *codec) if (!spec->gen.no_analog) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - codec->patch_ops = alc_patch_ops; - codec->patch_ops.unsol_event = alc880_unsol_event; - - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -1699,6 +1715,8 @@ static int patch_alc260(struct hda_codec *codec) spec->gen.prefer_hp_amp = 1; spec->gen.beep_nid = 0x01; + spec->shutup = alc_eapd_shutup; + snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl, alc260_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -1711,9 +1729,6 @@ static int patch_alc260(struct hda_codec *codec) if (!spec->gen.no_analog) set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); - codec->patch_ops = alc_patch_ops; - spec->shutup = alc_eapd_shutup; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -1767,6 +1782,7 @@ enum { ALC889_FIXUP_MBA11_VREF, ALC889_FIXUP_MBA21_VREF, ALC889_FIXUP_MP11_VREF, + ALC889_FIXUP_MP41_VREF, ALC882_FIXUP_INV_DMIC, ALC882_FIXUP_NO_PRIMARY_HP, ALC887_FIXUP_ASUS_BASS, @@ -1854,7 +1870,7 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - static hda_nid_t nids[2] = { 0x14, 0x15 }; + static hda_nid_t nids[3] = { 0x14, 0x15, 0x19 }; int i; if (action != HDA_FIXUP_ACT_INIT) @@ -2142,6 +2158,12 @@ static const struct hda_fixup alc882_fixups[] = { .chained = true, .chain_id = ALC885_FIXUP_MACPRO_GPIO, }, + [ALC889_FIXUP_MP41_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mbp_vref, + .chained = true, + .chain_id = ALC885_FIXUP_MACPRO_GPIO, + }, [ALC882_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic, @@ -2201,6 +2223,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), /* All Apple entries are in codec SSIDs */ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), @@ -2220,7 +2243,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF), SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF), @@ -2299,8 +2322,6 @@ static int patch_alc882(struct hda_codec *codec) if (!spec->gen.no_analog && spec->gen.beep_nid) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - codec->patch_ops = alc_patch_ops; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -2436,6 +2457,8 @@ static int patch_alc262(struct hda_codec *codec) spec = codec->spec; spec->gen.shared_mic_vref_pin = 0x18; + spec->shutup = alc_eapd_shutup; + #if 0 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is * under-run @@ -2461,9 +2484,6 @@ static int patch_alc262(struct hda_codec *codec) if (!spec->gen.no_analog && spec->gen.beep_nid) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - codec->patch_ops = alc_patch_ops; - spec->shutup = alc_eapd_shutup; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -2567,6 +2587,8 @@ static int patch_alc268(struct hda_codec *codec) spec = codec->spec; spec->gen.beep_nid = 0x01; + spec->shutup = alc_eapd_shutup; + snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -2588,9 +2610,6 @@ static int patch_alc268(struct hda_codec *codec) (0 << AC_AMPCAP_MUTE_SHIFT)); } - codec->patch_ops = alc_patch_ops; - spec->shutup = alc_eapd_shutup; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -2627,6 +2646,7 @@ enum { ALC269_TYPE_ALC298, ALC269_TYPE_ALC255, ALC269_TYPE_ALC256, + ALC269_TYPE_ALC225, }; /* @@ -2656,6 +2676,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) case ALC269_TYPE_ALC298: case ALC269_TYPE_ALC255: case ALC269_TYPE_ALC256: + case ALC269_TYPE_ALC225: ssids = alc269_ssids; break; default: @@ -3443,12 +3464,43 @@ static void gpio2_mic_hotkey_event(struct hda_codec *codec, /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore send both key on and key off event for every interrupt. */ - input_report_key(spec->kb_dev, KEY_MICMUTE, 1); + input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 1); input_sync(spec->kb_dev); - input_report_key(spec->kb_dev, KEY_MICMUTE, 0); + input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 0); input_sync(spec->kb_dev); } +static int alc_register_micmute_input_device(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + spec->kb_dev = input_allocate_device(); + if (!spec->kb_dev) { + codec_err(codec, "Out of memory (input_allocate_device)\n"); + return -ENOMEM; + } + + spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX] = KEY_MICMUTE; + + spec->kb_dev->name = "Microphone Mute Button"; + spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY); + spec->kb_dev->keycodesize = sizeof(spec->alc_mute_keycode_map[0]); + spec->kb_dev->keycodemax = ARRAY_SIZE(spec->alc_mute_keycode_map); + spec->kb_dev->keycode = spec->alc_mute_keycode_map; + for (i = 0; i < ARRAY_SIZE(spec->alc_mute_keycode_map); i++) + set_bit(spec->alc_mute_keycode_map[i], spec->kb_dev->keybit); + + if (input_register_device(spec->kb_dev)) { + codec_err(codec, "input_register_device failed\n"); + input_free_device(spec->kb_dev); + spec->kb_dev = NULL; + return -ENOMEM; + } + + return 0; +} + static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -3466,20 +3518,8 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, struct alc_spec *spec = codec->spec; if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->kb_dev = input_allocate_device(); - if (!spec->kb_dev) { - codec_err(codec, "Out of memory (input_allocate_device)\n"); - return; - } - spec->kb_dev->name = "Microphone Mute Button"; - spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY); - spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE); - if (input_register_device(spec->kb_dev)) { - codec_err(codec, "input_register_device failed\n"); - input_free_device(spec->kb_dev); - spec->kb_dev = NULL; + if (alc_register_micmute_input_device(codec) != 0) return; - } snd_hda_add_verbs(codec, gpio_init); snd_hda_codec_write_cache(codec, codec->core.afg, 0, @@ -3509,6 +3549,47 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec, } } +static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + /* Line2 = mic mute hotkey + GPIO2 = mic mute LED */ + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 }, + {} + }; + + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + if (alc_register_micmute_input_device(codec) != 0) + return; + + snd_hda_add_verbs(codec, gpio_init); + snd_hda_jack_detect_enable_callback(codec, 0x1b, + gpio2_mic_hotkey_event); + + spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; + spec->gpio_led = 0; + spec->mute_led_polarity = 0; + spec->gpio_mic_led_mask = 0x04; + return; + } + + if (!spec->kb_dev) + return; + + switch (action) { + case HDA_FIXUP_ACT_PROBE: + spec->init_amp = ALC_INIT_DEFAULT; + break; + case HDA_FIXUP_ACT_FREE: + input_unregister_device(spec->kb_dev); + spec->kb_dev = NULL; + } +} + static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -3574,6 +3655,16 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) WRITE_COEF(0xb7, 0x802b), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEF(0x4a, 1<<8, 0), + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), + UPDATE_COEF(0x63, 3<<14, 3<<14), + UPDATE_COEF(0x4a, 3<<4, 2<<4), + UPDATE_COEF(0x4a, 3<<10, 3<<10), + UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10), + UPDATE_COEF(0x4a, 3<<10, 0), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3586,6 +3677,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) break; case 0x10ec0286: case 0x10ec0288: + case 0x10ec0298: alc_process_coef_fw(codec, coef0288); break; case 0x10ec0292: @@ -3597,6 +3689,9 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) case 0x10ec0668: alc_process_coef_fw(codec, coef0668); break; + case 0x10ec0225: + alc_process_coef_fw(codec, coef0225); + break; } codec_dbg(codec, "Headset jack set to unplugged mode.\n"); } @@ -3642,6 +3737,13 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, UPDATE_COEF(0xc3, 0, 1<<12), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), + UPDATE_COEF(0x4a, 3<<4, 2<<4), + UPDATE_COEF(0x63, 3<<14, 0), + {} + }; + switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3660,6 +3762,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, break; case 0x10ec0286: case 0x10ec0288: + case 0x10ec0298: alc_update_coef_idx(codec, 0x4f, 0x000c, 0); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); alc_process_coef_fw(codec, coef0288); @@ -3686,6 +3789,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_process_coef_fw(codec, coef0688); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; + case 0x10ec0225: + alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0225); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; } codec_dbg(codec, "Headset jack set to mic-in mode.\n"); } @@ -3743,6 +3852,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) break; case 0x10ec0286: case 0x10ec0288: + case 0x10ec0298: alc_process_coef_fw(codec, coef0288); break; case 0x10ec0292: @@ -3797,6 +3907,13 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) WRITE_COEF(0xc3, 0x0000), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10), + UPDATE_COEF(0x49, 1<<8, 1<<8), + UPDATE_COEF(0x4a, 7<<6, 7<<6), + UPDATE_COEF(0x4a, 3<<4, 3<<4), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3807,6 +3924,9 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) case 0x10ec0283: alc_process_coef_fw(codec, coef0233); break; + case 0x10ec0298: + alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);/* Headset output enable */ + /* ALC298 jack type setting is the same with ALC286/ALC288 */ case 0x10ec0286: case 0x10ec0288: alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400); @@ -3822,6 +3942,9 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) case 0x10ec0668: alc_process_coef_fw(codec, coef0688); break; + case 0x10ec0225: + alc_process_coef_fw(codec, coef0225); + break; } codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); } @@ -3865,6 +3988,13 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) WRITE_COEF(0xc3, 0x0000), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10), + UPDATE_COEF(0x49, 1<<8, 1<<8), + UPDATE_COEF(0x4a, 7<<6, 7<<6), + UPDATE_COEF(0x4a, 3<<4, 3<<4), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3875,6 +4005,9 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) case 0x10ec0283: alc_process_coef_fw(codec, coef0233); break; + case 0x10ec0298: + alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */ + /* ALC298 jack type setting is the same with ALC286/ALC288 */ case 0x10ec0286: case 0x10ec0288: alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400); @@ -3890,6 +4023,9 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) case 0x10ec0668: alc_process_coef_fw(codec, coef0688); break; + case 0x10ec0225: + alc_process_coef_fw(codec, coef0225); + break; } codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); } @@ -3921,6 +4057,11 @@ static void alc_determine_headset_type(struct hda_codec *codec) WRITE_COEF(0xc3, 0x0c00), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10), + UPDATE_COEF(0x49, 1<<8, 1<<8), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3937,6 +4078,9 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; break; + case 0x10ec0298: + alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020); /* Headset output enable */ + /* ALC298 check jack type is the same with ALC286/ALC288 */ case 0x10ec0286: case 0x10ec0288: alc_process_coef_fw(codec, coef0288); @@ -3962,6 +4106,12 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0xbe); is_ctia = (val & 0x1c02) == 0x1c02; break; + case 0x10ec0225: + alc_process_coef_fw(codec, coef0225); + msleep(800); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x00f0) == 0x00f0; + break; } codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", @@ -4182,6 +4332,26 @@ static void alc_fixup_disable_aamix(struct hda_codec *codec, } } +/* fixup for Thinkpad docks: add dock pins, avoid HP parser fixup */ +static void alc_fixup_tpt440_dock(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const struct hda_pintbl pincfgs[] = { + { 0x16, 0x21211010 }, /* dock headphone */ + { 0x19, 0x21a11010 }, /* dock mic */ + { } + }; + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->shutup = alc_no_shutup; /* reduce click noise */ + spec->reboot_notify = alc_d3_at_reboot; /* reduce noise */ + spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; + codec->power_save_node = 0; /* avoid click noises */ + snd_hda_apply_pincfgs(codec, pincfgs); + } +} + static void alc_shutup_dell_xps13(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -4435,6 +4605,55 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec, } } +/* Hook to update amp GPIO4 for automute */ +static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + struct alc_spec *spec = codec->spec; + + snd_hda_gen_hp_automute(codec, jack); + /* mute_led_polarity is set to 0, so we pass inverted value here */ + alc_update_gpio_led(codec, 0x10, !spec->gen.hp_jack_present); +} + +/* Manage GPIOs for HP EliteBook Folio 9480m. + * + * GPIO4 is the headphone amplifier power control + * GPIO3 is the audio output mute indicator LED + */ + +static void alc280_fixup_hp_9480m(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 }, + {} + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + /* Set the hooks to turn the headphone amp on/off + * as needed + */ + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; + spec->gen.hp_automute_hook = alc280_hp_gpio4_automute_hook; + + /* The GPIOs are currently off */ + spec->gpio_led = 0; + + /* GPIO3 is connected to the output mute LED, + * high is on, low is off + */ + spec->mute_led_polarity = 0; + spec->gpio_mute_led_mask = 0x08; + + /* Initialize GPIO configuration */ + snd_hda_add_verbs(codec, gpio_init); + } +} + /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" @@ -4501,13 +4720,14 @@ enum { ALC290_FIXUP_SUBWOOFER, ALC290_FIXUP_SUBWOOFER_HSJACK, ALC269_FIXUP_THINKPAD_ACPI, + ALC269_FIXUP_DMIC_THINKPAD_ACPI, ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, ALC255_FIXUP_HEADSET_MODE, ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC, ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_FIXUP_TPT440_DOCK, - ALC292_FIXUP_TPT440_DOCK2, + ALC292_FIXUP_TPT440, ALC283_FIXUP_BXBT2807_MIC, ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, ALC282_FIXUP_ASPIRE_V5_PINS, @@ -4515,6 +4735,7 @@ enum { ALC286_FIXUP_HP_GPIO_LED, ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, ALC280_FIXUP_HP_DOCK_PINS, + ALC280_FIXUP_HP_9480M, ALC288_FIXUP_DELL_HEADSET_MODE, ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, ALC288_FIXUP_DELL_XPS_13_GPIO6, @@ -4522,6 +4743,13 @@ enum { ALC288_FIXUP_DISABLE_AAMIX, ALC292_FIXUP_DELL_E7X, ALC292_FIXUP_DISABLE_AAMIX, + ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK, + ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC275_FIXUP_DELL_XPS, + ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, + ALC293_FIXUP_LENOVO_SPK_NOISE, + ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, + ALC255_FIXUP_DELL_SPK_NOISE, }; static const struct hda_fixup alc269_fixups[] = { @@ -4931,6 +5159,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = hda_fixup_thinkpad_acpi, }, + [ALC269_FIXUP_DMIC_THINKPAD_ACPI] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI, + }, [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -4972,19 +5206,15 @@ static const struct hda_fixup alc269_fixups[] = { }, [ALC292_FIXUP_TPT440_DOCK] = { .type = HDA_FIXUP_FUNC, - .v.func = alc269_fixup_pincfg_no_hp_to_lineout, + .v.func = alc_fixup_tpt440_dock, .chained = true, - .chain_id = ALC292_FIXUP_TPT440_DOCK2 + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST }, - [ALC292_FIXUP_TPT440_DOCK2] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x16, 0x21211010 }, /* dock headphone */ - { 0x19, 0x21a11010 }, /* dock mic */ - { } - }, + [ALC292_FIXUP_TPT440] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, .chained = true, - .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST + .chain_id = ALC292_FIXUP_TPT440_DOCK, }, [ALC283_FIXUP_BXBT2807_MIC] = { .type = HDA_FIXUP_PINS, @@ -5036,6 +5266,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC280_FIXUP_HP_GPIO4 }, + [ALC280_FIXUP_HP_9480M] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc280_fixup_hp_9480m, + }, [ALC288_FIXUP_DELL_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode_dell_alc288, @@ -5081,12 +5315,66 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE }, + [ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE + }, [ALC292_FIXUP_DELL_E7X] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_dell_xps13, .chained = true, .chain_id = ALC292_FIXUP_DISABLE_AAMIX }, + [ALC298_FIXUP_DELL1_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE + }, + [ALC275_FIXUP_DELL_XPS] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* Enables internal speaker */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x1f}, + {0x20, AC_VERB_SET_PROC_COEF, 0x00c0}, + {0x20, AC_VERB_SET_COEF_INDEX, 0x30}, + {0x20, AC_VERB_SET_PROC_COEF, 0x00b1}, + {} + } + }, + [ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* Disable pass-through path for FRONT 14h */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x36}, + {0x20, AC_VERB_SET_PROC_COEF, 0x1737}, + {} + }, + .chained = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, + [ALC293_FIXUP_LENOVO_SPK_NOISE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI + }, + [ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc233_fixup_lenovo_line2_mic_hotkey, + }, + [ALC255_FIXUP_DELL_SPK_NOISE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -5098,9 +5386,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), + SND_PCI_QUIRK(0x1025, 0x0762, "Acer Aspire E1-472", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), + SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS), + SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X), + SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER), @@ -5109,6 +5402,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), + SND_PCI_QUIRK(0x1028, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x062e, "Dell Latitude E7450", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), @@ -5118,11 +5412,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC292_FIXUP_DISABLE_AAMIX), - SND_PCI_QUIRK(0x1028, 0x06dd, "Dell", ALC292_FIXUP_DISABLE_AAMIX), - SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC292_FIXUP_DISABLE_AAMIX), - SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC292_FIXUP_DISABLE_AAMIX), - SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC292_FIXUP_DISABLE_AAMIX), + SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), + SND_PCI_QUIRK(0x1028, 0x06dd, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), + SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), + SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), + SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), + SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), + SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -5150,6 +5446,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC280_FIXUP_HP_9480M), SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), /* ALC290 */ @@ -5220,13 +5517,19 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), - SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440), SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), + SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -5236,6 +5539,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), @@ -5307,6 +5611,8 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"}, {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"}, {.id = ALC269_FIXUP_HEADSET_MIC, .name = "headset-mic"}, + {.id = ALC269_FIXUP_HEADSET_MODE, .name = "headset-mode"}, + {.id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC, .name = "headset-mode-no-hp-mic"}, {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"}, {.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"}, {.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, @@ -5314,347 +5620,219 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"}, {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"}, {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"}, + {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, {} }; - -#define ALC255_STANDARD_PINS \ - {0x18, 0x411111f0}, \ - {0x19, 0x411111f0}, \ - {0x1a, 0x411111f0}, \ - {0x1b, 0x411111f0}, \ - {0x1e, 0x411111f0} +#define ALC225_STANDARD_PINS \ + {0x12, 0xb7a60130}, \ + {0x21, 0x04211020} #define ALC256_STANDARD_PINS \ {0x12, 0x90a60140}, \ {0x14, 0x90170110}, \ - {0x19, 0x411111f0}, \ - {0x1a, 0x411111f0}, \ - {0x1b, 0x411111f0}, \ - {0x1d, 0x40700001}, \ - {0x1e, 0x411111f0}, \ {0x21, 0x02211020} #define ALC282_STANDARD_PINS \ - {0x14, 0x90170110}, \ - {0x18, 0x411111f0}, \ - {0x1a, 0x411111f0}, \ - {0x1b, 0x411111f0}, \ - {0x1e, 0x411111f0} - -#define ALC288_STANDARD_PINS \ - {0x17, 0x411111f0}, \ - {0x18, 0x411111f0}, \ - {0x19, 0x411111f0}, \ - {0x1a, 0x411111f0}, \ - {0x1e, 0x411111f0} + {0x14, 0x90170110} #define ALC290_STANDARD_PINS \ - {0x12, 0x99a30130}, \ - {0x13, 0x40000000}, \ - {0x16, 0x411111f0}, \ - {0x17, 0x411111f0}, \ - {0x19, 0x411111f0}, \ - {0x1b, 0x411111f0}, \ - {0x1e, 0x411111f0} + {0x12, 0x99a30130} #define ALC292_STANDARD_PINS \ {0x14, 0x90170110}, \ - {0x15, 0x0221401f}, \ - {0x1a, 0x411111f0}, \ - {0x1b, 0x411111f0}, \ - {0x1d, 0x40700001}, \ - {0x1e, 0x411111f0} + {0x15, 0x0221401f} + +#define ALC298_STANDARD_PINS \ + {0x12, 0x90a60130}, \ + {0x21, 0x03211020} static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC225_STANDARD_PINS, + {0x14, 0x901701a0}), + SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC225_STANDARD_PINS, + {0x14, 0x901701b0}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, - {0x12, 0x40300000}, {0x14, 0x90170110}, - {0x17, 0x411111f0}, - {0x1d, 0x40538029}, {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, {0x12, 0x90a60140}, {0x14, 0x90170110}, - {0x17, 0x40000000}, - {0x1d, 0x40700001}, {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, {0x12, 0x90a60160}, {0x14, 0x90170120}, - {0x17, 0x40000000}, - {0x1d, 0x40700001}, {0x21, 0x02211030}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - {0x12, 0x40000000}, {0x14, 0x90170130}, - {0x17, 0x411111f0}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, {0x1b, 0x01014020}, - {0x1d, 0x4054c029}, - {0x1e, 0x411111f0}, {0x21, 0x0221103f}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170150}, + {0x1b, 0x02011020}, + {0x21, 0x0221105f}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x1b, 0x01014020}, + {0x21, 0x0221101f}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60160}, {0x14, 0x90170120}, {0x17, 0x90170140}, - {0x18, 0x40000000}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x41163b05}, - {0x1e, 0x411111f0}, {0x21, 0x0321102f}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, {0x12, 0x90a60160}, {0x14, 0x90170130}, - {0x17, 0x40000000}, - {0x1d, 0x40700001}, {0x21, 0x02211040}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, {0x12, 0x90a60160}, {0x14, 0x90170140}, - {0x17, 0x40000000}, - {0x1d, 0x40700001}, {0x21, 0x02211050}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, {0x12, 0x90a60170}, {0x14, 0x90170120}, - {0x17, 0x40000000}, - {0x1d, 0x40700001}, {0x21, 0x02211030}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, {0x12, 0x90a60170}, {0x14, 0x90170130}, - {0x17, 0x40000000}, - {0x1d, 0x40700001}, {0x21, 0x02211040}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, + {0x12, 0x90a60170}, + {0x14, 0x90171130}, + {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60170}, {0x14, 0x90170140}, - {0x17, 0x40000000}, - {0x1d, 0x40700001}, {0x21, 0x02211050}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5548", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, {0x12, 0x90a60180}, {0x14, 0x90170130}, - {0x17, 0x40000000}, - {0x1d, 0x40700001}, {0x21, 0x02211040}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC255_STANDARD_PINS, {0x12, 0x90a60160}, {0x14, 0x90170120}, - {0x17, 0x40000000}, - {0x1d, 0x40700001}, {0x21, 0x02211030}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC256_STANDARD_PINS, - {0x13, 0x40000000}), - SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC256_STANDARD_PINS, - {0x13, 0x411111f0}), + ALC256_STANDARD_PINS), SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4, {0x12, 0x90a60130}, - {0x13, 0x40000000}, {0x14, 0x90170110}, {0x15, 0x0421101f}, - {0x16, 0x411111f0}, - {0x17, 0x411111f0}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x04a11020}, - {0x1b, 0x411111f0}, - {0x1d, 0x40748605}, - {0x1e, 0x411111f0}), + {0x1a, 0x04a11020}), SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED, {0x12, 0x90a60140}, - {0x13, 0x40000000}, {0x14, 0x90170110}, {0x15, 0x0421101f}, - {0x16, 0x411111f0}, - {0x17, 0x411111f0}, {0x18, 0x02811030}, - {0x19, 0x411111f0}, {0x1a, 0x04a1103f}, - {0x1b, 0x02011020}, - {0x1d, 0x40700001}, - {0x1e, 0x411111f0}), + {0x1b, 0x02011020}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x17, 0x40000000}, {0x19, 0x03a11020}, - {0x1d, 0x40f41905}, {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x17, 0x40020008}, {0x19, 0x03a11020}, - {0x1d, 0x40e00001}, {0x21, 0x03211040}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x17, 0x40000000}, - {0x19, 0x03a11030}, - {0x1d, 0x40e00001}, - {0x21, 0x03211020}), - SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, - ALC282_STANDARD_PINS, - {0x12, 0x99a30130}, - {0x17, 0x40000000}, {0x19, 0x03a11030}, - {0x1d, 0x40f00001}, {0x21, 0x03211020}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x17, 0x40000000}, {0x19, 0x04a11020}, - {0x1d, 0x40f00001}, {0x21, 0x0421101f}), - SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, - ALC282_STANDARD_PINS, - {0x12, 0x99a30130}, - {0x17, 0x40000000}, - {0x19, 0x03a11030}, - {0x1d, 0x40f00001}, - {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED, ALC282_STANDARD_PINS, {0x12, 0x90a60140}, - {0x17, 0x40000000}, {0x19, 0x04a11030}, - {0x1d, 0x40f00001}, {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, ALC282_STANDARD_PINS, {0x12, 0x90a60130}, - {0x17, 0x40020008}, - {0x19, 0x411111f0}, - {0x1d, 0x40e00001}, {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60160}, {0x14, 0x90170120}, - {0x17, 0x40000000}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x40700001}, - {0x1e, 0x411111f0}, {0x21, 0x02211030}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, ALC282_STANDARD_PINS, {0x12, 0x90a60130}, - {0x17, 0x40020008}, {0x19, 0x03a11020}, - {0x1d, 0x40e00001}, {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL_XPS_13_GPIO6, - ALC288_STANDARD_PINS, {0x12, 0x90a60120}, - {0x13, 0x40000000}, {0x14, 0x90170110}, - {0x1d, 0x4076832d}, {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC290_STANDARD_PINS, - {0x14, 0x411111f0}, {0x15, 0x04211040}, {0x18, 0x90170112}, - {0x1a, 0x04a11020}, - {0x1d, 0x4075812d}), + {0x1a, 0x04a11020}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC290_STANDARD_PINS, - {0x14, 0x411111f0}, {0x15, 0x04211040}, {0x18, 0x90170110}, - {0x1a, 0x04a11020}, - {0x1d, 0x4075812d}), + {0x1a, 0x04a11020}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC290_STANDARD_PINS, - {0x14, 0x411111f0}, {0x15, 0x0421101f}, - {0x18, 0x411111f0}, - {0x1a, 0x04a11020}, - {0x1d, 0x4075812d}), + {0x1a, 0x04a11020}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC290_STANDARD_PINS, - {0x14, 0x411111f0}, {0x15, 0x04211020}, - {0x18, 0x411111f0}, - {0x1a, 0x04a11040}, - {0x1d, 0x4076a12d}), + {0x1a, 0x04a11040}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC290_STANDARD_PINS, {0x14, 0x90170110}, {0x15, 0x04211020}, - {0x18, 0x411111f0}, - {0x1a, 0x04a11040}, - {0x1d, 0x4076a12d}), + {0x1a, 0x04a11040}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC290_STANDARD_PINS, {0x14, 0x90170110}, {0x15, 0x04211020}, - {0x18, 0x411111f0}, - {0x1a, 0x04a11020}, - {0x1d, 0x4076a12d}), + {0x1a, 0x04a11020}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, ALC290_STANDARD_PINS, {0x14, 0x90170110}, {0x15, 0x0421101f}, - {0x18, 0x411111f0}, - {0x1a, 0x04a11020}, - {0x1d, 0x4075812d}), + {0x1a, 0x04a11020}), SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, ALC292_STANDARD_PINS, {0x12, 0x90a60140}, - {0x13, 0x411111f0}, {0x16, 0x01014020}, - {0x18, 0x411111f0}, {0x19, 0x01a19030}), SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, ALC292_STANDARD_PINS, {0x12, 0x90a60140}, - {0x13, 0x411111f0}, {0x16, 0x01014020}, {0x18, 0x02a19031}, {0x19, 0x01a1903e}), SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, ALC292_STANDARD_PINS, - {0x12, 0x90a60140}, - {0x13, 0x411111f0}, - {0x16, 0x411111f0}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}), + {0x12, 0x90a60140}), SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_STANDARD_PINS, - {0x12, 0x40000000}, {0x13, 0x90a60140}, {0x16, 0x21014020}, - {0x18, 0x411111f0}, {0x19, 0x21a19030}), SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_STANDARD_PINS, - {0x12, 0x40000000}, - {0x13, 0x90a60140}, - {0x16, 0x411111f0}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}), + {0x13, 0x90a60140}), + SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC298_STANDARD_PINS, + {0x17, 0x90170110}), + SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC298_STANDARD_PINS, + {0x17, 0x90170140}), + SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC298_STANDARD_PINS, + {0x17, 0x90170150}), {} }; @@ -5713,6 +5891,12 @@ static int patch_alc269(struct hda_codec *codec) spec->gen.shared_mic_vref_pin = 0x18; codec->power_save_node = 1; +#ifdef CONFIG_PM + codec->patch_ops.suspend = alc269_suspend; + codec->patch_ops.resume = alc269_resume; +#endif + spec->shutup = alc269_shutup; + snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); @@ -5794,6 +5978,9 @@ static int patch_alc269(struct hda_codec *codec) spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ break; + case 0x10ec0225: + spec->codec_variant = ALC269_TYPE_ALC225; + break; } if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) { @@ -5809,15 +5996,6 @@ static int patch_alc269(struct hda_codec *codec) if (!spec->gen.no_analog && spec->gen.beep_nid && spec->gen.mixer_nid) set_beep_amp(spec, spec->gen.mixer_nid, 0x04, HDA_INPUT); - codec->patch_ops = alc_patch_ops; - codec->patch_ops.stream_pm = snd_hda_gen_stream_pm; -#ifdef CONFIG_PM - codec->patch_ops.suspend = alc269_suspend; - codec->patch_ops.resume = alc269_resume; -#endif - if (!spec->shutup) - spec->shutup = alc269_shutup; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -5933,6 +6111,10 @@ static int patch_alc861(struct hda_codec *codec) spec = codec->spec; spec->gen.beep_nid = 0x23; +#ifdef CONFIG_PM + spec->power_hook = alc_power_eapd; +#endif + snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -5944,11 +6126,6 @@ static int patch_alc861(struct hda_codec *codec) if (!spec->gen.no_analog) set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); - codec->patch_ops = alc_patch_ops; -#ifdef CONFIG_PM - spec->power_hook = alc_power_eapd; -#endif - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -6025,6 +6202,8 @@ static int patch_alc861vd(struct hda_codec *codec) spec = codec->spec; spec->gen.beep_nid = 0x23; + spec->shutup = alc_eapd_shutup; + snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -6036,10 +6215,6 @@ static int patch_alc861vd(struct hda_codec *codec) if (!spec->gen.no_analog) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - codec->patch_ops = alc_patch_ops; - - spec->shutup = alc_eapd_shutup; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -6448,6 +6623,7 @@ static const struct hda_fixup alc662_fixups[] = { static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC), @@ -6465,6 +6641,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A), + SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), 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, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16), @@ -6554,77 +6731,33 @@ static const struct hda_model_fixup alc662_fixup_models[] = { static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE, - {0x12, 0x4004c000}, {0x14, 0x01014010}, - {0x15, 0x411111f0}, - {0x16, 0x411111f0}, {0x18, 0x01a19020}, - {0x19, 0x411111f0}, {0x1a, 0x0181302f}, - {0x1b, 0x0221401f}, - {0x1c, 0x411111f0}, - {0x1d, 0x4054c601}, - {0x1e, 0x411111f0}), + {0x1b, 0x0221401f}), SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, {0x12, 0x99a30130}, {0x14, 0x90170110}, {0x15, 0x0321101f}, - {0x16, 0x03011020}, - {0x18, 0x40000008}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x41000001}, - {0x1e, 0x411111f0}, - {0x1f, 0x411111f0}), + {0x16, 0x03011020}), SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, {0x12, 0x99a30140}, {0x14, 0x90170110}, {0x15, 0x0321101f}, - {0x16, 0x03011020}, - {0x18, 0x40000008}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x41000001}, - {0x1e, 0x411111f0}, - {0x1f, 0x411111f0}), + {0x16, 0x03011020}), SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, {0x12, 0x99a30150}, {0x14, 0x90170110}, {0x15, 0x0321101f}, - {0x16, 0x03011020}, - {0x18, 0x40000008}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x41000001}, - {0x1e, 0x411111f0}, - {0x1f, 0x411111f0}), + {0x16, 0x03011020}), SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, - {0x12, 0x411111f0}, {0x14, 0x90170110}, {0x15, 0x0321101f}, - {0x16, 0x03011020}, - {0x18, 0x40000008}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x41000001}, - {0x1e, 0x411111f0}, - {0x1f, 0x411111f0}), + {0x16, 0x03011020}), SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE, {0x12, 0x90a60130}, {0x14, 0x90170110}, - {0x15, 0x0321101f}, - {0x16, 0x40000000}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x40d6832d}, - {0x1e, 0x411111f0}, - {0x1f, 0x411111f0}), + {0x15, 0x0321101f}), {} }; @@ -6641,6 +6774,8 @@ static int patch_alc662(struct hda_codec *codec) spec = codec->spec; + spec->shutup = alc_eapd_shutup; + /* handle multiple HPs as is */ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; @@ -6692,9 +6827,6 @@ static int patch_alc662(struct hda_codec *codec) } } - codec->patch_ops = alc_patch_ops; - spec->shutup = alc_eapd_shutup; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -6731,86 +6863,77 @@ static int patch_alc680(struct hda_codec *codec) return err; } - codec->patch_ops = alc_patch_ops; - return 0; } /* * patch entries */ -static const struct hda_codec_preset snd_hda_preset_realtek[] = { - { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 }, - { .id = 0x10ec0231, .name = "ALC231", .patch = patch_alc269 }, - { .id = 0x10ec0233, .name = "ALC233", .patch = patch_alc269 }, - { .id = 0x10ec0235, .name = "ALC233", .patch = patch_alc269 }, - { .id = 0x10ec0255, .name = "ALC255", .patch = patch_alc269 }, - { .id = 0x10ec0256, .name = "ALC256", .patch = patch_alc269 }, - { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, - { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, - { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, - { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 }, - { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 }, - { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 }, - { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 }, - { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 }, - { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 }, - { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, - { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, - { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, - { .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 }, - { .id = 0x10ec0285, .name = "ALC285", .patch = patch_alc269 }, - { .id = 0x10ec0286, .name = "ALC286", .patch = patch_alc269 }, - { .id = 0x10ec0288, .name = "ALC288", .patch = patch_alc269 }, - { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, - { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, - { .id = 0x10ec0293, .name = "ALC293", .patch = patch_alc269 }, - { .id = 0x10ec0298, .name = "ALC298", .patch = patch_alc269 }, - { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", - .patch = patch_alc861 }, - { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, - { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 }, - { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd }, - { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2", - .patch = patch_alc882 }, - { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", - .patch = patch_alc662 }, - { .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3", - .patch = patch_alc662 }, - { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, - { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, - { .id = 0x10ec0667, .name = "ALC667", .patch = patch_alc662 }, - { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 }, - { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, - { .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 }, - { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 }, - { .id = 0x10ec0867, .name = "ALC891", .patch = patch_alc882 }, - { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, - { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, - { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, - { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A", - .patch = patch_alc882 }, - { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A", - .patch = patch_alc882 }, - { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, - { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 }, - { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200", - .patch = patch_alc882 }, - { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 }, - { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 }, - { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 }, - { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 }, - { .id = 0x10ec0900, .name = "ALC1150", .patch = patch_alc882 }, +static const struct hda_device_id snd_hda_id_realtek[] = { + HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260), + HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262), + HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268), + HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268), + HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0280, "ALC280", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0282, "ALC282", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0283, "ALC283", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0284, "ALC284", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0285, "ALC285", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0286, "ALC286", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0288, "ALC288", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0290, "ALC290", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269), + HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861), + HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd), + HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861), + HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd), + HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882), + HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662), + HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680), + HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880), + HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882), + HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882), + HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882), + HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:10ec*"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek HD-audio codec"); static struct hda_codec_driver realtek_driver = { - .preset = snd_hda_preset_realtek, + .id = snd_hda_id_realtek, }; module_hda_codec_driver(realtek_driver); diff --git a/kernel/sound/pci/hda/patch_si3054.c b/kernel/sound/pci/hda/patch_si3054.c index 5104bebb2..ffda38c45 100644 --- a/kernel/sound/pci/hda/patch_si3054.c +++ b/kernel/sound/pci/hda/patch_si3054.c @@ -289,41 +289,30 @@ static int patch_si3054(struct hda_codec *codec) /* * patch entries */ -static const struct hda_codec_preset snd_hda_preset_si3054[] = { - { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 }, - { .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 }, +static const struct hda_device_id snd_hda_id_si3054[] = { + HDA_CODEC_ENTRY(0x163c3055, "Si3054", patch_si3054), + HDA_CODEC_ENTRY(0x163c3155, "Si3054", patch_si3054), + HDA_CODEC_ENTRY(0x11c13026, "Si3054", patch_si3054), + HDA_CODEC_ENTRY(0x11c13055, "Si3054", patch_si3054), + HDA_CODEC_ENTRY(0x11c13155, "Si3054", patch_si3054), + HDA_CODEC_ENTRY(0x10573055, "Si3054", patch_si3054), + HDA_CODEC_ENTRY(0x10573057, "Si3054", patch_si3054), + HDA_CODEC_ENTRY(0x10573155, "Si3054", patch_si3054), /* VIA HDA on Clevo m540 */ - { .id = 0x11063288, .name = "Si3054", .patch = patch_si3054 }, + HDA_CODEC_ENTRY(0x11063288, "Si3054", patch_si3054), /* Asus A8J Modem (SM56) */ - { .id = 0x15433155, .name = "Si3054", .patch = patch_si3054 }, + HDA_CODEC_ENTRY(0x15433155, "Si3054", patch_si3054), /* LG LW20 modem */ - { .id = 0x18540018, .name = "Si3054", .patch = patch_si3054 }, + HDA_CODEC_ENTRY(0x18540018, "Si3054", patch_si3054), {} }; - -MODULE_ALIAS("snd-hda-codec-id:163c3055"); -MODULE_ALIAS("snd-hda-codec-id:163c3155"); -MODULE_ALIAS("snd-hda-codec-id:11c13026"); -MODULE_ALIAS("snd-hda-codec-id:11c13055"); -MODULE_ALIAS("snd-hda-codec-id:11c13155"); -MODULE_ALIAS("snd-hda-codec-id:10573055"); -MODULE_ALIAS("snd-hda-codec-id:10573057"); -MODULE_ALIAS("snd-hda-codec-id:10573155"); -MODULE_ALIAS("snd-hda-codec-id:11063288"); -MODULE_ALIAS("snd-hda-codec-id:15433155"); -MODULE_ALIAS("snd-hda-codec-id:18540018"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_si3054); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Si3054 HD-audio modem codec"); static struct hda_codec_driver si3054_driver = { - .preset = snd_hda_preset_si3054, + .id = snd_hda_id_si3054, }; module_hda_codec_driver(si3054_driver); diff --git a/kernel/sound/pci/hda/patch_sigmatel.c b/kernel/sound/pci/hda/patch_sigmatel.c index 25f0f45e6..37b70f8e8 100644 --- a/kernel/sound/pci/hda/patch_sigmatel.c +++ b/kernel/sound/pci/hda/patch_sigmatel.c @@ -493,9 +493,9 @@ static void jack_update_power(struct hda_codec *codec, if (!spec->num_pwrs) return; - if (jack && jack->tbl->nid) { - stac_toggle_power_map(codec, jack->tbl->nid, - snd_hda_jack_detect(codec, jack->tbl->nid), + if (jack && jack->nid) { + stac_toggle_power_map(codec, jack->nid, + snd_hda_jack_detect(codec, jack->nid), true); return; } @@ -702,6 +702,7 @@ static bool hp_bnb2011_with_dock(struct hda_codec *codec) static bool hp_blike_system(u32 subsystem_id) { switch (subsystem_id) { + case 0x103c1473: /* HP ProBook 6550b */ case 0x103c1520: case 0x103c1521: case 0x103c1523: @@ -3109,6 +3110,29 @@ static void stac92hd71bxx_fixup_hp_hdx(struct hda_codec *codec, spec->gpio_led = 0x08; } +static bool is_hp_output(struct hda_codec *codec, hda_nid_t pin) +{ + unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin); + + /* count line-out, too, as BIOS sets often so */ + return get_defcfg_connect(pin_cfg) != AC_JACK_PORT_NONE && + (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || + get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT); +} + +static void fixup_hp_headphone(struct hda_codec *codec, hda_nid_t pin) +{ + unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin); + + /* It was changed in the BIOS to just satisfy MS DTM. + * Lets turn it back into slaved HP + */ + pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) | + (AC_JACK_HP_OUT << AC_DEFCFG_DEVICE_SHIFT); + pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC | AC_DEFCFG_SEQUENCE))) | + 0x1f; + snd_hda_codec_set_pincfg(codec, pin, pin_cfg); +} static void stac92hd71bxx_fixup_hp(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -3118,22 +3142,12 @@ static void stac92hd71bxx_fixup_hp(struct hda_codec *codec, if (action != HDA_FIXUP_ACT_PRE_PROBE) return; - if (hp_blike_system(codec->core.subsystem_id)) { - unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f); - if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || - get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER || - get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) { - /* It was changed in the BIOS to just satisfy MS DTM. - * Lets turn it back into slaved HP - */ - pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) - | (AC_JACK_HP_OUT << - AC_DEFCFG_DEVICE_SHIFT); - pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC - | AC_DEFCFG_SEQUENCE))) - | 0x1f; - snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg); - } + /* when both output A and F are assigned, these are supposedly + * dock and built-in headphones; fix both pin configs + */ + if (is_hp_output(codec, 0x0a) && is_hp_output(codec, 0x0f)) { + fixup_hp_headphone(codec, 0x0a); + fixup_hp_headphone(codec, 0x0f); } if (find_mute_led_cfg(codec, 1)) @@ -4363,7 +4377,7 @@ static void stac_shutup(struct hda_codec *codec) #define stac_free snd_hda_gen_free -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS static void stac92hd_proc_hook(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { @@ -4443,6 +4457,7 @@ static int alloc_stac_spec(struct hda_codec *codec) codec->spec = spec; codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */ spec->gen.dac_min_mute = true; + codec->patch_ops = stac_patch_ops; return 0; } @@ -4459,7 +4474,6 @@ static int patch_stac9200(struct hda_codec *codec) spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; - codec->patch_ops = stac_patch_ops; codec->power_filter = snd_hda_codec_eapd_power_filter; snd_hda_add_verbs(codec, stac9200_eapd_init); @@ -4492,8 +4506,6 @@ static int patch_stac925x(struct hda_codec *codec) spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; - codec->patch_ops = stac_patch_ops; - snd_hda_add_verbs(codec, stac925x_core_init); snd_hda_pick_fixup(codec, stac925x_models, stac925x_fixup_tbl, @@ -4522,7 +4534,11 @@ static int patch_stac92hd73xx(struct hda_codec *codec) return err; spec = codec->spec; - codec->power_save_node = 1; + /* enable power_save_node only for new 92HD89xx chips, as it causes + * click noises on old 92HD73xx chips. + */ + if ((codec->core.vendor_id & 0xfffffff0) != 0x111d7670) + codec->power_save_node = 1; spec->linear_tone_beep = 0; spec->gen.mixer_nid = 0x1d; spec->have_spdif_mux = 1; @@ -4563,8 +4579,6 @@ static int patch_stac92hd73xx(struct hda_codec *codec) spec->gen.own_eapd_ctl = 1; spec->gen.power_down_unused = 1; - codec->patch_ops = stac_patch_ops; - snd_hda_pick_fixup(codec, stac92hd73xx_models, stac92hd73xx_fixup_tbl, stac92hd73xx_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -4640,8 +4654,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); spec->default_polarity = -1; /* no default cfg */ - codec->patch_ops = stac_patch_ops; - snd_hda_add_verbs(codec, stac92hd83xxx_core_init); snd_hda_pick_fixup(codec, stac92hd83xxx_models, stac92hd83xxx_fixup_tbl, @@ -4690,8 +4702,6 @@ static int patch_stac92hd95(struct hda_codec *codec) spec->num_pwrs = ARRAY_SIZE(stac92hd95_pwr_nids); spec->default_polarity = 0; - codec->patch_ops = stac_patch_ops; - snd_hda_pick_fixup(codec, stac92hd95_models, stac92hd95_fixup_tbl, stac92hd95_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -4730,8 +4740,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->gen.mixer_nid = 0x17; spec->have_spdif_mux = 1; - codec->patch_ops = stac_patch_ops; - /* GPIO0 = EAPD */ spec->gpio_mask = 0x01; spec->gpio_dir = 0x01; @@ -4810,8 +4818,6 @@ static int patch_stac922x(struct hda_codec *codec) spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; - codec->patch_ops = stac_patch_ops; - snd_hda_add_verbs(codec, stac922x_core_init); /* Fix Mux capture level; max to 2 */ @@ -4867,8 +4873,6 @@ static int patch_stac927x(struct hda_codec *codec) spec->aloopback_shift = 0; spec->eapd_switch = 1; - codec->patch_ops = stac_patch_ops; - snd_hda_pick_fixup(codec, stac927x_models, stac927x_fixup_tbl, stac927x_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -4930,8 +4934,6 @@ static int patch_stac9205(struct hda_codec *codec) /* Turn on/off EAPD per HP plugging */ spec->eapd_switch = 1; - codec->patch_ops = stac_patch_ops; - snd_hda_pick_fixup(codec, stac9205_models, stac9205_fixup_tbl, stac9205_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -5003,8 +5005,6 @@ static int patch_stac9872(struct hda_codec *codec) spec->linear_tone_beep = 1; spec->gen.own_eapd_ctl = 1; - codec->patch_ops = stac_patch_ops; - snd_hda_add_verbs(codec, stac9872_core_init); snd_hda_pick_fixup(codec, stac9872_models, stac9872_fixup_tbl, @@ -5026,121 +5026,119 @@ static int patch_stac9872(struct hda_codec *codec) /* * patch entries */ -static const struct hda_codec_preset snd_hda_preset_sigmatel[] = { - { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 }, - { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x }, - { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x }, - { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x }, - { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, - { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, - { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, - { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x }, - { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x }, - { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x }, - { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x }, - { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x }, - { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x }, - { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x }, - { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x }, - { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x }, - { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x }, - { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x }, - { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x }, - { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x }, - { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, - { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, - { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, - { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x }, - { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x }, - { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x }, - { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x }, - { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x }, - { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x }, - { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x }, - { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x }, - /* The following does not take into account .id=0x83847661 when subsys = - * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are - * currently not fully supported. - */ - { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 }, - { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 }, - { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 }, - { .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 }, - { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 }, - { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 }, - { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 }, - { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 }, - { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 }, - { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, - { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, - { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, - { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, - { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76d1, .name = "92HD87B1/3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76d9, .name = "92HD87B2/4", .patch = patch_stac92hd83xxx}, - { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx}, - { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx}, - { .id = 0x111d7669, .name = "92HD88B4", .patch = patch_stac92hd83xxx}, - { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, - { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, - { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, - { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, - { .id = 0x111d7695, .name = "92HD95", .patch = patch_stac92hd95 }, - { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, - { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, - { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, - { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, - { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, - { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, - { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, - { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, - { .id = 0x111d76c0, .name = "92HD89C3", .patch = patch_stac92hd73xx }, - { .id = 0x111d76c1, .name = "92HD89C2", .patch = patch_stac92hd73xx }, - { .id = 0x111d76c2, .name = "92HD89C1", .patch = patch_stac92hd73xx }, - { .id = 0x111d76c3, .name = "92HD89B3", .patch = patch_stac92hd73xx }, - { .id = 0x111d76c4, .name = "92HD89B2", .patch = patch_stac92hd73xx }, - { .id = 0x111d76c5, .name = "92HD89B1", .patch = patch_stac92hd73xx }, - { .id = 0x111d76c6, .name = "92HD89E3", .patch = patch_stac92hd73xx }, - { .id = 0x111d76c7, .name = "92HD89E2", .patch = patch_stac92hd73xx }, - { .id = 0x111d76c8, .name = "92HD89E1", .patch = patch_stac92hd73xx }, - { .id = 0x111d76c9, .name = "92HD89D3", .patch = patch_stac92hd73xx }, - { .id = 0x111d76ca, .name = "92HD89D2", .patch = patch_stac92hd73xx }, - { .id = 0x111d76cb, .name = "92HD89D1", .patch = patch_stac92hd73xx }, - { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx }, - { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx }, - { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx }, - { .id = 0x111d76df, .name = "92HD93BXX", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76e8, .name = "92HD66B1X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76e9, .name = "92HD66B2X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ea, .name = "92HD66B3X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76eb, .name = "92HD66C1X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ec, .name = "92HD66C2X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ed, .name = "92HD66C3X5", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ee, .name = "92HD66B1X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76ef, .name = "92HD66B2X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76f0, .name = "92HD66B3X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76f1, .name = "92HD66C1X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76f2, .name = "92HD66C2X3", .patch = patch_stac92hd83xxx}, - { .id = 0x111d76f3, .name = "92HD66C3/65", .patch = patch_stac92hd83xxx}, +static const struct hda_device_id snd_hda_id_sigmatel[] = { + HDA_CODEC_ENTRY(0x83847690, "STAC9200", patch_stac9200), + HDA_CODEC_ENTRY(0x83847882, "STAC9220 A1", patch_stac922x), + HDA_CODEC_ENTRY(0x83847680, "STAC9221 A1", patch_stac922x), + HDA_CODEC_ENTRY(0x83847880, "STAC9220 A2", patch_stac922x), + HDA_CODEC_ENTRY(0x83847681, "STAC9220D/9223D A2", patch_stac922x), + HDA_CODEC_ENTRY(0x83847682, "STAC9221 A2", patch_stac922x), + HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x), + HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x), + HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x), + HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x), + HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x), + HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x), + HDA_CODEC_ENTRY(0x83847615, "STAC9229", patch_stac927x), + HDA_CODEC_ENTRY(0x83847620, "STAC9274", patch_stac927x), + HDA_CODEC_ENTRY(0x83847621, "STAC9274D", patch_stac927x), + HDA_CODEC_ENTRY(0x83847622, "STAC9273X", patch_stac927x), + HDA_CODEC_ENTRY(0x83847623, "STAC9273D", patch_stac927x), + HDA_CODEC_ENTRY(0x83847624, "STAC9272X", patch_stac927x), + HDA_CODEC_ENTRY(0x83847625, "STAC9272D", patch_stac927x), + HDA_CODEC_ENTRY(0x83847626, "STAC9271X", patch_stac927x), + HDA_CODEC_ENTRY(0x83847627, "STAC9271D", patch_stac927x), + HDA_CODEC_ENTRY(0x83847628, "STAC9274X5NH", patch_stac927x), + HDA_CODEC_ENTRY(0x83847629, "STAC9274D5NH", patch_stac927x), + HDA_CODEC_ENTRY(0x83847632, "STAC9202", patch_stac925x), + HDA_CODEC_ENTRY(0x83847633, "STAC9202D", patch_stac925x), + HDA_CODEC_ENTRY(0x83847634, "STAC9250", patch_stac925x), + HDA_CODEC_ENTRY(0x83847635, "STAC9250D", patch_stac925x), + HDA_CODEC_ENTRY(0x83847636, "STAC9251", patch_stac925x), + HDA_CODEC_ENTRY(0x83847637, "STAC9250D", patch_stac925x), + HDA_CODEC_ENTRY(0x83847645, "92HD206X", patch_stac927x), + HDA_CODEC_ENTRY(0x83847646, "92HD206D", patch_stac927x), + /* The following does not take into account .id=0x83847661 when subsys = + * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are + * currently not fully supported. + */ + HDA_CODEC_ENTRY(0x83847661, "CXD9872RD/K", patch_stac9872), + HDA_CODEC_ENTRY(0x83847662, "STAC9872AK", patch_stac9872), + HDA_CODEC_ENTRY(0x83847664, "CXD9872AKD", patch_stac9872), + HDA_CODEC_ENTRY(0x83847698, "STAC9205", patch_stac9205), + HDA_CODEC_ENTRY(0x838476a0, "STAC9205", patch_stac9205), + HDA_CODEC_ENTRY(0x838476a1, "STAC9205D", patch_stac9205), + HDA_CODEC_ENTRY(0x838476a2, "STAC9204", patch_stac9205), + HDA_CODEC_ENTRY(0x838476a3, "STAC9204D", patch_stac9205), + HDA_CODEC_ENTRY(0x838476a4, "STAC9255", patch_stac9205), + HDA_CODEC_ENTRY(0x838476a5, "STAC9255D", patch_stac9205), + HDA_CODEC_ENTRY(0x838476a6, "STAC9254", patch_stac9205), + HDA_CODEC_ENTRY(0x838476a7, "STAC9254D", patch_stac9205), + HDA_CODEC_ENTRY(0x111d7603, "92HD75B3X5", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d7604, "92HD83C1X5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76d4, "92HD83C1C5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d7605, "92HD81B1X5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76d5, "92HD81B1C5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76d1, "92HD87B1/3", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76d9, "92HD87B2/4", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d7666, "92HD88B3", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d7667, "92HD88B1", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d7668, "92HD88B2", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d7669, "92HD88B4", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d7608, "92HD75B2X5", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d7674, "92HD73D1X5", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d7675, "92HD73C1X5", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d7676, "92HD73E1X5", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d7695, "92HD95", patch_stac92hd95), + HDA_CODEC_ENTRY(0x111d76b0, "92HD71B8X", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d76b1, "92HD71B8X", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d76b2, "92HD71B7X", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d76b3, "92HD71B7X", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d76b4, "92HD71B6X", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d76b5, "92HD71B6X", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d76b6, "92HD71B5X", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d76b7, "92HD71B5X", patch_stac92hd71bxx), + HDA_CODEC_ENTRY(0x111d76c0, "92HD89C3", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76c1, "92HD89C2", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76c2, "92HD89C1", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76c3, "92HD89B3", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76c4, "92HD89B2", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76c5, "92HD89B1", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76c6, "92HD89E3", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76c7, "92HD89E2", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76c8, "92HD89E1", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76c9, "92HD89D3", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76ca, "92HD89D2", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76cb, "92HD89D1", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76cc, "92HD89F3", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76cd, "92HD89F2", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76ce, "92HD89F1", patch_stac92hd73xx), + HDA_CODEC_ENTRY(0x111d76df, "92HD93BXX", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76e0, "92HD91BXX", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76e3, "92HD98BXX", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76e5, "92HD99BXX", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76e7, "92HD90BXX", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76e8, "92HD66B1X5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76e9, "92HD66B2X5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76ea, "92HD66B3X5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76eb, "92HD66C1X5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76ec, "92HD66C2X5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76ed, "92HD66C3X5", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76ee, "92HD66B1X3", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76ef, "92HD66B2X3", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76f0, "92HD66B3X3", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76f1, "92HD66C1X3", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76f2, "92HD66C2X3", patch_stac92hd83xxx), + HDA_CODEC_ENTRY(0x111d76f3, "92HD66C3/65", patch_stac92hd83xxx), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:8384*"); -MODULE_ALIAS("snd-hda-codec-id:111d*"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_sigmatel); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec"); static struct hda_codec_driver sigmatel_driver = { - .preset = snd_hda_preset_sigmatel, + .id = snd_hda_id_sigmatel, }; module_hda_codec_driver(sigmatel_driver); diff --git a/kernel/sound/pci/hda/patch_via.c b/kernel/sound/pci/hda/patch_via.c index 0baeecc22..fc30d1e8a 100644 --- a/kernel/sound/pci/hda/patch_via.c +++ b/kernel/sound/pci/hda/patch_via.c @@ -117,6 +117,8 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream, int action); +static const struct hda_codec_ops via_patch_ops; /* defined below */ + static struct via_spec *via_new_spec(struct hda_codec *codec) { struct via_spec *spec; @@ -137,6 +139,7 @@ static struct via_spec *via_new_spec(struct hda_codec *codec) spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO; codec->power_save_node = 1; spec->gen.power_down_unused = 1; + codec->patch_ops = via_patch_ops; return spec; } @@ -483,7 +486,6 @@ static const struct hda_codec_ops via_patch_ops = { .init = via_init, .free = via_free, .unsol_event = snd_hda_jack_unsol_event, - .stream_pm = snd_hda_gen_stream_pm, #ifdef CONFIG_PM .suspend = via_suspend, .resume = via_resume, @@ -663,6 +665,9 @@ static int patch_vt1708(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + /* override some patch_ops */ + codec->patch_ops.build_controls = vt1708_build_controls; + codec->patch_ops.build_pcms = vt1708_build_pcms; spec->gen.mixer_nid = 0x17; /* set jackpoll_interval while parsing the codec */ @@ -691,10 +696,6 @@ static int patch_vt1708(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs; - codec->patch_ops = via_patch_ops; - codec->patch_ops.build_controls = vt1708_build_controls; - codec->patch_ops.build_pcms = vt1708_build_pcms; - /* clear jackpoll_interval again; it's set dynamically */ codec->jackpoll_interval = 0; @@ -719,8 +720,6 @@ static int patch_vt1709(struct hda_codec *codec) return err; } - codec->patch_ops = via_patch_ops; - return 0; } @@ -747,7 +746,6 @@ static int patch_vt1708B(struct hda_codec *codec) return err; } - codec->patch_ops = via_patch_ops; return 0; } @@ -787,21 +785,11 @@ static int patch_vt1708S(struct hda_codec *codec) override_mic_boost(codec, 0x1e, 0, 3, 40); /* correct names for VT1708BCE */ - if (get_codec_type(codec) == VT1708BCE) { - kfree(codec->core.chip_name); - codec->core.chip_name = kstrdup("VT1708BCE", GFP_KERNEL); - snprintf(codec->card->mixername, - sizeof(codec->card->mixername), - "%s %s", codec->core.vendor_name, codec->core.chip_name); - } + if (get_codec_type(codec) == VT1708BCE) + snd_hda_codec_set_name(codec, "VT1708BCE"); /* correct names for VT1705 */ - if (codec->core.vendor_id == 0x11064397) { - kfree(codec->core.chip_name); - codec->core.chip_name = kstrdup("VT1705", GFP_KERNEL); - snprintf(codec->card->mixername, - sizeof(codec->card->mixername), - "%s %s", codec->core.vendor_name, codec->core.chip_name); - } + if (codec->core.vendor_id == 0x11064397) + snd_hda_codec_set_name(codec, "VT1705"); /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); @@ -812,7 +800,6 @@ static int patch_vt1708S(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs; - codec->patch_ops = via_patch_ops; return 0; } @@ -854,7 +841,6 @@ static int patch_vt1702(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs; - codec->patch_ops = via_patch_ops; return 0; } @@ -927,7 +913,6 @@ static int patch_vt1718S(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs; - codec->patch_ops = via_patch_ops; return 0; } @@ -1027,7 +1012,6 @@ static int patch_vt1716S(struct hda_codec *codec) spec->mixers[spec->num_mixers++] = vt1716s_dmic_mixer; spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; - codec->patch_ops = via_patch_ops; return 0; } @@ -1135,7 +1119,6 @@ static int patch_vt2002P(struct hda_codec *codec) else spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs; - codec->patch_ops = via_patch_ops; return 0; } @@ -1174,7 +1157,6 @@ static int patch_vt1812(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt1812_init_verbs; - codec->patch_ops = via_patch_ops; return 0; } @@ -1212,116 +1194,70 @@ static int patch_vt3476(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs; - codec->patch_ops = via_patch_ops; return 0; } /* * patch entries */ -static const struct hda_codec_preset snd_hda_preset_via[] = { - { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708}, - { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708}, - { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708}, - { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708}, - { .id = 0x1106e710, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, - { .id = 0x1106e711, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, - { .id = 0x1106e712, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, - { .id = 0x1106e713, .name = "VT1709 10-Ch", - .patch = patch_vt1709}, - { .id = 0x1106e714, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, - { .id = 0x1106e715, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, - { .id = 0x1106e716, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, - { .id = 0x1106e717, .name = "VT1709 6-Ch", - .patch = patch_vt1709}, - { .id = 0x1106e720, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, - { .id = 0x1106e721, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, - { .id = 0x1106e722, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, - { .id = 0x1106e723, .name = "VT1708B 8-Ch", - .patch = patch_vt1708B}, - { .id = 0x1106e724, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, - { .id = 0x1106e725, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, - { .id = 0x1106e726, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, - { .id = 0x1106e727, .name = "VT1708B 4-Ch", - .patch = patch_vt1708B}, - { .id = 0x11060397, .name = "VT1708S", - .patch = patch_vt1708S}, - { .id = 0x11061397, .name = "VT1708S", - .patch = patch_vt1708S}, - { .id = 0x11062397, .name = "VT1708S", - .patch = patch_vt1708S}, - { .id = 0x11063397, .name = "VT1708S", - .patch = patch_vt1708S}, - { .id = 0x11064397, .name = "VT1705", - .patch = patch_vt1708S}, - { .id = 0x11065397, .name = "VT1708S", - .patch = patch_vt1708S}, - { .id = 0x11066397, .name = "VT1708S", - .patch = patch_vt1708S}, - { .id = 0x11067397, .name = "VT1708S", - .patch = patch_vt1708S}, - { .id = 0x11060398, .name = "VT1702", - .patch = patch_vt1702}, - { .id = 0x11061398, .name = "VT1702", - .patch = patch_vt1702}, - { .id = 0x11062398, .name = "VT1702", - .patch = patch_vt1702}, - { .id = 0x11063398, .name = "VT1702", - .patch = patch_vt1702}, - { .id = 0x11064398, .name = "VT1702", - .patch = patch_vt1702}, - { .id = 0x11065398, .name = "VT1702", - .patch = patch_vt1702}, - { .id = 0x11066398, .name = "VT1702", - .patch = patch_vt1702}, - { .id = 0x11067398, .name = "VT1702", - .patch = patch_vt1702}, - { .id = 0x11060428, .name = "VT1718S", - .patch = patch_vt1718S}, - { .id = 0x11064428, .name = "VT1718S", - .patch = patch_vt1718S}, - { .id = 0x11060441, .name = "VT2020", - .patch = patch_vt1718S}, - { .id = 0x11064441, .name = "VT1828S", - .patch = patch_vt1718S}, - { .id = 0x11060433, .name = "VT1716S", - .patch = patch_vt1716S}, - { .id = 0x1106a721, .name = "VT1716S", - .patch = patch_vt1716S}, - { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P}, - { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P}, - { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812}, - { .id = 0x11060440, .name = "VT1818S", - .patch = patch_vt1708S}, - { .id = 0x11060446, .name = "VT1802", - .patch = patch_vt2002P}, - { .id = 0x11068446, .name = "VT1802", - .patch = patch_vt2002P}, - { .id = 0x11064760, .name = "VT1705CF", - .patch = patch_vt3476}, - { .id = 0x11064761, .name = "VT1708SCE", - .patch = patch_vt3476}, - { .id = 0x11064762, .name = "VT1808", - .patch = patch_vt3476}, +static const struct hda_device_id snd_hda_id_via[] = { + HDA_CODEC_ENTRY(0x11061708, "VT1708", patch_vt1708), + HDA_CODEC_ENTRY(0x11061709, "VT1708", patch_vt1708), + HDA_CODEC_ENTRY(0x1106170a, "VT1708", patch_vt1708), + HDA_CODEC_ENTRY(0x1106170b, "VT1708", patch_vt1708), + HDA_CODEC_ENTRY(0x1106e710, "VT1709 10-Ch", patch_vt1709), + HDA_CODEC_ENTRY(0x1106e711, "VT1709 10-Ch", patch_vt1709), + HDA_CODEC_ENTRY(0x1106e712, "VT1709 10-Ch", patch_vt1709), + HDA_CODEC_ENTRY(0x1106e713, "VT1709 10-Ch", patch_vt1709), + HDA_CODEC_ENTRY(0x1106e714, "VT1709 6-Ch", patch_vt1709), + HDA_CODEC_ENTRY(0x1106e715, "VT1709 6-Ch", patch_vt1709), + HDA_CODEC_ENTRY(0x1106e716, "VT1709 6-Ch", patch_vt1709), + HDA_CODEC_ENTRY(0x1106e717, "VT1709 6-Ch", patch_vt1709), + HDA_CODEC_ENTRY(0x1106e720, "VT1708B 8-Ch", patch_vt1708B), + HDA_CODEC_ENTRY(0x1106e721, "VT1708B 8-Ch", patch_vt1708B), + HDA_CODEC_ENTRY(0x1106e722, "VT1708B 8-Ch", patch_vt1708B), + HDA_CODEC_ENTRY(0x1106e723, "VT1708B 8-Ch", patch_vt1708B), + HDA_CODEC_ENTRY(0x1106e724, "VT1708B 4-Ch", patch_vt1708B), + HDA_CODEC_ENTRY(0x1106e725, "VT1708B 4-Ch", patch_vt1708B), + HDA_CODEC_ENTRY(0x1106e726, "VT1708B 4-Ch", patch_vt1708B), + HDA_CODEC_ENTRY(0x1106e727, "VT1708B 4-Ch", patch_vt1708B), + HDA_CODEC_ENTRY(0x11060397, "VT1708S", patch_vt1708S), + HDA_CODEC_ENTRY(0x11061397, "VT1708S", patch_vt1708S), + HDA_CODEC_ENTRY(0x11062397, "VT1708S", patch_vt1708S), + HDA_CODEC_ENTRY(0x11063397, "VT1708S", patch_vt1708S), + HDA_CODEC_ENTRY(0x11064397, "VT1705", patch_vt1708S), + HDA_CODEC_ENTRY(0x11065397, "VT1708S", patch_vt1708S), + HDA_CODEC_ENTRY(0x11066397, "VT1708S", patch_vt1708S), + HDA_CODEC_ENTRY(0x11067397, "VT1708S", patch_vt1708S), + HDA_CODEC_ENTRY(0x11060398, "VT1702", patch_vt1702), + HDA_CODEC_ENTRY(0x11061398, "VT1702", patch_vt1702), + HDA_CODEC_ENTRY(0x11062398, "VT1702", patch_vt1702), + HDA_CODEC_ENTRY(0x11063398, "VT1702", patch_vt1702), + HDA_CODEC_ENTRY(0x11064398, "VT1702", patch_vt1702), + HDA_CODEC_ENTRY(0x11065398, "VT1702", patch_vt1702), + HDA_CODEC_ENTRY(0x11066398, "VT1702", patch_vt1702), + HDA_CODEC_ENTRY(0x11067398, "VT1702", patch_vt1702), + HDA_CODEC_ENTRY(0x11060428, "VT1718S", patch_vt1718S), + HDA_CODEC_ENTRY(0x11064428, "VT1718S", patch_vt1718S), + HDA_CODEC_ENTRY(0x11060441, "VT2020", patch_vt1718S), + HDA_CODEC_ENTRY(0x11064441, "VT1828S", patch_vt1718S), + HDA_CODEC_ENTRY(0x11060433, "VT1716S", patch_vt1716S), + HDA_CODEC_ENTRY(0x1106a721, "VT1716S", patch_vt1716S), + HDA_CODEC_ENTRY(0x11060438, "VT2002P", patch_vt2002P), + HDA_CODEC_ENTRY(0x11064438, "VT2002P", patch_vt2002P), + HDA_CODEC_ENTRY(0x11060448, "VT1812", patch_vt1812), + HDA_CODEC_ENTRY(0x11060440, "VT1818S", patch_vt1708S), + HDA_CODEC_ENTRY(0x11060446, "VT1802", patch_vt2002P), + HDA_CODEC_ENTRY(0x11068446, "VT1802", patch_vt2002P), + HDA_CODEC_ENTRY(0x11064760, "VT1705CF", patch_vt3476), + HDA_CODEC_ENTRY(0x11064761, "VT1708SCE", patch_vt3476), + HDA_CODEC_ENTRY(0x11064762, "VT1808", patch_vt3476), {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:1106*"); +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_via); static struct hda_codec_driver via_driver = { - .preset = snd_hda_preset_via, + .id = snd_hda_id_via, }; MODULE_LICENSE("GPL"); |