@samitouri / QOSamiQemu / commits / 896627da1d

hw/audio: Remove wm8750 I2C audio device

The wm8750 audio I2C device was used only by the audio device on the SoC used in the now-removed musicpal machine. Since it has no users, we can delete it entirely. Although the wm8750 is an I2C device that could technically have been created on the command line, it isn't possible to do this usefully because the device only works when C code calls functions like wm8750_data_req_set() and wm8750_dac_buffer(). This resolves the problem noted in issue #4135 that there's a buffer overflow in the interaction between the marvell_88w8618 audio device and the wm8750, by removing the offending code entirely. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4135 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Acked-by: Jan Kiszka <jan.kiszka@web.de> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Message-id: 20260819185430.3467629-6-peter.maydell@linaro.org

Peter Maydell committed Aug 19, 2026 at 19:54 UTC 896627da1dda5f6d3840396d16f2af5375e0fe70
4 files changed -773
hw/audio/Kconfig
-4
@@ -38,10 +38,6 @@ config PCSPK
38 default y
39 depends on I8254
40
41 -config WM8750
42 - bool
43 - depends on I2C
44 -
41 config PL041
42 bool
43
hw/audio/meson.build
-1
@@ -11,6 +11,5 @@ system_ss.add(when: 'CONFIG_PCSPK', if_true: files('pcspk.c'))
11 system_ss.add(when: 'CONFIG_PL041', if_true: files('pl041.c', 'lm4549.c'))
12 system_ss.add(when: 'CONFIG_SB16', if_true: files('sb16.c'))
13 system_ss.add(when: 'CONFIG_VT82C686', if_true: files('via-ac97.c'))
14 -system_ss.add(when: 'CONFIG_WM8750', if_true: files('wm8750.c'))
14 system_ss.add(when: ['CONFIG_VIRTIO_SND', 'CONFIG_VIRTIO'], if_true: files('virtio-snd.c'))
15 system_ss.add(when: ['CONFIG_VIRTIO_SND', 'CONFIG_VIRTIO', 'CONFIG_VIRTIO_PCI'], if_true: files('virtio-snd-pci.c'))
hw/audio/wm8750.c deleted
-738
@@ -1,738 +0,0 @@
1 -/*
2 - * WM8750 audio CODEC.
3 - *
4 - * Copyright (c) 2006 Openedhand Ltd.
5 - * Written by Andrzej Zaborowski <balrog@zabor.org>
6 - *
7 - * This file is licensed under GNU GPL.
8 - */
9 -
10 -#include "qemu/osdep.h"
11 -#include "hw/i2c/i2c.h"
12 -#include "migration/vmstate.h"
13 -#include "qemu/module.h"
14 -#include "hw/audio/wm8750.h"
15 -#include "qemu/audio.h"
16 -#include "qom/object.h"
17 -
18 -#define IN_PORT_N 3
19 -#define OUT_PORT_N 3
20 -
21 -#define CODEC "wm8750"
22 -
23 -typedef struct {
24 - int adc;
25 - int adc_hz;
26 - int dac;
27 - int dac_hz;
28 -} WMRate;
29 -
30 -OBJECT_DECLARE_SIMPLE_TYPE(WM8750State, WM8750)
31 -
32 -struct WM8750State {
33 - I2CSlave parent_obj;
34 -
35 - uint8_t i2c_data[2];
36 - int i2c_len;
37 - AudioBackend *audio_be;
38 - SWVoiceIn *adc_voice[IN_PORT_N];
39 - SWVoiceOut *dac_voice[OUT_PORT_N];
40 - int enable;
41 - void (*data_req)(void *, int, int);
42 - void *opaque;
43 - uint8_t data_in[4096];
44 - uint8_t data_out[4096];
45 - int idx_in, req_in;
46 - int idx_out, req_out;
47 -
48 - SWVoiceOut **out[2];
49 - uint8_t outvol[7], outmute[2];
50 - SWVoiceIn **in[2];
51 - uint8_t invol[4], inmute[2];
52 -
53 - uint8_t diff[2], pol, ds, monomix[2], alc, mute;
54 - uint8_t path[4], mpath[2], power, format;
55 - const WMRate *rate;
56 - uint8_t rate_vmstate;
57 - int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
58 -};
59 -
60 -/* pow(10.0, -i / 20.0) * 255, i = 0..42 */
61 -static const uint8_t wm8750_vol_db_table[] = {
62 - 255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
63 - 40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
64 - 4, 4, 3, 3, 3, 2, 2
65 -};
66 -
67 -#define WM8750_OUTVOL_TRANSFORM(x) wm8750_vol_db_table[(0x7f - x) / 3]
68 -#define WM8750_INVOL_TRANSFORM(x) (x << 2)
69 -
70 -static inline void wm8750_in_load(WM8750State *s)
71 -{
72 - if (s->idx_in + s->req_in <= sizeof(s->data_in))
73 - return;
74 - s->idx_in = MAX(0, (int) sizeof(s->data_in) - s->req_in);
75 - audio_be_read(s->audio_be, *s->in[0], s->data_in + s->idx_in,
76 - sizeof(s->data_in) - s->idx_in);
77 -}
78 -
79 -static inline void wm8750_out_flush(WM8750State *s)
80 -{
81 - int sent = 0;
82 - while (sent < s->idx_out)
83 - sent += audio_be_write(s->audio_be, *s->out[0],
84 - s->data_out + sent, s->idx_out - sent)
85 - ?: s->idx_out;
86 - s->idx_out = 0;
87 -}
88 -
89 -static void wm8750_audio_in_cb(void *opaque, int avail_b)
90 -{
91 - WM8750State *s = (WM8750State *) opaque;
92 - s->req_in = avail_b;
93 - s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
94 -}
95 -
96 -static void wm8750_audio_out_cb(void *opaque, int free_b)
97 -{
98 - WM8750State *s = (WM8750State *) opaque;
99 -
100 - if (s->idx_out >= free_b) {
101 - s->idx_out = free_b;
102 - s->req_out = 0;
103 - wm8750_out_flush(s);
104 - } else
105 - s->req_out = free_b - s->idx_out;
106 -
107 - s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
108 -}
109 -
110 -static const WMRate wm_rate_table[] = {
111 - { 256, 48000, 256, 48000 }, /* SR: 00000 */
112 - { 384, 48000, 384, 48000 }, /* SR: 00001 */
113 - { 256, 48000, 1536, 8000 }, /* SR: 00010 */
114 - { 384, 48000, 2304, 8000 }, /* SR: 00011 */
115 - { 1536, 8000, 256, 48000 }, /* SR: 00100 */
116 - { 2304, 8000, 384, 48000 }, /* SR: 00101 */
117 - { 1536, 8000, 1536, 8000 }, /* SR: 00110 */
118 - { 2304, 8000, 2304, 8000 }, /* SR: 00111 */
119 - { 1024, 12000, 1024, 12000 }, /* SR: 01000 */
120 - { 1526, 12000, 1536, 12000 }, /* SR: 01001 */
121 - { 768, 16000, 768, 16000 }, /* SR: 01010 */
122 - { 1152, 16000, 1152, 16000 }, /* SR: 01011 */
123 - { 384, 32000, 384, 32000 }, /* SR: 01100 */
124 - { 576, 32000, 576, 32000 }, /* SR: 01101 */
125 - { 128, 96000, 128, 96000 }, /* SR: 01110 */
126 - { 192, 96000, 192, 96000 }, /* SR: 01111 */
127 - { 256, 44100, 256, 44100 }, /* SR: 10000 */
128 - { 384, 44100, 384, 44100 }, /* SR: 10001 */
129 - { 256, 44100, 1408, 8018 }, /* SR: 10010 */
130 - { 384, 44100, 2112, 8018 }, /* SR: 10011 */
131 - { 1408, 8018, 256, 44100 }, /* SR: 10100 */
132 - { 2112, 8018, 384, 44100 }, /* SR: 10101 */
133 - { 1408, 8018, 1408, 8018 }, /* SR: 10110 */
134 - { 2112, 8018, 2112, 8018 }, /* SR: 10111 */
135 - { 1024, 11025, 1024, 11025 }, /* SR: 11000 */
136 - { 1536, 11025, 1536, 11025 }, /* SR: 11001 */
137 - { 512, 22050, 512, 22050 }, /* SR: 11010 */
138 - { 768, 22050, 768, 22050 }, /* SR: 11011 */
139 - { 512, 24000, 512, 24000 }, /* SR: 11100 */
140 - { 768, 24000, 768, 24000 }, /* SR: 11101 */
141 - { 128, 88200, 128, 88200 }, /* SR: 11110 */
142 - { 192, 88200, 192, 88200 }, /* SR: 11111 */
143 -};
144 -
145 -static void wm8750_vol_update(WM8750State *s)
146 -{
147 - /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */
148 -
149 - audio_be_set_volume_in_lr(s->audio_be, s->adc_voice[0], s->mute,
150 - s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
151 - s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
152 - audio_be_set_volume_in_lr(s->audio_be, s->adc_voice[1], s->mute,
153 - s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
154 - s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
155 - audio_be_set_volume_in_lr(s->audio_be, s->adc_voice[2], s->mute,
156 - s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
157 - s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
158 -
159 - /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */
160 -
161 - /* Speaker: LOUT2VOL ROUT2VOL */
162 - audio_be_set_volume_out_lr(s->audio_be, s->dac_voice[0], s->mute,
163 - s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[4]),
164 - s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5]));
165 -
166 - /* Headphone: LOUT1VOL ROUT1VOL */
167 - audio_be_set_volume_out_lr(s->audio_be, s->dac_voice[1], s->mute,
168 - s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]),
169 - s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3]));
170 -
171 - /* MONOOUT: MONOVOL MONOVOL */
172 - audio_be_set_volume_out_lr(s->audio_be, s->dac_voice[2], s->mute,
173 - s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]),
174 - s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]));
175 -}
176 -
177 -static void wm8750_set_format(WM8750State *s)
178 -{
179 - int i;
180 - struct audsettings in_fmt;
181 - struct audsettings out_fmt;
182 -
183 - wm8750_out_flush(s);
184 -
185 - if (s->in[0] && *s->in[0])
186 - audio_be_set_active_in(s->audio_be, *s->in[0], 0);
187 - if (s->out[0] && *s->out[0])
188 - audio_be_set_active_out(s->audio_be, *s->out[0], 0);
189 -
190 - for (i = 0; i < IN_PORT_N; i ++)
191 - if (s->adc_voice[i]) {
192 - audio_be_close_in(s->audio_be, s->adc_voice[i]);
193 - s->adc_voice[i] = NULL;
194 - }
195 - for (i = 0; i < OUT_PORT_N; i ++)
196 - if (s->dac_voice[i]) {
197 - audio_be_close_out(s->audio_be, s->dac_voice[i]);
198 - s->dac_voice[i] = NULL;
199 - }
200 -
201 - if (!s->enable)
202 - return;
203 -
204 - /* Setup input */
205 - in_fmt.big_endian = false;
206 - in_fmt.nchannels = 2;
207 - in_fmt.freq = s->adc_hz;
208 - in_fmt.fmt = AUDIO_FORMAT_S16;
209 -
210 - s->adc_voice[0] = audio_be_open_in(s->audio_be, s->adc_voice[0],
211 - CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
212 - s->adc_voice[1] = audio_be_open_in(s->audio_be, s->adc_voice[1],
213 - CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
214 - s->adc_voice[2] = audio_be_open_in(s->audio_be, s->adc_voice[2],
215 - CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
216 -
217 - /* Setup output */
218 - out_fmt.big_endian = false;
219 - out_fmt.nchannels = 2;
220 - out_fmt.freq = s->dac_hz;
221 - out_fmt.fmt = AUDIO_FORMAT_S16;
222 -
223 - s->dac_voice[0] = audio_be_open_out(s->audio_be, s->dac_voice[0],
224 - CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
225 - s->dac_voice[1] = audio_be_open_out(s->audio_be, s->dac_voice[1],
226 - CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
227 - /* MONOMIX is also in stereo for simplicity */
228 - s->dac_voice[2] = audio_be_open_out(s->audio_be, s->dac_voice[2],
229 - CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
230 - /* no sense emulating OUT3 which is a mix of other outputs */
231 -
232 - wm8750_vol_update(s);
233 -
234 - /* We should connect the left and right channels to their
235 - * respective inputs/outputs but we have completely no need
236 - * for mixing or combining paths to different ports, so we
237 - * connect both channels to where the left channel is routed. */
238 - if (s->in[0] && *s->in[0])
239 - audio_be_set_active_in(s->audio_be, *s->in[0], 1);
240 - if (s->out[0] && *s->out[0])
241 - audio_be_set_active_out(s->audio_be, *s->out[0], 1);
242 -}
243 -
244 -static void wm8750_clk_update(WM8750State *s, int ext)
245 -{
246 - if (s->master || !s->ext_dac_hz)
247 - s->dac_hz = s->rate->dac_hz;
248 - else
249 - s->dac_hz = s->ext_dac_hz;
250 -
251 - if (s->master || !s->ext_adc_hz)
252 - s->adc_hz = s->rate->adc_hz;
253 - else
254 - s->adc_hz = s->ext_adc_hz;
255 -
256 - if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) {
257 - if (!ext)
258 - wm8750_set_format(s);
259 - } else {
260 - if (ext)
261 - wm8750_set_format(s);
262 - }
263 -}
264 -
265 -static void wm8750_reset(I2CSlave *i2c)
266 -{
267 - WM8750State *s = WM8750(i2c);
268 -
269 - s->rate = &wm_rate_table[0];
270 - s->enable = 0;
271 - wm8750_clk_update(s, 1);
272 - s->diff[0] = 0;
273 - s->diff[1] = 0;
274 - s->ds = 0;
275 - s->alc = 0;
276 - s->in[0] = &s->adc_voice[0];
277 - s->invol[0] = 0x17;
278 - s->invol[1] = 0x17;
279 - s->invol[2] = 0xc3;
280 - s->invol[3] = 0xc3;
281 - s->out[0] = &s->dac_voice[0];
282 - s->outvol[0] = 0xff;
283 - s->outvol[1] = 0xff;
284 - s->outvol[2] = 0x79;
285 - s->outvol[3] = 0x79;
286 - s->outvol[4] = 0x79;
287 - s->outvol[5] = 0x79;
288 - s->outvol[6] = 0x79;
289 - s->inmute[0] = 0;
290 - s->inmute[1] = 0;
291 - s->outmute[0] = 0;
292 - s->outmute[1] = 0;
293 - s->mute = 1;
294 - s->path[0] = 0;
295 - s->path[1] = 0;
296 - s->path[2] = 0;
297 - s->path[3] = 0;
298 - s->mpath[0] = 0;
299 - s->mpath[1] = 0;
300 - s->format = 0x0a;
301 - s->idx_in = sizeof(s->data_in);
302 - s->req_in = 0;
303 - s->idx_out = 0;
304 - s->req_out = 0;
305 - wm8750_vol_update(s);
306 - s->i2c_len = 0;
307 -}
308 -
309 -static int wm8750_event(I2CSlave *i2c, enum i2c_event event)
310 -{
311 - WM8750State *s = WM8750(i2c);
312 -
313 - switch (event) {
314 - case I2C_START_SEND:
315 - s->i2c_len = 0;
316 - break;
317 - case I2C_FINISH:
318 -#ifdef VERBOSE
319 - if (s->i2c_len < 2)
320 - printf("%s: message too short (%i bytes)\n",
321 - __func__, s->i2c_len);
322 -#endif
323 - break;
324 - default:
325 - break;
326 - }
327 -
328 - return 0;
329 -}
330 -
331 -#define WM8750_LINVOL 0x00
332 -#define WM8750_RINVOL 0x01
333 -#define WM8750_LOUT1V 0x02
334 -#define WM8750_ROUT1V 0x03
335 -#define WM8750_ADCDAC 0x05
336 -#define WM8750_IFACE 0x07
337 -#define WM8750_SRATE 0x08
338 -#define WM8750_LDAC 0x0a
339 -#define WM8750_RDAC 0x0b
340 -#define WM8750_BASS 0x0c
341 -#define WM8750_TREBLE 0x0d
342 -#define WM8750_RESET 0x0f
343 -#define WM8750_3D 0x10
344 -#define WM8750_ALC1 0x11
345 -#define WM8750_ALC2 0x12
346 -#define WM8750_ALC3 0x13
347 -#define WM8750_NGATE 0x14
348 -#define WM8750_LADC 0x15
349 -#define WM8750_RADC 0x16
350 -#define WM8750_ADCTL1 0x17
351 -#define WM8750_ADCTL2 0x18
352 -#define WM8750_PWR1 0x19
353 -#define WM8750_PWR2 0x1a
354 -#define WM8750_ADCTL3 0x1b
355 -#define WM8750_ADCIN 0x1f
356 -#define WM8750_LADCIN 0x20
357 -#define WM8750_RADCIN 0x21
358 -#define WM8750_LOUTM1 0x22
359 -#define WM8750_LOUTM2 0x23
360 -#define WM8750_ROUTM1 0x24
361 -#define WM8750_ROUTM2 0x25
362 -#define WM8750_MOUTM1 0x26
363 -#define WM8750_MOUTM2 0x27
364 -#define WM8750_LOUT2V 0x28
365 -#define WM8750_ROUT2V 0x29
366 -#define WM8750_MOUTV 0x2a
367 -
368 -static int wm8750_tx(I2CSlave *i2c, uint8_t data)
369 -{
370 - WM8750State *s = WM8750(i2c);
371 - uint8_t cmd;
372 - uint16_t value;
373 -
374 - if (s->i2c_len >= 2) {
375 -#ifdef VERBOSE
376 - printf("%s: long message (%i bytes)\n", __func__, s->i2c_len);
377 -#endif
378 - return 1;
379 - }
380 - s->i2c_data[s->i2c_len ++] = data;
381 - if (s->i2c_len != 2)
382 - return 0;
383 -
384 - cmd = s->i2c_data[0] >> 1;
385 - value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
386 -
387 - switch (cmd) {
388 - case WM8750_LADCIN: /* ADC Signal Path Control (Left) */
389 - s->diff[0] = (((value >> 6) & 3) == 3); /* LINSEL */
390 - if (s->diff[0])
391 - s->in[0] = &s->adc_voice[0 + s->ds * 1];
392 - else
393 - s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
394 - break;
395 -
396 - case WM8750_RADCIN: /* ADC Signal Path Control (Right) */
397 - s->diff[1] = (((value >> 6) & 3) == 3); /* RINSEL */
398 - if (s->diff[1])
399 - s->in[1] = &s->adc_voice[0 + s->ds * 1];
400 - else
401 - s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
402 - break;
403 -
404 - case WM8750_ADCIN: /* ADC Input Mode */
405 - s->ds = (value >> 8) & 1; /* DS */
406 - if (s->diff[0])
407 - s->in[0] = &s->adc_voice[0 + s->ds * 1];
408 - if (s->diff[1])
409 - s->in[1] = &s->adc_voice[0 + s->ds * 1];
410 - s->monomix[0] = (value >> 6) & 3; /* MONOMIX */
411 - break;
412 -
413 - case WM8750_ADCTL1: /* Additional Control (1) */
414 - s->monomix[1] = (value >> 1) & 1; /* DMONOMIX */
415 - break;
416 -
417 - case WM8750_PWR1: /* Power Management (1) */
418 - s->enable = ((value >> 6) & 7) == 3; /* VMIDSEL, VREF */
419 - wm8750_set_format(s);
420 - break;
421 -
422 - case WM8750_LINVOL: /* Left Channel PGA */
423 - s->invol[0] = value & 0x3f; /* LINVOL */
424 - s->inmute[0] = (value >> 7) & 1; /* LINMUTE */
425 - wm8750_vol_update(s);
426 - break;
427 -
428 - case WM8750_RINVOL: /* Right Channel PGA */
429 - s->invol[1] = value & 0x3f; /* RINVOL */
430 - s->inmute[1] = (value >> 7) & 1; /* RINMUTE */
431 - wm8750_vol_update(s);
432 - break;
433 -
434 - case WM8750_ADCDAC: /* ADC and DAC Control */
435 - s->pol = (value >> 5) & 3; /* ADCPOL */
436 - s->mute = (value >> 3) & 1; /* DACMU */
437 - wm8750_vol_update(s);
438 - break;
439 -
440 - case WM8750_ADCTL3: /* Additional Control (3) */
441 - break;
442 -
443 - case WM8750_LADC: /* Left ADC Digital Volume */
444 - s->invol[2] = value & 0xff; /* LADCVOL */
445 - wm8750_vol_update(s);
446 - break;
447 -
448 - case WM8750_RADC: /* Right ADC Digital Volume */
449 - s->invol[3] = value & 0xff; /* RADCVOL */
450 - wm8750_vol_update(s);
451 - break;
452 -
453 - case WM8750_ALC1: /* ALC Control (1) */
454 - s->alc = (value >> 7) & 3; /* ALCSEL */
455 - break;
456 -
457 - case WM8750_NGATE: /* Noise Gate Control */
458 - case WM8750_3D: /* 3D enhance */
459 - break;
460 -
461 - case WM8750_LDAC: /* Left Channel Digital Volume */
462 - s->outvol[0] = value & 0xff; /* LDACVOL */
463 - wm8750_vol_update(s);
464 - break;
465 -
466 - case WM8750_RDAC: /* Right Channel Digital Volume */
467 - s->outvol[1] = value & 0xff; /* RDACVOL */
468 - wm8750_vol_update(s);
469 - break;
470 -
471 - case WM8750_BASS: /* Bass Control */
472 - break;
473 -
474 - case WM8750_LOUTM1: /* Left Mixer Control (1) */
475 - s->path[0] = (value >> 8) & 1; /* LD2LO */
476 - /* TODO: mute/unmute respective paths */
477 - wm8750_vol_update(s);
478 - break;
479 -
480 - case WM8750_LOUTM2: /* Left Mixer Control (2) */
481 - s->path[1] = (value >> 8) & 1; /* RD2LO */
482 - /* TODO: mute/unmute respective paths */
483 - wm8750_vol_update(s);
484 - break;
485 -
486 - case WM8750_ROUTM1: /* Right Mixer Control (1) */
487 - s->path[2] = (value >> 8) & 1; /* LD2RO */
488 - /* TODO: mute/unmute respective paths */
489 - wm8750_vol_update(s);
490 - break;
491 -
492 - case WM8750_ROUTM2: /* Right Mixer Control (2) */
493 - s->path[3] = (value >> 8) & 1; /* RD2RO */
494 - /* TODO: mute/unmute respective paths */
495 - wm8750_vol_update(s);
496 - break;
497 -
498 - case WM8750_MOUTM1: /* Mono Mixer Control (1) */
499 - s->mpath[0] = (value >> 8) & 1; /* LD2MO */
500 - /* TODO: mute/unmute respective paths */
501 - wm8750_vol_update(s);
502 - break;
503 -
504 - case WM8750_MOUTM2: /* Mono Mixer Control (2) */
505 - s->mpath[1] = (value >> 8) & 1; /* RD2MO */
506 - /* TODO: mute/unmute respective paths */
507 - wm8750_vol_update(s);
508 - break;
509 -
510 - case WM8750_LOUT1V: /* LOUT1 Volume */
511 - s->outvol[2] = value & 0x7f; /* LOUT1VOL */
512 - wm8750_vol_update(s);
513 - break;
514 -
515 - case WM8750_LOUT2V: /* LOUT2 Volume */
516 - s->outvol[4] = value & 0x7f; /* LOUT2VOL */
517 - wm8750_vol_update(s);
518 - break;
519 -
520 - case WM8750_ROUT1V: /* ROUT1 Volume */
521 - s->outvol[3] = value & 0x7f; /* ROUT1VOL */
522 - wm8750_vol_update(s);
523 - break;
524 -
525 - case WM8750_ROUT2V: /* ROUT2 Volume */
526 - s->outvol[5] = value & 0x7f; /* ROUT2VOL */
527 - wm8750_vol_update(s);
528 - break;
529 -
530 - case WM8750_MOUTV: /* MONOOUT Volume */
531 - s->outvol[6] = value & 0x7f; /* MONOOUTVOL */
532 - wm8750_vol_update(s);
533 - break;
534 -
535 - case WM8750_ADCTL2: /* Additional Control (2) */
536 - break;
537 -
538 - case WM8750_PWR2: /* Power Management (2) */
539 - s->power = value & 0x7e;
540 - /* TODO: mute/unmute respective paths */
541 - wm8750_vol_update(s);
542 - break;
543 -
544 - case WM8750_IFACE: /* Digital Audio Interface Format */
545 - s->format = value;
546 - s->master = (value >> 6) & 1; /* MS */
547 - wm8750_clk_update(s, s->master);
548 - break;
549 -
550 - case WM8750_SRATE: /* Clocking and Sample Rate Control */
551 - s->rate = &wm_rate_table[(value >> 1) & 0x1f];
552 - wm8750_clk_update(s, 0);
553 - break;
554 -
555 - case WM8750_RESET: /* Reset */
556 - wm8750_reset(I2C_SLAVE(s));
557 - break;
558 -
559 -#ifdef VERBOSE
560 - default:
561 - printf("%s: unknown register %02x\n", __func__, cmd);
562 -#endif
563 - }
564 -
565 - return 0;
566 -}
567 -
568 -static uint8_t wm8750_rx(I2CSlave *i2c)
569 -{
570 - return 0x00;
571 -}
572 -
573 -static int wm8750_pre_save(void *opaque)
574 -{
575 - WM8750State *s = opaque;
576 -
577 - s->rate_vmstate = s->rate - wm_rate_table;
578 -
579 - return 0;
580 -}
581 -
582 -static int wm8750_post_load(void *opaque, int version_id)
583 -{
584 - WM8750State *s = opaque;
585 -
586 - s->rate = &wm_rate_table[s->rate_vmstate & 0x1f];
587 - return 0;
588 -}
589 -
590 -static const VMStateDescription vmstate_wm8750 = {
591 - .name = CODEC,
592 - .version_id = 0,
593 - .minimum_version_id = 0,
594 - .pre_save = wm8750_pre_save,
595 - .post_load = wm8750_post_load,
596 - .fields = (const VMStateField[]) {
597 - VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
598 - VMSTATE_INT32(i2c_len, WM8750State),
599 - VMSTATE_INT32(enable, WM8750State),
600 - VMSTATE_INT32(idx_in, WM8750State),
601 - VMSTATE_INT32(req_in, WM8750State),
602 - VMSTATE_INT32(idx_out, WM8750State),
603 - VMSTATE_INT32(req_out, WM8750State),
604 - VMSTATE_UINT8_ARRAY(outvol, WM8750State, 7),
605 - VMSTATE_UINT8_ARRAY(outmute, WM8750State, 2),
606 - VMSTATE_UINT8_ARRAY(invol, WM8750State, 4),
607 - VMSTATE_UINT8_ARRAY(inmute, WM8750State, 2),
608 - VMSTATE_UINT8_ARRAY(diff, WM8750State, 2),
609 - VMSTATE_UINT8(pol, WM8750State),
610 - VMSTATE_UINT8(ds, WM8750State),
611 - VMSTATE_UINT8_ARRAY(monomix, WM8750State, 2),
612 - VMSTATE_UINT8(alc, WM8750State),
613 - VMSTATE_UINT8(mute, WM8750State),
614 - VMSTATE_UINT8_ARRAY(path, WM8750State, 4),
615 - VMSTATE_UINT8_ARRAY(mpath, WM8750State, 2),
616 - VMSTATE_UINT8(format, WM8750State),
617 - VMSTATE_UINT8(power, WM8750State),
618 - VMSTATE_UINT8(rate_vmstate, WM8750State),
619 - VMSTATE_I2C_SLAVE(parent_obj, WM8750State),
620 - VMSTATE_END_OF_LIST()
621 - }
622 -};
623 -
624 -static void wm8750_realize(DeviceState *dev, Error **errp)
625 -{
626 - WM8750State *s = WM8750(dev);
627 -
628 - if (!audio_be_check(&s->audio_be, errp)) {
629 - return;
630 - }
631 -
632 - wm8750_reset(I2C_SLAVE(s));
633 -}
634 -
635 -#if 0
636 -static void wm8750_fini(I2CSlave *i2c)
637 -{
638 - WM8750State *s = WM8750(i2c);
639 -
640 - wm8750_reset(I2C_SLAVE(s));
641 - g_free(s);
642 -}
643 -#endif
644 -
645 -void wm8750_data_req_set(DeviceState *dev, data_req_cb *data_req, void *opaque)
646 -{
647 - WM8750State *s = WM8750(dev);
648 -
649 - s->data_req = data_req;
650 - s->opaque = opaque;
651 -}
652 -
653 -void wm8750_dac_dat(void *opaque, uint32_t sample)
654 -{
655 - WM8750State *s = (WM8750State *) opaque;
656 -
657 - *(uint32_t *) &s->data_out[s->idx_out] = sample;
658 - s->req_out -= 4;
659 - s->idx_out += 4;
660 - if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
661 - wm8750_out_flush(s);
662 -}
663 -
664 -void *wm8750_dac_buffer(void *opaque, int samples)
665 -{
666 - WM8750State *s = (WM8750State *) opaque;
667 - /* XXX: Should check if there are <i>samples</i> free samples available */
668 - void *ret = s->data_out + s->idx_out;
669 -
670 - s->idx_out += samples << 2;
671 - s->req_out -= samples << 2;
672 - return ret;
673 -}
674 -
675 -void wm8750_dac_commit(void *opaque)
676 -{
677 - WM8750State *s = (WM8750State *) opaque;
678 -
679 - wm8750_out_flush(s);
680 -}
681 -
682 -uint32_t wm8750_adc_dat(void *opaque)
683 -{
684 - WM8750State *s = (WM8750State *) opaque;
685 - uint32_t *data;
686 -
687 - if (s->idx_in >= sizeof(s->data_in)) {
688 - wm8750_in_load(s);
689 - if (s->idx_in >= sizeof(s->data_in)) {
690 - return 0x80008000; /* silence in AUDIO_FORMAT_S16 sample format */
691 - }
692 - }
693 -
694 - data = (uint32_t *) &s->data_in[s->idx_in];
695 - s->req_in -= 4;
696 - s->idx_in += 4;
697 - return *data;
698 -}
699 -
700 -void wm8750_set_bclk_in(void *opaque, int new_hz)
701 -{
702 - WM8750State *s = (WM8750State *) opaque;
703 -
704 - s->ext_adc_hz = new_hz;
705 - s->ext_dac_hz = new_hz;
706 - wm8750_clk_update(s, 1);
707 -}
708 -
709 -static const Property wm8750_properties[] = {
710 - DEFINE_AUDIO_PROPERTIES(WM8750State, audio_be),
711 -};
712 -
713 -static void wm8750_class_init(ObjectClass *klass, const void *data)
714 -{
715 - DeviceClass *dc = DEVICE_CLASS(klass);
716 - I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
717 -
718 - dc->realize = wm8750_realize;
719 - sc->event = wm8750_event;
720 - sc->recv = wm8750_rx;
721 - sc->send = wm8750_tx;
722 - dc->vmsd = &vmstate_wm8750;
723 - device_class_set_props(dc, wm8750_properties);
724 -}
725 -
726 -static const TypeInfo wm8750_info = {
727 - .name = TYPE_WM8750,
728 - .parent = TYPE_I2C_SLAVE,
729 - .instance_size = sizeof(WM8750State),
730 - .class_init = wm8750_class_init,
731 -};
732 -
733 -static void wm8750_register_types(void)
734 -{
735 - type_register_static(&wm8750_info);
736 -}
737 -
738 -type_init(wm8750_register_types)
include/hw/audio/wm8750.h deleted
-30
@@ -1,30 +0,0 @@
1 -/*
2 - * This program is free software; you can redistribute it and/or modify it
3 - * under the terms and conditions of the GNU General Public License,
4 - * version 2 or later, as published by the Free Software Foundation.
5 - *
6 - * This program is distributed in the hope it will be useful, but WITHOUT
7 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
9 - * more details.
10 - *
11 - * You should have received a copy of the GNU General Public License along with
12 - * this program. If not, see <http://www.gnu.org/licenses/>.
13 - */
14 -#ifndef HW_DAC_WM8750_H
15 -#define HW_DAC_WM8750_H
16 -
17 -
18 -#define TYPE_WM8750 "wm8750"
19 -#define TYPE_MV88W8618_AUDIO "mv88w8618_audio"
20 -
21 -typedef void data_req_cb(void *opaque, int free_out, int free_in);
22 -
23 -void wm8750_data_req_set(DeviceState *dev, data_req_cb *data_req, void *opaque);
24 -void wm8750_dac_dat(void *opaque, uint32_t sample);
25 -uint32_t wm8750_adc_dat(void *opaque);
26 -void *wm8750_dac_buffer(void *opaque, int samples);
27 -void wm8750_dac_commit(void *opaque);
28 -void wm8750_set_bclk_in(void *opaque, int new_hz);
29 -
30 -#endif