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> 12*01ed3c06STakashi Iwai #include <sound/hda_regmap.h> 137639a06cSTakashi Iwai #include "local.h" 147639a06cSTakashi Iwai 157639a06cSTakashi Iwai static void setup_fg_nodes(struct hdac_device *codec); 167639a06cSTakashi Iwai static int get_codec_vendor_name(struct hdac_device *codec); 177639a06cSTakashi Iwai 187639a06cSTakashi Iwai static void default_release(struct device *dev) 197639a06cSTakashi Iwai { 207639a06cSTakashi Iwai snd_hdac_device_exit(container_of(dev, struct hdac_device, dev)); 217639a06cSTakashi Iwai } 227639a06cSTakashi Iwai 237639a06cSTakashi Iwai /** 247639a06cSTakashi Iwai * snd_hdac_device_init - initialize the HD-audio codec base device 257639a06cSTakashi Iwai * @codec: device to initialize 267639a06cSTakashi Iwai * @bus: but to attach 277639a06cSTakashi Iwai * @name: device name string 287639a06cSTakashi Iwai * @addr: codec address 297639a06cSTakashi Iwai * 307639a06cSTakashi Iwai * Returns zero for success or a negative error code. 317639a06cSTakashi Iwai * 327639a06cSTakashi Iwai * This function increments the runtime PM counter and marks it active. 337639a06cSTakashi Iwai * The caller needs to turn it off appropriately later. 347639a06cSTakashi Iwai * 357639a06cSTakashi Iwai * The caller needs to set the device's release op properly by itself. 367639a06cSTakashi Iwai */ 377639a06cSTakashi Iwai int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, 387639a06cSTakashi Iwai const char *name, unsigned int addr) 397639a06cSTakashi Iwai { 407639a06cSTakashi Iwai struct device *dev; 417639a06cSTakashi Iwai hda_nid_t fg; 427639a06cSTakashi Iwai int err; 437639a06cSTakashi Iwai 447639a06cSTakashi Iwai dev = &codec->dev; 457639a06cSTakashi Iwai device_initialize(dev); 467639a06cSTakashi Iwai dev->parent = bus->dev; 477639a06cSTakashi Iwai dev->bus = &snd_hda_bus_type; 487639a06cSTakashi Iwai dev->release = default_release; 493256be65STakashi Iwai dev->groups = hdac_dev_attr_groups; 507639a06cSTakashi Iwai dev_set_name(dev, "%s", name); 517639a06cSTakashi Iwai device_enable_async_suspend(dev); 527639a06cSTakashi Iwai 537639a06cSTakashi Iwai codec->bus = bus; 547639a06cSTakashi Iwai codec->addr = addr; 557639a06cSTakashi Iwai codec->type = HDA_DEV_CORE; 567639a06cSTakashi Iwai pm_runtime_set_active(&codec->dev); 577639a06cSTakashi Iwai pm_runtime_get_noresume(&codec->dev); 587639a06cSTakashi Iwai atomic_set(&codec->in_pm, 0); 597639a06cSTakashi Iwai 607639a06cSTakashi Iwai err = snd_hdac_bus_add_device(bus, codec); 617639a06cSTakashi Iwai if (err < 0) 627639a06cSTakashi Iwai goto error; 637639a06cSTakashi Iwai 647639a06cSTakashi Iwai /* fill parameters */ 657639a06cSTakashi Iwai codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 667639a06cSTakashi Iwai AC_PAR_VENDOR_ID); 677639a06cSTakashi Iwai if (codec->vendor_id == -1) { 687639a06cSTakashi Iwai /* read again, hopefully the access method was corrected 697639a06cSTakashi Iwai * in the last read... 707639a06cSTakashi Iwai */ 717639a06cSTakashi Iwai codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 727639a06cSTakashi Iwai AC_PAR_VENDOR_ID); 737639a06cSTakashi Iwai } 747639a06cSTakashi Iwai 757639a06cSTakashi Iwai codec->subsystem_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 767639a06cSTakashi Iwai AC_PAR_SUBSYSTEM_ID); 777639a06cSTakashi Iwai codec->revision_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 787639a06cSTakashi Iwai AC_PAR_REV_ID); 797639a06cSTakashi Iwai 807639a06cSTakashi Iwai setup_fg_nodes(codec); 817639a06cSTakashi Iwai if (!codec->afg && !codec->mfg) { 827639a06cSTakashi Iwai dev_err(dev, "no AFG or MFG node found\n"); 837639a06cSTakashi Iwai err = -ENODEV; 847639a06cSTakashi Iwai goto error; 857639a06cSTakashi Iwai } 867639a06cSTakashi Iwai 877639a06cSTakashi Iwai fg = codec->afg ? codec->afg : codec->mfg; 887639a06cSTakashi Iwai 897639a06cSTakashi Iwai err = snd_hdac_refresh_widgets(codec); 907639a06cSTakashi Iwai if (err < 0) 917639a06cSTakashi Iwai goto error; 927639a06cSTakashi Iwai 937639a06cSTakashi Iwai codec->power_caps = snd_hdac_read_parm(codec, fg, AC_PAR_POWER_STATE); 947639a06cSTakashi Iwai /* reread ssid if not set by parameter */ 957639a06cSTakashi Iwai if (codec->subsystem_id == -1) 967639a06cSTakashi Iwai snd_hdac_read(codec, fg, AC_VERB_GET_SUBSYSTEM_ID, 0, 977639a06cSTakashi Iwai &codec->subsystem_id); 987639a06cSTakashi Iwai 997639a06cSTakashi Iwai err = get_codec_vendor_name(codec); 1007639a06cSTakashi Iwai if (err < 0) 1017639a06cSTakashi Iwai goto error; 1027639a06cSTakashi Iwai 1037639a06cSTakashi Iwai codec->chip_name = kasprintf(GFP_KERNEL, "ID %x", 1047639a06cSTakashi Iwai codec->vendor_id & 0xffff); 1057639a06cSTakashi Iwai if (!codec->chip_name) { 1067639a06cSTakashi Iwai err = -ENOMEM; 1077639a06cSTakashi Iwai goto error; 1087639a06cSTakashi Iwai } 1097639a06cSTakashi Iwai 1107639a06cSTakashi Iwai return 0; 1117639a06cSTakashi Iwai 1127639a06cSTakashi Iwai error: 1137639a06cSTakashi Iwai put_device(&codec->dev); 1147639a06cSTakashi Iwai return err; 1157639a06cSTakashi Iwai } 1167639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_init); 1177639a06cSTakashi Iwai 1187639a06cSTakashi Iwai /** 1197639a06cSTakashi Iwai * snd_hdac_device_exit - clean up the HD-audio codec base device 1207639a06cSTakashi Iwai * @codec: device to clean up 1217639a06cSTakashi Iwai */ 1227639a06cSTakashi Iwai void snd_hdac_device_exit(struct hdac_device *codec) 1237639a06cSTakashi Iwai { 124c4c2533fSTakashi Iwai pm_runtime_put_noidle(&codec->dev); 1257639a06cSTakashi Iwai snd_hdac_bus_remove_device(codec->bus, codec); 1267639a06cSTakashi Iwai kfree(codec->vendor_name); 1277639a06cSTakashi Iwai kfree(codec->chip_name); 1287639a06cSTakashi Iwai } 1297639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_exit); 1307639a06cSTakashi Iwai 1317639a06cSTakashi Iwai /** 1323256be65STakashi Iwai * snd_hdac_device_register - register the hd-audio codec base device 1333256be65STakashi Iwai * codec: the device to register 1343256be65STakashi Iwai */ 1353256be65STakashi Iwai int snd_hdac_device_register(struct hdac_device *codec) 1363256be65STakashi Iwai { 1373256be65STakashi Iwai int err; 1383256be65STakashi Iwai 1393256be65STakashi Iwai err = device_add(&codec->dev); 1403256be65STakashi Iwai if (err < 0) 1413256be65STakashi Iwai return err; 1423256be65STakashi Iwai err = hda_widget_sysfs_init(codec); 1433256be65STakashi Iwai if (err < 0) { 1443256be65STakashi Iwai device_del(&codec->dev); 1453256be65STakashi Iwai return err; 1463256be65STakashi Iwai } 1473256be65STakashi Iwai 1483256be65STakashi Iwai return 0; 1493256be65STakashi Iwai } 1503256be65STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_register); 1513256be65STakashi Iwai 1523256be65STakashi Iwai /** 1533256be65STakashi Iwai * snd_hdac_device_unregister - unregister the hd-audio codec base device 1543256be65STakashi Iwai * codec: the device to unregister 1553256be65STakashi Iwai */ 1563256be65STakashi Iwai void snd_hdac_device_unregister(struct hdac_device *codec) 1573256be65STakashi Iwai { 1583256be65STakashi Iwai if (device_is_registered(&codec->dev)) { 1593256be65STakashi Iwai hda_widget_sysfs_exit(codec); 1603256be65STakashi Iwai device_del(&codec->dev); 1613256be65STakashi Iwai } 1623256be65STakashi Iwai } 1633256be65STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_device_unregister); 1643256be65STakashi Iwai 1653256be65STakashi Iwai /** 1667639a06cSTakashi Iwai * snd_hdac_make_cmd - compose a 32bit command word to be sent to the 1677639a06cSTakashi Iwai * HD-audio controller 1687639a06cSTakashi Iwai * @codec: the codec object 1697639a06cSTakashi Iwai * @nid: NID to encode 1707639a06cSTakashi Iwai * @verb: verb to encode 1717639a06cSTakashi Iwai * @parm: parameter to encode 1727639a06cSTakashi Iwai * 1737639a06cSTakashi Iwai * Return an encoded command verb or -1 for error. 1747639a06cSTakashi Iwai */ 1757639a06cSTakashi Iwai unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, 1767639a06cSTakashi Iwai unsigned int verb, unsigned int parm) 1777639a06cSTakashi Iwai { 1787639a06cSTakashi Iwai u32 val, addr; 1797639a06cSTakashi Iwai 1807639a06cSTakashi Iwai addr = codec->addr; 1817639a06cSTakashi Iwai if ((addr & ~0xf) || (nid & ~0x7f) || 1827639a06cSTakashi Iwai (verb & ~0xfff) || (parm & ~0xffff)) { 1837639a06cSTakashi Iwai dev_err(&codec->dev, "out of range cmd %x:%x:%x:%x\n", 1847639a06cSTakashi Iwai addr, nid, verb, parm); 1857639a06cSTakashi Iwai return -1; 1867639a06cSTakashi Iwai } 1877639a06cSTakashi Iwai 1887639a06cSTakashi Iwai val = addr << 28; 1897639a06cSTakashi Iwai val |= (u32)nid << 20; 1907639a06cSTakashi Iwai val |= verb << 8; 1917639a06cSTakashi Iwai val |= parm; 1927639a06cSTakashi Iwai return val; 1937639a06cSTakashi Iwai } 1947639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_make_cmd); 1957639a06cSTakashi Iwai 1967639a06cSTakashi Iwai /** 19705852448STakashi Iwai * snd_hdac_exec_verb - execute an encoded verb 19805852448STakashi Iwai * @codec: the codec object 19905852448STakashi Iwai * @cmd: encoded verb to execute 20005852448STakashi Iwai * @flags: optional flags, pass zero for default 20105852448STakashi Iwai * @res: the pointer to store the result, NULL if running async 20205852448STakashi Iwai * 20305852448STakashi Iwai * Returns zero if successful, or a negative error code. 20405852448STakashi Iwai * 20505852448STakashi Iwai * This calls the exec_verb op when set in hdac_codec. If not, 20605852448STakashi Iwai * call the default snd_hdac_bus_exec_verb(). 20705852448STakashi Iwai */ 20805852448STakashi Iwai int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, 20905852448STakashi Iwai unsigned int flags, unsigned int *res) 21005852448STakashi Iwai { 21105852448STakashi Iwai if (codec->exec_verb) 21205852448STakashi Iwai return codec->exec_verb(codec, cmd, flags, res); 21305852448STakashi Iwai return snd_hdac_bus_exec_verb(codec->bus, codec->addr, cmd, res); 21405852448STakashi Iwai } 21505852448STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_exec_verb); 21605852448STakashi Iwai 21705852448STakashi Iwai 21805852448STakashi Iwai /** 2197639a06cSTakashi Iwai * snd_hdac_read - execute a verb 2207639a06cSTakashi Iwai * @codec: the codec object 2217639a06cSTakashi Iwai * @nid: NID to execute a verb 2227639a06cSTakashi Iwai * @verb: verb to execute 2237639a06cSTakashi Iwai * @parm: parameter for a verb 2247639a06cSTakashi Iwai * @res: the pointer to store the result, NULL if running async 2257639a06cSTakashi Iwai * 2267639a06cSTakashi Iwai * Returns zero if successful, or a negative error code. 2277639a06cSTakashi Iwai */ 2287639a06cSTakashi Iwai int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid, 2297639a06cSTakashi Iwai unsigned int verb, unsigned int parm, unsigned int *res) 2307639a06cSTakashi Iwai { 2317639a06cSTakashi Iwai unsigned int cmd = snd_hdac_make_cmd(codec, nid, verb, parm); 2327639a06cSTakashi Iwai 23305852448STakashi Iwai return snd_hdac_exec_verb(codec, cmd, 0, res); 2347639a06cSTakashi Iwai } 2357639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_read); 2367639a06cSTakashi Iwai 2377639a06cSTakashi Iwai /** 238*01ed3c06STakashi Iwai * _snd_hdac_read_parm - read a parmeter 2397639a06cSTakashi Iwai * 240*01ed3c06STakashi Iwai * This function returns zero or an error unlike snd_hdac_read_parm(). 2417639a06cSTakashi Iwai */ 242*01ed3c06STakashi Iwai int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm, 243*01ed3c06STakashi Iwai unsigned int *res) 2447639a06cSTakashi Iwai { 245*01ed3c06STakashi Iwai unsigned int cmd; 2467639a06cSTakashi Iwai 247*01ed3c06STakashi Iwai cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; 248*01ed3c06STakashi Iwai return snd_hdac_regmap_read_raw(codec, cmd, res); 2497639a06cSTakashi Iwai } 250*01ed3c06STakashi Iwai EXPORT_SYMBOL_GPL(_snd_hdac_read_parm); 2517639a06cSTakashi Iwai 2527639a06cSTakashi Iwai /** 2537639a06cSTakashi Iwai * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes 2547639a06cSTakashi Iwai * @codec: the codec object 2557639a06cSTakashi Iwai * @nid: NID to inspect 2567639a06cSTakashi Iwai * @start_id: the pointer to store the starting NID 2577639a06cSTakashi Iwai * 2587639a06cSTakashi Iwai * Returns the number of subtree nodes or zero if not found. 2597639a06cSTakashi Iwai */ 2607639a06cSTakashi Iwai int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, 2617639a06cSTakashi Iwai hda_nid_t *start_id) 2627639a06cSTakashi Iwai { 2637639a06cSTakashi Iwai unsigned int parm; 2647639a06cSTakashi Iwai 2657639a06cSTakashi Iwai parm = snd_hdac_read_parm(codec, nid, AC_PAR_NODE_COUNT); 2667639a06cSTakashi Iwai if (parm == -1) { 2677639a06cSTakashi Iwai *start_id = 0; 2687639a06cSTakashi Iwai return 0; 2697639a06cSTakashi Iwai } 2707639a06cSTakashi Iwai *start_id = (parm >> 16) & 0x7fff; 2717639a06cSTakashi Iwai return (int)(parm & 0x7fff); 2727639a06cSTakashi Iwai } 2737639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_sub_nodes); 2747639a06cSTakashi Iwai 2757639a06cSTakashi Iwai /* 2767639a06cSTakashi Iwai * look for an AFG and MFG nodes 2777639a06cSTakashi Iwai */ 2787639a06cSTakashi Iwai static void setup_fg_nodes(struct hdac_device *codec) 2797639a06cSTakashi Iwai { 2807639a06cSTakashi Iwai int i, total_nodes, function_id; 2817639a06cSTakashi Iwai hda_nid_t nid; 2827639a06cSTakashi Iwai 2837639a06cSTakashi Iwai total_nodes = snd_hdac_get_sub_nodes(codec, AC_NODE_ROOT, &nid); 2847639a06cSTakashi Iwai for (i = 0; i < total_nodes; i++, nid++) { 2857639a06cSTakashi Iwai function_id = snd_hdac_read_parm(codec, nid, 2867639a06cSTakashi Iwai AC_PAR_FUNCTION_TYPE); 2877639a06cSTakashi Iwai switch (function_id & 0xff) { 2887639a06cSTakashi Iwai case AC_GRP_AUDIO_FUNCTION: 2897639a06cSTakashi Iwai codec->afg = nid; 2907639a06cSTakashi Iwai codec->afg_function_id = function_id & 0xff; 2917639a06cSTakashi Iwai codec->afg_unsol = (function_id >> 8) & 1; 2927639a06cSTakashi Iwai break; 2937639a06cSTakashi Iwai case AC_GRP_MODEM_FUNCTION: 2947639a06cSTakashi Iwai codec->mfg = nid; 2957639a06cSTakashi Iwai codec->mfg_function_id = function_id & 0xff; 2967639a06cSTakashi Iwai codec->mfg_unsol = (function_id >> 8) & 1; 2977639a06cSTakashi Iwai break; 2987639a06cSTakashi Iwai default: 2997639a06cSTakashi Iwai break; 3007639a06cSTakashi Iwai } 3017639a06cSTakashi Iwai } 3027639a06cSTakashi Iwai } 3037639a06cSTakashi Iwai 3047639a06cSTakashi Iwai /** 3057639a06cSTakashi Iwai * snd_hdac_refresh_widgets - Reset the widget start/end nodes 3067639a06cSTakashi Iwai * @codec: the codec object 3077639a06cSTakashi Iwai */ 3087639a06cSTakashi Iwai int snd_hdac_refresh_widgets(struct hdac_device *codec) 3097639a06cSTakashi Iwai { 3107639a06cSTakashi Iwai hda_nid_t start_nid; 3117639a06cSTakashi Iwai int nums; 3127639a06cSTakashi Iwai 3137639a06cSTakashi Iwai nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); 3147639a06cSTakashi Iwai if (!start_nid || nums <= 0 || nums >= 0xff) { 3157639a06cSTakashi Iwai dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n", 3167639a06cSTakashi Iwai codec->afg); 3177639a06cSTakashi Iwai return -EINVAL; 3187639a06cSTakashi Iwai } 3197639a06cSTakashi Iwai 3207639a06cSTakashi Iwai codec->num_nodes = nums; 3217639a06cSTakashi Iwai codec->start_nid = start_nid; 3227639a06cSTakashi Iwai codec->end_nid = start_nid + nums; 3237639a06cSTakashi Iwai return 0; 3247639a06cSTakashi Iwai } 3257639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); 3267639a06cSTakashi Iwai 3277639a06cSTakashi Iwai /* return CONNLIST_LEN parameter of the given widget */ 3287639a06cSTakashi Iwai static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) 3297639a06cSTakashi Iwai { 3307639a06cSTakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 3317639a06cSTakashi Iwai unsigned int parm; 3327639a06cSTakashi Iwai 3337639a06cSTakashi Iwai if (!(wcaps & AC_WCAP_CONN_LIST) && 3347639a06cSTakashi Iwai get_wcaps_type(wcaps) != AC_WID_VOL_KNB) 3357639a06cSTakashi Iwai return 0; 3367639a06cSTakashi Iwai 3377639a06cSTakashi Iwai parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN); 3387639a06cSTakashi Iwai if (parm == -1) 3397639a06cSTakashi Iwai parm = 0; 3407639a06cSTakashi Iwai return parm; 3417639a06cSTakashi Iwai } 3427639a06cSTakashi Iwai 3437639a06cSTakashi Iwai /** 3447639a06cSTakashi Iwai * snd_hdac_get_connections - get a widget connection list 3457639a06cSTakashi Iwai * @codec: the codec object 3467639a06cSTakashi Iwai * @nid: NID 3477639a06cSTakashi Iwai * @conn_list: the array to store the results, can be NULL 3487639a06cSTakashi Iwai * @max_conns: the max size of the given array 3497639a06cSTakashi Iwai * 3507639a06cSTakashi Iwai * Returns the number of connected widgets, zero for no connection, or a 3517639a06cSTakashi Iwai * negative error code. When the number of elements don't fit with the 3527639a06cSTakashi Iwai * given array size, it returns -ENOSPC. 3537639a06cSTakashi Iwai * 3547639a06cSTakashi Iwai * When @conn_list is NULL, it just checks the number of connections. 3557639a06cSTakashi Iwai */ 3567639a06cSTakashi Iwai int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, 3577639a06cSTakashi Iwai hda_nid_t *conn_list, int max_conns) 3587639a06cSTakashi Iwai { 3597639a06cSTakashi Iwai unsigned int parm; 3607639a06cSTakashi Iwai int i, conn_len, conns, err; 3617639a06cSTakashi Iwai unsigned int shift, num_elems, mask; 3627639a06cSTakashi Iwai hda_nid_t prev_nid; 3637639a06cSTakashi Iwai int null_count = 0; 3647639a06cSTakashi Iwai 3657639a06cSTakashi Iwai parm = get_num_conns(codec, nid); 3667639a06cSTakashi Iwai if (!parm) 3677639a06cSTakashi Iwai return 0; 3687639a06cSTakashi Iwai 3697639a06cSTakashi Iwai if (parm & AC_CLIST_LONG) { 3707639a06cSTakashi Iwai /* long form */ 3717639a06cSTakashi Iwai shift = 16; 3727639a06cSTakashi Iwai num_elems = 2; 3737639a06cSTakashi Iwai } else { 3747639a06cSTakashi Iwai /* short form */ 3757639a06cSTakashi Iwai shift = 8; 3767639a06cSTakashi Iwai num_elems = 4; 3777639a06cSTakashi Iwai } 3787639a06cSTakashi Iwai conn_len = parm & AC_CLIST_LENGTH; 3797639a06cSTakashi Iwai mask = (1 << (shift-1)) - 1; 3807639a06cSTakashi Iwai 3817639a06cSTakashi Iwai if (!conn_len) 3827639a06cSTakashi Iwai return 0; /* no connection */ 3837639a06cSTakashi Iwai 3847639a06cSTakashi Iwai if (conn_len == 1) { 3857639a06cSTakashi Iwai /* single connection */ 3867639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, AC_VERB_GET_CONNECT_LIST, 0, 3877639a06cSTakashi Iwai &parm); 3887639a06cSTakashi Iwai if (err < 0) 3897639a06cSTakashi Iwai return err; 3907639a06cSTakashi Iwai if (conn_list) 3917639a06cSTakashi Iwai conn_list[0] = parm & mask; 3927639a06cSTakashi Iwai return 1; 3937639a06cSTakashi Iwai } 3947639a06cSTakashi Iwai 3957639a06cSTakashi Iwai /* multi connection */ 3967639a06cSTakashi Iwai conns = 0; 3977639a06cSTakashi Iwai prev_nid = 0; 3987639a06cSTakashi Iwai for (i = 0; i < conn_len; i++) { 3997639a06cSTakashi Iwai int range_val; 4007639a06cSTakashi Iwai hda_nid_t val, n; 4017639a06cSTakashi Iwai 4027639a06cSTakashi Iwai if (i % num_elems == 0) { 4037639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, 4047639a06cSTakashi Iwai AC_VERB_GET_CONNECT_LIST, i, 4057639a06cSTakashi Iwai &parm); 4067639a06cSTakashi Iwai if (err < 0) 4077639a06cSTakashi Iwai return -EIO; 4087639a06cSTakashi Iwai } 4097639a06cSTakashi Iwai range_val = !!(parm & (1 << (shift-1))); /* ranges */ 4107639a06cSTakashi Iwai val = parm & mask; 4117639a06cSTakashi Iwai if (val == 0 && null_count++) { /* no second chance */ 4127639a06cSTakashi Iwai dev_dbg(&codec->dev, 4137639a06cSTakashi Iwai "invalid CONNECT_LIST verb %x[%i]:%x\n", 4147639a06cSTakashi Iwai nid, i, parm); 4157639a06cSTakashi Iwai return 0; 4167639a06cSTakashi Iwai } 4177639a06cSTakashi Iwai parm >>= shift; 4187639a06cSTakashi Iwai if (range_val) { 4197639a06cSTakashi Iwai /* ranges between the previous and this one */ 4207639a06cSTakashi Iwai if (!prev_nid || prev_nid >= val) { 4217639a06cSTakashi Iwai dev_warn(&codec->dev, 4227639a06cSTakashi Iwai "invalid dep_range_val %x:%x\n", 4237639a06cSTakashi Iwai prev_nid, val); 4247639a06cSTakashi Iwai continue; 4257639a06cSTakashi Iwai } 4267639a06cSTakashi Iwai for (n = prev_nid + 1; n <= val; n++) { 4277639a06cSTakashi Iwai if (conn_list) { 4287639a06cSTakashi Iwai if (conns >= max_conns) 4297639a06cSTakashi Iwai return -ENOSPC; 4307639a06cSTakashi Iwai conn_list[conns] = n; 4317639a06cSTakashi Iwai } 4327639a06cSTakashi Iwai conns++; 4337639a06cSTakashi Iwai } 4347639a06cSTakashi Iwai } else { 4357639a06cSTakashi Iwai if (conn_list) { 4367639a06cSTakashi Iwai if (conns >= max_conns) 4377639a06cSTakashi Iwai return -ENOSPC; 4387639a06cSTakashi Iwai conn_list[conns] = val; 4397639a06cSTakashi Iwai } 4407639a06cSTakashi Iwai conns++; 4417639a06cSTakashi Iwai } 4427639a06cSTakashi Iwai prev_nid = val; 4437639a06cSTakashi Iwai } 4447639a06cSTakashi Iwai return conns; 4457639a06cSTakashi Iwai } 4467639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_connections); 4477639a06cSTakashi Iwai 4487639a06cSTakashi Iwai #ifdef CONFIG_PM 4497639a06cSTakashi Iwai /** 4507639a06cSTakashi Iwai * snd_hdac_power_up - increment the runtime pm counter 4517639a06cSTakashi Iwai * @codec: the codec object 4527639a06cSTakashi Iwai */ 4537639a06cSTakashi Iwai void snd_hdac_power_up(struct hdac_device *codec) 4547639a06cSTakashi Iwai { 4557639a06cSTakashi Iwai struct device *dev = &codec->dev; 4567639a06cSTakashi Iwai 4577639a06cSTakashi Iwai if (atomic_read(&codec->in_pm)) 4587639a06cSTakashi Iwai return; 4597639a06cSTakashi Iwai pm_runtime_get_sync(dev); 4607639a06cSTakashi Iwai } 4617639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_up); 4627639a06cSTakashi Iwai 4637639a06cSTakashi Iwai /** 4647639a06cSTakashi Iwai * snd_hdac_power_up - decrement the runtime pm counter 4657639a06cSTakashi Iwai * @codec: the codec object 4667639a06cSTakashi Iwai */ 4677639a06cSTakashi Iwai void snd_hdac_power_down(struct hdac_device *codec) 4687639a06cSTakashi Iwai { 4697639a06cSTakashi Iwai struct device *dev = &codec->dev; 4707639a06cSTakashi Iwai 4717639a06cSTakashi Iwai if (atomic_read(&codec->in_pm)) 4727639a06cSTakashi Iwai return; 4737639a06cSTakashi Iwai pm_runtime_mark_last_busy(dev); 4747639a06cSTakashi Iwai pm_runtime_put_autosuspend(dev); 4757639a06cSTakashi Iwai } 4767639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_down); 4777639a06cSTakashi Iwai #endif 4787639a06cSTakashi Iwai 4797639a06cSTakashi Iwai /* codec vendor labels */ 4807639a06cSTakashi Iwai struct hda_vendor_id { 4817639a06cSTakashi Iwai unsigned int id; 4827639a06cSTakashi Iwai const char *name; 4837639a06cSTakashi Iwai }; 4847639a06cSTakashi Iwai 4857639a06cSTakashi Iwai static struct hda_vendor_id hda_vendor_ids[] = { 4867639a06cSTakashi Iwai { 0x1002, "ATI" }, 4877639a06cSTakashi Iwai { 0x1013, "Cirrus Logic" }, 4887639a06cSTakashi Iwai { 0x1057, "Motorola" }, 4897639a06cSTakashi Iwai { 0x1095, "Silicon Image" }, 4907639a06cSTakashi Iwai { 0x10de, "Nvidia" }, 4917639a06cSTakashi Iwai { 0x10ec, "Realtek" }, 4927639a06cSTakashi Iwai { 0x1102, "Creative" }, 4937639a06cSTakashi Iwai { 0x1106, "VIA" }, 4947639a06cSTakashi Iwai { 0x111d, "IDT" }, 4957639a06cSTakashi Iwai { 0x11c1, "LSI" }, 4967639a06cSTakashi Iwai { 0x11d4, "Analog Devices" }, 4977639a06cSTakashi Iwai { 0x13f6, "C-Media" }, 4987639a06cSTakashi Iwai { 0x14f1, "Conexant" }, 4997639a06cSTakashi Iwai { 0x17e8, "Chrontel" }, 5007639a06cSTakashi Iwai { 0x1854, "LG" }, 5017639a06cSTakashi Iwai { 0x1aec, "Wolfson Microelectronics" }, 5027639a06cSTakashi Iwai { 0x1af4, "QEMU" }, 5037639a06cSTakashi Iwai { 0x434d, "C-Media" }, 5047639a06cSTakashi Iwai { 0x8086, "Intel" }, 5057639a06cSTakashi Iwai { 0x8384, "SigmaTel" }, 5067639a06cSTakashi Iwai {} /* terminator */ 5077639a06cSTakashi Iwai }; 5087639a06cSTakashi Iwai 5097639a06cSTakashi Iwai /* store the codec vendor name */ 5107639a06cSTakashi Iwai static int get_codec_vendor_name(struct hdac_device *codec) 5117639a06cSTakashi Iwai { 5127639a06cSTakashi Iwai const struct hda_vendor_id *c; 5137639a06cSTakashi Iwai u16 vendor_id = codec->vendor_id >> 16; 5147639a06cSTakashi Iwai 5157639a06cSTakashi Iwai for (c = hda_vendor_ids; c->id; c++) { 5167639a06cSTakashi Iwai if (c->id == vendor_id) { 5177639a06cSTakashi Iwai codec->vendor_name = kstrdup(c->name, GFP_KERNEL); 5187639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 5197639a06cSTakashi Iwai } 5207639a06cSTakashi Iwai } 5217639a06cSTakashi Iwai 5227639a06cSTakashi Iwai codec->vendor_name = kasprintf(GFP_KERNEL, "Generic %04x", vendor_id); 5237639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 5247639a06cSTakashi Iwai } 525