xref: /openbmc/linux/sound/hda/hdac_sysfs.c (revision 3256be65)
13256be65STakashi Iwai /*
23256be65STakashi Iwai  * sysfs support for HD-audio core device
33256be65STakashi Iwai  */
43256be65STakashi Iwai 
53256be65STakashi Iwai #include <linux/slab.h>
63256be65STakashi Iwai #include <linux/sysfs.h>
73256be65STakashi Iwai #include <linux/device.h>
83256be65STakashi Iwai #include <sound/core.h>
93256be65STakashi Iwai #include <sound/hdaudio.h>
103256be65STakashi Iwai #include "local.h"
113256be65STakashi Iwai 
123256be65STakashi Iwai struct hdac_widget_tree {
133256be65STakashi Iwai 	struct kobject *root;
143256be65STakashi Iwai 	struct kobject *afg;
153256be65STakashi Iwai 	struct kobject **nodes;
163256be65STakashi Iwai };
173256be65STakashi Iwai 
183256be65STakashi Iwai #define CODEC_ATTR(type)					\
193256be65STakashi Iwai static ssize_t type##_show(struct device *dev,			\
203256be65STakashi Iwai 			   struct device_attribute *attr,	\
213256be65STakashi Iwai 			   char *buf)				\
223256be65STakashi Iwai {								\
233256be65STakashi Iwai 	struct hdac_device *codec = dev_to_hdac_dev(dev);	\
243256be65STakashi Iwai 	return sprintf(buf, "0x%x\n", codec->type);		\
253256be65STakashi Iwai } \
263256be65STakashi Iwai static DEVICE_ATTR_RO(type)
273256be65STakashi Iwai 
283256be65STakashi Iwai #define CODEC_ATTR_STR(type)					\
293256be65STakashi Iwai static ssize_t type##_show(struct device *dev,			\
303256be65STakashi Iwai 			     struct device_attribute *attr,	\
313256be65STakashi Iwai 					char *buf)		\
323256be65STakashi Iwai {								\
333256be65STakashi Iwai 	struct hdac_device *codec = dev_to_hdac_dev(dev);	\
343256be65STakashi Iwai 	return sprintf(buf, "%s\n",				\
353256be65STakashi Iwai 		       codec->type ? codec->type : "");		\
363256be65STakashi Iwai } \
373256be65STakashi Iwai static DEVICE_ATTR_RO(type)
383256be65STakashi Iwai 
393256be65STakashi Iwai CODEC_ATTR(vendor_id);
403256be65STakashi Iwai CODEC_ATTR(subsystem_id);
413256be65STakashi Iwai CODEC_ATTR(revision_id);
423256be65STakashi Iwai CODEC_ATTR(afg);
433256be65STakashi Iwai CODEC_ATTR(mfg);
443256be65STakashi Iwai CODEC_ATTR_STR(vendor_name);
453256be65STakashi Iwai CODEC_ATTR_STR(chip_name);
463256be65STakashi Iwai 
473256be65STakashi Iwai static struct attribute *hdac_dev_attrs[] = {
483256be65STakashi Iwai 	&dev_attr_vendor_id.attr,
493256be65STakashi Iwai 	&dev_attr_subsystem_id.attr,
503256be65STakashi Iwai 	&dev_attr_revision_id.attr,
513256be65STakashi Iwai 	&dev_attr_afg.attr,
523256be65STakashi Iwai 	&dev_attr_mfg.attr,
533256be65STakashi Iwai 	&dev_attr_vendor_name.attr,
543256be65STakashi Iwai 	&dev_attr_chip_name.attr,
553256be65STakashi Iwai 	NULL
563256be65STakashi Iwai };
573256be65STakashi Iwai 
583256be65STakashi Iwai static struct attribute_group hdac_dev_attr_group = {
593256be65STakashi Iwai 	.attrs	= hdac_dev_attrs,
603256be65STakashi Iwai };
613256be65STakashi Iwai 
623256be65STakashi Iwai const struct attribute_group *hdac_dev_attr_groups[] = {
633256be65STakashi Iwai 	&hdac_dev_attr_group,
643256be65STakashi Iwai 	NULL
653256be65STakashi Iwai };
663256be65STakashi Iwai 
673256be65STakashi Iwai /*
683256be65STakashi Iwai  * Widget tree sysfs
693256be65STakashi Iwai  *
703256be65STakashi Iwai  * This is a tree showing the attributes of each widget.  It appears like
713256be65STakashi Iwai  * /sys/bus/hdaudioC0D0/widgets/04/caps
723256be65STakashi Iwai  */
733256be65STakashi Iwai 
743256be65STakashi Iwai struct widget_attribute;
753256be65STakashi Iwai 
763256be65STakashi Iwai struct widget_attribute {
773256be65STakashi Iwai 	struct attribute	attr;
783256be65STakashi Iwai 	ssize_t (*show)(struct hdac_device *codec, hda_nid_t nid,
793256be65STakashi Iwai 			struct widget_attribute *attr, char *buf);
803256be65STakashi Iwai 	ssize_t (*store)(struct hdac_device *codec, hda_nid_t nid,
813256be65STakashi Iwai 			 struct widget_attribute *attr,
823256be65STakashi Iwai 			 const char *buf, size_t count);
833256be65STakashi Iwai };
843256be65STakashi Iwai 
853256be65STakashi Iwai static int get_codec_nid(struct kobject *kobj, struct hdac_device **codecp)
863256be65STakashi Iwai {
873256be65STakashi Iwai 	struct device *dev = kobj_to_dev(kobj->parent->parent);
883256be65STakashi Iwai 	int nid;
893256be65STakashi Iwai 	ssize_t ret;
903256be65STakashi Iwai 
913256be65STakashi Iwai 	ret = kstrtoint(kobj->name, 16, &nid);
923256be65STakashi Iwai 	if (ret < 0)
933256be65STakashi Iwai 		return ret;
943256be65STakashi Iwai 	*codecp = dev_to_hdac_dev(dev);
953256be65STakashi Iwai 	return nid;
963256be65STakashi Iwai }
973256be65STakashi Iwai 
983256be65STakashi Iwai static ssize_t widget_attr_show(struct kobject *kobj, struct attribute *attr,
993256be65STakashi Iwai 				char *buf)
1003256be65STakashi Iwai {
1013256be65STakashi Iwai 	struct widget_attribute *wid_attr =
1023256be65STakashi Iwai 		container_of(attr, struct widget_attribute, attr);
1033256be65STakashi Iwai 	struct hdac_device *codec;
1043256be65STakashi Iwai 	int nid;
1053256be65STakashi Iwai 
1063256be65STakashi Iwai 	if (!wid_attr->show)
1073256be65STakashi Iwai 		return -EIO;
1083256be65STakashi Iwai 	nid = get_codec_nid(kobj, &codec);
1093256be65STakashi Iwai 	if (nid < 0)
1103256be65STakashi Iwai 		return nid;
1113256be65STakashi Iwai 	return wid_attr->show(codec, nid, wid_attr, buf);
1123256be65STakashi Iwai }
1133256be65STakashi Iwai 
1143256be65STakashi Iwai static ssize_t widget_attr_store(struct kobject *kobj, struct attribute *attr,
1153256be65STakashi Iwai 				 const char *buf, size_t count)
1163256be65STakashi Iwai {
1173256be65STakashi Iwai 	struct widget_attribute *wid_attr =
1183256be65STakashi Iwai 		container_of(attr, struct widget_attribute, attr);
1193256be65STakashi Iwai 	struct hdac_device *codec;
1203256be65STakashi Iwai 	int nid;
1213256be65STakashi Iwai 
1223256be65STakashi Iwai 	if (!wid_attr->store)
1233256be65STakashi Iwai 		return -EIO;
1243256be65STakashi Iwai 	nid = get_codec_nid(kobj, &codec);
1253256be65STakashi Iwai 	if (nid < 0)
1263256be65STakashi Iwai 		return nid;
1273256be65STakashi Iwai 	return wid_attr->store(codec, nid, wid_attr, buf, count);
1283256be65STakashi Iwai }
1293256be65STakashi Iwai 
1303256be65STakashi Iwai static const struct sysfs_ops widget_sysfs_ops = {
1313256be65STakashi Iwai 	.show	= widget_attr_show,
1323256be65STakashi Iwai 	.store	= widget_attr_store,
1333256be65STakashi Iwai };
1343256be65STakashi Iwai 
1353256be65STakashi Iwai static void widget_release(struct kobject *kobj)
1363256be65STakashi Iwai {
1373256be65STakashi Iwai 	kfree(kobj);
1383256be65STakashi Iwai }
1393256be65STakashi Iwai 
1403256be65STakashi Iwai static struct kobj_type widget_ktype = {
1413256be65STakashi Iwai 	.release	= widget_release,
1423256be65STakashi Iwai 	.sysfs_ops	= &widget_sysfs_ops,
1433256be65STakashi Iwai };
1443256be65STakashi Iwai 
1453256be65STakashi Iwai #define WIDGET_ATTR_RO(_name) \
1463256be65STakashi Iwai 	struct widget_attribute wid_attr_##_name = __ATTR_RO(_name)
1473256be65STakashi Iwai #define WIDGET_ATTR_RW(_name) \
1483256be65STakashi Iwai 	struct widget_attribute wid_attr_##_name = __ATTR_RW(_name)
1493256be65STakashi Iwai 
1503256be65STakashi Iwai static ssize_t caps_show(struct hdac_device *codec, hda_nid_t nid,
1513256be65STakashi Iwai 			struct widget_attribute *attr, char *buf)
1523256be65STakashi Iwai {
1533256be65STakashi Iwai 	return sprintf(buf, "0x%08x\n", get_wcaps(codec, nid));
1543256be65STakashi Iwai }
1553256be65STakashi Iwai 
1563256be65STakashi Iwai static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid,
1573256be65STakashi Iwai 			     struct widget_attribute *attr, char *buf)
1583256be65STakashi Iwai {
1593256be65STakashi Iwai 	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1603256be65STakashi Iwai 		return 0;
1613256be65STakashi Iwai 	return sprintf(buf, "0x%08x\n",
1623256be65STakashi Iwai 		       snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP));
1633256be65STakashi Iwai }
1643256be65STakashi Iwai 
1653256be65STakashi Iwai static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid,
1663256be65STakashi Iwai 			    struct widget_attribute *attr, char *buf)
1673256be65STakashi Iwai {
1683256be65STakashi Iwai 	unsigned int val;
1693256be65STakashi Iwai 
1703256be65STakashi Iwai 	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1713256be65STakashi Iwai 		return 0;
1723256be65STakashi Iwai 	if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val))
1733256be65STakashi Iwai 		return 0;
1743256be65STakashi Iwai 	return sprintf(buf, "0x%08x\n", val);
1753256be65STakashi Iwai }
1763256be65STakashi Iwai 
1773256be65STakashi Iwai static bool has_pcm_cap(struct hdac_device *codec, hda_nid_t nid)
1783256be65STakashi Iwai {
1793256be65STakashi Iwai 	if (nid == codec->afg || nid == codec->mfg)
1803256be65STakashi Iwai 		return true;
1813256be65STakashi Iwai 	switch (get_wcaps_type(get_wcaps(codec, nid))) {
1823256be65STakashi Iwai 	case AC_WID_AUD_OUT:
1833256be65STakashi Iwai 	case AC_WID_AUD_IN:
1843256be65STakashi Iwai 		return true;
1853256be65STakashi Iwai 	default:
1863256be65STakashi Iwai 		return false;
1873256be65STakashi Iwai 	}
1883256be65STakashi Iwai }
1893256be65STakashi Iwai 
1903256be65STakashi Iwai static ssize_t pcm_caps_show(struct hdac_device *codec, hda_nid_t nid,
1913256be65STakashi Iwai 			     struct widget_attribute *attr, char *buf)
1923256be65STakashi Iwai {
1933256be65STakashi Iwai 	if (!has_pcm_cap(codec, nid))
1943256be65STakashi Iwai 		return 0;
1953256be65STakashi Iwai 	return sprintf(buf, "0x%08x\n",
1963256be65STakashi Iwai 		       snd_hdac_read_parm(codec, nid, AC_PAR_PCM));
1973256be65STakashi Iwai }
1983256be65STakashi Iwai 
1993256be65STakashi Iwai static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid,
2003256be65STakashi Iwai 				struct widget_attribute *attr, char *buf)
2013256be65STakashi Iwai {
2023256be65STakashi Iwai 	if (!has_pcm_cap(codec, nid))
2033256be65STakashi Iwai 		return 0;
2043256be65STakashi Iwai 	return sprintf(buf, "0x%08x\n",
2053256be65STakashi Iwai 		       snd_hdac_read_parm(codec, nid, AC_PAR_STREAM));
2063256be65STakashi Iwai }
2073256be65STakashi Iwai 
2083256be65STakashi Iwai static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid,
2093256be65STakashi Iwai 				struct widget_attribute *attr, char *buf)
2103256be65STakashi Iwai {
2113256be65STakashi Iwai 	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
2123256be65STakashi Iwai 		return 0;
2133256be65STakashi Iwai 	return sprintf(buf, "0x%08x\n",
2143256be65STakashi Iwai 		       snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP));
2153256be65STakashi Iwai }
2163256be65STakashi Iwai 
2173256be65STakashi Iwai static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid,
2183256be65STakashi Iwai 				 struct widget_attribute *attr, char *buf)
2193256be65STakashi Iwai {
2203256be65STakashi Iwai 	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
2213256be65STakashi Iwai 		return 0;
2223256be65STakashi Iwai 	return sprintf(buf, "0x%08x\n",
2233256be65STakashi Iwai 		       snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP));
2243256be65STakashi Iwai }
2253256be65STakashi Iwai 
2263256be65STakashi Iwai static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid,
2273256be65STakashi Iwai 			       struct widget_attribute *attr, char *buf)
2283256be65STakashi Iwai {
2293256be65STakashi Iwai 	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_POWER))
2303256be65STakashi Iwai 		return 0;
2313256be65STakashi Iwai 	return sprintf(buf, "0x%08x\n",
2323256be65STakashi Iwai 		       snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE));
2333256be65STakashi Iwai }
2343256be65STakashi Iwai 
2353256be65STakashi Iwai static ssize_t gpio_caps_show(struct hdac_device *codec, hda_nid_t nid,
2363256be65STakashi Iwai 			      struct widget_attribute *attr, char *buf)
2373256be65STakashi Iwai {
2383256be65STakashi Iwai 	return sprintf(buf, "0x%08x\n",
2393256be65STakashi Iwai 		       snd_hdac_read_parm(codec, nid, AC_PAR_GPIO_CAP));
2403256be65STakashi Iwai }
2413256be65STakashi Iwai 
2423256be65STakashi Iwai static ssize_t connections_show(struct hdac_device *codec, hda_nid_t nid,
2433256be65STakashi Iwai 				struct widget_attribute *attr, char *buf)
2443256be65STakashi Iwai {
2453256be65STakashi Iwai 	hda_nid_t list[32];
2463256be65STakashi Iwai 	int i, nconns;
2473256be65STakashi Iwai 	ssize_t ret = 0;
2483256be65STakashi Iwai 
2493256be65STakashi Iwai 	nconns = snd_hdac_get_connections(codec, nid, list, ARRAY_SIZE(list));
2503256be65STakashi Iwai 	if (nconns <= 0)
2513256be65STakashi Iwai 		return nconns;
2523256be65STakashi Iwai 	for (i = 0; i < nconns; i++)
2533256be65STakashi Iwai 		ret += sprintf(buf + ret, "%s0x%02x", i ? " " : "", list[i]);
2543256be65STakashi Iwai 	ret += sprintf(buf + ret, "\n");
2553256be65STakashi Iwai 	return ret;
2563256be65STakashi Iwai }
2573256be65STakashi Iwai 
2583256be65STakashi Iwai static WIDGET_ATTR_RO(caps);
2593256be65STakashi Iwai static WIDGET_ATTR_RO(pin_caps);
2603256be65STakashi Iwai static WIDGET_ATTR_RO(pin_cfg);
2613256be65STakashi Iwai static WIDGET_ATTR_RO(pcm_caps);
2623256be65STakashi Iwai static WIDGET_ATTR_RO(pcm_formats);
2633256be65STakashi Iwai static WIDGET_ATTR_RO(amp_in_caps);
2643256be65STakashi Iwai static WIDGET_ATTR_RO(amp_out_caps);
2653256be65STakashi Iwai static WIDGET_ATTR_RO(power_caps);
2663256be65STakashi Iwai static WIDGET_ATTR_RO(gpio_caps);
2673256be65STakashi Iwai static WIDGET_ATTR_RO(connections);
2683256be65STakashi Iwai 
2693256be65STakashi Iwai static struct attribute *widget_node_attrs[] = {
2703256be65STakashi Iwai 	&wid_attr_caps.attr,
2713256be65STakashi Iwai 	&wid_attr_pin_caps.attr,
2723256be65STakashi Iwai 	&wid_attr_pin_cfg.attr,
2733256be65STakashi Iwai 	&wid_attr_pcm_caps.attr,
2743256be65STakashi Iwai 	&wid_attr_pcm_formats.attr,
2753256be65STakashi Iwai 	&wid_attr_amp_in_caps.attr,
2763256be65STakashi Iwai 	&wid_attr_amp_out_caps.attr,
2773256be65STakashi Iwai 	&wid_attr_power_caps.attr,
2783256be65STakashi Iwai 	&wid_attr_connections.attr,
2793256be65STakashi Iwai 	NULL,
2803256be65STakashi Iwai };
2813256be65STakashi Iwai 
2823256be65STakashi Iwai static struct attribute *widget_afg_attrs[] = {
2833256be65STakashi Iwai 	&wid_attr_pcm_caps.attr,
2843256be65STakashi Iwai 	&wid_attr_pcm_formats.attr,
2853256be65STakashi Iwai 	&wid_attr_amp_in_caps.attr,
2863256be65STakashi Iwai 	&wid_attr_amp_out_caps.attr,
2873256be65STakashi Iwai 	&wid_attr_power_caps.attr,
2883256be65STakashi Iwai 	&wid_attr_gpio_caps.attr,
2893256be65STakashi Iwai 	NULL,
2903256be65STakashi Iwai };
2913256be65STakashi Iwai 
2923256be65STakashi Iwai static const struct attribute_group widget_node_group = {
2933256be65STakashi Iwai 	.attrs = widget_node_attrs,
2943256be65STakashi Iwai };
2953256be65STakashi Iwai 
2963256be65STakashi Iwai static const struct attribute_group widget_afg_group = {
2973256be65STakashi Iwai 	.attrs = widget_afg_attrs,
2983256be65STakashi Iwai };
2993256be65STakashi Iwai 
3003256be65STakashi Iwai static void free_widget_node(struct kobject *kobj,
3013256be65STakashi Iwai 			     const struct attribute_group *group)
3023256be65STakashi Iwai {
3033256be65STakashi Iwai 	if (kobj) {
3043256be65STakashi Iwai 		sysfs_remove_group(kobj, group);
3053256be65STakashi Iwai 		kobject_put(kobj);
3063256be65STakashi Iwai 	}
3073256be65STakashi Iwai }
3083256be65STakashi Iwai 
3093256be65STakashi Iwai static void widget_tree_free(struct hdac_device *codec)
3103256be65STakashi Iwai {
3113256be65STakashi Iwai 	struct hdac_widget_tree *tree = codec->widgets;
3123256be65STakashi Iwai 	struct kobject **p;
3133256be65STakashi Iwai 
3143256be65STakashi Iwai 	if (!tree)
3153256be65STakashi Iwai 		return;
3163256be65STakashi Iwai 	if (tree->nodes) {
3173256be65STakashi Iwai 		for (p = tree->nodes; *p; p++)
3183256be65STakashi Iwai 			free_widget_node(*p, &widget_node_group);
3193256be65STakashi Iwai 		kfree(tree->nodes);
3203256be65STakashi Iwai 	}
3213256be65STakashi Iwai 	free_widget_node(tree->afg, &widget_afg_group);
3223256be65STakashi Iwai 	if (tree->root)
3233256be65STakashi Iwai 		kobject_put(tree->root);
3243256be65STakashi Iwai 	kfree(tree);
3253256be65STakashi Iwai 	codec->widgets = NULL;
3263256be65STakashi Iwai }
3273256be65STakashi Iwai 
3283256be65STakashi Iwai static int add_widget_node(struct kobject *parent, hda_nid_t nid,
3293256be65STakashi Iwai 			   const struct attribute_group *group,
3303256be65STakashi Iwai 			   struct kobject **res)
3313256be65STakashi Iwai {
3323256be65STakashi Iwai 	struct kobject *kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
3333256be65STakashi Iwai 	int err;
3343256be65STakashi Iwai 
3353256be65STakashi Iwai 	if (!kobj)
3363256be65STakashi Iwai 		return -ENOMEM;
3373256be65STakashi Iwai 	kobject_init(kobj, &widget_ktype);
3383256be65STakashi Iwai 	err = kobject_add(kobj, parent, "%02x", nid);
3393256be65STakashi Iwai 	if (err < 0)
3403256be65STakashi Iwai 		return err;
3413256be65STakashi Iwai 	err = sysfs_create_group(kobj, group);
3423256be65STakashi Iwai 	if (err < 0) {
3433256be65STakashi Iwai 		kobject_put(kobj);
3443256be65STakashi Iwai 		return err;
3453256be65STakashi Iwai 	}
3463256be65STakashi Iwai 
3473256be65STakashi Iwai 	*res = kobj;
3483256be65STakashi Iwai 	return 0;
3493256be65STakashi Iwai }
3503256be65STakashi Iwai 
3513256be65STakashi Iwai static int widget_tree_create(struct hdac_device *codec)
3523256be65STakashi Iwai {
3533256be65STakashi Iwai 	struct hdac_widget_tree *tree;
3543256be65STakashi Iwai 	int i, err;
3553256be65STakashi Iwai 	hda_nid_t nid;
3563256be65STakashi Iwai 
3573256be65STakashi Iwai 	tree = codec->widgets = kzalloc(sizeof(*tree), GFP_KERNEL);
3583256be65STakashi Iwai 	if (!tree)
3593256be65STakashi Iwai 		return -ENOMEM;
3603256be65STakashi Iwai 
3613256be65STakashi Iwai 	tree->root = kobject_create_and_add("widgets", &codec->dev.kobj);
3623256be65STakashi Iwai 	if (!tree->root)
3633256be65STakashi Iwai 		return -ENOMEM;
3643256be65STakashi Iwai 
3653256be65STakashi Iwai 	if (codec->afg) {
3663256be65STakashi Iwai 		err = add_widget_node(tree->root, codec->afg,
3673256be65STakashi Iwai 				      &widget_afg_group, &tree->afg);
3683256be65STakashi Iwai 		if (err < 0)
3693256be65STakashi Iwai 			return err;
3703256be65STakashi Iwai 	}
3713256be65STakashi Iwai 
3723256be65STakashi Iwai 	tree->nodes = kcalloc(codec->num_nodes + 1, sizeof(*tree->nodes),
3733256be65STakashi Iwai 			      GFP_KERNEL);
3743256be65STakashi Iwai 	if (!tree->nodes)
3753256be65STakashi Iwai 		return -ENOMEM;
3763256be65STakashi Iwai 
3773256be65STakashi Iwai 	for (i = 0, nid = codec->start_nid; i < codec->num_nodes; i++, nid++) {
3783256be65STakashi Iwai 		err = add_widget_node(tree->root, nid, &widget_node_group,
3793256be65STakashi Iwai 				      &tree->nodes[i]);
3803256be65STakashi Iwai 		if (err < 0)
3813256be65STakashi Iwai 			return err;
3823256be65STakashi Iwai 	}
3833256be65STakashi Iwai 
3843256be65STakashi Iwai 	kobject_uevent(tree->root, KOBJ_CHANGE);
3853256be65STakashi Iwai 	return 0;
3863256be65STakashi Iwai }
3873256be65STakashi Iwai 
3883256be65STakashi Iwai int hda_widget_sysfs_init(struct hdac_device *codec)
3893256be65STakashi Iwai {
3903256be65STakashi Iwai 	int err;
3913256be65STakashi Iwai 
3923256be65STakashi Iwai 	err = widget_tree_create(codec);
3933256be65STakashi Iwai 	if (err < 0) {
3943256be65STakashi Iwai 		widget_tree_free(codec);
3953256be65STakashi Iwai 		return err;
3963256be65STakashi Iwai 	}
3973256be65STakashi Iwai 
3983256be65STakashi Iwai 	return 0;
3993256be65STakashi Iwai }
4003256be65STakashi Iwai 
4013256be65STakashi Iwai void hda_widget_sysfs_exit(struct hdac_device *codec)
4023256be65STakashi Iwai {
4033256be65STakashi Iwai 	widget_tree_free(codec);
4043256be65STakashi Iwai }
405