diff options
Diffstat (limited to 'sound/hda')
-rw-r--r-- | sound/hda/ext/hdac_ext_stream.c | 9 | ||||
-rw-r--r-- | sound/hda/hda_bus_type.c | 13 | ||||
-rw-r--r-- | sound/hda/hdac_bus.c | 14 | ||||
-rw-r--r-- | sound/hda/hdac_device.c | 124 | ||||
-rw-r--r-- | sound/hda/hdac_i915.c | 70 | ||||
-rw-r--r-- | sound/hda/hdac_regmap.c | 10 | ||||
-rw-r--r-- | sound/hda/hdac_stream.c | 3 | ||||
-rw-r--r-- | sound/hda/hdac_sysfs.c | 8 |
8 files changed, 243 insertions, 8 deletions
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 33ba77dd3..cb89ec7c8 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -227,7 +227,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_setup); void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, int stream) { - snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0); + snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id); @@ -385,14 +385,13 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type) break; case HDAC_EXT_STREAM_TYPE_HOST: - if (stream->decoupled) { + if (stream->decoupled && !stream->link_locked) snd_hdac_ext_stream_decouple(ebus, stream, false); - snd_hdac_stream_release(&stream->hstream); - } + snd_hdac_stream_release(&stream->hstream); break; case HDAC_EXT_STREAM_TYPE_LINK: - if (stream->decoupled) + if (stream->decoupled && !stream->hstream.opened) snd_hdac_ext_stream_decouple(ebus, stream, false); spin_lock_irq(&bus->reg_lock); stream->link_locked = 0; diff --git a/sound/hda/hda_bus_type.c b/sound/hda/hda_bus_type.c index 89c2711ba..3060e2aee 100644 --- a/sound/hda/hda_bus_type.c +++ b/sound/hda/hda_bus_type.c @@ -4,6 +4,7 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/export.h> #include <sound/hdaudio.h> @@ -63,9 +64,21 @@ static int hda_bus_match(struct device *dev, struct device_driver *drv) return 1; } +static int hda_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + char modalias[32]; + + snd_hdac_codec_modalias(dev_to_hdac_dev(dev), modalias, + sizeof(modalias)); + if (add_uevent_var(env, "MODALIAS=%s", modalias)) + return -ENOMEM; + return 0; +} + struct bus_type snd_hda_bus_type = { .name = "hdaudio", .match = hda_bus_match, + .uevent = hda_uevent, }; EXPORT_SYMBOL_GPL(snd_hda_bus_type); diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 27c447e4f..0e81ea89a 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -172,6 +172,15 @@ static void process_unsol_events(struct work_struct *work) } } +/** + * snd_hdac_bus_add_device - Add a codec to bus + * @bus: HDA core bus + * @codec: HDA core device to add + * + * Adds the given codec to the list in the bus. The caddr_tbl array + * and codec_powered bits are updated, as well. + * Returns zero if success, or a negative error code. + */ int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec) { if (bus->caddr_tbl[codec->addr]) { @@ -188,6 +197,11 @@ int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec) } EXPORT_SYMBOL_GPL(snd_hdac_bus_add_device); +/** + * snd_hdac_bus_remove_device - Remove a codec from bus + * @bus: HDA core bus + * @codec: HDA core device to remove + */ void snd_hdac_bus_remove_device(struct hdac_bus *bus, struct hdac_device *codec) { diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index db96042a4..e361024ea 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -164,6 +164,43 @@ void snd_hdac_device_unregister(struct hdac_device *codec) EXPORT_SYMBOL_GPL(snd_hdac_device_unregister); /** + * snd_hdac_device_set_chip_name - set/update the codec name + * @codec: the HDAC device + * @name: name string to set + * + * Returns 0 if the name is set or updated, or a negative error code. + */ +int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name) +{ + char *newname; + + if (!name) + return 0; + newname = kstrdup(name, GFP_KERNEL); + if (!newname) + return -ENOMEM; + kfree(codec->chip_name); + codec->chip_name = newname; + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_device_set_chip_name); + +/** + * snd_hdac_codec_modalias - give the module alias name + * @codec: HDAC device + * @buf: string buffer to store + * @size: string buffer size + * + * Returns the size of string, like snprintf(), or a negative error code. + */ +int snd_hdac_codec_modalias(struct hdac_device *codec, char *buf, size_t size) +{ + return snprintf(buf, size, "hdaudio:v%08Xr%08Xa%02X\n", + codec->vendor_id, codec->revision_id, codec->type); +} +EXPORT_SYMBOL_GPL(snd_hdac_codec_modalias); + +/** * snd_hdac_make_cmd - compose a 32bit command word to be sent to the * HD-audio controller * @codec: the codec object @@ -592,8 +629,10 @@ int snd_hdac_power_down_pm(struct hdac_device *codec) EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); #endif -/* - * Enable/disable the link power for a codec. +/** + * snd_hdac_link_power - Enable/disable the link power for a codec + * @codec: the codec object + * @bool: enable or disable the link power */ int snd_hdac_link_power(struct hdac_device *codec, bool enable) { @@ -952,3 +991,84 @@ bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid, return true; } EXPORT_SYMBOL_GPL(snd_hdac_is_supported_format); + +static unsigned int codec_read(struct hdac_device *hdac, hda_nid_t nid, + int flags, unsigned int verb, unsigned int parm) +{ + unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm); + unsigned int res; + + if (snd_hdac_exec_verb(hdac, cmd, flags, &res)) + return -1; + + return res; +} + +static int codec_write(struct hdac_device *hdac, hda_nid_t nid, + int flags, unsigned int verb, unsigned int parm) +{ + unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm); + + return snd_hdac_exec_verb(hdac, cmd, flags, NULL); +} + +/** + * snd_hdac_codec_read - send a command and get the response + * @hdac: the HDAC device + * @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. + */ +int snd_hdac_codec_read(struct hdac_device *hdac, hda_nid_t nid, + int flags, unsigned int verb, unsigned int parm) +{ + return codec_read(hdac, nid, flags, verb, parm); +} +EXPORT_SYMBOL_GPL(snd_hdac_codec_read); + +/** + * snd_hdac_codec_write - send a single command without waiting for response + * @hdac: the HDAC device + * @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_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid, + int flags, unsigned int verb, unsigned int parm) +{ + return codec_write(hdac, nid, flags, verb, parm); +} +EXPORT_SYMBOL_GPL(snd_hdac_codec_write); + +/** + * snd_hdac_check_power_state - check whether the actual power state matches + * with the target state + * + * @hdac: the HDAC device + * @nid: NID to send the command + * @target_state: target state to check for + * + * Return true if state matches, false if not + */ +bool snd_hdac_check_power_state(struct hdac_device *hdac, + hda_nid_t nid, unsigned int target_state) +{ + unsigned int state = codec_read(hdac, nid, 0, + AC_VERB_GET_POWER_STATE, 0); + + if (state & AC_PWRST_ERROR) + return true; + state = (state >> 4) & 0x0f; + return (state == target_state); +} +EXPORT_SYMBOL_GPL(snd_hdac_check_power_state); diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 55c3df445..8fef1b8d1 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -23,6 +23,19 @@ static struct i915_audio_component *hdac_acomp; +/** + * snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup + * @bus: HDA core bus + * @enable: enable or disable the wakeup + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function should be called during the chip reset, also called at + * resume for updating STATESTS register read. + * + * Returns zero for success or a negative error code. + */ int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { struct i915_audio_component *acomp = bus->audio_component; @@ -45,6 +58,19 @@ int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) } EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); +/** + * snd_hdac_display_power - Power up / down the power refcount + * @bus: HDA core bus + * @enable: power up or down + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function manages a refcount and calls the i915 get_power() and + * put_power() ops accordingly, toggling the codec wakeup, too. + * + * Returns zero for success or a negative error code. + */ int snd_hdac_display_power(struct hdac_bus *bus, bool enable) { struct i915_audio_component *acomp = bus->audio_component; @@ -71,6 +97,16 @@ int snd_hdac_display_power(struct hdac_bus *bus, bool enable) } EXPORT_SYMBOL_GPL(snd_hdac_display_power); +/** + * snd_hdac_get_display_clk - Get CDCLK in kHz + * @bus: HDA core bus + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function queries CDCLK value in kHz from the graphics driver and + * returns the value. A negative code is returned in error. + */ int snd_hdac_get_display_clk(struct hdac_bus *bus) { struct i915_audio_component *acomp = bus->audio_component; @@ -134,6 +170,17 @@ static int hdac_component_master_match(struct device *dev, void *data) return !strcmp(dev->driver->name, "i915"); } +/** + * snd_hdac_i915_register_notifier - Register i915 audio component ops + * @aops: i915 audio component ops + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function sets the given ops to be called by the i915 graphics driver. + * + * Returns zero for success or a negative error code. + */ int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *aops) { if (WARN_ON(!hdac_acomp)) @@ -144,6 +191,18 @@ int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops } EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier); +/** + * snd_hdac_i915_init - Initialize i915 audio component + * @bus: HDA core bus + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function initializes and sets up the audio component to communicate + * with i915 graphics driver. + * + * Returns zero for success or a negative error code. + */ int snd_hdac_i915_init(struct hdac_bus *bus) { struct component_match *match = NULL; @@ -187,6 +246,17 @@ out_err: } EXPORT_SYMBOL_GPL(snd_hdac_i915_init); +/** + * snd_hdac_i915_exit - Finalize i915 audio component + * @bus: HDA core bus + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function releases the i915 audio component that has been used. + * + * Returns zero for success or a negative error code. + */ int snd_hdac_i915_exit(struct hdac_bus *bus) { struct device *dev = bus->dev; diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index b0ed870ff..eb8f7c30c 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c @@ -339,6 +339,12 @@ static const struct regmap_config hda_regmap_cfg = { .use_single_rw = true, }; +/** + * snd_hdac_regmap_init - Initialize regmap for HDA register accesses + * @codec: the codec object + * + * Returns zero for success or a negative error code. + */ int snd_hdac_regmap_init(struct hdac_device *codec) { struct regmap *regmap; @@ -352,6 +358,10 @@ int snd_hdac_regmap_init(struct hdac_device *codec) } EXPORT_SYMBOL_GPL(snd_hdac_regmap_init); +/** + * snd_hdac_regmap_init - Release the regmap from HDA codec + * @codec: the codec object + */ void snd_hdac_regmap_exit(struct hdac_device *codec) { if (codec->regmap) { diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 898115981..38990a77d 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -426,7 +426,8 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) } EXPORT_SYMBOL_GPL(snd_hdac_stream_setup_periods); -/* snd_hdac_stream_set_params - set stream parameters +/** + * snd_hdac_stream_set_params - set stream parameters * @azx_dev: HD-audio core stream for which parameters are to be set * @format_val: format value parameter * diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c index c71142dea..42d61bf41 100644 --- a/sound/hda/hdac_sysfs.c +++ b/sound/hda/hdac_sysfs.c @@ -45,6 +45,13 @@ CODEC_ATTR(mfg); CODEC_ATTR_STR(vendor_name); CODEC_ATTR_STR(chip_name); +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return snd_hdac_codec_modalias(dev_to_hdac_dev(dev), buf, 256); +} +static DEVICE_ATTR_RO(modalias); + static struct attribute *hdac_dev_attrs[] = { &dev_attr_type.attr, &dev_attr_vendor_id.attr, @@ -54,6 +61,7 @@ static struct attribute *hdac_dev_attrs[] = { &dev_attr_mfg.attr, &dev_attr_vendor_name.attr, &dev_attr_chip_name.attr, + &dev_attr_modalias.attr, NULL }; |