1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 27639a06cSTakashi Iwai /* 37639a06cSTakashi Iwai * HD-audio codec core device 47639a06cSTakashi Iwai */ 57639a06cSTakashi Iwai 67639a06cSTakashi Iwai #include <linux/init.h> 709787492SAbhijeet Kumar #include <linux/delay.h> 87639a06cSTakashi Iwai #include <linux/device.h> 97639a06cSTakashi Iwai #include <linux/slab.h> 107639a06cSTakashi Iwai #include <linux/module.h> 117639a06cSTakashi Iwai #include <linux/export.h> 127639a06cSTakashi Iwai #include <linux/pm_runtime.h> 137639a06cSTakashi Iwai #include <sound/hdaudio.h> 1401ed3c06STakashi Iwai #include <sound/hda_regmap.h> 15b7d023e1STakashi Iwai #include <sound/pcm.h> 167639a06cSTakashi Iwai #include "local.h" 177639a06cSTakashi Iwai 187639a06cSTakashi Iwai static void setup_fg_nodes(struct hdac_device *codec); 197639a06cSTakashi Iwai static int get_codec_vendor_name(struct hdac_device *codec); 207639a06cSTakashi Iwai 217639a06cSTakashi Iwai static void default_release(struct device *dev) 227639a06cSTakashi Iwai { 2350f0bf55SKai-Heng Feng snd_hdac_device_exit(dev_to_hdac_dev(dev)); 247639a06cSTakashi Iwai } 257639a06cSTakashi Iwai 267639a06cSTakashi Iwai /** 277639a06cSTakashi Iwai * snd_hdac_device_init - initialize the HD-audio codec base device 287639a06cSTakashi Iwai * @codec: device to initialize 297639a06cSTakashi Iwai * @bus: but to attach 307639a06cSTakashi Iwai * @name: device name string 317639a06cSTakashi Iwai * @addr: codec address 327639a06cSTakashi Iwai * 337639a06cSTakashi Iwai * Returns zero for success or a negative error code. 347639a06cSTakashi Iwai * 357639a06cSTakashi Iwai * This function increments the runtime PM counter and marks it active. 367639a06cSTakashi Iwai * The caller needs to turn it off appropriately later. 377639a06cSTakashi Iwai * 387639a06cSTakashi Iwai * The caller needs to set the device's release op properly by itself. 397639a06cSTakashi Iwai */ 407639a06cSTakashi Iwai int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, 417639a06cSTakashi Iwai const char *name, unsigned int addr) 427639a06cSTakashi Iwai { 437639a06cSTakashi Iwai struct device *dev; 447639a06cSTakashi Iwai hda_nid_t fg; 457639a06cSTakashi Iwai int err; 467639a06cSTakashi Iwai 477639a06cSTakashi Iwai dev = &codec->dev; 487639a06cSTakashi Iwai device_initialize(dev); 497639a06cSTakashi Iwai dev->parent = bus->dev; 507639a06cSTakashi Iwai dev->bus = &snd_hda_bus_type; 517639a06cSTakashi Iwai dev->release = default_release; 523256be65STakashi Iwai dev->groups = hdac_dev_attr_groups; 537639a06cSTakashi Iwai dev_set_name(dev, "%s", name); 547639a06cSTakashi Iwai device_enable_async_suspend(dev); 557639a06cSTakashi Iwai 567639a06cSTakashi Iwai codec->bus = bus; 577639a06cSTakashi Iwai codec->addr = addr; 587639a06cSTakashi Iwai codec->type = HDA_DEV_CORE; 59ed180abbSAmadeusz Sławiński mutex_init(&codec->widget_lock); 601a462be5STakashi Iwai mutex_init(&codec->regmap_lock); 617639a06cSTakashi Iwai pm_runtime_set_active(&codec->dev); 627639a06cSTakashi Iwai pm_runtime_get_noresume(&codec->dev); 637639a06cSTakashi Iwai atomic_set(&codec->in_pm, 0); 647639a06cSTakashi Iwai 65246bb4aaSTakashi Iwai err = snd_hdac_bus_add_device(bus, codec); 66246bb4aaSTakashi Iwai if (err < 0) 67246bb4aaSTakashi Iwai goto error; 68246bb4aaSTakashi Iwai 697639a06cSTakashi Iwai /* fill parameters */ 707639a06cSTakashi Iwai codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 717639a06cSTakashi Iwai AC_PAR_VENDOR_ID); 727639a06cSTakashi Iwai if (codec->vendor_id == -1) { 737639a06cSTakashi Iwai /* read again, hopefully the access method was corrected 747639a06cSTakashi Iwai * in the last read... 757639a06cSTakashi Iwai */ 767639a06cSTakashi Iwai codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 777639a06cSTakashi Iwai AC_PAR_VENDOR_ID); 787639a06cSTakashi Iwai } 797639a06cSTakashi Iwai 807639a06cSTakashi Iwai codec->subsystem_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 817639a06cSTakashi Iwai AC_PAR_SUBSYSTEM_ID); 827639a06cSTakashi Iwai codec->revision_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 837639a06cSTakashi Iwai AC_PAR_REV_ID); 847639a06cSTakashi Iwai 857639a06cSTakashi Iwai setup_fg_nodes(codec); 867639a06cSTakashi Iwai if (!codec->afg && !codec->mfg) { 877639a06cSTakashi Iwai dev_err(dev, "no AFG or MFG node found\n"); 887639a06cSTakashi Iwai err = -ENODEV; 897639a06cSTakashi Iwai goto error; 907639a06cSTakashi Iwai } 917639a06cSTakashi Iwai 927639a06cSTakashi Iwai fg = codec->afg ? codec->afg : codec->mfg; 937639a06cSTakashi Iwai 94774a075aSTakashi Iwai err = snd_hdac_refresh_widgets(codec); 957639a06cSTakashi Iwai if (err < 0) 967639a06cSTakashi Iwai goto error; 977639a06cSTakashi Iwai 987639a06cSTakashi Iwai codec->power_caps = snd_hdac_read_parm(codec, fg, AC_PAR_POWER_STATE); 997639a06cSTakashi Iwai /* reread ssid if not set by parameter */ 100ffda568eSDavid Henningsson if (codec->subsystem_id == -1 || codec->subsystem_id == 0) 1017639a06cSTakashi Iwai snd_hdac_read(codec, fg, AC_VERB_GET_SUBSYSTEM_ID, 0, 1027639a06cSTakashi Iwai &codec->subsystem_id); 1037639a06cSTakashi Iwai 1047639a06cSTakashi Iwai err = get_codec_vendor_name(codec); 1057639a06cSTakashi Iwai if (err < 0) 1067639a06cSTakashi Iwai goto error; 1077639a06cSTakashi Iwai 1087639a06cSTakashi Iwai codec->chip_name = kasprintf(GFP_KERNEL, "ID %x", 1097639a06cSTakashi Iwai codec->vendor_id & 0xffff); 1107639a06cSTakashi Iwai if (!codec->chip_name) { 1117639a06cSTakashi Iwai err = -ENOMEM; 1127639a06cSTakashi Iwai goto error; 1137639a06cSTakashi Iwai } 1147639a06cSTakashi Iwai 1157639a06cSTakashi Iwai return 0; 1167639a06cSTakashi Iwai 1177639a06cSTakashi Iwai error: 1187639a06cSTakashi Iwai put_device(&codec->dev); 1197639a06cSTakashi Iwai return err; 1207639a06cSTakashi Iwai } 1217639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_init); 1227639a06cSTakashi Iwai 1237639a06cSTakashi Iwai /** 1247639a06cSTakashi Iwai * snd_hdac_device_exit - clean up the HD-audio codec base device 1257639a06cSTakashi Iwai * @codec: device to clean up 1267639a06cSTakashi Iwai */ 1277639a06cSTakashi Iwai void snd_hdac_device_exit(struct hdac_device *codec) 1287639a06cSTakashi Iwai { 129c4c2533fSTakashi Iwai pm_runtime_put_noidle(&codec->dev); 13013774d81SRander Wang /* keep balance of runtime PM child_count in parent device */ 13113774d81SRander Wang pm_runtime_set_suspended(&codec->dev); 1327639a06cSTakashi Iwai snd_hdac_bus_remove_device(codec->bus, codec); 1337639a06cSTakashi Iwai kfree(codec->vendor_name); 1347639a06cSTakashi Iwai kfree(codec->chip_name); 1357639a06cSTakashi Iwai } 1367639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_exit); 1377639a06cSTakashi Iwai 1387639a06cSTakashi Iwai /** 1393256be65STakashi Iwai * snd_hdac_device_register - register the hd-audio codec base device 1406e57188fSKeyon Jie * @codec: the device to register 1413256be65STakashi Iwai */ 1423256be65STakashi Iwai int snd_hdac_device_register(struct hdac_device *codec) 1433256be65STakashi Iwai { 1443256be65STakashi Iwai int err; 1453256be65STakashi Iwai 1463256be65STakashi Iwai err = device_add(&codec->dev); 1473256be65STakashi Iwai if (err < 0) 1483256be65STakashi Iwai return err; 149ed180abbSAmadeusz Sławiński mutex_lock(&codec->widget_lock); 1503256be65STakashi Iwai err = hda_widget_sysfs_init(codec); 151ed180abbSAmadeusz Sławiński mutex_unlock(&codec->widget_lock); 152246bb4aaSTakashi Iwai if (err < 0) { 153ee5f85d9STakashi Iwai device_del(&codec->dev); 154ee5f85d9STakashi Iwai return err; 1553256be65STakashi Iwai } 156246bb4aaSTakashi Iwai 157246bb4aaSTakashi Iwai return 0; 158246bb4aaSTakashi Iwai } 1593256be65STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_register); 1603256be65STakashi Iwai 1613256be65STakashi Iwai /** 1623256be65STakashi Iwai * snd_hdac_device_unregister - unregister the hd-audio codec base device 1636e57188fSKeyon Jie * @codec: the device to unregister 1643256be65STakashi Iwai */ 1653256be65STakashi Iwai void snd_hdac_device_unregister(struct hdac_device *codec) 1663256be65STakashi Iwai { 1673256be65STakashi Iwai if (device_is_registered(&codec->dev)) { 168ed180abbSAmadeusz Sławiński mutex_lock(&codec->widget_lock); 1693256be65STakashi Iwai hda_widget_sysfs_exit(codec); 170ed180abbSAmadeusz Sławiński mutex_unlock(&codec->widget_lock); 171ee5f85d9STakashi Iwai device_del(&codec->dev); 172246bb4aaSTakashi Iwai snd_hdac_bus_remove_device(codec->bus, codec); 1733256be65STakashi Iwai } 1743256be65STakashi Iwai } 1753256be65STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_unregister); 1763256be65STakashi Iwai 1773256be65STakashi Iwai /** 178ded255beSTakashi Iwai * snd_hdac_device_set_chip_name - set/update the codec name 179ded255beSTakashi Iwai * @codec: the HDAC device 180ded255beSTakashi Iwai * @name: name string to set 181ded255beSTakashi Iwai * 182ded255beSTakashi Iwai * Returns 0 if the name is set or updated, or a negative error code. 183ded255beSTakashi Iwai */ 184ded255beSTakashi Iwai int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name) 185ded255beSTakashi Iwai { 186ded255beSTakashi Iwai char *newname; 187ded255beSTakashi Iwai 188ded255beSTakashi Iwai if (!name) 189ded255beSTakashi Iwai return 0; 190ded255beSTakashi Iwai newname = kstrdup(name, GFP_KERNEL); 191ded255beSTakashi Iwai if (!newname) 192ded255beSTakashi Iwai return -ENOMEM; 193ded255beSTakashi Iwai kfree(codec->chip_name); 194ded255beSTakashi Iwai codec->chip_name = newname; 195ded255beSTakashi Iwai return 0; 196ded255beSTakashi Iwai } 197ded255beSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_set_chip_name); 198ded255beSTakashi Iwai 199ded255beSTakashi Iwai /** 2004f9e0c38STakashi Iwai * snd_hdac_codec_modalias - give the module alias name 2014f9e0c38STakashi Iwai * @codec: HDAC device 2024f9e0c38STakashi Iwai * @buf: string buffer to store 2034f9e0c38STakashi Iwai * @size: string buffer size 2044f9e0c38STakashi Iwai * 2054f9e0c38STakashi Iwai * Returns the size of string, like snprintf(), or a negative error code. 2064f9e0c38STakashi Iwai */ 2072a81ada3SGreg Kroah-Hartman int snd_hdac_codec_modalias(const struct hdac_device *codec, char *buf, size_t size) 2084f9e0c38STakashi Iwai { 2090a7efa14STakashi Iwai return scnprintf(buf, size, "hdaudio:v%08Xr%08Xa%02X\n", 2104f9e0c38STakashi Iwai codec->vendor_id, codec->revision_id, codec->type); 2114f9e0c38STakashi Iwai } 2124f9e0c38STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_codec_modalias); 2134f9e0c38STakashi Iwai 2144f9e0c38STakashi Iwai /** 2157639a06cSTakashi Iwai * snd_hdac_make_cmd - compose a 32bit command word to be sent to the 2167639a06cSTakashi Iwai * HD-audio controller 2177639a06cSTakashi Iwai * @codec: the codec object 2187639a06cSTakashi Iwai * @nid: NID to encode 2197639a06cSTakashi Iwai * @verb: verb to encode 2207639a06cSTakashi Iwai * @parm: parameter to encode 2217639a06cSTakashi Iwai * 2227639a06cSTakashi Iwai * Return an encoded command verb or -1 for error. 2237639a06cSTakashi Iwai */ 224ddf7cb83STakashi Iwai static unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, 2257639a06cSTakashi Iwai unsigned int verb, unsigned int parm) 2267639a06cSTakashi Iwai { 2277639a06cSTakashi Iwai u32 val, addr; 2287639a06cSTakashi Iwai 2297639a06cSTakashi Iwai addr = codec->addr; 2307639a06cSTakashi Iwai if ((addr & ~0xf) || (nid & ~0x7f) || 2317639a06cSTakashi Iwai (verb & ~0xfff) || (parm & ~0xffff)) { 2327639a06cSTakashi Iwai dev_err(&codec->dev, "out of range cmd %x:%x:%x:%x\n", 2337639a06cSTakashi Iwai addr, nid, verb, parm); 2347639a06cSTakashi Iwai return -1; 2357639a06cSTakashi Iwai } 2367639a06cSTakashi Iwai 2377639a06cSTakashi Iwai val = addr << 28; 2387639a06cSTakashi Iwai val |= (u32)nid << 20; 2397639a06cSTakashi Iwai val |= verb << 8; 2407639a06cSTakashi Iwai val |= parm; 2417639a06cSTakashi Iwai return val; 2427639a06cSTakashi Iwai } 2437639a06cSTakashi Iwai 2447639a06cSTakashi Iwai /** 24505852448STakashi Iwai * snd_hdac_exec_verb - execute an encoded verb 24605852448STakashi Iwai * @codec: the codec object 24705852448STakashi Iwai * @cmd: encoded verb to execute 24805852448STakashi Iwai * @flags: optional flags, pass zero for default 24905852448STakashi Iwai * @res: the pointer to store the result, NULL if running async 25005852448STakashi Iwai * 25105852448STakashi Iwai * Returns zero if successful, or a negative error code. 25205852448STakashi Iwai * 25305852448STakashi Iwai * This calls the exec_verb op when set in hdac_codec. If not, 25405852448STakashi Iwai * call the default snd_hdac_bus_exec_verb(). 25505852448STakashi Iwai */ 25605852448STakashi Iwai int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, 25705852448STakashi Iwai unsigned int flags, unsigned int *res) 25805852448STakashi Iwai { 25905852448STakashi Iwai if (codec->exec_verb) 26005852448STakashi Iwai return codec->exec_verb(codec, cmd, flags, res); 26105852448STakashi Iwai return snd_hdac_bus_exec_verb(codec->bus, codec->addr, cmd, res); 26205852448STakashi Iwai } 26305852448STakashi Iwai 26405852448STakashi Iwai 26505852448STakashi Iwai /** 2667639a06cSTakashi Iwai * snd_hdac_read - execute a verb 2677639a06cSTakashi Iwai * @codec: the codec object 2687639a06cSTakashi Iwai * @nid: NID to execute a verb 2697639a06cSTakashi Iwai * @verb: verb to execute 2707639a06cSTakashi Iwai * @parm: parameter for a verb 2717639a06cSTakashi Iwai * @res: the pointer to store the result, NULL if running async 2727639a06cSTakashi Iwai * 2737639a06cSTakashi Iwai * Returns zero if successful, or a negative error code. 2747639a06cSTakashi Iwai */ 2757639a06cSTakashi Iwai int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid, 2767639a06cSTakashi Iwai unsigned int verb, unsigned int parm, unsigned int *res) 2777639a06cSTakashi Iwai { 2787639a06cSTakashi Iwai unsigned int cmd = snd_hdac_make_cmd(codec, nid, verb, parm); 2797639a06cSTakashi Iwai 28005852448STakashi Iwai return snd_hdac_exec_verb(codec, cmd, 0, res); 2817639a06cSTakashi Iwai } 2827639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_read); 2837639a06cSTakashi Iwai 2847639a06cSTakashi Iwai /** 28501ed3c06STakashi Iwai * _snd_hdac_read_parm - read a parmeter 2866e57188fSKeyon Jie * @codec: the codec object 2876e57188fSKeyon Jie * @nid: NID to read a parameter 2886e57188fSKeyon Jie * @parm: parameter to read 2896e57188fSKeyon Jie * @res: pointer to store the read value 2907639a06cSTakashi Iwai * 29101ed3c06STakashi Iwai * This function returns zero or an error unlike snd_hdac_read_parm(). 2927639a06cSTakashi Iwai */ 29301ed3c06STakashi Iwai int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm, 29401ed3c06STakashi Iwai unsigned int *res) 2957639a06cSTakashi Iwai { 29601ed3c06STakashi Iwai unsigned int cmd; 2977639a06cSTakashi Iwai 29801ed3c06STakashi Iwai cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; 29901ed3c06STakashi Iwai return snd_hdac_regmap_read_raw(codec, cmd, res); 3007639a06cSTakashi Iwai } 30101ed3c06STakashi Iwai EXPORT_SYMBOL_GPL(_snd_hdac_read_parm); 3027639a06cSTakashi Iwai 3037639a06cSTakashi Iwai /** 3049ba17b4dSTakashi Iwai * snd_hdac_read_parm_uncached - read a codec parameter without caching 3057639a06cSTakashi Iwai * @codec: the codec object 3067639a06cSTakashi Iwai * @nid: NID to read a parameter 3077639a06cSTakashi Iwai * @parm: parameter to read 3087639a06cSTakashi Iwai * 3097639a06cSTakashi Iwai * Returns -1 for error. If you need to distinguish the error more 3107639a06cSTakashi Iwai * strictly, use snd_hdac_read() directly. 3117639a06cSTakashi Iwai */ 3129ba17b4dSTakashi Iwai int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, 3139ba17b4dSTakashi Iwai int parm) 3147639a06cSTakashi Iwai { 3153194ed49STakashi Iwai unsigned int cmd, val; 3167639a06cSTakashi Iwai 3173194ed49STakashi Iwai cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; 3183194ed49STakashi Iwai if (snd_hdac_regmap_read_raw_uncached(codec, cmd, &val) < 0) 3193194ed49STakashi Iwai return -1; 3207639a06cSTakashi Iwai return val; 3217639a06cSTakashi Iwai } 3229ba17b4dSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached); 3239ba17b4dSTakashi Iwai 3249ba17b4dSTakashi Iwai /** 325faa75f8aSTakashi Iwai * snd_hdac_override_parm - override read-only parameters 326faa75f8aSTakashi Iwai * @codec: the codec object 327faa75f8aSTakashi Iwai * @nid: NID for the parameter 328faa75f8aSTakashi Iwai * @parm: the parameter to change 329faa75f8aSTakashi Iwai * @val: the parameter value to overwrite 330faa75f8aSTakashi Iwai */ 331faa75f8aSTakashi Iwai int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid, 332faa75f8aSTakashi Iwai unsigned int parm, unsigned int val) 333faa75f8aSTakashi Iwai { 334faa75f8aSTakashi Iwai unsigned int verb = (AC_VERB_PARAMETERS << 8) | (nid << 20) | parm; 335faa75f8aSTakashi Iwai int err; 336faa75f8aSTakashi Iwai 337faa75f8aSTakashi Iwai if (!codec->regmap) 338faa75f8aSTakashi Iwai return -EINVAL; 339faa75f8aSTakashi Iwai 340faa75f8aSTakashi Iwai codec->caps_overwriting = true; 341faa75f8aSTakashi Iwai err = snd_hdac_regmap_write_raw(codec, verb, val); 342faa75f8aSTakashi Iwai codec->caps_overwriting = false; 343faa75f8aSTakashi Iwai return err; 344faa75f8aSTakashi Iwai } 345faa75f8aSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_override_parm); 3467639a06cSTakashi Iwai 3477639a06cSTakashi Iwai /** 3487639a06cSTakashi Iwai * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes 3497639a06cSTakashi Iwai * @codec: the codec object 3507639a06cSTakashi Iwai * @nid: NID to inspect 3517639a06cSTakashi Iwai * @start_id: the pointer to store the starting NID 3527639a06cSTakashi Iwai * 3537639a06cSTakashi Iwai * Returns the number of subtree nodes or zero if not found. 3549ba17b4dSTakashi Iwai * This function reads parameters always without caching. 3557639a06cSTakashi Iwai */ 3567639a06cSTakashi Iwai int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, 3577639a06cSTakashi Iwai hda_nid_t *start_id) 3587639a06cSTakashi Iwai { 3597639a06cSTakashi Iwai unsigned int parm; 3607639a06cSTakashi Iwai 3619ba17b4dSTakashi Iwai parm = snd_hdac_read_parm_uncached(codec, nid, AC_PAR_NODE_COUNT); 3627639a06cSTakashi Iwai if (parm == -1) { 3637639a06cSTakashi Iwai *start_id = 0; 3647639a06cSTakashi Iwai return 0; 3657639a06cSTakashi Iwai } 3667639a06cSTakashi Iwai *start_id = (parm >> 16) & 0x7fff; 3677639a06cSTakashi Iwai return (int)(parm & 0x7fff); 3687639a06cSTakashi Iwai } 3697639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_sub_nodes); 3707639a06cSTakashi Iwai 3717639a06cSTakashi Iwai /* 3727639a06cSTakashi Iwai * look for an AFG and MFG nodes 3737639a06cSTakashi Iwai */ 3747639a06cSTakashi Iwai static void setup_fg_nodes(struct hdac_device *codec) 3757639a06cSTakashi Iwai { 3767639a06cSTakashi Iwai int i, total_nodes, function_id; 3777639a06cSTakashi Iwai hda_nid_t nid; 3787639a06cSTakashi Iwai 3797639a06cSTakashi Iwai total_nodes = snd_hdac_get_sub_nodes(codec, AC_NODE_ROOT, &nid); 3807639a06cSTakashi Iwai for (i = 0; i < total_nodes; i++, nid++) { 3817639a06cSTakashi Iwai function_id = snd_hdac_read_parm(codec, nid, 3827639a06cSTakashi Iwai AC_PAR_FUNCTION_TYPE); 3837639a06cSTakashi Iwai switch (function_id & 0xff) { 3847639a06cSTakashi Iwai case AC_GRP_AUDIO_FUNCTION: 3857639a06cSTakashi Iwai codec->afg = nid; 3867639a06cSTakashi Iwai codec->afg_function_id = function_id & 0xff; 3877639a06cSTakashi Iwai codec->afg_unsol = (function_id >> 8) & 1; 3887639a06cSTakashi Iwai break; 3897639a06cSTakashi Iwai case AC_GRP_MODEM_FUNCTION: 3907639a06cSTakashi Iwai codec->mfg = nid; 3917639a06cSTakashi Iwai codec->mfg_function_id = function_id & 0xff; 3927639a06cSTakashi Iwai codec->mfg_unsol = (function_id >> 8) & 1; 3937639a06cSTakashi Iwai break; 3947639a06cSTakashi Iwai default: 3957639a06cSTakashi Iwai break; 3967639a06cSTakashi Iwai } 3977639a06cSTakashi Iwai } 3987639a06cSTakashi Iwai } 3997639a06cSTakashi Iwai 4007639a06cSTakashi Iwai /** 4017639a06cSTakashi Iwai * snd_hdac_refresh_widgets - Reset the widget start/end nodes 4027639a06cSTakashi Iwai * @codec: the codec object 4037639a06cSTakashi Iwai */ 404774a075aSTakashi Iwai int snd_hdac_refresh_widgets(struct hdac_device *codec) 4057639a06cSTakashi Iwai { 4067639a06cSTakashi Iwai hda_nid_t start_nid; 40798482377SEvan Green int nums, err = 0; 4087639a06cSTakashi Iwai 40998482377SEvan Green /* 41098482377SEvan Green * Serialize against multiple threads trying to update the sysfs 41198482377SEvan Green * widgets array. 41298482377SEvan Green */ 41398482377SEvan Green mutex_lock(&codec->widget_lock); 4147639a06cSTakashi Iwai nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); 4157639a06cSTakashi Iwai if (!start_nid || nums <= 0 || nums >= 0xff) { 4167639a06cSTakashi Iwai dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n", 4177639a06cSTakashi Iwai codec->afg); 41898482377SEvan Green err = -EINVAL; 41998482377SEvan Green goto unlock; 4207639a06cSTakashi Iwai } 4217639a06cSTakashi Iwai 4229780ded3STakashi Iwai err = hda_widget_sysfs_reinit(codec, start_nid, nums); 4239780ded3STakashi Iwai if (err < 0) 42498482377SEvan Green goto unlock; 4259780ded3STakashi Iwai 4267639a06cSTakashi Iwai codec->num_nodes = nums; 4277639a06cSTakashi Iwai codec->start_nid = start_nid; 4287639a06cSTakashi Iwai codec->end_nid = start_nid + nums; 42998482377SEvan Green unlock: 43098482377SEvan Green mutex_unlock(&codec->widget_lock); 43198482377SEvan Green return err; 4327639a06cSTakashi Iwai } 4337639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); 4347639a06cSTakashi Iwai 4357639a06cSTakashi Iwai /* return CONNLIST_LEN parameter of the given widget */ 4367639a06cSTakashi Iwai static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) 4377639a06cSTakashi Iwai { 4387639a06cSTakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 4397639a06cSTakashi Iwai unsigned int parm; 4407639a06cSTakashi Iwai 4417639a06cSTakashi Iwai if (!(wcaps & AC_WCAP_CONN_LIST) && 4427639a06cSTakashi Iwai get_wcaps_type(wcaps) != AC_WID_VOL_KNB) 4437639a06cSTakashi Iwai return 0; 4447639a06cSTakashi Iwai 4457639a06cSTakashi Iwai parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN); 4467639a06cSTakashi Iwai if (parm == -1) 4477639a06cSTakashi Iwai parm = 0; 4487639a06cSTakashi Iwai return parm; 4497639a06cSTakashi Iwai } 4507639a06cSTakashi Iwai 4517639a06cSTakashi Iwai /** 4527639a06cSTakashi Iwai * snd_hdac_get_connections - get a widget connection list 4537639a06cSTakashi Iwai * @codec: the codec object 4547639a06cSTakashi Iwai * @nid: NID 4557639a06cSTakashi Iwai * @conn_list: the array to store the results, can be NULL 4567639a06cSTakashi Iwai * @max_conns: the max size of the given array 4577639a06cSTakashi Iwai * 4587639a06cSTakashi Iwai * Returns the number of connected widgets, zero for no connection, or a 4597639a06cSTakashi Iwai * negative error code. When the number of elements don't fit with the 4607639a06cSTakashi Iwai * given array size, it returns -ENOSPC. 4617639a06cSTakashi Iwai * 4627639a06cSTakashi Iwai * When @conn_list is NULL, it just checks the number of connections. 4637639a06cSTakashi Iwai */ 4647639a06cSTakashi Iwai int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, 4657639a06cSTakashi Iwai hda_nid_t *conn_list, int max_conns) 4667639a06cSTakashi Iwai { 4677639a06cSTakashi Iwai unsigned int parm; 4687639a06cSTakashi Iwai int i, conn_len, conns, err; 4697639a06cSTakashi Iwai unsigned int shift, num_elems, mask; 4707639a06cSTakashi Iwai hda_nid_t prev_nid; 4717639a06cSTakashi Iwai int null_count = 0; 4727639a06cSTakashi Iwai 4737639a06cSTakashi Iwai parm = get_num_conns(codec, nid); 4747639a06cSTakashi Iwai if (!parm) 4757639a06cSTakashi Iwai return 0; 4767639a06cSTakashi Iwai 4777639a06cSTakashi Iwai if (parm & AC_CLIST_LONG) { 4787639a06cSTakashi Iwai /* long form */ 4797639a06cSTakashi Iwai shift = 16; 4807639a06cSTakashi Iwai num_elems = 2; 4817639a06cSTakashi Iwai } else { 4827639a06cSTakashi Iwai /* short form */ 4837639a06cSTakashi Iwai shift = 8; 4847639a06cSTakashi Iwai num_elems = 4; 4857639a06cSTakashi Iwai } 4867639a06cSTakashi Iwai conn_len = parm & AC_CLIST_LENGTH; 4877639a06cSTakashi Iwai mask = (1 << (shift-1)) - 1; 4887639a06cSTakashi Iwai 4897639a06cSTakashi Iwai if (!conn_len) 4907639a06cSTakashi Iwai return 0; /* no connection */ 4917639a06cSTakashi Iwai 4927639a06cSTakashi Iwai if (conn_len == 1) { 4937639a06cSTakashi Iwai /* single connection */ 4947639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, AC_VERB_GET_CONNECT_LIST, 0, 4957639a06cSTakashi Iwai &parm); 4967639a06cSTakashi Iwai if (err < 0) 4977639a06cSTakashi Iwai return err; 4987639a06cSTakashi Iwai if (conn_list) 4997639a06cSTakashi Iwai conn_list[0] = parm & mask; 5007639a06cSTakashi Iwai return 1; 5017639a06cSTakashi Iwai } 5027639a06cSTakashi Iwai 5037639a06cSTakashi Iwai /* multi connection */ 5047639a06cSTakashi Iwai conns = 0; 5057639a06cSTakashi Iwai prev_nid = 0; 5067639a06cSTakashi Iwai for (i = 0; i < conn_len; i++) { 5077639a06cSTakashi Iwai int range_val; 5087639a06cSTakashi Iwai hda_nid_t val, n; 5097639a06cSTakashi Iwai 5107639a06cSTakashi Iwai if (i % num_elems == 0) { 5117639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, 5127639a06cSTakashi Iwai AC_VERB_GET_CONNECT_LIST, i, 5137639a06cSTakashi Iwai &parm); 5147639a06cSTakashi Iwai if (err < 0) 5157639a06cSTakashi Iwai return -EIO; 5167639a06cSTakashi Iwai } 5177639a06cSTakashi Iwai range_val = !!(parm & (1 << (shift-1))); /* ranges */ 5187639a06cSTakashi Iwai val = parm & mask; 5197639a06cSTakashi Iwai if (val == 0 && null_count++) { /* no second chance */ 5207639a06cSTakashi Iwai dev_dbg(&codec->dev, 5217639a06cSTakashi Iwai "invalid CONNECT_LIST verb %x[%i]:%x\n", 5227639a06cSTakashi Iwai nid, i, parm); 5237639a06cSTakashi Iwai return 0; 5247639a06cSTakashi Iwai } 5257639a06cSTakashi Iwai parm >>= shift; 5267639a06cSTakashi Iwai if (range_val) { 5277639a06cSTakashi Iwai /* ranges between the previous and this one */ 5287639a06cSTakashi Iwai if (!prev_nid || prev_nid >= val) { 5297639a06cSTakashi Iwai dev_warn(&codec->dev, 5307639a06cSTakashi Iwai "invalid dep_range_val %x:%x\n", 5317639a06cSTakashi Iwai prev_nid, val); 5327639a06cSTakashi Iwai continue; 5337639a06cSTakashi Iwai } 5347639a06cSTakashi Iwai for (n = prev_nid + 1; n <= val; n++) { 5357639a06cSTakashi Iwai if (conn_list) { 5367639a06cSTakashi Iwai if (conns >= max_conns) 5377639a06cSTakashi Iwai return -ENOSPC; 5387639a06cSTakashi Iwai conn_list[conns] = n; 5397639a06cSTakashi Iwai } 5407639a06cSTakashi Iwai conns++; 5417639a06cSTakashi Iwai } 5427639a06cSTakashi Iwai } else { 5437639a06cSTakashi Iwai if (conn_list) { 5447639a06cSTakashi Iwai if (conns >= max_conns) 5457639a06cSTakashi Iwai return -ENOSPC; 5467639a06cSTakashi Iwai conn_list[conns] = val; 5477639a06cSTakashi Iwai } 5487639a06cSTakashi Iwai conns++; 5497639a06cSTakashi Iwai } 5507639a06cSTakashi Iwai prev_nid = val; 5517639a06cSTakashi Iwai } 5527639a06cSTakashi Iwai return conns; 5537639a06cSTakashi Iwai } 5547639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_connections); 5557639a06cSTakashi Iwai 5567639a06cSTakashi Iwai #ifdef CONFIG_PM 5577639a06cSTakashi Iwai /** 558664c7155STakashi Iwai * snd_hdac_power_up - power up the codec 5597639a06cSTakashi Iwai * @codec: the codec object 560664c7155STakashi Iwai * 561664c7155STakashi Iwai * This function calls the runtime PM helper to power up the given codec. 562664c7155STakashi Iwai * Unlike snd_hdac_power_up_pm(), you should call this only for the code 563664c7155STakashi Iwai * path that isn't included in PM path. Otherwise it gets stuck. 564fbce23a0STakashi Iwai * 565fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 5667639a06cSTakashi Iwai */ 567fbce23a0STakashi Iwai int snd_hdac_power_up(struct hdac_device *codec) 5687639a06cSTakashi Iwai { 569fbce23a0STakashi Iwai return pm_runtime_get_sync(&codec->dev); 5707639a06cSTakashi Iwai } 5717639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_up); 5727639a06cSTakashi Iwai 5737639a06cSTakashi Iwai /** 574664c7155STakashi Iwai * snd_hdac_power_down - power down the codec 5757639a06cSTakashi Iwai * @codec: the codec object 576fbce23a0STakashi Iwai * 577fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 5787639a06cSTakashi Iwai */ 579fbce23a0STakashi Iwai int snd_hdac_power_down(struct hdac_device *codec) 5807639a06cSTakashi Iwai { 5817639a06cSTakashi Iwai struct device *dev = &codec->dev; 5827639a06cSTakashi Iwai 5837639a06cSTakashi Iwai pm_runtime_mark_last_busy(dev); 584fbce23a0STakashi Iwai return pm_runtime_put_autosuspend(dev); 5857639a06cSTakashi Iwai } 5867639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_down); 587c3aeda62STakashi Iwai 588c3aeda62STakashi Iwai /** 589c3aeda62STakashi Iwai * snd_hdac_power_up_pm - power up the codec 590c3aeda62STakashi Iwai * @codec: the codec object 591c3aeda62STakashi Iwai * 592c3aeda62STakashi Iwai * This function can be called in a recursive code path like init code 593c3aeda62STakashi Iwai * which may be called by PM suspend/resume again. OTOH, if a power-up 594c3aeda62STakashi Iwai * call must wake up the sleeper (e.g. in a kctl callback), use 595c3aeda62STakashi Iwai * snd_hdac_power_up() instead. 596fbce23a0STakashi Iwai * 597fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 598c3aeda62STakashi Iwai */ 599fbce23a0STakashi Iwai int snd_hdac_power_up_pm(struct hdac_device *codec) 600c3aeda62STakashi Iwai { 601c3aeda62STakashi Iwai if (!atomic_inc_not_zero(&codec->in_pm)) 602fbce23a0STakashi Iwai return snd_hdac_power_up(codec); 603fbce23a0STakashi Iwai return 0; 604c3aeda62STakashi Iwai } 605c3aeda62STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm); 606c3aeda62STakashi Iwai 607fc4f000bSTakashi Iwai /* like snd_hdac_power_up_pm(), but only increment the pm count when 608fc4f000bSTakashi Iwai * already powered up. Returns -1 if not powered up, 1 if incremented 609fc4f000bSTakashi Iwai * or 0 if unchanged. Only used in hdac_regmap.c 610fc4f000bSTakashi Iwai */ 611fc4f000bSTakashi Iwai int snd_hdac_keep_power_up(struct hdac_device *codec) 612fc4f000bSTakashi Iwai { 613fc4f000bSTakashi Iwai if (!atomic_inc_not_zero(&codec->in_pm)) { 614*81302b1cSTakashi Iwai int ret = pm_runtime_get_if_active(&codec->dev, true); 615fc4f000bSTakashi Iwai if (!ret) 616fc4f000bSTakashi Iwai return -1; 617fc4f000bSTakashi Iwai if (ret < 0) 618fc4f000bSTakashi Iwai return 0; 619fc4f000bSTakashi Iwai } 620fc4f000bSTakashi Iwai return 1; 621fc4f000bSTakashi Iwai } 622fc4f000bSTakashi Iwai 623c3aeda62STakashi Iwai /** 624c3aeda62STakashi Iwai * snd_hdac_power_down_pm - power down the codec 625c3aeda62STakashi Iwai * @codec: the codec object 626c3aeda62STakashi Iwai * 627c3aeda62STakashi Iwai * Like snd_hdac_power_up_pm(), this function is used in a recursive 628c3aeda62STakashi Iwai * code path like init code which may be called by PM suspend/resume again. 629fbce23a0STakashi Iwai * 630fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 631c3aeda62STakashi Iwai */ 632fbce23a0STakashi Iwai int snd_hdac_power_down_pm(struct hdac_device *codec) 633c3aeda62STakashi Iwai { 634c3aeda62STakashi Iwai if (atomic_dec_if_positive(&codec->in_pm) < 0) 635fbce23a0STakashi Iwai return snd_hdac_power_down(codec); 636fbce23a0STakashi Iwai return 0; 637c3aeda62STakashi Iwai } 638c3aeda62STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); 6397639a06cSTakashi Iwai #endif 6407639a06cSTakashi Iwai 6417639a06cSTakashi Iwai /* codec vendor labels */ 6427639a06cSTakashi Iwai struct hda_vendor_id { 6437639a06cSTakashi Iwai unsigned int id; 6447639a06cSTakashi Iwai const char *name; 6457639a06cSTakashi Iwai }; 6467639a06cSTakashi Iwai 647bf82326fSTakashi Iwai static const struct hda_vendor_id hda_vendor_ids[] = { 6487639a06cSTakashi Iwai { 0x1002, "ATI" }, 6497639a06cSTakashi Iwai { 0x1013, "Cirrus Logic" }, 6507639a06cSTakashi Iwai { 0x1057, "Motorola" }, 6517639a06cSTakashi Iwai { 0x1095, "Silicon Image" }, 6527639a06cSTakashi Iwai { 0x10de, "Nvidia" }, 6537639a06cSTakashi Iwai { 0x10ec, "Realtek" }, 6547639a06cSTakashi Iwai { 0x1102, "Creative" }, 6557639a06cSTakashi Iwai { 0x1106, "VIA" }, 6567639a06cSTakashi Iwai { 0x111d, "IDT" }, 6577639a06cSTakashi Iwai { 0x11c1, "LSI" }, 6587639a06cSTakashi Iwai { 0x11d4, "Analog Devices" }, 6597639a06cSTakashi Iwai { 0x13f6, "C-Media" }, 6607639a06cSTakashi Iwai { 0x14f1, "Conexant" }, 6617639a06cSTakashi Iwai { 0x17e8, "Chrontel" }, 6627639a06cSTakashi Iwai { 0x1854, "LG" }, 663527f4643Shuangwenhui { 0x19e5, "Huawei" }, 6647639a06cSTakashi Iwai { 0x1aec, "Wolfson Microelectronics" }, 6657639a06cSTakashi Iwai { 0x1af4, "QEMU" }, 6667639a06cSTakashi Iwai { 0x434d, "C-Media" }, 6677639a06cSTakashi Iwai { 0x8086, "Intel" }, 6687639a06cSTakashi Iwai { 0x8384, "SigmaTel" }, 6697639a06cSTakashi Iwai {} /* terminator */ 6707639a06cSTakashi Iwai }; 6717639a06cSTakashi Iwai 6727639a06cSTakashi Iwai /* store the codec vendor name */ 6737639a06cSTakashi Iwai static int get_codec_vendor_name(struct hdac_device *codec) 6747639a06cSTakashi Iwai { 6757639a06cSTakashi Iwai const struct hda_vendor_id *c; 6767639a06cSTakashi Iwai u16 vendor_id = codec->vendor_id >> 16; 6777639a06cSTakashi Iwai 6787639a06cSTakashi Iwai for (c = hda_vendor_ids; c->id; c++) { 6797639a06cSTakashi Iwai if (c->id == vendor_id) { 6807639a06cSTakashi Iwai codec->vendor_name = kstrdup(c->name, GFP_KERNEL); 6817639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 6827639a06cSTakashi Iwai } 6837639a06cSTakashi Iwai } 6847639a06cSTakashi Iwai 6857639a06cSTakashi Iwai codec->vendor_name = kasprintf(GFP_KERNEL, "Generic %04x", vendor_id); 6867639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 6877639a06cSTakashi Iwai } 688b7d023e1STakashi Iwai 689b7d023e1STakashi Iwai /* 690b7d023e1STakashi Iwai * stream formats 691b7d023e1STakashi Iwai */ 692b7d023e1STakashi Iwai struct hda_rate_tbl { 693b7d023e1STakashi Iwai unsigned int hz; 694b7d023e1STakashi Iwai unsigned int alsa_bits; 695b7d023e1STakashi Iwai unsigned int hda_fmt; 696b7d023e1STakashi Iwai }; 697b7d023e1STakashi Iwai 698b7d023e1STakashi Iwai /* rate = base * mult / div */ 699b7d023e1STakashi Iwai #define HDA_RATE(base, mult, div) \ 700b7d023e1STakashi Iwai (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ 701b7d023e1STakashi Iwai (((div) - 1) << AC_FMT_DIV_SHIFT)) 702b7d023e1STakashi Iwai 703bf82326fSTakashi Iwai static const struct hda_rate_tbl rate_bits[] = { 704b7d023e1STakashi Iwai /* rate in Hz, ALSA rate bitmask, HDA format value */ 705b7d023e1STakashi Iwai 706b7d023e1STakashi Iwai /* autodetected value used in snd_hda_query_supported_pcm */ 707b7d023e1STakashi Iwai { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) }, 708b7d023e1STakashi Iwai { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) }, 709b7d023e1STakashi Iwai { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) }, 710b7d023e1STakashi Iwai { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) }, 711b7d023e1STakashi Iwai { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) }, 712b7d023e1STakashi Iwai { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) }, 713b7d023e1STakashi Iwai { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) }, 714b7d023e1STakashi Iwai { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) }, 715b7d023e1STakashi Iwai { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) }, 716b7d023e1STakashi Iwai { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) }, 717b7d023e1STakashi Iwai { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) }, 718b7d023e1STakashi Iwai #define AC_PAR_PCM_RATE_BITS 11 719b7d023e1STakashi Iwai /* up to bits 10, 384kHZ isn't supported properly */ 720b7d023e1STakashi Iwai 721b7d023e1STakashi Iwai /* not autodetected value */ 722b7d023e1STakashi Iwai { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) }, 723b7d023e1STakashi Iwai 724b7d023e1STakashi Iwai { 0 } /* terminator */ 725b7d023e1STakashi Iwai }; 726b7d023e1STakashi Iwai 727b7d023e1STakashi Iwai /** 728b7d023e1STakashi Iwai * snd_hdac_calc_stream_format - calculate the format bitset 729b7d023e1STakashi Iwai * @rate: the sample rate 730b7d023e1STakashi Iwai * @channels: the number of channels 731b7d023e1STakashi Iwai * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) 732b7d023e1STakashi Iwai * @maxbps: the max. bps 733b7d023e1STakashi Iwai * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant) 734b7d023e1STakashi Iwai * 735b7d023e1STakashi Iwai * Calculate the format bitset from the given rate, channels and th PCM format. 736b7d023e1STakashi Iwai * 737b7d023e1STakashi Iwai * Return zero if invalid. 738b7d023e1STakashi Iwai */ 739b7d023e1STakashi Iwai unsigned int snd_hdac_calc_stream_format(unsigned int rate, 740b7d023e1STakashi Iwai unsigned int channels, 741a6ea5fe9STakashi Iwai snd_pcm_format_t format, 742b7d023e1STakashi Iwai unsigned int maxbps, 743b7d023e1STakashi Iwai unsigned short spdif_ctls) 744b7d023e1STakashi Iwai { 745b7d023e1STakashi Iwai int i; 746b7d023e1STakashi Iwai unsigned int val = 0; 747b7d023e1STakashi Iwai 748b7d023e1STakashi Iwai for (i = 0; rate_bits[i].hz; i++) 749b7d023e1STakashi Iwai if (rate_bits[i].hz == rate) { 750b7d023e1STakashi Iwai val = rate_bits[i].hda_fmt; 751b7d023e1STakashi Iwai break; 752b7d023e1STakashi Iwai } 753b7d023e1STakashi Iwai if (!rate_bits[i].hz) 754b7d023e1STakashi Iwai return 0; 755b7d023e1STakashi Iwai 756b7d023e1STakashi Iwai if (channels == 0 || channels > 8) 757b7d023e1STakashi Iwai return 0; 758b7d023e1STakashi Iwai val |= channels - 1; 759b7d023e1STakashi Iwai 760b7d023e1STakashi Iwai switch (snd_pcm_format_width(format)) { 761b7d023e1STakashi Iwai case 8: 762b7d023e1STakashi Iwai val |= AC_FMT_BITS_8; 763b7d023e1STakashi Iwai break; 764b7d023e1STakashi Iwai case 16: 765b7d023e1STakashi Iwai val |= AC_FMT_BITS_16; 766b7d023e1STakashi Iwai break; 767b7d023e1STakashi Iwai case 20: 768b7d023e1STakashi Iwai case 24: 769b7d023e1STakashi Iwai case 32: 770b7d023e1STakashi Iwai if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) 771b7d023e1STakashi Iwai val |= AC_FMT_BITS_32; 772b7d023e1STakashi Iwai else if (maxbps >= 24) 773b7d023e1STakashi Iwai val |= AC_FMT_BITS_24; 774b7d023e1STakashi Iwai else 775b7d023e1STakashi Iwai val |= AC_FMT_BITS_20; 776b7d023e1STakashi Iwai break; 777b7d023e1STakashi Iwai default: 778b7d023e1STakashi Iwai return 0; 779b7d023e1STakashi Iwai } 780b7d023e1STakashi Iwai 781b7d023e1STakashi Iwai if (spdif_ctls & AC_DIG1_NONAUDIO) 782b7d023e1STakashi Iwai val |= AC_FMT_TYPE_NON_PCM; 783b7d023e1STakashi Iwai 784b7d023e1STakashi Iwai return val; 785b7d023e1STakashi Iwai } 786b7d023e1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_calc_stream_format); 787b7d023e1STakashi Iwai 788b7d023e1STakashi Iwai static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid) 789b7d023e1STakashi Iwai { 790b7d023e1STakashi Iwai unsigned int val = 0; 791b7d023e1STakashi Iwai 792b7d023e1STakashi Iwai if (nid != codec->afg && 793b7d023e1STakashi Iwai (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) 794b7d023e1STakashi Iwai val = snd_hdac_read_parm(codec, nid, AC_PAR_PCM); 795b7d023e1STakashi Iwai if (!val || val == -1) 796b7d023e1STakashi Iwai val = snd_hdac_read_parm(codec, codec->afg, AC_PAR_PCM); 797b7d023e1STakashi Iwai if (!val || val == -1) 798b7d023e1STakashi Iwai return 0; 799b7d023e1STakashi Iwai return val; 800b7d023e1STakashi Iwai } 801b7d023e1STakashi Iwai 802b7d023e1STakashi Iwai static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid) 803b7d023e1STakashi Iwai { 804b7d023e1STakashi Iwai unsigned int streams = snd_hdac_read_parm(codec, nid, AC_PAR_STREAM); 805b7d023e1STakashi Iwai 806b7d023e1STakashi Iwai if (!streams || streams == -1) 807b7d023e1STakashi Iwai streams = snd_hdac_read_parm(codec, codec->afg, AC_PAR_STREAM); 808b7d023e1STakashi Iwai if (!streams || streams == -1) 809b7d023e1STakashi Iwai return 0; 810b7d023e1STakashi Iwai return streams; 811b7d023e1STakashi Iwai } 812b7d023e1STakashi Iwai 813b7d023e1STakashi Iwai /** 814b7d023e1STakashi Iwai * snd_hdac_query_supported_pcm - query the supported PCM rates and formats 815b7d023e1STakashi Iwai * @codec: the codec object 816b7d023e1STakashi Iwai * @nid: NID to query 817b7d023e1STakashi Iwai * @ratesp: the pointer to store the detected rate bitflags 818b7d023e1STakashi Iwai * @formatsp: the pointer to store the detected formats 819b7d023e1STakashi Iwai * @bpsp: the pointer to store the detected format widths 820b7d023e1STakashi Iwai * 821b7d023e1STakashi Iwai * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp 822b7d023e1STakashi Iwai * or @bsps argument is ignored. 823b7d023e1STakashi Iwai * 824b7d023e1STakashi Iwai * Returns 0 if successful, otherwise a negative error code. 825b7d023e1STakashi Iwai */ 826b7d023e1STakashi Iwai int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, 827b7d023e1STakashi Iwai u32 *ratesp, u64 *formatsp, unsigned int *bpsp) 828b7d023e1STakashi Iwai { 829b7d023e1STakashi Iwai unsigned int i, val, wcaps; 830b7d023e1STakashi Iwai 831b7d023e1STakashi Iwai wcaps = get_wcaps(codec, nid); 832b7d023e1STakashi Iwai val = query_pcm_param(codec, nid); 833b7d023e1STakashi Iwai 834b7d023e1STakashi Iwai if (ratesp) { 835b7d023e1STakashi Iwai u32 rates = 0; 836b7d023e1STakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) { 837b7d023e1STakashi Iwai if (val & (1 << i)) 838b7d023e1STakashi Iwai rates |= rate_bits[i].alsa_bits; 839b7d023e1STakashi Iwai } 840b7d023e1STakashi Iwai if (rates == 0) { 841b7d023e1STakashi Iwai dev_err(&codec->dev, 842b7d023e1STakashi Iwai "rates == 0 (nid=0x%x, val=0x%x, ovrd=%i)\n", 843b7d023e1STakashi Iwai nid, val, 844b7d023e1STakashi Iwai (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); 845b7d023e1STakashi Iwai return -EIO; 846b7d023e1STakashi Iwai } 847b7d023e1STakashi Iwai *ratesp = rates; 848b7d023e1STakashi Iwai } 849b7d023e1STakashi Iwai 850b7d023e1STakashi Iwai if (formatsp || bpsp) { 851b7d023e1STakashi Iwai u64 formats = 0; 852b7d023e1STakashi Iwai unsigned int streams, bps; 853b7d023e1STakashi Iwai 854b7d023e1STakashi Iwai streams = query_stream_param(codec, nid); 855b7d023e1STakashi Iwai if (!streams) 856b7d023e1STakashi Iwai return -EIO; 857b7d023e1STakashi Iwai 858b7d023e1STakashi Iwai bps = 0; 859b7d023e1STakashi Iwai if (streams & AC_SUPFMT_PCM) { 860b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_8) { 861b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_U8; 862b7d023e1STakashi Iwai bps = 8; 863b7d023e1STakashi Iwai } 864b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_16) { 865b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_S16_LE; 866b7d023e1STakashi Iwai bps = 16; 867b7d023e1STakashi Iwai } 868b7d023e1STakashi Iwai if (wcaps & AC_WCAP_DIGITAL) { 869b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_32) 870b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; 871b7d023e1STakashi Iwai if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) 872b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_S32_LE; 873b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_24) 874b7d023e1STakashi Iwai bps = 24; 875b7d023e1STakashi Iwai else if (val & AC_SUPPCM_BITS_20) 876b7d023e1STakashi Iwai bps = 20; 877b7d023e1STakashi Iwai } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24| 878b7d023e1STakashi Iwai AC_SUPPCM_BITS_32)) { 879b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_S32_LE; 880b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_32) 881b7d023e1STakashi Iwai bps = 32; 882b7d023e1STakashi Iwai else if (val & AC_SUPPCM_BITS_24) 883b7d023e1STakashi Iwai bps = 24; 884b7d023e1STakashi Iwai else if (val & AC_SUPPCM_BITS_20) 885b7d023e1STakashi Iwai bps = 20; 886b7d023e1STakashi Iwai } 887b7d023e1STakashi Iwai } 888b7d023e1STakashi Iwai #if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */ 889b7d023e1STakashi Iwai if (streams & AC_SUPFMT_FLOAT32) { 890b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; 891b7d023e1STakashi Iwai if (!bps) 892b7d023e1STakashi Iwai bps = 32; 893b7d023e1STakashi Iwai } 894b7d023e1STakashi Iwai #endif 895b7d023e1STakashi Iwai if (streams == AC_SUPFMT_AC3) { 896b7d023e1STakashi Iwai /* should be exclusive */ 897b7d023e1STakashi Iwai /* temporary hack: we have still no proper support 898b7d023e1STakashi Iwai * for the direct AC3 stream... 899b7d023e1STakashi Iwai */ 900b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_U8; 901b7d023e1STakashi Iwai bps = 8; 902b7d023e1STakashi Iwai } 903b7d023e1STakashi Iwai if (formats == 0) { 904b7d023e1STakashi Iwai dev_err(&codec->dev, 905b7d023e1STakashi Iwai "formats == 0 (nid=0x%x, val=0x%x, ovrd=%i, streams=0x%x)\n", 906b7d023e1STakashi Iwai nid, val, 907b7d023e1STakashi Iwai (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, 908b7d023e1STakashi Iwai streams); 909b7d023e1STakashi Iwai return -EIO; 910b7d023e1STakashi Iwai } 911b7d023e1STakashi Iwai if (formatsp) 912b7d023e1STakashi Iwai *formatsp = formats; 913b7d023e1STakashi Iwai if (bpsp) 914b7d023e1STakashi Iwai *bpsp = bps; 915b7d023e1STakashi Iwai } 916b7d023e1STakashi Iwai 917b7d023e1STakashi Iwai return 0; 918b7d023e1STakashi Iwai } 919b7d023e1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_query_supported_pcm); 920b7d023e1STakashi Iwai 921b7d023e1STakashi Iwai /** 922b7d023e1STakashi Iwai * snd_hdac_is_supported_format - Check the validity of the format 923b7d023e1STakashi Iwai * @codec: the codec object 924b7d023e1STakashi Iwai * @nid: NID to check 925b7d023e1STakashi Iwai * @format: the HD-audio format value to check 926b7d023e1STakashi Iwai * 927b7d023e1STakashi Iwai * Check whether the given node supports the format value. 928b7d023e1STakashi Iwai * 929b7d023e1STakashi Iwai * Returns true if supported, false if not. 930b7d023e1STakashi Iwai */ 931b7d023e1STakashi Iwai bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid, 932b7d023e1STakashi Iwai unsigned int format) 933b7d023e1STakashi Iwai { 934b7d023e1STakashi Iwai int i; 935b7d023e1STakashi Iwai unsigned int val = 0, rate, stream; 936b7d023e1STakashi Iwai 937b7d023e1STakashi Iwai val = query_pcm_param(codec, nid); 938b7d023e1STakashi Iwai if (!val) 939b7d023e1STakashi Iwai return false; 940b7d023e1STakashi Iwai 941b7d023e1STakashi Iwai rate = format & 0xff00; 942b7d023e1STakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) 943b7d023e1STakashi Iwai if (rate_bits[i].hda_fmt == rate) { 944b7d023e1STakashi Iwai if (val & (1 << i)) 945b7d023e1STakashi Iwai break; 946b7d023e1STakashi Iwai return false; 947b7d023e1STakashi Iwai } 948b7d023e1STakashi Iwai if (i >= AC_PAR_PCM_RATE_BITS) 949b7d023e1STakashi Iwai return false; 950b7d023e1STakashi Iwai 951b7d023e1STakashi Iwai stream = query_stream_param(codec, nid); 952b7d023e1STakashi Iwai if (!stream) 953b7d023e1STakashi Iwai return false; 954b7d023e1STakashi Iwai 955b7d023e1STakashi Iwai if (stream & AC_SUPFMT_PCM) { 956b7d023e1STakashi Iwai switch (format & 0xf0) { 957b7d023e1STakashi Iwai case 0x00: 958b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_8)) 959b7d023e1STakashi Iwai return false; 960b7d023e1STakashi Iwai break; 961b7d023e1STakashi Iwai case 0x10: 962b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_16)) 963b7d023e1STakashi Iwai return false; 964b7d023e1STakashi Iwai break; 965b7d023e1STakashi Iwai case 0x20: 966b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_20)) 967b7d023e1STakashi Iwai return false; 968b7d023e1STakashi Iwai break; 969b7d023e1STakashi Iwai case 0x30: 970b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_24)) 971b7d023e1STakashi Iwai return false; 972b7d023e1STakashi Iwai break; 973b7d023e1STakashi Iwai case 0x40: 974b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_32)) 975b7d023e1STakashi Iwai return false; 976b7d023e1STakashi Iwai break; 977b7d023e1STakashi Iwai default: 978b7d023e1STakashi Iwai return false; 979b7d023e1STakashi Iwai } 980b7d023e1STakashi Iwai } else { 981b7d023e1STakashi Iwai /* FIXME: check for float32 and AC3? */ 982b7d023e1STakashi Iwai } 983b7d023e1STakashi Iwai 984b7d023e1STakashi Iwai return true; 985b7d023e1STakashi Iwai } 986b7d023e1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_is_supported_format); 9871b5e6167SSubhransu S. Prusty 9881b5e6167SSubhransu S. Prusty static unsigned int codec_read(struct hdac_device *hdac, hda_nid_t nid, 9891b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 9901b5e6167SSubhransu S. Prusty { 9911b5e6167SSubhransu S. Prusty unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm); 9921b5e6167SSubhransu S. Prusty unsigned int res; 9931b5e6167SSubhransu S. Prusty 9941b5e6167SSubhransu S. Prusty if (snd_hdac_exec_verb(hdac, cmd, flags, &res)) 9951b5e6167SSubhransu S. Prusty return -1; 9961b5e6167SSubhransu S. Prusty 9971b5e6167SSubhransu S. Prusty return res; 9981b5e6167SSubhransu S. Prusty } 9991b5e6167SSubhransu S. Prusty 10001b5e6167SSubhransu S. Prusty static int codec_write(struct hdac_device *hdac, hda_nid_t nid, 10011b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 10021b5e6167SSubhransu S. Prusty { 10031b5e6167SSubhransu S. Prusty unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm); 10041b5e6167SSubhransu S. Prusty 10051b5e6167SSubhransu S. Prusty return snd_hdac_exec_verb(hdac, cmd, flags, NULL); 10061b5e6167SSubhransu S. Prusty } 10071b5e6167SSubhransu S. Prusty 10081b5e6167SSubhransu S. Prusty /** 10091b5e6167SSubhransu S. Prusty * snd_hdac_codec_read - send a command and get the response 10101b5e6167SSubhransu S. Prusty * @hdac: the HDAC device 10111b5e6167SSubhransu S. Prusty * @nid: NID to send the command 10121b5e6167SSubhransu S. Prusty * @flags: optional bit flags 10131b5e6167SSubhransu S. Prusty * @verb: the verb to send 10141b5e6167SSubhransu S. Prusty * @parm: the parameter for the verb 10151b5e6167SSubhransu S. Prusty * 10161b5e6167SSubhransu S. Prusty * Send a single command and read the corresponding response. 10171b5e6167SSubhransu S. Prusty * 10181b5e6167SSubhransu S. Prusty * Returns the obtained response value, or -1 for an error. 10191b5e6167SSubhransu S. Prusty */ 10201b5e6167SSubhransu S. Prusty int snd_hdac_codec_read(struct hdac_device *hdac, hda_nid_t nid, 10211b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 10221b5e6167SSubhransu S. Prusty { 10231b5e6167SSubhransu S. Prusty return codec_read(hdac, nid, flags, verb, parm); 10241b5e6167SSubhransu S. Prusty } 10251b5e6167SSubhransu S. Prusty EXPORT_SYMBOL_GPL(snd_hdac_codec_read); 10261b5e6167SSubhransu S. Prusty 10271b5e6167SSubhransu S. Prusty /** 10281b5e6167SSubhransu S. Prusty * snd_hdac_codec_write - send a single command without waiting for response 10291b5e6167SSubhransu S. Prusty * @hdac: the HDAC device 10301b5e6167SSubhransu S. Prusty * @nid: NID to send the command 10311b5e6167SSubhransu S. Prusty * @flags: optional bit flags 10321b5e6167SSubhransu S. Prusty * @verb: the verb to send 10331b5e6167SSubhransu S. Prusty * @parm: the parameter for the verb 10341b5e6167SSubhransu S. Prusty * 10351b5e6167SSubhransu S. Prusty * Send a single command without waiting for response. 10361b5e6167SSubhransu S. Prusty * 10371b5e6167SSubhransu S. Prusty * Returns 0 if successful, or a negative error code. 10381b5e6167SSubhransu S. Prusty */ 10391b5e6167SSubhransu S. Prusty int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid, 10401b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 10411b5e6167SSubhransu S. Prusty { 10421b5e6167SSubhransu S. Prusty return codec_write(hdac, nid, flags, verb, parm); 10431b5e6167SSubhransu S. Prusty } 10441b5e6167SSubhransu S. Prusty EXPORT_SYMBOL_GPL(snd_hdac_codec_write); 10451b5e6167SSubhransu S. Prusty 104678dd5e21STakashi Iwai /** 104778dd5e21STakashi Iwai * snd_hdac_check_power_state - check whether the actual power state matches 10481b5e6167SSubhransu S. Prusty * with the target state 10491b5e6167SSubhransu S. Prusty * 10501b5e6167SSubhransu S. Prusty * @hdac: the HDAC device 10511b5e6167SSubhransu S. Prusty * @nid: NID to send the command 10521b5e6167SSubhransu S. Prusty * @target_state: target state to check for 10531b5e6167SSubhransu S. Prusty * 10541b5e6167SSubhransu S. Prusty * Return true if state matches, false if not 10551b5e6167SSubhransu S. Prusty */ 10561b5e6167SSubhransu S. Prusty bool snd_hdac_check_power_state(struct hdac_device *hdac, 10571b5e6167SSubhransu S. Prusty hda_nid_t nid, unsigned int target_state) 10581b5e6167SSubhransu S. Prusty { 10591b5e6167SSubhransu S. Prusty unsigned int state = codec_read(hdac, nid, 0, 10601b5e6167SSubhransu S. Prusty AC_VERB_GET_POWER_STATE, 0); 10611b5e6167SSubhransu S. Prusty 10621b5e6167SSubhransu S. Prusty if (state & AC_PWRST_ERROR) 10631b5e6167SSubhransu S. Prusty return true; 10641b5e6167SSubhransu S. Prusty state = (state >> 4) & 0x0f; 10651b5e6167SSubhransu S. Prusty return (state == target_state); 10661b5e6167SSubhransu S. Prusty } 10671b5e6167SSubhransu S. Prusty EXPORT_SYMBOL_GPL(snd_hdac_check_power_state); 106809787492SAbhijeet Kumar /** 106909787492SAbhijeet Kumar * snd_hdac_sync_power_state - wait until actual power state matches 107009787492SAbhijeet Kumar * with the target state 107109787492SAbhijeet Kumar * 10726e57188fSKeyon Jie * @codec: the HDAC device 107309787492SAbhijeet Kumar * @nid: NID to send the command 10746e57188fSKeyon Jie * @power_state: target power state to wait for 107509787492SAbhijeet Kumar * 107609787492SAbhijeet Kumar * Return power state or PS_ERROR if codec rejects GET verb. 107709787492SAbhijeet Kumar */ 107809787492SAbhijeet Kumar unsigned int snd_hdac_sync_power_state(struct hdac_device *codec, 107909787492SAbhijeet Kumar hda_nid_t nid, unsigned int power_state) 108009787492SAbhijeet Kumar { 108109787492SAbhijeet Kumar unsigned long end_time = jiffies + msecs_to_jiffies(500); 108209787492SAbhijeet Kumar unsigned int state, actual_state, count; 108309787492SAbhijeet Kumar 108409787492SAbhijeet Kumar for (count = 0; count < 500; count++) { 108509787492SAbhijeet Kumar state = snd_hdac_codec_read(codec, nid, 0, 108609787492SAbhijeet Kumar AC_VERB_GET_POWER_STATE, 0); 108709787492SAbhijeet Kumar if (state & AC_PWRST_ERROR) { 108809787492SAbhijeet Kumar msleep(20); 108909787492SAbhijeet Kumar break; 109009787492SAbhijeet Kumar } 109109787492SAbhijeet Kumar actual_state = (state >> 4) & 0x0f; 109209787492SAbhijeet Kumar if (actual_state == power_state) 109309787492SAbhijeet Kumar break; 109409787492SAbhijeet Kumar if (time_after_eq(jiffies, end_time)) 109509787492SAbhijeet Kumar break; 109609787492SAbhijeet Kumar /* wait until the codec reachs to the target state */ 109709787492SAbhijeet Kumar msleep(1); 109809787492SAbhijeet Kumar } 109909787492SAbhijeet Kumar return state; 110009787492SAbhijeet Kumar } 110109787492SAbhijeet Kumar EXPORT_SYMBOL_GPL(snd_hdac_sync_power_state); 1102