plan 9 kernel history: overview | file list | diff list

2000/1117/bitsy/devuda1341.c (diff list | history)

2000/1116/sys/src/9/bitsy/devuda1341.c:41,542000/1117/sys/src/9/bitsy/devuda1341.c:41,54 (short | long | prev | next)
2000/1103    
 */ 
 
/*  
 * L3 setup and hold times (expressed in us) 
2000/1117    
 * L3 setup and hold times (expressed in µs) 
2000/1103    
 */ 
#define L3_DataSetupTime	1		/* 190 ns */ 
#define L3_DataHoldTime		1		/*  30 ns */ 
#define L3_ModeSetupTime	1		/* 190 ns */ 
#define L3_ModeHoldTime		1		/* 190 ns */ 
#define L3_ClockHighTime	100		/* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */ 
#define L3_ClockLowTime		100		/* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */ 
2000/1117    
#define L3_ClockHighTime	10		/* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ 
#define L3_ClockLowTime		10		/* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ 
2000/1103    
#define L3_HaltTime			1		/* 190 ns */ 
 
/* UDA 1341 Registers */ 
2000/1116/sys/src/9/bitsy/devuda1341.c:76,822000/1117/sys/src/9/bitsy/devuda1341.c:76,82
2000/1103    
#define UDA1341_DATA0	0 
#define UDA1341_DATA1	1 
#define UDA1341_STATUS	2 
2000/1111    
#define UDA1341_L3Addr	5 
2000/1117    
#define UDA1341_L3Addr	0x14 
2000/1103    
 
typedef struct	AQueue	AQueue; 
typedef struct	Buf	Buf; 
2000/1116/sys/src/9/bitsy/devuda1341.c:90,962000/1117/sys/src/9/bitsy/devuda1341.c:90,96
2000/1103    
	Qstatus, 
 
	Fmono		= 1, 
	Fin		= 2, 
2000/1117    
	Fin			= 2, 
2000/1103    
	Fout		= 4, 
 
	Aclosed		= 0, 
2000/1116/sys/src/9/bitsy/devuda1341.c:98,1082000/1117/sys/src/9/bitsy/devuda1341.c:98,104
2000/1103    
	Awrite, 
 
	Vaudio		= 0, 
	Vsynth, 
	Vcd, 
	Vline, 
	Vmic, 
	Vspeaker, 
	Vtreb, 
	Vbass, 
	Vspeed, 
2000/1116/sys/src/9/bitsy/devuda1341.c:164,1692000/1117/sys/src/9/bitsy/devuda1341.c:160,166
2000/1116    
	ulong	totaldma; 
	ulong	idledma; 
	ulong	faildma; 
2000/1117    
	ulong	samedma; 
2000/1116    
} iostats; 
 
2000/1103    
static	struct 
2000/1116/sys/src/9/bitsy/devuda1341.c:174,1882000/1117/sys/src/9/bitsy/devuda1341.c:171,181
2000/1103    
	int	irval; 
} volumes[] = 
{ 
[Vaudio]	"audio",	Fout, 		50,	50, 
[Vsynth]	"synth",	Fin|Fout,	0,	0, 
[Vcd]		"cd",		Fin|Fout,	0,	0, 
[Vline]		"line",		Fin|Fout,	0,	0, 
[Vmic]		"mic",		Fin|Fout|Fmono,	0,	0, 
[Vspeaker]	"speaker",	Fout|Fmono,	0,	0, 
2000/1117    
[Vaudio]	"audio",	Fout|Fmono,		50,	50, 
[Vmic]		"mic",		Fin,			 0,	 0, 
2000/1103    
 
[Vtreb]		"treb",		Fout, 		50,	50, 
[Vbass]		"bass",		Fout, 		50,	50, 
2000/1117    
[Vtreb]		"treb",		Fout|Fmono,		50,	50, 
[Vbass]		"bass",		Fout|Fmono, 	50,	50, 
2000/1103    
 
[Vspeed]	"speed",	Fin|Fout|Fmono,	Speed,	Speed, 
		0 
2000/1116/sys/src/9/bitsy/devuda1341.c:420,4392000/1117/sys/src/9/bitsy/devuda1341.c:413,437
2000/1110    
	/* do nothing */ 
} 
 
2000/1117    
uchar	status0	= 0x22; 
uchar	status1	= 0x80; 
uchar	data00	= 0x00;		/* volume control, bits 0 – 5 */ 
uchar	data01	= 0x40; 
uchar	data02	= 0x90; 
ushort	data0e2	= 0xf2c2; 
ushort	data0e4	= 0xf3c4; 
ushort	data0e6	= 0xe3c6; 
 
2000/1110    
static void 
audioenable(void) 
2000/1117    
enable(void) 
2000/1110    
{ 
2000/1111    
	uchar	data[2]; 
2000/1117    
	ushort	data; 
2000/1103    
 
	L3_init(); 
 
2000/1110    
	/* Setup the uarts */ 
2000/1116    
    ppcregs->assignment &= ~(1<<18); 
2000/1117    
	ppcregs->assignment &= ~(1<<18); 
2000/1103    
 
2000/1111    
    gpioregs->altfunc &= ~(GPIO_SSP_TXD_o | GPIO_SSP_RXD_i | GPIO_SSP_SCLK_o | GPIO_SSP_SFRM_o); 
	gpioregs->altfunc |= (GPIO_SSP_CLK_i); 
	gpioregs->direction &= ~(GPIO_SSP_CLK_i); 
2000/1103    
                 
2000/1116    
	sspregs->control0 = 0; 
	sspregs->control0 = 0x031f; /* 16 bits, TI frames, serial clock rate 3 */ 
	sspregs->control1 = 0x0020; /* ext clock */ 
2000/1116/sys/src/9/bitsy/devuda1341.c:445,5232000/1117/sys/src/9/bitsy/devuda1341.c:443,601
2000/1111    
	audiomute(0); 
2000/1110    
 
2000/1116    
	/* external clock configured for 44100 samples/sec */ 
2000/1111    
	gpioregs->direction |=  (GPIO_CLK_SET0_o|GPIO_CLK_SET1_o); 
2000/1116    
/* This is purportedly the wrong way round: 0 should be set, 1 cleared */ 
    gpioregs->set	= GPIO_CLK_SET0_o|GPIO_CLK_SET1_o; 
//    gpioregs->clear	= GPIO_CLK_SET1_o; 
2000/1117    
	gpioregs->set	= GPIO_CLK_SET0_o; 
	gpioregs->clear	= GPIO_CLK_SET1_o; 
2000/1116    
 
2000/1110    
	/* Wait for the UDA1341 to wake up */ 
2000/1111    
	delay(100); 
2000/1110    
 
2000/1111    
	/* Reset the chip */ 
2000/1116    
	data[0] = 2<<UdaStatusSC | 1<<UdaStatusIF | 1<<UdaStatusRST; 
2000/1111    
	L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 ); 
2000/1116    
	gpioregs->set = EGPIO_codec_reset; 
2000/1117    
	data = status0 | 1<<UdaStatusRST; 
	L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&data, 1 ); 
2000/1116    
	gpioregs->clear = EGPIO_codec_reset; 
2000/1117    
	gpioregs->set = EGPIO_codec_reset; 
2000/1116    
	/* write uda 1341 status[0] */ 
	data[0] &= ~(1<<UdaStatusRST); /* clear reset */ 
	L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 ); 
2000/1117    
	L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status0, 1 ); 
	L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); 
	L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1); 
	L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e2, 2); 
	L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 ); 
	L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e6, 2 ); 
2000/1110    
 
2000/1111    
	/* write uda 1341 status[1] */ 
	data[0] = 0x80 | 0x3<<UdaStatusPC | 1<<UdaStatusIGS | 1<<UdaStatusOGS; 
	L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1); 
2000/1117    
	if (debug) { 
		print("uchar	status0	= 0x%2.2ux\n", status0); 
		print("uchar	status1	= 0x%2.2ux\n", status1); 
		print("uchar	data02	= 0x%2.2ux\n", data02); 
		print("ushort	data0e2	= 0x%4.4ux\n", data0e2); 
		print("ushort	data0e4	= 0x%4.4ux\n", data0e4); 
		print("ushort	data0e6	= 0x%4.4ux\n", data0e6); 
		print("#A: audio enabled\n"); 
		print("\tsspregs->control0 = 0x%lux\n", sspregs->control0); 
		print("\tsspregs->control1 = 0x%lux\n", sspregs->control1); 
	} 
} 
2000/1111    
 
	/* write uda 1341 data0[0] (volume) */ 
2000/1116    
	data[0] = 15 & 0x3f;	/* 6 bits, others must be 0 */ 
2000/1111    
	L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 1); 
2000/1117    
static	void 
resetlevel(void) 
{ 
	int i; 
2000/1111    
 
	/* write uda 1341 data0[2] (mode switch) */ 
	data[0] = 0x80 | 3;	/* mode = 3 */ 
	L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 1); 
2000/1117    
	for(i=0; volumes[i].name; i++) { 
		audio.lovol[i] = volumes[i].ilval; 
		audio.rovol[i] = volumes[i].irval; 
		audio.livol[i] = volumes[i].ilval; 
		audio.rivol[i] = volumes[i].irval; 
	} 
} 
2000/1111    
 
	/* set mixer mode and level */ 
	data[0] = 0xc0 | 2 /* ext address */; 
	data[1] = 0xe0 | 2 | 4 << 2;	/* mixer mode and mic level */ 
	L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 2); 
2000/1117    
static void 
mxvolume(void) { 
	int *left, *right; 
2000/1111    
 
	/* set agc control and input amplifier gain */ 
	data[0] = 0xc0 | 4 /* ext address */; 
	data[1] = 0xe0 | 1<<4 | 3;	/* AGC control and input ampl gain */ 
	L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 2 ); 
2000/1117    
	if(audio.amode & Aread){ 
		left = audio.livol; 
		right = audio.rivol; 
	} 
	if(audio.amode & Awrite){ 
		left = audio.lovol; 
		right = audio.rovol; 
		data00 &= ~0x3f; 
		data00 |= ((200-left[Vaudio]-right[Vaudio])*0x3f/200)&0x3f; 
		L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1); 
		if (debug) print("uchar	data00	= 0x%2.2ux (audio out)\n", data00); 
		if (left[Vtreb]+right[Vtreb] <= 100 
		 && left[Vbass]+right[Vbass] <= 100) { 
			/* settings neutral */ 
			data02 &= ~0x03; 
			L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1); 
			if (debug) print("uchar	data02	= 0x%2.2ux (mode flat)\n", data02); 
		} else { 
			data02 |= 0x03; 
			L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1); 
			if (debug) print("uchar	data02	= 0x%2.2ux (mode boost)\n", data02); 
			data01 |= ~0x3f; 
			data01 |= ((left[Vtreb]+right[Vtreb]-100)*0x3/100)&0x03; 
			data01 |= (((left[Vbass]+right[Vbass]-100)*0xf/100)&0xf)<<2; 
			L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data01, 1); 
			if (debug) print("uchar	data01	= 0x%2.2ux (bass&treb)\n", data01); 
		} 
	} 
2000/1111    
 
	/* set agc time constant and output level */ 
	data[0] = 0xc0 | 6 /* ext address */; 
	data[1] = 0xe0 | 0<<2 | 3;	/* agc time constant and output level */ 
	L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 2 ); 
2000/1117    
} 
2000/1111    
 
2000/1117    
static void 
outenable(void) { 
	/* turn on DAC, set output gain switch */ 
	status1 |= 0x41; 
	L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); 
	/* set volume */ 
	data00 |= 0xf; 
	L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1); 
2000/1116    
	if (debug) { 
		print("#A: audio enabled\n"); 
		print("\tsspregs->control0 = 0x%lux\n", sspregs->control0); 
		print("\tsspregs->control1 = 0x%lux\n", sspregs->control1); 
2000/1117    
		print("uchar	status1	= 0x%2.2ux\n", status1); 
		print("uchar	data00	= 0x%2.2ux\n", data00); 
2000/1116    
	} 
2000/1103    
} 
2000/1107    
 
static void 
2000/1111    
sendaudio(IOstate *b) { 
2000/1117    
outdisable(void) { 
	/* turn off DAC, clear output gain switch */ 
	status1 &= ~0x41; 
	L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); 
	if (debug) { 
		print("uchar	status1	= 0x%2.2ux\n", status1); 
	} 
} 
 
static void 
inenable(void) { 
	/* turn on ADC, set input gain switch */ 
	status1 |= 0x22; 
	L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); 
	if (debug) { 
		print("uchar	status1	= 0x%2.2ux\n", status1); 
	} 
} 
 
static void 
indisable(void) { 
	/* turn off ADC, clear input gain switch */ 
	status1 &= ~0x22; 
	L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); 
	if (debug) { 
		print("uchar	status1	= 0x%2.2ux\n", status1); 
	} 
} 
 
static void 
sendaudio(IOstate *s) { 
2000/1115    
	/* interrupt routine calls this too */ 
2000/1116    
	int n; 
 
2000/1115    
	if (debug > 1) print("#A: sendaudio\n"); 
	ilock(&b->ilock); 
2000/1110    
	while (b->next != b->filling) { 
		assert(b->next->nbytes); 
2000/1116    
		if ((n = dmastart(b->dma, b->next->virt, b->next->nbytes)) == 0) { 
2000/1117    
	ilock(&s->ilock); 
	while (s->next != s->filling) { 
		assert(s->next->nbytes); 
		if ((n = dmastart(s->dma, s->next->virt, s->next->nbytes)) == 0) { 
2000/1116    
			iostats.faildma++; 
2000/1115    
			break; 
		} 
2000/1116    
		iostats.totaldma++; 
		if (n == 1) iostats.idledma++; 
2000/1115    
		if (debug > 1) print("#A: dmastart @%p\n", b->next); 
		b->next->nbytes = 0; 
2000/1110    
		b->next++; 
		if (b->next == &b->buf[Nbuf]) 
2000/1111    
			b->next = &b->buf[0]; 
2000/1117    
		switch (n) { 
		case 1: 
			iostats.idledma++; 
			break; 
		case 3: 
			iostats.faildma++; 
			break; 
		} 
		if (debug > 1) print("#A: dmastart @%p\n", s->next); 
		s->next->nbytes = 0; 
		s->next++; 
		if (s->next == &s->buf[Nbuf]) 
			s->next = &s->buf[0]; 
2000/1110    
	} 
2000/1115    
	iunlock(&b->ilock); 
2000/1117    
	iunlock(&s->ilock); 
2000/1110    
} 
 
static void 
2000/1116/sys/src/9/bitsy/devuda1341.c:557,5622000/1117/sys/src/9/bitsy/devuda1341.c:635,641
2000/1107    
static Chan* 
audioopen(Chan *c, int omode) 
{ 
2000/1117    
	IOstate *s; 
2000/1107    
 
	switch(c->qid.path & ~CHDIR) { 
	default: 
2000/1116/sys/src/9/bitsy/devuda1341.c:580,6082000/1117/sys/src/9/bitsy/devuda1341.c:659,691
2000/1107    
			qunlock(&audio); 
			error(Einuse); 
		} 
2000/1111    
		audioenable(); 
2000/1117    
		enable(); 
2000/1116    
		memset(&iostats, 0, sizeof(iostats)); 
2000/1109    
		if (omode & Aread) { 
2000/1117    
			inenable(); 
			s = &audio.i; 
2000/1108    
			/* read */ 
2000/1109    
			audio.amode |= Aread; 
			if(audio.i.bufinit == 0) 
				bufinit(&audio.i); 
			setempty(&audio.i); 
2000/1114    
			audio.i.chan = c; 
			audio.i.dma = dmaalloc(0, 0, 8, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)&audio.o); 
2000/1117    
			s->chan = c; 
			s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)&audio.o); 
2000/1108    
		} 
		if (omode & 0x2) { 
2000/1117    
			outenable(); 
			s = &audio.o; 
2000/1108    
			/* write */ 
2000/1111    
//			amplifierpower(1); 
//			audiomute(0); 
2000/1109    
			audio.amode |= Awrite; 
			if(audio.o.bufinit == 0) 
				bufinit(&audio.o); 
			setempty(&audio.o); 
2000/1110    
			audio.o.chan = c; 
2000/1114    
			audio.o.dma = dmaalloc(0, 0, 8, 2, SSPXmitDMA, Port4SSP, audiointr, (void*)&audio.o); 
2000/1117    
			if(s->bufinit == 0) 
				bufinit(s); 
			setempty(s); 
			s->chan = c; 
			s->dma = dmaalloc(0, 0, 4, 2, SSPXmitDMA, Port4SSP, audiointr, (void*)s); 
2000/1107    
		} 
2000/1109    
//		mxvolume(); 
2000/1117    
		mxvolume(); 
2000/1115    
		qunlock(&audio); 
2000/1113    
		if (debug) print("#A: open done\n"); 
2000/1107    
		break; 
2000/1116/sys/src/9/bitsy/devuda1341.c:618,6232000/1117/sys/src/9/bitsy/devuda1341.c:701,707
2000/1107    
static void 
audioclose(Chan *c) 
{ 
2000/1117    
	IOstate *s; 
2000/1107    
 
	switch(c->qid.path & ~CHDIR) { 
	default: 
2000/1116/sys/src/9/bitsy/devuda1341.c:633,6652000/1117/sys/src/9/bitsy/devuda1341.c:717,755
2000/1115    
		if (debug > 1) print("#A: close\n"); 
2000/1107    
		if(c->flag & COPEN) { 
			qlock(&audio); 
2000/1110    
			qlock(&audio.o); 
2000/1107    
			if(waserror()){ 
2000/1110    
				qunlock(&audio.o); 
2000/1107    
				qunlock(&audio); 
				nexterror(); 
			} 
2000/1110    
			if (audio.o.chan == c) { 
2000/1117    
				s = &audio.o; 
				qlock(s); 
				if(waserror()){ 
					qunlock(s); 
					nexterror(); 
				} 
2000/1110    
				/* closing the write end */ 
				audio.amode &= ~Awrite; 
 
2000/1115    
				if (audio.o.filling->nbytes) { 
2000/1110    
					audio.o.filling++; 
					if (audio.o.filling == &audio.o.buf[Nbuf]) 
						audio.o.filling = &audio.o.buf[0]; 
					sendaudio(&audio.o); 
2000/1117    
				if (s->filling->nbytes) { 
					/* send remaining partial buffer */ 
					s->filling++; 
					if (s->filling == &s->buf[Nbuf]) 
						s->filling = &s->buf[0]; 
					sendaudio(s); 
2000/1110    
				} 
2000/1116    
				delay(2000); 
		//		dmawait(audio.o.dma); 
				if (!dmaidle(audio.o.dma)) 
					print("dma still busy\n"); 
2000/1117    
				dmawait(s->dma); 
				outdisable(); 
2000/1111    
				amplifierpower(0); 
2000/1110    
				setempty(&audio.o); 
2000/1116    
				dmafree(audio.o.dma); 
2000/1117    
				setempty(s); 
				dmafree(s->dma); 
				qunlock(s); 
				poperror(); 
2000/1110    
			} 
			if (audio.i.chan == c) { 
				/* closing the read end */ 
				audio.amode &= ~Aread; 
2000/1117    
				indisable(); 
2000/1110    
				setempty(&audio.i); 
			} 
			if (audio.amode == 0) { 
2000/1116/sys/src/9/bitsy/devuda1341.c:666,6772000/1117/sys/src/9/bitsy/devuda1341.c:756,767
2000/1110    
				/* turn audio off */ 
				audiopower(0); 
			} 
2000/1107    
			poperror(); 
2000/1110    
			qunlock(&audio.o); 
2000/1107    
			qunlock(&audio); 
2000/1117    
			poperror(); 
2000/1116    
			print("total dmas: %lud\n", iostats.totaldma); 
			print("dmas while idle: %lud\n", iostats.idledma); 
			print("dmas while busy: %lud\n", iostats.faildma); 
2000/1117    
			print("out of order dma: %lud\n", iostats.samedma); 
2000/1107    
		} 
		break; 
	} 
2000/1116/sys/src/9/bitsy/devuda1341.c:807,8142000/1117/sys/src/9/bitsy/devuda1341.c:897,904
2000/1107    
			} 
 
			if(strcmp(field[i], "reset") == 0) { 
2000/1111    
//				resetlevel(); 
//				mxvolume(); 
2000/1117    
				resetlevel(); 
				mxvolume(); 
2000/1107    
				goto cont0; 
			} 
			if(strcmp(field[i], "in") == 0) { 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)