Statistics
| Branch: | Revision:

root / hw / wm8750.c @ cdbe40ca

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 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 af83e09e balrog
    int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
50 bc24a225 Paul Brook
} WM8750State;
51 adb86c37 balrog
52 db502b61 balrog
/* pow(10.0, -i / 20.0) * 255, i = 0..42 */
53 683efdcb balrog
static const uint8_t wm8750_vol_db_table[] = {
54 683efdcb balrog
    255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
55 683efdcb balrog
    40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
56 683efdcb balrog
    4, 4, 3, 3, 3, 2, 2
57 683efdcb balrog
};
58 683efdcb balrog
59 db502b61 balrog
#define WM8750_OUTVOL_TRANSFORM(x)        wm8750_vol_db_table[(0x7f - x) / 3]
60 db502b61 balrog
#define WM8750_INVOL_TRANSFORM(x)        (x << 2)
61 683efdcb balrog
62 bc24a225 Paul Brook
static inline void wm8750_in_load(WM8750State *s)
63 adb86c37 balrog
{
64 adb86c37 balrog
    int acquired;
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 adb86c37 balrog
    acquired = AUD_read(*s->in[0], s->data_in + s->idx_in,
69 adb86c37 balrog
                    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 aa941b94 balrog
static void wm8750_save(QEMUFile *f, void *opaque)
568 aa941b94 balrog
{
569 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
570 aa941b94 balrog
    int i;
571 aa941b94 balrog
    qemu_put_8s(f, &s->i2c_data[0]);
572 aa941b94 balrog
    qemu_put_8s(f, &s->i2c_data[1]);
573 aa941b94 balrog
    qemu_put_be32(f, s->i2c_len);
574 aa941b94 balrog
    qemu_put_be32(f, s->enable);
575 aa941b94 balrog
    qemu_put_be32(f, s->idx_in);
576 aa941b94 balrog
    qemu_put_be32(f, s->req_in);
577 aa941b94 balrog
    qemu_put_be32(f, s->idx_out);
578 aa941b94 balrog
    qemu_put_be32(f, s->req_out);
579 aa941b94 balrog
580 aa941b94 balrog
    for (i = 0; i < 7; i ++)
581 aa941b94 balrog
        qemu_put_8s(f, &s->outvol[i]);
582 aa941b94 balrog
    for (i = 0; i < 2; i ++)
583 aa941b94 balrog
        qemu_put_8s(f, &s->outmute[i]);
584 aa941b94 balrog
    for (i = 0; i < 4; i ++)
585 aa941b94 balrog
        qemu_put_8s(f, &s->invol[i]);
586 aa941b94 balrog
    for (i = 0; i < 2; i ++)
587 aa941b94 balrog
        qemu_put_8s(f, &s->inmute[i]);
588 aa941b94 balrog
589 aa941b94 balrog
    for (i = 0; i < 2; i ++)
590 aa941b94 balrog
        qemu_put_8s(f, &s->diff[i]);
591 aa941b94 balrog
    qemu_put_8s(f, &s->pol);
592 aa941b94 balrog
    qemu_put_8s(f, &s->ds);
593 aa941b94 balrog
    for (i = 0; i < 2; i ++)
594 aa941b94 balrog
        qemu_put_8s(f, &s->monomix[i]);
595 aa941b94 balrog
    qemu_put_8s(f, &s->alc);
596 aa941b94 balrog
    qemu_put_8s(f, &s->mute);
597 aa941b94 balrog
    for (i = 0; i < 4; i ++)
598 aa941b94 balrog
        qemu_put_8s(f, &s->path[i]);
599 aa941b94 balrog
    for (i = 0; i < 2; i ++)
600 aa941b94 balrog
        qemu_put_8s(f, &s->mpath[i]);
601 aa941b94 balrog
    qemu_put_8s(f, &s->format);
602 aa941b94 balrog
    qemu_put_8s(f, &s->power);
603 aa941b94 balrog
    qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
604 aa941b94 balrog
    i2c_slave_save(f, &s->i2c);
605 aa941b94 balrog
}
606 aa941b94 balrog
607 aa941b94 balrog
static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
608 aa941b94 balrog
{
609 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
610 aa941b94 balrog
    int i;
611 aa941b94 balrog
    qemu_get_8s(f, &s->i2c_data[0]);
612 aa941b94 balrog
    qemu_get_8s(f, &s->i2c_data[1]);
613 aa941b94 balrog
    s->i2c_len = qemu_get_be32(f);
614 aa941b94 balrog
    s->enable = qemu_get_be32(f);
615 aa941b94 balrog
    s->idx_in = qemu_get_be32(f);
616 aa941b94 balrog
    s->req_in = qemu_get_be32(f);
617 aa941b94 balrog
    s->idx_out = qemu_get_be32(f);
618 aa941b94 balrog
    s->req_out = qemu_get_be32(f);
619 aa941b94 balrog
620 aa941b94 balrog
    for (i = 0; i < 7; i ++)
621 aa941b94 balrog
        qemu_get_8s(f, &s->outvol[i]);
622 aa941b94 balrog
    for (i = 0; i < 2; i ++)
623 aa941b94 balrog
        qemu_get_8s(f, &s->outmute[i]);
624 aa941b94 balrog
    for (i = 0; i < 4; i ++)
625 aa941b94 balrog
        qemu_get_8s(f, &s->invol[i]);
626 aa941b94 balrog
    for (i = 0; i < 2; i ++)
627 aa941b94 balrog
        qemu_get_8s(f, &s->inmute[i]);
628 aa941b94 balrog
629 aa941b94 balrog
    for (i = 0; i < 2; i ++)
630 aa941b94 balrog
        qemu_get_8s(f, &s->diff[i]);
631 aa941b94 balrog
    qemu_get_8s(f, &s->pol);
632 aa941b94 balrog
    qemu_get_8s(f, &s->ds);
633 aa941b94 balrog
    for (i = 0; i < 2; i ++)
634 aa941b94 balrog
        qemu_get_8s(f, &s->monomix[i]);
635 aa941b94 balrog
    qemu_get_8s(f, &s->alc);
636 aa941b94 balrog
    qemu_get_8s(f, &s->mute);
637 aa941b94 balrog
    for (i = 0; i < 4; i ++)
638 aa941b94 balrog
        qemu_get_8s(f, &s->path[i]);
639 aa941b94 balrog
    for (i = 0; i < 2; i ++)
640 aa941b94 balrog
        qemu_get_8s(f, &s->mpath[i]);
641 aa941b94 balrog
    qemu_get_8s(f, &s->format);
642 aa941b94 balrog
    qemu_get_8s(f, &s->power);
643 aa941b94 balrog
    s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
644 aa941b94 balrog
    i2c_slave_load(f, &s->i2c);
645 aa941b94 balrog
    return 0;
646 aa941b94 balrog
}
647 aa941b94 balrog
648 cdbe40ca Paul Brook
static void wm8750_init(i2c_slave *i2c)
649 adb86c37 balrog
{
650 cdbe40ca Paul Brook
    WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c);
651 adb86c37 balrog
652 1a7dafce malc
    AUD_register_card(CODEC, &s->card);
653 adb86c37 balrog
    wm8750_reset(&s->i2c);
654 adb86c37 balrog
655 18be5187 pbrook
    register_savevm(CODEC, -1, 0, wm8750_save, wm8750_load, s);
656 adb86c37 balrog
}
657 adb86c37 balrog
658 523111e7 balrog
#if 0
659 9596ebb7 pbrook
static void wm8750_fini(i2c_slave *i2c)
660 adb86c37 balrog
{
661 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) i2c;
662 adb86c37 balrog
    wm8750_reset(&s->i2c);
663 adb86c37 balrog
    AUD_remove_card(&s->card);
664 adb86c37 balrog
    qemu_free(s);
665 adb86c37 balrog
}
666 523111e7 balrog
#endif
667 adb86c37 balrog
668 cdbe40ca Paul Brook
void wm8750_data_req_set(DeviceState *dev,
669 adb86c37 balrog
                void (*data_req)(void *, int, int), void *opaque)
670 adb86c37 balrog
{
671 cdbe40ca Paul Brook
    WM8750State *s = FROM_I2C_SLAVE(WM8750State, I2C_SLAVE_FROM_QDEV(dev));
672 adb86c37 balrog
    s->data_req = data_req;
673 adb86c37 balrog
    s->opaque = opaque;
674 adb86c37 balrog
}
675 adb86c37 balrog
676 adb86c37 balrog
void wm8750_dac_dat(void *opaque, uint32_t sample)
677 adb86c37 balrog
{
678 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
679 af83e09e balrog
680 683efdcb balrog
    *(uint32_t *) &s->data_out[s->idx_out] = sample;
681 adb86c37 balrog
    s->req_out -= 4;
682 adb86c37 balrog
    s->idx_out += 4;
683 adb86c37 balrog
    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
684 adb86c37 balrog
        wm8750_out_flush(s);
685 adb86c37 balrog
}
686 adb86c37 balrog
687 662caa6f balrog
void *wm8750_dac_buffer(void *opaque, int samples)
688 662caa6f balrog
{
689 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
690 662caa6f balrog
    /* XXX: Should check if there are <i>samples</i> free samples available */
691 662caa6f balrog
    void *ret = s->data_out + s->idx_out;
692 662caa6f balrog
693 662caa6f balrog
    s->idx_out += samples << 2;
694 662caa6f balrog
    s->req_out -= samples << 2;
695 662caa6f balrog
    return ret;
696 662caa6f balrog
}
697 662caa6f balrog
698 662caa6f balrog
void wm8750_dac_commit(void *opaque)
699 662caa6f balrog
{
700 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
701 662caa6f balrog
702 7442511c blueswir1
    wm8750_out_flush(s);
703 662caa6f balrog
}
704 662caa6f balrog
705 adb86c37 balrog
uint32_t wm8750_adc_dat(void *opaque)
706 adb86c37 balrog
{
707 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
708 adb86c37 balrog
    uint32_t *data;
709 af83e09e balrog
710 adb86c37 balrog
    if (s->idx_in >= sizeof(s->data_in))
711 adb86c37 balrog
        wm8750_in_load(s);
712 af83e09e balrog
713 adb86c37 balrog
    data = (uint32_t *) &s->data_in[s->idx_in];
714 adb86c37 balrog
    s->req_in -= 4;
715 adb86c37 balrog
    s->idx_in += 4;
716 683efdcb balrog
    return *data;
717 adb86c37 balrog
}
718 af83e09e balrog
719 b0f74c87 balrog
void wm8750_set_bclk_in(void *opaque, int new_hz)
720 af83e09e balrog
{
721 bc24a225 Paul Brook
    WM8750State *s = (WM8750State *) opaque;
722 af83e09e balrog
723 b0f74c87 balrog
    s->ext_adc_hz = new_hz;
724 b0f74c87 balrog
    s->ext_dac_hz = new_hz;
725 af83e09e balrog
    wm8750_clk_update(s, 1);
726 af83e09e balrog
}
727 cdbe40ca Paul Brook
728 cdbe40ca Paul Brook
static I2CSlaveInfo wm8750_info = {
729 cdbe40ca Paul Brook
    .init = wm8750_init,
730 cdbe40ca Paul Brook
    .event = wm8750_event,
731 cdbe40ca Paul Brook
    .recv = wm8750_rx,
732 cdbe40ca Paul Brook
    .send = wm8750_tx
733 cdbe40ca Paul Brook
};
734 cdbe40ca Paul Brook
735 cdbe40ca Paul Brook
static void wm8750_register_devices(void)
736 cdbe40ca Paul Brook
{
737 cdbe40ca Paul Brook
    i2c_register_slave("wm8750", sizeof(WM8750State), &wm8750_info);
738 cdbe40ca Paul Brook
}
739 cdbe40ca Paul Brook
740 cdbe40ca Paul Brook
device_init(wm8750_register_devices)