]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * HD-audio core stuff | |
3 | */ | |
4 | ||
5 | #ifndef __SOUND_HDAUDIO_H | |
6 | #define __SOUND_HDAUDIO_H | |
7 | ||
8 | #include <linux/device.h> | |
9 | #include <sound/hda_verbs.h> | |
10 | ||
11 | /* codec node id */ | |
12 | typedef u16 hda_nid_t; | |
13 | ||
14 | struct hdac_bus; | |
15 | struct hdac_device; | |
16 | struct hdac_driver; | |
17 | struct hdac_widget_tree; | |
18 | ||
19 | /* | |
20 | * exported bus type | |
21 | */ | |
22 | extern struct bus_type snd_hda_bus_type; | |
23 | ||
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 | ||
35 | /* | |
36 | * HD-audio codec base device | |
37 | */ | |
38 | struct hdac_device { | |
39 | struct device dev; | |
40 | int type; | |
41 | struct hdac_bus *bus; | |
42 | unsigned int addr; /* codec address */ | |
43 | struct list_head list; /* list point for bus codec_list */ | |
44 | ||
45 | hda_nid_t afg; /* AFG node id */ | |
46 | hda_nid_t mfg; /* MFG node id */ | |
47 | ||
48 | /* ids */ | |
49 | unsigned int vendor_id; | |
50 | unsigned int subsystem_id; | |
51 | unsigned int revision_id; | |
52 | unsigned int afg_function_id; | |
53 | unsigned int mfg_function_id; | |
54 | unsigned int afg_unsol:1; | |
55 | unsigned int mfg_unsol:1; | |
56 | ||
57 | unsigned int power_caps; /* FG power caps */ | |
58 | ||
59 | const char *vendor_name; /* codec vendor name */ | |
60 | const char *chip_name; /* codec chip name */ | |
61 | ||
62 | /* verb exec op override */ | |
63 | int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, | |
64 | unsigned int flags, unsigned int *res); | |
65 | ||
66 | /* widgets */ | |
67 | unsigned int num_nodes; | |
68 | hda_nid_t start_nid, end_nid; | |
69 | ||
70 | /* misc flags */ | |
71 | atomic_t in_pm; /* suspend/resume being performed */ | |
72 | ||
73 | /* sysfs */ | |
74 | struct hdac_widget_tree *widgets; | |
75 | ||
76 | /* regmap */ | |
77 | struct regmap *regmap; | |
78 | bool lazy_cache:1; /* don't wake up for writes */ | |
79 | }; | |
80 | ||
81 | /* device/driver type used for matching */ | |
82 | enum { | |
83 | HDA_DEV_CORE, | |
84 | HDA_DEV_LEGACY, | |
85 | }; | |
86 | ||
87 | /* direction */ | |
88 | enum { | |
89 | HDA_INPUT, HDA_OUTPUT | |
90 | }; | |
91 | ||
92 | #define dev_to_hdac_dev(_dev) container_of(_dev, struct hdac_device, dev) | |
93 | ||
94 | int snd_hdac_device_init(struct hdac_device *dev, struct hdac_bus *bus, | |
95 | const char *name, unsigned int addr); | |
96 | void snd_hdac_device_exit(struct hdac_device *dev); | |
97 | int snd_hdac_device_register(struct hdac_device *codec); | |
98 | void snd_hdac_device_unregister(struct hdac_device *codec); | |
99 | ||
100 | int snd_hdac_refresh_widgets(struct hdac_device *codec); | |
101 | ||
102 | unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, | |
103 | unsigned int verb, unsigned int parm); | |
104 | int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, | |
105 | unsigned int flags, unsigned int *res); | |
106 | int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid, | |
107 | unsigned int verb, unsigned int parm, unsigned int *res); | |
108 | int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm, | |
109 | unsigned int *res); | |
110 | int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, | |
111 | hda_nid_t *conn_list, int max_conns); | |
112 | int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, | |
113 | hda_nid_t *start_id); | |
114 | ||
115 | /** | |
116 | * snd_hdac_read_parm - read a codec parameter | |
117 | * @codec: the codec object | |
118 | * @nid: NID to read a parameter | |
119 | * @parm: parameter to read | |
120 | * | |
121 | * Returns -1 for error. If you need to distinguish the error more | |
122 | * strictly, use _snd_hdac_read_parm() directly. | |
123 | */ | |
124 | static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, | |
125 | int parm) | |
126 | { | |
127 | unsigned int val; | |
128 | ||
129 | return _snd_hdac_read_parm(codec, nid, parm, &val) < 0 ? -1 : val; | |
130 | } | |
131 | ||
132 | #ifdef CONFIG_PM | |
133 | void snd_hdac_power_up(struct hdac_device *codec); | |
134 | void snd_hdac_power_down(struct hdac_device *codec); | |
135 | #else | |
136 | static inline void snd_hdac_power_up(struct hdac_device *codec) {} | |
137 | static inline void snd_hdac_power_down(struct hdac_device *codec) {} | |
138 | #endif | |
139 | ||
140 | /* | |
141 | * HD-audio codec base driver | |
142 | */ | |
143 | struct hdac_driver { | |
144 | struct device_driver driver; | |
145 | int type; | |
146 | int (*match)(struct hdac_device *dev, struct hdac_driver *drv); | |
147 | void (*unsol_event)(struct hdac_device *dev, unsigned int event); | |
148 | }; | |
149 | ||
150 | #define drv_to_hdac_driver(_drv) container_of(_drv, struct hdac_driver, driver) | |
151 | ||
152 | /* | |
153 | * HD-audio bus base driver | |
154 | */ | |
155 | struct hdac_bus_ops { | |
156 | /* send a single command */ | |
157 | int (*command)(struct hdac_bus *bus, unsigned int cmd); | |
158 | /* get a response from the last command */ | |
159 | int (*get_response)(struct hdac_bus *bus, unsigned int addr, | |
160 | unsigned int *res); | |
161 | }; | |
162 | ||
163 | #define HDA_UNSOL_QUEUE_SIZE 64 | |
164 | ||
165 | struct hdac_bus { | |
166 | struct device *dev; | |
167 | const struct hdac_bus_ops *ops; | |
168 | ||
169 | /* codec linked list */ | |
170 | struct list_head codec_list; | |
171 | unsigned int num_codecs; | |
172 | ||
173 | /* link caddr -> codec */ | |
174 | struct hdac_device *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; | |
175 | ||
176 | /* unsolicited event queue */ | |
177 | u32 unsol_queue[HDA_UNSOL_QUEUE_SIZE * 2]; /* ring buffer */ | |
178 | unsigned int unsol_rp, unsol_wp; | |
179 | struct work_struct unsol_work; | |
180 | ||
181 | /* bit flags of powered codecs */ | |
182 | unsigned long codec_powered; | |
183 | ||
184 | /* flags */ | |
185 | bool sync_write:1; /* sync after verb write */ | |
186 | ||
187 | /* locks */ | |
188 | struct mutex cmd_mutex; | |
189 | }; | |
190 | ||
191 | int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, | |
192 | const struct hdac_bus_ops *ops); | |
193 | void snd_hdac_bus_exit(struct hdac_bus *bus); | |
194 | int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr, | |
195 | unsigned int cmd, unsigned int *res); | |
196 | int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr, | |
197 | unsigned int cmd, unsigned int *res); | |
198 | void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex); | |
199 | ||
200 | int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec); | |
201 | void snd_hdac_bus_remove_device(struct hdac_bus *bus, | |
202 | struct hdac_device *codec); | |
203 | ||
204 | static inline void snd_hdac_codec_link_up(struct hdac_device *codec) | |
205 | { | |
206 | set_bit(codec->addr, &codec->bus->codec_powered); | |
207 | } | |
208 | ||
209 | static inline void snd_hdac_codec_link_down(struct hdac_device *codec) | |
210 | { | |
211 | clear_bit(codec->addr, &codec->bus->codec_powered); | |
212 | } | |
213 | ||
214 | /* | |
215 | * generic array helpers | |
216 | */ | |
217 | void *snd_array_new(struct snd_array *array); | |
218 | void snd_array_free(struct snd_array *array); | |
219 | static inline void snd_array_init(struct snd_array *array, unsigned int size, | |
220 | unsigned int align) | |
221 | { | |
222 | array->elem_size = size; | |
223 | array->alloc_align = align; | |
224 | } | |
225 | ||
226 | static inline void *snd_array_elem(struct snd_array *array, unsigned int idx) | |
227 | { | |
228 | return array->list + idx * array->elem_size; | |
229 | } | |
230 | ||
231 | static inline unsigned int snd_array_index(struct snd_array *array, void *ptr) | |
232 | { | |
233 | return (unsigned long)(ptr - array->list) / array->elem_size; | |
234 | } | |
235 | ||
236 | #endif /* __SOUND_HDAUDIO_H */ |