Browse Source

ALSA: hda - Allow driver to add vendor-specific verbs for regmap

Codecs may have own vendor-specific verbs, and we need to allow each
driver to give such verbs for cached accesses.  Here a verb can be put
into a single array and looked through it at readable and writeable
callbacks.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 10 years ago
parent
commit
5e56bcea50
3 changed files with 31 additions and 1 deletions
  1. 2 1
      include/sound/hda_regmap.h
  2. 1 0
      include/sound/hdaudio.h
  3. 28 0
      sound/hda/hdac_regmap.c

+ 2 - 1
include/sound/hda_regmap.h

@@ -11,7 +11,8 @@
 
 int snd_hdac_regmap_init(struct hdac_device *codec);
 void snd_hdac_regmap_exit(struct hdac_device *codec);
-
+int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
+				    unsigned int verb);
 int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
 			     unsigned int *val);
 int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,

+ 1 - 0
include/sound/hdaudio.h

@@ -75,6 +75,7 @@ struct hdac_device {
 
 	/* regmap */
 	struct regmap *regmap;
+	struct snd_array vendor_verbs;
 	bool lazy_cache:1;	/* don't wake up for writes */
 	bool caps_overwriting:1; /* caps overwrite being in process */
 };

+ 28 - 0
sound/hda/hdac_regmap.c

@@ -60,6 +60,13 @@ static bool hda_writeable_reg(struct device *dev, unsigned int reg)
 {
 	struct hdac_device *codec = dev_to_hdac_dev(dev);
 	unsigned int verb = get_verb(reg);
+	int i;
+
+	for (i = 0; i < codec->vendor_verbs.used; i++) {
+		unsigned int *v = snd_array_elem(&codec->vendor_verbs, i);
+		if (verb == *v)
+			return true;
+	}
 
 	if (codec->caps_overwriting)
 		return true;
@@ -200,6 +207,7 @@ int snd_hdac_regmap_init(struct hdac_device *codec)
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 	codec->regmap = regmap;
+	snd_array_init(&codec->vendor_verbs, sizeof(unsigned int), 8);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_regmap_init);
@@ -209,10 +217,30 @@ void snd_hdac_regmap_exit(struct hdac_device *codec)
 	if (codec->regmap) {
 		regmap_exit(codec->regmap);
 		codec->regmap = NULL;
+		snd_array_free(&codec->vendor_verbs);
 	}
 }
 EXPORT_SYMBOL_GPL(snd_hdac_regmap_exit);
 
+/**
+ * snd_hdac_regmap_add_vendor_verb - add a vendor-specific verb to regmap
+ * @codec: the codec object
+ * @verb: verb to allow accessing via regmap
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
+				    unsigned int verb)
+{
+	unsigned int *p = snd_array_new(&codec->vendor_verbs);
+
+	if (!p)
+		return -ENOMEM;
+	*p = verb;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb);
+
 /*
  * helper functions
  */