Statistics
| Branch: | Revision:

root / hw / wm8750.c @ 9596ebb7

History | View | Annotate | Download (17.8 kB)

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 "hw.h"
11
#include "i2c.h"
12
#include "audio/audio.h"
13

    
14
#define IN_PORT_N        3
15
#define OUT_PORT_N        3
16

    
17
#define CODEC                "wm8750"
18

    
19
struct wm_rate_s;
20
struct wm8750_s {
21
    i2c_slave i2c;
22
    uint8_t i2c_data[2];
23
    int i2c_len;
24
    QEMUSoundCard card;
25
    SWVoiceIn *adc_voice[IN_PORT_N];
26
    SWVoiceOut *dac_voice[OUT_PORT_N];
27
    int enable;
28
    void (*data_req)(void *, int, int);
29
    void *opaque;
30
    uint8_t data_in[4096];
31
    uint8_t data_out[4096];
32
    int idx_in, req_in;
33
    int idx_out, req_out;
34

    
35
    SWVoiceOut **out[2];
36
    uint8_t outvol[7], outmute[2];
37
    SWVoiceIn **in[2];
38
    uint8_t invol[4], inmute[2];
39

    
40
    uint8_t diff[2], pol, ds, monomix[2], alc, mute;
41
    uint8_t path[4], mpath[2], power, format;
42
    uint32_t inmask, outmask;
43
    const struct wm_rate_s *rate;
44
};
45

    
46
static inline void wm8750_in_load(struct wm8750_s *s)
47
{
48
    int acquired;
49
    if (s->idx_in + s->req_in <= sizeof(s->data_in))
50
        return;
51
    s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
52
    acquired = AUD_read(*s->in[0], s->data_in + s->idx_in,
53
                    sizeof(s->data_in) - s->idx_in);
54
}
55

    
56
static inline void wm8750_out_flush(struct wm8750_s *s)
57
{
58
    int sent;
59
    if (!s->idx_out)
60
        return;
61
    sent = AUD_write(*s->out[0], s->data_out, s->idx_out);
62
    s->idx_out = 0;
63
}
64

    
65
static void wm8750_audio_in_cb(void *opaque, int avail_b)
66
{
67
    struct wm8750_s *s = (struct wm8750_s *) opaque;
68
    s->req_in = avail_b;
69
    s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
70

    
71
#if 0
72
    wm8750_in_load(s);
73
#endif
74
}
75

    
76
static void wm8750_audio_out_cb(void *opaque, int free_b)
77
{
78
    struct wm8750_s *s = (struct wm8750_s *) opaque;
79
    wm8750_out_flush(s);
80

    
81
    s->req_out = free_b;
82
    s->data_req(s->opaque, free_b >> 2, s->req_in >> 2);
83
}
84

    
85
struct wm_rate_s {
86
    int adc;
87
    int adc_hz;
88
    int dac;
89
    int dac_hz;
90
};
91

    
92
static const struct wm_rate_s wm_rate_table[] = {
93
    {  256, 48000,  256, 48000 },        /* SR: 00000 */
94
    {  384, 48000,  384, 48000 },        /* SR: 00001 */
95
    {  256, 48000, 1536,  8000 },        /* SR: 00010 */
96
    {  384, 48000, 2304,  8000 },        /* SR: 00011 */
97
    { 1536,  8000,  256, 48000 },        /* SR: 00100 */
98
    { 2304,  8000,  384, 48000 },        /* SR: 00101 */
99
    { 1536,  8000, 1536,  8000 },        /* SR: 00110 */
100
    { 2304,  8000, 2304,  8000 },        /* SR: 00111 */
101
    { 1024, 12000, 1024, 12000 },        /* SR: 01000 */
102
    { 1526, 12000, 1536, 12000 },        /* SR: 01001 */
103
    {  768, 16000,  768, 16000 },        /* SR: 01010 */
104
    { 1152, 16000, 1152, 16000 },        /* SR: 01011 */
105
    {  384, 32000,  384, 32000 },        /* SR: 01100 */
106
    {  576, 32000,  576, 32000 },        /* SR: 01101 */
107
    {  128, 96000,  128, 96000 },        /* SR: 01110 */
108
    {  192, 96000,  192, 96000 },        /* SR: 01111 */
109
    {  256, 44100,  256, 44100 },        /* SR: 10000 */
110
    {  384, 44100,  384, 44100 },        /* SR: 10001 */
111
    {  256, 44100, 1408,  8018 },        /* SR: 10010 */
112
    {  384, 44100, 2112,  8018 },        /* SR: 10011 */
113
    { 1408,  8018,  256, 44100 },        /* SR: 10100 */
114
    { 2112,  8018,  384, 44100 },        /* SR: 10101 */
115
    { 1408,  8018, 1408,  8018 },        /* SR: 10110 */
116
    { 2112,  8018, 2112,  8018 },        /* SR: 10111 */
117
    { 1024, 11025, 1024, 11025 },        /* SR: 11000 */
118
    { 1536, 11025, 1536, 11025 },        /* SR: 11001 */
119
    {  512, 22050,  512, 22050 },        /* SR: 11010 */
120
    {  768, 22050,  768, 22050 },        /* SR: 11011 */
121
    {  512, 24000,  512, 24000 },        /* SR: 11100 */
122
    {  768, 24000,  768, 24000 },        /* SR: 11101 */
123
    {  128, 88200,  128, 88200 },        /* SR: 11110 */
124
    {  192, 88200,  128, 88200 },        /* SR: 11111 */
125
};
126

    
127
static void wm8750_set_format(struct wm8750_s *s)
128
{
129
    int i;
130
    audsettings_t in_fmt;
131
    audsettings_t out_fmt;
132
    audsettings_t monoout_fmt;
133

    
134
    wm8750_out_flush(s);
135

    
136
    if (s->in[0] && *s->in[0])
137
        AUD_set_active_in(*s->in[0], 0);
138
    if (s->out[0] && *s->out[0])
139
        AUD_set_active_out(*s->out[0], 0);
140

    
141
    for (i = 0; i < IN_PORT_N; i ++)
142
        if (s->adc_voice[i]) {
143
            AUD_close_in(&s->card, s->adc_voice[i]);
144
            s->adc_voice[i] = 0;
145
        }
146
    for (i = 0; i < OUT_PORT_N; i ++)
147
        if (s->dac_voice[i]) {
148
            AUD_close_out(&s->card, s->dac_voice[i]);
149
            s->dac_voice[i] = 0;
150
        }
151

    
152
    if (!s->enable)
153
        return;
154

    
155
    /* Setup input */
156
    in_fmt.endianness = 0;
157
    in_fmt.nchannels = 2;
158
    in_fmt.freq = s->rate->adc_hz;
159
    in_fmt.fmt = AUD_FMT_S16;
160

    
161
    s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
162
                    CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
163
    s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
164
                    CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
165
    s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
166
                    CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
167

    
168
    /* Setup output */
169
    out_fmt.endianness = 0;
170
    out_fmt.nchannels = 2;
171
    out_fmt.freq = s->rate->dac_hz;
172
    out_fmt.fmt = AUD_FMT_S16;
173
    monoout_fmt.endianness = 0;
174
    monoout_fmt.nchannels = 1;
175
    monoout_fmt.freq = s->rate->dac_hz;
176
    monoout_fmt.fmt = AUD_FMT_S16;
177

    
178
    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
179
                    CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
180
    s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
181
                    CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
182
    /* MONOMIX is also in stereo for simplicity */
183
    s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
184
                    CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
185
    /* no sense emulating OUT3 which is a mix of other outputs */
186

    
187
    /* We should connect the left and right channels to their
188
     * respective inputs/outputs but we have completely no need
189
     * for mixing or combining paths to different ports, so we
190
     * connect both channels to where the left channel is routed.  */
191
    if (s->in[0] && *s->in[0])
192
        AUD_set_active_in(*s->in[0], 1);
193
    if (s->out[0] && *s->out[0])
194
        AUD_set_active_out(*s->out[0], 1);
195
}
196

    
197
static void inline wm8750_mask_update(struct wm8750_s *s)
198
{
199
#define R_ONLY        0x0000ffff
200
#define L_ONLY        0xffff0000
201
#define BOTH        (R_ONLY | L_ONLY)
202
#define NONE        (R_ONLY & L_ONLY)
203
    s->inmask =
204
            (s->inmute[0] ? R_ONLY : BOTH) &
205
            (s->inmute[1] ? L_ONLY : BOTH) &
206
            (s->mute ? NONE : BOTH);
207
    s->outmask =
208
            (s->outmute[0] ? R_ONLY : BOTH) &
209
            (s->outmute[1] ? L_ONLY : BOTH) &
210
            (s->mute ? NONE : BOTH);
211
}
212

    
213
void wm8750_reset(i2c_slave *i2c)
214
{
215
    struct wm8750_s *s = (struct wm8750_s *) i2c;
216
    s->enable = 0;
217
    wm8750_set_format(s);
218
    s->diff[0] = 0;
219
    s->diff[1] = 0;
220
    s->ds = 0;
221
    s->alc = 0;
222
    s->in[0] = &s->adc_voice[0];
223
    s->invol[0] = 0x17;
224
    s->invol[1] = 0x17;
225
    s->invol[2] = 0xc3;
226
    s->invol[3] = 0xc3;
227
    s->out[0] = &s->dac_voice[0];
228
    s->outvol[0] = 0xff;
229
    s->outvol[1] = 0xff;
230
    s->outvol[2] = 0x79;
231
    s->outvol[3] = 0x79;
232
    s->outvol[4] = 0x79;
233
    s->outvol[5] = 0x79;
234
    s->inmute[0] = 0;
235
    s->inmute[1] = 0;
236
    s->outmute[0] = 0;
237
    s->outmute[1] = 0;
238
    s->mute = 1;
239
    s->path[0] = 0;
240
    s->path[1] = 0;
241
    s->path[2] = 0;
242
    s->path[3] = 0;
243
    s->mpath[0] = 0;
244
    s->mpath[1] = 0;
245
    s->format = 0x0a;
246
    s->idx_in = sizeof(s->data_in);
247
    s->req_in = 0;
248
    s->idx_out = 0;
249
    s->req_out = 0;
250
    wm8750_mask_update(s);
251
    s->i2c_len = 0;
252
}
253

    
254
static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
255
{
256
    struct wm8750_s *s = (struct wm8750_s *) i2c;
257

    
258
    switch (event) {
259
    case I2C_START_SEND:
260
        s->i2c_len = 0;
261
        break;
262
    case I2C_FINISH:
263
#ifdef VERBOSE
264
        if (s->i2c_len < 2)
265
            printf("%s: message too short (%i bytes)\n",
266
                            __FUNCTION__, s->i2c_len);
267
#endif
268
        break;
269
    default:
270
        break;
271
    }
272
}
273

    
274
#define WM8750_LINVOL        0x00
275
#define WM8750_RINVOL        0x01
276
#define WM8750_LOUT1V        0x02
277
#define WM8750_ROUT1V        0x03
278
#define WM8750_ADCDAC        0x05
279
#define WM8750_IFACE        0x07
280
#define WM8750_SRATE        0x08
281
#define WM8750_LDAC        0x0a
282
#define WM8750_RDAC        0x0b
283
#define WM8750_BASS        0x0c
284
#define WM8750_TREBLE        0x0d
285
#define WM8750_RESET        0x0f
286
#define WM8750_3D        0x10
287
#define WM8750_ALC1        0x11
288
#define WM8750_ALC2        0x12
289
#define WM8750_ALC3        0x13
290
#define WM8750_NGATE        0x14
291
#define WM8750_LADC        0x15
292
#define WM8750_RADC        0x16
293
#define WM8750_ADCTL1        0x17
294
#define WM8750_ADCTL2        0x18
295
#define WM8750_PWR1        0x19
296
#define WM8750_PWR2        0x1a
297
#define WM8750_ADCTL3        0x1b
298
#define WM8750_ADCIN        0x1f
299
#define WM8750_LADCIN        0x20
300
#define WM8750_RADCIN        0x21
301
#define WM8750_LOUTM1        0x22
302
#define WM8750_LOUTM2        0x23
303
#define WM8750_ROUTM1        0x24
304
#define WM8750_ROUTM2        0x25
305
#define WM8750_MOUTM1        0x26
306
#define WM8750_MOUTM2        0x27
307
#define WM8750_LOUT2V        0x28
308
#define WM8750_ROUT2V        0x29
309
#define WM8750_MOUTV        0x2a
310

    
311
static int wm8750_tx(i2c_slave *i2c, uint8_t data)
312
{
313
    struct wm8750_s *s = (struct wm8750_s *) i2c;
314
    uint8_t cmd;
315
    uint16_t value;
316

    
317
    if (s->i2c_len >= 2) {
318
        printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
319
#ifdef VERBOSE
320
        return 1;
321
#endif
322
    }
323
    s->i2c_data[s->i2c_len ++] = data;
324
    if (s->i2c_len != 2)
325
        return 0;
326

    
327
    cmd = s->i2c_data[0] >> 1;
328
    value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
329

    
330
    switch (cmd) {
331
    case WM8750_LADCIN:        /* ADC Signal Path Control (Left) */
332
        s->diff[0] = (((value >> 6) & 3) == 3);        /* LINSEL */
333
        if (s->diff[0])
334
            s->in[0] = &s->adc_voice[0 + s->ds * 1];
335
        else
336
            s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
337
        break;
338

    
339
    case WM8750_RADCIN:        /* ADC Signal Path Control (Right) */
340
        s->diff[1] = (((value >> 6) & 3) == 3);        /* RINSEL */
341
        if (s->diff[1])
342
            s->in[1] = &s->adc_voice[0 + s->ds * 1];
343
        else
344
            s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
345
        break;
346

    
347
    case WM8750_ADCIN:        /* ADC Input Mode */
348
        s->ds = (value >> 8) & 1;        /* DS */
349
        if (s->diff[0])
350
            s->in[0] = &s->adc_voice[0 + s->ds * 1];
351
        if (s->diff[1])
352
            s->in[1] = &s->adc_voice[0 + s->ds * 1];
353
        s->monomix[0] = (value >> 6) & 3;        /* MONOMIX */
354
        break;
355

    
356
    case WM8750_ADCTL1:        /* Additional Control (1) */
357
        s->monomix[1] = (value >> 1) & 1;        /* DMONOMIX */
358
        break;
359

    
360
    case WM8750_PWR1:        /* Power Management (1) */
361
        s->enable = ((value >> 6) & 7) == 3;        /* VMIDSEL, VREF */
362
        wm8750_set_format(s);
363
        break;
364

    
365
    case WM8750_LINVOL:        /* Left Channel PGA */
366
        s->invol[0] = value & 0x3f;                /* LINVOL */
367
        s->inmute[0] = (value >> 7) & 1;        /* LINMUTE */
368
        wm8750_mask_update(s);
369
        break;
370

    
371
    case WM8750_RINVOL:        /* Right Channel PGA */
372
        s->invol[1] = value & 0x3f;                /* RINVOL */
373
        s->inmute[1] = (value >> 7) & 1;        /* RINMUTE */
374
        wm8750_mask_update(s);
375
        break;
376

    
377
    case WM8750_ADCDAC:        /* ADC and DAC Control */
378
        s->pol = (value >> 5) & 3;                /* ADCPOL */
379
        s->mute = (value >> 3) & 1;                /* DACMU */
380
        wm8750_mask_update(s);
381
        break;
382

    
383
    case WM8750_ADCTL3:        /* Additional Control (3) */
384
        break;
385

    
386
    case WM8750_LADC:        /* Left ADC Digital Volume */
387
        s->invol[2] = value & 0xff;                /* LADCVOL */
388
        break;
389

    
390
    case WM8750_RADC:        /* Right ADC Digital Volume */
391
        s->invol[3] = value & 0xff;                /* RADCVOL */
392
        break;
393

    
394
    case WM8750_ALC1:        /* ALC Control (1) */
395
        s->alc = (value >> 7) & 3;                /* ALCSEL */
396
        break;
397

    
398
    case WM8750_NGATE:        /* Noise Gate Control */
399
    case WM8750_3D:        /* 3D enhance */
400
        break;
401

    
402
    case WM8750_LDAC:        /* Left Channel Digital Volume */
403
        s->outvol[0] = value & 0xff;                /* LDACVOL */
404
        break;
405

    
406
    case WM8750_RDAC:        /* Right Channel Digital Volume */
407
        s->outvol[1] = value & 0xff;                /* RDACVOL */
408
        break;
409

    
410
    case WM8750_BASS:        /* Bass Control */
411
        break;
412

    
413
    case WM8750_LOUTM1:        /* Left Mixer Control (1) */
414
        s->path[0] = (value >> 8) & 1;                /* LD2LO */
415
        break;
416

    
417
    case WM8750_LOUTM2:        /* Left Mixer Control (2) */
418
        s->path[1] = (value >> 8) & 1;                /* RD2LO */
419
        break;
420

    
421
    case WM8750_ROUTM1:        /* Right Mixer Control (1) */
422
        s->path[2] = (value >> 8) & 1;                /* LD2RO */
423
        break;
424

    
425
    case WM8750_ROUTM2:        /* Right Mixer Control (2) */
426
        s->path[3] = (value >> 8) & 1;                /* RD2RO */
427
        break;
428

    
429
    case WM8750_MOUTM1:        /* Mono Mixer Control (1) */
430
        s->mpath[0] = (value >> 8) & 1;                /* LD2MO */
431
        break;
432

    
433
    case WM8750_MOUTM2:        /* Mono Mixer Control (2) */
434
        s->mpath[1] = (value >> 8) & 1;                /* RD2MO */
435
        break;
436

    
437
    case WM8750_LOUT1V:        /* LOUT1 Volume */
438
        s->outvol[2] = value & 0x7f;                /* LOUT2VOL */
439
        break;
440

    
441
    case WM8750_LOUT2V:        /* LOUT2 Volume */
442
        s->outvol[4] = value & 0x7f;                /* LOUT2VOL */
443
        break;
444

    
445
    case WM8750_ROUT1V:        /* ROUT1 Volume */
446
        s->outvol[3] = value & 0x7f;                /* ROUT2VOL */
447
        break;
448

    
449
    case WM8750_ROUT2V:        /* ROUT2 Volume */
450
        s->outvol[5] = value & 0x7f;                /* ROUT2VOL */
451
        break;
452

    
453
    case WM8750_MOUTV:        /* MONOOUT Volume */
454
        s->outvol[6] = value & 0x7f;                /* MONOOUTVOL */
455
        break;
456

    
457
    case WM8750_ADCTL2:        /* Additional Control (2) */
458
        break;
459

    
460
    case WM8750_PWR2:        /* Power Management (2) */
461
        s->power = value & 0x7e;
462
        break;
463

    
464
    case WM8750_IFACE:        /* Digital Audio Interface Format */
465
#ifdef VERBOSE
466
        if (value & 0x40)                        /* MS */
467
            printf("%s: attempt to enable Master Mode\n", __FUNCTION__);
468
#endif
469
        s->format = value;
470
        wm8750_set_format(s);
471
        break;
472

    
473
    case WM8750_SRATE:        /* Clocking and Sample Rate Control */
474
        s->rate = &wm_rate_table[(value >> 1) & 0x1f];
475
        wm8750_set_format(s);
476
        break;
477

    
478
    case WM8750_RESET:        /* Reset */
479
        wm8750_reset(&s->i2c);
480
        break;
481

    
482
#ifdef VERBOSE
483
    default:
484
        printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
485
#endif
486
    }
487

    
488
    return 0;
489
}
490

    
491
static int wm8750_rx(i2c_slave *i2c)
492
{
493
    return 0x00;
494
}
495

    
496
static void wm8750_save(QEMUFile *f, void *opaque)
497
{
498
    struct wm8750_s *s = (struct wm8750_s *) opaque;
499
    int i;
500
    qemu_put_8s(f, &s->i2c_data[0]);
501
    qemu_put_8s(f, &s->i2c_data[1]);
502
    qemu_put_be32(f, s->i2c_len);
503
    qemu_put_be32(f, s->enable);
504
    qemu_put_be32(f, s->idx_in);
505
    qemu_put_be32(f, s->req_in);
506
    qemu_put_be32(f, s->idx_out);
507
    qemu_put_be32(f, s->req_out);
508

    
509
    for (i = 0; i < 7; i ++)
510
        qemu_put_8s(f, &s->outvol[i]);
511
    for (i = 0; i < 2; i ++)
512
        qemu_put_8s(f, &s->outmute[i]);
513
    for (i = 0; i < 4; i ++)
514
        qemu_put_8s(f, &s->invol[i]);
515
    for (i = 0; i < 2; i ++)
516
        qemu_put_8s(f, &s->inmute[i]);
517

    
518
    for (i = 0; i < 2; i ++)
519
        qemu_put_8s(f, &s->diff[i]);
520
    qemu_put_8s(f, &s->pol);
521
    qemu_put_8s(f, &s->ds);
522
    for (i = 0; i < 2; i ++)
523
        qemu_put_8s(f, &s->monomix[i]);
524
    qemu_put_8s(f, &s->alc);
525
    qemu_put_8s(f, &s->mute);
526
    for (i = 0; i < 4; i ++)
527
        qemu_put_8s(f, &s->path[i]);
528
    for (i = 0; i < 2; i ++)
529
        qemu_put_8s(f, &s->mpath[i]);
530
    qemu_put_8s(f, &s->format);
531
    qemu_put_8s(f, &s->power);
532
    qemu_put_be32s(f, &s->inmask);
533
    qemu_put_be32s(f, &s->outmask);
534
    qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
535
    i2c_slave_save(f, &s->i2c);
536
}
537

    
538
static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
539
{
540
    struct wm8750_s *s = (struct wm8750_s *) opaque;
541
    int i;
542
    qemu_get_8s(f, &s->i2c_data[0]);
543
    qemu_get_8s(f, &s->i2c_data[1]);
544
    s->i2c_len = qemu_get_be32(f);
545
    s->enable = qemu_get_be32(f);
546
    s->idx_in = qemu_get_be32(f);
547
    s->req_in = qemu_get_be32(f);
548
    s->idx_out = qemu_get_be32(f);
549
    s->req_out = qemu_get_be32(f);
550

    
551
    for (i = 0; i < 7; i ++)
552
        qemu_get_8s(f, &s->outvol[i]);
553
    for (i = 0; i < 2; i ++)
554
        qemu_get_8s(f, &s->outmute[i]);
555
    for (i = 0; i < 4; i ++)
556
        qemu_get_8s(f, &s->invol[i]);
557
    for (i = 0; i < 2; i ++)
558
        qemu_get_8s(f, &s->inmute[i]);
559

    
560
    for (i = 0; i < 2; i ++)
561
        qemu_get_8s(f, &s->diff[i]);
562
    qemu_get_8s(f, &s->pol);
563
    qemu_get_8s(f, &s->ds);
564
    for (i = 0; i < 2; i ++)
565
        qemu_get_8s(f, &s->monomix[i]);
566
    qemu_get_8s(f, &s->alc);
567
    qemu_get_8s(f, &s->mute);
568
    for (i = 0; i < 4; i ++)
569
        qemu_get_8s(f, &s->path[i]);
570
    for (i = 0; i < 2; i ++)
571
        qemu_get_8s(f, &s->mpath[i]);
572
    qemu_get_8s(f, &s->format);
573
    qemu_get_8s(f, &s->power);
574
    qemu_get_be32s(f, &s->inmask);
575
    qemu_get_be32s(f, &s->outmask);
576
    s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
577
    i2c_slave_load(f, &s->i2c);
578
    return 0;
579
}
580

    
581
static int wm8750_iid = 0;
582

    
583
i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
584
{
585
    struct wm8750_s *s = (struct wm8750_s *)
586
            i2c_slave_init(bus, 0, sizeof(struct wm8750_s));
587
    s->i2c.event = wm8750_event;
588
    s->i2c.recv = wm8750_rx;
589
    s->i2c.send = wm8750_tx;
590

    
591
    AUD_register_card(audio, CODEC, &s->card);
592
    wm8750_reset(&s->i2c);
593

    
594
    register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s);
595

    
596
    return &s->i2c;
597
}
598

    
599
static void wm8750_fini(i2c_slave *i2c)
600
{
601
    struct wm8750_s *s = (struct wm8750_s *) i2c;
602
    wm8750_reset(&s->i2c);
603
    AUD_remove_card(&s->card);
604
    qemu_free(s);
605
}
606

    
607
void wm8750_data_req_set(i2c_slave *i2c,
608
                void (*data_req)(void *, int, int), void *opaque)
609
{
610
    struct wm8750_s *s = (struct wm8750_s *) i2c;
611
    s->data_req = data_req;
612
    s->opaque = opaque;
613
}
614

    
615
void wm8750_dac_dat(void *opaque, uint32_t sample)
616
{
617
    struct wm8750_s *s = (struct wm8750_s *) opaque;
618
    uint32_t *data = (uint32_t *) &s->data_out[s->idx_out];
619
    *data = sample & s->outmask;
620
    s->req_out -= 4;
621
    s->idx_out += 4;
622
    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
623
        wm8750_out_flush(s);
624
}
625

    
626
uint32_t wm8750_adc_dat(void *opaque)
627
{
628
    struct wm8750_s *s = (struct wm8750_s *) opaque;
629
    uint32_t *data;
630
    if (s->idx_in >= sizeof(s->data_in))
631
        wm8750_in_load(s);
632
    data = (uint32_t *) &s->data_in[s->idx_in];
633
    s->req_in -= 4;
634
    s->idx_in += 4;
635
    return *data & s->inmask;
636
}