mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
Merge branch 'topic/hda-bus' into for-next
This commit is contained in:
commit
8f88f0256f
@ -4,7 +4,7 @@ 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_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.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-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
|
||||
|
@ -160,6 +160,7 @@ static int snd_hda_do_attach(struct hda_beep *beep)
|
||||
input_dev->name = "HDA Digital PCBeep";
|
||||
input_dev->phys = beep->phys;
|
||||
input_dev->id.bustype = BUS_PCI;
|
||||
input_dev->dev.parent = &codec->bus->card->card_dev;
|
||||
|
||||
input_dev->id.vendor = codec->vendor_id >> 16;
|
||||
input_dev->id.product = codec->vendor_id & 0xffff;
|
||||
@ -168,7 +169,6 @@ static int snd_hda_do_attach(struct hda_beep *beep)
|
||||
input_dev->evbit[0] = BIT_MASK(EV_SND);
|
||||
input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
|
||||
input_dev->event = snd_hda_beep_event;
|
||||
input_dev->dev.parent = &codec->dev;
|
||||
input_set_drvdata(input_dev, beep);
|
||||
|
||||
beep->dev = input_dev;
|
||||
|
321
sound/pci/hda/hda_bind.c
Normal file
321
sound/pci/hda/hda_bind.c
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* HD-audio codec driver binding
|
||||
* Copyright (c) Takashi Iwai <tiwai@suse.de>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/pm.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
||||
/* codec vendor labels */
|
||||
struct hda_vendor_id {
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static struct hda_vendor_id hda_vendor_ids[] = {
|
||||
{ 0x1002, "ATI" },
|
||||
{ 0x1013, "Cirrus Logic" },
|
||||
{ 0x1057, "Motorola" },
|
||||
{ 0x1095, "Silicon Image" },
|
||||
{ 0x10de, "Nvidia" },
|
||||
{ 0x10ec, "Realtek" },
|
||||
{ 0x1102, "Creative" },
|
||||
{ 0x1106, "VIA" },
|
||||
{ 0x111d, "IDT" },
|
||||
{ 0x11c1, "LSI" },
|
||||
{ 0x11d4, "Analog Devices" },
|
||||
{ 0x13f6, "C-Media" },
|
||||
{ 0x14f1, "Conexant" },
|
||||
{ 0x17e8, "Chrontel" },
|
||||
{ 0x1854, "LG" },
|
||||
{ 0x1aec, "Wolfson Microelectronics" },
|
||||
{ 0x1af4, "QEMU" },
|
||||
{ 0x434d, "C-Media" },
|
||||
{ 0x8086, "Intel" },
|
||||
{ 0x8384, "SigmaTel" },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
/*
|
||||
* find a matching codec preset
|
||||
*/
|
||||
static int hda_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct hda_codec *codec = container_of(dev, struct hda_codec, dev);
|
||||
struct hda_codec_driver *driver =
|
||||
container_of(drv, struct hda_codec_driver, driver);
|
||||
const struct hda_codec_preset *preset;
|
||||
/* check probe_id instead of vendor_id if set */
|
||||
u32 id = codec->probe_id ? codec->probe_id : codec->vendor_id;
|
||||
|
||||
for (preset = driver->preset; preset->id; preset++) {
|
||||
u32 mask = preset->mask;
|
||||
|
||||
if (preset->afg && preset->afg != codec->afg)
|
||||
continue;
|
||||
if (preset->mfg && preset->mfg != codec->mfg)
|
||||
continue;
|
||||
if (!mask)
|
||||
mask = ~0;
|
||||
if (preset->id == (id & mask) &&
|
||||
(!preset->rev || preset->rev == codec->revision_id)) {
|
||||
codec->preset = preset;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reset the codec name from the preset */
|
||||
static int codec_refresh_name(struct hda_codec *codec, const char *name)
|
||||
{
|
||||
char tmp[16];
|
||||
|
||||
kfree(codec->chip_name);
|
||||
if (!name) {
|
||||
sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
|
||||
name = tmp;
|
||||
}
|
||||
codec->chip_name = kstrdup(name, GFP_KERNEL);
|
||||
return codec->chip_name ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static int hda_codec_driver_probe(struct device *dev)
|
||||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(dev);
|
||||
struct module *owner = dev->driver->owner;
|
||||
int err;
|
||||
|
||||
if (WARN_ON(!codec->preset))
|
||||
return -EINVAL;
|
||||
|
||||
err = codec_refresh_name(codec, codec->preset->name);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
if (!try_module_get(owner)) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = codec->preset->patch(codec);
|
||||
if (err < 0) {
|
||||
module_put(owner);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
codec->preset = NULL;
|
||||
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hda_codec_driver_remove(struct device *dev)
|
||||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(dev);
|
||||
|
||||
if (codec->patch_ops.free)
|
||||
codec->patch_ops.free(codec);
|
||||
codec->preset = NULL;
|
||||
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
|
||||
module_put(dev->driver->owner);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
|
||||
struct module *owner)
|
||||
{
|
||||
drv->driver.name = name;
|
||||
drv->driver.owner = owner;
|
||||
drv->driver.bus = &snd_hda_bus_type;
|
||||
drv->driver.probe = hda_codec_driver_probe;
|
||||
drv->driver.remove = hda_codec_driver_remove;
|
||||
drv->driver.pm = &hda_codec_driver_pm;
|
||||
return driver_register(&drv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__hda_codec_driver_register);
|
||||
|
||||
void hda_codec_driver_unregister(struct hda_codec_driver *drv)
|
||||
{
|
||||
driver_unregister(&drv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hda_codec_driver_unregister);
|
||||
|
||||
static inline bool codec_probed(struct hda_codec *codec)
|
||||
{
|
||||
return device_attach(hda_codec_dev(codec)) > 0 && codec->preset;
|
||||
}
|
||||
|
||||
/* 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->vendor_id);
|
||||
if (codec_probed(codec))
|
||||
return;
|
||||
request_module("snd-hda-codec-id:%04x*",
|
||||
(codec->vendor_id >> 16) & 0xffff);
|
||||
if (codec_probed(codec))
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* store the codec vendor name */
|
||||
static int get_codec_vendor_name(struct hda_codec *codec)
|
||||
{
|
||||
const struct hda_vendor_id *c;
|
||||
const char *vendor = NULL;
|
||||
u16 vendor_id = codec->vendor_id >> 16;
|
||||
char tmp[16];
|
||||
|
||||
for (c = hda_vendor_ids; c->id; c++) {
|
||||
if (c->id == vendor_id) {
|
||||
vendor = c->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!vendor) {
|
||||
sprintf(tmp, "Generic %04x", vendor_id);
|
||||
vendor = tmp;
|
||||
}
|
||||
codec->vendor_name = kstrdup(vendor, GFP_KERNEL);
|
||||
if (!codec->vendor_name)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
|
||||
/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */
|
||||
static bool is_likely_hdmi_codec(struct hda_codec *codec)
|
||||
{
|
||||
hda_nid_t nid = codec->start_nid;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
switch (get_wcaps_type(wcaps)) {
|
||||
case AC_WID_AUD_IN:
|
||||
return false; /* HDMI parser supports only HDMI out */
|
||||
case AC_WID_AUD_OUT:
|
||||
if (!(wcaps & AC_WCAP_DIGITAL))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
/* no HDMI codec parser support */
|
||||
#define is_likely_hdmi_codec(codec) false
|
||||
#endif /* CONFIG_SND_HDA_CODEC_HDMI */
|
||||
|
||||
static int codec_bind_generic(struct hda_codec *codec)
|
||||
{
|
||||
if (codec->probe_id)
|
||||
return -ENODEV;
|
||||
|
||||
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
|
||||
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
|
||||
if (codec_probed(codec))
|
||||
return 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
|
||||
#define is_generic_config(codec) \
|
||||
(codec->modelname && !strcmp(codec->modelname, "generic"))
|
||||
#else
|
||||
#define is_generic_config(codec) 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* snd_hda_codec_configure - (Re-)configure the HD-audio codec
|
||||
* @codec: the HDA codec
|
||||
*
|
||||
* Start parsing of the given codec tree and (re-)initialize the whole
|
||||
* patch instance.
|
||||
*
|
||||
* Returns 0 if successful or a negative error code.
|
||||
*/
|
||||
int snd_hda_codec_configure(struct hda_codec *codec)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!codec->vendor_name) {
|
||||
err = get_codec_vendor_name(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (is_generic_config(codec))
|
||||
codec->probe_id = HDA_CODEC_ID_GENERIC;
|
||||
else
|
||||
codec->probe_id = 0;
|
||||
|
||||
err = device_add(hda_codec_dev(codec));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!codec->preset)
|
||||
codec_bind_module(codec);
|
||||
if (!codec->preset) {
|
||||
err = codec_bind_generic(codec);
|
||||
if (err < 0) {
|
||||
codec_err(codec, "Unable to bind the codec\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* audio codec should override the mixer name */
|
||||
if (codec->afg || !*codec->bus->card->mixername)
|
||||
snprintf(codec->bus->card->mixername,
|
||||
sizeof(codec->bus->card->mixername),
|
||||
"%s %s", codec->vendor_name, codec->chip_name);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
device_del(hda_codec_dev(codec));
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
|
||||
|
||||
/*
|
||||
* bus registration
|
||||
*/
|
||||
struct bus_type snd_hda_bus_type = {
|
||||
.name = "hdaudio",
|
||||
.match = hda_bus_match,
|
||||
};
|
||||
|
||||
static int __init hda_codec_init(void)
|
||||
{
|
||||
return bus_register(&snd_hda_bus_type);
|
||||
}
|
||||
|
||||
static void __exit hda_codec_exit(void)
|
||||
{
|
||||
bus_unregister(&snd_hda_bus_type);
|
||||
}
|
||||
|
||||
module_init(hda_codec_init);
|
||||
module_exit(hda_codec_exit);
|
@ -26,6 +26,8 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/async.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include <sound/asoundef.h>
|
||||
@ -40,92 +42,13 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "hda_trace.h"
|
||||
|
||||
/*
|
||||
* vendor / preset table
|
||||
*/
|
||||
|
||||
struct hda_vendor_id {
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* codec vendor labels */
|
||||
static struct hda_vendor_id hda_vendor_ids[] = {
|
||||
{ 0x1002, "ATI" },
|
||||
{ 0x1013, "Cirrus Logic" },
|
||||
{ 0x1057, "Motorola" },
|
||||
{ 0x1095, "Silicon Image" },
|
||||
{ 0x10de, "Nvidia" },
|
||||
{ 0x10ec, "Realtek" },
|
||||
{ 0x1102, "Creative" },
|
||||
{ 0x1106, "VIA" },
|
||||
{ 0x111d, "IDT" },
|
||||
{ 0x11c1, "LSI" },
|
||||
{ 0x11d4, "Analog Devices" },
|
||||
{ 0x13f6, "C-Media" },
|
||||
{ 0x14f1, "Conexant" },
|
||||
{ 0x17e8, "Chrontel" },
|
||||
{ 0x1854, "LG" },
|
||||
{ 0x1aec, "Wolfson Microelectronics" },
|
||||
{ 0x1af4, "QEMU" },
|
||||
{ 0x434d, "C-Media" },
|
||||
{ 0x8086, "Intel" },
|
||||
{ 0x8384, "SigmaTel" },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(preset_mutex);
|
||||
static LIST_HEAD(hda_preset_tables);
|
||||
|
||||
/**
|
||||
* snd_hda_add_codec_preset - Add a codec preset to the chain
|
||||
* @preset: codec preset table to add
|
||||
*/
|
||||
int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
|
||||
{
|
||||
mutex_lock(&preset_mutex);
|
||||
list_add_tail(&preset->list, &hda_preset_tables);
|
||||
mutex_unlock(&preset_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset);
|
||||
|
||||
/**
|
||||
* snd_hda_delete_codec_preset - Delete a codec preset from the chain
|
||||
* @preset: codec preset table to delete
|
||||
*/
|
||||
int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
|
||||
{
|
||||
mutex_lock(&preset_mutex);
|
||||
list_del(&preset->list);
|
||||
mutex_unlock(&preset_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#define codec_in_pm(codec) ((codec)->in_pm)
|
||||
static void hda_power_work(struct work_struct *work);
|
||||
static void hda_keep_power_on(struct hda_codec *codec);
|
||||
#define hda_codec_is_power_on(codec) ((codec)->power_on)
|
||||
|
||||
static void hda_call_pm_notify(struct hda_codec *codec, bool power_up)
|
||||
{
|
||||
struct hda_bus *bus = codec->bus;
|
||||
|
||||
if ((power_up && codec->pm_up_notified) ||
|
||||
(!power_up && !codec->pm_up_notified))
|
||||
return;
|
||||
if (bus->ops.pm_notify)
|
||||
bus->ops.pm_notify(bus, power_up);
|
||||
codec->pm_up_notified = power_up;
|
||||
}
|
||||
|
||||
#define codec_in_pm(codec) atomic_read(&(codec)->in_pm)
|
||||
#define hda_codec_is_power_on(codec) \
|
||||
(!pm_runtime_suspended(hda_codec_dev(codec)))
|
||||
#else
|
||||
#define codec_in_pm(codec) 0
|
||||
static inline void hda_keep_power_on(struct hda_codec *codec) {}
|
||||
#define hda_codec_is_power_on(codec) 1
|
||||
#define hda_call_pm_notify(codec, state) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -885,111 +808,6 @@ int snd_hda_bus_new(struct snd_card *card,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_bus_new);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
|
||||
#define is_generic_config(codec) \
|
||||
(codec->modelname && !strcmp(codec->modelname, "generic"))
|
||||
#else
|
||||
#define is_generic_config(codec) 0
|
||||
#endif
|
||||
|
||||
#ifdef MODULE
|
||||
#define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */
|
||||
#else
|
||||
#define HDA_MODREQ_MAX_COUNT 0 /* all presets are statically linked */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* find a matching codec preset
|
||||
*/
|
||||
static const struct hda_codec_preset *
|
||||
find_codec_preset(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_codec_preset_list *tbl;
|
||||
const struct hda_codec_preset *preset;
|
||||
unsigned int mod_requested = 0;
|
||||
|
||||
again:
|
||||
mutex_lock(&preset_mutex);
|
||||
list_for_each_entry(tbl, &hda_preset_tables, list) {
|
||||
if (!try_module_get(tbl->owner)) {
|
||||
codec_err(codec, "cannot module_get\n");
|
||||
continue;
|
||||
}
|
||||
for (preset = tbl->preset; preset->id; preset++) {
|
||||
u32 mask = preset->mask;
|
||||
if (preset->afg && preset->afg != codec->afg)
|
||||
continue;
|
||||
if (preset->mfg && preset->mfg != codec->mfg)
|
||||
continue;
|
||||
if (!mask)
|
||||
mask = ~0;
|
||||
if (preset->id == (codec->vendor_id & mask) &&
|
||||
(!preset->rev ||
|
||||
preset->rev == codec->revision_id)) {
|
||||
mutex_unlock(&preset_mutex);
|
||||
codec->owner = tbl->owner;
|
||||
return preset;
|
||||
}
|
||||
}
|
||||
module_put(tbl->owner);
|
||||
}
|
||||
mutex_unlock(&preset_mutex);
|
||||
|
||||
if (mod_requested < HDA_MODREQ_MAX_COUNT) {
|
||||
if (!mod_requested)
|
||||
request_module("snd-hda-codec-id:%08x",
|
||||
codec->vendor_id);
|
||||
else
|
||||
request_module("snd-hda-codec-id:%04x*",
|
||||
(codec->vendor_id >> 16) & 0xffff);
|
||||
mod_requested++;
|
||||
goto again;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_codec_name - store the codec name
|
||||
*/
|
||||
static int get_codec_name(struct hda_codec *codec)
|
||||
{
|
||||
const struct hda_vendor_id *c;
|
||||
const char *vendor = NULL;
|
||||
u16 vendor_id = codec->vendor_id >> 16;
|
||||
char tmp[16];
|
||||
|
||||
if (codec->vendor_name)
|
||||
goto get_chip_name;
|
||||
|
||||
for (c = hda_vendor_ids; c->id; c++) {
|
||||
if (c->id == vendor_id) {
|
||||
vendor = c->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!vendor) {
|
||||
sprintf(tmp, "Generic %04x", vendor_id);
|
||||
vendor = tmp;
|
||||
}
|
||||
codec->vendor_name = kstrdup(vendor, GFP_KERNEL);
|
||||
if (!codec->vendor_name)
|
||||
return -ENOMEM;
|
||||
|
||||
get_chip_name:
|
||||
if (codec->chip_name)
|
||||
return 0;
|
||||
|
||||
if (codec->preset && codec->preset->name)
|
||||
codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL);
|
||||
else {
|
||||
sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
|
||||
codec->chip_name = kstrdup(tmp, GFP_KERNEL);
|
||||
}
|
||||
if (!codec->chip_name)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* look for an AFG and MFG nodes
|
||||
*/
|
||||
@ -1300,20 +1118,6 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid)
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dynamic symbol binding for the codec parsers
|
||||
*/
|
||||
|
||||
#define load_parser(codec, sym) \
|
||||
((codec)->parser = (int (*)(struct hda_codec *))symbol_request(sym))
|
||||
|
||||
static void unload_parser(struct hda_codec *codec)
|
||||
{
|
||||
if (codec->parser)
|
||||
symbol_put_addr(codec->parser);
|
||||
codec->parser = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* codec destructor
|
||||
*/
|
||||
@ -1322,12 +1126,11 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
||||
if (!codec)
|
||||
return;
|
||||
cancel_delayed_work_sync(&codec->jackpoll_work);
|
||||
if (device_is_registered(hda_codec_dev(codec)))
|
||||
device_del(hda_codec_dev(codec));
|
||||
snd_hda_jack_tbl_clear(codec);
|
||||
free_init_pincfgs(codec);
|
||||
#ifdef CONFIG_PM
|
||||
cancel_delayed_work(&codec->power_work);
|
||||
flush_workqueue(codec->bus->workq);
|
||||
#endif
|
||||
list_del(&codec->list);
|
||||
snd_array_free(&codec->mixers);
|
||||
snd_array_free(&codec->nids);
|
||||
@ -1335,12 +1138,8 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
||||
snd_array_free(&codec->spdif_out);
|
||||
remove_conn_list(codec);
|
||||
codec->bus->caddr_tbl[codec->addr] = NULL;
|
||||
if (codec->patch_ops.free)
|
||||
codec->patch_ops.free(codec);
|
||||
hda_call_pm_notify(codec, false); /* cancel leftover refcounts */
|
||||
clear_bit(codec->addr, &codec->bus->codec_powered);
|
||||
snd_hda_sysfs_clear(codec);
|
||||
unload_parser(codec);
|
||||
module_put(codec->owner);
|
||||
free_hda_cache(&codec->amp_cache);
|
||||
free_hda_cache(&codec->cmd_cache);
|
||||
kfree(codec->vendor_name);
|
||||
@ -1348,7 +1147,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
||||
kfree(codec->modelname);
|
||||
kfree(codec->wcaps);
|
||||
codec->bus->num_codecs--;
|
||||
put_device(&codec->dev);
|
||||
put_device(hda_codec_dev(codec));
|
||||
}
|
||||
|
||||
static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
|
||||
@ -1360,11 +1159,12 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
|
||||
static int snd_hda_codec_dev_register(struct snd_device *device)
|
||||
{
|
||||
struct hda_codec *codec = device->device_data;
|
||||
int err = device_add(&codec->dev);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
snd_hda_register_beep_device(codec);
|
||||
if (device_is_registered(hda_codec_dev(codec)))
|
||||
pm_runtime_enable(hda_codec_dev(codec));
|
||||
/* it was powered up in snd_hda_codec_new(), now all done */
|
||||
snd_hda_power_down(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1373,7 +1173,6 @@ static int snd_hda_codec_dev_disconnect(struct snd_device *device)
|
||||
struct hda_codec *codec = device->device_data;
|
||||
|
||||
snd_hda_detach_beep_device(codec);
|
||||
device_del(&codec->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1386,7 +1185,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
|
||||
/* just free the container */
|
||||
static void snd_hda_codec_dev_release(struct device *dev)
|
||||
{
|
||||
kfree(container_of(dev, struct hda_codec, dev));
|
||||
kfree(dev_to_hda_codec(dev));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1402,6 +1201,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
struct hda_codec *codec;
|
||||
struct device *dev;
|
||||
char component[31];
|
||||
hda_nid_t fg;
|
||||
int err;
|
||||
@ -1429,14 +1229,15 @@ int snd_hda_codec_new(struct hda_bus *bus,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
device_initialize(&codec->dev);
|
||||
codec->dev.parent = &bus->card->card_dev;
|
||||
codec->dev.class = sound_class;
|
||||
codec->dev.release = snd_hda_codec_dev_release;
|
||||
codec->dev.groups = snd_hda_dev_attr_groups;
|
||||
dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number,
|
||||
codec_addr);
|
||||
dev_set_drvdata(&codec->dev, codec); /* for sysfs */
|
||||
dev = hda_codec_dev(codec);
|
||||
device_initialize(dev);
|
||||
dev->parent = bus->card->dev;
|
||||
dev->bus = &snd_hda_bus_type;
|
||||
dev->release = snd_hda_codec_dev_release;
|
||||
dev->groups = snd_hda_dev_attr_groups;
|
||||
dev_set_name(dev, "hdaudioC%dD%d", bus->card->number, codec_addr);
|
||||
dev_set_drvdata(dev, codec); /* for sysfs */
|
||||
device_enable_async_suspend(dev);
|
||||
|
||||
codec->bus = bus;
|
||||
codec->addr = codec_addr;
|
||||
@ -1460,13 +1261,13 @@ int snd_hda_codec_new(struct hda_bus *bus,
|
||||
codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
spin_lock_init(&codec->power_lock);
|
||||
INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
|
||||
/* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
|
||||
* the caller has to power down appropriatley after initialization
|
||||
* phase.
|
||||
* it's powered down later in snd_hda_codec_dev_register().
|
||||
*/
|
||||
hda_keep_power_on(codec);
|
||||
set_bit(codec->addr, &bus->codec_powered);
|
||||
pm_runtime_set_active(hda_codec_dev(codec));
|
||||
pm_runtime_get_noresume(hda_codec_dev(codec));
|
||||
codec->power_jiffies = jiffies;
|
||||
#endif
|
||||
|
||||
snd_hda_sysfs_init(codec);
|
||||
@ -1526,11 +1327,6 @@ int snd_hda_codec_new(struct hda_bus *bus,
|
||||
#endif
|
||||
codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
|
||||
AC_PWRST_EPSS);
|
||||
#ifdef CONFIG_PM
|
||||
if (!codec->d3_stop_clk || !codec->epss)
|
||||
bus->power_keep_link_on = 1;
|
||||
#endif
|
||||
|
||||
|
||||
/* power-up all before initialization */
|
||||
hda_set_power_state(codec, AC_PWRST_D0);
|
||||
@ -1587,92 +1383,6 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets);
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
|
||||
/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */
|
||||
static bool is_likely_hdmi_codec(struct hda_codec *codec)
|
||||
{
|
||||
hda_nid_t nid = codec->start_nid;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
switch (get_wcaps_type(wcaps)) {
|
||||
case AC_WID_AUD_IN:
|
||||
return false; /* HDMI parser supports only HDMI out */
|
||||
case AC_WID_AUD_OUT:
|
||||
if (!(wcaps & AC_WCAP_DIGITAL))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
/* no HDMI codec parser support */
|
||||
#define is_likely_hdmi_codec(codec) false
|
||||
#endif /* CONFIG_SND_HDA_CODEC_HDMI */
|
||||
|
||||
/**
|
||||
* snd_hda_codec_configure - (Re-)configure the HD-audio codec
|
||||
* @codec: the HDA codec
|
||||
*
|
||||
* Start parsing of the given codec tree and (re-)initialize the whole
|
||||
* patch instance.
|
||||
*
|
||||
* Returns 0 if successful or a negative error code.
|
||||
*/
|
||||
int snd_hda_codec_configure(struct hda_codec *codec)
|
||||
{
|
||||
int (*patch)(struct hda_codec *) = NULL;
|
||||
int err;
|
||||
|
||||
codec->preset = find_codec_preset(codec);
|
||||
if (!codec->vendor_name || !codec->chip_name) {
|
||||
err = get_codec_name(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!is_generic_config(codec) && codec->preset)
|
||||
patch = codec->preset->patch;
|
||||
if (!patch) {
|
||||
unload_parser(codec); /* to be sure */
|
||||
if (is_likely_hdmi_codec(codec)) {
|
||||
#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI)
|
||||
patch = load_parser(codec, snd_hda_parse_hdmi_codec);
|
||||
#elif IS_BUILTIN(CONFIG_SND_HDA_CODEC_HDMI)
|
||||
patch = snd_hda_parse_hdmi_codec;
|
||||
#endif
|
||||
}
|
||||
if (!patch) {
|
||||
#if IS_MODULE(CONFIG_SND_HDA_GENERIC)
|
||||
patch = load_parser(codec, snd_hda_parse_generic_codec);
|
||||
#elif IS_BUILTIN(CONFIG_SND_HDA_GENERIC)
|
||||
patch = snd_hda_parse_generic_codec;
|
||||
#endif
|
||||
}
|
||||
if (!patch) {
|
||||
codec_err(codec, "No codec parser is available\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
err = patch(codec);
|
||||
if (err < 0) {
|
||||
unload_parser(codec);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* audio codec should override the mixer name */
|
||||
if (codec->afg || !*codec->bus->card->mixername)
|
||||
snprintf(codec->bus->card->mixername,
|
||||
sizeof(codec->bus->card->mixername),
|
||||
"%s %s", codec->vendor_name, codec->chip_name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
|
||||
|
||||
/* update the stream-id if changed */
|
||||
static void update_pcm_stream_id(struct hda_codec *codec,
|
||||
struct hda_cvt_setup *p, hda_nid_t nid,
|
||||
@ -2725,10 +2435,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
|
||||
|
||||
/* OK, let it free */
|
||||
cancel_delayed_work_sync(&codec->jackpoll_work);
|
||||
#ifdef CONFIG_PM
|
||||
cancel_delayed_work_sync(&codec->power_work);
|
||||
flush_workqueue(bus->workq);
|
||||
#endif
|
||||
snd_hda_ctls_clear(codec);
|
||||
/* release PCMs */
|
||||
for (i = 0; i < codec->num_pcms; i++) {
|
||||
@ -2739,8 +2446,9 @@ int snd_hda_codec_reset(struct hda_codec *codec)
|
||||
}
|
||||
}
|
||||
snd_hda_detach_beep_device(codec);
|
||||
if (codec->patch_ops.free)
|
||||
codec->patch_ops.free(codec);
|
||||
if (device_is_registered(hda_codec_dev(codec)))
|
||||
device_del(hda_codec_dev(codec));
|
||||
|
||||
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
|
||||
snd_hda_jack_tbl_clear(codec);
|
||||
codec->proc_widget_hook = NULL;
|
||||
@ -2759,9 +2467,6 @@ int snd_hda_codec_reset(struct hda_codec *codec)
|
||||
codec->preset = NULL;
|
||||
codec->slave_dig_outs = NULL;
|
||||
codec->spdif_status_reset = 0;
|
||||
unload_parser(codec);
|
||||
module_put(codec->owner);
|
||||
codec->owner = NULL;
|
||||
|
||||
/* allow device access again */
|
||||
snd_hda_unlock_devices(bus);
|
||||
@ -4167,31 +3872,40 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/* update the power on/off account with the current jiffies */
|
||||
static void update_power_acct(struct hda_codec *codec, bool on)
|
||||
{
|
||||
unsigned long delta = jiffies - codec->power_jiffies;
|
||||
|
||||
if (on)
|
||||
codec->power_on_acct += delta;
|
||||
else
|
||||
codec->power_off_acct += delta;
|
||||
codec->power_jiffies += delta;
|
||||
}
|
||||
|
||||
void snd_hda_update_power_acct(struct hda_codec *codec)
|
||||
{
|
||||
update_power_acct(codec, hda_codec_is_power_on(codec));
|
||||
}
|
||||
|
||||
/*
|
||||
* call suspend and power-down; used both from PM and power-save
|
||||
* this function returns the power state in the end
|
||||
*/
|
||||
static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
|
||||
static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int state;
|
||||
|
||||
codec->in_pm = 1;
|
||||
atomic_inc(&codec->in_pm);
|
||||
|
||||
if (codec->patch_ops.suspend)
|
||||
codec->patch_ops.suspend(codec);
|
||||
hda_cleanup_all_streams(codec);
|
||||
state = hda_set_power_state(codec, AC_PWRST_D3);
|
||||
/* Cancel delayed work if we aren't currently running from it. */
|
||||
if (!in_wq)
|
||||
cancel_delayed_work_sync(&codec->power_work);
|
||||
spin_lock(&codec->power_lock);
|
||||
snd_hda_update_power_acct(codec);
|
||||
trace_hda_power_down(codec);
|
||||
codec->power_on = 0;
|
||||
codec->power_transition = 0;
|
||||
codec->power_jiffies = jiffies;
|
||||
spin_unlock(&codec->power_lock);
|
||||
codec->in_pm = 0;
|
||||
update_power_acct(codec, true);
|
||||
atomic_dec(&codec->in_pm);
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -4216,14 +3930,13 @@ static void hda_mark_cmd_cache_dirty(struct hda_codec *codec)
|
||||
*/
|
||||
static void hda_call_codec_resume(struct hda_codec *codec)
|
||||
{
|
||||
codec->in_pm = 1;
|
||||
atomic_inc(&codec->in_pm);
|
||||
|
||||
trace_hda_power_up(codec);
|
||||
hda_mark_cmd_cache_dirty(codec);
|
||||
|
||||
/* set as if powered on for avoiding re-entering the resume
|
||||
* in the resume / power-save sequence
|
||||
*/
|
||||
hda_keep_power_on(codec);
|
||||
codec->power_jiffies = jiffies;
|
||||
|
||||
hda_set_power_state(codec, AC_PWRST_D0);
|
||||
restore_shutup_pins(codec);
|
||||
hda_exec_init_verbs(codec);
|
||||
@ -4241,12 +3954,42 @@ static void hda_call_codec_resume(struct hda_codec *codec)
|
||||
hda_jackpoll_work(&codec->jackpoll_work.work);
|
||||
else
|
||||
snd_hda_jack_report_sync(codec);
|
||||
atomic_dec(&codec->in_pm);
|
||||
}
|
||||
|
||||
codec->in_pm = 0;
|
||||
snd_hda_power_down(codec); /* flag down before returning */
|
||||
static int hda_codec_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(dev);
|
||||
unsigned int state;
|
||||
int i;
|
||||
|
||||
cancel_delayed_work_sync(&codec->jackpoll_work);
|
||||
for (i = 0; i < codec->num_pcms; i++)
|
||||
snd_pcm_suspend_all(codec->pcm_info[i].pcm);
|
||||
state = hda_call_codec_suspend(codec);
|
||||
if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK))
|
||||
clear_bit(codec->addr, &codec->bus->codec_powered);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hda_codec_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(dev);
|
||||
|
||||
set_bit(codec->addr, &codec->bus->codec_powered);
|
||||
hda_call_codec_resume(codec);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/* referred in hda_bind.c */
|
||||
const struct dev_pm_ops hda_codec_driver_pm = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_hda_build_controls - build mixer controls
|
||||
@ -4984,127 +4727,70 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
|
||||
EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void hda_power_work(struct work_struct *work)
|
||||
{
|
||||
struct hda_codec *codec =
|
||||
container_of(work, struct hda_codec, power_work.work);
|
||||
struct hda_bus *bus = codec->bus;
|
||||
unsigned int state;
|
||||
|
||||
spin_lock(&codec->power_lock);
|
||||
if (codec->power_transition > 0) { /* during power-up sequence? */
|
||||
spin_unlock(&codec->power_lock);
|
||||
return;
|
||||
}
|
||||
if (!codec->power_on || codec->power_count) {
|
||||
codec->power_transition = 0;
|
||||
spin_unlock(&codec->power_lock);
|
||||
return;
|
||||
}
|
||||
spin_unlock(&codec->power_lock);
|
||||
|
||||
state = hda_call_codec_suspend(codec, true);
|
||||
if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK))
|
||||
hda_call_pm_notify(codec, false);
|
||||
}
|
||||
|
||||
static void hda_keep_power_on(struct hda_codec *codec)
|
||||
{
|
||||
spin_lock(&codec->power_lock);
|
||||
codec->power_count++;
|
||||
codec->power_on = 1;
|
||||
codec->power_jiffies = jiffies;
|
||||
spin_unlock(&codec->power_lock);
|
||||
hda_call_pm_notify(codec, true);
|
||||
}
|
||||
|
||||
/* update the power on/off account with the current jiffies */
|
||||
void snd_hda_update_power_acct(struct hda_codec *codec)
|
||||
{
|
||||
unsigned long delta = jiffies - codec->power_jiffies;
|
||||
if (codec->power_on)
|
||||
codec->power_on_acct += delta;
|
||||
else
|
||||
codec->power_off_acct += delta;
|
||||
codec->power_jiffies += delta;
|
||||
}
|
||||
|
||||
/* Transition to powered up, if wait_power_down then wait for a pending
|
||||
* transition to D3 to complete. A pending D3 transition is indicated
|
||||
* with power_transition == -1. */
|
||||
/* call this with codec->power_lock held! */
|
||||
static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
|
||||
{
|
||||
/* Return if power_on or transitioning to power_on, unless currently
|
||||
* powering down. */
|
||||
if ((codec->power_on || codec->power_transition > 0) &&
|
||||
!(wait_power_down && codec->power_transition < 0))
|
||||
return;
|
||||
spin_unlock(&codec->power_lock);
|
||||
|
||||
cancel_delayed_work_sync(&codec->power_work);
|
||||
|
||||
spin_lock(&codec->power_lock);
|
||||
/* If the power down delayed work was cancelled above before starting,
|
||||
* then there is no need to go through power up here.
|
||||
/**
|
||||
* snd_hda_power_up - Power-up the codec
|
||||
* @codec: HD-audio codec
|
||||
*
|
||||
* Increment the usage counter and resume the device if not done yet.
|
||||
*/
|
||||
if (codec->power_on) {
|
||||
if (codec->power_transition < 0)
|
||||
codec->power_transition = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
trace_hda_power_up(codec);
|
||||
snd_hda_update_power_acct(codec);
|
||||
codec->power_on = 1;
|
||||
codec->power_jiffies = jiffies;
|
||||
codec->power_transition = 1; /* avoid reentrance */
|
||||
spin_unlock(&codec->power_lock);
|
||||
|
||||
hda_call_codec_resume(codec);
|
||||
|
||||
spin_lock(&codec->power_lock);
|
||||
codec->power_transition = 0;
|
||||
}
|
||||
|
||||
#define power_save(codec) \
|
||||
((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
|
||||
|
||||
/* Transition to powered down */
|
||||
static void __snd_hda_power_down(struct hda_codec *codec)
|
||||
void snd_hda_power_up(struct hda_codec *codec)
|
||||
{
|
||||
if (!codec->power_on || codec->power_count || codec->power_transition)
|
||||
return;
|
||||
struct device *dev = hda_codec_dev(codec);
|
||||
|
||||
if (power_save(codec)) {
|
||||
codec->power_transition = -1; /* avoid reentrance */
|
||||
queue_delayed_work(codec->bus->workq, &codec->power_work,
|
||||
msecs_to_jiffies(power_save(codec) * 1000));
|
||||
if (codec_in_pm(codec))
|
||||
return;
|
||||
pm_runtime_get_sync(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_power_up);
|
||||
|
||||
/**
|
||||
* snd_hda_power_down - Power-down the codec
|
||||
* @codec: HD-audio codec
|
||||
*
|
||||
* Decrement the usage counter and schedules the autosuspend if none used.
|
||||
*/
|
||||
void snd_hda_power_down(struct hda_codec *codec)
|
||||
{
|
||||
struct device *dev = hda_codec_dev(codec);
|
||||
|
||||
if (codec_in_pm(codec))
|
||||
return;
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_power_down);
|
||||
|
||||
static void codec_set_power_save(struct hda_codec *codec, int delay)
|
||||
{
|
||||
struct device *dev = hda_codec_dev(codec);
|
||||
|
||||
if (delay > 0) {
|
||||
pm_runtime_set_autosuspend_delay(dev, delay);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_allow(dev);
|
||||
if (!pm_runtime_suspended(dev))
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
} else {
|
||||
pm_runtime_dont_use_autosuspend(dev);
|
||||
pm_runtime_forbid(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_power_save - Power-up/down/sync the codec
|
||||
* @codec: HD-audio codec
|
||||
* @delta: the counter delta to change
|
||||
* @d3wait: sync for D3 transition complete
|
||||
* snd_hda_set_power_save - reprogram autosuspend for the given delay
|
||||
* @bus: HD-audio bus
|
||||
* @delay: autosuspend delay in msec, 0 = off
|
||||
*
|
||||
* Change the power-up counter via @delta, and power up or down the hardware
|
||||
* appropriately. For the power-down, queue to the delayed action.
|
||||
* Passing zero to @delta means to synchronize the power state.
|
||||
* Synchronize the runtime PM autosuspend state from the power_save option.
|
||||
*/
|
||||
void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait)
|
||||
void snd_hda_set_power_save(struct hda_bus *bus, int delay)
|
||||
{
|
||||
spin_lock(&codec->power_lock);
|
||||
codec->power_count += delta;
|
||||
trace_hda_power_count(codec);
|
||||
if (delta > 0)
|
||||
__snd_hda_power_up(codec, d3wait);
|
||||
else
|
||||
__snd_hda_power_down(codec);
|
||||
spin_unlock(&codec->power_lock);
|
||||
struct hda_codec *c;
|
||||
|
||||
list_for_each_entry(c, &bus->codec_list, list)
|
||||
codec_set_power_save(c, delay);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_power_save);
|
||||
EXPORT_SYMBOL_GPL(snd_hda_set_power_save);
|
||||
|
||||
/**
|
||||
* snd_hda_check_amp_list_power - Check the amp list and update the power
|
||||
@ -5157,88 +4843,6 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
|
||||
EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Channel mode helper
|
||||
*/
|
||||
|
||||
/**
|
||||
* snd_hda_ch_mode_info - Info callback helper for the channel mode enum
|
||||
* @codec: the HDA codec
|
||||
* @uinfo: pointer to get/store the data
|
||||
* @chmode: channel mode array
|
||||
* @num_chmodes: channel mode array size
|
||||
*/
|
||||
int snd_hda_ch_mode_info(struct hda_codec *codec,
|
||||
struct snd_ctl_elem_info *uinfo,
|
||||
const struct hda_channel_mode *chmode,
|
||||
int num_chmodes)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.enumerated.items = num_chmodes;
|
||||
if (uinfo->value.enumerated.item >= num_chmodes)
|
||||
uinfo->value.enumerated.item = num_chmodes - 1;
|
||||
sprintf(uinfo->value.enumerated.name, "%dch",
|
||||
chmode[uinfo->value.enumerated.item].channels);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info);
|
||||
|
||||
/**
|
||||
* snd_hda_ch_mode_get - Get callback helper for the channel mode enum
|
||||
* @codec: the HDA codec
|
||||
* @ucontrol: pointer to get/store the data
|
||||
* @chmode: channel mode array
|
||||
* @num_chmodes: channel mode array size
|
||||
* @max_channels: max number of channels
|
||||
*/
|
||||
int snd_hda_ch_mode_get(struct hda_codec *codec,
|
||||
struct snd_ctl_elem_value *ucontrol,
|
||||
const struct hda_channel_mode *chmode,
|
||||
int num_chmodes,
|
||||
int max_channels)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_chmodes; i++) {
|
||||
if (max_channels == chmode[i].channels) {
|
||||
ucontrol->value.enumerated.item[0] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get);
|
||||
|
||||
/**
|
||||
* snd_hda_ch_mode_put - Put callback helper for the channel mode enum
|
||||
* @codec: the HDA codec
|
||||
* @ucontrol: pointer to get/store the data
|
||||
* @chmode: channel mode array
|
||||
* @num_chmodes: channel mode array size
|
||||
* @max_channelsp: pointer to store the max channels
|
||||
*/
|
||||
int snd_hda_ch_mode_put(struct hda_codec *codec,
|
||||
struct snd_ctl_elem_value *ucontrol,
|
||||
const struct hda_channel_mode *chmode,
|
||||
int num_chmodes,
|
||||
int *max_channelsp)
|
||||
{
|
||||
unsigned int mode;
|
||||
|
||||
mode = ucontrol->value.enumerated.item[0];
|
||||
if (mode >= num_chmodes)
|
||||
return -EINVAL;
|
||||
if (*max_channelsp == chmode[mode].channels)
|
||||
return 0;
|
||||
/* change the current channel setting */
|
||||
*max_channelsp = chmode[mode].channels;
|
||||
if (chmode[mode].sequence)
|
||||
snd_hda_sequence_write_cache(codec, chmode[mode].sequence);
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put);
|
||||
|
||||
/*
|
||||
* input MUX helper
|
||||
*/
|
||||
@ -5780,77 +5384,26 @@ int snd_hda_add_imux_item(struct hda_codec *codec,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_add_imux_item);
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* power management
|
||||
*/
|
||||
|
||||
|
||||
static void hda_async_suspend(void *data, async_cookie_t cookie)
|
||||
{
|
||||
hda_call_codec_suspend(data, false);
|
||||
}
|
||||
|
||||
static void hda_async_resume(void *data, async_cookie_t cookie)
|
||||
{
|
||||
hda_call_codec_resume(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_suspend - suspend the codecs
|
||||
* @bus: the HDA bus
|
||||
*
|
||||
* Returns 0 if successful.
|
||||
* snd_hda_bus_reset - Reset the bus
|
||||
* @bus: HD-audio bus
|
||||
*/
|
||||
int snd_hda_suspend(struct hda_bus *bus)
|
||||
void snd_hda_bus_reset(struct hda_bus *bus)
|
||||
{
|
||||
struct hda_codec *codec;
|
||||
ASYNC_DOMAIN_EXCLUSIVE(domain);
|
||||
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
/* FIXME: maybe a better way needed for forced reset */
|
||||
cancel_delayed_work_sync(&codec->jackpoll_work);
|
||||
#ifdef CONFIG_PM
|
||||
if (hda_codec_is_power_on(codec)) {
|
||||
if (bus->num_codecs > 1)
|
||||
async_schedule_domain(hda_async_suspend, codec,
|
||||
&domain);
|
||||
else
|
||||
hda_call_codec_suspend(codec, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (bus->num_codecs > 1)
|
||||
async_synchronize_full_domain(&domain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_suspend);
|
||||
|
||||
/**
|
||||
* snd_hda_resume - resume the codecs
|
||||
* @bus: the HDA bus
|
||||
*
|
||||
* Returns 0 if successful.
|
||||
*/
|
||||
int snd_hda_resume(struct hda_bus *bus)
|
||||
{
|
||||
struct hda_codec *codec;
|
||||
ASYNC_DOMAIN_EXCLUSIVE(domain);
|
||||
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
if (bus->num_codecs > 1)
|
||||
async_schedule_domain(hda_async_resume, codec, &domain);
|
||||
else
|
||||
hda_call_codec_suspend(codec);
|
||||
hda_call_codec_resume(codec);
|
||||
}
|
||||
|
||||
if (bus->num_codecs > 1)
|
||||
async_synchronize_full_domain(&domain);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_resume);
|
||||
#endif /* CONFIG_PM */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_bus_reset);
|
||||
|
||||
/*
|
||||
* generic arrays
|
||||
|
@ -83,10 +83,6 @@ struct hda_bus_ops {
|
||||
struct hda_pcm *pcm);
|
||||
/* reset bus for retry verb */
|
||||
void (*bus_reset)(struct hda_bus *bus);
|
||||
#ifdef CONFIG_PM
|
||||
/* notify power-up/down from codec to controller */
|
||||
void (*pm_notify)(struct hda_bus *bus, bool power_up);
|
||||
#endif
|
||||
#ifdef CONFIG_SND_HDA_DSP_LOADER
|
||||
/* prepare DSP transfer */
|
||||
int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format,
|
||||
@ -122,7 +118,6 @@ struct hda_bus {
|
||||
void *private_data;
|
||||
struct pci_dev *pci;
|
||||
const char *modelname;
|
||||
int *power_save;
|
||||
struct hda_bus_ops ops;
|
||||
|
||||
/* codec linked list */
|
||||
@ -151,10 +146,10 @@ struct hda_bus {
|
||||
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 power_keep_link_on:1; /* don't power off HDA link */
|
||||
unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
|
||||
|
||||
int primary_dig_out_type; /* primary digital out PCM type */
|
||||
unsigned long codec_powered; /* bit flags of powered codecs */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -174,15 +169,22 @@ struct hda_codec_preset {
|
||||
int (*patch)(struct hda_codec *codec);
|
||||
};
|
||||
|
||||
struct hda_codec_preset_list {
|
||||
#define HDA_CODEC_ID_GENERIC_HDMI 0x00000101
|
||||
#define HDA_CODEC_ID_GENERIC 0x00000201
|
||||
|
||||
struct hda_codec_driver {
|
||||
struct device_driver driver;
|
||||
const struct hda_codec_preset *preset;
|
||||
struct module *owner;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/* initial hook */
|
||||
int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset);
|
||||
int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset);
|
||||
int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
|
||||
struct module *owner);
|
||||
#define hda_codec_driver_register(drv) \
|
||||
__hda_codec_driver_register(drv, KBUILD_MODNAME, THIS_MODULE)
|
||||
void hda_codec_driver_unregister(struct hda_codec_driver *drv);
|
||||
#define module_hda_codec_driver(drv) \
|
||||
module_driver(drv, hda_codec_driver_register, \
|
||||
hda_codec_driver_unregister)
|
||||
|
||||
/* ops set by the preset patch */
|
||||
struct hda_codec_ops {
|
||||
@ -286,11 +288,10 @@ struct hda_codec {
|
||||
u32 vendor_id;
|
||||
u32 subsystem_id;
|
||||
u32 revision_id;
|
||||
u32 probe_id; /* overridden id for probing */
|
||||
|
||||
/* detected preset */
|
||||
const struct hda_codec_preset *preset;
|
||||
struct module *owner;
|
||||
int (*parser)(struct hda_codec *codec);
|
||||
const char *vendor_name; /* codec vendor name */
|
||||
const char *chip_name; /* codec chip name */
|
||||
const char *modelname; /* model name for preset */
|
||||
@ -366,17 +367,11 @@ 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 */
|
||||
#ifdef CONFIG_PM
|
||||
unsigned int power_on :1; /* current (global) power-state */
|
||||
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
|
||||
unsigned int pm_up_notified:1; /* PM notified to controller */
|
||||
unsigned int in_pm:1; /* suspend/resume being performed */
|
||||
int power_transition; /* power-state in transition */
|
||||
int power_count; /* current (global) power refcount */
|
||||
struct delayed_work power_work; /* delayed task for powerdown */
|
||||
atomic_t in_pm; /* suspend/resume being performed */
|
||||
unsigned long power_on_acct;
|
||||
unsigned long power_off_acct;
|
||||
unsigned long power_jiffies;
|
||||
spinlock_t power_lock;
|
||||
#endif
|
||||
|
||||
/* filter the requested power state per nid */
|
||||
@ -408,6 +403,11 @@ struct hda_codec {
|
||||
struct snd_array verbs;
|
||||
};
|
||||
|
||||
#define dev_to_hda_codec(_dev) container_of(_dev, struct hda_codec, dev)
|
||||
#define hda_codec_dev(_dev) (&(_dev)->dev)
|
||||
|
||||
extern struct bus_type snd_hda_bus_type;
|
||||
|
||||
/* direction */
|
||||
enum {
|
||||
HDA_INPUT, HDA_OUTPUT
|
||||
@ -556,14 +556,12 @@ 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);
|
||||
|
||||
/*
|
||||
* power management
|
||||
*/
|
||||
#ifdef CONFIG_PM
|
||||
int snd_hda_suspend(struct hda_bus *bus);
|
||||
int snd_hda_resume(struct hda_bus *bus);
|
||||
#endif
|
||||
extern const struct dev_pm_ops hda_codec_driver_pm;
|
||||
|
||||
static inline
|
||||
int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
|
||||
@ -586,64 +584,16 @@ const char *snd_hda_get_jack_location(u32 cfg);
|
||||
* power saving
|
||||
*/
|
||||
#ifdef CONFIG_PM
|
||||
void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait);
|
||||
void snd_hda_power_up(struct hda_codec *codec);
|
||||
void snd_hda_power_down(struct hda_codec *codec);
|
||||
void snd_hda_set_power_save(struct hda_bus *bus, int delay);
|
||||
void snd_hda_update_power_acct(struct hda_codec *codec);
|
||||
#else
|
||||
static inline void snd_hda_power_save(struct hda_codec *codec, int delta,
|
||||
bool d3wait) {}
|
||||
static inline void snd_hda_power_up(struct hda_codec *codec) {}
|
||||
static inline void snd_hda_power_down(struct hda_codec *codec) {}
|
||||
static inline void snd_hda_set_power_save(struct hda_bus *bus, int delay) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* snd_hda_power_up - Power-up the codec
|
||||
* @codec: HD-audio codec
|
||||
*
|
||||
* Increment the power-up counter and power up the hardware really when
|
||||
* not turned on yet.
|
||||
*/
|
||||
static inline void snd_hda_power_up(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_power_save(codec, 1, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
|
||||
* D3 transition to complete. This differs from snd_hda_power_up() when
|
||||
* power_transition == -1. snd_hda_power_up sees this case as a nop,
|
||||
* snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
|
||||
* back up.
|
||||
* @codec: HD-audio codec
|
||||
*
|
||||
* Cancel any power down operation hapenning on the work queue, then power up.
|
||||
*/
|
||||
static inline void snd_hda_power_up_d3wait(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_power_save(codec, 1, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_power_down - Power-down the codec
|
||||
* @codec: HD-audio codec
|
||||
*
|
||||
* Decrement the power-up counter and schedules the power-off work if
|
||||
* the counter rearches to zero.
|
||||
*/
|
||||
static inline void snd_hda_power_down(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_power_save(codec, -1, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_power_sync - Synchronize the power-save status
|
||||
* @codec: HD-audio codec
|
||||
*
|
||||
* Synchronize the actual power state with the power account;
|
||||
* called when power_save parameter is changed
|
||||
*/
|
||||
static inline void snd_hda_power_sync(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_power_save(codec, 0, false);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||
/*
|
||||
* patch firmware
|
||||
|
@ -258,11 +258,18 @@ static void azx_timecounter_init(struct snd_pcm_substream *substream,
|
||||
tc->cycle_last = last;
|
||||
}
|
||||
|
||||
static inline struct hda_pcm_stream *
|
||||
to_hda_pcm_stream(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||
return &apcm->info->stream[substream->stream];
|
||||
}
|
||||
|
||||
static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
|
||||
u64 nsec)
|
||||
{
|
||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
||||
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
|
||||
u64 codec_frames, codec_nsecs;
|
||||
|
||||
if (!hinfo->ops.get_delay)
|
||||
@ -398,7 +405,7 @@ static int azx_setup_periods(struct azx *chip,
|
||||
static int azx_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
||||
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;
|
||||
@ -440,7 +447,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||||
struct azx *chip = apcm->chip;
|
||||
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
||||
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
|
||||
int err;
|
||||
|
||||
/* reset BDL address */
|
||||
@ -467,7 +474,7 @@ static int azx_pcm_prepare(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);
|
||||
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
||||
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;
|
||||
int err;
|
||||
@ -707,7 +714,7 @@ unsigned int azx_get_position(struct azx *chip,
|
||||
|
||||
if (substream->runtime) {
|
||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||
struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
|
||||
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
|
||||
|
||||
if (chip->get_delay[stream])
|
||||
delay += chip->get_delay[stream](chip, azx_dev, pos);
|
||||
@ -790,7 +797,7 @@ static struct snd_pcm_hardware azx_pcm_hw = {
|
||||
static int azx_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
||||
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
|
||||
struct azx *chip = apcm->chip;
|
||||
struct azx_dev *azx_dev;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
@ -836,7 +843,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
||||
buff_step);
|
||||
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
|
||||
buff_step);
|
||||
snd_hda_power_up_d3wait(apcm->codec);
|
||||
snd_hda_power_up(apcm->codec);
|
||||
err = hinfo->ops.open(hinfo, apcm->codec, substream);
|
||||
if (err < 0) {
|
||||
azx_release_device(azx_dev);
|
||||
@ -904,6 +911,7 @@ static void azx_pcm_free(struct snd_pcm *pcm)
|
||||
struct azx_pcm *apcm = pcm->private_data;
|
||||
if (apcm) {
|
||||
list_del(&apcm->list);
|
||||
apcm->info->pcm = NULL;
|
||||
kfree(apcm);
|
||||
}
|
||||
}
|
||||
@ -940,6 +948,7 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
|
||||
apcm->chip = chip;
|
||||
apcm->pcm = pcm;
|
||||
apcm->codec = codec;
|
||||
apcm->info = cpcm;
|
||||
pcm->private_data = apcm;
|
||||
pcm->private_free = azx_pcm_free;
|
||||
if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
|
||||
@ -947,7 +956,6 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
|
||||
list_add_tail(&apcm->list, &chip->pcm_list);
|
||||
cpcm->pcm = pcm;
|
||||
for (s = 0; s < 2; s++) {
|
||||
apcm->hinfo[s] = &cpcm->stream[s];
|
||||
if (cpcm->stream[s].substreams)
|
||||
snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
|
||||
}
|
||||
@ -958,9 +966,6 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
|
||||
chip->card->dev,
|
||||
size, MAX_PREALLOC_SIZE);
|
||||
/* link to codec */
|
||||
for (s = 0; s < 2; s++)
|
||||
pcm->streams[s].dev.parent = &codec->dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1778,34 +1783,11 @@ static void azx_bus_reset(struct hda_bus *bus)
|
||||
bus->in_reset = 1;
|
||||
azx_stop_chip(chip);
|
||||
azx_init_chip(chip, true);
|
||||
#ifdef CONFIG_PM
|
||||
if (chip->initialized) {
|
||||
struct azx_pcm *p;
|
||||
list_for_each_entry(p, &chip->pcm_list, list)
|
||||
snd_pcm_suspend_all(p->pcm);
|
||||
snd_hda_suspend(chip->bus);
|
||||
snd_hda_resume(chip->bus);
|
||||
}
|
||||
#endif
|
||||
if (chip->initialized)
|
||||
snd_hda_bus_reset(chip->bus);
|
||||
bus->in_reset = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/* power-up/down the controller */
|
||||
static void azx_power_notify(struct hda_bus *bus, bool power_up)
|
||||
{
|
||||
struct azx *chip = bus->private_data;
|
||||
|
||||
if (!azx_has_pm_runtime(chip))
|
||||
return;
|
||||
|
||||
if (power_up)
|
||||
pm_runtime_get_sync(chip->card->dev);
|
||||
else
|
||||
pm_runtime_put_sync(chip->card->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int get_jackpoll_interval(struct azx *chip)
|
||||
{
|
||||
int i;
|
||||
@ -1832,9 +1814,6 @@ static struct hda_bus_ops bus_ops = {
|
||||
.get_response = azx_get_response,
|
||||
.attach_pcm = azx_attach_pcm_stream,
|
||||
.bus_reset = azx_bus_reset,
|
||||
#ifdef CONFIG_PM
|
||||
.pm_notify = azx_power_notify,
|
||||
#endif
|
||||
#ifdef CONFIG_SND_HDA_DSP_LOADER
|
||||
.load_dsp_prepare = azx_load_dsp_prepare,
|
||||
.load_dsp_trigger = azx_load_dsp_trigger,
|
||||
@ -1843,7 +1822,7 @@ static struct hda_bus_ops bus_ops = {
|
||||
};
|
||||
|
||||
/* HD-audio bus initialization */
|
||||
int azx_bus_create(struct azx *chip, const char *model, int *power_save_to)
|
||||
int azx_bus_create(struct azx *chip, const char *model)
|
||||
{
|
||||
struct hda_bus *bus;
|
||||
int err;
|
||||
@ -1857,9 +1836,6 @@ int azx_bus_create(struct azx *chip, const char *model, int *power_save_to)
|
||||
bus->pci = chip->pci;
|
||||
bus->modelname = model;
|
||||
bus->ops = bus_ops;
|
||||
#ifdef CONFIG_PM
|
||||
bus->power_save = power_save_to;
|
||||
#endif
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
|
||||
dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
|
||||
|
@ -283,7 +283,7 @@ struct azx_pcm {
|
||||
struct azx *chip;
|
||||
struct snd_pcm *pcm;
|
||||
struct hda_codec *codec;
|
||||
struct hda_pcm_stream *hinfo[2];
|
||||
struct hda_pcm *info;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
@ -432,7 +432,7 @@ void azx_enter_link_reset(struct azx *chip);
|
||||
irqreturn_t azx_interrupt(int irq, void *dev_id);
|
||||
|
||||
/* Codec interface */
|
||||
int azx_bus_create(struct azx *chip, const char *model, int *power_save_to);
|
||||
int azx_bus_create(struct azx *chip, const char *model);
|
||||
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);
|
||||
|
@ -5524,13 +5524,11 @@ static const struct hda_codec_ops generic_patch_ops = {
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* snd_hda_parse_generic_codec - Generic codec parser
|
||||
* @codec: the HDA codec
|
||||
*
|
||||
* This should be called from the HDA codec core.
|
||||
*/
|
||||
int snd_hda_parse_generic_codec(struct hda_codec *codec)
|
||||
static int snd_hda_parse_generic_codec(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_gen_spec *spec;
|
||||
int err;
|
||||
@ -5556,7 +5554,17 @@ error:
|
||||
snd_hda_gen_free(codec);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_parse_generic_codec);
|
||||
|
||||
static const struct hda_codec_preset snd_hda_preset_generic[] = {
|
||||
{ .id = HDA_CODEC_ID_GENERIC, .patch = snd_hda_parse_generic_codec },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
static struct hda_codec_driver generic_driver = {
|
||||
.preset = snd_hda_preset_generic,
|
||||
};
|
||||
|
||||
module_hda_codec_driver(generic_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Generic HD-audio codec parser");
|
||||
|
@ -116,9 +116,6 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
|
||||
hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
|
||||
#endif
|
||||
|
||||
/* link to codec */
|
||||
hwdep->dev.parent = &codec->dev;
|
||||
|
||||
/* for sysfs */
|
||||
hwdep->dev.groups = snd_hda_dev_attr_groups;
|
||||
dev_set_drvdata(&hwdep->dev, codec);
|
||||
|
@ -173,7 +173,6 @@ static struct kernel_param_ops param_ops_xint = {
|
||||
#define param_check_xint param_check_int
|
||||
|
||||
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
|
||||
static int *power_save_addr = &power_save;
|
||||
module_param(power_save, xint, 0644);
|
||||
MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
|
||||
"(in second, 0 = disable).");
|
||||
@ -186,7 +185,7 @@ static bool power_save_controller = 1;
|
||||
module_param(power_save_controller, bool, 0644);
|
||||
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
|
||||
#else
|
||||
static int *power_save_addr;
|
||||
#define power_save 0
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static int align_buffer_size = -1;
|
||||
@ -740,7 +739,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
struct hda_intel *hda;
|
||||
struct azx *chip;
|
||||
struct hda_codec *c;
|
||||
int prev = power_save;
|
||||
int ret = param_set_int(val, kp);
|
||||
|
||||
@ -752,8 +750,7 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
|
||||
chip = &hda->chip;
|
||||
if (!chip->bus || chip->disabled)
|
||||
continue;
|
||||
list_for_each_entry(c, &chip->bus->codec_list, list)
|
||||
snd_hda_power_sync(c);
|
||||
snd_hda_set_power_save(chip->bus, power_save * 1000);
|
||||
}
|
||||
mutex_unlock(&card_list_lock);
|
||||
return 0;
|
||||
@ -772,7 +769,6 @@ static int azx_suspend(struct device *dev)
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip;
|
||||
struct hda_intel *hda;
|
||||
struct azx_pcm *p;
|
||||
|
||||
if (!card)
|
||||
return 0;
|
||||
@ -784,10 +780,6 @@ static int azx_suspend(struct device *dev)
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
azx_clear_irq_pending(chip);
|
||||
list_for_each_entry(p, &chip->pcm_list, list)
|
||||
snd_pcm_suspend_all(p->pcm);
|
||||
if (chip->initialized)
|
||||
snd_hda_suspend(chip->bus);
|
||||
azx_stop_chip(chip);
|
||||
azx_enter_link_reset(chip);
|
||||
if (chip->irq >= 0) {
|
||||
@ -830,7 +822,6 @@ static int azx_resume(struct device *dev)
|
||||
|
||||
azx_init_chip(chip, true);
|
||||
|
||||
snd_hda_resume(chip->bus);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
return 0;
|
||||
}
|
||||
@ -927,7 +918,8 @@ static int azx_runtime_idle(struct device *dev)
|
||||
if (chip->disabled || hda->init_failed)
|
||||
return 0;
|
||||
|
||||
if (!power_save_controller || !azx_has_pm_runtime(chip))
|
||||
if (!power_save_controller || !azx_has_pm_runtime(chip) ||
|
||||
chip->bus->codec_powered)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
@ -1612,19 +1604,6 @@ static int azx_first_init(struct azx *chip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void power_down_all_codecs(struct azx *chip)
|
||||
{
|
||||
#ifdef CONFIG_PM
|
||||
/* The codecs were powered up in snd_hda_codec_new().
|
||||
* Now all initialization done, so turn them down if possible
|
||||
*/
|
||||
struct hda_codec *codec;
|
||||
list_for_each_entry(codec, &chip->bus->codec_list, list) {
|
||||
snd_hda_power_down(codec);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||
/* callback from request_firmware_nowait() */
|
||||
static void azx_firmware_cb(const struct firmware *fw, void *context)
|
||||
@ -1893,7 +1872,7 @@ static int azx_probe_continue(struct azx *chip)
|
||||
#endif
|
||||
|
||||
/* create codec instances */
|
||||
err = azx_bus_create(chip, model[dev], power_save_addr);
|
||||
err = azx_bus_create(chip, model[dev]);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
|
||||
@ -1934,9 +1913,9 @@ static int azx_probe_continue(struct azx *chip)
|
||||
goto out_free;
|
||||
|
||||
chip->running = 1;
|
||||
power_down_all_codecs(chip);
|
||||
azx_notifier_register(chip);
|
||||
azx_add_card_list(chip);
|
||||
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);
|
||||
|
||||
|
@ -272,29 +272,6 @@ int snd_hda_add_imux_item(struct hda_codec *codec,
|
||||
struct hda_input_mux *imux, const char *label,
|
||||
int index, int *type_index_ret);
|
||||
|
||||
/*
|
||||
* Channel mode helper
|
||||
*/
|
||||
struct hda_channel_mode {
|
||||
int channels;
|
||||
const struct hda_verb *sequence;
|
||||
};
|
||||
|
||||
int snd_hda_ch_mode_info(struct hda_codec *codec,
|
||||
struct snd_ctl_elem_info *uinfo,
|
||||
const struct hda_channel_mode *chmode,
|
||||
int num_chmodes);
|
||||
int snd_hda_ch_mode_get(struct hda_codec *codec,
|
||||
struct snd_ctl_elem_value *ucontrol,
|
||||
const struct hda_channel_mode *chmode,
|
||||
int num_chmodes,
|
||||
int max_channels);
|
||||
int snd_hda_ch_mode_put(struct hda_codec *codec,
|
||||
struct snd_ctl_elem_value *ucontrol,
|
||||
const struct hda_channel_mode *chmode,
|
||||
int num_chmodes,
|
||||
int *max_channelsp);
|
||||
|
||||
/*
|
||||
* Multi-channel / digital-out PCM helper
|
||||
*/
|
||||
@ -350,12 +327,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
|
||||
int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
|
||||
struct hda_multi_out *mout);
|
||||
|
||||
/*
|
||||
* generic codec parser
|
||||
*/
|
||||
int snd_hda_parse_generic_codec(struct hda_codec *codec);
|
||||
int snd_hda_parse_hdmi_codec(struct hda_codec *codec);
|
||||
|
||||
/*
|
||||
* generic proc interface
|
||||
*/
|
||||
@ -783,9 +754,13 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
|
||||
|
||||
/*
|
||||
*/
|
||||
#define codec_err(codec, fmt, args...) dev_err(&(codec)->dev, fmt, ##args)
|
||||
#define codec_warn(codec, fmt, args...) dev_warn(&(codec)->dev, fmt, ##args)
|
||||
#define codec_info(codec, fmt, args...) dev_info(&(codec)->dev, fmt, ##args)
|
||||
#define codec_dbg(codec, fmt, args...) dev_dbg(&(codec)->dev, fmt, ##args)
|
||||
#define codec_err(codec, fmt, args...) \
|
||||
dev_err(hda_codec_dev(codec), fmt, ##args)
|
||||
#define codec_warn(codec, fmt, args...) \
|
||||
dev_warn(hda_codec_dev(codec), fmt, ##args)
|
||||
#define codec_info(codec, fmt, args...) \
|
||||
dev_info(hda_codec_dev(codec), fmt, ##args)
|
||||
#define codec_dbg(codec, fmt, args...) \
|
||||
dev_dbg(hda_codec_dev(codec), fmt, ##args)
|
||||
|
||||
#endif /* __SOUND_HDA_LOCAL_H */
|
||||
|
@ -81,7 +81,7 @@ module_param(power_save, bint, 0644);
|
||||
MODULE_PARM_DESC(power_save,
|
||||
"Automatic power-saving timeout (in seconds, 0 = disable).");
|
||||
#else
|
||||
static int power_save = 0;
|
||||
#define power_save 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -249,14 +249,9 @@ static int hda_tegra_suspend(struct device *dev)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip = card->private_data;
|
||||
struct azx_pcm *p;
|
||||
struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
list_for_each_entry(p, &chip->pcm_list, list)
|
||||
snd_pcm_suspend_all(p->pcm);
|
||||
if (chip->initialized)
|
||||
snd_hda_suspend(chip->bus);
|
||||
|
||||
azx_stop_chip(chip);
|
||||
azx_enter_link_reset(chip);
|
||||
@ -277,7 +272,6 @@ static int hda_tegra_resume(struct device *dev)
|
||||
|
||||
azx_init_chip(chip, 1);
|
||||
|
||||
snd_hda_resume(chip->bus);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
|
||||
return 0;
|
||||
@ -343,17 +337,6 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The codecs were powered up in snd_hda_codec_new().
|
||||
* Now all initialization done, so turn them down if possible
|
||||
*/
|
||||
static void power_down_all_codecs(struct azx *chip)
|
||||
{
|
||||
struct hda_codec *codec;
|
||||
list_for_each_entry(codec, &chip->bus->codec_list, list)
|
||||
snd_hda_power_down(codec);
|
||||
}
|
||||
|
||||
static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
|
||||
{
|
||||
struct snd_card *card = chip->card;
|
||||
@ -502,7 +485,7 @@ static int hda_tegra_probe(struct platform_device *pdev)
|
||||
goto out_free;
|
||||
|
||||
/* create codec instances */
|
||||
err = azx_bus_create(chip, NULL, &power_save);
|
||||
err = azx_bus_create(chip, NULL);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
|
||||
@ -529,8 +512,8 @@ static int hda_tegra_probe(struct platform_device *pdev)
|
||||
goto out_free;
|
||||
|
||||
chip->running = 1;
|
||||
power_down_all_codecs(chip);
|
||||
azx_notifier_register(chip);
|
||||
snd_hda_set_power_save(chip->bus, power_save * 1000);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -87,30 +87,6 @@ DEFINE_EVENT(hda_power, hda_power_up,
|
||||
TP_PROTO(struct hda_codec *codec),
|
||||
TP_ARGS(codec)
|
||||
);
|
||||
|
||||
TRACE_EVENT(hda_power_count,
|
||||
TP_PROTO(struct hda_codec *codec),
|
||||
TP_ARGS(codec),
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, card )
|
||||
__field( unsigned int, addr )
|
||||
__field( int, power_count )
|
||||
__field( int, power_on )
|
||||
__field( int, power_transition )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->card = (codec)->bus->card->number;
|
||||
__entry->addr = (codec)->addr;
|
||||
__entry->power_count = (codec)->power_count;
|
||||
__entry->power_on = (codec)->power_on;
|
||||
__entry->power_transition = (codec)->power_transition;
|
||||
),
|
||||
|
||||
TP_printk("[%d:%d] power_count=%d, power_on=%d, power_transition=%d",
|
||||
__entry->card, __entry->addr, __entry->power_count,
|
||||
__entry->power_on, __entry->power_transition)
|
||||
);
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
TRACE_EVENT(hda_unsol_event,
|
||||
|
@ -1194,20 +1194,8 @@ MODULE_ALIAS("snd-hda-codec-id:11d4*");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Analog Devices HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list analog_list = {
|
||||
static struct hda_codec_driver analog_driver = {
|
||||
.preset = snd_hda_preset_analog,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_analog_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&analog_list);
|
||||
}
|
||||
|
||||
static void __exit patch_analog_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&analog_list);
|
||||
}
|
||||
|
||||
module_init(patch_analog_init)
|
||||
module_exit(patch_analog_exit)
|
||||
module_hda_codec_driver(analog_driver);
|
||||
|
@ -98,20 +98,8 @@ MODULE_ALIAS("snd-hda-codec-id:1102000d");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list ca0110_list = {
|
||||
static struct hda_codec_driver ca0110_driver = {
|
||||
.preset = snd_hda_preset_ca0110,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_ca0110_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&ca0110_list);
|
||||
}
|
||||
|
||||
static void __exit patch_ca0110_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&ca0110_list);
|
||||
}
|
||||
|
||||
module_init(patch_ca0110_init)
|
||||
module_exit(patch_ca0110_exit)
|
||||
module_hda_codec_driver(ca0110_driver);
|
||||
|
@ -4702,20 +4702,8 @@ MODULE_ALIAS("snd-hda-codec-id:11020011");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Creative Sound Core3D codec");
|
||||
|
||||
static struct hda_codec_preset_list ca0132_list = {
|
||||
static struct hda_codec_driver ca0132_driver = {
|
||||
.preset = snd_hda_preset_ca0132,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_ca0132_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&ca0132_list);
|
||||
}
|
||||
|
||||
static void __exit patch_ca0132_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&ca0132_list);
|
||||
}
|
||||
|
||||
module_init(patch_ca0132_init)
|
||||
module_exit(patch_ca0132_exit)
|
||||
module_hda_codec_driver(ca0132_driver);
|
||||
|
@ -1221,20 +1221,8 @@ MODULE_ALIAS("snd-hda-codec-id:10134213");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list cirrus_list = {
|
||||
static struct hda_codec_driver cirrus_driver = {
|
||||
.preset = snd_hda_preset_cirrus,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_cirrus_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&cirrus_list);
|
||||
}
|
||||
|
||||
static void __exit patch_cirrus_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&cirrus_list);
|
||||
}
|
||||
|
||||
module_init(patch_cirrus_init)
|
||||
module_exit(patch_cirrus_exit)
|
||||
module_hda_codec_driver(cirrus_driver);
|
||||
|
@ -137,20 +137,8 @@ MODULE_ALIAS("snd-hda-codec-id:434d4980");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("C-Media HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list cmedia_list = {
|
||||
static struct hda_codec_driver cmedia_driver = {
|
||||
.preset = snd_hda_preset_cmedia,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_cmedia_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&cmedia_list);
|
||||
}
|
||||
|
||||
static void __exit patch_cmedia_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&cmedia_list);
|
||||
}
|
||||
|
||||
module_init(patch_cmedia_init)
|
||||
module_exit(patch_cmedia_exit)
|
||||
module_hda_codec_driver(cmedia_driver);
|
||||
|
@ -1018,20 +1018,8 @@ MODULE_ALIAS("snd-hda-codec-id:14f151d7");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Conexant HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list conexant_list = {
|
||||
static struct hda_codec_driver conexant_driver = {
|
||||
.preset = snd_hda_preset_conexant,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_conexant_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&conexant_list);
|
||||
}
|
||||
|
||||
static void __exit patch_conexant_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&conexant_list);
|
||||
}
|
||||
|
||||
module_init(patch_conexant_init)
|
||||
module_exit(patch_conexant_exit)
|
||||
module_hda_codec_driver(conexant_driver);
|
||||
|
@ -3300,15 +3300,6 @@ static int patch_via_hdmi(struct hda_codec *codec)
|
||||
return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
|
||||
}
|
||||
|
||||
/*
|
||||
* called from hda_codec.c for generic HDMI support
|
||||
*/
|
||||
int snd_hda_parse_hdmi_codec(struct hda_codec *codec)
|
||||
{
|
||||
return patch_generic_hdmi(codec);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_parse_hdmi_codec);
|
||||
|
||||
/*
|
||||
* patch entries
|
||||
*/
|
||||
@ -3373,6 +3364,8 @@ static const struct hda_codec_preset snd_hda_preset_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 },
|
||||
/* special ID for generic HDMI */
|
||||
{ .id = HDA_CODEC_ID_GENERIC_HDMI, .patch = patch_generic_hdmi },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
@ -3442,20 +3435,8 @@ MODULE_ALIAS("snd-hda-codec-intelhdmi");
|
||||
MODULE_ALIAS("snd-hda-codec-nvhdmi");
|
||||
MODULE_ALIAS("snd-hda-codec-atihdmi");
|
||||
|
||||
static struct hda_codec_preset_list intel_list = {
|
||||
static struct hda_codec_driver hdmi_driver = {
|
||||
.preset = snd_hda_preset_hdmi,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_hdmi_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&intel_list);
|
||||
}
|
||||
|
||||
static void __exit patch_hdmi_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&intel_list);
|
||||
}
|
||||
|
||||
module_init(patch_hdmi_init)
|
||||
module_exit(patch_hdmi_exit)
|
||||
module_hda_codec_driver(hdmi_driver);
|
||||
|
@ -6521,20 +6521,8 @@ MODULE_ALIAS("snd-hda-codec-id:10ec*");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Realtek HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list realtek_list = {
|
||||
static struct hda_codec_driver realtek_driver = {
|
||||
.preset = snd_hda_preset_realtek,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_realtek_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&realtek_list);
|
||||
}
|
||||
|
||||
static void __exit patch_realtek_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&realtek_list);
|
||||
}
|
||||
|
||||
module_init(patch_realtek_init)
|
||||
module_exit(patch_realtek_exit)
|
||||
module_hda_codec_driver(realtek_driver);
|
||||
|
@ -319,20 +319,8 @@ MODULE_ALIAS("snd-hda-codec-id:18540018");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
|
||||
|
||||
static struct hda_codec_preset_list si3054_list = {
|
||||
static struct hda_codec_driver si3054_driver = {
|
||||
.preset = snd_hda_preset_si3054,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_si3054_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&si3054_list);
|
||||
}
|
||||
|
||||
static void __exit patch_si3054_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&si3054_list);
|
||||
}
|
||||
|
||||
module_init(patch_si3054_init)
|
||||
module_exit(patch_si3054_exit)
|
||||
module_hda_codec_driver(si3054_driver);
|
||||
|
@ -2132,8 +2132,10 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
|
||||
|
||||
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
|
||||
spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
|
||||
#ifdef CONFIG_PM
|
||||
/* resetting controller clears GPIO, so we need to keep on */
|
||||
codec->bus->power_keep_link_on = 1;
|
||||
codec->d3_stop_clk = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -5091,20 +5093,8 @@ MODULE_ALIAS("snd-hda-codec-id:111d*");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
|
||||
|
||||
static struct hda_codec_preset_list sigmatel_list = {
|
||||
static struct hda_codec_driver sigmatel_driver = {
|
||||
.preset = snd_hda_preset_sigmatel,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init patch_sigmatel_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&sigmatel_list);
|
||||
}
|
||||
|
||||
static void __exit patch_sigmatel_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&sigmatel_list);
|
||||
}
|
||||
|
||||
module_init(patch_sigmatel_init)
|
||||
module_exit(patch_sigmatel_exit)
|
||||
module_hda_codec_driver(sigmatel_driver);
|
||||
|
@ -1884,23 +1884,11 @@ static const struct hda_codec_preset snd_hda_preset_via[] = {
|
||||
|
||||
MODULE_ALIAS("snd-hda-codec-id:1106*");
|
||||
|
||||
static struct hda_codec_preset_list via_list = {
|
||||
static struct hda_codec_driver via_driver = {
|
||||
.preset = snd_hda_preset_via,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("VIA HD-audio codec");
|
||||
|
||||
static int __init patch_via_init(void)
|
||||
{
|
||||
return snd_hda_add_codec_preset(&via_list);
|
||||
}
|
||||
|
||||
static void __exit patch_via_exit(void)
|
||||
{
|
||||
snd_hda_delete_codec_preset(&via_list);
|
||||
}
|
||||
|
||||
module_init(patch_via_init)
|
||||
module_exit(patch_via_exit)
|
||||
module_hda_codec_driver(via_driver);
|
||||
|
Loading…
Reference in New Issue
Block a user