]> Git Repo - qemu.git/blobdiff - hw/wm8750.c
qemu: add qemu_free_irqs (Marcelo Tosatti)
[qemu.git] / hw / wm8750.c
index c4df1250ec87ad6680075f161220e258b287bb57..93fa6d7ff68dd2bbaec52099063aedc75fe56402 100644 (file)
@@ -40,6 +40,7 @@ struct wm8750_s {
     uint8_t diff[2], pol, ds, monomix[2], alc, mute;
     uint8_t path[4], mpath[2], power, format;
     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 */
@@ -169,9 +170,9 @@ static void wm8750_vol_update(struct wm8750_s *s)
 static void wm8750_set_format(struct wm8750_s *s)
 {
     int i;
-    audsettings_t in_fmt;
-    audsettings_t out_fmt;
-    audsettings_t monoout_fmt;
+    struct audsettings in_fmt;
+    struct audsettings out_fmt;
+    struct audsettings monoout_fmt;
 
     wm8750_out_flush(s);
 
@@ -197,7 +198,7 @@ static void wm8750_set_format(struct wm8750_s *s)
     /* Setup input */
     in_fmt.endianness = 0;
     in_fmt.nchannels = 2;
-    in_fmt.freq = s->rate->adc_hz;
+    in_fmt.freq = s->adc_hz;
     in_fmt.fmt = AUD_FMT_S16;
 
     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 */
     out_fmt.endianness = 0;
     out_fmt.nchannels = 2;
-    out_fmt.freq = s->rate->dac_hz;
+    out_fmt.freq = s->dac_hz;
     out_fmt.fmt = AUD_FMT_S16;
     monoout_fmt.endianness = 0;
     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);
 }
 
+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)
 {
     struct wm8750_s *s = (struct wm8750_s *) i2c;
     s->rate = &wm_rate_table[0];
     s->enable = 0;
-    wm8750_set_format(s);
+    wm8750_clk_update(s, 1);
     s->diff[0] = 0;
     s->diff[1] = 0;
     s->ds = 0;
@@ -515,17 +537,14 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data)
         break;
 
     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;
-        wm8750_set_format(s);
+        s->master = (value >> 6) & 1;                  /* MS */
+        wm8750_clk_update(s, s->master);
         break;
 
     case WM8750_SRATE: /* Clocking and Sample Rate Control */
         s->rate = &wm_rate_table[(value >> 1) & 0x1f];
-        wm8750_set_format(s);
+        wm8750_clk_update(s, 0);
         break;
 
     case WM8750_RESET: /* Reset */
@@ -627,8 +646,6 @@ static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static int wm8750_iid = 0;
-
 i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
 {
     struct wm8750_s *s = (struct wm8750_s *)
@@ -640,7 +657,7 @@ i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
     AUD_register_card(audio, CODEC, &s->card);
     wm8750_reset(&s->i2c);
 
-    register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s);
+    register_savevm(CODEC, -1, 0, wm8750_save, wm8750_load, s);
 
     return &s->i2c;
 }
@@ -666,6 +683,7 @@ void wm8750_data_req_set(i2c_slave *i2c,
 void wm8750_dac_dat(void *opaque, uint32_t sample)
 {
     struct wm8750_s *s = (struct wm8750_s *) opaque;
+
     *(uint32_t *) &s->data_out[s->idx_out] = sample;
     s->req_out -= 4;
     s->idx_out += 4;
@@ -695,10 +713,21 @@ uint32_t wm8750_adc_dat(void *opaque)
 {
     struct wm8750_s *s = (struct wm8750_s *) opaque;
     uint32_t *data;
+
     if (s->idx_in >= sizeof(s->data_in))
         wm8750_in_load(s);
+
     data = (uint32_t *) &s->data_in[s->idx_in];
     s->req_in -= 4;
     s->idx_in += 4;
     return *data;
 }
+
+void wm8750_set_bclk_in(void *opaque, int new_hz)
+{
+    struct wm8750_s *s = (struct wm8750_s *) opaque;
+
+    s->ext_adc_hz = new_hz;
+    s->ext_dac_hz = new_hz;
+    wm8750_clk_update(s, 1);
+}
This page took 0.027272 seconds and 4 git commands to generate.