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> 127639a06cSTakashi Iwai #include "local.h" 137639a06cSTakashi Iwai 147639a06cSTakashi Iwai static void setup_fg_nodes(struct hdac_device *codec); 157639a06cSTakashi Iwai static int get_codec_vendor_name(struct hdac_device *codec); 167639a06cSTakashi Iwai 177639a06cSTakashi Iwai static void default_release(struct device *dev) 187639a06cSTakashi Iwai { 197639a06cSTakashi Iwai snd_hdac_device_exit(container_of(dev, struct hdac_device, dev)); 207639a06cSTakashi Iwai } 217639a06cSTakashi Iwai 227639a06cSTakashi Iwai /** 237639a06cSTakashi Iwai * snd_hdac_device_init - initialize the HD-audio codec base device 247639a06cSTakashi Iwai * @codec: device to initialize 257639a06cSTakashi Iwai * @bus: but to attach 267639a06cSTakashi Iwai * @name: device name string 277639a06cSTakashi Iwai * @addr: codec address 287639a06cSTakashi Iwai * 297639a06cSTakashi Iwai * Returns zero for success or a negative error code. 307639a06cSTakashi Iwai * 317639a06cSTakashi Iwai * This function increments the runtime PM counter and marks it active. 327639a06cSTakashi Iwai * The caller needs to turn it off appropriately later. 337639a06cSTakashi Iwai * 347639a06cSTakashi Iwai * The caller needs to set the device's release op properly by itself. 357639a06cSTakashi Iwai */ 367639a06cSTakashi Iwai int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, 377639a06cSTakashi Iwai const char *name, unsigned int addr) 387639a06cSTakashi Iwai { 397639a06cSTakashi Iwai struct device *dev; 407639a06cSTakashi Iwai hda_nid_t fg; 417639a06cSTakashi Iwai int err; 427639a06cSTakashi Iwai 437639a06cSTakashi Iwai dev = &codec->dev; 447639a06cSTakashi Iwai device_initialize(dev); 457639a06cSTakashi Iwai dev->parent = bus->dev; 467639a06cSTakashi Iwai dev->bus = &snd_hda_bus_type; 477639a06cSTakashi Iwai dev->release = default_release; 483256be65STakashi Iwai dev->groups = hdac_dev_attr_groups; 497639a06cSTakashi Iwai dev_set_name(dev, "%s", name); 507639a06cSTakashi Iwai device_enable_async_suspend(dev); 517639a06cSTakashi Iwai 527639a06cSTakashi Iwai codec->bus = bus; 537639a06cSTakashi Iwai codec->addr = addr; 547639a06cSTakashi Iwai codec->type = HDA_DEV_CORE; 557639a06cSTakashi Iwai pm_runtime_set_active(&codec->dev); 567639a06cSTakashi Iwai pm_runtime_get_noresume(&codec->dev); 577639a06cSTakashi Iwai atomic_set(&codec->in_pm, 0); 587639a06cSTakashi Iwai 597639a06cSTakashi Iwai err = snd_hdac_bus_add_device(bus, codec); 607639a06cSTakashi Iwai if (err < 0) 617639a06cSTakashi Iwai goto error; 627639a06cSTakashi Iwai 637639a06cSTakashi Iwai /* fill parameters */ 647639a06cSTakashi Iwai codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 657639a06cSTakashi Iwai AC_PAR_VENDOR_ID); 667639a06cSTakashi Iwai if (codec->vendor_id == -1) { 677639a06cSTakashi Iwai /* read again, hopefully the access method was corrected 687639a06cSTakashi Iwai * in the last read... 697639a06cSTakashi Iwai */ 707639a06cSTakashi Iwai codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 717639a06cSTakashi Iwai AC_PAR_VENDOR_ID); 727639a06cSTakashi Iwai } 737639a06cSTakashi Iwai 747639a06cSTakashi Iwai codec->subsystem_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 757639a06cSTakashi Iwai AC_PAR_SUBSYSTEM_ID); 767639a06cSTakashi Iwai codec->revision_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, 777639a06cSTakashi Iwai AC_PAR_REV_ID); 787639a06cSTakashi Iwai 797639a06cSTakashi Iwai setup_fg_nodes(codec); 807639a06cSTakashi Iwai if (!codec->afg && !codec->mfg) { 817639a06cSTakashi Iwai dev_err(dev, "no AFG or MFG node found\n"); 827639a06cSTakashi Iwai err = -ENODEV; 837639a06cSTakashi Iwai goto error; 847639a06cSTakashi Iwai } 857639a06cSTakashi Iwai 867639a06cSTakashi Iwai fg = codec->afg ? codec->afg : codec->mfg; 877639a06cSTakashi Iwai 887639a06cSTakashi Iwai err = snd_hdac_refresh_widgets(codec); 897639a06cSTakashi Iwai if (err < 0) 907639a06cSTakashi Iwai goto error; 917639a06cSTakashi Iwai 927639a06cSTakashi Iwai codec->power_caps = snd_hdac_read_parm(codec, fg, AC_PAR_POWER_STATE); 937639a06cSTakashi Iwai /* reread ssid if not set by parameter */ 947639a06cSTakashi Iwai if (codec->subsystem_id == -1) 957639a06cSTakashi Iwai snd_hdac_read(codec, fg, AC_VERB_GET_SUBSYSTEM_ID, 0, 967639a06cSTakashi Iwai &codec->subsystem_id); 977639a06cSTakashi Iwai 987639a06cSTakashi Iwai err = get_codec_vendor_name(codec); 997639a06cSTakashi Iwai if (err < 0) 1007639a06cSTakashi Iwai goto error; 1017639a06cSTakashi Iwai 1027639a06cSTakashi Iwai codec->chip_name = kasprintf(GFP_KERNEL, "ID %x", 1037639a06cSTakashi Iwai codec->vendor_id & 0xffff); 1047639a06cSTakashi Iwai if (!codec->chip_name) { 1057639a06cSTakashi Iwai err = -ENOMEM; 1067639a06cSTakashi Iwai goto error; 1077639a06cSTakashi Iwai } 1087639a06cSTakashi Iwai 1097639a06cSTakashi Iwai return 0; 1107639a06cSTakashi Iwai 1117639a06cSTakashi Iwai error: 1127639a06cSTakashi Iwai pm_runtime_put_noidle(&codec->dev); 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 { 1247639a06cSTakashi 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 /** 197*05852448STakashi Iwai * snd_hdac_exec_verb - execute an encoded verb 198*05852448STakashi Iwai * @codec: the codec object 199*05852448STakashi Iwai * @cmd: encoded verb to execute 200*05852448STakashi Iwai * @flags: optional flags, pass zero for default 201*05852448STakashi Iwai * @res: the pointer to store the result, NULL if running async 202*05852448STakashi Iwai * 203*05852448STakashi Iwai * Returns zero if successful, or a negative error code. 204*05852448STakashi Iwai * 205*05852448STakashi Iwai * This calls the exec_verb op when set in hdac_codec. If not, 206*05852448STakashi Iwai * call the default snd_hdac_bus_exec_verb(). 207*05852448STakashi Iwai */ 208*05852448STakashi Iwai int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, 209*05852448STakashi Iwai unsigned int flags, unsigned int *res) 210*05852448STakashi Iwai { 211*05852448STakashi Iwai if (codec->exec_verb) 212*05852448STakashi Iwai return codec->exec_verb(codec, cmd, flags, res); 213*05852448STakashi Iwai return snd_hdac_bus_exec_verb(codec->bus, codec->addr, cmd, res); 214*05852448STakashi Iwai } 215*05852448STakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_exec_verb); 216*05852448STakashi Iwai 217*05852448STakashi Iwai 218*05852448STakashi 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 233*05852448STakashi Iwai return snd_hdac_exec_verb(codec, cmd, 0, res); 2347639a06cSTakashi Iwai } 2357639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_read); 2367639a06cSTakashi Iwai 2377639a06cSTakashi Iwai /** 2387639a06cSTakashi Iwai * snd_hdac_read_parm - read a codec parameter 2397639a06cSTakashi Iwai * @codec: the codec object 2407639a06cSTakashi Iwai * @nid: NID to read a parameter 2417639a06cSTakashi Iwai * @parm: parameter to read 2427639a06cSTakashi Iwai * 2437639a06cSTakashi Iwai * Returns -1 for error. If you need to distinguish the error more 2447639a06cSTakashi Iwai * strictly, use snd_hdac_read() directly. 2457639a06cSTakashi Iwai */ 2467639a06cSTakashi Iwai int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm) 2477639a06cSTakashi Iwai { 2487639a06cSTakashi Iwai int val; 2497639a06cSTakashi Iwai 2507639a06cSTakashi Iwai if (snd_hdac_read(codec, nid, AC_VERB_PARAMETERS, parm, &val)) 2517639a06cSTakashi Iwai return -1; 2527639a06cSTakashi Iwai return val; 2537639a06cSTakashi Iwai } 2547639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_read_parm); 2557639a06cSTakashi Iwai 2567639a06cSTakashi Iwai /** 2577639a06cSTakashi Iwai * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes 2587639a06cSTakashi Iwai * @codec: the codec object 2597639a06cSTakashi Iwai * @nid: NID to inspect 2607639a06cSTakashi Iwai * @start_id: the pointer to store the starting NID 2617639a06cSTakashi Iwai * 2627639a06cSTakashi Iwai * Returns the number of subtree nodes or zero if not found. 2637639a06cSTakashi Iwai */ 2647639a06cSTakashi Iwai int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, 2657639a06cSTakashi Iwai hda_nid_t *start_id) 2667639a06cSTakashi Iwai { 2677639a06cSTakashi Iwai unsigned int parm; 2687639a06cSTakashi Iwai 2697639a06cSTakashi Iwai parm = snd_hdac_read_parm(codec, nid, AC_PAR_NODE_COUNT); 2707639a06cSTakashi Iwai if (parm == -1) { 2717639a06cSTakashi Iwai *start_id = 0; 2727639a06cSTakashi Iwai return 0; 2737639a06cSTakashi Iwai } 2747639a06cSTakashi Iwai *start_id = (parm >> 16) & 0x7fff; 2757639a06cSTakashi Iwai return (int)(parm & 0x7fff); 2767639a06cSTakashi Iwai } 2777639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_sub_nodes); 2787639a06cSTakashi Iwai 2797639a06cSTakashi Iwai /* 2807639a06cSTakashi Iwai * look for an AFG and MFG nodes 2817639a06cSTakashi Iwai */ 2827639a06cSTakashi Iwai static void setup_fg_nodes(struct hdac_device *codec) 2837639a06cSTakashi Iwai { 2847639a06cSTakashi Iwai int i, total_nodes, function_id; 2857639a06cSTakashi Iwai hda_nid_t nid; 2867639a06cSTakashi Iwai 2877639a06cSTakashi Iwai total_nodes = snd_hdac_get_sub_nodes(codec, AC_NODE_ROOT, &nid); 2887639a06cSTakashi Iwai for (i = 0; i < total_nodes; i++, nid++) { 2897639a06cSTakashi Iwai function_id = snd_hdac_read_parm(codec, nid, 2907639a06cSTakashi Iwai AC_PAR_FUNCTION_TYPE); 2917639a06cSTakashi Iwai switch (function_id & 0xff) { 2927639a06cSTakashi Iwai case AC_GRP_AUDIO_FUNCTION: 2937639a06cSTakashi Iwai codec->afg = nid; 2947639a06cSTakashi Iwai codec->afg_function_id = function_id & 0xff; 2957639a06cSTakashi Iwai codec->afg_unsol = (function_id >> 8) & 1; 2967639a06cSTakashi Iwai break; 2977639a06cSTakashi Iwai case AC_GRP_MODEM_FUNCTION: 2987639a06cSTakashi Iwai codec->mfg = nid; 2997639a06cSTakashi Iwai codec->mfg_function_id = function_id & 0xff; 3007639a06cSTakashi Iwai codec->mfg_unsol = (function_id >> 8) & 1; 3017639a06cSTakashi Iwai break; 3027639a06cSTakashi Iwai default: 3037639a06cSTakashi Iwai break; 3047639a06cSTakashi Iwai } 3057639a06cSTakashi Iwai } 3067639a06cSTakashi Iwai } 3077639a06cSTakashi Iwai 3087639a06cSTakashi Iwai /** 3097639a06cSTakashi Iwai * snd_hdac_refresh_widgets - Reset the widget start/end nodes 3107639a06cSTakashi Iwai * @codec: the codec object 3117639a06cSTakashi Iwai */ 3127639a06cSTakashi Iwai int snd_hdac_refresh_widgets(struct hdac_device *codec) 3137639a06cSTakashi Iwai { 3147639a06cSTakashi Iwai hda_nid_t start_nid; 3157639a06cSTakashi Iwai int nums; 3167639a06cSTakashi Iwai 3177639a06cSTakashi Iwai nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); 3187639a06cSTakashi Iwai if (!start_nid || nums <= 0 || nums >= 0xff) { 3197639a06cSTakashi Iwai dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n", 3207639a06cSTakashi Iwai codec->afg); 3217639a06cSTakashi Iwai return -EINVAL; 3227639a06cSTakashi Iwai } 3237639a06cSTakashi Iwai 3247639a06cSTakashi Iwai codec->num_nodes = nums; 3257639a06cSTakashi Iwai codec->start_nid = start_nid; 3267639a06cSTakashi Iwai codec->end_nid = start_nid + nums; 3277639a06cSTakashi Iwai return 0; 3287639a06cSTakashi Iwai } 3297639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); 3307639a06cSTakashi Iwai 3317639a06cSTakashi Iwai /* return CONNLIST_LEN parameter of the given widget */ 3327639a06cSTakashi Iwai static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) 3337639a06cSTakashi Iwai { 3347639a06cSTakashi Iwai unsigned int wcaps = get_wcaps(codec, nid); 3357639a06cSTakashi Iwai unsigned int parm; 3367639a06cSTakashi Iwai 3377639a06cSTakashi Iwai if (!(wcaps & AC_WCAP_CONN_LIST) && 3387639a06cSTakashi Iwai get_wcaps_type(wcaps) != AC_WID_VOL_KNB) 3397639a06cSTakashi Iwai return 0; 3407639a06cSTakashi Iwai 3417639a06cSTakashi Iwai parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN); 3427639a06cSTakashi Iwai if (parm == -1) 3437639a06cSTakashi Iwai parm = 0; 3447639a06cSTakashi Iwai return parm; 3457639a06cSTakashi Iwai } 3467639a06cSTakashi Iwai 3477639a06cSTakashi Iwai /** 3487639a06cSTakashi Iwai * snd_hdac_get_connections - get a widget connection list 3497639a06cSTakashi Iwai * @codec: the codec object 3507639a06cSTakashi Iwai * @nid: NID 3517639a06cSTakashi Iwai * @conn_list: the array to store the results, can be NULL 3527639a06cSTakashi Iwai * @max_conns: the max size of the given array 3537639a06cSTakashi Iwai * 3547639a06cSTakashi Iwai * Returns the number of connected widgets, zero for no connection, or a 3557639a06cSTakashi Iwai * negative error code. When the number of elements don't fit with the 3567639a06cSTakashi Iwai * given array size, it returns -ENOSPC. 3577639a06cSTakashi Iwai * 3587639a06cSTakashi Iwai * When @conn_list is NULL, it just checks the number of connections. 3597639a06cSTakashi Iwai */ 3607639a06cSTakashi Iwai int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, 3617639a06cSTakashi Iwai hda_nid_t *conn_list, int max_conns) 3627639a06cSTakashi Iwai { 3637639a06cSTakashi Iwai unsigned int parm; 3647639a06cSTakashi Iwai int i, conn_len, conns, err; 3657639a06cSTakashi Iwai unsigned int shift, num_elems, mask; 3667639a06cSTakashi Iwai hda_nid_t prev_nid; 3677639a06cSTakashi Iwai int null_count = 0; 3687639a06cSTakashi Iwai 3697639a06cSTakashi Iwai parm = get_num_conns(codec, nid); 3707639a06cSTakashi Iwai if (!parm) 3717639a06cSTakashi Iwai return 0; 3727639a06cSTakashi Iwai 3737639a06cSTakashi Iwai if (parm & AC_CLIST_LONG) { 3747639a06cSTakashi Iwai /* long form */ 3757639a06cSTakashi Iwai shift = 16; 3767639a06cSTakashi Iwai num_elems = 2; 3777639a06cSTakashi Iwai } else { 3787639a06cSTakashi Iwai /* short form */ 3797639a06cSTakashi Iwai shift = 8; 3807639a06cSTakashi Iwai num_elems = 4; 3817639a06cSTakashi Iwai } 3827639a06cSTakashi Iwai conn_len = parm & AC_CLIST_LENGTH; 3837639a06cSTakashi Iwai mask = (1 << (shift-1)) - 1; 3847639a06cSTakashi Iwai 3857639a06cSTakashi Iwai if (!conn_len) 3867639a06cSTakashi Iwai return 0; /* no connection */ 3877639a06cSTakashi Iwai 3887639a06cSTakashi Iwai if (conn_len == 1) { 3897639a06cSTakashi Iwai /* single connection */ 3907639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, AC_VERB_GET_CONNECT_LIST, 0, 3917639a06cSTakashi Iwai &parm); 3927639a06cSTakashi Iwai if (err < 0) 3937639a06cSTakashi Iwai return err; 3947639a06cSTakashi Iwai if (conn_list) 3957639a06cSTakashi Iwai conn_list[0] = parm & mask; 3967639a06cSTakashi Iwai return 1; 3977639a06cSTakashi Iwai } 3987639a06cSTakashi Iwai 3997639a06cSTakashi Iwai /* multi connection */ 4007639a06cSTakashi Iwai conns = 0; 4017639a06cSTakashi Iwai prev_nid = 0; 4027639a06cSTakashi Iwai for (i = 0; i < conn_len; i++) { 4037639a06cSTakashi Iwai int range_val; 4047639a06cSTakashi Iwai hda_nid_t val, n; 4057639a06cSTakashi Iwai 4067639a06cSTakashi Iwai if (i % num_elems == 0) { 4077639a06cSTakashi Iwai err = snd_hdac_read(codec, nid, 4087639a06cSTakashi Iwai AC_VERB_GET_CONNECT_LIST, i, 4097639a06cSTakashi Iwai &parm); 4107639a06cSTakashi Iwai if (err < 0) 4117639a06cSTakashi Iwai return -EIO; 4127639a06cSTakashi Iwai } 4137639a06cSTakashi Iwai range_val = !!(parm & (1 << (shift-1))); /* ranges */ 4147639a06cSTakashi Iwai val = parm & mask; 4157639a06cSTakashi Iwai if (val == 0 && null_count++) { /* no second chance */ 4167639a06cSTakashi Iwai dev_dbg(&codec->dev, 4177639a06cSTakashi Iwai "invalid CONNECT_LIST verb %x[%i]:%x\n", 4187639a06cSTakashi Iwai nid, i, parm); 4197639a06cSTakashi Iwai return 0; 4207639a06cSTakashi Iwai } 4217639a06cSTakashi Iwai parm >>= shift; 4227639a06cSTakashi Iwai if (range_val) { 4237639a06cSTakashi Iwai /* ranges between the previous and this one */ 4247639a06cSTakashi Iwai if (!prev_nid || prev_nid >= val) { 4257639a06cSTakashi Iwai dev_warn(&codec->dev, 4267639a06cSTakashi Iwai "invalid dep_range_val %x:%x\n", 4277639a06cSTakashi Iwai prev_nid, val); 4287639a06cSTakashi Iwai continue; 4297639a06cSTakashi Iwai } 4307639a06cSTakashi Iwai for (n = prev_nid + 1; n <= val; n++) { 4317639a06cSTakashi Iwai if (conn_list) { 4327639a06cSTakashi Iwai if (conns >= max_conns) 4337639a06cSTakashi Iwai return -ENOSPC; 4347639a06cSTakashi Iwai conn_list[conns] = n; 4357639a06cSTakashi Iwai } 4367639a06cSTakashi Iwai conns++; 4377639a06cSTakashi Iwai } 4387639a06cSTakashi Iwai } else { 4397639a06cSTakashi Iwai if (conn_list) { 4407639a06cSTakashi Iwai if (conns >= max_conns) 4417639a06cSTakashi Iwai return -ENOSPC; 4427639a06cSTakashi Iwai conn_list[conns] = val; 4437639a06cSTakashi Iwai } 4447639a06cSTakashi Iwai conns++; 4457639a06cSTakashi Iwai } 4467639a06cSTakashi Iwai prev_nid = val; 4477639a06cSTakashi Iwai } 4487639a06cSTakashi Iwai return conns; 4497639a06cSTakashi Iwai } 4507639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_get_connections); 4517639a06cSTakashi Iwai 4527639a06cSTakashi Iwai #ifdef CONFIG_PM 4537639a06cSTakashi Iwai /** 4547639a06cSTakashi Iwai * snd_hdac_power_up - increment the runtime pm counter 4557639a06cSTakashi Iwai * @codec: the codec object 4567639a06cSTakashi Iwai */ 4577639a06cSTakashi Iwai void snd_hdac_power_up(struct hdac_device *codec) 4587639a06cSTakashi Iwai { 4597639a06cSTakashi Iwai struct device *dev = &codec->dev; 4607639a06cSTakashi Iwai 4617639a06cSTakashi Iwai if (atomic_read(&codec->in_pm)) 4627639a06cSTakashi Iwai return; 4637639a06cSTakashi Iwai pm_runtime_get_sync(dev); 4647639a06cSTakashi Iwai } 4657639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_up); 4667639a06cSTakashi Iwai 4677639a06cSTakashi Iwai /** 4687639a06cSTakashi Iwai * snd_hdac_power_up - decrement the runtime pm counter 4697639a06cSTakashi Iwai * @codec: the codec object 4707639a06cSTakashi Iwai */ 4717639a06cSTakashi Iwai void snd_hdac_power_down(struct hdac_device *codec) 4727639a06cSTakashi Iwai { 4737639a06cSTakashi Iwai struct device *dev = &codec->dev; 4747639a06cSTakashi Iwai 4757639a06cSTakashi Iwai if (atomic_read(&codec->in_pm)) 4767639a06cSTakashi Iwai return; 4777639a06cSTakashi Iwai pm_runtime_mark_last_busy(dev); 4787639a06cSTakashi Iwai pm_runtime_put_autosuspend(dev); 4797639a06cSTakashi Iwai } 4807639a06cSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_power_down); 4817639a06cSTakashi Iwai #endif 4827639a06cSTakashi Iwai 4837639a06cSTakashi Iwai /* codec vendor labels */ 4847639a06cSTakashi Iwai struct hda_vendor_id { 4857639a06cSTakashi Iwai unsigned int id; 4867639a06cSTakashi Iwai const char *name; 4877639a06cSTakashi Iwai }; 4887639a06cSTakashi Iwai 4897639a06cSTakashi Iwai static struct hda_vendor_id hda_vendor_ids[] = { 4907639a06cSTakashi Iwai { 0x1002, "ATI" }, 4917639a06cSTakashi Iwai { 0x1013, "Cirrus Logic" }, 4927639a06cSTakashi Iwai { 0x1057, "Motorola" }, 4937639a06cSTakashi Iwai { 0x1095, "Silicon Image" }, 4947639a06cSTakashi Iwai { 0x10de, "Nvidia" }, 4957639a06cSTakashi Iwai { 0x10ec, "Realtek" }, 4967639a06cSTakashi Iwai { 0x1102, "Creative" }, 4977639a06cSTakashi Iwai { 0x1106, "VIA" }, 4987639a06cSTakashi Iwai { 0x111d, "IDT" }, 4997639a06cSTakashi Iwai { 0x11c1, "LSI" }, 5007639a06cSTakashi Iwai { 0x11d4, "Analog Devices" }, 5017639a06cSTakashi Iwai { 0x13f6, "C-Media" }, 5027639a06cSTakashi Iwai { 0x14f1, "Conexant" }, 5037639a06cSTakashi Iwai { 0x17e8, "Chrontel" }, 5047639a06cSTakashi Iwai { 0x1854, "LG" }, 5057639a06cSTakashi Iwai { 0x1aec, "Wolfson Microelectronics" }, 5067639a06cSTakashi Iwai { 0x1af4, "QEMU" }, 5077639a06cSTakashi Iwai { 0x434d, "C-Media" }, 5087639a06cSTakashi Iwai { 0x8086, "Intel" }, 5097639a06cSTakashi Iwai { 0x8384, "SigmaTel" }, 5107639a06cSTakashi Iwai {} /* terminator */ 5117639a06cSTakashi Iwai }; 5127639a06cSTakashi Iwai 5137639a06cSTakashi Iwai /* store the codec vendor name */ 5147639a06cSTakashi Iwai static int get_codec_vendor_name(struct hdac_device *codec) 5157639a06cSTakashi Iwai { 5167639a06cSTakashi Iwai const struct hda_vendor_id *c; 5177639a06cSTakashi Iwai u16 vendor_id = codec->vendor_id >> 16; 5187639a06cSTakashi Iwai 5197639a06cSTakashi Iwai for (c = hda_vendor_ids; c->id; c++) { 5207639a06cSTakashi Iwai if (c->id == vendor_id) { 5217639a06cSTakashi Iwai codec->vendor_name = kstrdup(c->name, GFP_KERNEL); 5227639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 5237639a06cSTakashi Iwai } 5247639a06cSTakashi Iwai } 5257639a06cSTakashi Iwai 5267639a06cSTakashi Iwai codec->vendor_name = kasprintf(GFP_KERNEL, "Generic %04x", vendor_id); 5277639a06cSTakashi Iwai return codec->vendor_name ? 0 : -ENOMEM; 5287639a06cSTakashi Iwai } 529