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

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

2000/1109/sys/src/9/bitsy/devuda1341.c:17,222000/1110/sys/src/9/bitsy/devuda1341.c:17,23 (short | long | prev | next)
2000/1103    
#include	"fns.h" 
#include	"../port/error.h" 
#include	"io.h" 
2000/1110    
#include	"sa1110dma.h" 
2000/1103    
 
/* 
 * GPIO based L3 bus support. 
2000/1109/sys/src/9/bitsy/devuda1341.c:122,1282000/1110/sys/src/9/bitsy/devuda1341.c:123,128
2000/1103    
 
struct	Buf 
{ 
2000/1109    
	int		active;			/* dma running */ 
2000/1103    
	uchar*	virt; 
2000/1109    
	uint	nbytes; 
2000/1103    
}; 
2000/1109/sys/src/9/bitsy/devuda1341.c:130,1402000/1110/sys/src/9/bitsy/devuda1341.c:130,144
2000/1109    
struct	IOstate 
2000/1103    
{ 
	QLock; 
	Rendez	vous; 
2000/1109    
	int		bufinit;		/* boolean, if buffers allocated */ 
	Buf		buf[Nbuf];		/* buffers and queues */ 
	Buf		*current;		/* next candidate for dma */ 
	Buf		*filling;		/* buffer being filled */ 
2000/1110    
	Rendez			vous; 
	Chan			*chan;			/* chan of open */ 
	int				dma;			/* dma chan, alloc on open, free on close */ 
	int				bufinit;		/* boolean, if buffers allocated */ 
	Buf				buf[Nbuf];		/* buffers and queues */ 
	int				active;			/* # of dmas in progress */ 
	volatile Buf	*current;		/* next dma to finish */ 
	volatile Buf	*next;			/* next candidate for dma */ 
	volatile Buf	*filling;		/* buffer being filled */ 
2000/1109    
}; 
2000/1103    
 
2000/1104    
static	struct 
2000/1109/sys/src/9/bitsy/devuda1341.c:177,2052000/1110/sys/src/9/bitsy/devuda1341.c:181,212
2000/1103    
/* 
 * Grab control of the IIC/L3 shared pins 
 */ 
2000/1104    
static void L3_acquirepins(void) 
2000/1110    
static void 
L3_acquirepins(void) 
2000/1103    
{ 
	GPSR = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); 
	GPDR |=  (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); 
2000/1110    
	gpioregs->set = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); 
	gpioregs->direction |=  (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); 
2000/1103    
} 
 
/* 
 * Release control of the IIC/L3 shared pins 
 */ 
2000/1104    
static void L3_releasepins(void) 
2000/1110    
static void 
L3_releasepins(void) 
2000/1103    
{ 
	GPDR &= ~(GPIO_L3_SCLK_o | GPIO_L3_SDA_io); 
	GPCR = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); 
2000/1110    
	gpioregs->direction &= ~(GPIO_L3_SCLK_o | GPIO_L3_SDA_io); 
	gpioregs->clear = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); 
2000/1103    
} 
 
/* 
 * Initialize the interface 
 */ 
static void __init L3_init(void) 
2000/1110    
static void  
L3_init(void) 
2000/1103    
{ 
	GAFR &= ~(GPIO_L3_SDA_io | GPIO_L3_SCLK_o | GPIO_L3_MODE_o); 
	GPSR = GPIO_L3_MODE_o; 
	GPDR |= GPIO_L3_MODE_o; 
2000/1110    
	gpioregs->altfunc &= ~(GPIO_L3_SDA_io | GPIO_L3_SCLK_o | GPIO_L3_MODE_o); 
	gpioregs->set = GPIO_L3_MODE_o; 
	gpioregs->direction |= GPIO_L3_MODE_o; 
2000/1103    
	L3_releasepins(); 
} 
 
2000/1109/sys/src/9/bitsy/devuda1341.c:207,2232000/1110/sys/src/9/bitsy/devuda1341.c:214,231
2000/1103    
 * Get a bit. The clock is high on entry and on exit. Data is read after 
 * the clock low time has expired. 
 */ 
2000/1104    
static int L3_getbit(void) 
2000/1110    
static int 
L3_getbit(void) 
2000/1103    
{ 
	int data; 
 
	GPCR = GPIO_L3_SCLK_o; 
	udelay(L3_ClockLowTime); 
2000/1110    
	gpioregs->clear = GPIO_L3_SCLK_o; 
	µdelay(L3_ClockLowTime); 
2000/1103    
 
	data = (GPLR & GPIO_L3_SDA_io) ? 1 : 0; 
2000/1110    
	data = (gpioregs->level & GPIO_L3_SDA_io) ? 1 : 0; 
2000/1103    
 
 	GPSR = GPIO_L3_SCLK_o; 
	udelay(L3_ClockHighTime); 
2000/1110    
 	gpioregs->set = GPIO_L3_SCLK_o; 
	µdelay(L3_ClockHighTime); 
2000/1103    
 
	return data; 
} 
2000/1109/sys/src/9/bitsy/devuda1341.c:226,2452000/1110/sys/src/9/bitsy/devuda1341.c:234,254
2000/1103    
 * Send a bit. The clock is high on entry and on exit. Data is sent only 
 * when the clock is low (I2C compatibility). 
 */ 
2000/1104    
static void L3_sendbit(int bit) 
2000/1110    
static void 
L3_sendbit(int bit) 
2000/1103    
{ 
	GPCR = GPIO_L3_SCLK_o; 
2000/1110    
	gpioregs->clear = GPIO_L3_SCLK_o; 
2000/1103    
 
	if (bit & 1) 
		GPSR = GPIO_L3_SDA_io; 
2000/1110    
		gpioregs->set = GPIO_L3_SDA_io; 
2000/1103    
	else 
		GPCR = GPIO_L3_SDA_io; 
2000/1110    
		gpioregs->clear = GPIO_L3_SDA_io; 
2000/1103    
 
	/* Assumes L3_DataSetupTime < L3_ClockLowTime */ 
	udelay(L3_ClockLowTime); 
2000/1110    
	µdelay(L3_ClockLowTime); 
2000/1103    
 
	GPSR = GPIO_L3_SCLK_o; 
	udelay(L3_ClockHighTime); 
2000/1110    
	gpioregs->set = GPIO_L3_SCLK_o; 
	µdelay(L3_ClockHighTime); 
2000/1103    
} 
 
/* 
2000/1109/sys/src/9/bitsy/devuda1341.c:247,2532000/1110/sys/src/9/bitsy/devuda1341.c:256,263
2000/1103    
 * count. The mode line is high on entry and exit. The mod line is pulsed 
 * before the second data byte and before ech byte thereafter. 
 */ 
static void L3_sendbyte(char data, int mode) 
2000/1110    
static void 
L3_sendbyte(char data, int mode) 
2000/1103    
{ 
	int i; 
 
2000/1109/sys/src/9/bitsy/devuda1341.c:254,2802000/1110/sys/src/9/bitsy/devuda1341.c:264,290
2000/1103    
	L3_acquirepins(); 
 
	switch(mode) { 
	    case 0: /* Address mode */ 
		GPCR = GPIO_L3_MODE_o; 
2000/1110    
	case 0: /* Address mode */ 
		gpioregs->clear = GPIO_L3_MODE_o; 
2000/1103    
		break; 
	    case 1: /* First data byte */ 
2000/1110    
	case 1: /* First data byte */ 
2000/1103    
		break; 
	    default: /* Subsequent bytes */ 
		GPCR = GPIO_L3_MODE_o; 
		udelay(L3_HaltTime); 
		GPSR = GPIO_L3_MODE_o; 
2000/1110    
	default: /* Subsequent bytes */ 
		gpioregs->clear = GPIO_L3_MODE_o; 
		µdelay(L3_HaltTime); 
		gpioregs->set = GPIO_L3_MODE_o; 
2000/1103    
		break; 
	} 
 
	udelay(L3_ModeSetupTime); 
2000/1110    
	µdelay(L3_ModeSetupTime); 
2000/1103    
 
	for (i = 0; i < 8; i++) 
		L3_sendbit(data >> i); 
 
	if (mode == 0)  /* Address mode */ 
		GPSR = GPIO_L3_MODE_o; 
2000/1110    
		gpioregs->set = GPIO_L3_MODE_o; 
2000/1103    
 
	udelay(L3_ModeHoldTime); 
2000/1110    
	µdelay(L3_ModeHoldTime); 
2000/1103    
 
	L3_releasepins(); 
} 
2000/1109/sys/src/9/bitsy/devuda1341.c:286,3172000/1110/sys/src/9/bitsy/devuda1341.c:296,328
2000/1103    
 * function is never valid with mode == 0 (address cycle) as the address 
 * is always sent on the bus, not read. 
 */ 
static char L3_getbyte(int mode) 
2000/1110    
static char 
L3_getbyte(int mode) 
2000/1103    
{ 
	char data = 0; 
	int i; 
 
	L3_acquirepins(); 
	GPDR &= ~(GPIO_L3_SDA_io); 
2000/1110    
	gpioregs->direction &= ~(GPIO_L3_SDA_io); 
2000/1103    
 
	switch(mode) { 
	    case 0: /* Address mode - never valid */ 
2000/1110    
	case 0: /* Address mode - never valid */ 
2000/1103    
		break; 
	    case 1: /* First data byte */ 
2000/1110    
	case 1: /* First data byte */ 
2000/1103    
		break; 
	    default: /* Subsequent bytes */ 
		GPCR = GPIO_L3_MODE_o; 
		udelay(L3_HaltTime); 
		GPSR = GPIO_L3_MODE_o; 
2000/1110    
	default: /* Subsequent bytes */ 
		gpioregs->clear = GPIO_L3_MODE_o; 
		µdelay(L3_HaltTime); 
		gpioregs->set = GPIO_L3_MODE_o; 
2000/1103    
		break; 
	} 
 
	udelay(L3_ModeSetupTime); 
2000/1110    
	µdelay(L3_ModeSetupTime); 
2000/1103    
 
	for (i = 0; i < 8; i++) 
		data |= (L3_getbit() << i); 
 
	udelay(L3_ModeHoldTime); 
2000/1110    
	µdelay(L3_ModeHoldTime); 
2000/1103    
 
	L3_releasepins(); 
 
2000/1109/sys/src/9/bitsy/devuda1341.c:324,3302000/1110/sys/src/9/bitsy/devuda1341.c:335,342
2000/1103    
 * is encoded in the address (low two bits are set and device address is 
 * in the upper 6 bits). 
 */ 
static int L3_write(char addr, char *data, int len) 
2000/1110    
static int 
L3_write(char addr, char *data, int len) 
2000/1103    
{ 
	int mode = 0; 
	int bytes = len; 
2000/1109/sys/src/9/bitsy/devuda1341.c:342,3482000/1110/sys/src/9/bitsy/devuda1341.c:354,361
2000/1103    
 * is encoded in the address (low two bits are set and device address is 
 * in the upper 6 bits). 
 */ 
static int L3_read(char addr, char * data, int len) 
2000/1110    
static int 
L3_read(char addr, char * data, int len) 
2000/1103    
{ 
	int mode = 0; 
	int bytes = len; 
2000/1109/sys/src/9/bitsy/devuda1341.c:378,4052000/1110/sys/src/9/bitsy/devuda1341.c:391,461
2000/1109    
	} 
	b->filling = b->buf; 
	b->current = b->buf; 
2000/1110    
	b->next = b->buf; 
2000/1103    
} 
 
2000/1110    
static int 
audioqnotfull(IOstate *s) 
{ 
	/* called with lock */ 
	return s->active == 0 || s->filling != s->current; 
} 
 
static int 
audioqnotempty(IOstate *s) 
{ 
	/* called with lock */ 
	return s->next != s->filling; 
} 
 
static int 
audioidle(IOstate *s) 
{ 
	/* called with lock */ 
	return s->active == 0; 
} 
 
2000/1103    
static void 
audioinit(void) 
{ 
2000/1110    
	/* do nothing */ 
} 
 
static void 
audioenable(void) 
{ 
2000/1103    
	int err; 
                    
	/* Acquire and initialize DMA */ 
	if( audio_init_dma( &output_stream, "UDA1341 DMA out" ) || 
	    audio_init_dma( &input_stream, "UDA1341 DMA in" ) ){ 
		audio_clear_dma( &output_stream ); 
		audio_clear_dma( &input_stream ); 
		return -EBUSY; 
	} 
 
	L3_init(); 
	audio_ssp_init(); 
 
        audio_uda1341_reset(); 
2000/1110    
	/* Setup the uarts */ 
    ppcregs->assignment &= ~(1<<18);	/* Could be the other way round! */ 
2000/1103    
 
	init_waitqueue_head(&audio_waitq); 
2000/1110    
    gpioregs->altfunc &= ~(GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM); 
	gpioregs->altfunc |= (GPIO_SSP_CLK); 
	gpioregs->direction &= ~(GPIO_SSP_CLK); 
2000/1103    
 
2000/1110    
	sspregs->control0 = 0x10<<0 | 0x1<<4 | 1<<7 | 0x8<<8; 
	sspregs->control1 = 0<<3 + 0<<4 + 1<<5; 
 
	/* Enable the audio power */ 
          set_bitsy_egpio(EGPIO_BITSY_CODEC_NRESET|EGPIO_BITSY_AUD_AMP_ON|EGPIO_BITSY_AUD_PWR_ON); 
          clr_bitsy_egpio(EGPIO_BITSY_QMUTE); 
	  gpioregs->direction |=  (GPIO_BITSY_CLK_SET0|GPIO_BITSY_CLK_SET1); 
	  /* external clock configured for 44100 samples/sec */ 
          GPSR =   GPIO_BITSY_CLK_SET0; 
          GPCR =   GPIO_BITSY_CLK_SET1; 
 
  
        printk("gpioregs->altfunc=%08x gpioregs->direction=%08x GPLR=%08x\n", gpioregs->altfunc, gpioregs->direction, GPLR); 
        printk("PPDR=%08x PPSR=%08x PPAR=%08x PPFR=%08x\n", PPDR, PPSR, PPAR, PPFR); 
 
	/* Wait for the UDA1341 to wake up */ 
	mdelay(100); 
        printk("Ser4SSSR=%08x\n", Ser4SSSR); 
 
    audio_uda1341_reset(); 
 
2000/1103    
	/* Set some default mixer values... */ 
	STATUS_1.DAC_gain = 1; 
	STATUS_1.ADC_gain = 1; 
2000/1109/sys/src/9/bitsy/devuda1341.c:416,4382000/1110/sys/src/9/bitsy/devuda1341.c:472,513
2000/1103    
	DATA0_ext6.AGC_level = 3; 
	L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_ext6, 2 ); 
 
	/* register devices */ 
	audio_dev_dsp = register_sound_dsp(&UDA1341_dsp_fops, -1); 
	audio_dev_mixer = register_sound_mixer(&UDA1341_mixer_fops, -1); 
2000/1110    
	print("audio enabled\n"); 
2000/1103    
 
	printk( AUDIO_NAME_VERBOSE " initialized\n" ); 
                 
	return 0; 
} 
2000/1107    
 
static void 
2000/1109    
sendaudio(IOstat *b) { 
	if (dmastart(b->chan, b->current->virt, b->current->nbytes)) { 
		b->current->active++; 
		b->current++; 
2000/1110    
	/* call this with lock held */ 
	while (b->next != b->filling) { 
		assert(b->next->nbytes); 
		if (dmastart(b->dma, b->next->virt, b->next->nbytes) == 0) 
			break; 
		incref(&b->active); 
		b->next++; 
		if (b->next == &b->buf[Nbuf]) 
			b->next == &b->buf[0]; 
	} 
} 
 
static void 
audiointr(void *x, ulong state) { 
	IOstate *s = x; 
 
	if (s == &audio.o) { 
		decref(&s->active); 
		/* Only interrupt routine touches s->current */ 
		s->current->nbytes = 0; 
		s->current++; 
2000/1109    
		if (b->current == &b->buf[Nbuf]) 
			b->current == &b->buf[0]; 
2000/1110    
		if (canlock(s)) { 
			sendaudio(s); 
			unlock(s); 
		} 
2000/1109    
	} 
2000/1110    
	wakeup(s->vous); 
2000/1109    
} 
2000/1107    
 
static Chan* 
2000/1109/sys/src/9/bitsy/devuda1341.c:471,4772000/1110/sys/src/9/bitsy/devuda1341.c:546,553
2000/1107    
 
	case Qaudio: 
2000/1109    
		omode = (omode & 0x7) + 1; 
		if (omode & ~(Aread | Awrite)) 
2000/1110    
//		if (omode & ~(Aread | Awrite)) 
		if (omode & ~(Awrite)) 
2000/1108    
			error(Ebadarg); 
2000/1107    
		qlock(&audio); 
2000/1108    
		if(audio.amode & omode){ 
2000/1109/sys/src/9/bitsy/devuda1341.c:478,4962000/1110/sys/src/9/bitsy/devuda1341.c:554,578
2000/1107    
			qunlock(&audio); 
			error(Einuse); 
		} 
2000/1110    
		audiopower(1); 
2000/1109    
		if (omode & Aread) { 
2000/1108    
			/* read */ 
2000/1109    
			audio.amode |= Aread; 
			if(audio.i.bufinit == 0) 
				bufinit(&audio.i); 
2000/1110    
			audio.i.chan = c; 
2000/1109    
			setempty(&audio.i); 
2000/1108    
		} 
		if (omode & 0x2) { 
			/* write */ 
2000/1110    
			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; 
			&audio.o.dma = dmaalloc(0, 0, 8, 2, AudioDMA, void *port, void (*f)(int, ulong)) 
2000/1107    
		} 
		qunlock(&audio); 
2000/1109    
//		mxvolume(); 
2000/1109/sys/src/9/bitsy/devuda1341.c:507,5132000/1110/sys/src/9/bitsy/devuda1341.c:589,595
2000/1107    
static void 
audioclose(Chan *c) 
{ 
	Buf *b; 
2000/1110    
	IOstate *b; 
2000/1107    
 
	switch(c->qid.path & ~CHDIR) { 
	default: 
2000/1109/sys/src/9/bitsy/devuda1341.c:522,5432000/1110/sys/src/9/bitsy/devuda1341.c:604,641
2000/1107    
	case Qaudio: 
		if(c->flag & COPEN) { 
			qlock(&audio); 
2000/1109    
			if(audio.amode & Awrite) { 
2000/1107    
				/* flush out last partial buffer */ 
2000/1109    
				b = audio.o.filling; 
				if(audio.o.buf[b].count) { 
2000/1107    
					putbuf(&audio.full, b); 
				} 
			} 
			audio.amode = Aclosed; 
2000/1110    
			qlock(&audio.o); 
2000/1107    
			if(waserror()){ 
2000/1110    
				qunlock(&audio.o); 
2000/1107    
				qunlock(&audio); 
				nexterror(); 
			} 
			while(audio.active) 
				waitaudio(); 
			setempty(); 
2000/1110    
			if (audio.o.chan == c) { 
				/* closing the write end */ 
				audio.amode &= ~Awrite; 
 
				while (audio.o.filling->nbytes) { 
					audio.o.filling++; 
					if (audio.o.filling == &audio.o.buf[Nbuf]) 
						audio.o.filling = &audio.o.buf[0]; 
					sendaudio(&audio.o); 
				} 
				while(!audioidle(&audio.o)) 
					sleep(&audio.o.vous, audioidle, &audio.o); 
				audioamplifier(0); 
				setempty(&audio.o); 
			} 
			if (audio.i.chan == c) { 
				/* closing the read end */ 
				audio.amode &= ~Aread; 
				setempty(&audio.i); 
			} 
			if (audio.amode == 0) { 
				/* turn audio off */ 
				audiopower(0); 
			} 
2000/1107    
			poperror(); 
2000/1110    
			qunlock(&audio.o); 
2000/1107    
			qunlock(&audio); 
		} 
		break; 
2000/1109/sys/src/9/bitsy/devuda1341.c:566,6052000/1110/sys/src/9/bitsy/devuda1341.c:664,669
2000/1107    
		return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); 
 
	case Qaudio: 
		if(audio.amode != Aread) 
			error(Emode); 
		qlock(&audio); 
		if(waserror()){ 
			qunlock(&audio); 
			nexterror(); 
		} 
		while(n > 0) { 
			b = audio.filling; 
			if(b == 0) { 
				b = getbuf(&audio.full); 
				if(b == 0) { 
					waitaudio(); 
					continue; 
				} 
				audio.filling = b; 
				swab(b->virt); 
				audio.curcount = 0; 
			} 
			m = Bufsize-audio.curcount; 
			if(m > n) 
				m = n; 
			memmove(a, b->virt+audio.curcount, m); 
                 
			audio.curcount += m; 
			n -= m; 
			a += m; 
			if(audio.curcount >= Bufsize) { 
				audio.filling = 0; 
				putbuf(&audio.empty, b); 
			} 
		} 
		poperror(); 
		qunlock(&audio); 
		break; 
 
	case Qstatus: 
2000/1109/sys/src/9/bitsy/devuda1341.c:752,7592000/1110/sys/src/9/bitsy/devuda1341.c:816,823
2000/1107    
		} 
		while(n > 0) { 
2000/1109    
			/* wait if dma in progress */ 
			while (a->filling->active) 
				waitaudio(a); 
2000/1110    
			while (a->active && a->filling == a->current) 
				sleep(&a->vous, audioqnotfull, a); 
2000/1107    
 
2000/1109    
			m = Bufsize - a->filling->nbytes; 
2000/1107    
			if(m > n) 
2000/1109/sys/src/9/bitsy/devuda1341.c:764,7732000/1110/sys/src/9/bitsy/devuda1341.c:828,837
2000/1107    
			n -= m; 
2000/1109    
			p += m; 
			if(a->filling->nbytes >= Bufsize) { 
				sendaudio(a); 
				a->filling++; 
				if (a->filling == &a->buf[Nbuf]) 
					a->filling = a->buf; 
2000/1110    
				sendaudio(a); 
2000/1107    
			} 
		} 
		poperror(); 


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