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 /** 1677639a06cSTakashi Iwai * snd_hdac_make_cmd - compose a 32bit command word to be sent to the 1687639a06cSTakashi Iwai * HD-audio controller 1697639a06cSTakashi Iwai * @codec: the codec object 1707639a06cSTakashi Iwai * @nid: NID to encode 1717639a06cSTakashi Iwai * @verb: verb to encode 1727639a06cSTakashi Iwai * @parm: parameter to encode 1737639a06cSTakashi Iwai * 1747639a06cSTakashi Iwai * Return an encoded command verb or -1 for error. 1757639a06cSTakashi Iwai */ 1767639a06cSTakashi Iwai unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, 1777639a06cSTakashi Iwai unsigned int verb, unsigned int parm) 1787639a06cSTakashi Iwai { 1797639a06cSTakashi Iwai u32 val, addr; 1807639a06cSTakashi Iwai 1817639a06cSTakashi Iwai addr = codec->addr; 1827639a06cSTakashi Iwai if ((addr & ~0xf) || (nid & ~0x7f) || 1837639a06cSTakashi Iwai (verb & ~0xfff) || (parm & ~0xffff)) { 1847639a06cSTakashi Iwai dev_err(&codec->dev, "out of range cmd %x:%x:%x:%x\n", 1857639a06cSTakashi Iwai addr, nid, verb, parm); 1867639a06cSTakashi Iwai return -1; 1877639a06cSTakashi Iwai } 1887639a06cSTakashi Iwai 1897639a06cSTakashi Iwai val = addr << 28; 1907639a06cSTakashi Iwai val |= (u32)nid << 20; 1917639a06cSTakashi Iwai val |= verb << 8; 1927639a06cSTakashi Iwai val |= parm; 1937639a06cSTakashi Iwai return val; 1947639a06cSTakashi Iwai } 1957639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_make_cmd); 1967639a06cSTakashi Iwai 1977639a06cSTakashi Iwai /** 19805852448STakashi Iwai * snd_hdac_exec_verb - execute an encoded verb 19905852448STakashi Iwai * @codec: the codec object 20005852448STakashi Iwai * @cmd: encoded verb to execute 20105852448STakashi Iwai * @flags: optional flags, pass zero for default 20205852448STakashi Iwai * @res: the pointer to store the result, NULL if running async 20305852448STakashi Iwai * 20405852448STakashi Iwai * Returns zero if successful, or a negative error code. 20505852448STakashi Iwai * 20605852448STakashi Iwai * This calls the exec_verb op when set in hdac_codec. If not, 20705852448STakashi Iwai * call the default snd_hdac_bus_exec_verb(). 20805852448STakashi Iwai */ 20905852448STakashi Iwai int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, 21005852448STakashi Iwai unsigned int flags, unsigned int *res) 21105852448STakashi Iwai { 21205852448STakashi Iwai if (codec->exec_verb) 21305852448STakashi Iwai return codec->exec_verb(codec, cmd, flags, res); 21405852448STakashi Iwai return snd_hdac_bus_exec_verb(codec->bus, codec->addr, cmd, res); 21505852448STakashi Iwai } 21605852448STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_exec_verb); 21705852448STakashi Iwai 21805852448STakashi Iwai 21905852448STakashi Iwai /** 2207639a06cSTakashi Iwai * snd_hdac_read - execute a verb 2217639a06cSTakashi Iwai * @codec: the codec object 2227639a06cSTakashi Iwai * @nid: NID to execute a verb 2237639a06cSTakashi Iwai * @verb: verb to execute 2247639a06cSTakashi Iwai * @parm: parameter for a verb 2257639a06cSTakashi Iwai * @res: the pointer to store the result, NULL if running async 2267639a06cSTakashi Iwai * 2277639a06cSTakashi Iwai * Returns zero if successful, or a negative error code. 2287639a06cSTakashi Iwai */ 2297639a06cSTakashi Iwai int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid, 2307639a06cSTakashi Iwai unsigned int verb, unsigned int parm, unsigned int *res) 2317639a06cSTakashi Iwai { 2327639a06cSTakashi Iwai unsigned int cmd = snd_hdac_make_cmd(codec, nid, verb, parm); 2337639a06cSTakashi Iwai 23405852448STakashi Iwai return snd_hdac_exec_verb(codec, cmd, 0, res); 2357639a06cSTakashi Iwai } 2367639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_read); 2377639a06cSTakashi Iwai 2387639a06cSTakashi Iwai /** 23901ed3c06STakashi Iwai * _snd_hdac_read_parm - read a parmeter 2407639a06cSTakashi Iwai * 24101ed3c06STakashi Iwai * This function returns zero or an error unlike snd_hdac_read_parm(). 2427639a06cSTakashi Iwai */ 24301ed3c06STakashi Iwai int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm, 24401ed3c06STakashi Iwai unsigned int *res) 2457639a06cSTakashi Iwai { 24601ed3c06STakashi Iwai unsigned int cmd; 2477639a06cSTakashi Iwai 24801ed3c06STakashi Iwai cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; 24901ed3c06STakashi Iwai return snd_hdac_regmap_read_raw(codec, cmd, res); 2507639a06cSTakashi Iwai } 25101ed3c06STakashi Iwai EXPORT_SYMBOL_GPL(_snd_hdac_read_parm); 2527639a06cSTakashi Iwai 2537639a06cSTakashi Iwai /** 2549ba17b4dSTakashi Iwai * snd_hdac_read_parm_uncached - read a codec parameter without caching 2557639a06cSTakashi Iwai * @codec: the codec object 2567639a06cSTakashi Iwai * @nid: NID to read a parameter 2577639a06cSTakashi Iwai * @parm: parameter to read 2587639a06cSTakashi Iwai * 2597639a06cSTakashi Iwai * Returns -1 for error. If you need to distinguish the error more 2607639a06cSTakashi Iwai * strictly, use snd_hdac_read() directly. 2617639a06cSTakashi Iwai */ 2629ba17b4dSTakashi Iwai int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, 2639ba17b4dSTakashi Iwai int parm) 2647639a06cSTakashi Iwai { 2657639a06cSTakashi Iwai int val; 2667639a06cSTakashi Iwai 2679ba17b4dSTakashi Iwai if (codec->regmap) 2689ba17b4dSTakashi Iwai regcache_cache_bypass(codec->regmap, true); 2699ba17b4dSTakashi Iwai val = snd_hdac_read_parm(codec, nid, parm); 2709ba17b4dSTakashi Iwai if (codec->regmap) 2719ba17b4dSTakashi Iwai regcache_cache_bypass(codec->regmap, false); 2727639a06cSTakashi Iwai return val; 2737639a06cSTakashi Iwai } 2749ba17b4dSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached); 2759ba17b4dSTakashi Iwai 2769ba17b4dSTakashi Iwai /** 277faa75f8aSTakashi Iwai * snd_hdac_override_parm - override read-only parameters 278faa75f8aSTakashi Iwai * @codec: the codec object 279faa75f8aSTakashi Iwai * @nid: NID for the parameter 280faa75f8aSTakashi Iwai * @parm: the parameter to change 281faa75f8aSTakashi Iwai * @val: the parameter value to overwrite 282faa75f8aSTakashi Iwai */ 283faa75f8aSTakashi Iwai int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid, 284faa75f8aSTakashi Iwai unsigned int parm, unsigned int val) 285faa75f8aSTakashi Iwai { 286faa75f8aSTakashi Iwai unsigned int verb = (AC_VERB_PARAMETERS << 8) | (nid << 20) | parm; 287faa75f8aSTakashi Iwai int err; 288faa75f8aSTakashi Iwai 289faa75f8aSTakashi Iwai if (!codec->regmap) 290faa75f8aSTakashi Iwai return -EINVAL; 291faa75f8aSTakashi Iwai 292faa75f8aSTakashi Iwai codec->caps_overwriting = true; 293faa75f8aSTakashi Iwai err = snd_hdac_regmap_write_raw(codec, verb, val); 294faa75f8aSTakashi Iwai codec->caps_overwriting = false; 295faa75f8aSTakashi Iwai return err; 296faa75f8aSTakashi Iwai } 297faa75f8aSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_override_parm); 2987639a06cSTakashi Iwai 2997639a06cSTakashi Iwai /** 3007639a06cSTakashi Iwai * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes 3017639a06cSTakashi Iwai * @codec: the codec object 3027639a06cSTakashi Iwai * @nid: NID to inspect 3037639a06cSTakashi Iwai * @start_id: the pointer to store the starting NID 3047639a06cSTakashi Iwai * 3057639a06cSTakashi Iwai * Returns the number of subtree nodes or zero if not found. 3069ba17b4dSTakashi Iwai * This function reads parameters always without caching. 3077639a06cSTakashi Iwai */ 3087639a06cSTakashi Iwai int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, 3097639a06cSTakashi Iwai hda_nid_t *start_id) 3107639a06cSTakashi Iwai { 3117639a06cSTakashi Iwai unsigned int parm; 3127639a06cSTakashi Iwai 3139ba17b4dSTakashi Iwai parm = snd_hdac_read_parm_uncached(codec, nid, AC_PAR_NODE_COUNT); 3147639a06cSTakashi Iwai if (parm == -1) { 3157639a06cSTakashi Iwai *start_id = 0; 3167639a06cSTakashi Iwai return 0; 3177639a06cSTakashi Iwai } 3187639a06cSTakashi Iwai *start_id = (parm >> 16) & 0x7fff; 3197639a06cSTakashi Iwai return (int)(parm & 0x7fff); 3207639a06cSTakashi Iwai } 3217639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_sub_nodes); 3227639a06cSTakashi Iwai 3237639a06cSTakashi Iwai /* 3247639a06cSTakashi Iwai * look for an AFG and MFG nodes 3257639a06cSTakashi Iwai */ 3267639a06cSTakashi Iwai static void setup_fg_nodes(struct hdac_device *codec) 3277639a06cSTakashi Iwai { 3287639a06cSTakashi Iwai int i, total_nodes, function_id; 3297639a06cSTakashi Iwai hda_nid_t nid; 3307639a06cSTakashi Iwai 3317639a06cSTakashi Iwai total_nodes = snd_hdac_get_sub_nodes(codec, AC_NODE_ROOT, &nid); 3327639a06cSTakashi Iwai for (i = 0; i < total_nodes; i++, nid++) { 3337639a06cSTakashi Iwai function_id = snd_hdac_read_parm(codec, nid, 3347639a06cSTakashi Iwai AC_PAR_FUNCTION_TYPE); 3357639a06cSTakashi Iwai switch (function_id & 0xff) { 3367639a06cSTakashi Iwai case AC_GRP_AUDIO_FUNCTION: 3377639a06cSTakashi Iwai codec->afg = nid; 3387639a06cSTakashi Iwai codec->afg_function_id = function_id & 0xff; 3397639a06cSTakashi Iwai codec->afg_unsol = (function_id >> 8) & 1; 3407639a06cSTakashi Iwai break; 3417639a06cSTakashi Iwai case AC_GRP_MODEM_FUNCTION: 3427639a06cSTakashi Iwai codec->mfg = nid; 3437639a06cSTakashi Iwai codec->mfg_function_id = function_id & 0xff; 3447639a06cSTakashi Iwai codec->mfg_unsol = (function_id >> 8) & 1; 3457639a06cSTakashi Iwai break; 3467639a06cSTakashi Iwai default: 3477639a06cSTakashi Iwai break; 3487639a06cSTakashi Iwai } 3497639a06cSTakashi Iwai } 3507639a06cSTakashi Iwai } 3517639a06cSTakashi Iwai 3527639a06cSTakashi Iwai /** 3537639a06cSTakashi Iwai * snd_hdac_refresh_widgets - Reset the widget start/end nodes 3547639a06cSTakashi Iwai * @codec: the codec object 3557639a06cSTakashi Iwai */ 3567639a06cSTakashi Iwai int snd_hdac_refresh_widgets(struct hdac_device *codec) 3577639a06cSTakashi Iwai { 3587639a06cSTakashi Iwai hda_nid_t start_nid; 3597639a06cSTakashi Iwai int nums; 3607639a06cSTakashi Iwai 3617639a06cSTakashi Iwai nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); 3627639a06cSTakashi Iwai if (!start_nid || nums <= 0 || nums >= 0xff) { 3637639a06cSTakashi Iwai dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n", 3647639a06cSTakashi Iwai codec->afg); 3657639a06cSTakashi Iwai return -EINVAL; 3667639a06cSTakashi Iwai } 3677639a06cSTakashi Iwai 3687639a06cSTakashi Iwai codec->num_nodes = nums; 3697639a06cSTakashi Iwai codec->start_nid = start_nid; 3707639a06cSTakashi Iwai codec->end_nid = start_nid + nums; 3717639a06cSTakashi Iwai return 0; 3727639a06cSTakashi Iwai } 3737639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); 3747639a06cSTakashi Iwai 37518dfd79dSVinod Koul /** 37618dfd79dSVinod Koul * snd_hdac_refresh_widget_sysfs - Reset the codec widgets and reinit the 37718dfd79dSVinod Koul * codec sysfs 37818dfd79dSVinod Koul * @codec: the codec object 37918dfd79dSVinod Koul * 38018dfd79dSVinod Koul * first we need to remove sysfs, then refresh widgets and lastly 38118dfd79dSVinod Koul * recreate it 38218dfd79dSVinod Koul */ 38318dfd79dSVinod Koul int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec) 38418dfd79dSVinod Koul { 38518dfd79dSVinod Koul int ret; 38618dfd79dSVinod Koul 387a92d5ee8STakashi Iwai if (device_is_registered(&codec->dev)) 38818dfd79dSVinod Koul hda_widget_sysfs_exit(codec); 38918dfd79dSVinod Koul ret = snd_hdac_refresh_widgets(codec); 39018dfd79dSVinod Koul if (ret) { 39118dfd79dSVinod Koul dev_err(&codec->dev, "failed to refresh widget: %d\n", ret); 39218dfd79dSVinod Koul return ret; 39318dfd79dSVinod Koul } 394a92d5ee8STakashi Iwai if (device_is_registered(&codec->dev)) { 39518dfd79dSVinod Koul ret = hda_widget_sysfs_init(codec); 39618dfd79dSVinod Koul if (ret) { 39718dfd79dSVinod Koul dev_err(&codec->dev, "failed to init sysfs: %d\n", ret); 39818dfd79dSVinod Koul return ret; 39918dfd79dSVinod Koul } 400a92d5ee8STakashi Iwai } 40118dfd79dSVinod Koul return ret; 40218dfd79dSVinod Koul } 40318dfd79dSVinod Koul EXPORT_SYMBOL_GPL(snd_hdac_refresh_widget_sysfs); 40418dfd79dSVinod Koul 4057639a06cSTakashi Iwai /* return CONNLIST_LEN parameter of the given widget */ 4067639a06cSTakashi Iwai static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) 4077639a06cSTakashi Iwai { 4087639a06cSTakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 4097639a06cSTakashi Iwai unsigned int parm; 4107639a06cSTakashi Iwai 4117639a06cSTakashi Iwai if (!(wcaps & AC_WCAP_CONN_LIST) && 4127639a06cSTakashi Iwai get_wcaps_type(wcaps) != AC_WID_VOL_KNB) 4137639a06cSTakashi Iwai return 0; 4147639a06cSTakashi Iwai 4157639a06cSTakashi Iwai parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN); 4167639a06cSTakashi Iwai if (parm == -1) 4177639a06cSTakashi Iwai parm = 0; 4187639a06cSTakashi Iwai return parm; 4197639a06cSTakashi Iwai } 4207639a06cSTakashi Iwai 4217639a06cSTakashi Iwai /** 4227639a06cSTakashi Iwai * snd_hdac_get_connections - get a widget connection list 4237639a06cSTakashi Iwai * @codec: the codec object 4247639a06cSTakashi Iwai * @nid: NID 4257639a06cSTakashi Iwai * @conn_list: the array to store the results, can be NULL 4267639a06cSTakashi Iwai * @max_conns: the max size of the given array 4277639a06cSTakashi Iwai * 4287639a06cSTakashi Iwai * Returns the number of connected widgets, zero for no connection, or a 4297639a06cSTakashi Iwai * negative error code. When the number of elements don't fit with the 4307639a06cSTakashi Iwai * given array size, it returns -ENOSPC. 4317639a06cSTakashi Iwai * 4327639a06cSTakashi Iwai * When @conn_list is NULL, it just checks the number of connections. 4337639a06cSTakashi Iwai */ 4347639a06cSTakashi Iwai int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, 4357639a06cSTakashi Iwai hda_nid_t *conn_list, int max_conns) 4367639a06cSTakashi Iwai { 4377639a06cSTakashi Iwai unsigned int parm; 4387639a06cSTakashi Iwai int i, conn_len, conns, err; 4397639a06cSTakashi Iwai unsigned int shift, num_elems, mask; 4407639a06cSTakashi Iwai hda_nid_t prev_nid; 4417639a06cSTakashi Iwai int null_count = 0; 4427639a06cSTakashi Iwai 4437639a06cSTakashi Iwai parm = get_num_conns(codec, nid); 4447639a06cSTakashi Iwai if (!parm) 4457639a06cSTakashi Iwai return 0; 4467639a06cSTakashi Iwai 4477639a06cSTakashi Iwai if (parm & AC_CLIST_LONG) { 4487639a06cSTakashi Iwai /* long form */ 4497639a06cSTakashi Iwai shift = 16; 4507639a06cSTakashi Iwai num_elems = 2; 4517639a06cSTakashi Iwai } else { 4527639a06cSTakashi Iwai /* short form */ 4537639a06cSTakashi Iwai shift = 8; 4547639a06cSTakashi Iwai num_elems = 4; 4557639a06cSTakashi Iwai } 4567639a06cSTakashi Iwai conn_len = parm & AC_CLIST_LENGTH; 4577639a06cSTakashi Iwai mask = (1 << (shift-1)) - 1; 4587639a06cSTakashi Iwai 4597639a06cSTakashi Iwai if (!conn_len) 4607639a06cSTakashi Iwai return 0; /* no connection */ 4617639a06cSTakashi Iwai 4627639a06cSTakashi Iwai if (conn_len == 1) { 4637639a06cSTakashi Iwai /* single connection */ 4647639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, AC_VERB_GET_CONNECT_LIST, 0, 4657639a06cSTakashi Iwai &parm); 4667639a06cSTakashi Iwai if (err < 0) 4677639a06cSTakashi Iwai return err; 4687639a06cSTakashi Iwai if (conn_list) 4697639a06cSTakashi Iwai conn_list[0] = parm & mask; 4707639a06cSTakashi Iwai return 1; 4717639a06cSTakashi Iwai } 4727639a06cSTakashi Iwai 4737639a06cSTakashi Iwai /* multi connection */ 4747639a06cSTakashi Iwai conns = 0; 4757639a06cSTakashi Iwai prev_nid = 0; 4767639a06cSTakashi Iwai for (i = 0; i < conn_len; i++) { 4777639a06cSTakashi Iwai int range_val; 4787639a06cSTakashi Iwai hda_nid_t val, n; 4797639a06cSTakashi Iwai 4807639a06cSTakashi Iwai if (i % num_elems == 0) { 4817639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, 4827639a06cSTakashi Iwai AC_VERB_GET_CONNECT_LIST, i, 4837639a06cSTakashi Iwai &parm); 4847639a06cSTakashi Iwai if (err < 0) 4857639a06cSTakashi Iwai return -EIO; 4867639a06cSTakashi Iwai } 4877639a06cSTakashi Iwai range_val = !!(parm & (1 << (shift-1))); /* ranges */ 4887639a06cSTakashi Iwai val = parm & mask; 4897639a06cSTakashi Iwai if (val == 0 && null_count++) { /* no second chance */ 4907639a06cSTakashi Iwai dev_dbg(&codec->dev, 4917639a06cSTakashi Iwai "invalid CONNECT_LIST verb %x[%i]:%x\n", 4927639a06cSTakashi Iwai nid, i, parm); 4937639a06cSTakashi Iwai return 0; 4947639a06cSTakashi Iwai } 4957639a06cSTakashi Iwai parm >>= shift; 4967639a06cSTakashi Iwai if (range_val) { 4977639a06cSTakashi Iwai /* ranges between the previous and this one */ 4987639a06cSTakashi Iwai if (!prev_nid || prev_nid >= val) { 4997639a06cSTakashi Iwai dev_warn(&codec->dev, 5007639a06cSTakashi Iwai "invalid dep_range_val %x:%x\n", 5017639a06cSTakashi Iwai prev_nid, val); 5027639a06cSTakashi Iwai continue; 5037639a06cSTakashi Iwai } 5047639a06cSTakashi Iwai for (n = prev_nid + 1; n <= val; n++) { 5057639a06cSTakashi Iwai if (conn_list) { 5067639a06cSTakashi Iwai if (conns >= max_conns) 5077639a06cSTakashi Iwai return -ENOSPC; 5087639a06cSTakashi Iwai conn_list[conns] = n; 5097639a06cSTakashi Iwai } 5107639a06cSTakashi Iwai conns++; 5117639a06cSTakashi Iwai } 5127639a06cSTakashi Iwai } else { 5137639a06cSTakashi Iwai if (conn_list) { 5147639a06cSTakashi Iwai if (conns >= max_conns) 5157639a06cSTakashi Iwai return -ENOSPC; 5167639a06cSTakashi Iwai conn_list[conns] = val; 5177639a06cSTakashi Iwai } 5187639a06cSTakashi Iwai conns++; 5197639a06cSTakashi Iwai } 5207639a06cSTakashi Iwai prev_nid = val; 5217639a06cSTakashi Iwai } 5227639a06cSTakashi Iwai return conns; 5237639a06cSTakashi Iwai } 5247639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_connections); 5257639a06cSTakashi Iwai 5267639a06cSTakashi Iwai #ifdef CONFIG_PM 5277639a06cSTakashi Iwai /** 528664c7155STakashi Iwai * snd_hdac_power_up - power up the codec 5297639a06cSTakashi Iwai * @codec: the codec object 530664c7155STakashi Iwai * 531664c7155STakashi Iwai * This function calls the runtime PM helper to power up the given codec. 532664c7155STakashi Iwai * Unlike snd_hdac_power_up_pm(), you should call this only for the code 533664c7155STakashi Iwai * path that isn't included in PM path. Otherwise it gets stuck. 534fbce23a0STakashi Iwai * 535fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 5367639a06cSTakashi Iwai */ 537fbce23a0STakashi Iwai int snd_hdac_power_up(struct hdac_device *codec) 5387639a06cSTakashi Iwai { 539fbce23a0STakashi Iwai return pm_runtime_get_sync(&codec->dev); 5407639a06cSTakashi Iwai } 5417639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_up); 5427639a06cSTakashi Iwai 5437639a06cSTakashi Iwai /** 544664c7155STakashi Iwai * snd_hdac_power_down - power down the codec 5457639a06cSTakashi Iwai * @codec: the codec object 546fbce23a0STakashi Iwai * 547fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 5487639a06cSTakashi Iwai */ 549fbce23a0STakashi Iwai int snd_hdac_power_down(struct hdac_device *codec) 5507639a06cSTakashi Iwai { 5517639a06cSTakashi Iwai struct device *dev = &codec->dev; 5527639a06cSTakashi Iwai 5537639a06cSTakashi Iwai pm_runtime_mark_last_busy(dev); 554fbce23a0STakashi Iwai return pm_runtime_put_autosuspend(dev); 5557639a06cSTakashi Iwai } 5567639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_down); 557c3aeda62STakashi Iwai 558c3aeda62STakashi Iwai /** 559c3aeda62STakashi Iwai * snd_hdac_power_up_pm - power up the codec 560c3aeda62STakashi Iwai * @codec: the codec object 561c3aeda62STakashi Iwai * 562c3aeda62STakashi Iwai * This function can be called in a recursive code path like init code 563c3aeda62STakashi Iwai * which may be called by PM suspend/resume again. OTOH, if a power-up 564c3aeda62STakashi Iwai * call must wake up the sleeper (e.g. in a kctl callback), use 565c3aeda62STakashi Iwai * snd_hdac_power_up() instead. 566fbce23a0STakashi Iwai * 567fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 568c3aeda62STakashi Iwai */ 569fbce23a0STakashi Iwai int snd_hdac_power_up_pm(struct hdac_device *codec) 570c3aeda62STakashi Iwai { 571c3aeda62STakashi Iwai if (!atomic_inc_not_zero(&codec->in_pm)) 572fbce23a0STakashi Iwai return snd_hdac_power_up(codec); 573fbce23a0STakashi Iwai return 0; 574c3aeda62STakashi Iwai } 575c3aeda62STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm); 576c3aeda62STakashi Iwai 577c3aeda62STakashi Iwai /** 578c3aeda62STakashi Iwai * snd_hdac_power_down_pm - power down the codec 579c3aeda62STakashi Iwai * @codec: the codec object 580c3aeda62STakashi Iwai * 581c3aeda62STakashi Iwai * Like snd_hdac_power_up_pm(), this function is used in a recursive 582c3aeda62STakashi Iwai * code path like init code which may be called by PM suspend/resume again. 583fbce23a0STakashi Iwai * 584fbce23a0STakashi Iwai * Returns zero if successful, or a negative error code. 585c3aeda62STakashi Iwai */ 586fbce23a0STakashi Iwai int snd_hdac_power_down_pm(struct hdac_device *codec) 587c3aeda62STakashi Iwai { 588c3aeda62STakashi Iwai if (atomic_dec_if_positive(&codec->in_pm) < 0) 589fbce23a0STakashi Iwai return snd_hdac_power_down(codec); 590fbce23a0STakashi Iwai return 0; 591c3aeda62STakashi Iwai } 592c3aeda62STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); 5937639a06cSTakashi Iwai #endif 5947639a06cSTakashi Iwai 595a5e7e07cSMengdong Lin /* 596a5e7e07cSMengdong Lin * Enable/disable the link power for a codec. 597a5e7e07cSMengdong Lin */ 598a5e7e07cSMengdong Lin int snd_hdac_link_power(struct hdac_device *codec, bool enable) 599a5e7e07cSMengdong Lin { 600a5e7e07cSMengdong Lin if (!codec->link_power_control) 601a5e7e07cSMengdong Lin return 0; 602a5e7e07cSMengdong Lin 603a5e7e07cSMengdong Lin if (codec->bus->ops->link_power) 604a5e7e07cSMengdong Lin return codec->bus->ops->link_power(codec->bus, enable); 605a5e7e07cSMengdong Lin else 606a5e7e07cSMengdong Lin return -EINVAL; 607a5e7e07cSMengdong Lin } 608a5e7e07cSMengdong Lin EXPORT_SYMBOL_GPL(snd_hdac_link_power); 609a5e7e07cSMengdong Lin 6107639a06cSTakashi Iwai /* codec vendor labels */ 6117639a06cSTakashi Iwai struct hda_vendor_id { 6127639a06cSTakashi Iwai unsigned int id; 6137639a06cSTakashi Iwai const char *name; 6147639a06cSTakashi Iwai }; 6157639a06cSTakashi Iwai 6167639a06cSTakashi Iwai static struct hda_vendor_id hda_vendor_ids[] = { 6177639a06cSTakashi Iwai { 0x1002, "ATI" }, 6187639a06cSTakashi Iwai { 0x1013, "Cirrus Logic" }, 6197639a06cSTakashi Iwai { 0x1057, "Motorola" }, 6207639a06cSTakashi Iwai { 0x1095, "Silicon Image" }, 6217639a06cSTakashi Iwai { 0x10de, "Nvidia" }, 6227639a06cSTakashi Iwai { 0x10ec, "Realtek" }, 6237639a06cSTakashi Iwai { 0x1102, "Creative" }, 6247639a06cSTakashi Iwai { 0x1106, "VIA" }, 6257639a06cSTakashi Iwai { 0x111d, "IDT" }, 6267639a06cSTakashi Iwai { 0x11c1, "LSI" }, 6277639a06cSTakashi Iwai { 0x11d4, "Analog Devices" }, 6287639a06cSTakashi Iwai { 0x13f6, "C-Media" }, 6297639a06cSTakashi Iwai { 0x14f1, "Conexant" }, 6307639a06cSTakashi Iwai { 0x17e8, "Chrontel" }, 6317639a06cSTakashi Iwai { 0x1854, "LG" }, 6327639a06cSTakashi Iwai { 0x1aec, "Wolfson Microelectronics" }, 6337639a06cSTakashi Iwai { 0x1af4, "QEMU" }, 6347639a06cSTakashi Iwai { 0x434d, "C-Media" }, 6357639a06cSTakashi Iwai { 0x8086, "Intel" }, 6367639a06cSTakashi Iwai { 0x8384, "SigmaTel" }, 6377639a06cSTakashi Iwai {} /* terminator */ 6387639a06cSTakashi Iwai }; 6397639a06cSTakashi Iwai 6407639a06cSTakashi Iwai /* store the codec vendor name */ 6417639a06cSTakashi Iwai static int get_codec_vendor_name(struct hdac_device *codec) 6427639a06cSTakashi Iwai { 6437639a06cSTakashi Iwai const struct hda_vendor_id *c; 6447639a06cSTakashi Iwai u16 vendor_id = codec->vendor_id >> 16; 6457639a06cSTakashi Iwai 6467639a06cSTakashi Iwai for (c = hda_vendor_ids; c->id; c++) { 6477639a06cSTakashi Iwai if (c->id == vendor_id) { 6487639a06cSTakashi Iwai codec->vendor_name = kstrdup(c->name, GFP_KERNEL); 6497639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 6507639a06cSTakashi Iwai } 6517639a06cSTakashi Iwai } 6527639a06cSTakashi Iwai 6537639a06cSTakashi Iwai codec->vendor_name = kasprintf(GFP_KERNEL, "Generic %04x", vendor_id); 6547639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 6557639a06cSTakashi Iwai } 656b7d023e1STakashi Iwai 657b7d023e1STakashi Iwai /* 658b7d023e1STakashi Iwai * stream formats 659b7d023e1STakashi Iwai */ 660b7d023e1STakashi Iwai struct hda_rate_tbl { 661b7d023e1STakashi Iwai unsigned int hz; 662b7d023e1STakashi Iwai unsigned int alsa_bits; 663b7d023e1STakashi Iwai unsigned int hda_fmt; 664b7d023e1STakashi Iwai }; 665b7d023e1STakashi Iwai 666b7d023e1STakashi Iwai /* rate = base * mult / div */ 667b7d023e1STakashi Iwai #define HDA_RATE(base, mult, div) \ 668b7d023e1STakashi Iwai (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ 669b7d023e1STakashi Iwai (((div) - 1) << AC_FMT_DIV_SHIFT)) 670b7d023e1STakashi Iwai 671b7d023e1STakashi Iwai static struct hda_rate_tbl rate_bits[] = { 672b7d023e1STakashi Iwai /* rate in Hz, ALSA rate bitmask, HDA format value */ 673b7d023e1STakashi Iwai 674b7d023e1STakashi Iwai /* autodetected value used in snd_hda_query_supported_pcm */ 675b7d023e1STakashi Iwai { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) }, 676b7d023e1STakashi Iwai { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) }, 677b7d023e1STakashi Iwai { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) }, 678b7d023e1STakashi Iwai { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) }, 679b7d023e1STakashi Iwai { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) }, 680b7d023e1STakashi Iwai { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) }, 681b7d023e1STakashi Iwai { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) }, 682b7d023e1STakashi Iwai { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) }, 683b7d023e1STakashi Iwai { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) }, 684b7d023e1STakashi Iwai { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) }, 685b7d023e1STakashi Iwai { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) }, 686b7d023e1STakashi Iwai #define AC_PAR_PCM_RATE_BITS 11 687b7d023e1STakashi Iwai /* up to bits 10, 384kHZ isn't supported properly */ 688b7d023e1STakashi Iwai 689b7d023e1STakashi Iwai /* not autodetected value */ 690b7d023e1STakashi Iwai { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) }, 691b7d023e1STakashi Iwai 692b7d023e1STakashi Iwai { 0 } /* terminator */ 693b7d023e1STakashi Iwai }; 694b7d023e1STakashi Iwai 695b7d023e1STakashi Iwai /** 696b7d023e1STakashi Iwai * snd_hdac_calc_stream_format - calculate the format bitset 697b7d023e1STakashi Iwai * @rate: the sample rate 698b7d023e1STakashi Iwai * @channels: the number of channels 699b7d023e1STakashi Iwai * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) 700b7d023e1STakashi Iwai * @maxbps: the max. bps 701b7d023e1STakashi Iwai * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant) 702b7d023e1STakashi Iwai * 703b7d023e1STakashi Iwai * Calculate the format bitset from the given rate, channels and th PCM format. 704b7d023e1STakashi Iwai * 705b7d023e1STakashi Iwai * Return zero if invalid. 706b7d023e1STakashi Iwai */ 707b7d023e1STakashi Iwai unsigned int snd_hdac_calc_stream_format(unsigned int rate, 708b7d023e1STakashi Iwai unsigned int channels, 709b7d023e1STakashi Iwai unsigned int format, 710b7d023e1STakashi Iwai unsigned int maxbps, 711b7d023e1STakashi Iwai unsigned short spdif_ctls) 712b7d023e1STakashi Iwai { 713b7d023e1STakashi Iwai int i; 714b7d023e1STakashi Iwai unsigned int val = 0; 715b7d023e1STakashi Iwai 716b7d023e1STakashi Iwai for (i = 0; rate_bits[i].hz; i++) 717b7d023e1STakashi Iwai if (rate_bits[i].hz == rate) { 718b7d023e1STakashi Iwai val = rate_bits[i].hda_fmt; 719b7d023e1STakashi Iwai break; 720b7d023e1STakashi Iwai } 721b7d023e1STakashi Iwai if (!rate_bits[i].hz) 722b7d023e1STakashi Iwai return 0; 723b7d023e1STakashi Iwai 724b7d023e1STakashi Iwai if (channels == 0 || channels > 8) 725b7d023e1STakashi Iwai return 0; 726b7d023e1STakashi Iwai val |= channels - 1; 727b7d023e1STakashi Iwai 728b7d023e1STakashi Iwai switch (snd_pcm_format_width(format)) { 729b7d023e1STakashi Iwai case 8: 730b7d023e1STakashi Iwai val |= AC_FMT_BITS_8; 731b7d023e1STakashi Iwai break; 732b7d023e1STakashi Iwai case 16: 733b7d023e1STakashi Iwai val |= AC_FMT_BITS_16; 734b7d023e1STakashi Iwai break; 735b7d023e1STakashi Iwai case 20: 736b7d023e1STakashi Iwai case 24: 737b7d023e1STakashi Iwai case 32: 738b7d023e1STakashi Iwai if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) 739b7d023e1STakashi Iwai val |= AC_FMT_BITS_32; 740b7d023e1STakashi Iwai else if (maxbps >= 24) 741b7d023e1STakashi Iwai val |= AC_FMT_BITS_24; 742b7d023e1STakashi Iwai else 743b7d023e1STakashi Iwai val |= AC_FMT_BITS_20; 744b7d023e1STakashi Iwai break; 745b7d023e1STakashi Iwai default: 746b7d023e1STakashi Iwai return 0; 747b7d023e1STakashi Iwai } 748b7d023e1STakashi Iwai 749b7d023e1STakashi Iwai if (spdif_ctls & AC_DIG1_NONAUDIO) 750b7d023e1STakashi Iwai val |= AC_FMT_TYPE_NON_PCM; 751b7d023e1STakashi Iwai 752b7d023e1STakashi Iwai return val; 753b7d023e1STakashi Iwai } 754b7d023e1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_calc_stream_format); 755b7d023e1STakashi Iwai 756b7d023e1STakashi Iwai static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid) 757b7d023e1STakashi Iwai { 758b7d023e1STakashi Iwai unsigned int val = 0; 759b7d023e1STakashi Iwai 760b7d023e1STakashi Iwai if (nid != codec->afg && 761b7d023e1STakashi Iwai (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) 762b7d023e1STakashi Iwai val = snd_hdac_read_parm(codec, nid, AC_PAR_PCM); 763b7d023e1STakashi Iwai if (!val || val == -1) 764b7d023e1STakashi Iwai val = snd_hdac_read_parm(codec, codec->afg, AC_PAR_PCM); 765b7d023e1STakashi Iwai if (!val || val == -1) 766b7d023e1STakashi Iwai return 0; 767b7d023e1STakashi Iwai return val; 768b7d023e1STakashi Iwai } 769b7d023e1STakashi Iwai 770b7d023e1STakashi Iwai static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid) 771b7d023e1STakashi Iwai { 772b7d023e1STakashi Iwai unsigned int streams = snd_hdac_read_parm(codec, nid, AC_PAR_STREAM); 773b7d023e1STakashi Iwai 774b7d023e1STakashi Iwai if (!streams || streams == -1) 775b7d023e1STakashi Iwai streams = snd_hdac_read_parm(codec, codec->afg, AC_PAR_STREAM); 776b7d023e1STakashi Iwai if (!streams || streams == -1) 777b7d023e1STakashi Iwai return 0; 778b7d023e1STakashi Iwai return streams; 779b7d023e1STakashi Iwai } 780b7d023e1STakashi Iwai 781b7d023e1STakashi Iwai /** 782b7d023e1STakashi Iwai * snd_hdac_query_supported_pcm - query the supported PCM rates and formats 783b7d023e1STakashi Iwai * @codec: the codec object 784b7d023e1STakashi Iwai * @nid: NID to query 785b7d023e1STakashi Iwai * @ratesp: the pointer to store the detected rate bitflags 786b7d023e1STakashi Iwai * @formatsp: the pointer to store the detected formats 787b7d023e1STakashi Iwai * @bpsp: the pointer to store the detected format widths 788b7d023e1STakashi Iwai * 789b7d023e1STakashi Iwai * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp 790b7d023e1STakashi Iwai * or @bsps argument is ignored. 791b7d023e1STakashi Iwai * 792b7d023e1STakashi Iwai * Returns 0 if successful, otherwise a negative error code. 793b7d023e1STakashi Iwai */ 794b7d023e1STakashi Iwai int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, 795b7d023e1STakashi Iwai u32 *ratesp, u64 *formatsp, unsigned int *bpsp) 796b7d023e1STakashi Iwai { 797b7d023e1STakashi Iwai unsigned int i, val, wcaps; 798b7d023e1STakashi Iwai 799b7d023e1STakashi Iwai wcaps = get_wcaps(codec, nid); 800b7d023e1STakashi Iwai val = query_pcm_param(codec, nid); 801b7d023e1STakashi Iwai 802b7d023e1STakashi Iwai if (ratesp) { 803b7d023e1STakashi Iwai u32 rates = 0; 804b7d023e1STakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) { 805b7d023e1STakashi Iwai if (val & (1 << i)) 806b7d023e1STakashi Iwai rates |= rate_bits[i].alsa_bits; 807b7d023e1STakashi Iwai } 808b7d023e1STakashi Iwai if (rates == 0) { 809b7d023e1STakashi Iwai dev_err(&codec->dev, 810b7d023e1STakashi Iwai "rates == 0 (nid=0x%x, val=0x%x, ovrd=%i)\n", 811b7d023e1STakashi Iwai nid, val, 812b7d023e1STakashi Iwai (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); 813b7d023e1STakashi Iwai return -EIO; 814b7d023e1STakashi Iwai } 815b7d023e1STakashi Iwai *ratesp = rates; 816b7d023e1STakashi Iwai } 817b7d023e1STakashi Iwai 818b7d023e1STakashi Iwai if (formatsp || bpsp) { 819b7d023e1STakashi Iwai u64 formats = 0; 820b7d023e1STakashi Iwai unsigned int streams, bps; 821b7d023e1STakashi Iwai 822b7d023e1STakashi Iwai streams = query_stream_param(codec, nid); 823b7d023e1STakashi Iwai if (!streams) 824b7d023e1STakashi Iwai return -EIO; 825b7d023e1STakashi Iwai 826b7d023e1STakashi Iwai bps = 0; 827b7d023e1STakashi Iwai if (streams & AC_SUPFMT_PCM) { 828b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_8) { 829b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_U8; 830b7d023e1STakashi Iwai bps = 8; 831b7d023e1STakashi Iwai } 832b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_16) { 833b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_S16_LE; 834b7d023e1STakashi Iwai bps = 16; 835b7d023e1STakashi Iwai } 836b7d023e1STakashi Iwai if (wcaps & AC_WCAP_DIGITAL) { 837b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_32) 838b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; 839b7d023e1STakashi Iwai if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) 840b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_S32_LE; 841b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_24) 842b7d023e1STakashi Iwai bps = 24; 843b7d023e1STakashi Iwai else if (val & AC_SUPPCM_BITS_20) 844b7d023e1STakashi Iwai bps = 20; 845b7d023e1STakashi Iwai } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24| 846b7d023e1STakashi Iwai AC_SUPPCM_BITS_32)) { 847b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_S32_LE; 848b7d023e1STakashi Iwai if (val & AC_SUPPCM_BITS_32) 849b7d023e1STakashi Iwai bps = 32; 850b7d023e1STakashi Iwai else if (val & AC_SUPPCM_BITS_24) 851b7d023e1STakashi Iwai bps = 24; 852b7d023e1STakashi Iwai else if (val & AC_SUPPCM_BITS_20) 853b7d023e1STakashi Iwai bps = 20; 854b7d023e1STakashi Iwai } 855b7d023e1STakashi Iwai } 856b7d023e1STakashi Iwai #if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */ 857b7d023e1STakashi Iwai if (streams & AC_SUPFMT_FLOAT32) { 858b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; 859b7d023e1STakashi Iwai if (!bps) 860b7d023e1STakashi Iwai bps = 32; 861b7d023e1STakashi Iwai } 862b7d023e1STakashi Iwai #endif 863b7d023e1STakashi Iwai if (streams == AC_SUPFMT_AC3) { 864b7d023e1STakashi Iwai /* should be exclusive */ 865b7d023e1STakashi Iwai /* temporary hack: we have still no proper support 866b7d023e1STakashi Iwai * for the direct AC3 stream... 867b7d023e1STakashi Iwai */ 868b7d023e1STakashi Iwai formats |= SNDRV_PCM_FMTBIT_U8; 869b7d023e1STakashi Iwai bps = 8; 870b7d023e1STakashi Iwai } 871b7d023e1STakashi Iwai if (formats == 0) { 872b7d023e1STakashi Iwai dev_err(&codec->dev, 873b7d023e1STakashi Iwai "formats == 0 (nid=0x%x, val=0x%x, ovrd=%i, streams=0x%x)\n", 874b7d023e1STakashi Iwai nid, val, 875b7d023e1STakashi Iwai (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, 876b7d023e1STakashi Iwai streams); 877b7d023e1STakashi Iwai return -EIO; 878b7d023e1STakashi Iwai } 879b7d023e1STakashi Iwai if (formatsp) 880b7d023e1STakashi Iwai *formatsp = formats; 881b7d023e1STakashi Iwai if (bpsp) 882b7d023e1STakashi Iwai *bpsp = bps; 883b7d023e1STakashi Iwai } 884b7d023e1STakashi Iwai 885b7d023e1STakashi Iwai return 0; 886b7d023e1STakashi Iwai } 887b7d023e1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_query_supported_pcm); 888b7d023e1STakashi Iwai 889b7d023e1STakashi Iwai /** 890b7d023e1STakashi Iwai * snd_hdac_is_supported_format - Check the validity of the format 891b7d023e1STakashi Iwai * @codec: the codec object 892b7d023e1STakashi Iwai * @nid: NID to check 893b7d023e1STakashi Iwai * @format: the HD-audio format value to check 894b7d023e1STakashi Iwai * 895b7d023e1STakashi Iwai * Check whether the given node supports the format value. 896b7d023e1STakashi Iwai * 897b7d023e1STakashi Iwai * Returns true if supported, false if not. 898b7d023e1STakashi Iwai */ 899b7d023e1STakashi Iwai bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid, 900b7d023e1STakashi Iwai unsigned int format) 901b7d023e1STakashi Iwai { 902b7d023e1STakashi Iwai int i; 903b7d023e1STakashi Iwai unsigned int val = 0, rate, stream; 904b7d023e1STakashi Iwai 905b7d023e1STakashi Iwai val = query_pcm_param(codec, nid); 906b7d023e1STakashi Iwai if (!val) 907b7d023e1STakashi Iwai return false; 908b7d023e1STakashi Iwai 909b7d023e1STakashi Iwai rate = format & 0xff00; 910b7d023e1STakashi Iwai for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) 911b7d023e1STakashi Iwai if (rate_bits[i].hda_fmt == rate) { 912b7d023e1STakashi Iwai if (val & (1 << i)) 913b7d023e1STakashi Iwai break; 914b7d023e1STakashi Iwai return false; 915b7d023e1STakashi Iwai } 916b7d023e1STakashi Iwai if (i >= AC_PAR_PCM_RATE_BITS) 917b7d023e1STakashi Iwai return false; 918b7d023e1STakashi Iwai 919b7d023e1STakashi Iwai stream = query_stream_param(codec, nid); 920b7d023e1STakashi Iwai if (!stream) 921b7d023e1STakashi Iwai return false; 922b7d023e1STakashi Iwai 923b7d023e1STakashi Iwai if (stream & AC_SUPFMT_PCM) { 924b7d023e1STakashi Iwai switch (format & 0xf0) { 925b7d023e1STakashi Iwai case 0x00: 926b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_8)) 927b7d023e1STakashi Iwai return false; 928b7d023e1STakashi Iwai break; 929b7d023e1STakashi Iwai case 0x10: 930b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_16)) 931b7d023e1STakashi Iwai return false; 932b7d023e1STakashi Iwai break; 933b7d023e1STakashi Iwai case 0x20: 934b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_20)) 935b7d023e1STakashi Iwai return false; 936b7d023e1STakashi Iwai break; 937b7d023e1STakashi Iwai case 0x30: 938b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_24)) 939b7d023e1STakashi Iwai return false; 940b7d023e1STakashi Iwai break; 941b7d023e1STakashi Iwai case 0x40: 942b7d023e1STakashi Iwai if (!(val & AC_SUPPCM_BITS_32)) 943b7d023e1STakashi Iwai return false; 944b7d023e1STakashi Iwai break; 945b7d023e1STakashi Iwai default: 946b7d023e1STakashi Iwai return false; 947b7d023e1STakashi Iwai } 948b7d023e1STakashi Iwai } else { 949b7d023e1STakashi Iwai /* FIXME: check for float32 and AC3? */ 950b7d023e1STakashi Iwai } 951b7d023e1STakashi Iwai 952b7d023e1STakashi Iwai return true; 953b7d023e1STakashi Iwai } 954b7d023e1STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_is_supported_format); 955*1b5e6167SSubhransu S. Prusty 956*1b5e6167SSubhransu S. Prusty static unsigned int codec_read(struct hdac_device *hdac, hda_nid_t nid, 957*1b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 958*1b5e6167SSubhransu S. Prusty { 959*1b5e6167SSubhransu S. Prusty unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm); 960*1b5e6167SSubhransu S. Prusty unsigned int res; 961*1b5e6167SSubhransu S. Prusty 962*1b5e6167SSubhransu S. Prusty if (snd_hdac_exec_verb(hdac, cmd, flags, &res)) 963*1b5e6167SSubhransu S. Prusty return -1; 964*1b5e6167SSubhransu S. Prusty 965*1b5e6167SSubhransu S. Prusty return res; 966*1b5e6167SSubhransu S. Prusty } 967*1b5e6167SSubhransu S. Prusty 968*1b5e6167SSubhransu S. Prusty static int codec_write(struct hdac_device *hdac, hda_nid_t nid, 969*1b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 970*1b5e6167SSubhransu S. Prusty { 971*1b5e6167SSubhransu S. Prusty unsigned int cmd = snd_hdac_make_cmd(hdac, nid, verb, parm); 972*1b5e6167SSubhransu S. Prusty 973*1b5e6167SSubhransu S. Prusty return snd_hdac_exec_verb(hdac, cmd, flags, NULL); 974*1b5e6167SSubhransu S. Prusty } 975*1b5e6167SSubhransu S. Prusty 976*1b5e6167SSubhransu S. Prusty /** 977*1b5e6167SSubhransu S. Prusty * snd_hdac_codec_read - send a command and get the response 978*1b5e6167SSubhransu S. Prusty * @hdac: the HDAC device 979*1b5e6167SSubhransu S. Prusty * @nid: NID to send the command 980*1b5e6167SSubhransu S. Prusty * @flags: optional bit flags 981*1b5e6167SSubhransu S. Prusty * @verb: the verb to send 982*1b5e6167SSubhransu S. Prusty * @parm: the parameter for the verb 983*1b5e6167SSubhransu S. Prusty * 984*1b5e6167SSubhransu S. Prusty * Send a single command and read the corresponding response. 985*1b5e6167SSubhransu S. Prusty * 986*1b5e6167SSubhransu S. Prusty * Returns the obtained response value, or -1 for an error. 987*1b5e6167SSubhransu S. Prusty */ 988*1b5e6167SSubhransu S. Prusty int snd_hdac_codec_read(struct hdac_device *hdac, hda_nid_t nid, 989*1b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 990*1b5e6167SSubhransu S. Prusty { 991*1b5e6167SSubhransu S. Prusty return codec_read(hdac, nid, flags, verb, parm); 992*1b5e6167SSubhransu S. Prusty } 993*1b5e6167SSubhransu S. Prusty EXPORT_SYMBOL_GPL(snd_hdac_codec_read); 994*1b5e6167SSubhransu S. Prusty 995*1b5e6167SSubhransu S. Prusty /** 996*1b5e6167SSubhransu S. Prusty * snd_hdac_codec_write - send a single command without waiting for response 997*1b5e6167SSubhransu S. Prusty * @hdac: the HDAC device 998*1b5e6167SSubhransu S. Prusty * @nid: NID to send the command 999*1b5e6167SSubhransu S. Prusty * @flags: optional bit flags 1000*1b5e6167SSubhransu S. Prusty * @verb: the verb to send 1001*1b5e6167SSubhransu S. Prusty * @parm: the parameter for the verb 1002*1b5e6167SSubhransu S. Prusty * 1003*1b5e6167SSubhransu S. Prusty * Send a single command without waiting for response. 1004*1b5e6167SSubhransu S. Prusty * 1005*1b5e6167SSubhransu S. Prusty * Returns 0 if successful, or a negative error code. 1006*1b5e6167SSubhransu S. Prusty */ 1007*1b5e6167SSubhransu S. Prusty int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid, 1008*1b5e6167SSubhransu S. Prusty int flags, unsigned int verb, unsigned int parm) 1009*1b5e6167SSubhransu S. Prusty { 1010*1b5e6167SSubhransu S. Prusty return codec_write(hdac, nid, flags, verb, parm); 1011*1b5e6167SSubhransu S. Prusty } 1012*1b5e6167SSubhransu S. Prusty EXPORT_SYMBOL_GPL(snd_hdac_codec_write); 1013*1b5e6167SSubhransu S. Prusty 1014*1b5e6167SSubhransu S. Prusty /* 1015*1b5e6167SSubhransu S. Prusty * snd_hdac_check_power_state: check whether the actual power state matches 1016*1b5e6167SSubhransu S. Prusty * with the target state 1017*1b5e6167SSubhransu S. Prusty * 1018*1b5e6167SSubhransu S. Prusty * @hdac: the HDAC device 1019*1b5e6167SSubhransu S. Prusty * @nid: NID to send the command 1020*1b5e6167SSubhransu S. Prusty * @target_state: target state to check for 1021*1b5e6167SSubhransu S. Prusty * 1022*1b5e6167SSubhransu S. Prusty * Return true if state matches, false if not 1023*1b5e6167SSubhransu S. Prusty */ 1024*1b5e6167SSubhransu S. Prusty bool snd_hdac_check_power_state(struct hdac_device *hdac, 1025*1b5e6167SSubhransu S. Prusty hda_nid_t nid, unsigned int target_state) 1026*1b5e6167SSubhransu S. Prusty { 1027*1b5e6167SSubhransu S. Prusty unsigned int state = codec_read(hdac, nid, 0, 1028*1b5e6167SSubhransu S. Prusty AC_VERB_GET_POWER_STATE, 0); 1029*1b5e6167SSubhransu S. Prusty 1030*1b5e6167SSubhransu S. Prusty if (state & AC_PWRST_ERROR) 1031*1b5e6167SSubhransu S. Prusty return true; 1032*1b5e6167SSubhransu S. Prusty state = (state >> 4) & 0x0f; 1033*1b5e6167SSubhransu S. Prusty return (state == target_state); 1034*1b5e6167SSubhransu S. Prusty } 1035*1b5e6167SSubhransu S. Prusty EXPORT_SYMBOL_GPL(snd_hdac_check_power_state); 1036