Statistics
| Branch: | Revision:

root / hw / wm8750.c @ d9346e81

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