Statistics
| Branch: | Revision:

root / hw / audio / wm8750.c @ a8aec295

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