From 35a2b63b9016ccd4e1d441a7b494133e309c5d17 Mon Sep 17 00:00:00 2001 From: macallan Date: Mon, 11 Dec 2006 02:17:53 +0000 Subject: [PATCH] actually change the sample rate when asked to. Fix provided by Marco Trillo in PR35204 While there also enable 24bit I/O. --- sys/arch/macppc/dev/snapper.c | 143 +++++++++++++++++++++++----------- 1 file changed, 96 insertions(+), 47 deletions(-) diff --git a/sys/arch/macppc/dev/snapper.c b/sys/arch/macppc/dev/snapper.c index ec93d4faf3b2..3bdeaf73c158 100644 --- a/sys/arch/macppc/dev/snapper.c +++ b/sys/arch/macppc/dev/snapper.c @@ -1,8 +1,8 @@ -/* $NetBSD: snapper.c,v 1.13 2006/09/24 03:47:09 jmcneill Exp $ */ +/* $NetBSD: snapper.c,v 1.14 2006/12/11 02:17:53 macallan Exp $ */ /* Id: snapper.c,v 1.11 2002/10/31 17:42:13 tsubai Exp */ - +/* Id: i2s.c,v 1.12 2005/01/15 14:32:35 tsubai Exp */ /*- - * Copyright (c) 2002 Tsubai Masanari. All rights reserved. + * Copyright (c) 2002, 2003 Tsubai Masanari. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -77,6 +77,9 @@ struct snapper_softc { i2c_addr_t sc_deqaddr; i2c_tag_t sc_i2c; + int sc_rate; /* current sampling rate */ + int sc_bitspersample; + u_int sc_vol_l; u_int sc_vol_r; u_int sc_treble; @@ -113,7 +116,7 @@ int snapper_trigger_output(void *, void *, void *, int, void (*)(void *), int snapper_trigger_input(void *, void *, void *, int, void (*)(void *), void *, const audio_params_t *); void snapper_set_volume(struct snapper_softc *, int, int); -int snapper_set_rate(struct snapper_softc *, u_int); +int snapper_set_rate(struct snapper_softc *); void snapper_set_treble(struct snapper_softc *, int); void snapper_set_bass(struct snapper_softc *, int); void snapper_write_mixers(struct snapper_softc *); @@ -389,10 +392,12 @@ const uint8_t snapper_mixer_gain[178][3] = { { 0x00, 0x00, 0x00 } /* Mute */ }; -#define SNAPPER_NFORMATS 1 +#define SNAPPER_NFORMATS 2 static const struct audio_format snapper_formats[SNAPPER_NFORMATS] = { {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_BE, 16, 16, - 2, AUFMT_STEREO, 3, {8000, 44100, 48000}}, + 2, AUFMT_STEREO, 4, {8000, 32000, 44100, 48000}}, + {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_BE, 24, 24, + 2, AUFMT_STEREO, 4, {8000, 32000, 44100, 48000}}, }; static u_char *amp_mute; @@ -409,6 +414,16 @@ static int headphone_detect_active; #define I2S_FRAMEMATCH 0x50 #define I2S_WORDSIZE 0x60 +/* I2S_INT register definitions */ +#define I2S_INT_CLKSTOPPEND 0x01000000 /* clock-stop interrupt pending */ + +/* FCR(0x3c) bits */ +#define I2S0CLKEN 0x1000 +#define I2S0EN 0x2000 +#define I2S1CLKEN 0x080000 +#define I2S1EN 0x100000 +#define FCR3C_BITMASK "\020\25I2S1EN\24I2S1CLKEN\16I2S0EN\15I2S0CLKEN" + /* TAS3004 registers */ #define DEQ_MCR1 0x01 /* Main control register 1 (1byte) */ #define DEQ_DRC 0x02 /* Dynamic range compression (6bytes?) */ @@ -450,6 +465,7 @@ static int headphone_detect_active; #define DEQ_MCR1_W_16 0x00 /* 16 bit */ #define DEQ_MCR1_W_18 0x01 /* 18 bit */ #define DEQ_MCR1_W_20 0x02 /* 20 bit */ +#define DEQ_MCR1_W_24 0x03 /* 20 bit */ #define DEQ_MCR2_DL 0x80 /* Download */ #define DEQ_MCR2_AP 0x02 /* All pass mode */ @@ -782,9 +798,10 @@ snapper_set_params(void *h, int setmode, int usemode, } /* Set the speed. p points HW encoding. */ - if (snapper_set_rate(sc, p->sample_rate)) - return EINVAL; - + if (p) { + sc->sc_rate = p->sample_rate; + sc->sc_bitspersample = p->precision; + } return 0; } @@ -1120,9 +1137,14 @@ snapper_trigger_output(void *h, void *start, void *end, int bsize, struct dbdma_command *cmd; vaddr_t va; int i, len, intmode; + int res; DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize); sc = h; + + if ((res = snapper_set_rate(sc)) != 0) + return res; + cmd = sc->sc_odmacmd; sc->sc_ointr = intr; sc->sc_oarg = arg; @@ -1170,9 +1192,14 @@ snapper_trigger_input(void *h, void *start, void *end, int bsize, struct dbdma_command *cmd; vaddr_t va; int i, len, intmode; + int res; DPRINTF("trigger_input %p %p 0x%x\n", start, end, bsize); sc = h; + + if ((res = snapper_set_rate(sc)) != 0) + return res; + cmd = sc->sc_idmacmd; sc->sc_iintr = intr; sc->sc_iarg = arg; @@ -1343,14 +1370,17 @@ void snapper_write_mixers(struct snapper_softc *sc) */ int -snapper_set_rate(struct snapper_softc *sc, u_int rate) +snapper_set_rate(struct snapper_softc *sc) { - u_int reg; + u_int reg = 0, x; + u_int rate = sc->sc_rate; + uint32_t wordsize, ows; int MCLK; int clksrc, mdiv, sdiv; int mclk_fs; + int timo; + uint8_t mcr1; - reg = 0; switch (rate) { case 8000: clksrc = 18432000; /* 18MHz */ @@ -1364,6 +1394,7 @@ snapper_set_rate(struct snapper_softc *sc, u_int rate) mclk_fs = 256; break; + case 32000: case 48000: clksrc = 49152000; /* 49MHz */ reg = CLKSRC_49MHz; @@ -1411,21 +1442,64 @@ snapper_set_rate(struct snapper_softc *sc, u_int rate) reg |= SERIAL_64x; /* stereo input and output */ + + DPRINTF("precision: %d\n", sc->sc_bitspersample); + switch(sc->sc_bitspersample) { + case 16: + wordsize = 0x02000200; + mcr1 = DEQ_MCR1_SC_64 | DEQ_MCR1_SM_I2S | DEQ_MCR1_W_16; + break; + case 24: + wordsize = 0x03000300; + mcr1 = DEQ_MCR1_SC_64 | DEQ_MCR1_SM_I2S | DEQ_MCR1_W_24; + break; + default: + printf("%s: unsupported sample size %d\n", + sc->sc_dev.dv_xname, sc->sc_bitspersample); + return EINVAL; + } + + ows = in32rb(sc->sc_reg + I2S_WORDSIZE); DPRINTF("I2SSetDataWordSizeReg 0x%08x -> 0x%08x\n", - in32rb(sc->sc_reg + I2S_WORDSIZE), 0x02000200); - out32rb(sc->sc_reg + I2S_WORDSIZE, 0x02000200); + ows, wordsize); + if (ows != wordsize) { + out32rb(sc->sc_reg + I2S_WORDSIZE, wordsize); + tas3004_write(sc, DEQ_MCR1, &mcr1); + } + + x = in32rb(sc->sc_reg + I2S_FORMAT); + if (x == reg) + return 0; /* No change; do nothing. */ DPRINTF("I2SSetSerialFormatReg 0x%x -> 0x%x\n", in32rb(sc->sc_reg + I2S_FORMAT), reg); + + /* Clear CLKSTOPPEND. */ + out32rb(sc->sc_reg + I2S_INT, I2S_INT_CLKSTOPPEND); + + x = in32rb(0x8000003c); /* FCR */ + x &= ~I2S0CLKEN; /* XXX I2S0 */ + out32rb(0x8000003c, x); + + /* Wait until clock is stopped. */ + for (timo = 1000; timo > 0; timo--) { + if (in32rb(sc->sc_reg + I2S_INT) & I2S_INT_CLKSTOPPEND) + goto done; + delay(1); + } + DPRINTF("snapper_set_rate: timeout\n"); +done: out32rb(sc->sc_reg + I2S_FORMAT, reg); + x = in32rb(0x8000003c); + x |= I2S0CLKEN; + out32rb(0x8000003c, x); + return 0; } -/*#define DEQaddr 0x6a*/ - const struct tas3004_reg tas3004_initdata = { - { DEQ_MCR1_SC_64 | DEQ_MCR1_SM_I2S | DEQ_MCR1_W_20 }, /* MCR1 */ + { DEQ_MCR1_SC_64 | DEQ_MCR1_SM_I2S | DEQ_MCR1_W_16 }, /* MCR1 */ { 1, 0, 0, 0, 0, 0 }, /* DRC */ { 0, 0, 0, 0, 0, 0 }, /* VOLUME */ { 0x72 }, /* TREBLE */ @@ -1505,16 +1579,8 @@ tas3004_write(struct snapper_softc *sc, u_int reg, const void *data) size = tas3004_regsize[reg]; KASSERT(size > 0); -#ifdef SNAPPER_DEBUG - printf("reg: %x, %d %d\n", reg, size, ((const char*)data)[0]); -#endif -#if 0 - ki2c_setmode(sc->sc_i2c, 8); /* std+sub mode */ - - if (ki2c_write(sc->sc_i2c, DEQaddr, reg, data, size)) - return -1; -#endif - /* ugly, but for now... */ + DPRINTF("reg: %x, %d %d\n", reg, size, ((const char*)data)[0]); + regblock[0] = reg; memcpy(®block[1], data, size); iic_acquire_bus(sc->sc_i2c, 0); @@ -1666,14 +1732,6 @@ err: return -1; } -/* FCR(0x3c) bits */ -#define I2S0CLKEN 0x1000 -#define I2S0EN 0x2000 -#define I2S1CLKEN 0x080000 -#define I2S1EN 0x100000 - -#define FCR3C_BITMASK "\020\25I2S1EN\24I2S1CLKEN\16I2S0EN\15I2S0CLKEN" - void snapper_init(struct snapper_softc *sc, int node) { @@ -1734,8 +1792,8 @@ snapper_init(struct snapper_softc *sc, int node) intr_establish(headphone_detect_intr, IST_EDGE, IPL_AUDIO, snapper_cint, sc); - /* "sample-rates" (44100, 48000) */ - snapper_set_rate(sc, 44100); + sc->sc_rate = 44100; /* default rate */ + sc->sc_bitspersample = 16; /* Enable headphone interrupt? */ *headphone_detect |= 0x80; @@ -1743,22 +1801,13 @@ snapper_init(struct snapper_softc *sc, int node) /* i2c_set_port(port); */ -#if 0 - /* Enable I2C interrupts. */ -#define IER 4 -#define I2C_INT_DATA 0x01 -#define I2C_INT_ADDR 0x02 -#define I2C_INT_STOP 0x04 - ki2c_writereg(sc->sc_i2c, IER,I2C_INT_DATA|I2C_INT_ADDR|I2C_INT_STOP); -#endif - if (tas3004_init(sc)) return; /* Update headphone status. */ snapper_cint(sc); - snapper_set_volume(sc, 80, 80); + snapper_set_volume(sc, 128, 128); sc->sc_bass = 128; sc->sc_treble = 128;