// SPDX-License-Identifier: GPL-2.0-only /* * HD-audio codec core device */ #include <linux/init.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/export.h> #include <linux/pm_runtime.h> #include <sound/hdaudio.h> #include <sound/hda_regmap.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include "local.h" static void setup_fg_nodes(struct hdac_device *codec); static int get_codec_vendor_name(struct hdac_device *codec); static void default_release(struct device *dev) { … } /** * snd_hdac_device_init - initialize the HD-audio codec base device * @codec: device to initialize * @bus: but to attach * @name: device name string * @addr: codec address * * Returns zero for success or a negative error code. * * This function increments the runtime PM counter and marks it active. * The caller needs to turn it off appropriately later. * * The caller needs to set the device's release op properly by itself. */ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, const char *name, unsigned int addr) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_device_exit - clean up the HD-audio codec base device * @codec: device to clean up */ void snd_hdac_device_exit(struct hdac_device *codec) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_device_register - register the hd-audio codec base device * @codec: the device to register */ int snd_hdac_device_register(struct hdac_device *codec) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_device_unregister - unregister the hd-audio codec base device * @codec: the device to unregister */ void snd_hdac_device_unregister(struct hdac_device *codec) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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(const struct hdac_device *codec, char *buf, size_t size) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_make_cmd - compose a 32bit command word to be sent to the * HD-audio controller * @codec: the codec object * @nid: NID to encode * @verb: verb to encode * @parm: parameter to encode * * Return an encoded command verb or -1 for error. */ static unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, unsigned int verb, unsigned int parm) { … } /** * snd_hdac_exec_verb - execute an encoded verb * @codec: the codec object * @cmd: encoded verb to execute * @flags: optional flags, pass zero for default * @res: the pointer to store the result, NULL if running async * * Returns zero if successful, or a negative error code. * * This calls the exec_verb op when set in hdac_codec. If not, * call the default snd_hdac_bus_exec_verb(). */ int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, unsigned int flags, unsigned int *res) { … } /** * snd_hdac_read - execute a verb * @codec: the codec object * @nid: NID to execute a verb * @verb: verb to execute * @parm: parameter for a verb * @res: the pointer to store the result, NULL if running async * * Returns zero if successful, or a negative error code. */ int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid, unsigned int verb, unsigned int parm, unsigned int *res) { … } EXPORT_SYMBOL_GPL(…); /** * _snd_hdac_read_parm - read a parmeter * @codec: the codec object * @nid: NID to read a parameter * @parm: parameter to read * @res: pointer to store the read value * * This function returns zero or an error unlike snd_hdac_read_parm(). */ int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm, unsigned int *res) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_read_parm_uncached - read a codec parameter without caching * @codec: the codec object * @nid: NID to read a parameter * @parm: parameter to read * * Returns -1 for error. If you need to distinguish the error more * strictly, use snd_hdac_read() directly. */ int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, int parm) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_override_parm - override read-only parameters * @codec: the codec object * @nid: NID for the parameter * @parm: the parameter to change * @val: the parameter value to overwrite */ int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid, unsigned int parm, unsigned int val) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes * @codec: the codec object * @nid: NID to inspect * @start_id: the pointer to store the starting NID * * Returns the number of subtree nodes or zero if not found. * This function reads parameters always without caching. */ int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, hda_nid_t *start_id) { … } EXPORT_SYMBOL_GPL(…); /* * look for an AFG and MFG nodes */ static void setup_fg_nodes(struct hdac_device *codec) { … } /** * snd_hdac_refresh_widgets - Reset the widget start/end nodes * @codec: the codec object */ int snd_hdac_refresh_widgets(struct hdac_device *codec) { … } EXPORT_SYMBOL_GPL(…); /* return CONNLIST_LEN parameter of the given widget */ static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) { … } /** * snd_hdac_get_connections - get a widget connection list * @codec: the codec object * @nid: NID * @conn_list: the array to store the results, can be NULL * @max_conns: the max size of the given array * * Returns the number of connected widgets, zero for no connection, or a * negative error code. When the number of elements don't fit with the * given array size, it returns -ENOSPC. * * When @conn_list is NULL, it just checks the number of connections. */ int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns) { … } EXPORT_SYMBOL_GPL(…); #ifdef CONFIG_PM /** * snd_hdac_power_up - power up the codec * @codec: the codec object * * This function calls the runtime PM helper to power up the given codec. * Unlike snd_hdac_power_up_pm(), you should call this only for the code * path that isn't included in PM path. Otherwise it gets stuck. * * Returns zero if successful, or a negative error code. */ int snd_hdac_power_up(struct hdac_device *codec) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_power_down - power down the codec * @codec: the codec object * * Returns zero if successful, or a negative error code. */ int snd_hdac_power_down(struct hdac_device *codec) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_power_up_pm - power up the codec * @codec: the codec object * * This function can be called in a recursive code path like init code * which may be called by PM suspend/resume again. OTOH, if a power-up * call must wake up the sleeper (e.g. in a kctl callback), use * snd_hdac_power_up() instead. * * Returns zero if successful, or a negative error code. */ int snd_hdac_power_up_pm(struct hdac_device *codec) { … } EXPORT_SYMBOL_GPL(…); /* like snd_hdac_power_up_pm(), but only increment the pm count when * already powered up. Returns -1 if not powered up, 1 if incremented * or 0 if unchanged. Only used in hdac_regmap.c */ int snd_hdac_keep_power_up(struct hdac_device *codec) { … } /** * snd_hdac_power_down_pm - power down the codec * @codec: the codec object * * Like snd_hdac_power_up_pm(), this function is used in a recursive * code path like init code which may be called by PM suspend/resume again. * * Returns zero if successful, or a negative error code. */ int snd_hdac_power_down_pm(struct hdac_device *codec) { … } EXPORT_SYMBOL_GPL(…); #endif /* codec vendor labels */ struct hda_vendor_id { … }; static const struct hda_vendor_id hda_vendor_ids[] = …; /* store the codec vendor name */ static int get_codec_vendor_name(struct hdac_device *codec) { … } /* * stream formats */ struct hda_rate_tbl { … }; /* rate = base * mult / div */ #define HDA_RATE(base, mult, div) … static const struct hda_rate_tbl rate_bits[] = …; static snd_pcm_format_t snd_hdac_format_normalize(snd_pcm_format_t format) { … } /** * snd_hdac_stream_format_bits - obtain bits per sample value. * @format: the PCM format. * @subformat: the PCM subformat. * @maxbits: the maximum bits per sample. * * Return: The number of bits per sample. */ unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subformat_t subformat, unsigned int maxbits) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_stream_format - convert format parameters to SDxFMT value. * @channels: the number of channels. * @bits: bits per sample. * @rate: the sample rate. * * Return: The format bitset or zero if invalid. */ unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_spdif_stream_format - convert format parameters to SDxFMT value. * @channels: the number of channels. * @bits: bits per sample. * @rate: the sample rate. * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant). * * Return: The format bitset or zero if invalid. */ unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits, unsigned int rate, unsigned short spdif_ctls) { … } EXPORT_SYMBOL_GPL(…); static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid) { … } static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid) { … } /** * snd_hdac_query_supported_pcm - query the supported PCM rates and formats * @codec: the codec object * @nid: NID to query * @ratesp: the pointer to store the detected rate bitflags * @formatsp: the pointer to store the detected formats * @subformatsp: the pointer to store the detected subformats for S32_LE format * @bpsp: the pointer to store the detected format widths * * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp, * @subformatsp or @bpsp argument is ignored. * * Returns 0 if successful, otherwise a negative error code. */ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, u32 *subformatsp, unsigned int *bpsp) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_is_supported_format - Check the validity of the format * @codec: the codec object * @nid: NID to check * @format: the HD-audio format value to check * * Check whether the given node supports the format value. * * Returns true if supported, false if not. */ bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid, unsigned int format) { … } EXPORT_SYMBOL_GPL(…); static unsigned int codec_read(struct hdac_device *hdac, hda_nid_t nid, int flags, unsigned int verb, unsigned int parm) { … } static int codec_write(struct hdac_device *hdac, hda_nid_t nid, int flags, unsigned int verb, unsigned int parm) { … } /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * snd_hdac_sync_power_state - wait until actual power state matches * with the target state * * @codec: the HDAC device * @nid: NID to send the command * @power_state: target power state to wait for * * Return power state or PS_ERROR if codec rejects GET verb. */ unsigned int snd_hdac_sync_power_state(struct hdac_device *codec, hda_nid_t nid, unsigned int power_state) { … } EXPORT_SYMBOL_GPL(…);