Commit adb86c372e1596c07437682ff7aa71c905dbc14f

Authored by balrog
1 parent 3f582262

Add WM8750 and MAX7310 chips (I2C slaves).

Wolfson Microsystems WM8750 audio chip and Maxim MAX7310 gpio expander chip are used in the Spitz.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2854 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -459,8 +459,8 @@ VL_OBJS+= versatile_pci.o sd.o ptimer.o
459 459 VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
460 460 VL_OBJS+= arm-semi.o
461 461 VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
462   -VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o
463   -VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV)
  462 +VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o
  463 +VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o
464 464 CPPFLAGS += -DHAS_AUDIO
465 465 endif
466 466 ifeq ($(TARGET_BASE_ARCH), sh4)
... ...
hw/i2c.h
... ... @@ -46,4 +46,18 @@ void i2c_nack(i2c_bus *bus);
46 46 int i2c_send(i2c_bus *bus, uint8_t data);
47 47 int i2c_recv(i2c_bus *bus);
48 48  
  49 +/* max7310.c */
  50 +i2c_slave *max7310_init(i2c_bus *bus);
  51 +void max7310_reset(i2c_slave *i2c);
  52 +qemu_irq *max7310_gpio_in_get(i2c_slave *i2c);
  53 +void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler);
  54 +
  55 +/* wm8750.c */
  56 +i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio);
  57 +void wm8750_reset(i2c_slave *i2c);
  58 +void wm8750_data_req_set(i2c_slave *i2c,
  59 + void (*data_req)(void *, int, int), void *opaque);
  60 +void wm8750_dac_dat(void *opaque, uint32_t sample);
  61 +uint32_t wm8750_adc_dat(void *opaque);
  62 +
49 63 #endif
... ...
hw/max7310.c 0 → 100644
  1 +/*
  2 + * MAX7310 8-port GPIO expansion chip.
  3 + *
  4 + * Copyright (c) 2006 Openedhand Ltd.
  5 + * Written by Andrzej Zaborowski <balrog@zabor.org>
  6 + *
  7 + * This file is licensed under GNU GPL.
  8 + */
  9 +
  10 +#include "vl.h"
  11 +
  12 +struct max7310_s {
  13 + i2c_slave i2c;
  14 + int i2c_command_byte;
  15 + int len;
  16 +
  17 + uint8_t level;
  18 + uint8_t direction;
  19 + uint8_t polarity;
  20 + uint8_t status;
  21 + uint8_t command;
  22 + qemu_irq handler[8];
  23 + qemu_irq *gpio_in;
  24 +};
  25 +
  26 +void max7310_reset(i2c_slave *i2c)
  27 +{
  28 + struct max7310_s *s = (struct max7310_s *) i2c;
  29 + s->level &= s->direction;
  30 + s->direction = 0xff;
  31 + s->polarity = 0xf0;
  32 + s->status = 0x01;
  33 + s->command = 0x00;
  34 +}
  35 +
  36 +static int max7310_rx(i2c_slave *i2c)
  37 +{
  38 + struct max7310_s *s = (struct max7310_s *) i2c;
  39 +
  40 + switch (s->command) {
  41 + case 0x00: /* Input port */
  42 + return s->level ^ s->polarity;
  43 + break;
  44 +
  45 + case 0x01: /* Output port */
  46 + return s->level & ~s->direction;
  47 + break;
  48 +
  49 + case 0x02: /* Polarity inversion */
  50 + return s->polarity;
  51 +
  52 + case 0x03: /* Configuration */
  53 + return s->direction;
  54 +
  55 + case 0x04: /* Timeout */
  56 + return s->status;
  57 + break;
  58 +
  59 + case 0xff: /* Reserved */
  60 + return 0xff;
  61 +
  62 + default:
  63 +#ifdef VERBOSE
  64 + printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
  65 +#endif
  66 + break;
  67 + }
  68 + return 0xff;
  69 +}
  70 +
  71 +static int max7310_tx(i2c_slave *i2c, uint8_t data)
  72 +{
  73 + struct max7310_s *s = (struct max7310_s *) i2c;
  74 + uint8_t diff;
  75 + int line;
  76 +
  77 + if (s->len ++ > 1) {
  78 +#ifdef VERBOSE
  79 + printf("%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
  80 +#endif
  81 + return 1;
  82 + }
  83 +
  84 + if (s->i2c_command_byte) {
  85 + s->command = data;
  86 + s->i2c_command_byte = 0;
  87 + return 0;
  88 + }
  89 +
  90 + switch (s->command) {
  91 + case 0x01: /* Output port */
  92 + for (diff = (data ^ s->level) & ~s->direction; diff;
  93 + diff &= ~(1 << line)) {
  94 + line = ffs(diff) - 1;
  95 + if (s->handler[line])
  96 + qemu_set_irq(s->handler[line], (data >> line) & 1);
  97 + }
  98 + s->level = (s->level & s->direction) | (data & ~s->direction);
  99 + break;
  100 +
  101 + case 0x02: /* Polarity inversion */
  102 + s->polarity = data;
  103 + break;
  104 +
  105 + case 0x03: /* Configuration */
  106 + s->level &= ~(s->direction ^ data);
  107 + s->direction = data;
  108 + break;
  109 +
  110 + case 0x04: /* Timeout */
  111 + s->status = data;
  112 + break;
  113 +
  114 + case 0x00: /* Input port - ignore writes */
  115 + break;
  116 + default:
  117 +#ifdef VERBOSE
  118 + printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
  119 +#endif
  120 + return 1;
  121 + }
  122 +
  123 + return 0;
  124 +}
  125 +
  126 +static void max7310_event(i2c_slave *i2c, enum i2c_event event)
  127 +{
  128 + struct max7310_s *s = (struct max7310_s *) i2c;
  129 + s->len = 0;
  130 +
  131 + switch (event) {
  132 + case I2C_START_SEND:
  133 + s->i2c_command_byte = 1;
  134 + break;
  135 + case I2C_FINISH:
  136 + if (s->len == 1)
  137 +#ifdef VERBOSE
  138 + printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
  139 +#endif
  140 + break;
  141 + default:
  142 + break;
  143 + }
  144 +}
  145 +
  146 +static void max7310_gpio_set(void *opaque, int line, int level)
  147 +{
  148 + struct max7310_s *s = (struct max7310_s *) opaque;
  149 + if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0)
  150 + cpu_abort(cpu_single_env, "bad GPIO line");
  151 +
  152 + if (level)
  153 + s->level |= s->direction & (1 << line);
  154 + else
  155 + s->level &= ~(s->direction & (1 << line));
  156 +}
  157 +
  158 +/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
  159 + * but also accepts sequences that are not SMBus so return an I2C device. */
  160 +struct i2c_slave *max7310_init(i2c_bus *bus)
  161 +{
  162 + struct max7310_s *s = (struct max7310_s *)
  163 + i2c_slave_init(bus, 0, sizeof(struct max7310_s));
  164 + s->i2c.event = max7310_event;
  165 + s->i2c.recv = max7310_rx;
  166 + s->i2c.send = max7310_tx;
  167 + s->gpio_in = qemu_allocate_irqs(max7310_gpio_set, s,
  168 + sizeof(s->handler) / sizeof(*s->handler));
  169 +
  170 + max7310_reset(&s->i2c);
  171 +
  172 + return &s->i2c;
  173 +}
  174 +
  175 +qemu_irq *max7310_gpio_in_get(i2c_slave *i2c)
  176 +{
  177 + struct max7310_s *s = (struct max7310_s *) i2c;
  178 + return s->gpio_in;
  179 +}
  180 +
  181 +void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler)
  182 +{
  183 + struct max7310_s *s = (struct max7310_s *) i2c;
  184 + if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0)
  185 + cpu_abort(cpu_single_env, "bad GPIO line");
  186 +
  187 + s->handler[line] = handler;
  188 +}
... ...
hw/spitz.c
... ... @@ -801,6 +801,57 @@ static void spitz_microdrive_attach(struct pxa2xx_state_s *cpu)
801 801 }
802 802 }
803 803  
  804 +/* Wm8750 and Max7310 on I2C */
  805 +
  806 +#define AKITA_MAX_ADDR 0x18
  807 +#define SPITZ_WM_ADDRL 0x1a
  808 +#define SPITZ_WM_ADDRH 0x1b
  809 +
  810 +#define SPITZ_GPIO_WM 5
  811 +
  812 +#ifdef HAS_AUDIO
  813 +static void spitz_wm8750_addr(int line, int level, void *opaque)
  814 +{
  815 + i2c_slave *wm = (i2c_slave *) opaque;
  816 + if (level)
  817 + i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
  818 + else
  819 + i2c_set_slave_address(wm, SPITZ_WM_ADDRL);
  820 +}
  821 +#endif
  822 +
  823 +static void spitz_i2c_setup(struct pxa2xx_state_s *cpu)
  824 +{
  825 + /* Attach the CPU on one end of our I2C bus. */
  826 + i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
  827 +
  828 +#ifdef HAS_AUDIO
  829 + AudioState *audio;
  830 + i2c_slave *wm;
  831 +
  832 + audio = AUD_init();
  833 + if (!audio)
  834 + return;
  835 + /* Attach a WM8750 to the bus */
  836 + wm = wm8750_init(bus, audio);
  837 +
  838 + spitz_wm8750_addr(0, 0, wm);
  839 + pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_WM, spitz_wm8750_addr, wm);
  840 + /* .. and to the sound interface. */
  841 + cpu->i2s->opaque = wm;
  842 + cpu->i2s->codec_out = wm8750_dac_dat;
  843 + cpu->i2s->codec_in = wm8750_adc_dat;
  844 + wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
  845 +#endif
  846 +}
  847 +
  848 +static void spitz_akita_i2c_setup(struct pxa2xx_state_s *cpu)
  849 +{
  850 + /* Attach a Max7310 to Akita I2C bus. */
  851 + i2c_set_slave_address(max7310_init(pxa2xx_i2c_bus(cpu->i2c[0])),
  852 + AKITA_MAX_ADDR);
  853 +}
  854 +
804 855 /* Other peripherals */
805 856  
806 857 static void spitz_charge_switch(int line, int level, void *opaque)
... ... @@ -1026,6 +1077,11 @@ static void spitz_common_init(int ram_size, int vga_ram_size,
1026 1077  
1027 1078 spitz_gpio_setup(cpu, (model == akita) ? 1 : 2);
1028 1079  
  1080 + spitz_i2c_setup(cpu);
  1081 +
  1082 + if (model == akita)
  1083 + spitz_akita_i2c_setup(cpu);
  1084 +
1029 1085 if (model == terrier)
1030 1086 /* A 6.0 GB microdrive is permanently sitting in CF slot 0. */
1031 1087 spitz_microdrive_attach(cpu);
... ...
hw/wm8750.c 0 → 100644
  1 +/*
  2 + * WM8750 audio CODEC.
  3 + *
  4 + * Copyright (c) 2006 Openedhand Ltd.
  5 + * Written by Andrzej Zaborowski <balrog@zabor.org>
  6 + *
  7 + * This file is licensed under GNU GPL.
  8 + */
  9 +
  10 +#include "vl.h"
  11 +
  12 +#define IN_PORT_N 3
  13 +#define OUT_PORT_N 3
  14 +
  15 +#define CODEC "wm8750"
  16 +
  17 +struct wm_rate_s;
  18 +struct wm8750_s {
  19 + i2c_slave i2c;
  20 + uint8_t i2c_data[2];
  21 + int i2c_len;
  22 + QEMUSoundCard card;
  23 + SWVoiceIn *adc_voice[IN_PORT_N];
  24 + SWVoiceOut *dac_voice[OUT_PORT_N];
  25 + int enable;
  26 + void (*data_req)(void *, int, int);
  27 + void *opaque;
  28 + uint8_t data_in[4096];
  29 + uint8_t data_out[4096];
  30 + int idx_in, req_in;
  31 + int idx_out, req_out;
  32 +
  33 + SWVoiceOut **out[2];
  34 + uint8_t outvol[7], outmute[2];
  35 + SWVoiceIn **in[2];
  36 + uint8_t invol[4], inmute[2];
  37 +
  38 + uint8_t diff[2], pol, ds, monomix[2], alc, mute;
  39 + uint8_t path[4], mpath[2], power, format;
  40 + uint32_t inmask, outmask;
  41 + const struct wm_rate_s *rate;
  42 +};
  43 +
  44 +static inline void wm8750_in_load(struct wm8750_s *s)
  45 +{
  46 + int acquired;
  47 + if (s->idx_in + s->req_in <= sizeof(s->data_in))
  48 + return;
  49 + s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
  50 + acquired = AUD_read(*s->in[0], s->data_in + s->idx_in,
  51 + sizeof(s->data_in) - s->idx_in);
  52 +}
  53 +
  54 +static inline void wm8750_out_flush(struct wm8750_s *s)
  55 +{
  56 + int sent;
  57 + if (!s->idx_out)
  58 + return;
  59 + sent = AUD_write(*s->out[0], s->data_out, s->idx_out);
  60 + s->idx_out = 0;
  61 +}
  62 +
  63 +static void wm8750_audio_in_cb(void *opaque, int avail_b)
  64 +{
  65 + struct wm8750_s *s = (struct wm8750_s *) opaque;
  66 + s->req_in = avail_b;
  67 + s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
  68 +
  69 +#if 0
  70 + wm8750_in_load(s);
  71 +#endif
  72 +}
  73 +
  74 +static void wm8750_audio_out_cb(void *opaque, int free_b)
  75 +{
  76 + struct wm8750_s *s = (struct wm8750_s *) opaque;
  77 + wm8750_out_flush(s);
  78 +
  79 + s->req_out = free_b;
  80 + s->data_req(s->opaque, free_b >> 2, s->req_in >> 2);
  81 +}
  82 +
  83 +struct wm_rate_s {
  84 + int adc;
  85 + int adc_hz;
  86 + int dac;
  87 + int dac_hz;
  88 +};
  89 +
  90 +static const struct wm_rate_s wm_rate_table[] = {
  91 + { 256, 48000, 256, 48000 }, /* SR: 00000 */
  92 + { 384, 48000, 384, 48000 }, /* SR: 00001 */
  93 + { 256, 48000, 1536, 8000 }, /* SR: 00010 */
  94 + { 384, 48000, 2304, 8000 }, /* SR: 00011 */
  95 + { 1536, 8000, 256, 48000 }, /* SR: 00100 */
  96 + { 2304, 8000, 384, 48000 }, /* SR: 00101 */
  97 + { 1536, 8000, 1536, 8000 }, /* SR: 00110 */
  98 + { 2304, 8000, 2304, 8000 }, /* SR: 00111 */
  99 + { 1024, 12000, 1024, 12000 }, /* SR: 01000 */
  100 + { 1526, 12000, 1536, 12000 }, /* SR: 01001 */
  101 + { 768, 16000, 768, 16000 }, /* SR: 01010 */
  102 + { 1152, 16000, 1152, 16000 }, /* SR: 01011 */
  103 + { 384, 32000, 384, 32000 }, /* SR: 01100 */
  104 + { 576, 32000, 576, 32000 }, /* SR: 01101 */
  105 + { 128, 96000, 128, 96000 }, /* SR: 01110 */
  106 + { 192, 96000, 192, 96000 }, /* SR: 01111 */
  107 + { 256, 44100, 256, 44100 }, /* SR: 10000 */
  108 + { 384, 44100, 384, 44100 }, /* SR: 10001 */
  109 + { 256, 44100, 1408, 8018 }, /* SR: 10010 */
  110 + { 384, 44100, 2112, 8018 }, /* SR: 10011 */
  111 + { 1408, 8018, 256, 44100 }, /* SR: 10100 */
  112 + { 2112, 8018, 384, 44100 }, /* SR: 10101 */
  113 + { 1408, 8018, 1408, 8018 }, /* SR: 10110 */
  114 + { 2112, 8018, 2112, 8018 }, /* SR: 10111 */
  115 + { 1024, 11025, 1024, 11025 }, /* SR: 11000 */
  116 + { 1536, 11025, 1536, 11025 }, /* SR: 11001 */
  117 + { 512, 22050, 512, 22050 }, /* SR: 11010 */
  118 + { 768, 22050, 768, 22050 }, /* SR: 11011 */
  119 + { 512, 24000, 512, 24000 }, /* SR: 11100 */
  120 + { 768, 24000, 768, 24000 }, /* SR: 11101 */
  121 + { 128, 88200, 128, 88200 }, /* SR: 11110 */
  122 + { 192, 88200, 128, 88200 }, /* SR: 11111 */
  123 +};
  124 +
  125 +void wm8750_set_format(struct wm8750_s *s)
  126 +{
  127 + int i;
  128 + audsettings_t in_fmt;
  129 + audsettings_t out_fmt;
  130 + audsettings_t monoout_fmt;
  131 +
  132 + wm8750_out_flush(s);
  133 +
  134 + if (s->in[0] && *s->in[0])
  135 + AUD_set_active_in(*s->in[0], 0);
  136 + if (s->out[0] && *s->out[0])
  137 + AUD_set_active_out(*s->out[0], 0);
  138 +
  139 + for (i = 0; i < IN_PORT_N; i ++)
  140 + if (s->adc_voice[i]) {
  141 + AUD_close_in(&s->card, s->adc_voice[i]);
  142 + s->adc_voice[i] = 0;
  143 + }
  144 + for (i = 0; i < OUT_PORT_N; i ++)
  145 + if (s->dac_voice[i]) {
  146 + AUD_close_out(&s->card, s->dac_voice[i]);
  147 + s->dac_voice[i] = 0;
  148 + }
  149 +
  150 + if (!s->enable)
  151 + return;
  152 +
  153 + /* Setup input */
  154 + in_fmt.endianness = 0;
  155 + in_fmt.nchannels = 2;
  156 + in_fmt.freq = s->rate->adc_hz;
  157 + in_fmt.fmt = AUD_FMT_S16;
  158 +
  159 + s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
  160 + CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
  161 + s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
  162 + CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
  163 + s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
  164 + CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
  165 +
  166 + /* Setup output */
  167 + out_fmt.endianness = 0;
  168 + out_fmt.nchannels = 2;
  169 + out_fmt.freq = s->rate->dac_hz;
  170 + out_fmt.fmt = AUD_FMT_S16;
  171 + monoout_fmt.endianness = 0;
  172 + monoout_fmt.nchannels = 1;
  173 + monoout_fmt.freq = s->rate->dac_hz;
  174 + monoout_fmt.fmt = AUD_FMT_S16;
  175 +
  176 + s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
  177 + CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
  178 + s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
  179 + CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
  180 + /* MONOMIX is also in stereo for simplicity */
  181 + s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
  182 + CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
  183 + /* no sense emulating OUT3 which is a mix of other outputs */
  184 +
  185 + /* We should connect the left and right channels to their
  186 + * respective inputs/outputs but we have completely no need
  187 + * for mixing or combining paths to different ports, so we
  188 + * connect both channels to where the left channel is routed. */
  189 + if (s->in[0] && *s->in[0])
  190 + AUD_set_active_in(*s->in[0], 1);
  191 + if (s->out[0] && *s->out[0])
  192 + AUD_set_active_out(*s->out[0], 1);
  193 +}
  194 +
  195 +void inline wm8750_mask_update(struct wm8750_s *s)
  196 +{
  197 +#define R_ONLY 0x0000ffff
  198 +#define L_ONLY 0xffff0000
  199 +#define BOTH (R_ONLY | L_ONLY)
  200 +#define NONE (R_ONLY & L_ONLY)
  201 + s->inmask =
  202 + (s->inmute[0] ? R_ONLY : BOTH) &
  203 + (s->inmute[1] ? L_ONLY : BOTH) &
  204 + (s->mute ? NONE : BOTH);
  205 + s->outmask =
  206 + (s->outmute[0] ? R_ONLY : BOTH) &
  207 + (s->outmute[1] ? L_ONLY : BOTH) &
  208 + (s->mute ? NONE : BOTH);
  209 +}
  210 +
  211 +void wm8750_reset(i2c_slave *i2c)
  212 +{
  213 + struct wm8750_s *s = (struct wm8750_s *) i2c;
  214 + s->enable = 0;
  215 + wm8750_set_format(s);
  216 + s->diff[0] = 0;
  217 + s->diff[1] = 0;
  218 + s->ds = 0;
  219 + s->alc = 0;
  220 + s->in[0] = &s->adc_voice[0];
  221 + s->invol[0] = 0x17;
  222 + s->invol[1] = 0x17;
  223 + s->invol[2] = 0xc3;
  224 + s->invol[3] = 0xc3;
  225 + s->out[0] = &s->dac_voice[0];
  226 + s->outvol[0] = 0xff;
  227 + s->outvol[1] = 0xff;
  228 + s->outvol[2] = 0x79;
  229 + s->outvol[3] = 0x79;
  230 + s->outvol[4] = 0x79;
  231 + s->outvol[5] = 0x79;
  232 + s->inmute[0] = 0;
  233 + s->inmute[1] = 0;
  234 + s->outmute[0] = 0;
  235 + s->outmute[1] = 0;
  236 + s->mute = 1;
  237 + s->path[0] = 0;
  238 + s->path[1] = 0;
  239 + s->path[2] = 0;
  240 + s->path[3] = 0;
  241 + s->mpath[0] = 0;
  242 + s->mpath[1] = 0;
  243 + s->format = 0x0a;
  244 + s->idx_in = sizeof(s->data_in);
  245 + s->req_in = 0;
  246 + s->idx_out = 0;
  247 + s->req_out = 0;
  248 + wm8750_mask_update(s);
  249 + s->i2c_len = 0;
  250 +}
  251 +
  252 +static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
  253 +{
  254 + struct wm8750_s *s = (struct wm8750_s *) i2c;
  255 +
  256 + switch (event) {
  257 + case I2C_START_SEND:
  258 + s->i2c_len = 0;
  259 + break;
  260 + case I2C_FINISH:
  261 +#ifdef VERBOSE
  262 + if (s->i2c_len < 2)
  263 + printf("%s: message too short (%i bytes)\n",
  264 + __FUNCTION__, s->i2c_len);
  265 +#endif
  266 + break;
  267 + default:
  268 + break;
  269 + }
  270 +}
  271 +
  272 +#define WM8750_LINVOL 0x00
  273 +#define WM8750_RINVOL 0x01
  274 +#define WM8750_LOUT1V 0x02
  275 +#define WM8750_ROUT1V 0x03
  276 +#define WM8750_ADCDAC 0x05
  277 +#define WM8750_IFACE 0x07
  278 +#define WM8750_SRATE 0x08
  279 +#define WM8750_LDAC 0x0a
  280 +#define WM8750_RDAC 0x0b
  281 +#define WM8750_BASS 0x0c
  282 +#define WM8750_TREBLE 0x0d
  283 +#define WM8750_RESET 0x0f
  284 +#define WM8750_3D 0x10
  285 +#define WM8750_ALC1 0x11
  286 +#define WM8750_ALC2 0x12
  287 +#define WM8750_ALC3 0x13
  288 +#define WM8750_NGATE 0x14
  289 +#define WM8750_LADC 0x15
  290 +#define WM8750_RADC 0x16
  291 +#define WM8750_ADCTL1 0x17
  292 +#define WM8750_ADCTL2 0x18
  293 +#define WM8750_PWR1 0x19
  294 +#define WM8750_PWR2 0x1a
  295 +#define WM8750_ADCTL3 0x1b
  296 +#define WM8750_ADCIN 0x1f
  297 +#define WM8750_LADCIN 0x20
  298 +#define WM8750_RADCIN 0x21
  299 +#define WM8750_LOUTM1 0x22
  300 +#define WM8750_LOUTM2 0x23
  301 +#define WM8750_ROUTM1 0x24
  302 +#define WM8750_ROUTM2 0x25
  303 +#define WM8750_MOUTM1 0x26
  304 +#define WM8750_MOUTM2 0x27
  305 +#define WM8750_LOUT2V 0x28
  306 +#define WM8750_ROUT2V 0x29
  307 +#define WM8750_MOUTV 0x2a
  308 +
  309 +static int wm8750_tx(i2c_slave *i2c, uint8_t data)
  310 +{
  311 + struct wm8750_s *s = (struct wm8750_s *) i2c;
  312 + uint8_t cmd;
  313 + uint16_t value;
  314 +
  315 + if (s->i2c_len >= 2) {
  316 + printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
  317 +#ifdef VERBOSE
  318 + return 1;
  319 +#endif
  320 + }
  321 + s->i2c_data[s->i2c_len ++] = data;
  322 + if (s->i2c_len != 2)
  323 + return 0;
  324 +
  325 + cmd = s->i2c_data[0] >> 1;
  326 + value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
  327 +
  328 + switch (cmd) {
  329 + case WM8750_LADCIN: /* ADC Signal Path Control (Left) */
  330 + s->diff[0] = (((value >> 6) & 3) == 3); /* LINSEL */
  331 + if (s->diff[0])
  332 + s->in[0] = &s->adc_voice[0 + s->ds * 1];
  333 + else
  334 + s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
  335 + break;
  336 +
  337 + case WM8750_RADCIN: /* ADC Signal Path Control (Right) */
  338 + s->diff[1] = (((value >> 6) & 3) == 3); /* RINSEL */
  339 + if (s->diff[1])
  340 + s->in[1] = &s->adc_voice[0 + s->ds * 1];
  341 + else
  342 + s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
  343 + break;
  344 +
  345 + case WM8750_ADCIN: /* ADC Input Mode */
  346 + s->ds = (value >> 8) & 1; /* DS */
  347 + if (s->diff[0])
  348 + s->in[0] = &s->adc_voice[0 + s->ds * 1];
  349 + if (s->diff[1])
  350 + s->in[1] = &s->adc_voice[0 + s->ds * 1];
  351 + s->monomix[0] = (value >> 6) & 3; /* MONOMIX */
  352 + break;
  353 +
  354 + case WM8750_ADCTL1: /* Additional Control (1) */
  355 + s->monomix[1] = (value >> 1) & 1; /* DMONOMIX */
  356 + break;
  357 +
  358 + case WM8750_PWR1: /* Power Management (1) */
  359 + s->enable = ((value >> 6) & 7) == 3; /* VMIDSEL, VREF */
  360 + wm8750_set_format(s);
  361 + break;
  362 +
  363 + case WM8750_LINVOL: /* Left Channel PGA */
  364 + s->invol[0] = value & 0x3f; /* LINVOL */
  365 + s->inmute[0] = (value >> 7) & 1; /* LINMUTE */
  366 + wm8750_mask_update(s);
  367 + break;
  368 +
  369 + case WM8750_RINVOL: /* Right Channel PGA */
  370 + s->invol[1] = value & 0x3f; /* RINVOL */
  371 + s->inmute[1] = (value >> 7) & 1; /* RINMUTE */
  372 + wm8750_mask_update(s);
  373 + break;
  374 +
  375 + case WM8750_ADCDAC: /* ADC and DAC Control */
  376 + s->pol = (value >> 5) & 3; /* ADCPOL */
  377 + s->mute = (value >> 3) & 1; /* DACMU */
  378 + wm8750_mask_update(s);
  379 + break;
  380 +
  381 + case WM8750_ADCTL3: /* Additional Control (3) */
  382 + break;
  383 +
  384 + case WM8750_LADC: /* Left ADC Digital Volume */
  385 + s->invol[2] = value & 0xff; /* LADCVOL */
  386 + break;
  387 +
  388 + case WM8750_RADC: /* Right ADC Digital Volume */
  389 + s->invol[3] = value & 0xff; /* RADCVOL */
  390 + break;
  391 +
  392 + case WM8750_ALC1: /* ALC Control (1) */
  393 + s->alc = (value >> 7) & 3; /* ALCSEL */
  394 + break;
  395 +
  396 + case WM8750_NGATE: /* Noise Gate Control */
  397 + case WM8750_3D: /* 3D enhance */
  398 + break;
  399 +
  400 + case WM8750_LDAC: /* Left Channel Digital Volume */
  401 + s->outvol[0] = value & 0xff; /* LDACVOL */
  402 + break;
  403 +
  404 + case WM8750_RDAC: /* Right Channel Digital Volume */
  405 + s->outvol[1] = value & 0xff; /* RDACVOL */
  406 + break;
  407 +
  408 + case WM8750_BASS: /* Bass Control */
  409 + break;
  410 +
  411 + case WM8750_LOUTM1: /* Left Mixer Control (1) */
  412 + s->path[0] = (value >> 8) & 1; /* LD2LO */
  413 + break;
  414 +
  415 + case WM8750_LOUTM2: /* Left Mixer Control (2) */
  416 + s->path[1] = (value >> 8) & 1; /* RD2LO */
  417 + break;
  418 +
  419 + case WM8750_ROUTM1: /* Right Mixer Control (1) */
  420 + s->path[2] = (value >> 8) & 1; /* LD2RO */
  421 + break;
  422 +
  423 + case WM8750_ROUTM2: /* Right Mixer Control (2) */
  424 + s->path[3] = (value >> 8) & 1; /* RD2RO */
  425 + break;
  426 +
  427 + case WM8750_MOUTM1: /* Mono Mixer Control (1) */
  428 + s->mpath[0] = (value >> 8) & 1; /* LD2MO */
  429 + break;
  430 +
  431 + case WM8750_MOUTM2: /* Mono Mixer Control (2) */
  432 + s->mpath[1] = (value >> 8) & 1; /* RD2MO */
  433 + break;
  434 +
  435 + case WM8750_LOUT1V: /* LOUT1 Volume */
  436 + s->outvol[2] = value & 0x7f; /* LOUT2VOL */
  437 + break;
  438 +
  439 + case WM8750_LOUT2V: /* LOUT2 Volume */
  440 + s->outvol[4] = value & 0x7f; /* LOUT2VOL */
  441 + break;
  442 +
  443 + case WM8750_ROUT1V: /* ROUT1 Volume */
  444 + s->outvol[3] = value & 0x7f; /* ROUT2VOL */
  445 + break;
  446 +
  447 + case WM8750_ROUT2V: /* ROUT2 Volume */
  448 + s->outvol[5] = value & 0x7f; /* ROUT2VOL */
  449 + break;
  450 +
  451 + case WM8750_MOUTV: /* MONOOUT Volume */
  452 + s->outvol[6] = value & 0x7f; /* MONOOUTVOL */
  453 + break;
  454 +
  455 + case WM8750_ADCTL2: /* Additional Control (2) */
  456 + break;
  457 +
  458 + case WM8750_PWR2: /* Power Management (2) */
  459 + s->power = value & 0x7e;
  460 + break;
  461 +
  462 + case WM8750_IFACE: /* Digital Audio Interface Format */
  463 +#ifdef VERBOSE
  464 + if (value & 0x40) /* MS */
  465 + printf("%s: attempt to enable Master Mode\n", __FUNCTION__);
  466 +#endif
  467 + s->format = value;
  468 + wm8750_set_format(s);
  469 + break;
  470 +
  471 + case WM8750_SRATE: /* Clocking and Sample Rate Control */
  472 + s->rate = &wm_rate_table[(value >> 1) & 0x1f];
  473 + wm8750_set_format(s);
  474 + break;
  475 +
  476 + case WM8750_RESET: /* Reset */
  477 + wm8750_reset(&s->i2c);
  478 + break;
  479 +
  480 +#ifdef VERBOSE
  481 + default:
  482 + printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
  483 +#endif
  484 + }
  485 +
  486 + return 0;
  487 +}
  488 +
  489 +static int wm8750_rx(i2c_slave *i2c)
  490 +{
  491 + return 0x00;
  492 +}
  493 +
  494 +i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
  495 +{
  496 + struct wm8750_s *s = (struct wm8750_s *)
  497 + i2c_slave_init(bus, 0, sizeof(struct wm8750_s));
  498 + s->i2c.event = wm8750_event;
  499 + s->i2c.recv = wm8750_rx;
  500 + s->i2c.send = wm8750_tx;
  501 +
  502 + AUD_register_card(audio, CODEC, &s->card);
  503 + wm8750_reset(&s->i2c);
  504 +
  505 + return &s->i2c;
  506 +}
  507 +
  508 +void wm8750_fini(i2c_slave *i2c)
  509 +{
  510 + struct wm8750_s *s = (struct wm8750_s *) i2c;
  511 + wm8750_reset(&s->i2c);
  512 + AUD_remove_card(&s->card);
  513 + qemu_free(s);
  514 +}
  515 +
  516 +void wm8750_data_req_set(i2c_slave *i2c,
  517 + void (*data_req)(void *, int, int), void *opaque)
  518 +{
  519 + struct wm8750_s *s = (struct wm8750_s *) i2c;
  520 + s->data_req = data_req;
  521 + s->opaque = opaque;
  522 +}
  523 +
  524 +void wm8750_dac_dat(void *opaque, uint32_t sample)
  525 +{
  526 + struct wm8750_s *s = (struct wm8750_s *) opaque;
  527 + uint32_t *data = (uint32_t *) &s->data_out[s->idx_out];
  528 + *data = sample & s->outmask;
  529 + s->req_out -= 4;
  530 + s->idx_out += 4;
  531 + if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
  532 + wm8750_out_flush(s);
  533 +}
  534 +
  535 +uint32_t wm8750_adc_dat(void *opaque)
  536 +{
  537 + struct wm8750_s *s = (struct wm8750_s *) opaque;
  538 + uint32_t *data;
  539 + if (s->idx_in >= sizeof(s->data_in))
  540 + wm8750_in_load(s);
  541 + data = (uint32_t *) &s->data_in[s->idx_in];
  542 + s->req_in -= 4;
  543 + s->idx_in += 4;
  544 + return *data & s->inmask;
  545 +}
... ...