Skip to content

Commit 664bc5c

Browse files
committed
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: Takashi Iwai <tiwai@suse.de>
2 parents ffda568 + 9d82f92 commit 664bc5c

19 files changed

+1006
-747
lines changed

include/sound/hda_regmap.h

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* HD-audio regmap helpers
3+
*/
4+
5+
#ifndef __SOUND_HDA_REGMAP_H
6+
#define __SOUND_HDA_REGMAP_H
7+
8+
#include <linux/regmap.h>
9+
#include <sound/core.h>
10+
#include <sound/hdaudio.h>
11+
12+
int snd_hdac_regmap_init(struct hdac_device *codec);
13+
void snd_hdac_regmap_exit(struct hdac_device *codec);
14+
int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
15+
unsigned int verb);
16+
int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
17+
unsigned int *val);
18+
int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
19+
unsigned int val);
20+
int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
21+
unsigned int mask, unsigned int val);
22+
23+
/**
24+
* snd_hdac_regmap_encode_verb - encode the verb to a pseudo register
25+
* @nid: widget NID
26+
* @verb: codec verb
27+
*
28+
* Returns an encoded pseudo register.
29+
*/
30+
#define snd_hdac_regmap_encode_verb(nid, verb) \
31+
(((verb) << 8) | 0x80000 | ((unsigned int)(nid) << 20))
32+
33+
/**
34+
* snd_hdac_regmap_encode_amp - encode the AMP verb to a pseudo register
35+
* @nid: widget NID
36+
* @ch: channel (left = 0, right = 1)
37+
* @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
38+
* @idx: input index value
39+
*
40+
* Returns an encoded pseudo register.
41+
*/
42+
#define snd_hdac_regmap_encode_amp(nid, ch, dir, idx) \
43+
(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
44+
((ch) ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT) | \
45+
((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
46+
(idx))
47+
48+
/**
49+
* snd_hdac_regmap_encode_amp_stereo - encode a pseudo register for stereo AMPs
50+
* @nid: widget NID
51+
* @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
52+
* @idx: input index value
53+
*
54+
* Returns an encoded pseudo register.
55+
*/
56+
#define snd_hdac_regmap_encode_amp_stereo(nid, dir, idx) \
57+
(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
58+
AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | /* both bits set! */ \
59+
((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
60+
(idx))
61+
62+
/**
63+
* snd_hdac_regmap_write - Write a verb with caching
64+
* @nid: codec NID
65+
* @reg: verb to write
66+
* @val: value to write
67+
*
68+
* For writing an amp value, use snd_hda_regmap_amp_update().
69+
*/
70+
static inline int
71+
snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
72+
unsigned int verb, unsigned int val)
73+
{
74+
unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
75+
76+
return snd_hdac_regmap_write_raw(codec, cmd, val);
77+
}
78+
79+
/**
80+
* snd_hda_regmap_update - Update a verb value with caching
81+
* @nid: codec NID
82+
* @verb: verb to update
83+
* @mask: bit mask to update
84+
* @val: value to update
85+
*
86+
* For updating an amp value, use snd_hda_regmap_amp_update().
87+
*/
88+
static inline int
89+
snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
90+
unsigned int verb, unsigned int mask,
91+
unsigned int val)
92+
{
93+
unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
94+
95+
return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
96+
}
97+
98+
/**
99+
* snd_hda_regmap_read - Read a verb with caching
100+
* @nid: codec NID
101+
* @verb: verb to read
102+
* @val: pointer to store the value
103+
*
104+
* For reading an amp value, use snd_hda_regmap_get_amp().
105+
*/
106+
static inline int
107+
snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
108+
unsigned int verb, unsigned int *val)
109+
{
110+
unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
111+
112+
return snd_hdac_regmap_read_raw(codec, cmd, val);
113+
}
114+
115+
/**
116+
* snd_hdac_regmap_get_amp - Read AMP value
117+
* @codec: HD-audio codec
118+
* @nid: NID to read the AMP value
119+
* @ch: channel (left=0 or right=1)
120+
* @direction: #HDA_INPUT or #HDA_OUTPUT
121+
* @index: the index value (only for input direction)
122+
* @val: the pointer to store the value
123+
*
124+
* Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
125+
* Returns the value or a negative error.
126+
*/
127+
static inline int
128+
snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
129+
int ch, int dir, int idx)
130+
{
131+
unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
132+
int err, val;
133+
134+
err = snd_hdac_regmap_read_raw(codec, cmd, &val);
135+
return err < 0 ? err : val;
136+
}
137+
138+
/**
139+
* snd_hdac_regmap_update_amp - update the AMP value
140+
* @codec: HD-audio codec
141+
* @nid: NID to read the AMP value
142+
* @ch: channel (left=0 or right=1)
143+
* @direction: #HDA_INPUT or #HDA_OUTPUT
144+
* @idx: the index value (only for input direction)
145+
* @mask: bit mask to set
146+
* @val: the bits value to set
147+
*
148+
* Update the AMP value with a bit mask.
149+
* Returns 0 if the value is unchanged, 1 if changed, or a negative error.
150+
*/
151+
static inline int
152+
snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
153+
int ch, int dir, int idx, int mask, int val)
154+
{
155+
unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
156+
157+
return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
158+
}
159+
160+
/**
161+
* snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
162+
* @codec: HD-audio codec
163+
* @nid: NID to read the AMP value
164+
* @ch: channel (left=0 or right=1)
165+
* @direction: #HDA_INPUT or #HDA_OUTPUT
166+
* @index: the index value (only for input direction)
167+
* @val: the pointer to store the value
168+
*
169+
* Read stereo AMP values. The lower byte is left, the upper byte is right.
170+
* Returns the value or a negative error.
171+
*/
172+
static inline int
173+
snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
174+
int dir, int idx)
175+
{
176+
unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
177+
int err, val;
178+
179+
err = snd_hdac_regmap_read_raw(codec, cmd, &val);
180+
return err < 0 ? err : val;
181+
}
182+
183+
/**
184+
* snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
185+
* @codec: HD-audio codec
186+
* @nid: NID to read the AMP value
187+
* @direction: #HDA_INPUT or #HDA_OUTPUT
188+
* @idx: the index value (only for input direction)
189+
* @mask: bit mask to set
190+
* @val: the bits value to set
191+
*
192+
* Update the stereo AMP value with a bit mask.
193+
* The lower byte is left, the upper byte is right.
194+
* Returns 0 if the value is unchanged, 1 if changed, or a negative error.
195+
*/
196+
static inline int
197+
snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
198+
int dir, int idx, int mask, int val)
199+
{
200+
unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
201+
202+
return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
203+
}
204+
205+
#endif /* __SOUND_HDA_REGMAP_H */

include/sound/hdaudio.h

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ struct hdac_widget_tree;
2121
*/
2222
extern struct bus_type snd_hda_bus_type;
2323

24+
/*
25+
* generic arrays
26+
*/
27+
struct snd_array {
28+
unsigned int used;
29+
unsigned int alloced;
30+
unsigned int elem_size;
31+
unsigned int alloc_align;
32+
void *list;
33+
};
34+
2435
/*
2536
* HD-audio codec base device
2637
*/
@@ -61,6 +72,13 @@ struct hdac_device {
6172

6273
/* sysfs */
6374
struct hdac_widget_tree *widgets;
75+
76+
/* regmap */
77+
struct regmap *regmap;
78+
struct snd_array vendor_verbs;
79+
bool lazy_cache:1; /* don't wake up for writes */
80+
bool caps_overwriting:1; /* caps overwrite being in process */
81+
bool cache_coef:1; /* cache COEF read/write too */
6482
};
6583

6684
/* device/driver type used for matching */
@@ -90,12 +108,34 @@ int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd,
90108
unsigned int flags, unsigned int *res);
91109
int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid,
92110
unsigned int verb, unsigned int parm, unsigned int *res);
93-
int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm);
111+
int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm,
112+
unsigned int *res);
113+
int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
114+
int parm);
115+
int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
116+
unsigned int parm, unsigned int val);
94117
int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
95118
hda_nid_t *conn_list, int max_conns);
96119
int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
97120
hda_nid_t *start_id);
98121

122+
/**
123+
* snd_hdac_read_parm - read a codec parameter
124+
* @codec: the codec object
125+
* @nid: NID to read a parameter
126+
* @parm: parameter to read
127+
*
128+
* Returns -1 for error. If you need to distinguish the error more
129+
* strictly, use _snd_hdac_read_parm() directly.
130+
*/
131+
static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid,
132+
int parm)
133+
{
134+
unsigned int val;
135+
136+
return _snd_hdac_read_parm(codec, nid, parm, &val) < 0 ? -1 : val;
137+
}
138+
99139
#ifdef CONFIG_PM
100140
void snd_hdac_power_up(struct hdac_device *codec);
101141
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)
178218
clear_bit(codec->addr, &codec->bus->codec_powered);
179219
}
180220

221+
/*
222+
* generic array helpers
223+
*/
224+
void *snd_array_new(struct snd_array *array);
225+
void snd_array_free(struct snd_array *array);
226+
static inline void snd_array_init(struct snd_array *array, unsigned int size,
227+
unsigned int align)
228+
{
229+
array->elem_size = size;
230+
array->alloc_align = align;
231+
}
232+
233+
static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
234+
{
235+
return array->list + idx * array->elem_size;
236+
}
237+
238+
static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
239+
{
240+
return (unsigned long)(ptr - array->list) / array->elem_size;
241+
}
242+
181243
#endif /* __SOUND_HDAUDIO_H */

sound/hda/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
config SND_HDA_CORE
22
tristate
3+
select REGMAP

sound/hda/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o
1+
snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \
2+
hdac_regmap.o array.o
23

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

sound/hda/array.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* generic arrays
3+
*/
4+
5+
#include <linux/slab.h>
6+
#include <sound/core.h>
7+
#include <sound/hdaudio.h>
8+
9+
/**
10+
* snd_array_new - get a new element from the given array
11+
* @array: the array object
12+
*
13+
* Get a new element from the given array. If it exceeds the
14+
* pre-allocated array size, re-allocate the array.
15+
*
16+
* Returns NULL if allocation failed.
17+
*/
18+
void *snd_array_new(struct snd_array *array)
19+
{
20+
if (snd_BUG_ON(!array->elem_size))
21+
return NULL;
22+
if (array->used >= array->alloced) {
23+
int num = array->alloced + array->alloc_align;
24+
int size = (num + 1) * array->elem_size;
25+
void *nlist;
26+
if (snd_BUG_ON(num >= 4096))
27+
return NULL;
28+
nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO);
29+
if (!nlist)
30+
return NULL;
31+
array->list = nlist;
32+
array->alloced = num;
33+
}
34+
return snd_array_elem(array, array->used++);
35+
}
36+
EXPORT_SYMBOL_GPL(snd_array_new);
37+
38+
/**
39+
* snd_array_free - free the given array elements
40+
* @array: the array object
41+
*/
42+
void snd_array_free(struct snd_array *array)
43+
{
44+
kfree(array->list);
45+
array->used = 0;
46+
array->alloced = 0;
47+
array->list = NULL;
48+
}
49+
EXPORT_SYMBOL_GPL(snd_array_free);

0 commit comments

Comments
 (0)