Commit af83e09e9e7589c28bcf66518fd20908378880c6
1 parent
762abf67
Use external clock in wm8750 slave mode.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4325 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
57 additions
and
9 deletions
hw/i2c.h
@@ -69,6 +69,7 @@ void wm8750_dac_dat(void *opaque, uint32_t sample); | @@ -69,6 +69,7 @@ void wm8750_dac_dat(void *opaque, uint32_t sample); | ||
69 | uint32_t wm8750_adc_dat(void *opaque); | 69 | uint32_t wm8750_adc_dat(void *opaque); |
70 | void *wm8750_dac_buffer(void *opaque, int samples); | 70 | void *wm8750_dac_buffer(void *opaque, int samples); |
71 | void wm8750_dac_commit(void *opaque); | 71 | void wm8750_dac_commit(void *opaque); |
72 | +void wm8750_set_bclk_in(void *opaque, int hz); | ||
72 | 73 | ||
73 | /* ssd0303.c */ | 74 | /* ssd0303.c */ |
74 | void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address); | 75 | void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address); |
hw/musicpal.c
@@ -298,6 +298,20 @@ static void audio_callback(void *opaque, int free_out, int free_in) | @@ -298,6 +298,20 @@ static void audio_callback(void *opaque, int free_out, int free_in) | ||
298 | qemu_irq_raise(s->irq); | 298 | qemu_irq_raise(s->irq); |
299 | } | 299 | } |
300 | 300 | ||
301 | +static void musicpal_audio_clock_update(musicpal_audio_state *s) | ||
302 | +{ | ||
303 | + int rate; | ||
304 | + | ||
305 | + if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) | ||
306 | + rate = 24576000 / 64; /* 24.576MHz */ | ||
307 | + else | ||
308 | + rate = 11289600 / 64; /* 11.2896MHz */ | ||
309 | + | ||
310 | + rate /= ((s->clock_div >> 8) & 0xff) + 1; | ||
311 | + | ||
312 | + wm8750_set_bclk_in(s->wm, rate / 2); | ||
313 | +} | ||
314 | + | ||
301 | static uint32_t musicpal_audio_read(void *opaque, target_phys_addr_t offset) | 315 | static uint32_t musicpal_audio_read(void *opaque, target_phys_addr_t offset) |
302 | { | 316 | { |
303 | musicpal_audio_state *s = opaque; | 317 | musicpal_audio_state *s = opaque; |
@@ -339,12 +353,14 @@ static void musicpal_audio_write(void *opaque, target_phys_addr_t offset, | @@ -339,12 +353,14 @@ static void musicpal_audio_write(void *opaque, target_phys_addr_t offset, | ||
339 | s->play_pos = 0; | 353 | s->play_pos = 0; |
340 | } | 354 | } |
341 | s->playback_mode = value; | 355 | s->playback_mode = value; |
356 | + musicpal_audio_clock_update(s); | ||
342 | break; | 357 | break; |
343 | 358 | ||
344 | case MP_AUDIO_CLOCK_DIV: | 359 | case MP_AUDIO_CLOCK_DIV: |
345 | s->clock_div = value; | 360 | s->clock_div = value; |
346 | s->last_free = 0; | 361 | s->last_free = 0; |
347 | s->play_pos = 0; | 362 | s->play_pos = 0; |
363 | + musicpal_audio_clock_update(s); | ||
348 | break; | 364 | break; |
349 | 365 | ||
350 | case MP_AUDIO_IRQ_STATUS: | 366 | case MP_AUDIO_IRQ_STATUS: |
hw/wm8750.c
@@ -40,6 +40,7 @@ struct wm8750_s { | @@ -40,6 +40,7 @@ struct wm8750_s { | ||
40 | uint8_t diff[2], pol, ds, monomix[2], alc, mute; | 40 | uint8_t diff[2], pol, ds, monomix[2], alc, mute; |
41 | uint8_t path[4], mpath[2], power, format; | 41 | uint8_t path[4], mpath[2], power, format; |
42 | const struct wm_rate_s *rate; | 42 | const struct wm_rate_s *rate; |
43 | + int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master; | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | /* pow(10.0, -i / 20.0) * 255, i = 0..42 */ | 46 | /* pow(10.0, -i / 20.0) * 255, i = 0..42 */ |
@@ -197,7 +198,7 @@ static void wm8750_set_format(struct wm8750_s *s) | @@ -197,7 +198,7 @@ static void wm8750_set_format(struct wm8750_s *s) | ||
197 | /* Setup input */ | 198 | /* Setup input */ |
198 | in_fmt.endianness = 0; | 199 | in_fmt.endianness = 0; |
199 | in_fmt.nchannels = 2; | 200 | in_fmt.nchannels = 2; |
200 | - in_fmt.freq = s->rate->adc_hz; | 201 | + in_fmt.freq = s->adc_hz; |
201 | in_fmt.fmt = AUD_FMT_S16; | 202 | in_fmt.fmt = AUD_FMT_S16; |
202 | 203 | ||
203 | s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0], | 204 | s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0], |
@@ -210,7 +211,7 @@ static void wm8750_set_format(struct wm8750_s *s) | @@ -210,7 +211,7 @@ static void wm8750_set_format(struct wm8750_s *s) | ||
210 | /* Setup output */ | 211 | /* Setup output */ |
211 | out_fmt.endianness = 0; | 212 | out_fmt.endianness = 0; |
212 | out_fmt.nchannels = 2; | 213 | out_fmt.nchannels = 2; |
213 | - out_fmt.freq = s->rate->dac_hz; | 214 | + out_fmt.freq = s->dac_hz; |
214 | out_fmt.fmt = AUD_FMT_S16; | 215 | out_fmt.fmt = AUD_FMT_S16; |
215 | monoout_fmt.endianness = 0; | 216 | monoout_fmt.endianness = 0; |
216 | monoout_fmt.nchannels = 1; | 217 | monoout_fmt.nchannels = 1; |
@@ -238,12 +239,33 @@ static void wm8750_set_format(struct wm8750_s *s) | @@ -238,12 +239,33 @@ static void wm8750_set_format(struct wm8750_s *s) | ||
238 | AUD_set_active_out(*s->out[0], 1); | 239 | AUD_set_active_out(*s->out[0], 1); |
239 | } | 240 | } |
240 | 241 | ||
242 | +static void wm8750_clk_update(struct wm8750_s *s, int ext) | ||
243 | +{ | ||
244 | + if (s->master || !s->ext_dac_hz) | ||
245 | + s->dac_hz = s->rate->dac_hz; | ||
246 | + else | ||
247 | + s->dac_hz = s->ext_dac_hz; | ||
248 | + | ||
249 | + if (s->master || !s->ext_adc_hz) | ||
250 | + s->adc_hz = s->rate->adc_hz; | ||
251 | + else | ||
252 | + s->adc_hz = s->ext_adc_hz; | ||
253 | + | ||
254 | + if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) { | ||
255 | + if (!ext) | ||
256 | + wm8750_set_format(s); | ||
257 | + } else { | ||
258 | + if (ext) | ||
259 | + wm8750_set_format(s); | ||
260 | + } | ||
261 | +} | ||
262 | + | ||
241 | void wm8750_reset(i2c_slave *i2c) | 263 | void wm8750_reset(i2c_slave *i2c) |
242 | { | 264 | { |
243 | struct wm8750_s *s = (struct wm8750_s *) i2c; | 265 | struct wm8750_s *s = (struct wm8750_s *) i2c; |
244 | s->rate = &wm_rate_table[0]; | 266 | s->rate = &wm_rate_table[0]; |
245 | s->enable = 0; | 267 | s->enable = 0; |
246 | - wm8750_set_format(s); | 268 | + wm8750_clk_update(s, 1); |
247 | s->diff[0] = 0; | 269 | s->diff[0] = 0; |
248 | s->diff[1] = 0; | 270 | s->diff[1] = 0; |
249 | s->ds = 0; | 271 | s->ds = 0; |
@@ -515,17 +537,14 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data) | @@ -515,17 +537,14 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data) | ||
515 | break; | 537 | break; |
516 | 538 | ||
517 | case WM8750_IFACE: /* Digital Audio Interface Format */ | 539 | case WM8750_IFACE: /* Digital Audio Interface Format */ |
518 | -#ifdef VERBOSE | ||
519 | - if (value & 0x40) /* MS */ | ||
520 | - printf("%s: attempt to enable Master Mode\n", __FUNCTION__); | ||
521 | -#endif | ||
522 | s->format = value; | 540 | s->format = value; |
523 | - wm8750_set_format(s); | 541 | + s->master = (value >> 6) & 1; /* MS */ |
542 | + wm8750_clk_update(s, s->master); | ||
524 | break; | 543 | break; |
525 | 544 | ||
526 | case WM8750_SRATE: /* Clocking and Sample Rate Control */ | 545 | case WM8750_SRATE: /* Clocking and Sample Rate Control */ |
527 | s->rate = &wm_rate_table[(value >> 1) & 0x1f]; | 546 | s->rate = &wm_rate_table[(value >> 1) & 0x1f]; |
528 | - wm8750_set_format(s); | 547 | + wm8750_clk_update(s, 0); |
529 | break; | 548 | break; |
530 | 549 | ||
531 | case WM8750_RESET: /* Reset */ | 550 | case WM8750_RESET: /* Reset */ |
@@ -666,6 +685,7 @@ void wm8750_data_req_set(i2c_slave *i2c, | @@ -666,6 +685,7 @@ void wm8750_data_req_set(i2c_slave *i2c, | ||
666 | void wm8750_dac_dat(void *opaque, uint32_t sample) | 685 | void wm8750_dac_dat(void *opaque, uint32_t sample) |
667 | { | 686 | { |
668 | struct wm8750_s *s = (struct wm8750_s *) opaque; | 687 | struct wm8750_s *s = (struct wm8750_s *) opaque; |
688 | + | ||
669 | *(uint32_t *) &s->data_out[s->idx_out] = sample; | 689 | *(uint32_t *) &s->data_out[s->idx_out] = sample; |
670 | s->req_out -= 4; | 690 | s->req_out -= 4; |
671 | s->idx_out += 4; | 691 | s->idx_out += 4; |
@@ -695,10 +715,21 @@ uint32_t wm8750_adc_dat(void *opaque) | @@ -695,10 +715,21 @@ uint32_t wm8750_adc_dat(void *opaque) | ||
695 | { | 715 | { |
696 | struct wm8750_s *s = (struct wm8750_s *) opaque; | 716 | struct wm8750_s *s = (struct wm8750_s *) opaque; |
697 | uint32_t *data; | 717 | uint32_t *data; |
718 | + | ||
698 | if (s->idx_in >= sizeof(s->data_in)) | 719 | if (s->idx_in >= sizeof(s->data_in)) |
699 | wm8750_in_load(s); | 720 | wm8750_in_load(s); |
721 | + | ||
700 | data = (uint32_t *) &s->data_in[s->idx_in]; | 722 | data = (uint32_t *) &s->data_in[s->idx_in]; |
701 | s->req_in -= 4; | 723 | s->req_in -= 4; |
702 | s->idx_in += 4; | 724 | s->idx_in += 4; |
703 | return *data; | 725 | return *data; |
704 | } | 726 | } |
727 | + | ||
728 | +void wm8750_set_bclk_in(void *opaque, int hz) | ||
729 | +{ | ||
730 | + struct wm8750_s *s = (struct wm8750_s *) opaque; | ||
731 | + | ||
732 | + s->ext_adc_hz = hz; | ||
733 | + s->ext_dac_hz = hz; | ||
734 | + wm8750_clk_update(s, 1); | ||
735 | +} |