Skip to content

Commit

Permalink
Merge branch 'topic/hda-regmap' into for-next
Browse files Browse the repository at this point in the history
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: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai committed Apr 4, 2015
2 parents ffda568 + 9d82f92 commit 664bc5c
Show file tree
Hide file tree
Showing 19 changed files with 1,006 additions and 747 deletions.
205 changes: 205 additions & 0 deletions include/sound/hda_regmap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
* 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 */
64 changes: 63 additions & 1 deletion include/sound/hdaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 change: 1 addition & 0 deletions sound/hda/Kconfig
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
config SND_HDA_CORE
tristate
select REGMAP
3 changes: 2 additions & 1 deletion sound/hda/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
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)
Expand Down
49 changes: 49 additions & 0 deletions sound/hda/array.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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

0 comments on commit 664bc5c

Please sign in to comment.