Statistics
| Branch: | Revision:

root / hw / wm8750.c @ 1237ad76

History | View | Annotate | Download (20.3 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 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 adb86c37 balrog
    i2c_slave 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 1ea879e5 malc
    struct audsettings monoout_fmt;
175 adb86c37 balrog
176 adb86c37 balrog
    wm8750_out_flush(s);
177 adb86c37 balrog
178 adb86c37 balrog
    if (s->in[0] && *s->in[0])
179 adb86c37 balrog
        AUD_set_active_in(*s->in[0], 0);
180 adb86c37 balrog
    if (s->out[0] && *s->out[0])
181 adb86c37 balrog
        AUD_set_active_out(*s->out[0], 0);
182 adb86c37 balrog
183 adb86c37 balrog
    for (i = 0; i < IN_PORT_N; i ++)
184 adb86c37 balrog
        if (s->adc_voice[i]) {
185 adb86c37 balrog
            AUD_close_in(&s->card, s->adc_voice[i]);
186 511d2b14 blueswir1
            s->adc_voice[i] = NULL;
187 adb86c37 balrog
        }
188 adb86c37 balrog
    for (i = 0; i < OUT_PORT_N; i ++)
189 adb86c37 balrog
        if (s->dac_voice[i]) {
190 adb86c37 balrog
            AUD_close_out(&s->card, s->dac_voice[i]);
191 511d2b14 blueswir1
            s->dac_voice[i] = NULL;
192 adb86c37 balrog
        }
193 adb86c37 balrog
194 adb86c37 balrog
    if (!s->enable)
195 adb86c37 balrog
        return;
196 adb86c37 balrog
197 adb86c37 balrog
    /* Setup input */
198 adb86c37 balrog
    in_fmt.endianness = 0;
199 adb86c37 balrog
    in_fmt.nchannels = 2;
200 af83e09e balrog
    in_fmt.freq = s->adc_hz;
201 adb86c37 balrog
    in_fmt.fmt = AUD_FMT_S16;
202 adb86c37 balrog
203 adb86c37 balrog
    s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
204 adb86c37 balrog
                    CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
205 adb86c37 balrog
    s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
206 adb86c37 balrog
                    CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
207 adb86c37 balrog
    s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
208 adb86c37 balrog
                    CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
209 adb86c37 balrog
210 adb86c37 balrog
    /* Setup output */
211 adb86c37 balrog
    out_fmt.endianness = 0;
212 adb86c37 balrog
    out_fmt.nchannels = 2;
213 af83e09e balrog
    out_fmt.freq = s->dac_hz;
214 adb86c37 balrog
    out_fmt.fmt = AUD_FMT_S16;
215 adb86c37 balrog
    monoout_fmt.endianness = 0;
216 adb86c37 balrog
    monoout_fmt.nchannels = 1;
217 adb86c37 balrog
    monoout_fmt.freq = s->rate->dac_hz;
218 adb86c37 balrog
    monoout_fmt.fmt = AUD_FMT_S16;
219 adb86c37 balrog
220 adb86c37 balrog
    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
221 adb86c37 balrog
                    CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
222 adb86c37 balrog
    s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
223 adb86c37 balrog
                    CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
224 adb86c37 balrog
    /* MONOMIX is also in stereo for simplicity */
225 adb86c37 balrog
    s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
226 adb86c37 balrog
                    CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
227 adb86c37 balrog
    /* no sense emulating OUT3 which is a mix of other outputs */
228 adb86c37 balrog
229 683efdcb balrog
    wm8750_vol_update(s);
230 683efdcb balrog
231 adb86c37 balrog
    /* We should connect the left and right channels to their
232 adb86c37 balrog
     * respective inputs/outputs but we have completely no need
233 adb86c37 balrog
     * for mixing or combining paths to different ports, so we
234 adb86c37 balrog
     * connect both channels to where the left channel is routed.  */
235 adb86c37 balrog
    if (s->in[0] && *s->in[0])
236 adb86c37 balrog
        AUD_set_active_in(*s->in[0], 1);
237 adb86c37 balrog
    if (s->out[0] && *s->out[0])
238 adb86c37 balrog
        AUD_set_active_out(*s->out[0], 1);
239 adb86c37 balrog
}
240 adb86c37 balrog
241 bc24a225 Paul Brook
static void wm8750_clk_update(WM8750State *s, int ext)
242 af83e09e balrog
{
243 af83e09e balrog
    if (s->master || !s->ext_dac_hz)
244 af83e09e balrog
        s->dac_hz = s->rate->dac_hz;
245 af83e09e balrog
    else
246 af83e09e balrog
        s->dac_hz = s->ext_dac_hz;
247 af83e09e balrog
248 af83e09e balrog
    if (s->master || !s->ext_adc_hz)
249 af83e09e balrog
        s->adc_hz = s->rate->adc_hz;
250 af83e09e balrog
    else
251 af83e09e balrog
        s->adc_hz = s->ext_adc_hz;
252 af83e09e balrog
253 af83e09e balrog
    if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) {
254 af83e09e balrog
        if (!ext)
255 af83e09e balrog
            wm8750_set_format(s);
256 af83e09e balrog
    } else {
257 af83e09e balrog
        if (ext)
258 af83e09e balrog
            wm8750_set_format(s);
259 af83e09e balrog
    }
260 af83e09e balrog
}
261 af83e09e balrog
262 cdbe40ca Paul Brook
static void wm8750_reset(i2c_slave *i2c)
263 adb86c37 balrog
{
264 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) i2c;
265 eb69b50a balrog
    s->rate = &wm_rate_table[0];
266 adb86c37 balrog
    s->enable = 0;
267 af83e09e balrog
    wm8750_clk_update(s, 1);
268 adb86c37 balrog
    s->diff[0] = 0;
269 adb86c37 balrog
    s->diff[1] = 0;
270 adb86c37 balrog
    s->ds = 0;
271 adb86c37 balrog
    s->alc = 0;
272 adb86c37 balrog
    s->in[0] = &s->adc_voice[0];
273 adb86c37 balrog
    s->invol[0] = 0x17;
274 adb86c37 balrog
    s->invol[1] = 0x17;
275 adb86c37 balrog
    s->invol[2] = 0xc3;
276 adb86c37 balrog
    s->invol[3] = 0xc3;
277 adb86c37 balrog
    s->out[0] = &s->dac_voice[0];
278 adb86c37 balrog
    s->outvol[0] = 0xff;
279 adb86c37 balrog
    s->outvol[1] = 0xff;
280 adb86c37 balrog
    s->outvol[2] = 0x79;
281 adb86c37 balrog
    s->outvol[3] = 0x79;
282 adb86c37 balrog
    s->outvol[4] = 0x79;
283 adb86c37 balrog
    s->outvol[5] = 0x79;
284 db502b61 balrog
    s->outvol[6] = 0x79;
285 adb86c37 balrog
    s->inmute[0] = 0;
286 adb86c37 balrog
    s->inmute[1] = 0;
287 adb86c37 balrog
    s->outmute[0] = 0;
288 adb86c37 balrog
    s->outmute[1] = 0;
289 adb86c37 balrog
    s->mute = 1;
290 adb86c37 balrog
    s->path[0] = 0;
291 adb86c37 balrog
    s->path[1] = 0;
292 adb86c37 balrog
    s->path[2] = 0;
293 adb86c37 balrog
    s->path[3] = 0;
294 adb86c37 balrog
    s->mpath[0] = 0;
295 adb86c37 balrog
    s->mpath[1] = 0;
296 adb86c37 balrog
    s->format = 0x0a;
297 adb86c37 balrog
    s->idx_in = sizeof(s->data_in);
298 adb86c37 balrog
    s->req_in = 0;
299 adb86c37 balrog
    s->idx_out = 0;
300 adb86c37 balrog
    s->req_out = 0;
301 683efdcb balrog
    wm8750_vol_update(s);
302 adb86c37 balrog
    s->i2c_len = 0;
303 adb86c37 balrog
}
304 adb86c37 balrog
305 adb86c37 balrog
static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
306 adb86c37 balrog
{
307 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) i2c;
308 adb86c37 balrog
309 adb86c37 balrog
    switch (event) {
310 adb86c37 balrog
    case I2C_START_SEND:
311 adb86c37 balrog
        s->i2c_len = 0;
312 adb86c37 balrog
        break;
313 adb86c37 balrog
    case I2C_FINISH:
314 adb86c37 balrog
#ifdef VERBOSE
315 adb86c37 balrog
        if (s->i2c_len < 2)
316 adb86c37 balrog
            printf("%s: message too short (%i bytes)\n",
317 adb86c37 balrog
                            __FUNCTION__, s->i2c_len);
318 adb86c37 balrog
#endif
319 adb86c37 balrog
        break;
320 adb86c37 balrog
    default:
321 adb86c37 balrog
        break;
322 adb86c37 balrog
    }
323 adb86c37 balrog
}
324 adb86c37 balrog
325 adb86c37 balrog
#define WM8750_LINVOL        0x00
326 adb86c37 balrog
#define WM8750_RINVOL        0x01
327 adb86c37 balrog
#define WM8750_LOUT1V        0x02
328 adb86c37 balrog
#define WM8750_ROUT1V        0x03
329 adb86c37 balrog
#define WM8750_ADCDAC        0x05
330 adb86c37 balrog
#define WM8750_IFACE        0x07
331 adb86c37 balrog
#define WM8750_SRATE        0x08
332 adb86c37 balrog
#define WM8750_LDAC        0x0a
333 adb86c37 balrog
#define WM8750_RDAC        0x0b
334 adb86c37 balrog
#define WM8750_BASS        0x0c
335 adb86c37 balrog
#define WM8750_TREBLE        0x0d
336 adb86c37 balrog
#define WM8750_RESET        0x0f
337 adb86c37 balrog
#define WM8750_3D        0x10
338 adb86c37 balrog
#define WM8750_ALC1        0x11
339 adb86c37 balrog
#define WM8750_ALC2        0x12
340 adb86c37 balrog
#define WM8750_ALC3        0x13
341 adb86c37 balrog
#define WM8750_NGATE        0x14
342 adb86c37 balrog
#define WM8750_LADC        0x15
343 adb86c37 balrog
#define WM8750_RADC        0x16
344 adb86c37 balrog
#define WM8750_ADCTL1        0x17
345 adb86c37 balrog
#define WM8750_ADCTL2        0x18
346 adb86c37 balrog
#define WM8750_PWR1        0x19
347 adb86c37 balrog
#define WM8750_PWR2        0x1a
348 adb86c37 balrog
#define WM8750_ADCTL3        0x1b
349 adb86c37 balrog
#define WM8750_ADCIN        0x1f
350 adb86c37 balrog
#define WM8750_LADCIN        0x20
351 adb86c37 balrog
#define WM8750_RADCIN        0x21
352 adb86c37 balrog
#define WM8750_LOUTM1        0x22
353 adb86c37 balrog
#define WM8750_LOUTM2        0x23
354 adb86c37 balrog
#define WM8750_ROUTM1        0x24
355 adb86c37 balrog
#define WM8750_ROUTM2        0x25
356 adb86c37 balrog
#define WM8750_MOUTM1        0x26
357 adb86c37 balrog
#define WM8750_MOUTM2        0x27
358 adb86c37 balrog
#define WM8750_LOUT2V        0x28
359 adb86c37 balrog
#define WM8750_ROUT2V        0x29
360 adb86c37 balrog
#define WM8750_MOUTV        0x2a
361 adb86c37 balrog
362 adb86c37 balrog
static int wm8750_tx(i2c_slave *i2c, uint8_t data)
363 adb86c37 balrog
{
364 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) i2c;
365 adb86c37 balrog
    uint8_t cmd;
366 adb86c37 balrog
    uint16_t value;
367 adb86c37 balrog
368 adb86c37 balrog
    if (s->i2c_len >= 2) {
369 adb86c37 balrog
        printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
370 adb86c37 balrog
#ifdef VERBOSE
371 adb86c37 balrog
        return 1;
372 adb86c37 balrog
#endif
373 adb86c37 balrog
    }
374 adb86c37 balrog
    s->i2c_data[s->i2c_len ++] = data;
375 adb86c37 balrog
    if (s->i2c_len != 2)
376 adb86c37 balrog
        return 0;
377 adb86c37 balrog
378 adb86c37 balrog
    cmd = s->i2c_data[0] >> 1;
379 adb86c37 balrog
    value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
380 adb86c37 balrog
381 adb86c37 balrog
    switch (cmd) {
382 adb86c37 balrog
    case WM8750_LADCIN:        /* ADC Signal Path Control (Left) */
383 adb86c37 balrog
        s->diff[0] = (((value >> 6) & 3) == 3);        /* LINSEL */
384 adb86c37 balrog
        if (s->diff[0])
385 adb86c37 balrog
            s->in[0] = &s->adc_voice[0 + s->ds * 1];
386 adb86c37 balrog
        else
387 adb86c37 balrog
            s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
388 adb86c37 balrog
        break;
389 adb86c37 balrog
390 adb86c37 balrog
    case WM8750_RADCIN:        /* ADC Signal Path Control (Right) */
391 adb86c37 balrog
        s->diff[1] = (((value >> 6) & 3) == 3);        /* RINSEL */
392 adb86c37 balrog
        if (s->diff[1])
393 adb86c37 balrog
            s->in[1] = &s->adc_voice[0 + s->ds * 1];
394 adb86c37 balrog
        else
395 adb86c37 balrog
            s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
396 adb86c37 balrog
        break;
397 adb86c37 balrog
398 adb86c37 balrog
    case WM8750_ADCIN:        /* ADC Input Mode */
399 adb86c37 balrog
        s->ds = (value >> 8) & 1;        /* DS */
400 adb86c37 balrog
        if (s->diff[0])
401 adb86c37 balrog
            s->in[0] = &s->adc_voice[0 + s->ds * 1];
402 adb86c37 balrog
        if (s->diff[1])
403 adb86c37 balrog
            s->in[1] = &s->adc_voice[0 + s->ds * 1];
404 adb86c37 balrog
        s->monomix[0] = (value >> 6) & 3;        /* MONOMIX */
405 adb86c37 balrog
        break;
406 adb86c37 balrog
407 adb86c37 balrog
    case WM8750_ADCTL1:        /* Additional Control (1) */
408 adb86c37 balrog
        s->monomix[1] = (value >> 1) & 1;        /* DMONOMIX */
409 adb86c37 balrog
        break;
410 adb86c37 balrog
411 adb86c37 balrog
    case WM8750_PWR1:        /* Power Management (1) */
412 adb86c37 balrog
        s->enable = ((value >> 6) & 7) == 3;        /* VMIDSEL, VREF */
413 adb86c37 balrog
        wm8750_set_format(s);
414 adb86c37 balrog
        break;
415 adb86c37 balrog
416 adb86c37 balrog
    case WM8750_LINVOL:        /* Left Channel PGA */
417 adb86c37 balrog
        s->invol[0] = value & 0x3f;                /* LINVOL */
418 adb86c37 balrog
        s->inmute[0] = (value >> 7) & 1;        /* LINMUTE */
419 683efdcb balrog
        wm8750_vol_update(s);
420 adb86c37 balrog
        break;
421 adb86c37 balrog
422 adb86c37 balrog
    case WM8750_RINVOL:        /* Right Channel PGA */
423 adb86c37 balrog
        s->invol[1] = value & 0x3f;                /* RINVOL */
424 adb86c37 balrog
        s->inmute[1] = (value >> 7) & 1;        /* RINMUTE */
425 683efdcb balrog
        wm8750_vol_update(s);
426 adb86c37 balrog
        break;
427 adb86c37 balrog
428 adb86c37 balrog
    case WM8750_ADCDAC:        /* ADC and DAC Control */
429 adb86c37 balrog
        s->pol = (value >> 5) & 3;                /* ADCPOL */
430 adb86c37 balrog
        s->mute = (value >> 3) & 1;                /* DACMU */
431 683efdcb balrog
        wm8750_vol_update(s);
432 adb86c37 balrog
        break;
433 adb86c37 balrog
434 adb86c37 balrog
    case WM8750_ADCTL3:        /* Additional Control (3) */
435 adb86c37 balrog
        break;
436 adb86c37 balrog
437 adb86c37 balrog
    case WM8750_LADC:        /* Left ADC Digital Volume */
438 adb86c37 balrog
        s->invol[2] = value & 0xff;                /* LADCVOL */
439 db502b61 balrog
        wm8750_vol_update(s);
440 adb86c37 balrog
        break;
441 adb86c37 balrog
442 adb86c37 balrog
    case WM8750_RADC:        /* Right ADC Digital Volume */
443 adb86c37 balrog
        s->invol[3] = value & 0xff;                /* RADCVOL */
444 db502b61 balrog
        wm8750_vol_update(s);
445 adb86c37 balrog
        break;
446 adb86c37 balrog
447 adb86c37 balrog
    case WM8750_ALC1:        /* ALC Control (1) */
448 adb86c37 balrog
        s->alc = (value >> 7) & 3;                /* ALCSEL */
449 adb86c37 balrog
        break;
450 adb86c37 balrog
451 adb86c37 balrog
    case WM8750_NGATE:        /* Noise Gate Control */
452 adb86c37 balrog
    case WM8750_3D:        /* 3D enhance */
453 adb86c37 balrog
        break;
454 adb86c37 balrog
455 adb86c37 balrog
    case WM8750_LDAC:        /* Left Channel Digital Volume */
456 adb86c37 balrog
        s->outvol[0] = value & 0xff;                /* LDACVOL */
457 db502b61 balrog
        wm8750_vol_update(s);
458 adb86c37 balrog
        break;
459 adb86c37 balrog
460 adb86c37 balrog
    case WM8750_RDAC:        /* Right Channel Digital Volume */
461 adb86c37 balrog
        s->outvol[1] = value & 0xff;                /* RDACVOL */
462 db502b61 balrog
        wm8750_vol_update(s);
463 adb86c37 balrog
        break;
464 adb86c37 balrog
465 adb86c37 balrog
    case WM8750_BASS:        /* Bass Control */
466 adb86c37 balrog
        break;
467 adb86c37 balrog
468 adb86c37 balrog
    case WM8750_LOUTM1:        /* Left Mixer Control (1) */
469 adb86c37 balrog
        s->path[0] = (value >> 8) & 1;                /* LD2LO */
470 db502b61 balrog
        /* TODO: mute/unmute respective paths */
471 db502b61 balrog
        wm8750_vol_update(s);
472 adb86c37 balrog
        break;
473 adb86c37 balrog
474 adb86c37 balrog
    case WM8750_LOUTM2:        /* Left Mixer Control (2) */
475 adb86c37 balrog
        s->path[1] = (value >> 8) & 1;                /* RD2LO */
476 db502b61 balrog
        /* TODO: mute/unmute respective paths */
477 db502b61 balrog
        wm8750_vol_update(s);
478 adb86c37 balrog
        break;
479 adb86c37 balrog
480 adb86c37 balrog
    case WM8750_ROUTM1:        /* Right Mixer Control (1) */
481 adb86c37 balrog
        s->path[2] = (value >> 8) & 1;                /* LD2RO */
482 db502b61 balrog
        /* TODO: mute/unmute respective paths */
483 db502b61 balrog
        wm8750_vol_update(s);
484 adb86c37 balrog
        break;
485 adb86c37 balrog
486 adb86c37 balrog
    case WM8750_ROUTM2:        /* Right Mixer Control (2) */
487 adb86c37 balrog
        s->path[3] = (value >> 8) & 1;                /* RD2RO */
488 db502b61 balrog
        /* TODO: mute/unmute respective paths */
489 db502b61 balrog
        wm8750_vol_update(s);
490 adb86c37 balrog
        break;
491 adb86c37 balrog
492 adb86c37 balrog
    case WM8750_MOUTM1:        /* Mono Mixer Control (1) */
493 adb86c37 balrog
        s->mpath[0] = (value >> 8) & 1;                /* LD2MO */
494 db502b61 balrog
        /* TODO: mute/unmute respective paths */
495 db502b61 balrog
        wm8750_vol_update(s);
496 adb86c37 balrog
        break;
497 adb86c37 balrog
498 adb86c37 balrog
    case WM8750_MOUTM2:        /* Mono Mixer Control (2) */
499 adb86c37 balrog
        s->mpath[1] = (value >> 8) & 1;                /* RD2MO */
500 db502b61 balrog
        /* TODO: mute/unmute respective paths */
501 db502b61 balrog
        wm8750_vol_update(s);
502 adb86c37 balrog
        break;
503 adb86c37 balrog
504 adb86c37 balrog
    case WM8750_LOUT1V:        /* LOUT1 Volume */
505 683efdcb balrog
        s->outvol[2] = value & 0x7f;                /* LOUT1VOL */
506 db502b61 balrog
        wm8750_vol_update(s);
507 adb86c37 balrog
        break;
508 adb86c37 balrog
509 adb86c37 balrog
    case WM8750_LOUT2V:        /* LOUT2 Volume */
510 adb86c37 balrog
        s->outvol[4] = value & 0x7f;                /* LOUT2VOL */
511 683efdcb balrog
        wm8750_vol_update(s);
512 adb86c37 balrog
        break;
513 adb86c37 balrog
514 adb86c37 balrog
    case WM8750_ROUT1V:        /* ROUT1 Volume */
515 683efdcb balrog
        s->outvol[3] = value & 0x7f;                /* ROUT1VOL */
516 db502b61 balrog
        wm8750_vol_update(s);
517 adb86c37 balrog
        break;
518 adb86c37 balrog
519 adb86c37 balrog
    case WM8750_ROUT2V:        /* ROUT2 Volume */
520 adb86c37 balrog
        s->outvol[5] = value & 0x7f;                /* ROUT2VOL */
521 683efdcb balrog
        wm8750_vol_update(s);
522 adb86c37 balrog
        break;
523 adb86c37 balrog
524 adb86c37 balrog
    case WM8750_MOUTV:        /* MONOOUT Volume */
525 adb86c37 balrog
        s->outvol[6] = value & 0x7f;                /* MONOOUTVOL */
526 db502b61 balrog
        wm8750_vol_update(s);
527 adb86c37 balrog
        break;
528 adb86c37 balrog
529 adb86c37 balrog
    case WM8750_ADCTL2:        /* Additional Control (2) */
530 adb86c37 balrog
        break;
531 adb86c37 balrog
532 adb86c37 balrog
    case WM8750_PWR2:        /* Power Management (2) */
533 adb86c37 balrog
        s->power = value & 0x7e;
534 db502b61 balrog
        /* TODO: mute/unmute respective paths */
535 db502b61 balrog
        wm8750_vol_update(s);
536 adb86c37 balrog
        break;
537 adb86c37 balrog
538 adb86c37 balrog
    case WM8750_IFACE:        /* Digital Audio Interface Format */
539 adb86c37 balrog
        s->format = value;
540 af83e09e balrog
        s->master = (value >> 6) & 1;                        /* MS */
541 af83e09e balrog
        wm8750_clk_update(s, s->master);
542 adb86c37 balrog
        break;
543 adb86c37 balrog
544 adb86c37 balrog
    case WM8750_SRATE:        /* Clocking and Sample Rate Control */
545 adb86c37 balrog
        s->rate = &wm_rate_table[(value >> 1) & 0x1f];
546 af83e09e balrog
        wm8750_clk_update(s, 0);
547 adb86c37 balrog
        break;
548 adb86c37 balrog
549 adb86c37 balrog
    case WM8750_RESET:        /* Reset */
550 adb86c37 balrog
        wm8750_reset(&s->i2c);
551 adb86c37 balrog
        break;
552 adb86c37 balrog
553 adb86c37 balrog
#ifdef VERBOSE
554 adb86c37 balrog
    default:
555 adb86c37 balrog
        printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
556 adb86c37 balrog
#endif
557 adb86c37 balrog
    }
558 adb86c37 balrog
559 adb86c37 balrog
    return 0;
560 adb86c37 balrog
}
561 adb86c37 balrog
562 adb86c37 balrog
static int wm8750_rx(i2c_slave *i2c)
563 adb86c37 balrog
{
564 adb86c37 balrog
    return 0x00;
565 adb86c37 balrog
}
566 adb86c37 balrog
567 c1d803b3 Juan Quintela
static void wm8750_pre_save(void *opaque)
568 aa941b94 balrog
{
569 c1d803b3 Juan Quintela
    WM8750State *s = opaque;
570 c1d803b3 Juan Quintela
571 c1d803b3 Juan Quintela
    s->rate_vmstate = (s->rate - wm_rate_table) / sizeof(*s->rate);
572 aa941b94 balrog
}
573 aa941b94 balrog
574 c1d803b3 Juan Quintela
static int wm8750_post_load(void *opaque, int version_id)
575 aa941b94 balrog
{
576 c1d803b3 Juan Quintela
    WM8750State *s = opaque;
577 c1d803b3 Juan Quintela
578 c1d803b3 Juan Quintela
    s->rate = &wm_rate_table[s->rate_vmstate & 0x1f];
579 aa941b94 balrog
    return 0;
580 aa941b94 balrog
}
581 aa941b94 balrog
582 c1d803b3 Juan Quintela
static const VMStateDescription vmstate_wm8750 = {
583 c1d803b3 Juan Quintela
    .name = CODEC,
584 c1d803b3 Juan Quintela
    .version_id = 0,
585 c1d803b3 Juan Quintela
    .minimum_version_id = 0,
586 c1d803b3 Juan Quintela
    .minimum_version_id_old = 0,
587 c1d803b3 Juan Quintela
    .pre_save = wm8750_pre_save,
588 c1d803b3 Juan Quintela
    .post_load = wm8750_post_load,
589 c1d803b3 Juan Quintela
    .fields      = (VMStateField []) {
590 c1d803b3 Juan Quintela
        VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
591 c1d803b3 Juan Quintela
        VMSTATE_INT32(i2c_len, WM8750State),
592 c1d803b3 Juan Quintela
        VMSTATE_INT32(enable, WM8750State),
593 c1d803b3 Juan Quintela
        VMSTATE_INT32(idx_in, WM8750State),
594 c1d803b3 Juan Quintela
        VMSTATE_INT32(req_in, WM8750State),
595 c1d803b3 Juan Quintela
        VMSTATE_INT32(idx_out, WM8750State),
596 c1d803b3 Juan Quintela
        VMSTATE_INT32(req_out, WM8750State),
597 c1d803b3 Juan Quintela
        VMSTATE_UINT8_ARRAY(outvol, WM8750State, 7),
598 c1d803b3 Juan Quintela
        VMSTATE_UINT8_ARRAY(outmute, WM8750State, 2),
599 c1d803b3 Juan Quintela
        VMSTATE_UINT8_ARRAY(invol, WM8750State, 4),
600 c1d803b3 Juan Quintela
        VMSTATE_UINT8_ARRAY(inmute, WM8750State, 2),
601 c1d803b3 Juan Quintela
        VMSTATE_UINT8_ARRAY(diff, WM8750State, 2),
602 c1d803b3 Juan Quintela
        VMSTATE_UINT8(pol, WM8750State),
603 c1d803b3 Juan Quintela
        VMSTATE_UINT8(ds, WM8750State),
604 c1d803b3 Juan Quintela
        VMSTATE_UINT8_ARRAY(monomix, WM8750State, 2),
605 c1d803b3 Juan Quintela
        VMSTATE_UINT8(alc, WM8750State),
606 c1d803b3 Juan Quintela
        VMSTATE_UINT8(mute, WM8750State),
607 c1d803b3 Juan Quintela
        VMSTATE_UINT8_ARRAY(path, WM8750State, 4),
608 c1d803b3 Juan Quintela
        VMSTATE_UINT8_ARRAY(mpath, WM8750State, 2),
609 c1d803b3 Juan Quintela
        VMSTATE_UINT8(format, WM8750State),
610 c1d803b3 Juan Quintela
        VMSTATE_UINT8(power, WM8750State),
611 c1d803b3 Juan Quintela
        VMSTATE_UINT8(rate_vmstate, WM8750State),
612 c1d803b3 Juan Quintela
        VMSTATE_I2C_SLAVE(i2c, WM8750State),
613 c1d803b3 Juan Quintela
        VMSTATE_END_OF_LIST()
614 c1d803b3 Juan Quintela
    }
615 c1d803b3 Juan Quintela
};
616 c1d803b3 Juan Quintela
617 81a322d4 Gerd Hoffmann
static int wm8750_init(i2c_slave *i2c)
618 adb86c37 balrog
{
619 cdbe40ca Paul Brook
    WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c);
620 adb86c37 balrog
621 1a7dafce malc
    AUD_register_card(CODEC, &s->card);
622 adb86c37 balrog
    wm8750_reset(&s->i2c);
623 adb86c37 balrog
624 81a322d4 Gerd Hoffmann
    return 0;
625 adb86c37 balrog
}
626 adb86c37 balrog
627 523111e7 balrog
#if 0
628 9596ebb7 pbrook
static void wm8750_fini(i2c_slave *i2c)
629 adb86c37 balrog
{
630 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) i2c;
631 adb86c37 balrog
    wm8750_reset(&s->i2c);
632 adb86c37 balrog
    AUD_remove_card(&s->card);
633 adb86c37 balrog
    qemu_free(s);
634 adb86c37 balrog
}
635 523111e7 balrog
#endif
636 adb86c37 balrog
637 cdbe40ca Paul Brook
void wm8750_data_req_set(DeviceState *dev,
638 adb86c37 balrog
                void (*data_req)(void *, int, int), void *opaque)
639 adb86c37 balrog
{
640 cdbe40ca Paul Brook
    WM8750State *s = FROM_I2C_SLAVE(WM8750State, I2C_SLAVE_FROM_QDEV(dev));
641 adb86c37 balrog
    s->data_req = data_req;
642 adb86c37 balrog
    s->opaque = opaque;
643 adb86c37 balrog
}
644 adb86c37 balrog
645 adb86c37 balrog
void wm8750_dac_dat(void *opaque, uint32_t sample)
646 adb86c37 balrog
{
647 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
648 af83e09e balrog
649 683efdcb balrog
    *(uint32_t *) &s->data_out[s->idx_out] = sample;
650 adb86c37 balrog
    s->req_out -= 4;
651 adb86c37 balrog
    s->idx_out += 4;
652 adb86c37 balrog
    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
653 adb86c37 balrog
        wm8750_out_flush(s);
654 adb86c37 balrog
}
655 adb86c37 balrog
656 662caa6f balrog
void *wm8750_dac_buffer(void *opaque, int samples)
657 662caa6f balrog
{
658 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
659 662caa6f balrog
    /* XXX: Should check if there are <i>samples</i> free samples available */
660 662caa6f balrog
    void *ret = s->data_out + s->idx_out;
661 662caa6f balrog
662 662caa6f balrog
    s->idx_out += samples << 2;
663 662caa6f balrog
    s->req_out -= samples << 2;
664 662caa6f balrog
    return ret;
665 662caa6f balrog
}
666 662caa6f balrog
667 662caa6f balrog
void wm8750_dac_commit(void *opaque)
668 662caa6f balrog
{
669 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
670 662caa6f balrog
671 7442511c blueswir1
    wm8750_out_flush(s);
672 662caa6f balrog
}
673 662caa6f balrog
674 adb86c37 balrog
uint32_t wm8750_adc_dat(void *opaque)
675 adb86c37 balrog
{
676 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
677 adb86c37 balrog
    uint32_t *data;
678 af83e09e balrog
679 adb86c37 balrog
    if (s->idx_in >= sizeof(s->data_in))
680 adb86c37 balrog
        wm8750_in_load(s);
681 af83e09e balrog
682 adb86c37 balrog
    data = (uint32_t *) &s->data_in[s->idx_in];
683 adb86c37 balrog
    s->req_in -= 4;
684 adb86c37 balrog
    s->idx_in += 4;
685 683efdcb balrog
    return *data;
686 adb86c37 balrog
}
687 af83e09e balrog
688 b0f74c87 balrog
void wm8750_set_bclk_in(void *opaque, int new_hz)
689 af83e09e balrog
{
690 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
691 af83e09e balrog
692 b0f74c87 balrog
    s->ext_adc_hz = new_hz;
693 b0f74c87 balrog
    s->ext_dac_hz = new_hz;
694 af83e09e balrog
    wm8750_clk_update(s, 1);
695 af83e09e balrog
}
696 cdbe40ca Paul Brook
697 cdbe40ca Paul Brook
static I2CSlaveInfo wm8750_info = {
698 074f2fff Gerd Hoffmann
    .qdev.name = "wm8750",
699 074f2fff Gerd Hoffmann
    .qdev.size = sizeof(WM8750State),
700 be73cfe2 Juan Quintela
    .qdev.vmsd = &vmstate_wm8750,
701 cdbe40ca Paul Brook
    .init = wm8750_init,
702 cdbe40ca Paul Brook
    .event = wm8750_event,
703 cdbe40ca Paul Brook
    .recv = wm8750_rx,
704 cdbe40ca Paul Brook
    .send = wm8750_tx
705 cdbe40ca Paul Brook
};
706 cdbe40ca Paul Brook
707 cdbe40ca Paul Brook
static void wm8750_register_devices(void)
708 cdbe40ca Paul Brook
{
709 074f2fff Gerd Hoffmann
    i2c_register_slave(&wm8750_info);
710 cdbe40ca Paul Brook
}
711 cdbe40ca Paul Brook
712 cdbe40ca Paul Brook
device_init(wm8750_register_devices)