Statistics
| Branch: | Revision:

root / hw / wm8750.c @ 72ecb8d9

History | View | Annotate | Download (21 kB)

1 adb86c37 balrog
/*
2 adb86c37 balrog
 * WM8750 audio CODEC.
3 adb86c37 balrog
 *
4 adb86c37 balrog
 * Copyright (c) 2006 Openedhand Ltd.
5 adb86c37 balrog
 * Written by Andrzej Zaborowski <balrog@zabor.org>
6 adb86c37 balrog
 *
7 adb86c37 balrog
 * This file is licensed under GNU GPL.
8 adb86c37 balrog
 */
9 adb86c37 balrog
10 87ecb68b pbrook
#include "hw.h"
11 87ecb68b pbrook
#include "i2c.h"
12 87ecb68b pbrook
#include "audio/audio.h"
13 adb86c37 balrog
14 adb86c37 balrog
#define IN_PORT_N        3
15 adb86c37 balrog
#define OUT_PORT_N        3
16 adb86c37 balrog
17 adb86c37 balrog
#define CODEC                "wm8750"
18 adb86c37 balrog
19 adb86c37 balrog
struct wm_rate_s;
20 adb86c37 balrog
struct wm8750_s {
21 adb86c37 balrog
    i2c_slave i2c;
22 adb86c37 balrog
    uint8_t i2c_data[2];
23 adb86c37 balrog
    int i2c_len;
24 adb86c37 balrog
    QEMUSoundCard card;
25 adb86c37 balrog
    SWVoiceIn *adc_voice[IN_PORT_N];
26 adb86c37 balrog
    SWVoiceOut *dac_voice[OUT_PORT_N];
27 adb86c37 balrog
    int enable;
28 adb86c37 balrog
    void (*data_req)(void *, int, int);
29 adb86c37 balrog
    void *opaque;
30 adb86c37 balrog
    uint8_t data_in[4096];
31 adb86c37 balrog
    uint8_t data_out[4096];
32 adb86c37 balrog
    int idx_in, req_in;
33 adb86c37 balrog
    int idx_out, req_out;
34 adb86c37 balrog
35 adb86c37 balrog
    SWVoiceOut **out[2];
36 adb86c37 balrog
    uint8_t outvol[7], outmute[2];
37 adb86c37 balrog
    SWVoiceIn **in[2];
38 adb86c37 balrog
    uint8_t invol[4], inmute[2];
39 adb86c37 balrog
40 adb86c37 balrog
    uint8_t diff[2], pol, ds, monomix[2], alc, mute;
41 adb86c37 balrog
    uint8_t path[4], mpath[2], power, format;
42 adb86c37 balrog
    const struct wm_rate_s *rate;
43 af83e09e balrog
    int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
44 adb86c37 balrog
};
45 adb86c37 balrog
46 db502b61 balrog
/* pow(10.0, -i / 20.0) * 255, i = 0..42 */
47 683efdcb balrog
static const uint8_t wm8750_vol_db_table[] = {
48 683efdcb balrog
    255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
49 683efdcb balrog
    40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
50 683efdcb balrog
    4, 4, 3, 3, 3, 2, 2
51 683efdcb balrog
};
52 683efdcb balrog
53 db502b61 balrog
#define WM8750_OUTVOL_TRANSFORM(x)        wm8750_vol_db_table[(0x7f - x) / 3]
54 db502b61 balrog
#define WM8750_INVOL_TRANSFORM(x)        (x << 2)
55 683efdcb balrog
56 adb86c37 balrog
static inline void wm8750_in_load(struct wm8750_s *s)
57 adb86c37 balrog
{
58 adb86c37 balrog
    int acquired;
59 adb86c37 balrog
    if (s->idx_in + s->req_in <= sizeof(s->data_in))
60 adb86c37 balrog
        return;
61 adb86c37 balrog
    s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
62 adb86c37 balrog
    acquired = AUD_read(*s->in[0], s->data_in + s->idx_in,
63 adb86c37 balrog
                    sizeof(s->data_in) - s->idx_in);
64 adb86c37 balrog
}
65 adb86c37 balrog
66 adb86c37 balrog
static inline void wm8750_out_flush(struct wm8750_s *s)
67 adb86c37 balrog
{
68 523111e7 balrog
    int sent = 0;
69 523111e7 balrog
    while (sent < s->idx_out)
70 523111e7 balrog
        sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent)
71 523111e7 balrog
                ?: s->idx_out;
72 adb86c37 balrog
    s->idx_out = 0;
73 adb86c37 balrog
}
74 adb86c37 balrog
75 adb86c37 balrog
static void wm8750_audio_in_cb(void *opaque, int avail_b)
76 adb86c37 balrog
{
77 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
78 adb86c37 balrog
    s->req_in = avail_b;
79 adb86c37 balrog
    s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
80 adb86c37 balrog
}
81 adb86c37 balrog
82 adb86c37 balrog
static void wm8750_audio_out_cb(void *opaque, int free_b)
83 adb86c37 balrog
{
84 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
85 adb86c37 balrog
86 523111e7 balrog
    if (s->idx_out >= free_b) {
87 523111e7 balrog
        s->idx_out = free_b;
88 523111e7 balrog
        s->req_out = 0;
89 523111e7 balrog
        wm8750_out_flush(s);
90 523111e7 balrog
    } else
91 523111e7 balrog
        s->req_out = free_b - s->idx_out;
92 523111e7 balrog
 
93 523111e7 balrog
    s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
94 adb86c37 balrog
}
95 adb86c37 balrog
96 adb86c37 balrog
struct wm_rate_s {
97 adb86c37 balrog
    int adc;
98 adb86c37 balrog
    int adc_hz;
99 adb86c37 balrog
    int dac;
100 adb86c37 balrog
    int dac_hz;
101 adb86c37 balrog
};
102 adb86c37 balrog
103 adb86c37 balrog
static const struct wm_rate_s 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 683efdcb balrog
static void wm8750_vol_update(struct wm8750_s *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 9596ebb7 pbrook
static void wm8750_set_format(struct wm8750_s *s)
171 adb86c37 balrog
{
172 adb86c37 balrog
    int i;
173 adb86c37 balrog
    audsettings_t in_fmt;
174 adb86c37 balrog
    audsettings_t out_fmt;
175 adb86c37 balrog
    audsettings_t 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 adb86c37 balrog
            s->adc_voice[i] = 0;
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 adb86c37 balrog
            s->dac_voice[i] = 0;
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 af83e09e balrog
static void wm8750_clk_update(struct wm8750_s *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 adb86c37 balrog
void wm8750_reset(i2c_slave *i2c)
264 adb86c37 balrog
{
265 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) 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 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) 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 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) 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 aa941b94 balrog
static void wm8750_save(QEMUFile *f, void *opaque)
569 aa941b94 balrog
{
570 aa941b94 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
571 aa941b94 balrog
    int i;
572 aa941b94 balrog
    qemu_put_8s(f, &s->i2c_data[0]);
573 aa941b94 balrog
    qemu_put_8s(f, &s->i2c_data[1]);
574 aa941b94 balrog
    qemu_put_be32(f, s->i2c_len);
575 aa941b94 balrog
    qemu_put_be32(f, s->enable);
576 aa941b94 balrog
    qemu_put_be32(f, s->idx_in);
577 aa941b94 balrog
    qemu_put_be32(f, s->req_in);
578 aa941b94 balrog
    qemu_put_be32(f, s->idx_out);
579 aa941b94 balrog
    qemu_put_be32(f, s->req_out);
580 aa941b94 balrog
581 aa941b94 balrog
    for (i = 0; i < 7; i ++)
582 aa941b94 balrog
        qemu_put_8s(f, &s->outvol[i]);
583 aa941b94 balrog
    for (i = 0; i < 2; i ++)
584 aa941b94 balrog
        qemu_put_8s(f, &s->outmute[i]);
585 aa941b94 balrog
    for (i = 0; i < 4; i ++)
586 aa941b94 balrog
        qemu_put_8s(f, &s->invol[i]);
587 aa941b94 balrog
    for (i = 0; i < 2; i ++)
588 aa941b94 balrog
        qemu_put_8s(f, &s->inmute[i]);
589 aa941b94 balrog
590 aa941b94 balrog
    for (i = 0; i < 2; i ++)
591 aa941b94 balrog
        qemu_put_8s(f, &s->diff[i]);
592 aa941b94 balrog
    qemu_put_8s(f, &s->pol);
593 aa941b94 balrog
    qemu_put_8s(f, &s->ds);
594 aa941b94 balrog
    for (i = 0; i < 2; i ++)
595 aa941b94 balrog
        qemu_put_8s(f, &s->monomix[i]);
596 aa941b94 balrog
    qemu_put_8s(f, &s->alc);
597 aa941b94 balrog
    qemu_put_8s(f, &s->mute);
598 aa941b94 balrog
    for (i = 0; i < 4; i ++)
599 aa941b94 balrog
        qemu_put_8s(f, &s->path[i]);
600 aa941b94 balrog
    for (i = 0; i < 2; i ++)
601 aa941b94 balrog
        qemu_put_8s(f, &s->mpath[i]);
602 aa941b94 balrog
    qemu_put_8s(f, &s->format);
603 aa941b94 balrog
    qemu_put_8s(f, &s->power);
604 aa941b94 balrog
    qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
605 aa941b94 balrog
    i2c_slave_save(f, &s->i2c);
606 aa941b94 balrog
}
607 aa941b94 balrog
608 aa941b94 balrog
static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
609 aa941b94 balrog
{
610 aa941b94 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
611 aa941b94 balrog
    int i;
612 aa941b94 balrog
    qemu_get_8s(f, &s->i2c_data[0]);
613 aa941b94 balrog
    qemu_get_8s(f, &s->i2c_data[1]);
614 aa941b94 balrog
    s->i2c_len = qemu_get_be32(f);
615 aa941b94 balrog
    s->enable = qemu_get_be32(f);
616 aa941b94 balrog
    s->idx_in = qemu_get_be32(f);
617 aa941b94 balrog
    s->req_in = qemu_get_be32(f);
618 aa941b94 balrog
    s->idx_out = qemu_get_be32(f);
619 aa941b94 balrog
    s->req_out = qemu_get_be32(f);
620 aa941b94 balrog
621 aa941b94 balrog
    for (i = 0; i < 7; i ++)
622 aa941b94 balrog
        qemu_get_8s(f, &s->outvol[i]);
623 aa941b94 balrog
    for (i = 0; i < 2; i ++)
624 aa941b94 balrog
        qemu_get_8s(f, &s->outmute[i]);
625 aa941b94 balrog
    for (i = 0; i < 4; i ++)
626 aa941b94 balrog
        qemu_get_8s(f, &s->invol[i]);
627 aa941b94 balrog
    for (i = 0; i < 2; i ++)
628 aa941b94 balrog
        qemu_get_8s(f, &s->inmute[i]);
629 aa941b94 balrog
630 aa941b94 balrog
    for (i = 0; i < 2; i ++)
631 aa941b94 balrog
        qemu_get_8s(f, &s->diff[i]);
632 aa941b94 balrog
    qemu_get_8s(f, &s->pol);
633 aa941b94 balrog
    qemu_get_8s(f, &s->ds);
634 aa941b94 balrog
    for (i = 0; i < 2; i ++)
635 aa941b94 balrog
        qemu_get_8s(f, &s->monomix[i]);
636 aa941b94 balrog
    qemu_get_8s(f, &s->alc);
637 aa941b94 balrog
    qemu_get_8s(f, &s->mute);
638 aa941b94 balrog
    for (i = 0; i < 4; i ++)
639 aa941b94 balrog
        qemu_get_8s(f, &s->path[i]);
640 aa941b94 balrog
    for (i = 0; i < 2; i ++)
641 aa941b94 balrog
        qemu_get_8s(f, &s->mpath[i]);
642 aa941b94 balrog
    qemu_get_8s(f, &s->format);
643 aa941b94 balrog
    qemu_get_8s(f, &s->power);
644 aa941b94 balrog
    s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
645 aa941b94 balrog
    i2c_slave_load(f, &s->i2c);
646 aa941b94 balrog
    return 0;
647 aa941b94 balrog
}
648 aa941b94 balrog
649 adb86c37 balrog
i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
650 adb86c37 balrog
{
651 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *)
652 adb86c37 balrog
            i2c_slave_init(bus, 0, sizeof(struct wm8750_s));
653 adb86c37 balrog
    s->i2c.event = wm8750_event;
654 adb86c37 balrog
    s->i2c.recv = wm8750_rx;
655 adb86c37 balrog
    s->i2c.send = wm8750_tx;
656 adb86c37 balrog
657 adb86c37 balrog
    AUD_register_card(audio, CODEC, &s->card);
658 adb86c37 balrog
    wm8750_reset(&s->i2c);
659 adb86c37 balrog
660 18be5187 pbrook
    register_savevm(CODEC, -1, 0, wm8750_save, wm8750_load, s);
661 aa941b94 balrog
662 adb86c37 balrog
    return &s->i2c;
663 adb86c37 balrog
}
664 adb86c37 balrog
665 523111e7 balrog
#if 0
666 9596ebb7 pbrook
static void wm8750_fini(i2c_slave *i2c)
667 adb86c37 balrog
{
668 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) i2c;
669 adb86c37 balrog
    wm8750_reset(&s->i2c);
670 adb86c37 balrog
    AUD_remove_card(&s->card);
671 adb86c37 balrog
    qemu_free(s);
672 adb86c37 balrog
}
673 523111e7 balrog
#endif
674 adb86c37 balrog
675 adb86c37 balrog
void wm8750_data_req_set(i2c_slave *i2c,
676 adb86c37 balrog
                void (*data_req)(void *, int, int), void *opaque)
677 adb86c37 balrog
{
678 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) i2c;
679 adb86c37 balrog
    s->data_req = data_req;
680 adb86c37 balrog
    s->opaque = opaque;
681 adb86c37 balrog
}
682 adb86c37 balrog
683 adb86c37 balrog
void wm8750_dac_dat(void *opaque, uint32_t sample)
684 adb86c37 balrog
{
685 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
686 af83e09e balrog
687 683efdcb balrog
    *(uint32_t *) &s->data_out[s->idx_out] = sample;
688 adb86c37 balrog
    s->req_out -= 4;
689 adb86c37 balrog
    s->idx_out += 4;
690 adb86c37 balrog
    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
691 adb86c37 balrog
        wm8750_out_flush(s);
692 adb86c37 balrog
}
693 adb86c37 balrog
694 662caa6f balrog
void *wm8750_dac_buffer(void *opaque, int samples)
695 662caa6f balrog
{
696 662caa6f balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
697 662caa6f balrog
    /* XXX: Should check if there are <i>samples</i> free samples available */
698 662caa6f balrog
    void *ret = s->data_out + s->idx_out;
699 662caa6f balrog
700 662caa6f balrog
    s->idx_out += samples << 2;
701 662caa6f balrog
    s->req_out -= samples << 2;
702 662caa6f balrog
    return ret;
703 662caa6f balrog
}
704 662caa6f balrog
705 662caa6f balrog
void wm8750_dac_commit(void *opaque)
706 662caa6f balrog
{
707 662caa6f balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
708 662caa6f balrog
709 662caa6f balrog
    return wm8750_out_flush(s);
710 662caa6f balrog
}
711 662caa6f balrog
712 adb86c37 balrog
uint32_t wm8750_adc_dat(void *opaque)
713 adb86c37 balrog
{
714 adb86c37 balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
715 adb86c37 balrog
    uint32_t *data;
716 af83e09e balrog
717 adb86c37 balrog
    if (s->idx_in >= sizeof(s->data_in))
718 adb86c37 balrog
        wm8750_in_load(s);
719 af83e09e balrog
720 adb86c37 balrog
    data = (uint32_t *) &s->data_in[s->idx_in];
721 adb86c37 balrog
    s->req_in -= 4;
722 adb86c37 balrog
    s->idx_in += 4;
723 683efdcb balrog
    return *data;
724 adb86c37 balrog
}
725 af83e09e balrog
726 af83e09e balrog
void wm8750_set_bclk_in(void *opaque, int hz)
727 af83e09e balrog
{
728 af83e09e balrog
    struct wm8750_s *s = (struct wm8750_s *) opaque;
729 af83e09e balrog
730 af83e09e balrog
    s->ext_adc_hz = hz;
731 af83e09e balrog
    s->ext_dac_hz = hz;
732 af83e09e balrog
    wm8750_clk_update(s, 1);
733 af83e09e balrog
}