Use external clock in wm8750 slave mode.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4325 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
balrog 2008-05-04 12:15:51 +00:00
parent 762abf6774
commit af83e09e9e
3 changed files with 57 additions and 9 deletions

View File

@ -69,6 +69,7 @@ void wm8750_dac_dat(void *opaque, uint32_t sample);
uint32_t wm8750_adc_dat(void *opaque); uint32_t wm8750_adc_dat(void *opaque);
void *wm8750_dac_buffer(void *opaque, int samples); void *wm8750_dac_buffer(void *opaque, int samples);
void wm8750_dac_commit(void *opaque); void wm8750_dac_commit(void *opaque);
void wm8750_set_bclk_in(void *opaque, int hz);
/* ssd0303.c */ /* ssd0303.c */
void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address); void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address);

View File

@ -298,6 +298,20 @@ static void audio_callback(void *opaque, int free_out, int free_in)
qemu_irq_raise(s->irq); qemu_irq_raise(s->irq);
} }
static void musicpal_audio_clock_update(musicpal_audio_state *s)
{
int rate;
if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ)
rate = 24576000 / 64; /* 24.576MHz */
else
rate = 11289600 / 64; /* 11.2896MHz */
rate /= ((s->clock_div >> 8) & 0xff) + 1;
wm8750_set_bclk_in(s->wm, rate / 2);
}
static uint32_t musicpal_audio_read(void *opaque, target_phys_addr_t offset) static uint32_t musicpal_audio_read(void *opaque, target_phys_addr_t offset)
{ {
musicpal_audio_state *s = opaque; musicpal_audio_state *s = opaque;
@ -339,12 +353,14 @@ static void musicpal_audio_write(void *opaque, target_phys_addr_t offset,
s->play_pos = 0; s->play_pos = 0;
} }
s->playback_mode = value; s->playback_mode = value;
musicpal_audio_clock_update(s);
break; break;
case MP_AUDIO_CLOCK_DIV: case MP_AUDIO_CLOCK_DIV:
s->clock_div = value; s->clock_div = value;
s->last_free = 0; s->last_free = 0;
s->play_pos = 0; s->play_pos = 0;
musicpal_audio_clock_update(s);
break; break;
case MP_AUDIO_IRQ_STATUS: case MP_AUDIO_IRQ_STATUS:

View File

@ -40,6 +40,7 @@ struct wm8750_s {
uint8_t diff[2], pol, ds, monomix[2], alc, mute; uint8_t diff[2], pol, ds, monomix[2], alc, mute;
uint8_t path[4], mpath[2], power, format; uint8_t path[4], mpath[2], power, format;
const struct wm_rate_s *rate; const struct wm_rate_s *rate;
int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
}; };
/* pow(10.0, -i / 20.0) * 255, i = 0..42 */ /* pow(10.0, -i / 20.0) * 255, i = 0..42 */
@ -197,7 +198,7 @@ static void wm8750_set_format(struct wm8750_s *s)
/* Setup input */ /* Setup input */
in_fmt.endianness = 0; in_fmt.endianness = 0;
in_fmt.nchannels = 2; in_fmt.nchannels = 2;
in_fmt.freq = s->rate->adc_hz; in_fmt.freq = s->adc_hz;
in_fmt.fmt = AUD_FMT_S16; in_fmt.fmt = AUD_FMT_S16;
s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0], 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)
/* Setup output */ /* Setup output */
out_fmt.endianness = 0; out_fmt.endianness = 0;
out_fmt.nchannels = 2; out_fmt.nchannels = 2;
out_fmt.freq = s->rate->dac_hz; out_fmt.freq = s->dac_hz;
out_fmt.fmt = AUD_FMT_S16; out_fmt.fmt = AUD_FMT_S16;
monoout_fmt.endianness = 0; monoout_fmt.endianness = 0;
monoout_fmt.nchannels = 1; monoout_fmt.nchannels = 1;
@ -238,12 +239,33 @@ static void wm8750_set_format(struct wm8750_s *s)
AUD_set_active_out(*s->out[0], 1); AUD_set_active_out(*s->out[0], 1);
} }
static void wm8750_clk_update(struct wm8750_s *s, int ext)
{
if (s->master || !s->ext_dac_hz)
s->dac_hz = s->rate->dac_hz;
else
s->dac_hz = s->ext_dac_hz;
if (s->master || !s->ext_adc_hz)
s->adc_hz = s->rate->adc_hz;
else
s->adc_hz = s->ext_adc_hz;
if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) {
if (!ext)
wm8750_set_format(s);
} else {
if (ext)
wm8750_set_format(s);
}
}
void wm8750_reset(i2c_slave *i2c) void wm8750_reset(i2c_slave *i2c)
{ {
struct wm8750_s *s = (struct wm8750_s *) i2c; struct wm8750_s *s = (struct wm8750_s *) i2c;
s->rate = &wm_rate_table[0]; s->rate = &wm_rate_table[0];
s->enable = 0; s->enable = 0;
wm8750_set_format(s); wm8750_clk_update(s, 1);
s->diff[0] = 0; s->diff[0] = 0;
s->diff[1] = 0; s->diff[1] = 0;
s->ds = 0; s->ds = 0;
@ -515,17 +537,14 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data)
break; break;
case WM8750_IFACE: /* Digital Audio Interface Format */ case WM8750_IFACE: /* Digital Audio Interface Format */
#ifdef VERBOSE
if (value & 0x40) /* MS */
printf("%s: attempt to enable Master Mode\n", __FUNCTION__);
#endif
s->format = value; s->format = value;
wm8750_set_format(s); s->master = (value >> 6) & 1; /* MS */
wm8750_clk_update(s, s->master);
break; break;
case WM8750_SRATE: /* Clocking and Sample Rate Control */ case WM8750_SRATE: /* Clocking and Sample Rate Control */
s->rate = &wm_rate_table[(value >> 1) & 0x1f]; s->rate = &wm_rate_table[(value >> 1) & 0x1f];
wm8750_set_format(s); wm8750_clk_update(s, 0);
break; break;
case WM8750_RESET: /* Reset */ case WM8750_RESET: /* Reset */
@ -666,6 +685,7 @@ void wm8750_data_req_set(i2c_slave *i2c,
void wm8750_dac_dat(void *opaque, uint32_t sample) void wm8750_dac_dat(void *opaque, uint32_t sample)
{ {
struct wm8750_s *s = (struct wm8750_s *) opaque; struct wm8750_s *s = (struct wm8750_s *) opaque;
*(uint32_t *) &s->data_out[s->idx_out] = sample; *(uint32_t *) &s->data_out[s->idx_out] = sample;
s->req_out -= 4; s->req_out -= 4;
s->idx_out += 4; s->idx_out += 4;
@ -695,10 +715,21 @@ uint32_t wm8750_adc_dat(void *opaque)
{ {
struct wm8750_s *s = (struct wm8750_s *) opaque; struct wm8750_s *s = (struct wm8750_s *) opaque;
uint32_t *data; uint32_t *data;
if (s->idx_in >= sizeof(s->data_in)) if (s->idx_in >= sizeof(s->data_in))
wm8750_in_load(s); wm8750_in_load(s);
data = (uint32_t *) &s->data_in[s->idx_in]; data = (uint32_t *) &s->data_in[s->idx_in];
s->req_in -= 4; s->req_in -= 4;
s->idx_in += 4; s->idx_in += 4;
return *data; return *data;
} }
void wm8750_set_bclk_in(void *opaque, int hz)
{
struct wm8750_s *s = (struct wm8750_s *) opaque;
s->ext_adc_hz = hz;
s->ext_dac_hz = hz;
wm8750_clk_update(s, 1);
}