Statistics
| Branch: | Revision:

root / hw / wm8750.c @ c75a823c

History | View | Annotate | Download (18.4 kB)

1 adb86c37 balrog
/*
2 adb86c37 balrog
 * WM8750 audio CODEC.
3 adb86c37 balrog
 *
4 adb86c37 balrog
 * Copyright (c) 2006 Openedhand Ltd.
5 adb86c37 balrog
 * Written by Andrzej Zaborowski <balrog@zabor.org>
6 adb86c37 balrog
 *
7 adb86c37 balrog
 * This file is licensed under GNU GPL.
8 adb86c37 balrog
 */
9 adb86c37 balrog
10 87ecb68b pbrook
#include "hw.h"
11 87ecb68b pbrook
#include "i2c.h"
12 87ecb68b pbrook
#include "audio/audio.h"
13 adb86c37 balrog
14 adb86c37 balrog
#define IN_PORT_N        3
15 adb86c37 balrog
#define OUT_PORT_N        3
16 adb86c37 balrog
17 adb86c37 balrog
#define CODEC                "wm8750"
18 adb86c37 balrog
19 adb86c37 balrog
struct wm_rate_s;
20 adb86c37 balrog
struct wm8750_s {
21 adb86c37 balrog
    i2c_slave i2c;
22 adb86c37 balrog
    uint8_t i2c_data[2];
23 adb86c37 balrog
    int i2c_len;
24 adb86c37 balrog
    QEMUSoundCard card;
25 adb86c37 balrog
    SWVoiceIn *adc_voice[IN_PORT_N];
26 adb86c37 balrog
    SWVoiceOut *dac_voice[OUT_PORT_N];
27 adb86c37 balrog
    int enable;
28 adb86c37 balrog
    void (*data_req)(void *, int, int);
29 adb86c37 balrog
    void *opaque;
30 adb86c37 balrog
    uint8_t data_in[4096];
31 adb86c37 balrog
    uint8_t data_out[4096];
32 adb86c37 balrog
    int idx_in, req_in;
33 adb86c37 balrog
    int idx_out, req_out;
34 adb86c37 balrog
35 adb86c37 balrog
    SWVoiceOut **out[2];
36 adb86c37 balrog
    uint8_t outvol[7], outmute[2];
37 adb86c37 balrog
    SWVoiceIn **in[2];
38 adb86c37 balrog
    uint8_t invol[4], inmute[2];
39 adb86c37 balrog
40 adb86c37 balrog
    uint8_t diff[2], pol, ds, monomix[2], alc, mute;
41 adb86c37 balrog
    uint8_t path[4], mpath[2], power, format;
42 adb86c37 balrog
    uint32_t inmask, outmask;
43 adb86c37 balrog
    const struct wm_rate_s *rate;
44 adb86c37 balrog
};
45 adb86c37 balrog
46 adb86c37 balrog
static inline void wm8750_in_load(struct wm8750_s *s)
47 adb86c37 balrog
{
48 adb86c37 balrog
    int acquired;
49 adb86c37 balrog
    if (s->idx_in + s->req_in <= sizeof(s->data_in))
50 adb86c37 balrog
        return;
51 adb86c37 balrog
    s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
52 adb86c37 balrog
    acquired = AUD_read(*s->in[0], s->data_in + s->idx_in,
53 adb86c37 balrog
                    sizeof(s->data_in) - s->idx_in);
54 adb86c37 balrog
}
55 adb86c37 balrog
56 adb86c37 balrog
static inline void wm8750_out_flush(struct wm8750_s *s)
57 adb86c37 balrog
{
58 523111e7 balrog
    int sent = 0;
59 523111e7 balrog
    while (sent < s->idx_out)
60 523111e7 balrog
        sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent)
61 523111e7 balrog
                ?: s->idx_out;
62 adb86c37 balrog
    s->idx_out = 0;
63 adb86c37 balrog
}
64 adb86c37 balrog
65 adb86c37 balrog
static void wm8750_audio_in_cb(void *opaque, int avail_b)
66 adb86c37 balrog
{
67 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
68 adb86c37 balrog
    s->req_in = avail_b;
69 adb86c37 balrog
    s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
70 adb86c37 balrog
}
71 adb86c37 balrog
72 adb86c37 balrog
static void wm8750_audio_out_cb(void *opaque, int free_b)
73 adb86c37 balrog
{
74 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
75 adb86c37 balrog
76 523111e7 balrog
    if (s->idx_out >= free_b) {
77 523111e7 balrog
        s->idx_out = free_b;
78 523111e7 balrog
        s->req_out = 0;
79 523111e7 balrog
        wm8750_out_flush(s);
80 523111e7 balrog
    } else
81 523111e7 balrog
        s->req_out = free_b - s->idx_out;
82 523111e7 balrog
 
83 523111e7 balrog
    s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
84 adb86c37 balrog
}
85 adb86c37 balrog
86 adb86c37 balrog
struct wm_rate_s {
87 adb86c37 balrog
    int adc;
88 adb86c37 balrog
    int adc_hz;
89 adb86c37 balrog
    int dac;
90 adb86c37 balrog
    int dac_hz;
91 adb86c37 balrog
};
92 adb86c37 balrog
93 adb86c37 balrog
static const struct wm_rate_s wm_rate_table[] = {
94 adb86c37 balrog
    {  256, 48000,  256, 48000 },        /* SR: 00000 */
95 adb86c37 balrog
    {  384, 48000,  384, 48000 },        /* SR: 00001 */
96 adb86c37 balrog
    {  256, 48000, 1536,  8000 },        /* SR: 00010 */
97 adb86c37 balrog
    {  384, 48000, 2304,  8000 },        /* SR: 00011 */
98 adb86c37 balrog
    { 1536,  8000,  256, 48000 },        /* SR: 00100 */
99 adb86c37 balrog
    { 2304,  8000,  384, 48000 },        /* SR: 00101 */
100 adb86c37 balrog
    { 1536,  8000, 1536,  8000 },        /* SR: 00110 */
101 adb86c37 balrog
    { 2304,  8000, 2304,  8000 },        /* SR: 00111 */
102 adb86c37 balrog
    { 1024, 12000, 1024, 12000 },        /* SR: 01000 */
103 adb86c37 balrog
    { 1526, 12000, 1536, 12000 },        /* SR: 01001 */
104 adb86c37 balrog
    {  768, 16000,  768, 16000 },        /* SR: 01010 */
105 adb86c37 balrog
    { 1152, 16000, 1152, 16000 },        /* SR: 01011 */
106 adb86c37 balrog
    {  384, 32000,  384, 32000 },        /* SR: 01100 */
107 adb86c37 balrog
    {  576, 32000,  576, 32000 },        /* SR: 01101 */
108 adb86c37 balrog
    {  128, 96000,  128, 96000 },        /* SR: 01110 */
109 adb86c37 balrog
    {  192, 96000,  192, 96000 },        /* SR: 01111 */
110 adb86c37 balrog
    {  256, 44100,  256, 44100 },        /* SR: 10000 */
111 adb86c37 balrog
    {  384, 44100,  384, 44100 },        /* SR: 10001 */
112 adb86c37 balrog
    {  256, 44100, 1408,  8018 },        /* SR: 10010 */
113 adb86c37 balrog
    {  384, 44100, 2112,  8018 },        /* SR: 10011 */
114 adb86c37 balrog
    { 1408,  8018,  256, 44100 },        /* SR: 10100 */
115 adb86c37 balrog
    { 2112,  8018,  384, 44100 },        /* SR: 10101 */
116 adb86c37 balrog
    { 1408,  8018, 1408,  8018 },        /* SR: 10110 */
117 adb86c37 balrog
    { 2112,  8018, 2112,  8018 },        /* SR: 10111 */
118 adb86c37 balrog
    { 1024, 11025, 1024, 11025 },        /* SR: 11000 */
119 adb86c37 balrog
    { 1536, 11025, 1536, 11025 },        /* SR: 11001 */
120 adb86c37 balrog
    {  512, 22050,  512, 22050 },        /* SR: 11010 */
121 adb86c37 balrog
    {  768, 22050,  768, 22050 },        /* SR: 11011 */
122 adb86c37 balrog
    {  512, 24000,  512, 24000 },        /* SR: 11100 */
123 adb86c37 balrog
    {  768, 24000,  768, 24000 },        /* SR: 11101 */
124 adb86c37 balrog
    {  128, 88200,  128, 88200 },        /* SR: 11110 */
125 523111e7 balrog
    {  192, 88200,  192, 88200 },        /* SR: 11111 */
126 adb86c37 balrog
};
127 adb86c37 balrog
128 9596ebb7 pbrook
static void wm8750_set_format(struct wm8750_s *s)
129 adb86c37 balrog
{
130 adb86c37 balrog
    int i;
131 adb86c37 balrog
    audsettings_t in_fmt;
132 adb86c37 balrog
    audsettings_t out_fmt;
133 adb86c37 balrog
    audsettings_t monoout_fmt;
134 adb86c37 balrog
135 adb86c37 balrog
    wm8750_out_flush(s);
136 adb86c37 balrog
137 adb86c37 balrog
    if (s->in[0] && *s->in[0])
138 adb86c37 balrog
        AUD_set_active_in(*s->in[0], 0);
139 adb86c37 balrog
    if (s->out[0] && *s->out[0])
140 adb86c37 balrog
        AUD_set_active_out(*s->out[0], 0);
141 adb86c37 balrog
142 adb86c37 balrog
    for (i = 0; i < IN_PORT_N; i ++)
143 adb86c37 balrog
        if (s->adc_voice[i]) {
144 adb86c37 balrog
            AUD_close_in(&s->card, s->adc_voice[i]);
145 adb86c37 balrog
            s->adc_voice[i] = 0;
146 adb86c37 balrog
        }
147 adb86c37 balrog
    for (i = 0; i < OUT_PORT_N; i ++)
148 adb86c37 balrog
        if (s->dac_voice[i]) {
149 adb86c37 balrog
            AUD_close_out(&s->card, s->dac_voice[i]);
150 adb86c37 balrog
            s->dac_voice[i] = 0;
151 adb86c37 balrog
        }
152 adb86c37 balrog
153 adb86c37 balrog
    if (!s->enable)
154 adb86c37 balrog
        return;
155 adb86c37 balrog
156 adb86c37 balrog
    /* Setup input */
157 adb86c37 balrog
    in_fmt.endianness = 0;
158 adb86c37 balrog
    in_fmt.nchannels = 2;
159 adb86c37 balrog
    in_fmt.freq = s->rate->adc_hz;
160 adb86c37 balrog
    in_fmt.fmt = AUD_FMT_S16;
161 adb86c37 balrog
162 adb86c37 balrog
    s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
163 adb86c37 balrog
                    CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
164 adb86c37 balrog
    s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
165 adb86c37 balrog
                    CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
166 adb86c37 balrog
    s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
167 adb86c37 balrog
                    CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
168 adb86c37 balrog
169 adb86c37 balrog
    /* Setup output */
170 adb86c37 balrog
    out_fmt.endianness = 0;
171 adb86c37 balrog
    out_fmt.nchannels = 2;
172 adb86c37 balrog
    out_fmt.freq = s->rate->dac_hz;
173 adb86c37 balrog
    out_fmt.fmt = AUD_FMT_S16;
174 adb86c37 balrog
    monoout_fmt.endianness = 0;
175 adb86c37 balrog
    monoout_fmt.nchannels = 1;
176 adb86c37 balrog
    monoout_fmt.freq = s->rate->dac_hz;
177 adb86c37 balrog
    monoout_fmt.fmt = AUD_FMT_S16;
178 adb86c37 balrog
179 adb86c37 balrog
    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
180 adb86c37 balrog
                    CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
181 adb86c37 balrog
    s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
182 adb86c37 balrog
                    CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
183 adb86c37 balrog
    /* MONOMIX is also in stereo for simplicity */
184 adb86c37 balrog
    s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
185 adb86c37 balrog
                    CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
186 adb86c37 balrog
    /* no sense emulating OUT3 which is a mix of other outputs */
187 adb86c37 balrog
188 adb86c37 balrog
    /* We should connect the left and right channels to their
189 adb86c37 balrog
     * respective inputs/outputs but we have completely no need
190 adb86c37 balrog
     * for mixing or combining paths to different ports, so we
191 adb86c37 balrog
     * connect both channels to where the left channel is routed.  */
192 adb86c37 balrog
    if (s->in[0] && *s->in[0])
193 adb86c37 balrog
        AUD_set_active_in(*s->in[0], 1);
194 adb86c37 balrog
    if (s->out[0] && *s->out[0])
195 adb86c37 balrog
        AUD_set_active_out(*s->out[0], 1);
196 adb86c37 balrog
}
197 adb86c37 balrog
198 9596ebb7 pbrook
static void inline wm8750_mask_update(struct wm8750_s *s)
199 adb86c37 balrog
{
200 adb86c37 balrog
#define R_ONLY        0x0000ffff
201 adb86c37 balrog
#define L_ONLY        0xffff0000
202 adb86c37 balrog
#define BOTH        (R_ONLY | L_ONLY)
203 adb86c37 balrog
#define NONE        (R_ONLY & L_ONLY)
204 adb86c37 balrog
    s->inmask =
205 adb86c37 balrog
            (s->inmute[0] ? R_ONLY : BOTH) &
206 adb86c37 balrog
            (s->inmute[1] ? L_ONLY : BOTH) &
207 adb86c37 balrog
            (s->mute ? NONE : BOTH);
208 adb86c37 balrog
    s->outmask =
209 adb86c37 balrog
            (s->outmute[0] ? R_ONLY : BOTH) &
210 adb86c37 balrog
            (s->outmute[1] ? L_ONLY : BOTH) &
211 adb86c37 balrog
            (s->mute ? NONE : BOTH);
212 adb86c37 balrog
}
213 adb86c37 balrog
214 adb86c37 balrog
void wm8750_reset(i2c_slave *i2c)
215 adb86c37 balrog
{
216 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) i2c;
217 eb69b50a balrog
    s->rate = &wm_rate_table[0];
218 adb86c37 balrog
    s->enable = 0;
219 adb86c37 balrog
    wm8750_set_format(s);
220 adb86c37 balrog
    s->diff[0] = 0;
221 adb86c37 balrog
    s->diff[1] = 0;
222 adb86c37 balrog
    s->ds = 0;
223 adb86c37 balrog
    s->alc = 0;
224 adb86c37 balrog
    s->in[0] = &s->adc_voice[0];
225 adb86c37 balrog
    s->invol[0] = 0x17;
226 adb86c37 balrog
    s->invol[1] = 0x17;
227 adb86c37 balrog
    s->invol[2] = 0xc3;
228 adb86c37 balrog
    s->invol[3] = 0xc3;
229 adb86c37 balrog
    s->out[0] = &s->dac_voice[0];
230 adb86c37 balrog
    s->outvol[0] = 0xff;
231 adb86c37 balrog
    s->outvol[1] = 0xff;
232 adb86c37 balrog
    s->outvol[2] = 0x79;
233 adb86c37 balrog
    s->outvol[3] = 0x79;
234 adb86c37 balrog
    s->outvol[4] = 0x79;
235 adb86c37 balrog
    s->outvol[5] = 0x79;
236 adb86c37 balrog
    s->inmute[0] = 0;
237 adb86c37 balrog
    s->inmute[1] = 0;
238 adb86c37 balrog
    s->outmute[0] = 0;
239 adb86c37 balrog
    s->outmute[1] = 0;
240 adb86c37 balrog
    s->mute = 1;
241 adb86c37 balrog
    s->path[0] = 0;
242 adb86c37 balrog
    s->path[1] = 0;
243 adb86c37 balrog
    s->path[2] = 0;
244 adb86c37 balrog
    s->path[3] = 0;
245 adb86c37 balrog
    s->mpath[0] = 0;
246 adb86c37 balrog
    s->mpath[1] = 0;
247 adb86c37 balrog
    s->format = 0x0a;
248 adb86c37 balrog
    s->idx_in = sizeof(s->data_in);
249 adb86c37 balrog
    s->req_in = 0;
250 adb86c37 balrog
    s->idx_out = 0;
251 adb86c37 balrog
    s->req_out = 0;
252 adb86c37 balrog
    wm8750_mask_update(s);
253 adb86c37 balrog
    s->i2c_len = 0;
254 adb86c37 balrog
}
255 adb86c37 balrog
256 adb86c37 balrog
static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
257 adb86c37 balrog
{
258 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) i2c;
259 adb86c37 balrog
260 adb86c37 balrog
    switch (event) {
261 adb86c37 balrog
    case I2C_START_SEND:
262 adb86c37 balrog
        s->i2c_len = 0;
263 adb86c37 balrog
        break;
264 adb86c37 balrog
    case I2C_FINISH:
265 adb86c37 balrog
#ifdef VERBOSE
266 adb86c37 balrog
        if (s->i2c_len < 2)
267 adb86c37 balrog
            printf("%s: message too short (%i bytes)\n",
268 adb86c37 balrog
                            __FUNCTION__, s->i2c_len);
269 adb86c37 balrog
#endif
270 adb86c37 balrog
        break;
271 adb86c37 balrog
    default:
272 adb86c37 balrog
        break;
273 adb86c37 balrog
    }
274 adb86c37 balrog
}
275 adb86c37 balrog
276 adb86c37 balrog
#define WM8750_LINVOL        0x00
277 adb86c37 balrog
#define WM8750_RINVOL        0x01
278 adb86c37 balrog
#define WM8750_LOUT1V        0x02
279 adb86c37 balrog
#define WM8750_ROUT1V        0x03
280 adb86c37 balrog
#define WM8750_ADCDAC        0x05
281 adb86c37 balrog
#define WM8750_IFACE        0x07
282 adb86c37 balrog
#define WM8750_SRATE        0x08
283 adb86c37 balrog
#define WM8750_LDAC        0x0a
284 adb86c37 balrog
#define WM8750_RDAC        0x0b
285 adb86c37 balrog
#define WM8750_BASS        0x0c
286 adb86c37 balrog
#define WM8750_TREBLE        0x0d
287 adb86c37 balrog
#define WM8750_RESET        0x0f
288 adb86c37 balrog
#define WM8750_3D        0x10
289 adb86c37 balrog
#define WM8750_ALC1        0x11
290 adb86c37 balrog
#define WM8750_ALC2        0x12
291 adb86c37 balrog
#define WM8750_ALC3        0x13
292 adb86c37 balrog
#define WM8750_NGATE        0x14
293 adb86c37 balrog
#define WM8750_LADC        0x15
294 adb86c37 balrog
#define WM8750_RADC        0x16
295 adb86c37 balrog
#define WM8750_ADCTL1        0x17
296 adb86c37 balrog
#define WM8750_ADCTL2        0x18
297 adb86c37 balrog
#define WM8750_PWR1        0x19
298 adb86c37 balrog
#define WM8750_PWR2        0x1a
299 adb86c37 balrog
#define WM8750_ADCTL3        0x1b
300 adb86c37 balrog
#define WM8750_ADCIN        0x1f
301 adb86c37 balrog
#define WM8750_LADCIN        0x20
302 adb86c37 balrog
#define WM8750_RADCIN        0x21
303 adb86c37 balrog
#define WM8750_LOUTM1        0x22
304 adb86c37 balrog
#define WM8750_LOUTM2        0x23
305 adb86c37 balrog
#define WM8750_ROUTM1        0x24
306 adb86c37 balrog
#define WM8750_ROUTM2        0x25
307 adb86c37 balrog
#define WM8750_MOUTM1        0x26
308 adb86c37 balrog
#define WM8750_MOUTM2        0x27
309 adb86c37 balrog
#define WM8750_LOUT2V        0x28
310 adb86c37 balrog
#define WM8750_ROUT2V        0x29
311 adb86c37 balrog
#define WM8750_MOUTV        0x2a
312 adb86c37 balrog
313 adb86c37 balrog
static int wm8750_tx(i2c_slave *i2c, uint8_t data)
314 adb86c37 balrog
{
315 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) i2c;
316 adb86c37 balrog
    uint8_t cmd;
317 adb86c37 balrog
    uint16_t value;
318 adb86c37 balrog
319 adb86c37 balrog
    if (s->i2c_len >= 2) {
320 adb86c37 balrog
        printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
321 adb86c37 balrog
#ifdef VERBOSE
322 adb86c37 balrog
        return 1;
323 adb86c37 balrog
#endif
324 adb86c37 balrog
    }
325 adb86c37 balrog
    s->i2c_data[s->i2c_len ++] = data;
326 adb86c37 balrog
    if (s->i2c_len != 2)
327 adb86c37 balrog
        return 0;
328 adb86c37 balrog
329 adb86c37 balrog
    cmd = s->i2c_data[0] >> 1;
330 adb86c37 balrog
    value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
331 adb86c37 balrog
332 adb86c37 balrog
    switch (cmd) {
333 adb86c37 balrog
    case WM8750_LADCIN:        /* ADC Signal Path Control (Left) */
334 adb86c37 balrog
        s->diff[0] = (((value >> 6) & 3) == 3);        /* LINSEL */
335 adb86c37 balrog
        if (s->diff[0])
336 adb86c37 balrog
            s->in[0] = &s->adc_voice[0 + s->ds * 1];
337 adb86c37 balrog
        else
338 adb86c37 balrog
            s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
339 adb86c37 balrog
        break;
340 adb86c37 balrog
341 adb86c37 balrog
    case WM8750_RADCIN:        /* ADC Signal Path Control (Right) */
342 adb86c37 balrog
        s->diff[1] = (((value >> 6) & 3) == 3);        /* RINSEL */
343 adb86c37 balrog
        if (s->diff[1])
344 adb86c37 balrog
            s->in[1] = &s->adc_voice[0 + s->ds * 1];
345 adb86c37 balrog
        else
346 adb86c37 balrog
            s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
347 adb86c37 balrog
        break;
348 adb86c37 balrog
349 adb86c37 balrog
    case WM8750_ADCIN:        /* ADC Input Mode */
350 adb86c37 balrog
        s->ds = (value >> 8) & 1;        /* DS */
351 adb86c37 balrog
        if (s->diff[0])
352 adb86c37 balrog
            s->in[0] = &s->adc_voice[0 + s->ds * 1];
353 adb86c37 balrog
        if (s->diff[1])
354 adb86c37 balrog
            s->in[1] = &s->adc_voice[0 + s->ds * 1];
355 adb86c37 balrog
        s->monomix[0] = (value >> 6) & 3;        /* MONOMIX */
356 adb86c37 balrog
        break;
357 adb86c37 balrog
358 adb86c37 balrog
    case WM8750_ADCTL1:        /* Additional Control (1) */
359 adb86c37 balrog
        s->monomix[1] = (value >> 1) & 1;        /* DMONOMIX */
360 adb86c37 balrog
        break;
361 adb86c37 balrog
362 adb86c37 balrog
    case WM8750_PWR1:        /* Power Management (1) */
363 adb86c37 balrog
        s->enable = ((value >> 6) & 7) == 3;        /* VMIDSEL, VREF */
364 adb86c37 balrog
        wm8750_set_format(s);
365 adb86c37 balrog
        break;
366 adb86c37 balrog
367 adb86c37 balrog
    case WM8750_LINVOL:        /* Left Channel PGA */
368 adb86c37 balrog
        s->invol[0] = value & 0x3f;                /* LINVOL */
369 adb86c37 balrog
        s->inmute[0] = (value >> 7) & 1;        /* LINMUTE */
370 adb86c37 balrog
        wm8750_mask_update(s);
371 adb86c37 balrog
        break;
372 adb86c37 balrog
373 adb86c37 balrog
    case WM8750_RINVOL:        /* Right Channel PGA */
374 adb86c37 balrog
        s->invol[1] = value & 0x3f;                /* RINVOL */
375 adb86c37 balrog
        s->inmute[1] = (value >> 7) & 1;        /* RINMUTE */
376 adb86c37 balrog
        wm8750_mask_update(s);
377 adb86c37 balrog
        break;
378 adb86c37 balrog
379 adb86c37 balrog
    case WM8750_ADCDAC:        /* ADC and DAC Control */
380 adb86c37 balrog
        s->pol = (value >> 5) & 3;                /* ADCPOL */
381 adb86c37 balrog
        s->mute = (value >> 3) & 1;                /* DACMU */
382 adb86c37 balrog
        wm8750_mask_update(s);
383 adb86c37 balrog
        break;
384 adb86c37 balrog
385 adb86c37 balrog
    case WM8750_ADCTL3:        /* Additional Control (3) */
386 adb86c37 balrog
        break;
387 adb86c37 balrog
388 adb86c37 balrog
    case WM8750_LADC:        /* Left ADC Digital Volume */
389 adb86c37 balrog
        s->invol[2] = value & 0xff;                /* LADCVOL */
390 adb86c37 balrog
        break;
391 adb86c37 balrog
392 adb86c37 balrog
    case WM8750_RADC:        /* Right ADC Digital Volume */
393 adb86c37 balrog
        s->invol[3] = value & 0xff;                /* RADCVOL */
394 adb86c37 balrog
        break;
395 adb86c37 balrog
396 adb86c37 balrog
    case WM8750_ALC1:        /* ALC Control (1) */
397 adb86c37 balrog
        s->alc = (value >> 7) & 3;                /* ALCSEL */
398 adb86c37 balrog
        break;
399 adb86c37 balrog
400 adb86c37 balrog
    case WM8750_NGATE:        /* Noise Gate Control */
401 adb86c37 balrog
    case WM8750_3D:        /* 3D enhance */
402 adb86c37 balrog
        break;
403 adb86c37 balrog
404 adb86c37 balrog
    case WM8750_LDAC:        /* Left Channel Digital Volume */
405 adb86c37 balrog
        s->outvol[0] = value & 0xff;                /* LDACVOL */
406 adb86c37 balrog
        break;
407 adb86c37 balrog
408 adb86c37 balrog
    case WM8750_RDAC:        /* Right Channel Digital Volume */
409 adb86c37 balrog
        s->outvol[1] = value & 0xff;                /* RDACVOL */
410 adb86c37 balrog
        break;
411 adb86c37 balrog
412 adb86c37 balrog
    case WM8750_BASS:        /* Bass Control */
413 adb86c37 balrog
        break;
414 adb86c37 balrog
415 adb86c37 balrog
    case WM8750_LOUTM1:        /* Left Mixer Control (1) */
416 adb86c37 balrog
        s->path[0] = (value >> 8) & 1;                /* LD2LO */
417 adb86c37 balrog
        break;
418 adb86c37 balrog
419 adb86c37 balrog
    case WM8750_LOUTM2:        /* Left Mixer Control (2) */
420 adb86c37 balrog
        s->path[1] = (value >> 8) & 1;                /* RD2LO */
421 adb86c37 balrog
        break;
422 adb86c37 balrog
423 adb86c37 balrog
    case WM8750_ROUTM1:        /* Right Mixer Control (1) */
424 adb86c37 balrog
        s->path[2] = (value >> 8) & 1;                /* LD2RO */
425 adb86c37 balrog
        break;
426 adb86c37 balrog
427 adb86c37 balrog
    case WM8750_ROUTM2:        /* Right Mixer Control (2) */
428 adb86c37 balrog
        s->path[3] = (value >> 8) & 1;                /* RD2RO */
429 adb86c37 balrog
        break;
430 adb86c37 balrog
431 adb86c37 balrog
    case WM8750_MOUTM1:        /* Mono Mixer Control (1) */
432 adb86c37 balrog
        s->mpath[0] = (value >> 8) & 1;                /* LD2MO */
433 adb86c37 balrog
        break;
434 adb86c37 balrog
435 adb86c37 balrog
    case WM8750_MOUTM2:        /* Mono Mixer Control (2) */
436 adb86c37 balrog
        s->mpath[1] = (value >> 8) & 1;                /* RD2MO */
437 adb86c37 balrog
        break;
438 adb86c37 balrog
439 adb86c37 balrog
    case WM8750_LOUT1V:        /* LOUT1 Volume */
440 adb86c37 balrog
        s->outvol[2] = value & 0x7f;                /* LOUT2VOL */
441 adb86c37 balrog
        break;
442 adb86c37 balrog
443 adb86c37 balrog
    case WM8750_LOUT2V:        /* LOUT2 Volume */
444 adb86c37 balrog
        s->outvol[4] = value & 0x7f;                /* LOUT2VOL */
445 adb86c37 balrog
        break;
446 adb86c37 balrog
447 adb86c37 balrog
    case WM8750_ROUT1V:        /* ROUT1 Volume */
448 adb86c37 balrog
        s->outvol[3] = value & 0x7f;                /* ROUT2VOL */
449 adb86c37 balrog
        break;
450 adb86c37 balrog
451 adb86c37 balrog
    case WM8750_ROUT2V:        /* ROUT2 Volume */
452 adb86c37 balrog
        s->outvol[5] = value & 0x7f;                /* ROUT2VOL */
453 adb86c37 balrog
        break;
454 adb86c37 balrog
455 adb86c37 balrog
    case WM8750_MOUTV:        /* MONOOUT Volume */
456 adb86c37 balrog
        s->outvol[6] = value & 0x7f;                /* MONOOUTVOL */
457 adb86c37 balrog
        break;
458 adb86c37 balrog
459 adb86c37 balrog
    case WM8750_ADCTL2:        /* Additional Control (2) */
460 adb86c37 balrog
        break;
461 adb86c37 balrog
462 adb86c37 balrog
    case WM8750_PWR2:        /* Power Management (2) */
463 adb86c37 balrog
        s->power = value & 0x7e;
464 adb86c37 balrog
        break;
465 adb86c37 balrog
466 adb86c37 balrog
    case WM8750_IFACE:        /* Digital Audio Interface Format */
467 adb86c37 balrog
#ifdef VERBOSE
468 adb86c37 balrog
        if (value & 0x40)                        /* MS */
469 adb86c37 balrog
            printf("%s: attempt to enable Master Mode\n", __FUNCTION__);
470 adb86c37 balrog
#endif
471 adb86c37 balrog
        s->format = value;
472 adb86c37 balrog
        wm8750_set_format(s);
473 adb86c37 balrog
        break;
474 adb86c37 balrog
475 adb86c37 balrog
    case WM8750_SRATE:        /* Clocking and Sample Rate Control */
476 adb86c37 balrog
        s->rate = &wm_rate_table[(value >> 1) & 0x1f];
477 adb86c37 balrog
        wm8750_set_format(s);
478 adb86c37 balrog
        break;
479 adb86c37 balrog
480 adb86c37 balrog
    case WM8750_RESET:        /* Reset */
481 adb86c37 balrog
        wm8750_reset(&s->i2c);
482 adb86c37 balrog
        break;
483 adb86c37 balrog
484 adb86c37 balrog
#ifdef VERBOSE
485 adb86c37 balrog
    default:
486 adb86c37 balrog
        printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
487 adb86c37 balrog
#endif
488 adb86c37 balrog
    }
489 adb86c37 balrog
490 adb86c37 balrog
    return 0;
491 adb86c37 balrog
}
492 adb86c37 balrog
493 adb86c37 balrog
static int wm8750_rx(i2c_slave *i2c)
494 adb86c37 balrog
{
495 adb86c37 balrog
    return 0x00;
496 adb86c37 balrog
}
497 adb86c37 balrog
498 aa941b94 balrog
static void wm8750_save(QEMUFile *f, void *opaque)
499 aa941b94 balrog
{
500 aa941b94 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
501 aa941b94 balrog
    int i;
502 aa941b94 balrog
    qemu_put_8s(f, &s->i2c_data[0]);
503 aa941b94 balrog
    qemu_put_8s(f, &s->i2c_data[1]);
504 aa941b94 balrog
    qemu_put_be32(f, s->i2c_len);
505 aa941b94 balrog
    qemu_put_be32(f, s->enable);
506 aa941b94 balrog
    qemu_put_be32(f, s->idx_in);
507 aa941b94 balrog
    qemu_put_be32(f, s->req_in);
508 aa941b94 balrog
    qemu_put_be32(f, s->idx_out);
509 aa941b94 balrog
    qemu_put_be32(f, s->req_out);
510 aa941b94 balrog
511 aa941b94 balrog
    for (i = 0; i < 7; i ++)
512 aa941b94 balrog
        qemu_put_8s(f, &s->outvol[i]);
513 aa941b94 balrog
    for (i = 0; i < 2; i ++)
514 aa941b94 balrog
        qemu_put_8s(f, &s->outmute[i]);
515 aa941b94 balrog
    for (i = 0; i < 4; i ++)
516 aa941b94 balrog
        qemu_put_8s(f, &s->invol[i]);
517 aa941b94 balrog
    for (i = 0; i < 2; i ++)
518 aa941b94 balrog
        qemu_put_8s(f, &s->inmute[i]);
519 aa941b94 balrog
520 aa941b94 balrog
    for (i = 0; i < 2; i ++)
521 aa941b94 balrog
        qemu_put_8s(f, &s->diff[i]);
522 aa941b94 balrog
    qemu_put_8s(f, &s->pol);
523 aa941b94 balrog
    qemu_put_8s(f, &s->ds);
524 aa941b94 balrog
    for (i = 0; i < 2; i ++)
525 aa941b94 balrog
        qemu_put_8s(f, &s->monomix[i]);
526 aa941b94 balrog
    qemu_put_8s(f, &s->alc);
527 aa941b94 balrog
    qemu_put_8s(f, &s->mute);
528 aa941b94 balrog
    for (i = 0; i < 4; i ++)
529 aa941b94 balrog
        qemu_put_8s(f, &s->path[i]);
530 aa941b94 balrog
    for (i = 0; i < 2; i ++)
531 aa941b94 balrog
        qemu_put_8s(f, &s->mpath[i]);
532 aa941b94 balrog
    qemu_put_8s(f, &s->format);
533 aa941b94 balrog
    qemu_put_8s(f, &s->power);
534 aa941b94 balrog
    qemu_put_be32s(f, &s->inmask);
535 aa941b94 balrog
    qemu_put_be32s(f, &s->outmask);
536 aa941b94 balrog
    qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
537 aa941b94 balrog
    i2c_slave_save(f, &s->i2c);
538 aa941b94 balrog
}
539 aa941b94 balrog
540 aa941b94 balrog
static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
541 aa941b94 balrog
{
542 aa941b94 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
543 aa941b94 balrog
    int i;
544 aa941b94 balrog
    qemu_get_8s(f, &s->i2c_data[0]);
545 aa941b94 balrog
    qemu_get_8s(f, &s->i2c_data[1]);
546 aa941b94 balrog
    s->i2c_len = qemu_get_be32(f);
547 aa941b94 balrog
    s->enable = qemu_get_be32(f);
548 aa941b94 balrog
    s->idx_in = qemu_get_be32(f);
549 aa941b94 balrog
    s->req_in = qemu_get_be32(f);
550 aa941b94 balrog
    s->idx_out = qemu_get_be32(f);
551 aa941b94 balrog
    s->req_out = qemu_get_be32(f);
552 aa941b94 balrog
553 aa941b94 balrog
    for (i = 0; i < 7; i ++)
554 aa941b94 balrog
        qemu_get_8s(f, &s->outvol[i]);
555 aa941b94 balrog
    for (i = 0; i < 2; i ++)
556 aa941b94 balrog
        qemu_get_8s(f, &s->outmute[i]);
557 aa941b94 balrog
    for (i = 0; i < 4; i ++)
558 aa941b94 balrog
        qemu_get_8s(f, &s->invol[i]);
559 aa941b94 balrog
    for (i = 0; i < 2; i ++)
560 aa941b94 balrog
        qemu_get_8s(f, &s->inmute[i]);
561 aa941b94 balrog
562 aa941b94 balrog
    for (i = 0; i < 2; i ++)
563 aa941b94 balrog
        qemu_get_8s(f, &s->diff[i]);
564 aa941b94 balrog
    qemu_get_8s(f, &s->pol);
565 aa941b94 balrog
    qemu_get_8s(f, &s->ds);
566 aa941b94 balrog
    for (i = 0; i < 2; i ++)
567 aa941b94 balrog
        qemu_get_8s(f, &s->monomix[i]);
568 aa941b94 balrog
    qemu_get_8s(f, &s->alc);
569 aa941b94 balrog
    qemu_get_8s(f, &s->mute);
570 aa941b94 balrog
    for (i = 0; i < 4; i ++)
571 aa941b94 balrog
        qemu_get_8s(f, &s->path[i]);
572 aa941b94 balrog
    for (i = 0; i < 2; i ++)
573 aa941b94 balrog
        qemu_get_8s(f, &s->mpath[i]);
574 aa941b94 balrog
    qemu_get_8s(f, &s->format);
575 aa941b94 balrog
    qemu_get_8s(f, &s->power);
576 aa941b94 balrog
    qemu_get_be32s(f, &s->inmask);
577 aa941b94 balrog
    qemu_get_be32s(f, &s->outmask);
578 aa941b94 balrog
    s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
579 aa941b94 balrog
    i2c_slave_load(f, &s->i2c);
580 aa941b94 balrog
    return 0;
581 aa941b94 balrog
}
582 aa941b94 balrog
583 aa941b94 balrog
static int wm8750_iid = 0;
584 aa941b94 balrog
585 adb86c37 balrog
i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
586 adb86c37 balrog
{
587 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *)
588 adb86c37 balrog
            i2c_slave_init(bus, 0, sizeof(struct wm8750_s));
589 adb86c37 balrog
    s->i2c.event = wm8750_event;
590 adb86c37 balrog
    s->i2c.recv = wm8750_rx;
591 adb86c37 balrog
    s->i2c.send = wm8750_tx;
592 adb86c37 balrog
593 adb86c37 balrog
    AUD_register_card(audio, CODEC, &s->card);
594 adb86c37 balrog
    wm8750_reset(&s->i2c);
595 adb86c37 balrog
596 aa941b94 balrog
    register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s);
597 aa941b94 balrog
598 adb86c37 balrog
    return &s->i2c;
599 adb86c37 balrog
}
600 adb86c37 balrog
601 523111e7 balrog
#if 0
602 9596ebb7 pbrook
static void wm8750_fini(i2c_slave *i2c)
603 adb86c37 balrog
{
604 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) i2c;
605 adb86c37 balrog
    wm8750_reset(&s->i2c);
606 adb86c37 balrog
    AUD_remove_card(&s->card);
607 adb86c37 balrog
    qemu_free(s);
608 adb86c37 balrog
}
609 523111e7 balrog
#endif
610 adb86c37 balrog
611 adb86c37 balrog
void wm8750_data_req_set(i2c_slave *i2c,
612 adb86c37 balrog
                void (*data_req)(void *, int, int), void *opaque)
613 adb86c37 balrog
{
614 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) i2c;
615 adb86c37 balrog
    s->data_req = data_req;
616 adb86c37 balrog
    s->opaque = opaque;
617 adb86c37 balrog
}
618 adb86c37 balrog
619 adb86c37 balrog
void wm8750_dac_dat(void *opaque, uint32_t sample)
620 adb86c37 balrog
{
621 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
622 adb86c37 balrog
    uint32_t *data = (uint32_t *) &s->data_out[s->idx_out];
623 adb86c37 balrog
    *data = sample & s->outmask;
624 adb86c37 balrog
    s->req_out -= 4;
625 adb86c37 balrog
    s->idx_out += 4;
626 adb86c37 balrog
    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
627 adb86c37 balrog
        wm8750_out_flush(s);
628 adb86c37 balrog
}
629 adb86c37 balrog
630 662caa6f balrog
void *wm8750_dac_buffer(void *opaque, int samples)
631 662caa6f balrog
{
632 662caa6f balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
633 662caa6f balrog
    /* XXX: Should check if there are <i>samples</i> free samples available */
634 662caa6f balrog
    void *ret = s->data_out + s->idx_out;
635 662caa6f balrog
636 662caa6f balrog
    s->idx_out += samples << 2;
637 662caa6f balrog
    s->req_out -= samples << 2;
638 662caa6f balrog
    return ret;
639 662caa6f balrog
}
640 662caa6f balrog
641 662caa6f balrog
void wm8750_dac_commit(void *opaque)
642 662caa6f balrog
{
643 662caa6f balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
644 662caa6f balrog
645 662caa6f balrog
    return wm8750_out_flush(s);
646 662caa6f balrog
}
647 662caa6f balrog
648 adb86c37 balrog
uint32_t wm8750_adc_dat(void *opaque)
649 adb86c37 balrog
{
650 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
651 adb86c37 balrog
    uint32_t *data;
652 adb86c37 balrog
    if (s->idx_in >= sizeof(s->data_in))
653 adb86c37 balrog
        wm8750_in_load(s);
654 adb86c37 balrog
    data = (uint32_t *) &s->data_in[s->idx_in];
655 adb86c37 balrog
    s->req_in -= 4;
656 adb86c37 balrog
    s->idx_in += 4;
657 adb86c37 balrog
    return *data & s->inmask;
658 adb86c37 balrog
}