Commit 73560bc8e347e8c71bd646e977282efab204ff44
1 parent
79b02417
Clean-up/rewrite audio over I^2S support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3704 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
227 additions
and
110 deletions
hw/omap.c
... | ... | @@ -997,7 +997,8 @@ static void omap_dma_clk_update(void *opaque, int line, int on) |
997 | 997 | struct omap_dma_s *s = (struct omap_dma_s *) opaque; |
998 | 998 | |
999 | 999 | if (on) { |
1000 | - s->delay = ticks_per_sec >> 7; | |
1000 | + /* TODO: make a clever calculation */ | |
1001 | + s->delay = ticks_per_sec >> 8; | |
1001 | 1002 | if (s->run_count) |
1002 | 1003 | qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); |
1003 | 1004 | } else { |
... | ... | @@ -4097,8 +4098,11 @@ struct omap_mcbsp_s { |
4097 | 4098 | int tx_rate; |
4098 | 4099 | int rx_rate; |
4099 | 4100 | int tx_req; |
4101 | + int rx_req; | |
4100 | 4102 | |
4101 | 4103 | struct i2s_codec_s *codec; |
4104 | + QEMUTimer *source_timer; | |
4105 | + QEMUTimer *sink_timer; | |
4102 | 4106 | }; |
4103 | 4107 | |
4104 | 4108 | static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) |
... | ... | @@ -4134,88 +4138,149 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) |
4134 | 4138 | qemu_set_irq(s->txirq, irq); |
4135 | 4139 | } |
4136 | 4140 | |
4137 | -static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) | |
4141 | +static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) | |
4138 | 4142 | { |
4139 | - int prev = s->tx_req; | |
4140 | - | |
4141 | - s->tx_req = (s->tx_rate || | |
4142 | - (s->spcr[0] & (1 << 12))) && /* CLKSTP */ | |
4143 | - (s->spcr[1] & (1 << 6)) && /* GRST */ | |
4144 | - (s->spcr[1] & (1 << 0)); /* XRST */ | |
4145 | - | |
4146 | - if (!s->tx_req && prev) { | |
4147 | - s->spcr[1] &= ~(1 << 1); /* XRDY */ | |
4148 | - qemu_irq_lower(s->txdrq); | |
4149 | - omap_mcbsp_intr_update(s); | |
4150 | - | |
4151 | - if (s->codec) | |
4152 | - s->codec->tx_swallow(s->codec->opaque); | |
4153 | - } else if (s->codec && s->tx_req && !prev) { | |
4154 | - s->spcr[1] |= 1 << 1; /* XRDY */ | |
4155 | - qemu_irq_raise(s->txdrq); | |
4156 | - omap_mcbsp_intr_update(s); | |
4157 | - } | |
4143 | + if ((s->spcr[0] >> 1) & 1) /* RRDY */ | |
4144 | + s->spcr[0] |= 1 << 2; /* RFULL */ | |
4145 | + s->spcr[0] |= 1 << 1; /* RRDY */ | |
4146 | + qemu_irq_raise(s->rxdrq); | |
4147 | + omap_mcbsp_intr_update(s); | |
4158 | 4148 | } |
4159 | 4149 | |
4160 | -static void omap_mcbsp_rate_update(struct omap_mcbsp_s *s) | |
4150 | +static void omap_mcbsp_source_tick(void *opaque) | |
4161 | 4151 | { |
4162 | - int rx_clk = 0, tx_clk = 0; | |
4163 | - int cpu_rate = 1500000; /* XXX */ | |
4164 | - if (!s->codec) | |
4152 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
4153 | + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; | |
4154 | + | |
4155 | + if (!s->rx_rate) | |
4165 | 4156 | return; |
4157 | + if (s->rx_req) | |
4158 | + printf("%s: Rx FIFO overrun\n", __FUNCTION__); | |
4166 | 4159 | |
4167 | - if (s->spcr[1] & (1 << 6)) { /* GRST */ | |
4168 | - if (s->spcr[0] & (1 << 0)) /* RRST */ | |
4169 | - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
4170 | - (s->pcr & (1 << 8))) /* CLKRM */ | |
4171 | - if (~s->pcr & (1 << 7)) /* SCLKME */ | |
4172 | - rx_clk = cpu_rate / | |
4173 | - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
4174 | - if (s->spcr[1] & (1 << 0)) /* XRST */ | |
4175 | - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
4176 | - (s->pcr & (1 << 9))) /* CLKXM */ | |
4177 | - if (~s->pcr & (1 << 7)) /* SCLKME */ | |
4178 | - tx_clk = cpu_rate / | |
4179 | - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
4180 | - } | |
4160 | + s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7]; | |
4181 | 4161 | |
4182 | - s->codec->set_rate(s->codec->opaque, rx_clk, tx_clk); | |
4162 | + omap_mcbsp_rx_newdata(s); | |
4163 | + qemu_mod_timer(s->source_timer, qemu_get_clock(vm_clock) + ticks_per_sec); | |
4183 | 4164 | } |
4184 | 4165 | |
4185 | 4166 | static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) |
4186 | 4167 | { |
4187 | - if (!(s->spcr[0] & 1)) { /* RRST */ | |
4188 | - if (s->codec) | |
4189 | - s->codec->in.len = 0; | |
4190 | - return; | |
4168 | + if (!s->codec || !s->codec->rts) | |
4169 | + omap_mcbsp_source_tick(s); | |
4170 | + else if (s->codec->in.len) { | |
4171 | + s->rx_req = s->codec->in.len; | |
4172 | + omap_mcbsp_rx_newdata(s); | |
4191 | 4173 | } |
4192 | - | |
4193 | - if ((s->spcr[0] >> 1) & 1) /* RRDY */ | |
4194 | - s->spcr[0] |= 1 << 2; /* RFULL */ | |
4195 | - s->spcr[0] |= 1 << 1; /* RRDY */ | |
4196 | - qemu_irq_raise(s->rxdrq); | |
4197 | - omap_mcbsp_intr_update(s); | |
4198 | 4174 | } |
4199 | 4175 | |
4200 | 4176 | static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) |
4201 | 4177 | { |
4178 | + qemu_del_timer(s->source_timer); | |
4179 | +} | |
4180 | + | |
4181 | +static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) | |
4182 | +{ | |
4202 | 4183 | s->spcr[0] &= ~(1 << 1); /* RRDY */ |
4203 | 4184 | qemu_irq_lower(s->rxdrq); |
4204 | 4185 | omap_mcbsp_intr_update(s); |
4205 | 4186 | } |
4206 | 4187 | |
4207 | -static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) | |
4188 | +static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) | |
4189 | +{ | |
4190 | + s->spcr[1] |= 1 << 1; /* XRDY */ | |
4191 | + qemu_irq_raise(s->txdrq); | |
4192 | + omap_mcbsp_intr_update(s); | |
4193 | +} | |
4194 | + | |
4195 | +static void omap_mcbsp_sink_tick(void *opaque) | |
4208 | 4196 | { |
4209 | - if (s->tx_rate) | |
4197 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
4198 | + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; | |
4199 | + | |
4200 | + if (!s->tx_rate) | |
4210 | 4201 | return; |
4211 | - s->tx_rate = 1; | |
4212 | - omap_mcbsp_req_update(s); | |
4202 | + if (s->tx_req) | |
4203 | + printf("%s: Tx FIFO underrun\n", __FUNCTION__); | |
4204 | + | |
4205 | + s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7]; | |
4206 | + | |
4207 | + omap_mcbsp_tx_newdata(s); | |
4208 | + qemu_mod_timer(s->sink_timer, qemu_get_clock(vm_clock) + ticks_per_sec); | |
4209 | +} | |
4210 | + | |
4211 | +static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) | |
4212 | +{ | |
4213 | + if (!s->codec || !s->codec->cts) | |
4214 | + omap_mcbsp_sink_tick(s); | |
4215 | + else if (s->codec->out.size) { | |
4216 | + s->tx_req = s->codec->out.size; | |
4217 | + omap_mcbsp_tx_newdata(s); | |
4218 | + } | |
4219 | +} | |
4220 | + | |
4221 | +static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s) | |
4222 | +{ | |
4223 | + s->spcr[1] &= ~(1 << 1); /* XRDY */ | |
4224 | + qemu_irq_lower(s->txdrq); | |
4225 | + omap_mcbsp_intr_update(s); | |
4226 | + if (s->codec && s->codec->cts) | |
4227 | + s->codec->tx_swallow(s->codec->opaque); | |
4213 | 4228 | } |
4214 | 4229 | |
4215 | 4230 | static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) |
4216 | 4231 | { |
4217 | - s->tx_rate = 0; | |
4218 | - omap_mcbsp_req_update(s); | |
4232 | + s->tx_req = 0; | |
4233 | + omap_mcbsp_tx_done(s); | |
4234 | + qemu_del_timer(s->sink_timer); | |
4235 | +} | |
4236 | + | |
4237 | +static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) | |
4238 | +{ | |
4239 | + int prev_rx_rate, prev_tx_rate; | |
4240 | + int rx_rate = 0, tx_rate = 0; | |
4241 | + int cpu_rate = 1500000; /* XXX */ | |
4242 | + | |
4243 | + /* TODO: check CLKSTP bit */ | |
4244 | + if (s->spcr[1] & (1 << 6)) { /* GRST */ | |
4245 | + if (s->spcr[0] & (1 << 0)) { /* RRST */ | |
4246 | + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
4247 | + (s->pcr & (1 << 8))) { /* CLKRM */ | |
4248 | + if (~s->pcr & (1 << 7)) /* SCLKME */ | |
4249 | + rx_rate = cpu_rate / | |
4250 | + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
4251 | + } else | |
4252 | + if (s->codec) | |
4253 | + rx_rate = s->codec->rx_rate; | |
4254 | + } | |
4255 | + | |
4256 | + if (s->spcr[1] & (1 << 0)) { /* XRST */ | |
4257 | + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
4258 | + (s->pcr & (1 << 9))) { /* CLKXM */ | |
4259 | + if (~s->pcr & (1 << 7)) /* SCLKME */ | |
4260 | + tx_rate = cpu_rate / | |
4261 | + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
4262 | + } else | |
4263 | + if (s->codec) | |
4264 | + tx_rate = s->codec->tx_rate; | |
4265 | + } | |
4266 | + } | |
4267 | + prev_tx_rate = s->tx_rate; | |
4268 | + prev_rx_rate = s->rx_rate; | |
4269 | + s->tx_rate = tx_rate; | |
4270 | + s->rx_rate = rx_rate; | |
4271 | + | |
4272 | + if (s->codec) | |
4273 | + s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate); | |
4274 | + | |
4275 | + if (!prev_tx_rate && tx_rate) | |
4276 | + omap_mcbsp_tx_start(s); | |
4277 | + else if (s->tx_rate && !tx_rate) | |
4278 | + omap_mcbsp_tx_stop(s); | |
4279 | + | |
4280 | + if (!prev_rx_rate && rx_rate) | |
4281 | + omap_mcbsp_rx_start(s); | |
4282 | + else if (prev_tx_rate && !tx_rate) | |
4283 | + omap_mcbsp_rx_stop(s); | |
4219 | 4284 | } |
4220 | 4285 | |
4221 | 4286 | static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) |
... | ... | @@ -4230,17 +4295,19 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) |
4230 | 4295 | return 0x0000; |
4231 | 4296 | /* Fall through. */ |
4232 | 4297 | case 0x02: /* DRR1 */ |
4233 | - if (!s->codec) | |
4234 | - return 0x0000; | |
4235 | - if (s->codec->in.len < 2) { | |
4298 | + if (s->rx_req < 2) { | |
4236 | 4299 | printf("%s: Rx FIFO underrun\n", __FUNCTION__); |
4237 | - omap_mcbsp_rx_stop(s); | |
4300 | + omap_mcbsp_rx_done(s); | |
4238 | 4301 | } else { |
4239 | - s->codec->in.len -= 2; | |
4240 | - ret = s->codec->in.fifo[s->codec->in.start ++] << 8; | |
4241 | - ret |= s->codec->in.fifo[s->codec->in.start ++]; | |
4242 | - if (!s->codec->in.len) | |
4243 | - omap_mcbsp_rx_stop(s); | |
4302 | + s->tx_req -= 2; | |
4303 | + if (s->codec && s->codec->in.len >= 2) { | |
4304 | + ret = s->codec->in.fifo[s->codec->in.start ++] << 8; | |
4305 | + ret |= s->codec->in.fifo[s->codec->in.start ++]; | |
4306 | + s->codec->in.len -= 2; | |
4307 | + } else | |
4308 | + ret = 0x0000; | |
4309 | + if (!s->tx_req) | |
4310 | + omap_mcbsp_rx_done(s); | |
4244 | 4311 | return ret; |
4245 | 4312 | } |
4246 | 4313 | return 0x0000; |
... | ... | @@ -4309,7 +4376,7 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) |
4309 | 4376 | return 0; |
4310 | 4377 | } |
4311 | 4378 | |
4312 | -static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, | |
4379 | +static void omap_mcbsp_writeh(void *opaque, target_phys_addr_t addr, | |
4313 | 4380 | uint32_t value) |
4314 | 4381 | { |
4315 | 4382 | struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; |
... | ... | @@ -4326,18 +4393,14 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
4326 | 4393 | return; |
4327 | 4394 | /* Fall through. */ |
4328 | 4395 | case 0x06: /* DXR1 */ |
4329 | - if (!s->codec) | |
4330 | - return; | |
4331 | - if (s->tx_req) { | |
4332 | - if (s->codec->out.len > s->codec->out.size - 2) { | |
4333 | - printf("%s: Tx FIFO overrun\n", __FUNCTION__); | |
4334 | - omap_mcbsp_tx_stop(s); | |
4335 | - } else { | |
4396 | + if (s->tx_req > 1) { | |
4397 | + s->tx_req -= 2; | |
4398 | + if (s->codec && s->codec->cts) { | |
4336 | 4399 | s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; |
4337 | 4400 | s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; |
4338 | - if (s->codec->out.len >= s->codec->out.size) | |
4339 | - omap_mcbsp_tx_stop(s); | |
4340 | 4401 | } |
4402 | + if (s->tx_req < 2) | |
4403 | + omap_mcbsp_tx_done(s); | |
4341 | 4404 | } else |
4342 | 4405 | printf("%s: Tx FIFO overrun\n", __FUNCTION__); |
4343 | 4406 | return; |
... | ... | @@ -4346,14 +4409,8 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
4346 | 4409 | s->spcr[1] &= 0x0002; |
4347 | 4410 | s->spcr[1] |= 0x03f9 & value; |
4348 | 4411 | s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ |
4349 | - if (~value & 1) { /* XRST */ | |
4412 | + if (~value & 1) /* XRST */ | |
4350 | 4413 | s->spcr[1] &= ~6; |
4351 | - qemu_irq_lower(s->rxdrq); | |
4352 | - if (s->codec) | |
4353 | - s->codec->out.len = 0; | |
4354 | - } | |
4355 | - if (s->codec) | |
4356 | - omap_mcbsp_rate_update(s); | |
4357 | 4414 | omap_mcbsp_req_update(s); |
4358 | 4415 | return; |
4359 | 4416 | case 0x0a: /* SPCR1 */ |
... | ... | @@ -4363,12 +4420,9 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
4363 | 4420 | printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); |
4364 | 4421 | if (~value & 1) { /* RRST */ |
4365 | 4422 | s->spcr[0] &= ~6; |
4366 | - qemu_irq_lower(s->txdrq); | |
4367 | - if (s->codec) | |
4368 | - s->codec->in.len = 0; | |
4423 | + s->rx_req = 0; | |
4424 | + omap_mcbsp_rx_done(s); | |
4369 | 4425 | } |
4370 | - if (s->codec) | |
4371 | - omap_mcbsp_rate_update(s); | |
4372 | 4426 | omap_mcbsp_req_update(s); |
4373 | 4427 | return; |
4374 | 4428 | |
... | ... | @@ -4386,11 +4440,11 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
4386 | 4440 | return; |
4387 | 4441 | case 0x14: /* SRGR2 */ |
4388 | 4442 | s->srgr[1] = value & 0xffff; |
4389 | - omap_mcbsp_rate_update(s); | |
4443 | + omap_mcbsp_req_update(s); | |
4390 | 4444 | return; |
4391 | 4445 | case 0x16: /* SRGR1 */ |
4392 | 4446 | s->srgr[0] = value & 0xffff; |
4393 | - omap_mcbsp_rate_update(s); | |
4447 | + omap_mcbsp_req_update(s); | |
4394 | 4448 | return; |
4395 | 4449 | case 0x18: /* MCR2 */ |
4396 | 4450 | s->mcr[1] = value & 0x03e3; |
... | ... | @@ -4460,6 +4514,37 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
4460 | 4514 | OMAP_BAD_REG(addr); |
4461 | 4515 | } |
4462 | 4516 | |
4517 | +static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr, | |
4518 | + uint32_t value) | |
4519 | +{ | |
4520 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
4521 | + int offset = addr & OMAP_MPUI_REG_MASK; | |
4522 | + | |
4523 | + if (offset == 0x04) { /* DXR */ | |
4524 | + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ | |
4525 | + return; | |
4526 | + if (s->tx_req > 3) { | |
4527 | + s->tx_req -= 4; | |
4528 | + if (s->codec && s->codec->cts) { | |
4529 | + s->codec->out.fifo[s->codec->out.len ++] = | |
4530 | + (value >> 24) & 0xff; | |
4531 | + s->codec->out.fifo[s->codec->out.len ++] = | |
4532 | + (value >> 16) & 0xff; | |
4533 | + s->codec->out.fifo[s->codec->out.len ++] = | |
4534 | + (value >> 8) & 0xff; | |
4535 | + s->codec->out.fifo[s->codec->out.len ++] = | |
4536 | + (value >> 0) & 0xff; | |
4537 | + } | |
4538 | + if (s->tx_req < 4) | |
4539 | + omap_mcbsp_tx_done(s); | |
4540 | + } else | |
4541 | + printf("%s: Tx FIFO overrun\n", __FUNCTION__); | |
4542 | + return; | |
4543 | + } | |
4544 | + | |
4545 | + omap_badwidth_write16(opaque, addr, value); | |
4546 | +} | |
4547 | + | |
4463 | 4548 | static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { |
4464 | 4549 | omap_badwidth_read16, |
4465 | 4550 | omap_mcbsp_read, |
... | ... | @@ -4468,8 +4553,8 @@ static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { |
4468 | 4553 | |
4469 | 4554 | static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = { |
4470 | 4555 | omap_badwidth_write16, |
4471 | - omap_mcbsp_write, | |
4472 | - omap_badwidth_write16, | |
4556 | + omap_mcbsp_writeh, | |
4557 | + omap_mcbsp_writew, | |
4473 | 4558 | }; |
4474 | 4559 | |
4475 | 4560 | static void omap_mcbsp_reset(struct omap_mcbsp_s *s) |
... | ... | @@ -4484,8 +4569,11 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s) |
4484 | 4569 | memset(&s->rcer, 0, sizeof(s->rcer)); |
4485 | 4570 | memset(&s->xcer, 0, sizeof(s->xcer)); |
4486 | 4571 | s->tx_req = 0; |
4572 | + s->rx_req = 0; | |
4487 | 4573 | s->tx_rate = 0; |
4488 | 4574 | s->rx_rate = 0; |
4575 | + qemu_del_timer(s->source_timer); | |
4576 | + qemu_del_timer(s->sink_timer); | |
4489 | 4577 | } |
4490 | 4578 | |
4491 | 4579 | struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, |
... | ... | @@ -4500,6 +4588,8 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, |
4500 | 4588 | s->rxirq = irq[1]; |
4501 | 4589 | s->txdrq = dma[0]; |
4502 | 4590 | s->rxdrq = dma[1]; |
4591 | + s->sink_timer = qemu_new_timer(vm_clock, omap_mcbsp_sink_tick, s); | |
4592 | + s->source_timer = qemu_new_timer(vm_clock, omap_mcbsp_source_tick, s); | |
4503 | 4593 | omap_mcbsp_reset(s); |
4504 | 4594 | |
4505 | 4595 | iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn, |
... | ... | @@ -4513,14 +4603,20 @@ static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) |
4513 | 4603 | { |
4514 | 4604 | struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; |
4515 | 4605 | |
4516 | - omap_mcbsp_rx_start(s); | |
4606 | + if (s->rx_rate) { | |
4607 | + s->rx_req = s->codec->in.len; | |
4608 | + omap_mcbsp_rx_newdata(s); | |
4609 | + } | |
4517 | 4610 | } |
4518 | 4611 | |
4519 | 4612 | static void omap_mcbsp_i2s_start(void *opaque, int line, int level) |
4520 | 4613 | { |
4521 | 4614 | struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; |
4522 | 4615 | |
4523 | - omap_mcbsp_tx_start(s); | |
4616 | + if (s->tx_rate) { | |
4617 | + s->tx_req = s->codec->out.size; | |
4618 | + omap_mcbsp_tx_newdata(s); | |
4619 | + } | |
4524 | 4620 | } |
4525 | 4621 | |
4526 | 4622 | void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave) | ... | ... |
hw/omap.h
hw/tsc210x.c
... | ... | @@ -283,10 +283,30 @@ static void tsc210x_audio_out_cb(struct tsc210x_state_s *s, int free_b) |
283 | 283 | qemu_irq_raise(s->codec.tx_start); |
284 | 284 | } |
285 | 285 | |
286 | -static void tsc2102_audio_set_format(struct tsc210x_state_s *s) | |
286 | +static void tsc2102_audio_rate_update(struct tsc210x_state_s *s) | |
287 | 287 | { |
288 | - int enable; | |
289 | 288 | const struct tsc210x_rate_info_s *rate; |
289 | + | |
290 | + s->codec.tx_rate = 0; | |
291 | + s->codec.rx_rate = 0; | |
292 | + if (s->dac_power & (1 << 15)) /* PWDNC */ | |
293 | + return; | |
294 | + | |
295 | + for (rate = tsc2102_rates; rate->rate; rate ++) | |
296 | + if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ | |
297 | + rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ | |
298 | + break; | |
299 | + if (!rate->rate) { | |
300 | + printf("%s: unknown sampling rate configured\n", __FUNCTION__); | |
301 | + return; | |
302 | + } | |
303 | + | |
304 | + s->codec.tx_rate = rate->rate; | |
305 | +} | |
306 | + | |
307 | +static void tsc2102_audio_output_update(struct tsc210x_state_s *s) | |
308 | +{ | |
309 | + int enable; | |
290 | 310 | audsettings_t fmt; |
291 | 311 | |
292 | 312 | if (s->dac_voice[0]) { |
... | ... | @@ -296,32 +316,26 @@ static void tsc2102_audio_set_format(struct tsc210x_state_s *s) |
296 | 316 | AUD_close_out(&s->card, s->dac_voice[0]); |
297 | 317 | s->dac_voice[0] = 0; |
298 | 318 | } |
319 | + s->codec.cts = 0; | |
299 | 320 | |
300 | 321 | enable = |
301 | 322 | (~s->dac_power & (1 << 15)) && /* PWDNC */ |
302 | 323 | (~s->dac_power & (1 << 10)); /* DAPWDN */ |
303 | - if (!enable) | |
304 | - return; | |
305 | - | |
306 | - for (rate = tsc2102_rates; rate->rate; rate ++) | |
307 | - if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ | |
308 | - rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ | |
309 | - break; | |
310 | - if (!rate->rate) { | |
311 | - printf("%s: unknown sampling rate configured\n", __FUNCTION__); | |
324 | + if (!enable || !s->codec.tx_rate) | |
312 | 325 | return; |
313 | - } | |
314 | 326 | |
315 | 327 | /* Force our own sampling rate even in slave DAC mode */ |
316 | 328 | fmt.endianness = 0; |
317 | 329 | fmt.nchannels = 2; |
318 | - fmt.freq = rate->rate; | |
330 | + fmt.freq = s->codec.tx_rate; | |
319 | 331 | fmt.fmt = AUD_FMT_S16; |
320 | 332 | |
321 | 333 | s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], |
322 | 334 | "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt); |
323 | - if (s->dac_voice[0]) | |
335 | + if (s->dac_voice[0]) { | |
336 | + s->codec.cts = 1; | |
324 | 337 | AUD_set_active_out(s->dac_voice[0], 1); |
338 | + } | |
325 | 339 | } |
326 | 340 | |
327 | 341 | static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) |
... | ... | @@ -587,8 +601,9 @@ static void tsc2102_audio_register_write( |
587 | 601 | fprintf(stderr, "tsc2102_audio_register_write: " |
588 | 602 | "wrong value written into Audio 1\n"); |
589 | 603 | #endif |
604 | + tsc2102_audio_rate_update(s); | |
590 | 605 | if (s->audio) |
591 | - tsc2102_audio_set_format(s); | |
606 | + tsc2102_audio_output_update(s); | |
592 | 607 | return; |
593 | 608 | |
594 | 609 | case 0x01: |
... | ... | @@ -631,8 +646,9 @@ static void tsc2102_audio_register_write( |
631 | 646 | fprintf(stderr, "tsc2102_audio_register_write: " |
632 | 647 | "wrong value written into Power\n"); |
633 | 648 | #endif |
649 | + tsc2102_audio_rate_update(s); | |
634 | 650 | if (s->audio) |
635 | - tsc2102_audio_set_format(s); | |
651 | + tsc2102_audio_output_update(s); | |
636 | 652 | return; |
637 | 653 | |
638 | 654 | case 0x06: /* Audio Control 3 */ |
... | ... | @@ -644,7 +660,7 @@ static void tsc2102_audio_register_write( |
644 | 660 | "wrong value written into Audio 3\n"); |
645 | 661 | #endif |
646 | 662 | if (s->audio) |
647 | - tsc2102_audio_set_format(s); | |
663 | + tsc2102_audio_output_update(s); | |
648 | 664 | return; |
649 | 665 | |
650 | 666 | case 0x07: /* LCH_BASS_BOOST_N0 */ | ... | ... |