Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 664bc5c5 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/hda-regmap' into for-next



This merges the support of regmap in HD-audio infrastructure.
Many in-house cache codes in HD-audio driver are relaced with the
more standard regmap base now.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parents ffda568e 9d82f927
Loading
Loading
Loading
Loading
+205 −0
Original line number Diff line number Diff line
/*
 * HD-audio regmap helpers
 */

#ifndef __SOUND_HDA_REGMAP_H
#define __SOUND_HDA_REGMAP_H

#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/hdaudio.h>

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,
			      unsigned int val);
int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
			       unsigned int mask, unsigned int val);

/**
 * snd_hdac_regmap_encode_verb - encode the verb to a pseudo register
 * @nid: widget NID
 * @verb: codec verb
 *
 * Returns an encoded pseudo register.
 */
#define snd_hdac_regmap_encode_verb(nid, verb)		\
	(((verb) << 8) | 0x80000 | ((unsigned int)(nid) << 20))

/**
 * snd_hdac_regmap_encode_amp - encode the AMP verb to a pseudo register
 * @nid: widget NID
 * @ch: channel (left = 0, right = 1)
 * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
 * @idx: input index value
 *
 * Returns an encoded pseudo register.
 */
#define snd_hdac_regmap_encode_amp(nid, ch, dir, idx)			\
	(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) |	\
	 ((ch) ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT) |			\
	 ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
	 (idx))

/**
 * snd_hdac_regmap_encode_amp_stereo - encode a pseudo register for stereo AMPs
 * @nid: widget NID
 * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
 * @idx: input index value
 *
 * Returns an encoded pseudo register.
 */
#define snd_hdac_regmap_encode_amp_stereo(nid, dir, idx)		\
	(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) |	\
	 AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | /* both bits set! */	\
	 ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
	 (idx))

/**
 * snd_hdac_regmap_write - Write a verb with caching
 * @nid: codec NID
 * @reg: verb to write
 * @val: value to write
 *
 * For writing an amp value, use snd_hda_regmap_amp_update().
 */
static inline int
snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
		      unsigned int verb, unsigned int val)
{
	unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);

	return snd_hdac_regmap_write_raw(codec, cmd, val);
}

/**
 * snd_hda_regmap_update - Update a verb value with caching
 * @nid: codec NID
 * @verb: verb to update
 * @mask: bit mask to update
 * @val: value to update
 *
 * For updating an amp value, use snd_hda_regmap_amp_update().
 */
static inline int
snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
		       unsigned int verb, unsigned int mask,
		       unsigned int val)
{
	unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);

	return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
}

/**
 * snd_hda_regmap_read - Read a verb with caching
 * @nid: codec NID
 * @verb: verb to read
 * @val: pointer to store the value
 *
 * For reading an amp value, use snd_hda_regmap_get_amp().
 */
static inline int
snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
		     unsigned int verb, unsigned int *val)
{
	unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);

	return snd_hdac_regmap_read_raw(codec, cmd, val);
}

/**
 * snd_hdac_regmap_get_amp - Read AMP value
 * @codec: HD-audio codec
 * @nid: NID to read the AMP value
 * @ch: channel (left=0 or right=1)
 * @direction: #HDA_INPUT or #HDA_OUTPUT
 * @index: the index value (only for input direction)
 * @val: the pointer to store the value
 *
 * Read AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
 * Returns the value or a negative error.
 */
static inline int
snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
			int ch, int dir, int idx)
{
	unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
	int err, val;

	err = snd_hdac_regmap_read_raw(codec, cmd, &val);
	return err < 0 ? err : val;
}

/**
 * snd_hdac_regmap_update_amp - update the AMP value
 * @codec: HD-audio codec
 * @nid: NID to read the AMP value
 * @ch: channel (left=0 or right=1)
 * @direction: #HDA_INPUT or #HDA_OUTPUT
 * @idx: the index value (only for input direction)
 * @mask: bit mask to set
 * @val: the bits value to set
 *
 * Update the AMP value with a bit mask.
 * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
 */
static inline int
snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
			   int ch, int dir, int idx, int mask, int val)
{
	unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);

	return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
}

/**
 * snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
 * @codec: HD-audio codec
 * @nid: NID to read the AMP value
 * @ch: channel (left=0 or right=1)
 * @direction: #HDA_INPUT or #HDA_OUTPUT
 * @index: the index value (only for input direction)
 * @val: the pointer to store the value
 *
 * Read stereo AMP values.  The lower byte is left, the upper byte is right.
 * Returns the value or a negative error.
 */
static inline int
snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
			       int dir, int idx)
{
	unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
	int err, val;

	err = snd_hdac_regmap_read_raw(codec, cmd, &val);
	return err < 0 ? err : val;
}

/**
 * snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
 * @codec: HD-audio codec
 * @nid: NID to read the AMP value
 * @direction: #HDA_INPUT or #HDA_OUTPUT
 * @idx: the index value (only for input direction)
 * @mask: bit mask to set
 * @val: the bits value to set
 *
 * Update the stereo AMP value with a bit mask.
 * The lower byte is left, the upper byte is right.
 * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
 */
static inline int
snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
				  int dir, int idx, int mask, int val)
{
	unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);

	return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
}

#endif /* __SOUND_HDA_REGMAP_H */
+63 −1
Original line number Diff line number Diff line
@@ -21,6 +21,17 @@ struct hdac_widget_tree;
 */
extern struct bus_type snd_hda_bus_type;

/*
 * generic arrays
 */
struct snd_array {
	unsigned int used;
	unsigned int alloced;
	unsigned int elem_size;
	unsigned int alloc_align;
	void *list;
};

/*
 * HD-audio codec base device
 */
@@ -61,6 +72,13 @@ struct hdac_device {

	/* sysfs */
	struct hdac_widget_tree *widgets;

	/* 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 */
	bool cache_coef:1;	/* cache COEF read/write too */
};

/* device/driver type used for matching */
@@ -90,12 +108,34 @@ int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd,
		       unsigned int flags, unsigned int *res);
int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid,
		  unsigned int verb, unsigned int parm, unsigned int *res);
int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm);
int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm,
			unsigned int *res);
int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
				int parm);
int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
			   unsigned int parm, unsigned int val);
int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
			     hda_nid_t *conn_list, int max_conns);
int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
			   hda_nid_t *start_id);

/**
 * snd_hdac_read_parm - read a codec parameter
 * @codec: the codec object
 * @nid: NID to read a parameter
 * @parm: parameter to read
 *
 * Returns -1 for error.  If you need to distinguish the error more
 * strictly, use _snd_hdac_read_parm() directly.
 */
static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid,
				     int parm)
{
	unsigned int val;

	return _snd_hdac_read_parm(codec, nid, parm, &val) < 0 ? -1 : val;
}

#ifdef CONFIG_PM
void snd_hdac_power_up(struct hdac_device *codec);
void snd_hdac_power_down(struct hdac_device *codec);
@@ -178,4 +218,26 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
	clear_bit(codec->addr, &codec->bus->codec_powered);
}

/*
 * generic array helpers
 */
void *snd_array_new(struct snd_array *array);
void snd_array_free(struct snd_array *array);
static inline void snd_array_init(struct snd_array *array, unsigned int size,
				  unsigned int align)
{
	array->elem_size = size;
	array->alloc_align = align;
}

static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
{
	return array->list + idx * array->elem_size;
}

static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
{
	return (unsigned long)(ptr - array->list) / array->elem_size;
}

#endif /* __SOUND_HDAUDIO_H */
+1 −0
Original line number Diff line number Diff line
config SND_HDA_CORE
	tristate
	select REGMAP
+2 −1
Original line number Diff line number Diff line
snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o
snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \
	hdac_regmap.o array.o

snd-hda-core-objs += trace.o
CFLAGS_trace.o := -I$(src)

sound/hda/array.c

0 → 100644
+49 −0
Original line number Diff line number Diff line
/*
 * generic arrays
 */

#include <linux/slab.h>
#include <sound/core.h>
#include <sound/hdaudio.h>

/**
 * snd_array_new - get a new element from the given array
 * @array: the array object
 *
 * Get a new element from the given array.  If it exceeds the
 * pre-allocated array size, re-allocate the array.
 *
 * Returns NULL if allocation failed.
 */
void *snd_array_new(struct snd_array *array)
{
	if (snd_BUG_ON(!array->elem_size))
		return NULL;
	if (array->used >= array->alloced) {
		int num = array->alloced + array->alloc_align;
		int size = (num + 1) * array->elem_size;
		void *nlist;
		if (snd_BUG_ON(num >= 4096))
			return NULL;
		nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO);
		if (!nlist)
			return NULL;
		array->list = nlist;
		array->alloced = num;
	}
	return snd_array_elem(array, array->used++);
}
EXPORT_SYMBOL_GPL(snd_array_new);

/**
 * snd_array_free - free the given array elements
 * @array: the array object
 */
void snd_array_free(struct snd_array *array)
{
	kfree(array->list);
	array->used = 0;
	array->alloced = 0;
	array->list = NULL;
}
EXPORT_SYMBOL_GPL(snd_array_free);
Loading