Commit af83e09e9e7589c28bcf66518fd20908378880c6

Authored by balrog
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
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 +}