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 | 69 | uint32_t wm8750_adc_dat(void *opaque); |
| 70 | 70 | void *wm8750_dac_buffer(void *opaque, int samples); |
| 71 | 71 | void wm8750_dac_commit(void *opaque); |
| 72 | +void wm8750_set_bclk_in(void *opaque, int hz); | |
| 72 | 73 | |
| 73 | 74 | /* ssd0303.c */ |
| 74 | 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 | 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 | 315 | static uint32_t musicpal_audio_read(void *opaque, target_phys_addr_t offset) |
| 302 | 316 | { |
| 303 | 317 | musicpal_audio_state *s = opaque; |
| ... | ... | @@ -339,12 +353,14 @@ static void musicpal_audio_write(void *opaque, target_phys_addr_t offset, |
| 339 | 353 | s->play_pos = 0; |
| 340 | 354 | } |
| 341 | 355 | s->playback_mode = value; |
| 356 | + musicpal_audio_clock_update(s); | |
| 342 | 357 | break; |
| 343 | 358 | |
| 344 | 359 | case MP_AUDIO_CLOCK_DIV: |
| 345 | 360 | s->clock_div = value; |
| 346 | 361 | s->last_free = 0; |
| 347 | 362 | s->play_pos = 0; |
| 363 | + musicpal_audio_clock_update(s); | |
| 348 | 364 | break; |
| 349 | 365 | |
| 350 | 366 | case MP_AUDIO_IRQ_STATUS: | ... | ... |
hw/wm8750.c
| ... | ... | @@ -40,6 +40,7 @@ struct wm8750_s { |
| 40 | 40 | uint8_t diff[2], pol, ds, monomix[2], alc, mute; |
| 41 | 41 | uint8_t path[4], mpath[2], power, format; |
| 42 | 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 | 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 | 198 | /* Setup input */ |
| 198 | 199 | in_fmt.endianness = 0; |
| 199 | 200 | in_fmt.nchannels = 2; |
| 200 | - in_fmt.freq = s->rate->adc_hz; | |
| 201 | + in_fmt.freq = s->adc_hz; | |
| 201 | 202 | in_fmt.fmt = AUD_FMT_S16; |
| 202 | 203 | |
| 203 | 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 | 211 | /* Setup output */ |
| 211 | 212 | out_fmt.endianness = 0; |
| 212 | 213 | out_fmt.nchannels = 2; |
| 213 | - out_fmt.freq = s->rate->dac_hz; | |
| 214 | + out_fmt.freq = s->dac_hz; | |
| 214 | 215 | out_fmt.fmt = AUD_FMT_S16; |
| 215 | 216 | monoout_fmt.endianness = 0; |
| 216 | 217 | monoout_fmt.nchannels = 1; |
| ... | ... | @@ -238,12 +239,33 @@ static void wm8750_set_format(struct wm8750_s *s) |
| 238 | 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 | 263 | void wm8750_reset(i2c_slave *i2c) |
| 242 | 264 | { |
| 243 | 265 | struct wm8750_s *s = (struct wm8750_s *) i2c; |
| 244 | 266 | s->rate = &wm_rate_table[0]; |
| 245 | 267 | s->enable = 0; |
| 246 | - wm8750_set_format(s); | |
| 268 | + wm8750_clk_update(s, 1); | |
| 247 | 269 | s->diff[0] = 0; |
| 248 | 270 | s->diff[1] = 0; |
| 249 | 271 | s->ds = 0; |
| ... | ... | @@ -515,17 +537,14 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data) |
| 515 | 537 | break; |
| 516 | 538 | |
| 517 | 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 | 540 | s->format = value; |
| 523 | - wm8750_set_format(s); | |
| 541 | + s->master = (value >> 6) & 1; /* MS */ | |
| 542 | + wm8750_clk_update(s, s->master); | |
| 524 | 543 | break; |
| 525 | 544 | |
| 526 | 545 | case WM8750_SRATE: /* Clocking and Sample Rate Control */ |
| 527 | 546 | s->rate = &wm_rate_table[(value >> 1) & 0x1f]; |
| 528 | - wm8750_set_format(s); | |
| 547 | + wm8750_clk_update(s, 0); | |
| 529 | 548 | break; |
| 530 | 549 | |
| 531 | 550 | case WM8750_RESET: /* Reset */ |
| ... | ... | @@ -666,6 +685,7 @@ void wm8750_data_req_set(i2c_slave *i2c, |
| 666 | 685 | void wm8750_dac_dat(void *opaque, uint32_t sample) |
| 667 | 686 | { |
| 668 | 687 | struct wm8750_s *s = (struct wm8750_s *) opaque; |
| 688 | + | |
| 669 | 689 | *(uint32_t *) &s->data_out[s->idx_out] = sample; |
| 670 | 690 | s->req_out -= 4; |
| 671 | 691 | s->idx_out += 4; |
| ... | ... | @@ -695,10 +715,21 @@ uint32_t wm8750_adc_dat(void *opaque) |
| 695 | 715 | { |
| 696 | 716 | struct wm8750_s *s = (struct wm8750_s *) opaque; |
| 697 | 717 | uint32_t *data; |
| 718 | + | |
| 698 | 719 | if (s->idx_in >= sizeof(s->data_in)) |
| 699 | 720 | wm8750_in_load(s); |
| 721 | + | |
| 700 | 722 | data = (uint32_t *) &s->data_in[s->idx_in]; |
| 701 | 723 | s->req_in -= 4; |
| 702 | 724 | s->idx_in += 4; |
| 703 | 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 | +} | ... | ... |