Commit 73560bc8e347e8c71bd646e977282efab204ff44

Authored by balrog
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
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
... ... @@ -491,6 +491,11 @@ struct i2s_codec_s {
491 491 qemu_irq rx_swallow;
492 492 qemu_irq tx_start;
493 493  
  494 + int tx_rate;
  495 + int cts;
  496 + int rx_rate;
  497 + int rts;
  498 +
494 499 struct i2s_fifo_s {
495 500 uint8_t *fifo;
496 501 int len;
... ...
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 */
... ...