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 | +} |