17639a06cSTakashi Iwai /* 27639a06cSTakashi Iwai * HD-audio codec core device 37639a06cSTakashi Iwai */ 47639a06cSTakashi Iwai 57639a06cSTakashi Iwai #include <linux/init.h> 67639a06cSTakashi Iwai #include <linux/device.h> 77639a06cSTakashi Iwai #include <linux/slab.h> 87639a06cSTakashi Iwai #include <linux/module.h> 97639a06cSTakashi Iwai #include <linux/export.h> 107639a06cSTakashi Iwai #include <linux/pm_runtime.h> 117639a06cSTakashi Iwai #include <sound/hdaudio.h> 1201ed3c06STakashi Iwai #include <sound/hda_regmap.h> 13b7d023e1STakashi Iwai #include <sound/pcm.h> 147639a06cSTakashi Iwai #include "local.h" 157639a06cSTakashi Iwai 167639a06cSTakashi Iwai static void setup_fg_nodes(struct hdac_device *codec); 177639a06cSTakashi Iwai static int get_codec_vendor_name(struct hdac_device *codec); 187639a06cSTakashi Iwai 197639a06cSTakashi Iwai static void default_release(struct device *dev) 207639a06cSTakashi Iwai { 217639a06cSTakashi Iwai snd_hdac_device_exit(container_of(dev, struct hdac_device, dev)); 227639a06cSTakashi Iwai } 237639a06cSTakashi Iwai 247639a06cSTakashi Iwai /** 257639a06cSTakashi Iwai * snd_hdac_device_init - initialize the HD-audio codec base device 267639a06cSTakashi Iwai * @codec: device to initialize 277639a06cSTakashi Iwai * @bus: but to attach 287639a06cSTakashi Iwai * @name: device name string 297639a06cSTakashi Iwai * @addr: codec address 307639a06cSTakashi Iwai * 317639a06cSTakashi Iwai * Returns zero for success or a negative error code. 327639a06cSTakashi Iwai * 337639a06cSTakashi Iwai * This function increments the runtime PM counter and marks it active. 347639a06cSTakashi Iwai * The caller needs to turn it off appropriately later. 357639a06cSTakashi Iwai * 367639a06cSTakashi Iwai * The caller needs to set the device's release op properly by itself. 377639a06cSTakashi Iwai */ 387639a06cSTakashi Iwai int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, 397639a06cSTakashi Iwai const char *name, unsigned int addr) 407639a06cSTakashi Iwai { 417639a06cSTakashi Iwai struct device *dev; 427639a06cSTakashi Iwai hda_nid_t fg; 437639a06cSTakashi Iwai int err; 447639a06cSTakashi Iwai 457639a06cSTakashi Iwai dev = &codec->dev; 467639a06cSTakashi Iwai device_initialize(dev); 477639a06cSTakashi Iwai dev->parent = bus->dev; 487639a06cSTakashi Iwai dev->bus = &snd_hda_bus_type; 497639a06cSTakashi Iwai dev->release = default_release; 503256be65STakashi Iwai dev->groups = hdac_dev_attr_groups; 517639a06cSTakashi Iwai dev_set_name(dev, "%s", name); 527639a06cSTakashi Iwai device_enable_async_suspend(dev); 537639a06cSTakashi Iwai 547639a06cSTakashi Iwai codec->bus = bus; 557639a06cSTakashi Iwai codec->addr = addr; 567639a06cSTakashi Iwai codec->type = HDA_DEV_CORE; 577639a06cSTakashi Iwai pm_runtime_set_active(&codec->dev); 587639a06cSTakashi Iwai pm_runtime_get_noresume(&codec->dev); 597639a06cSTakashi Iwai atomic_set(&codec->in_pm, 0); 607639a06cSTakashi Iwai 617639a06cSTakashi Iwai err = snd_hdac_bus_add_device(bus, codec); 627639a06cSTakashi Iwai if (err < 0) 637639a06cSTakashi Iwai goto error; 647639a06cSTakashi Iwai 657639a06cSTakashi Iwai /* fill parameters */ 667639a06cSTakashi Iwai codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 677639a06cSTakashi Iwai AC_PAR_VENDOR_ID); 687639a06cSTakashi Iwai if (codec->vendor_id == -1) { 697639a06cSTakashi Iwai /* read again, hopefully the access method was corrected 707639a06cSTakashi Iwai * in the last read... 717639a06cSTakashi Iwai */ 727639a06cSTakashi Iwai codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 737639a06cSTakashi Iwai AC_PAR_VENDOR_ID); 747639a06cSTakashi Iwai } 757639a06cSTakashi Iwai 767639a06cSTakashi Iwai codec->subsystem_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 777639a06cSTakashi Iwai AC_PAR_SUBSYSTEM_ID); 787639a06cSTakashi Iwai codec->revision_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 797639a06cSTakashi Iwai AC_PAR_REV_ID); 807639a06cSTakashi Iwai 817639a06cSTakashi Iwai setup_fg_nodes(codec); 827639a06cSTakashi Iwai if (!codec->afg && !codec->mfg) { 837639a06cSTakashi Iwai dev_err(dev, "no AFG or MFG node found\n"); 847639a06cSTakashi Iwai err = -ENODEV; 857639a06cSTakashi Iwai goto error; 867639a06cSTakashi Iwai } 877639a06cSTakashi Iwai 887639a06cSTakashi Iwai fg = codec->afg ? codec->afg : codec->mfg; 897639a06cSTakashi Iwai 907639a06cSTakashi Iwai err = snd_hdac_refresh_widgets(codec); 917639a06cSTakashi Iwai if (err < 0) 927639a06cSTakashi Iwai goto error; 937639a06cSTakashi Iwai 947639a06cSTakashi Iwai codec->power_caps = snd_hdac_read_parm(codec, fg, AC_PAR_POWER_STATE); 957639a06cSTakashi Iwai /* reread ssid if not set by parameter */ 96ffda568eSDavid Henningsson if (codec->subsystem_id == -1 || codec->subsystem_id == 0) 977639a06cSTakashi Iwai snd_hdac_read(codec, fg, AC_VERB_GET_SUBSYSTEM_ID, 0, 987639a06cSTakashi Iwai &codec->subsystem_id); 997639a06cSTakashi Iwai 1007639a06cSTakashi Iwai err = get_codec_vendor_name(codec); 1017639a06cSTakashi Iwai if (err < 0) 1027639a06cSTakashi Iwai goto error; 1037639a06cSTakashi Iwai 1047639a06cSTakashi Iwai codec->chip_name = kasprintf(GFP_KERNEL, "ID %x", 1057639a06cSTakashi Iwai codec->vendor_id & 0xffff); 1067639a06cSTakashi Iwai if (!codec->chip_name) { 1077639a06cSTakashi Iwai err = -ENOMEM; 1087639a06cSTakashi Iwai goto error; 1097639a06cSTakashi Iwai } 1107639a06cSTakashi Iwai 1117639a06cSTakashi Iwai return 0; 1127639a06cSTakashi Iwai 1137639a06cSTakashi Iwai error: 1147639a06cSTakashi Iwai put_device(&codec->dev); 1157639a06cSTakashi Iwai return err; 1167639a06cSTakashi Iwai } 1177639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_init); 1187639a06cSTakashi Iwai 1197639a06cSTakashi Iwai /** 1207639a06cSTakashi Iwai * snd_hdac_device_exit - clean up the HD-audio codec base device 1217639a06cSTakashi Iwai * @codec: device to clean up 1227639a06cSTakashi Iwai */ 1237639a06cSTakashi Iwai void snd_hdac_device_exit(struct hdac_device *codec) 1247639a06cSTakashi Iwai { 125c4c2533fSTakashi Iwai pm_runtime_put_noidle(&codec->dev); 1267639a06cSTakashi Iwai snd_hdac_bus_remove_device(codec->bus, codec); 1277639a06cSTakashi Iwai kfree(codec->vendor_name); 1287639a06cSTakashi Iwai kfree(codec->chip_name); 1297639a06cSTakashi Iwai } 1307639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_exit); 1317639a06cSTakashi Iwai 1327639a06cSTakashi Iwai /** 1333256be65STakashi Iwai * snd_hdac_device_register - register the hd-audio codec base device 1343256be65STakashi Iwai * codec: the device to register 1353256be65STakashi Iwai */ 1363256be65STakashi Iwai int snd_hdac_device_register(struct hdac_device *codec) 1373256be65STakashi Iwai { 1383256be65STakashi Iwai int err; 1393256be65STakashi Iwai 1403256be65STakashi Iwai err = device_add(&codec->dev); 1413256be65STakashi Iwai if (err < 0) 1423256be65STakashi Iwai return err; 1433256be65STakashi Iwai err = hda_widget_sysfs_init(codec); 1443256be65STakashi Iwai if (err < 0) { 1453256be65STakashi Iwai device_del(&codec->dev); 1463256be65STakashi Iwai return err; 1473256be65STakashi Iwai } 1483256be65STakashi Iwai 1493256be65STakashi Iwai return 0; 1503256be65STakashi Iwai } 1513256be65STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_register); 1523256be65STakashi Iwai 1533256be65STakashi Iwai /** 1543256be65STakashi Iwai * snd_hdac_device_unregister - unregister the hd-audio codec base device 1553256be65STakashi Iwai * codec: the device to unregister 1563256be65STakashi Iwai */ 1573256be65STakashi Iwai void snd_hdac_device_unregister(struct hdac_device *codec) 1583256be65STakashi Iwai { 1593256be65STakashi Iwai if (device_is_registered(&codec->dev)) { 1603256be65STakashi Iwai hda_widget_sysfs_exit(codec); 1613256be65STakashi Iwai device_del(&codec->dev); 1623256be65STakashi Iwai } 1633256be65STakashi Iwai } 1643256be65STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_unregister); 1653256be65STakashi Iwai 1663256be65STakashi Iwai /** 167ded255beSTakashi Iwai * snd_hdac_device_set_chip_name - set/update the codec name 168ded255beSTakashi Iwai * @codec: the HDAC device 169ded255beSTakashi Iwai * @name: name string to set 170ded255beSTakashi Iwai * 171ded255beSTakashi Iwai * Returns 0 if the name is set or updated, or a negative error code. 172ded255beSTakashi Iwai */ 173ded255beSTakashi Iwai int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name) 174ded255beSTakashi Iwai { 175ded255beSTakashi Iwai char *newname; 176ded255beSTakashi Iwai 177ded255beSTakashi Iwai if (!name) 178ded255beSTakashi Iwai return 0; 179ded255beSTakashi Iwai newname = kstrdup(name, GFP_KERNEL); 180ded255beSTakashi Iwai if (!newname) 181ded255beSTakashi Iwai return -ENOMEM; 182ded255beSTakashi Iwai kfree(codec->chip_name); 183ded255beSTakashi Iwai codec->chip_name = newname; 184ded255beSTakashi Iwai return 0; 185ded255beSTakashi Iwai } 186ded255beSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_set_chip_name); 187ded255beSTakashi Iwai 188ded255beSTakashi Iwai /** 1894f9e0c38STakashi Iwai * snd_hdac_codec_modalias - give the module alias name 1904f9e0c38STakashi Iwai * @codec: HDAC device 1914f9e0c38STakashi Iwai * @buf: string buffer to store 1924f9e0c38STakashi Iwai * @size: string buffer size 1934f9e0c38STakashi Iwai * 1944f9e0c38STakashi Iwai * Returns the size of string, like snprintf(), or a negative error code. 1954f9e0c38STakashi Iwai */ 1964f9e0c38STakashi Iwai int snd_hdac_codec_modalias(struct hdac_device *codec, char *buf, size_t size) 1974f9e0c38STakashi Iwai { 1984f9e0c38STakashi Iwai return snprintf(buf, size, "hdaudio:v%08Xr%08Xa%02X\n", 1994f9e0c38STakashi Iwai codec->vendor_id, codec->revision_id, codec->type); 2004f9e0c38STakashi Iwai } 2014f9e0c38STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_codec_modalias); 2024f9e0c38STakashi Iwai 2034f9e0c38STakashi Iwai /** 2047639a06cSTakashi Iwai * snd_hdac_make_cmd - compose a 32bit command word to be sent to the 2057639a06cSTakashi Iwai * HD-audio controller 2067639a06cSTakashi Iwai * @codec: the codec object 2077639a06cSTakashi Iwai * @nid: NID to encode 2087639a06cSTakashi Iwai * @verb: verb to encode 2097639a06cSTakashi Iwai * @parm: parameter to encode 2107639a06cSTakashi Iwai * 2117639a06cSTakashi Iwai * Return an encoded command verb or -1 for error. 2127639a06cSTakashi Iwai */ 2137639a06cSTakashi Iwai unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, 2147639a06cSTakashi Iwai unsigned int verb, unsigned int parm) 2157639a06cSTakashi Iwai { 2167639a06cSTakashi Iwai u32 val, addr; 2177639a06cSTakashi Iwai 2187639a06cSTakashi Iwai addr = codec->addr; 2197639a06cSTakashi Iwai if ((addr & ~0xf) || (nid & ~0x7f) || 2207639a06cSTakashi Iwai (verb & ~0xfff) || (parm & ~0xffff)) { 2217639a06cSTakashi Iwai dev_err(&codec->dev, "out of range cmd %x:%x:%x:%x\n", 2227639a06cSTakashi Iwai addr, nid, verb, parm); 2237639a06cSTakashi Iwai return -1; 2247639a06cSTakashi Iwai } 2257639a06cSTakashi Iwai 2267639a06cSTakashi Iwai val = addr << 28; 2277639a06cSTakashi Iwai val |= (u32)nid << 20; 2287639a06cSTakashi Iwai val |= verb << 8; 2297639a06cSTakashi Iwai val |= parm; 2307639a06cSTakashi Iwai return val; 2317639a06cSTakashi Iwai } 2327639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_make_cmd); 2337639a06cSTakashi Iwai 2347639a06cSTakashi Iwai /** 23505852448STakashi Iwai * snd_hdac_exec_verb - execute an encoded verb 23605852448STakashi Iwai * @codec: the codec object 23705852448STakashi Iwai * @cmd: encoded verb to execute 23805852448STakashi Iwai * @flags: optional flags, pass zero for default 23905852448STakashi Iwai * @res: the pointer to store the result, NULL if running async 24005852448STakashi Iwai * 24105852448STakashi Iwai * Returns zero if successful, or a negative error code. 24205852448STakashi Iwai * 24305852448STakashi Iwai * This calls the exec_verb op when set in hdac_codec. If not, 24405852448STakashi Iwai * call the default snd_hdac_bus_exec_verb(). 24505852448STakashi Iwai */ 24605852448STakashi Iwai int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, 24705852448STakashi Iwai unsigned int flags, unsigned int *res) 24805852448STakashi Iwai { 24905852448STakashi Iwai if (codec->exec_verb) 25005852448STakashi Iwai return codec->exec_verb(codec, cmd, flags, res); 25105852448STakashi Iwai return snd_hdac_bus_exec_verb(codec->bus, codec->addr, cmd, res); 25205852448STakashi Iwai } 25305852448STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_exec_verb); 25405852448STakashi Iwai 25505852448STakashi Iwai 25605852448STakashi Iwai /** 2577639a06cSTakashi Iwai * snd_hdac_read - execute a verb 2587639a06cSTakashi Iwai * @codec: the codec object 2597639a06cSTakashi Iwai * @nid: NID to execute a verb 2607639a06cSTakashi Iwai * @verb: verb to execute 2617639a06cSTakashi Iwai * @parm: parameter for a verb 2627639a06cSTakashi Iwai * @res: the pointer to store the result, NULL if running async 2637639a06cSTakashi Iwai * 2647639a06cSTakashi Iwai * Returns zero if successful, or a negative error code. 2657639a06cSTakashi Iwai */ 2667639a06cSTakashi Iwai int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid, 2677639a06cSTakashi Iwai unsigned int verb, unsigned int parm, unsigned int *res) 2687639a06cSTakashi Iwai { 2697639a06cSTakashi Iwai unsigned int cmd = snd_hdac_make_cmd(codec, nid, verb, parm); 2707639a06cSTakashi Iwai 27105852448STakashi Iwai return snd_hdac_exec_verb(codec, cmd, 0, res); 2727639a06cSTakashi Iwai } 2737639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_read); 2747639a06cSTakashi Iwai 2757639a06cSTakashi Iwai /** 27601ed3c06STakashi Iwai * _snd_hdac_read_parm - read a parmeter 2777639a06cSTakashi Iwai * 27801ed3c06STakashi Iwai * This function returns zero or an error unlike snd_hdac_read_parm(). 2797639a06cSTakashi Iwai */ 28001ed3c06STakashi Iwai int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm, 28101ed3c06STakashi Iwai unsigned int *res) 2827639a06cSTakashi Iwai { 28301ed3c06STakashi Iwai unsigned int cmd; 2847639a06cSTakashi Iwai 28501ed3c06STakashi Iwai cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; 28601ed3c06STakashi Iwai return snd_hdac_regmap_read_raw(codec, cmd, res); 2877639a06cSTakashi Iwai } 28801ed3c06STakashi Iwai EXPORT_SYMBOL_GPL(_snd_hdac_read_parm); 2897639a06cSTakashi Iwai 2907639a06cSTakashi Iwai /** 2919ba17b4dSTakashi Iwai * snd_hdac_read_parm_uncached - read a codec parameter without caching 2927639a06cSTakashi Iwai * @codec: the codec object 2937639a06cSTakashi Iwai * @nid: NID to read a parameter 2947639a06cSTakashi Iwai * @parm: parameter to read 2957639a06cSTakashi Iwai * 2967639a06cSTakashi Iwai * Returns -1 for error. If you need to distinguish the error more 2977639a06cSTakashi Iwai * strictly, use snd_hdac_read() directly. 2987639a06cSTakashi Iwai */ 2999ba17b4dSTakashi Iwai int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, 3009ba17b4dSTakashi Iwai int parm) 3017639a06cSTakashi Iwai { 3027639a06cSTakashi Iwai int val; 3037639a06cSTakashi Iwai 3049ba17b4dSTakashi Iwai if (codec->regmap) 3059ba17b4dSTakashi Iwai regcache_cache_bypass(codec->regmap, true); 3069ba17b4dSTakashi Iwai val = snd_hdac_read_parm(codec, nid, parm); 3079ba17b4dSTakashi Iwai if (codec->regmap) 3089ba17b4dSTakashi Iwai regcache_cache_bypass(codec->regmap, false); 3097639a06cSTakashi Iwai return val; 3107639a06cSTakashi Iwai } 3119ba17b4dSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached); 3129ba17b4dSTakashi Iwai 3139ba17b4dSTakashi Iwai /** 314faa75f8aSTakashi Iwai * snd_hdac_override_parm - override read-only parameters 315faa75f8aSTakashi Iwai * @codec: the codec object 316faa75f8aSTakashi Iwai * @nid: NID for the parameter 317faa75f8aSTakashi Iwai * @parm: the parameter to change 318faa75f8aSTakashi Iwai * @val: the parameter value to overwrite 319faa75f8aSTakashi Iwai */ 320faa75f8aSTakashi Iwai int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid, 321faa75f8aSTakashi Iwai unsigned int parm, unsigned int val) 322faa75f8aSTakashi Iwai { 323faa75f8aSTakashi Iwai unsigned int verb = (AC_VERB_PARAMETERS << 8) | (nid << 20) | parm; 324faa75f8aSTakashi Iwai int err; 325faa75f8aSTakashi Iwai 326faa75f8aSTakashi Iwai if (!codec->regmap) 327faa75f8aSTakashi Iwai return -EINVAL; 328faa75f8aSTakashi Iwai 329faa75f8aSTakashi Iwai codec->caps_overwriting = true; 330faa75f8aSTakashi Iwai err = snd_hdac_regmap_write_raw(codec, verb, val); 331faa75f8aSTakashi Iwai codec->caps_overwriting = false; 332faa75f8aSTakashi Iwai return err; 333faa75f8aSTakashi Iwai } 334faa75f8aSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_override_parm); 3357639a06cSTakashi Iwai 3367639a06cSTakashi Iwai /** 3377639a06cSTakashi Iwai * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes 3387639a06cSTakashi Iwai * @codec: the codec object 3397639a06cSTakashi Iwai * @nid: NID to inspect 3407639a06cSTakashi Iwai * @start_id: the pointer to store the starting NID 3417639a06cSTakashi Iwai * 3427639a06cSTakashi Iwai * Returns the number of subtree nodes or zero if not found. 3439ba17b4dSTakashi Iwai * This function reads parameters always without caching. 3447639a06cSTakashi Iwai */ 3457639a06cSTakashi Iwai int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, 3467639a06cSTakashi Iwai hda_nid_t *start_id) 3477639a06cSTakashi Iwai { 3487639a06cSTakashi Iwai unsigned int parm; 3497639a06cSTakashi Iwai 3509ba17b4dSTakashi Iwai parm = snd_hdac_read_parm_uncached(codec, nid, AC_PAR_NODE_COUNT); 3517639a06cSTakashi Iwai if (parm == -1) { 3527639a06cSTakashi Iwai *start_id = 0; 3537639a06cSTakashi Iwai return 0; 3547639a06cSTakashi Iwai } 3557639a06cSTakashi Iwai *start_id = (parm >> 16) & 0x7fff; 3567639a06cSTakashi Iwai return (int)(parm & 0x7fff); 3577639a06cSTakashi Iwai } 3587639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_sub_nodes); 3597639a06cSTakashi Iwai 3607639a06cSTakashi Iwai /* 3617639a06cSTakashi Iwai * look for an AFG and MFG nodes 3627639a06cSTakashi Iwai */ 3637639a06cSTakashi Iwai static void setup_fg_nodes(struct hdac_device *codec) 3647639a06cSTakashi Iwai { 3657639a06cSTakashi Iwai int i, total_nodes, function_id; 3667639a06cSTakashi Iwai hda_nid_t nid; 3677639a06cSTakashi Iwai 3687639a06cSTakashi Iwai total_nodes = snd_hdac_get_sub_nodes(codec, AC_NODE_ROOT, &nid); 3697639a06cSTakashi Iwai for (i = 0; i < total_nodes; i++, nid++) { 3707639a06cSTakashi Iwai function_id = snd_hdac_read_parm(codec, nid, 3717639a06cSTakashi Iwai AC_PAR_FUNCTION_TYPE); 3727639a06cSTakashi Iwai switch (function_id & 0xff) { 3737639a06cSTakashi Iwai case AC_GRP_AUDIO_FUNCTION: 3747639a06cSTakashi Iwai codec->afg = nid; 3757639a06cSTakashi Iwai codec->afg_function_id = function_id & 0xff; 3767639a06cSTakashi Iwai codec->afg_unsol = (function_id >> 8) & 1; 3777639a06cSTakashi Iwai break; 3787639a06cSTakashi Iwai case AC_GRP_MODEM_FUNCTION: 3797639a06cSTakashi Iwai codec->mfg = nid; 3807639a06cSTakashi Iwai codec->mfg_function_id = function_id & 0xff; 3817639a06cSTakashi Iwai codec->mfg_unsol = (function_id >> 8) & 1; 3827639a06cSTakashi Iwai break; 3837639a06cSTakashi Iwai default: 3847639a06cSTakashi Iwai break; 3857639a06cSTakashi Iwai } 3867639a06cSTakashi Iwai } 3877639a06cSTakashi Iwai } 3887639a06cSTakashi Iwai 3897639a06cSTakashi Iwai /** 3907639a06cSTakashi Iwai * snd_hdac_refresh_widgets - Reset the widget start/end nodes 3917639a06cSTakashi Iwai * @codec: the codec object 3927639a06cSTakashi Iwai */ 3937639a06cSTakashi Iwai int snd_hdac_refresh_widgets(struct hdac_device *codec) 3947639a06cSTakashi Iwai { 3957639a06cSTakashi Iwai hda_nid_t start_nid; 3967639a06cSTakashi Iwai int nums; 3977639a06cSTakashi Iwai 3987639a06cSTakashi Iwai nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); 3997639a06cSTakashi Iwai if (!start_nid || nums <= 0 || nums >= 0xff) { 4007639a06cSTakashi Iwai dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n", 4017639a06cSTakashi Iwai codec->afg); 4027639a06cSTakashi Iwai return -EINVAL; 4037639a06cSTakashi Iwai } 4047639a06cSTakashi Iwai 4057639a06cSTakashi Iwai codec->num_nodes = nums; 4067639a06cSTakashi Iwai codec->start_nid = start_nid; 4077639a06cSTakashi Iwai codec->end_nid = start_nid + nums; 4087639a06cSTakashi Iwai return 0; 4097639a06cSTakashi Iwai } 4107639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); 4117639a06cSTakashi Iwai 41218dfd79dSVinod Koul /** 41318dfd79dSVinod Koul * snd_hdac_refresh_widget_sysfs - Reset the codec widgets and reinit the 41418dfd79dSVinod Koul * codec sysfs 41518dfd79dSVinod Koul * @codec: the codec object 41618dfd79dSVinod Koul * 41718dfd79dSVinod Koul * first we need to remove sysfs, then refresh widgets and lastly 41818dfd79dSVinod Koul * recreate it 41918dfd79dSVinod Koul */ 42018dfd79dSVinod Koul int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec) 42118dfd79dSVinod Koul { 42218dfd79dSVinod Koul int ret; 42318dfd79dSVinod Koul 424a92d5ee8STakashi Iwai if (device_is_registered(&codec->dev)) 42518dfd79dSVinod Koul hda_widget_sysfs_exit(codec); 42618dfd79dSVinod Koul ret = snd_hdac_refresh_widgets(codec); 42718dfd79dSVinod Koul if (ret) { 42818dfd79dSVinod Koul dev_err(&codec->dev, "failed to refresh widget: %d\n", ret); 42918dfd79dSVinod Koul return ret; 43018dfd79dSVinod Koul } 431a92d5ee8STakashi Iwai if (device_is_registered(&codec->dev)) { 43218dfd79dSVinod Koul ret = hda_widget_sysfs_init(codec); 43318dfd79dSVinod Koul if (ret) { 43418dfd79dSVinod Koul dev_err(&codec->dev, "failed to init sysfs: %d\n", ret); 43518dfd79dSVinod Koul return ret; 43618dfd79dSVinod Koul } 437a92d5ee8STakashi Iwai } 43818dfd79dSVinod Koul return ret; 43918dfd79dSVinod Koul } 44018dfd79dSVinod Koul EXPORT_SYMBOL_GPL(snd_hdac_refresh_widget_sysfs); 44118dfd79dSVinod Koul 4427639a06cSTakashi Iwai /* return CONNLIST_LEN parameter of the given widget */ 4437639a06cSTakashi Iwai static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) 4447639a06cSTakashi Iwai { 4457639a06cSTakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 4467639a06cSTakashi Iwai unsigned int parm; 4477639a06cSTakashi Iwai 4487639a06cSTakashi Iwai if (!(wcaps & AC_WCAP_CONN_LIST) && 4497639a06cSTakashi Iwai get_wcaps_type(wcaps) != AC_WID_VOL_KNB) 4507639a06cSTakashi Iwai return 0; 4517639a06cSTakashi Iwai 4527639a06cSTakashi Iwai parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN); 4537639a06cSTakashi Iwai if (parm == -1) 4547639a06cSTakashi Iwai parm = 0; 4557639a06cSTakashi Iwai return parm; 4567639a06cSTakashi Iwai } 4577639a06cSTakashi Iwai 4587639a06cSTakashi Iwai /** 4597639a06cSTakashi Iwai * snd_hdac_get_connections - get a widget connection list 4607639a06cSTakashi Iwai * @codec: the codec object 4617639a06cSTakashi Iwai * @nid: NID 4627639a06cSTakashi Iwai * @conn_list: the array to store the results, can be NULL 4637639a06cSTakashi Iwai * @max_conns: the max size of the given array 4647639a06cSTakashi Iwai * 4657639a06cSTakashi Iwai * Returns the number of connected widgets, zero for no connection, or a 4667639a06cSTakashi Iwai * negative error code. When the number of elements don't fit with the 4677639a06cSTakashi Iwai * given array size, it returns -ENOSPC. 4687639a06cSTakashi Iwai * 4697639a06cSTakashi Iwai * When @conn_list is NULL, it just checks the number of connections. 4707639a06cSTakashi Iwai */ 4717639a06cSTakashi Iwai int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, 4727639a06cSTakashi Iwai hda_nid_t *conn_list, int max_conns) 4737639a06cSTakashi Iwai { 4747639a06cSTakashi Iwai unsigned int parm; 4757639a06cSTakashi Iwai int i, conn_len, conns, err; 4767639a06cSTakashi Iwai unsigned int shift, num_elems, mask; 4777639a06cSTakashi Iwai hda_nid_t prev_nid; 4787639a06cSTakashi Iwai int null_count = 0; 4797639a06cSTakashi Iwai 4807639a06cSTakashi Iwai parm = get_num_conns(codec, nid); 4817639a06cSTakashi Iwai if (!parm) 4827639a06cSTakashi Iwai return 0; 4837639a06cSTakashi Iwai 4847639a06cSTakashi Iwai if (parm & AC_CLIST_LONG) { 4857639a06cSTakashi Iwai /* long form */ 4867639a06cSTakashi Iwai shift = 16; 4877639a06cSTakashi Iwai num_elems = 2; 4887639a06cSTakashi Iwai } else { 4897639a06cSTakashi Iwai /* short form */ 4907639a06cSTakashi Iwai shift = 8; 4917639a06cSTakashi Iwai num_elems = 4; 4927639a06cSTakashi Iwai } 4937639a06cSTakashi Iwai conn_len = parm & AC_CLIST_LENGTH; 4947639a06cSTakashi Iwai mask = (1 << (shift-1)) - 1; 4957639a06cSTakashi Iwai 4967639a06cSTakashi Iwai if (!conn_len) 4977639a06cSTakashi Iwai return 0; /* no connection */ 4987639a06cSTakashi Iwai 4997639a06cSTakashi Iwai if (conn_len == 1) { 5007639a06cSTakashi Iwai /* single connection */ 5017639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, AC_VERB_GET_CONNECT_LIST, 0, 5027639a06cSTakashi Iwai &parm); 5037639a06cSTakashi Iwai if (err < 0) 5047639a06cSTakashi Iwai return err; 5057639a06cSTakashi Iwai if (conn_list) 5067639a06cSTakashi Iwai conn_list[0] = parm & mask; 5077639a06cSTakashi Iwai return 1; 5087639a06cSTakashi Iwai } 5097639a06cSTakashi Iwai 5107639a06cSTakashi Iwai /* multi connection */ 5117639a06cSTakashi Iwai conns = 0; 5127639a06cSTakashi Iwai prev_nid = 0; 5137639a06cSTakashi Iwai for (i = 0; i < conn_len; i++) { 5147639a06cSTakashi Iwai int range_val; 5157639a06cSTakashi Iwai hda_nid_t val, n; 5167639a06cSTakashi Iwai 5177639a06cSTakashi Iwai if (i % num_elems == 0) { 5187639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, 5197639a06cSTakashi Iwai AC_VERB_GET_CONNECT_LIST, i, 5207639a06cSTakashi Iwai &parm); 5217639a06cSTakashi Iwai if (err < 0) 5227639a06cSTakashi Iwai return -EIO; 5237639a06cSTakashi Iwai } 5247639a06cSTakashi Iwai range_val = !!(parm & (1 << (shift-1))); /* ranges */ 5257639a06cSTakashi Iwai val = parm & mask; 5267639a06cSTakashi Iwai if (val == 0 && null_count++) { /* no second chance */ 5277639a06cSTakashi Iwai dev_dbg(&codec->dev, 5287639a06cSTakashi Iwai "invalid CONNECT_LIST verb %x[%i]:%x\n", 5297639a06cSTakashi Iwai nid, i, parm); 5307639a06cSTakashi Iwai return 0; 5317639a06cSTakashi Iwai } 5327639a06cSTakashi Iwai parm >>= shift; 5337639a06cSTakashi Iwai if (range_val) { 5347639a06cSTakashi Iwai /* ranges between the previous and this one */ 5357639a06cSTakashi Iwai if (!prev_nid || prev_nid >= val) { 5367639a06cSTakashi Iwai dev_warn(&codec->dev, 5377639a06cSTakashi Iwai "invalid dep_range_val %x:%x\n", 5387639a06cSTakashi Iwai prev_nid, val); 5397639a06cSTakashi Iwai continue; 5407639a06cSTakashi Iwai } 5417639a06cSTakashi Iwai for (n = prev_nid + 1; n <= val; n++) { 5427639a06cSTakashi Iwai if (conn_list) { 5437639a06cSTakashi Iwai if (conns >= max_conns) 5447639a06cSTakashi Iwai return -ENOSPC; 5457639a06cSTakashi Iwai conn_list[conns] = n; 5467639a06cSTakashi Iwai } 5477639a06cSTakashi Iwai conns++; 5487639a06cSTakashi Iwai } 5497639a06cSTakashi Iwai } else { 5507639a06cSTakashi Iwai if (conn_list) { 5517639a06cSTakashi Iwai if (conns >= max_conns) 5527639a06cSTakashi Iwai return -ENOSPC; 5537639a06cSTakashi Iwai conn_list[conns] = val; 5547639a06cSTakashi Iwai } 5557639a06cSTakashi Iwai conns++; 5567639a06cSTakashi Iwai } 5577639a06cSTakashi Iwai prev_nid = val; 5587639a06cSTakashi Iwai } 5597639a06cSTakashi Iwai return conns; 5607639a06cSTakashi Iwai } 5617639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_connections); 5627639a06cSTakashi Iwai 5637639a06cSTakashi Iwai #ifdef CONFIG_PM 5647639a06cSTakashi Iwai /** 565664c7155STakashi Iwai * snd_hdac_power_up - power up the codec 5667639a06cSTakashi Iwai * @codec: the codec object 567664c7155STakashi Iwai * 568664c7155STakashi Iwai * This function calls the runtime PM helper to power up the given codec. 569664c7155STakashi Iwai * Unlike snd_hdac_power_up_pm(), you should call this only for the code 570664c7155STakashi Iwai * path that isn't included in PM path. Otherwise it gets stuck. 571fbce23a0STakashi Iwai * 572fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 5737639a06cSTakashi Iwai */ 574fbce23a0STakashi Iwai int snd_hdac_power_up(struct hdac_device *codec) 5757639a06cSTakashi Iwai { 576fbce23a0STakashi Iwai return pm_runtime_get_sync(&codec->dev); 5777639a06cSTakashi Iwai } 5787639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_up); 5797639a06cSTakashi Iwai 5807639a06cSTakashi Iwai /** 581664c7155STakashi Iwai * snd_hdac_power_down - power down the codec 5827639a06cSTakashi Iwai * @codec: the codec object 583fbce23a0STakashi Iwai * 584fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 5857639a06cSTakashi Iwai */ 586fbce23a0STakashi Iwai int snd_hdac_power_down(struct hdac_device *codec) 5877639a06cSTakashi Iwai { 5887639a06cSTakashi Iwai struct device *dev = &codec->dev; 5897639a06cSTakashi Iwai 5907639a06cSTakashi Iwai pm_runtime_mark_last_busy(dev); 591fbce23a0STakashi Iwai return pm_runtime_put_autosuspend(dev); 5927639a06cSTakashi Iwai } 5937639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_down); 594c3aeda62STakashi Iwai 595c3aeda62STakashi Iwai /** 596c3aeda62STakashi Iwai * snd_hdac_power_up_pm - power up the codec 597c3aeda62STakashi Iwai * @codec: the codec object 598c3aeda62STakashi Iwai * 599c3aeda62STakashi Iwai * This function can be called in a recursive code path like init code 600c3aeda62STakashi Iwai * which may be called by PM suspend/resume again. OTOH, if a power-up 601c3aeda62STakashi Iwai * call must wake up the sleeper (e.g. in a kctl callback), use 602c3aeda62STakashi Iwai * snd_hdac_power_up() instead. 603fbce23a0STakashi Iwai * 604fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 605c3aeda62STakashi Iwai */ 606fbce23a0STakashi Iwai int snd_hdac_power_up_pm(struct hdac_device *codec) 607c3aeda62STakashi Iwai { 608c3aeda62STakashi Iwai if (!atomic_inc_not_zero(&codec->in_pm)) 609fbce23a0STakashi Iwai return snd_hdac_power_up(codec); 610fbce23a0STakashi Iwai return 0; 611c3aeda62STakashi Iwai } 612c3aeda62STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm); 613c3aeda62STakashi Iwai 614*fc4f000bSTakashi Iwai /* like snd_hdac_power_up_pm(), but only increment the pm count when 615*fc4f000bSTakashi Iwai * already powered up. Returns -1 if not powered up, 1 if incremented 616*fc4f000bSTakashi Iwai * or 0 if unchanged. Only used in hdac_regmap.c 617*fc4f000bSTakashi Iwai */ 618*fc4f000bSTakashi Iwai int snd_hdac_keep_power_up(struct hdac_device *codec) 619*fc4f000bSTakashi Iwai { 620*fc4f000bSTakashi Iwai if (!atomic_inc_not_zero(&codec->in_pm)) { 621*fc4f000bSTakashi Iwai int ret = pm_runtime_get_if_in_use(&codec->dev); 622*fc4f000bSTakashi Iwai if (!ret) 623*fc4f000bSTakashi Iwai return -1; 624*fc4f000bSTakashi Iwai if (ret < 0) 625*fc4f000bSTakashi Iwai return 0; 626*fc4f000bSTakashi Iwai } 627*fc4f000bSTakashi Iwai return 1; 628*fc4f000bSTakashi Iwai } 629*fc4f000bSTakashi Iwai 630c3aeda62STakashi Iwai /** 631c3aeda62STakashi Iwai * snd_hdac_power_down_pm - power down the codec 632c3aeda62STakashi Iwai * @codec: the codec object 633c3aeda62STakashi Iwai * 634c3aeda62STakashi Iwai * Like snd_hdac_power_up_pm(), this function is used in a recursive 635c3aeda62STakashi Iwai * code path like init code which may be called by PM suspend/resume again. 636fbce23a0STakashi Iwai * 637fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 638c3aeda62STakashi Iwai */ 639fbce23a0STakashi Iwai int snd_hdac_power_down_pm(struct hdac_device *codec) 640c3aeda62STakashi Iwai { 641c3aeda62STakashi Iwai if (atomic_dec_if_positive(&codec->in_pm) < 0) 642fbce23a0STakashi Iwai return snd_hdac_power_down(codec); 643fbce23a0STakashi Iwai return 0; 644c3aeda62STakashi Iwai } 645c3aeda62STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); 6467639a06cSTakashi Iwai #endif 6477639a06cSTakashi Iwai 64878dd5e21STakashi Iwai /** 64978dd5e21STakashi Iwai * snd_hdac_link_power - Enable/disable the link power for a codec 65078dd5e21STakashi Iwai * @codec: the codec object 65178dd5e21STakashi Iwai * @bool: enable or disable the link power 652a5e7e07cSMengdong Lin */ 653a5e7e07cSMengdong Lin int snd_hdac_link_power(struct hdac_device *codec, bool enable) 654a5e7e07cSMengdong Lin { 655a5e7e07cSMengdong Lin if (!codec->link_power_control) 656a5e7e07cSMengdong Lin return 0; 657a5e7e07cSMengdong Lin 658a5e7e07cSMengdong Lin if (codec->bus->ops->link_power) 659a5e7e07cSMengdong Lin return codec->bus->ops->link_power(codec->bus, enable); 660a5e7e07cSMengdong Lin else 661a5e7e07cSMengdong Lin return -EINVAL; 662a5e7e07cSMengdong Lin } 663a5e7e07cSMengdong Lin EXPORT_SYMBOL_GPL(snd_hdac_link_power); 664a5e7e07cSMengdong Lin 6657639a06cSTakashi Iwai /* codec vendor labels */ 6667639a06cSTakashi Iwai struct hda_vendor_id { 6677639a06cSTakashi Iwai unsigned int id; 6687639a06cSTakashi Iwai const char *name; 6697639a06cSTakashi Iwai }; 6707639a06cSTakashi Iwai 6717639a06cSTakashi Iwai static struct hda_vendor_id hda_vendor_ids[] = { 6727639a06cSTakashi Iwai { 0x1002, "ATI" }, 6737639a06cSTakashi Iwai { 0x1013, "Cirrus Logic" }, 6747639a06cSTakashi Iwai { 0x1057, "Motorola" }, 6757639a06cSTakashi Iwai { 0x1095, "Silicon Image" }, 6767639a06cSTakashi Iwai { 0x10de, "Nvidia" }, 6777639a06cSTakashi Iwai { 0x10ec, "Realtek" }, 6787639a06cSTakashi Iwai { 0x1102, "Creative" }, 6797639a06cSTakashi Iwai { 0x1106, "VIA" }, 6807639a06cSTakashi Iwai { 0x111d, "IDT" }, 6817639a06cSTakashi Iwai { 0x11c1, "LSI" }, 6827639a06cSTakashi Iwai { 0x11d4, "Analog Devices" }, 6837639a06cSTakashi Iwai { 0x13f6, "C-Media" }, 6847639a06cSTakashi Iwai { 0x14f1, "Conexant" }, 6857639a06cSTakashi Iwai { 0x17e8, "Chrontel" }, 6867639a06cSTakashi Iwai { 0x1854, "LG" }, 6877639a06cSTakashi Iwai { 0x1aec, "Wolfson Microelectronics" }, 6887639a06cSTakashi Iwai { 0x1af4, "QEMU" }, 6897639a06cSTakashi Iwai { 0x434d, "C-Media" }, 6907639a06cSTakashi Iwai { 0x8086, "Intel" }, 6917639a06cSTakashi Iwai { 0x8384, "SigmaTel" }, 6927639a06cSTakashi Iwai {} /* terminator */ 6937639a06cSTakashi Iwai }; 6947639a06cSTakashi Iwai 6957639a06cSTakashi Iwai /* store the codec vendor name */ 6967639a06cSTakashi Iwai static int get_codec_vendor_name(struct hdac_device *codec) 6977639a06cSTakashi Iwai { 6987639a06cSTakashi Iwai const struct hda_vendor_id *c; 6997639a06cSTakashi Iwai u16 vendor_id = codec->vendor_id >> 16; 7007639a06cSTakashi Iwai 7017639a06cSTakashi Iwai for (c = hda_vendor_ids; c->id; c++) { 7027639a06cSTakashi Iwai if (c->id == vendor_id) { 7037639a06cSTakashi Iwai codec->vendor_name = kstrdup(c->name, GFP_KERNEL); 7047639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 7057639a06cSTakashi Iwai } 7067639a06cSTakashi Iwai } 7077639a06cSTakashi Iwai 7087639a06cSTakashi Iwai codec->vendor_name = kasprintf(GFP_KERNEL, "Generic %04x", vendor_id); 7097639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 7107639a06cSTakashi Iwai } 711b7d023e1STakashi Iwai 712b7d023e1STakashi Iwai /* 713b7d023e1STakashi Iwai * stream formats 714b7d023e1STakashi Iwai */ 715b7d023e1STakashi Iwai struct hda_rate_tbl { 716b7d023e1STakashi Iwai unsigned int hz; 717b7d023e1STakashi Iwai unsigned int alsa_bits; 718b7d023e1STakashi Iwai unsigned int hda_fmt; 719b7d023e1STakashi Iwai }; 720b7d023e1STakashi Iwai 721b7d023e1STakashi Iwai /* rate = base * mult / div */ 722b7d023e1STakashi Iwai #define HDA_RATE(base, mult, div) \ 723b7d023e1STakashi Iwai (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ 724b7d023e1STakashi Iwai (((div) - 1) << AC_FMT_DIV_SHIFT)) 725b7d023e1STakashi Iwai 726b7d023e1STakashi Iwai static struct hda_rate_tbl rate_bits[] = { 727b7d023e1STakashi Iwai /* rate in Hz, ALSA rate bitmask, HDA format value */ 728b7d023e1STakashi Iwai 729b7d023e1STakashi Iwai /* autodetected value used in snd_hda_query_supported_pcm */ 730b7d023e1STakashi Iwai { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) }, 731b7d023e1STakashi Iwai { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) }, 732b7d023e1STakashi Iwai { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) }, 733b7d023e1STakashi Iwai { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) }, 734b7d023e1STakashi Iwai { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) }, 735b7d023e1STakashi Iwai { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) }, 736b7d023e1STakashi Iwai { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) }, 737b7d023e1STakashi Iwai { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) }, 738b7d023e1STakashi Iwai { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) }, 739b7d023e1STakashi Iwai { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) }, 740b7d023e1STakashi Iwai { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) }, 741b7d023e1STakashi Iwai #define AC_PAR_PCM_RATE_BITS 11 742b7d023e1STakashi Iwai /* up to bits 10, 384kHZ isn't supported properly */ 743b7d023e1STakashi Iwai 744b7d023e1STakashi Iwai /* not autodetected value */ 745b7d023e1STakashi Iwai { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) }, 746b7d023e1STakashi Iwai 747b7d023e1STakashi Iwai { 0 } /* terminator */ 748b7d023e1STakashi Iwai }; 749b7d023e1STakashi Iwai 750b7d023e1STakashi Iwai /** 751b7d023e1STakashi Iwai * snd_hdac_calc_stream_format - calculate the format bitset 752b7d023e1STakashi Iwai * @rate: the sample rate 753b7d023e1STakashi Iwai * @channels: the number of channels 754b7d023e1STakashi Iwai * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) 755b7d023e1STakashi Iwai * @maxbps: the max. bps 756b7d023e1STakashi Iwai * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant) 757b7d023e1STakashi Iwai * 758b7d023e1STakashi Iwai * Calculate the format bitset from the given rate, channels and th PCM format. 759b7d023e1STakashi Iwai * 760b7d023e1STakashi Iwai * Return zero if invalid. 761b7d023e1STakashi Iwai */ 762b7d023e1STakashi Iwai unsigned int snd_hdac_calc_stream_format(unsigned int rate, 763b7d023e1STakashi Iwai unsigned int channels, 764b7d023e1STakashi Iwai unsigned int format, 765b7d023e1STakashi Iwai unsigned int maxbps, 766b7d023e1STakashi Iwai unsigned short spdif_ctls) 767b7d023e1STakashi Iwai { 768b7d023e1STakashi Iwai int i; 769b7d023e1STakashi Iwai unsigned int val = 0; 770b7d023e1STakashi Iwai 771b7d023e1STakashi Iwai for (i = 0; rate_bits[i].hz; i++) 772b7d023e1STakashi Iwai if (rate_bits[i].hz == rate) { 773b7d023e1STakashi Iwai val = rate_bits[i].hda_fmt; 774b7d023e1STakashi Iwai break; 775b7d023e1STakashi Iwai } 776b7d023e1STakashi Iwai if (!rate_bits[i].hz) 777b7d023e1STakashi Iwai return 0; 778b7d023e1STakashi Iwai 779b7d023e1STakashi Iwai if (channels == 0 || channels > 8) 780b7d023e1STakashi Iwai return 0; 781b7d023e1STakashi Iwai val |= channels - 1; 782b7d023e1STakashi Iwai 783b7d023e1STakashi Iwai switch (snd_pcm_format_width(format)) { 784b7d023e1STakashi Iwai case 8: 785b7d023e1STakashi Iwai val |= AC_FMT_BITS_8; 786b7d023e1STakashi Iwai break; 787b7d023e1STakashi Iwai case 16: 788b7d023e1STakashi Iwai val |= AC_FMT_BITS_16; 789b7d023e1STakashi Iwai break; 790b7d023e1STakashi Iwai case 20: 791b7d023e1STakashi Iwai case 24: 792b7d023e1STakashi Iwai case 32: 793b7d023e1STakashi Iwai if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) 794b7d023e1STakashi Iwai val |= AC_FMT_BITS_32; 795b7d023e1STakashi Iwai else if (maxbps >= 24) 796b7d023e1STakashi Iwai val |= AC_FMT_BITS_24; 797b7d023e1STakashi Iwai else 798b7d023e1STakashi Iwai val |= AC_FMT_BITS_20; 799b7d023e1STakashi Iwai break; 800b7d023e1STakashi Iwai default: 801b7d023e1STakashi Iwai return 0; 802b7d023e1STakashi Iwai } 803b7d023e1STakashi Iwai 804b7d023e1STakashi Iwai if (spdif_ctls & AC_DIG1_NONAUDIO) 805b7d023e1STakashi Iwai val |= AC_FMT_TYPE_NON_PCM; 806b7d023e1STakashi Iwai 807b7d023e1STakashi Iwai return val; 808b7d023e1STakashi Iwai } 809b7d023e1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_calc_stream_format); 810b7d023e1STakashi Iwai 811b7d023e1STakashi Iwai static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid) 812b7d023e1STakashi Iwai { 813b7d023e1STakashi Iwai unsigned int val = 0; 814b7d023e1STakashi Iwai 815b7d023e1STakashi Iwai if (nid != codec->afg && 816b7d023e1STakashi Iwai (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) 817b7d023e1STakashi Iwai val = snd_hdac_read_parm(codec, nid, AC_PAR_PCM); 818b7d023e1STakashi Iwai if (!val || val == -1) 819b7d023e1STakashi Iwai val = snd_hdac_read_parm(codec, codec->afg, AC_PAR_PCM); 820b7d023e1STakashi Iwai if (!val || val == -1) 821b7d023e1STakashi Iwai return 0; 822b7d023e1STakashi Iwai return val; 823b7d023e1STakashi Iwai } 824b7d023e1STakashi Iwai 825b7d023e1STakashi Iwai static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid) 826b7d023e1STakashi Iwai { 827b7d023e1STakashi Iwai unsigned int streams = snd_hdac_read_parm(codec, nid, AC_PAR_STREAM); 828b7d023e1STakashi Iwai 829b7d023e1STakashi Iwai if (!streams || streams == -1) 830b7d023e1STakashi Iwai streams = snd_hdac_read_parm(codec, codec->afg, AC_PAR_STREAM); 831b7d023e1STakashi Iwai if (!streams || streams == -1) 832b7d023e1STakashi Iwai return 0; 833b7d023e1STakashi Iwai return streams; 834b7d023e1STakashi Iwai } 835b7d023e1STakashi Iwai 836b7d023e1STakashi Iwai /** 837b7d023e1STakashi Iwai * snd_hdac_query_supported_pcm - query the supported PCM rates and formats 838b7d023e1STakashi Iwai * @codec: the codec object 839b7d023e1STakashi Iwai * @nid: NID to query 840b7d023e1STakashi Iwai * @ratesp: the pointer to store the detected rate bitflags 841b7d023e1STakashi Iwai * @formatsp: the pointer to store the detected formats 842b7d023e1STakashi Iwai * @bpsp: the pointer to store the detected format widths 843b7d023e1STakashi Iwai * 844b7d023e1STakashi Iwai * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp 845b7d023e1STakashi Iwai * or @bsps argument is ignored. 846b7d023e1STakashi Iwai * 847b7d023e1STakashi Iwai * Returns 0 if successful, otherwise a negative error code. 848b7d023e1STakashi Iwai */ 849b7d023e1STakashi Iwai int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, 850b7d023e1STakashi Iwai u32 *ratesp, u64 *formatsp, unsigned int *bpsp) 851b7d023e1STakashi Iwai { 852b7d023e1STakashi Iwai unsigned int i, val, wcaps; 853b7d023e1STakashi Iwai 854b7d023e1STakashi Iwai wcaps = get_wcaps(codec, nid); 855b7d023e1STakashi Iwai val = query_pcm_param(codec, nid); 856b7d023e1STakashi Iwai 857b7d023e1STakashi Iwai if (ratesp) { 858b7d023e1STakashi Iwai u32 rates = 0; 859b7d023e1STakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) { 860b7d023e1STakashi Iwai if (val & (1 << i)) 861b7d023e1STakashi Iwai rates |= rate_bits[i].alsa_bits; 862b7d023e1STakashi Iwai } 863b7d023e1STakashi Iwai if (rates == 0) { 864b7d023e1STakashi Iwai dev_err(&codec->dev, 865b7d023e1STakashi Iwai "rates == 0 (nid=0x%x, val=0x%x, ovrd=%i)\n", 866b7d023e1STakashi Iwai nid, val, 867b7d023e1STakashi Iwai (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); 868b7d023e1STakashi Iwai return -EIO; 869b7d023e1STakashi Iwai } 870b7d023e1STakashi Iwai *ratesp = rates; 871b7d023e1STakashi Iwai } 872b7d023e1STakashi Iwai 873b7d023e1STakashi Iwai if (formatsp || bpsp) { 874b7d023e1STakashi Iwai u64 formats = 0; 875b7d023e1STakashi Iwai unsigned int streams, bps; 876b7d023e1STakashi Iwai 877b7d023e1STakashi Iwai streams = query_stream_param(codec, nid); 878b7d023e1STakashi Iwai if (!streams) 879b7d023e1STakashi Iwai return -EIO; 880b7d023e1STakashi Iwai 881b7d023e1STakashi Iwai bps = 0; 882b7d023e1STakashi Iwai if (streams & AC_SUPFMT_PCM) { 883b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_8) { 884b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_U8; 885b7d023e1STakashi Iwai bps = 8; 886b7d023e1STakashi Iwai } 887b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_16) { 888b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_S16_LE; 889b7d023e1STakashi Iwai bps = 16; 890b7d023e1STakashi Iwai } 891b7d023e1STakashi Iwai if (wcaps & AC_WCAP_DIGITAL) { 892b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_32) 893b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; 894b7d023e1STakashi Iwai if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) 895b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_S32_LE; 896b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_24) 897b7d023e1STakashi Iwai bps = 24; 898b7d023e1STakashi Iwai else if (val & AC_SUPPCM_BITS_20) 899b7d023e1STakashi Iwai bps = 20; 900b7d023e1STakashi Iwai } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24| 901b7d023e1STakashi Iwai AC_SUPPCM_BITS_32)) { 902b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_S32_LE; 903b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_32) 904b7d023e1STakashi Iwai bps = 32; 905b7d023e1STakashi Iwai else if (val & AC_SUPPCM_BITS_24) 906b7d023e1STakashi Iwai bps = 24; 907b7d023e1STakashi Iwai else if (val & AC_SUPPCM_BITS_20) 908b7d023e1STakashi Iwai bps = 20; 909b7d023e1STakashi Iwai } 910b7d023e1STakashi Iwai } 911b7d023e1STakashi Iwai #if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */ 912b7d023e1STakashi Iwai if (streams & AC_SUPFMT_FLOAT32) { 913b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; 914b7d023e1STakashi Iwai if (!bps) 915b7d023e1STakashi Iwai bps = 32; 916b7d023e1STakashi Iwai } 917b7d023e1STakashi Iwai #endif 918b7d023e1STakashi Iwai if (streams == AC_SUPFMT_AC3) { 919b7d023e1STakashi Iwai /* should be exclusive */ 920b7d023e1STakashi Iwai /* temporary hack: we have still no proper support 921b7d023e1STakashi Iwai * for the direct AC3 stream... 922b7d023e1STakashi Iwai */ 923b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_U8; 924b7d023e1STakashi Iwai bps = 8; 925b7d023e1STakashi Iwai } 926b7d023e1STakashi Iwai if (formats == 0) { 927b7d023e1STakashi Iwai dev_err(&codec->dev, 928b7d023e1STakashi Iwai "formats == 0 (nid=0x%x, val=0x%x, ovrd=%i, streams=0x%x)\n", 929b7d023e1STakashi Iwai nid, val, 930b7d023e1STakashi Iwai (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, 931b7d023e1STakashi Iwai streams); 932b7d023e1STakashi Iwai return -EIO; 933b7d023e1STakashi Iwai } 934b7d023e1STakashi Iwai if (formatsp) 935b7d023e1STakashi Iwai *formatsp = formats; 936b7d023e1STakashi Iwai if (bpsp) 937b7d023e1STakashi Iwai *bpsp = bps; 938b7d023e1STakashi Iwai } 939b7d023e1STakashi Iwai 940b7d023e1STakashi Iwai return 0; 941b7d023e1STakashi Iwai } 942b7d023e1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_query_supported_pcm); 943b7d023e1STakashi Iwai 944b7d023e1STakashi Iwai /** 945b7d023e1STakashi Iwai * snd_hdac_is_supported_format - Check the validity of the format 946b7d023e1STakashi Iwai * @codec: the codec object 947b7d023e1STakashi Iwai * @nid: NID to check 948b7d023e1STakashi Iwai * @format: the HD-audio format value to check 949b7d023e1STakashi Iwai * 950b7d023e1STakashi Iwai * Check whether the given node supports the format value. 951b7d023e1STakashi Iwai * 952b7d023e1STakashi Iwai * Returns true if supported, false if not. 953b7d023e1STakashi Iwai */ 954b7d023e1STakashi Iwai bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid, 955b7d023e1STakashi Iwai unsigned int format) 956b7d023e1STakashi Iwai { 957b7d023e1STakashi Iwai int i; 958b7d023e1STakashi Iwai unsigned int val = 0, rate, stream; 959b7d023e1STakashi Iwai 960b7d023e1STakashi Iwai val = query_pcm_param(codec, nid); 961b7d023e1STakashi Iwai if (!val) 962b7d023e1STakashi Iwai return false; 963b7d023e1STakashi Iwai 964b7d023e1STakashi Iwai rate = format & 0xff00; 965b7d023e1STakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) 966b7d023e1STakashi Iwai if (rate_bits[i].hda_fmt == rate) { 967b7d023e1STakashi Iwai if (val & (1 << i)) 968b7d023e1STakashi Iwai break; 969b7d023e1STakashi Iwai return false; 970b7d023e1STakashi Iwai } 971b7d023e1STakashi Iwai if (i >= AC_PAR_PCM_RATE_BITS) 972b7d023e1STakashi Iwai return false; 973b7d023e1STakashi Iwai 974b7d023e1STakashi Iwai stream = query_stream_param(codec, nid); 975b7d023e1STakashi Iwai if (!stream) 976b7d023e1STakashi Iwai return false; 977b7d023e1STakashi Iwai 978b7d023e1STakashi Iwai if (stream & AC_SUPFMT_PCM) { 979b7d023e1STakashi Iwai switch (format & 0xf0) { 980b7d023e1STakashi Iwai case 0x00: 981b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_8)) 982b7d023e1STakashi Iwai return false; 983b7d023e1STakashi Iwai break; 984b7d023e1STakashi Iwai case 0x10: 985b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_16)) 986b7d023e1STakashi Iwai return false; 987b7d023e1STakashi Iwai break; 988b7d023e1STakashi Iwai case 0x20: 989b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_20)) 990b7d023e1STakashi Iwai return false; 991b7d023e1STakashi Iwai break; 992b7d023e1STakashi Iwai case 0x30: 993b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_24)) 994b7d023e1STakashi Iwai return false; 995b7d023e1STakashi Iwai break; 996b7d023e1STakashi Iwai case 0x40: 997b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_32)) 998b7d023e1STakashi Iwai return false; 999b7d023e1STakashi Iwai break; 1000b7d023e1STakashi Iwai default: 1001b7d023e1STakashi Iwai return false; 1002b7d023e1STakashi Iwai } 1003b7d023e1STakashi Iwai } else { 1004b7d023e1STakashi Iwai /* FIXME: check for float32 and AC3? */ 1005b7d023e1STakashi Iwai } 1006b7d023e1STakashi Iwai 1007b7d023e1STakashi Iwai return true; 1008b7d023e1STakashi Iwai } 1009b7d023e1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_is_supported_format); 10101b5e6167SSubhransu S. Prusty 10111b5e6167SSubhransu S. Prusty static unsigned int codec_read(struct hdac_device *hdac, hda_nid_t nid, 10121b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 10131b5e6167SSubhransu S. Prusty { 10141b5e6167SSubhransu S. Prusty unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm); 10151b5e6167SSubhransu S. Prusty unsigned int res; 10161b5e6167SSubhransu S. Prusty 10171b5e6167SSubhransu S. Prusty if (snd_hdac_exec_verb(hdac, cmd, flags, &res)) 10181b5e6167SSubhransu S. Prusty return -1; 10191b5e6167SSubhransu S. Prusty 10201b5e6167SSubhransu S. Prusty return res; 10211b5e6167SSubhransu S. Prusty } 10221b5e6167SSubhransu S. Prusty 10231b5e6167SSubhransu S. Prusty static int codec_write(struct hdac_device *hdac, hda_nid_t nid, 10241b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 10251b5e6167SSubhransu S. Prusty { 10261b5e6167SSubhransu S. Prusty unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm); 10271b5e6167SSubhransu S. Prusty 10281b5e6167SSubhransu S. Prusty return snd_hdac_exec_verb(hdac, cmd, flags, NULL); 10291b5e6167SSubhransu S. Prusty } 10301b5e6167SSubhransu S. Prusty 10311b5e6167SSubhransu S. Prusty /** 10321b5e6167SSubhransu S. Prusty * snd_hdac_codec_read - send a command and get the response 10331b5e6167SSubhransu S. Prusty * @hdac: the HDAC device 10341b5e6167SSubhransu S. Prusty * @nid: NID to send the command 10351b5e6167SSubhransu S. Prusty * @flags: optional bit flags 10361b5e6167SSubhransu S. Prusty * @verb: the verb to send 10371b5e6167SSubhransu S. Prusty * @parm: the parameter for the verb 10381b5e6167SSubhransu S. Prusty * 10391b5e6167SSubhransu S. Prusty * Send a single command and read the corresponding response. 10401b5e6167SSubhransu S. Prusty * 10411b5e6167SSubhransu S. Prusty * Returns the obtained response value, or -1 for an error. 10421b5e6167SSubhransu S. Prusty */ 10431b5e6167SSubhransu S. Prusty int snd_hdac_codec_read(struct hdac_device *hdac, hda_nid_t nid, 10441b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 10451b5e6167SSubhransu S. Prusty { 10461b5e6167SSubhransu S. Prusty return codec_read(hdac, nid, flags, verb, parm); 10471b5e6167SSubhransu S. Prusty } 10481b5e6167SSubhransu S. Prusty EXPORT_SYMBOL_GPL(snd_hdac_codec_read); 10491b5e6167SSubhransu S. Prusty 10501b5e6167SSubhransu S. Prusty /** 10511b5e6167SSubhransu S. Prusty * snd_hdac_codec_write - send a single command without waiting for response 10521b5e6167SSubhransu S. Prusty * @hdac: the HDAC device 10531b5e6167SSubhransu S. Prusty * @nid: NID to send the command 10541b5e6167SSubhransu S. Prusty * @flags: optional bit flags 10551b5e6167SSubhransu S. Prusty * @verb: the verb to send 10561b5e6167SSubhransu S. Prusty * @parm: the parameter for the verb 10571b5e6167SSubhransu S. Prusty * 10581b5e6167SSubhransu S. Prusty * Send a single command without waiting for response. 10591b5e6167SSubhransu S. Prusty * 10601b5e6167SSubhransu S. Prusty * Returns 0 if successful, or a negative error code. 10611b5e6167SSubhransu S. Prusty */ 10621b5e6167SSubhransu S. Prusty int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid, 10631b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 10641b5e6167SSubhransu S. Prusty { 10651b5e6167SSubhransu S. Prusty return codec_write(hdac, nid, flags, verb, parm); 10661b5e6167SSubhransu S. Prusty } 10671b5e6167SSubhransu S. Prusty EXPORT_SYMBOL_GPL(snd_hdac_codec_write); 10681b5e6167SSubhransu S. Prusty 106978dd5e21STakashi Iwai /** 107078dd5e21STakashi Iwai * snd_hdac_check_power_state - check whether the actual power state matches 10711b5e6167SSubhransu S. Prusty * with the target state 10721b5e6167SSubhransu S. Prusty * 10731b5e6167SSubhransu S. Prusty * @hdac: the HDAC device 10741b5e6167SSubhransu S. Prusty * @nid: NID to send the command 10751b5e6167SSubhransu S. Prusty * @target_state: target state to check for 10761b5e6167SSubhransu S. Prusty * 10771b5e6167SSubhransu S. Prusty * Return true if state matches, false if not 10781b5e6167SSubhransu S. Prusty */ 10791b5e6167SSubhransu S. Prusty bool snd_hdac_check_power_state(struct hdac_device *hdac, 10801b5e6167SSubhransu S. Prusty hda_nid_t nid, unsigned int target_state) 10811b5e6167SSubhransu S. Prusty { 10821b5e6167SSubhransu S. Prusty unsigned int state = codec_read(hdac, nid, 0, 10831b5e6167SSubhransu S. Prusty AC_VERB_GET_POWER_STATE, 0); 10841b5e6167SSubhransu S. Prusty 10851b5e6167SSubhransu S. Prusty if (state & AC_PWRST_ERROR) 10861b5e6167SSubhransu S. Prusty return true; 10871b5e6167SSubhransu S. Prusty state = (state >> 4) & 0x0f; 10881b5e6167SSubhransu S. Prusty return (state == target_state); 10891b5e6167SSubhransu S. Prusty } 10901b5e6167SSubhransu S. Prusty EXPORT_SYMBOL_GPL(snd_hdac_check_power_state); 1091