Esempio n. 1
0
static int
cs4281_rdcd(kobj_t obj, void *devinfo, int regno)
{
    struct sc_info *sc = (struct sc_info *)devinfo;
    int codecno;

    codecno = regno >> 8;
    regno &= 0xff;

    /* Remove old state */
    cs4281_rd(sc, CS4281PCI_ACSDA);

    /* Fill in AC97 register value request form */
    cs4281_wr(sc, CS4281PCI_ACCAD, regno);
    cs4281_wr(sc, CS4281PCI_ACCDA, 0);
    cs4281_wr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_ESYN |
	      CS4281PCI_ACCTL_VFRM | CS4281PCI_ACCTL_DCV |
	      CS4281PCI_ACCTL_CRW);

    /* Wait for read to complete */
    if (cs4281_waitclr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_DCV, 250) == 0) {
	device_printf(sc->dev, "cs4281_rdcd: DCV did not go\n");
	return -1;
    }

    /* Wait for valid status */
    if (cs4281_waitset(sc, CS4281PCI_ACSTS, CS4281PCI_ACSTS_VSTS, 250) == 0) {
	device_printf(sc->dev,"cs4281_rdcd: VSTS did not come\n");
	return -1;
    }

    return cs4281_rd(sc, CS4281PCI_ACSDA);
}
Esempio n. 2
0
static void
cs4281_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
{
    struct sc_info *sc = (struct sc_info *)devinfo;
    regno &= 0xff;

    cs4281_wr(sc, CS4281PCI_ACCAD, regno);
    cs4281_wr(sc, CS4281PCI_ACCDA, data);
    cs4281_wr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_ESYN |
	      CS4281PCI_ACCTL_VFRM | CS4281PCI_ACCTL_DCV);

    if (cs4281_waitclr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_DCV, 250) == 0) {
	device_printf(sc->dev,"cs4281_wrcd: DCV did not go\n");
    }
}
Esempio n. 3
0
static void
adcdac_prog(struct sc_chinfo *ch)
{
    struct sc_info *sc = ch->parent;
    u_int32_t go;

    if (!ch->dma_setup) {
	go = adcdac_go(ch, 0);
	cs4281_wr(sc, CS4281PCI_DBA(ch->dma_chan),
		  sndbuf_getbufaddr(ch->buffer));
	cs4281_wr(sc, CS4281PCI_DBC(ch->dma_chan),
		  sndbuf_getsize(ch->buffer) / ch->bps - 1);
	ch->dma_setup = 1;
	adcdac_go(ch, go);
    }
}
Esempio n. 4
0
static int
cs4281chan_setformat(kobj_t obj, void *data, u_int32_t format)
{
    struct sc_chinfo *ch = data;
    struct sc_info *sc = ch->parent;
    u_int32_t v, go;

    go = adcdac_go(ch, 0); /* pause */

    if (ch->dma_chan == CS4281_DMA_PLAY)
	v = CS4281PCI_DMR_TR_PLAY;
    else
	v = CS4281PCI_DMR_TR_REC;
    v |= CS4281PCI_DMR_DMA | CS4281PCI_DMR_AUTO;
    v |= cs4281_format_to_dmr(format);
    cs4281_wr(sc, CS4281PCI_DMR(ch->dma_chan), v);

    adcdac_go(ch, go); /* unpause */

    ch->fmt = format;
    ch->bps = cs4281_format_to_bps(format);
    ch->dma_setup = 0;

    return 0;
}
Esempio n. 5
0
static inline void
cs4281_set4(struct sc_info *sc, int regno, u_int32_t mask)
{
    u_int32_t v;
    v = cs4281_rd(sc, regno);
    cs4281_wr(sc, regno, v | mask);
}
Esempio n. 6
0
static inline void
cs4281_clr4(struct sc_info *sc, int regno, u_int32_t mask)
{
    u_int32_t r;
    r = cs4281_rd(sc, regno);
    cs4281_wr(sc, regno, r & ~mask);
}
Esempio n. 7
0
static u_int32_t
cs4281chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
    struct sc_chinfo *ch = data;
    struct sc_info *sc = ch->parent;
    u_int32_t go, v, r;

    go = adcdac_go(ch, 0); /* pause */
    r = (ch->dma_chan == CS4281_DMA_PLAY) ? CS4281PCI_DACSR : CS4281PCI_ADCSR;
    v = cs4281_rate_to_rv(speed);
    cs4281_wr(sc, r, v);
    adcdac_go(ch, go); /* unpause */

    ch->spd = cs4281_rv_to_rate(v);
    return ch->spd;
}
Esempio n. 8
0
static u_int32_t
adcdac_go(struct sc_chinfo *ch, u_int32_t go)
{
    struct sc_info *sc = ch->parent;
    u_int32_t going;

    going = !(cs4281_rd(sc, CS4281PCI_DCR(ch->dma_chan)) & CS4281PCI_DCR_MSK);

    if (go)
	cs4281_clr4(sc, CS4281PCI_DCR(ch->dma_chan), CS4281PCI_DCR_MSK);
    else
	cs4281_set4(sc, CS4281PCI_DCR(ch->dma_chan), CS4281PCI_DCR_MSK);

    cs4281_wr(sc, CS4281PCI_HICR, CS4281PCI_HICR_EOI);

    return going;
}
Esempio n. 9
0
static int
cs4281_power(struct sc_info *sc, int state)
{

    switch (state) {
    case 0:
        /* Permit r/w access to all BA0 registers */
        cs4281_wr(sc, CS4281PCI_CWPR, CS4281PCI_CWPR_MAGIC);
        /* Power on */
        cs4281_clr4(sc, CS4281PCI_EPPMC, CS4281PCI_EPPMC_FPDN);
        break;
    case 3:
    	/* Power off card and codec */
    	cs4281_set4(sc, CS4281PCI_EPPMC, CS4281PCI_EPPMC_FPDN);
    	cs4281_clr4(sc, CS4281PCI_SPMC, CS4281PCI_SPMC_RSTN);
        break;
    }

    DEB(printf("cs4281_power %d -> %d\n", sc->power, state));
    sc->power = state;

    return 0;
}
Esempio n. 10
0
static void
cs4281_intr(void *p)
{
    struct sc_info *sc = (struct sc_info *)p;
    u_int32_t hisr;

    hisr = cs4281_rd(sc, CS4281PCI_HISR);

    if (hisr == 0) return;

    if (hisr & CS4281PCI_HISR_DMA(CS4281_DMA_PLAY)) {
	chn_intr(sc->pch.channel);
	cs4281_rd(sc, CS4281PCI_HDSR(CS4281_DMA_PLAY)); /* Clear interrupt */
    }

    if (hisr & CS4281PCI_HISR_DMA(CS4281_DMA_REC)) {
	chn_intr(sc->rch.channel);
	cs4281_rd(sc, CS4281PCI_HDSR(CS4281_DMA_REC)); /* Clear interrupt */
    }

    /* Signal End-of-Interrupt */
    cs4281_wr(sc, CS4281PCI_HICR, CS4281PCI_HICR_EOI);
}
Esempio n. 11
0
static int
cs4281_init(struct sc_info *sc)
{
    u_int32_t i, v;

    /* (0) Blast clock register and serial port */
    cs4281_wr(sc, CS4281PCI_CLKCR1, 0);
    cs4281_wr(sc, CS4281PCI_SERMC,  0);

    /* (1) Make ESYN 0 to turn sync pulse on AC97 link */
    cs4281_wr(sc, CS4281PCI_ACCTL, 0);
    DELAY(50);

    /* (2) Effect Reset */
    cs4281_wr(sc, CS4281PCI_SPMC, 0);
    DELAY(100);
    cs4281_wr(sc, CS4281PCI_SPMC, CS4281PCI_SPMC_RSTN);
    /* Wait 50ms for ABITCLK to become stable */
    DELAY(50000);

    /* (3) Enable Sound System Clocks */
    cs4281_wr(sc, CS4281PCI_CLKCR1, CS4281PCI_CLKCR1_DLLP);
    DELAY(50000); /* Wait for PLL to stabilize */
    cs4281_wr(sc, CS4281PCI_CLKCR1,
	      CS4281PCI_CLKCR1_DLLP | CS4281PCI_CLKCR1_SWCE);

    /* (4) Power Up - this combination is essential. */
    cs4281_set4(sc, CS4281PCI_SSPM,
		CS4281PCI_SSPM_ACLEN | CS4281PCI_SSPM_PSRCEN |
		CS4281PCI_SSPM_CSRCEN | CS4281PCI_SSPM_MIXEN);

    /* (5) Wait for clock stabilization */
    if (cs4281_waitset(sc,
		       CS4281PCI_CLKCR1,
		       CS4281PCI_CLKCR1_DLLRDY,
		       250) == 0) {
	device_printf(sc->dev, "Clock stabilization failed\n");
	return -1;
    }

    /* (6) Enable ASYNC generation. */
    cs4281_wr(sc, CS4281PCI_ACCTL,CS4281PCI_ACCTL_ESYN);

    /* Wait to allow AC97 to start generating clock bit */
    DELAY(50000);

    /* Set AC97 timing */
    cs4281_wr(sc, CS4281PCI_SERMC, CS4281PCI_SERMC_PTC_AC97);

    /* (7) Wait for AC97 ready signal */
    if (cs4281_waitset(sc, CS4281PCI_ACSTS, CS4281PCI_ACSTS_CRDY, 250) == 0) {
	device_printf(sc->dev, "codec did not avail\n");
	return -1;
    }

    /* (8) Assert valid frame signal to begin sending commands to
     *     AC97 codec */
    cs4281_wr(sc,
	      CS4281PCI_ACCTL,
	      CS4281PCI_ACCTL_VFRM | CS4281PCI_ACCTL_ESYN);

    /* (9) Wait for codec calibration */
    for(i = 0 ; i < 1000; i++) {
	DELAY(10000);
	v = cs4281_rdcd(0, sc, AC97_REG_POWER);
	if ((v & 0x0f) == 0x0f) {
	    break;
	}
    }
    if (i == 1000) {
	device_printf(sc->dev, "codec failed to calibrate\n");
	return -1;
    }

    /* (10) Set AC97 timing */
    cs4281_wr(sc, CS4281PCI_SERMC, CS4281PCI_SERMC_PTC_AC97);

    /* (11) Wait for valid data to arrive */
    if (cs4281_waitset(sc,
		       CS4281PCI_ACISV,
		       CS4281PCI_ACISV_ISV(3) | CS4281PCI_ACISV_ISV(4),
		       10000) == 0) {
	device_printf(sc->dev, "cs4281 never got valid data\n");
	return -1;
    }

    /* (12) Start digital data transfer of audio data to codec */
    cs4281_wr(sc,
	      CS4281PCI_ACOSV,
	      CS4281PCI_ACOSV_SLV(3) | CS4281PCI_ACOSV_SLV(4));

    /* Set Master and headphone to max */
    cs4281_wrcd(0, sc, AC97_MIX_AUXOUT, 0);
    cs4281_wrcd(0, sc, AC97_MIX_MASTER, 0);

    /* Power on the DAC */
    v = cs4281_rdcd(0, sc, AC97_REG_POWER) & 0xfdff;
    cs4281_wrcd(0, sc, AC97_REG_POWER, v);

    /* Wait until DAC state ready */
    for(i = 0; i < 320; i++) {
	DELAY(100);
	v = cs4281_rdcd(0, sc, AC97_REG_POWER);
	if (v & 0x02) break;
    }

    /* Power on the ADC */
    v = cs4281_rdcd(0, sc, AC97_REG_POWER) & 0xfeff;
    cs4281_wrcd(0, sc, AC97_REG_POWER, v);

    /* Wait until ADC state ready */
    for(i = 0; i < 320; i++) {
	DELAY(100);
	v = cs4281_rdcd(0, sc, AC97_REG_POWER);
	if (v & 0x01) break;
    }

    /* FIFO configuration (driver is DMA orientated, implicit FIFO) */
    /* Play FIFO */

    v = CS4281PCI_FCR_RS(CS4281PCI_RPCM_PLAY_SLOT) |
	CS4281PCI_FCR_LS(CS4281PCI_LPCM_PLAY_SLOT) |
	CS4281PCI_FCR_SZ(CS4281_FIFO_SIZE)|
	CS4281PCI_FCR_OF(0);
    cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_PLAY), v);

    cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_PLAY), v | CS4281PCI_FCR_FEN);

    /* Record FIFO */
    v = CS4281PCI_FCR_RS(CS4281PCI_RPCM_REC_SLOT) |
	CS4281PCI_FCR_LS(CS4281PCI_LPCM_REC_SLOT) |
	CS4281PCI_FCR_SZ(CS4281_FIFO_SIZE)|
	CS4281PCI_FCR_OF(CS4281_FIFO_SIZE + 1);
    cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_REC), v | CS4281PCI_FCR_PSH);
    cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_REC), v | CS4281PCI_FCR_FEN);

    /* Match AC97 slots to FIFOs */
    v = CS4281PCI_SRCSA_PLSS(CS4281PCI_LPCM_PLAY_SLOT) |
	CS4281PCI_SRCSA_PRSS(CS4281PCI_RPCM_PLAY_SLOT) |
	CS4281PCI_SRCSA_CLSS(CS4281PCI_LPCM_REC_SLOT) |
	CS4281PCI_SRCSA_CRSS(CS4281PCI_RPCM_REC_SLOT);
    cs4281_wr(sc, CS4281PCI_SRCSA, v);

    /* Set Auto-Initialize and set directions */
    cs4281_wr(sc,
	      CS4281PCI_DMR(CS4281_DMA_PLAY),
	      CS4281PCI_DMR_DMA  |
	      CS4281PCI_DMR_AUTO |
	      CS4281PCI_DMR_TR_PLAY);
    cs4281_wr(sc,
	      CS4281PCI_DMR(CS4281_DMA_REC),
	      CS4281PCI_DMR_DMA  |
	      CS4281PCI_DMR_AUTO |
	      CS4281PCI_DMR_TR_REC);

    /* Enable half and empty buffer interrupts keeping DMA paused */
    cs4281_wr(sc,
	      CS4281PCI_DCR(CS4281_DMA_PLAY),
	      CS4281PCI_DCR_TCIE | CS4281PCI_DCR_HTCIE | CS4281PCI_DCR_MSK);
    cs4281_wr(sc,
	      CS4281PCI_DCR(CS4281_DMA_REC),
	      CS4281PCI_DCR_TCIE | CS4281PCI_DCR_HTCIE | CS4281PCI_DCR_MSK);

    /* Enable Interrupts */
    cs4281_clr4(sc,
		CS4281PCI_HIMR,
		CS4281PCI_HIMR_DMAI |
		CS4281PCI_HIMR_DMA(CS4281_DMA_PLAY) |
		CS4281PCI_HIMR_DMA(CS4281_DMA_REC));

    /* Set playback volume */
    cs4281_wr(sc, CS4281PCI_PPLVC, 7);
    cs4281_wr(sc, CS4281PCI_PPRVC, 7);

    return 0;
}