1400 lines · 29.6 KB · C
RawDownload
/* *	SAC/UDA 1341 Audio driver for the Bitsy * *	The Philips UDA 1341 sound chip is accessed through the Serial Audio *	Controller (SAC) of the StrongARM SA-1110.  This is much more a SAC *	controller than a UDA controller, but we have a devsac.c already. * *	The code morphs Nicolas Pitre's <nico@cam.org> Linux controller *	and Ken's Soundblaster controller. * *	The interface should be identical to that of devaudio.c */#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include	"io.h"#include	"sa1110dma.h" static int debug = 0; /* * GPIO based L3 bus support. * * This provides control of Philips L3 type devices.  * GPIO lines are used for clock, data and mode pins. * * Note: The L3 pins are shared with I2C devices. This should not present * any problems as long as an I2C start sequence is not generated. This is * defined as a 1->0 transition on the data lines when the clock is high. * It is critical this code only allow data transitions when the clock * is low. This is always legal in L3. * * The IIC interface requires the clock and data pin to be LOW when idle. We * must make sure we leave them in this state. * * It appears the read data is generated on the falling edge of the clock * and should be held stable during the clock high time. */ /*  * L3 setup and hold times (expressed in µs) */enum {	L3_AcquireTime =		1,	L3_ReleaseTime =		1,	L3_DataSetupTime =	(190+999)/1000,	/* 190 ns */	L3_DataHoldTime =		( 30+999)/1000,	L3_ModeSetupTime =	(190+999)/1000,	L3_ModeHoldTime =	(190+999)/1000,	L3_ClockHighTime =	(100+999)/1000,	L3_ClockLowTime =		(100+999)/1000,	L3_HaltTime =			(190+999)/1000,}; /* UDA 1341 Registers */enum {	/* Status0 register */	UdaStatusDC		= 0,	/* 1 bit */	UdaStatusIF		= 1,	/* 3 bits */	UdaStatusSC		= 4,	/* 2 bits */	UdaStatusRST		= 6,	/* 1 bit */}; enum {	/* Status1 register */	UdaStatusPC	= 0,	/* 2 bits */	UdaStatusDS	= 2,	/* 1 bit */	UdaStatusPDA	= 3,	/* 1 bit */	UdaStatusPAD	= 4,	/* 1 bit */	UdaStatusIGS	= 5,	/* 1 bit */	UdaStatusOGS	= 6,	/* 1 bit */}; /* * UDA1341 L3 address and command types */ enum {	UDA1341_DATA0 =	0,	UDA1341_DATA1,	UDA1341_STATUS,	UDA1341_L3Addr = 0x14,}; typedef struct	AQueue	AQueue;typedef struct	Buf	Buf;typedef struct	IOstate IOstate; enum{	Qdir		= 0,	Qaudio,	Qvolume,	Qstatus,	Qstats, 	Fmono		= 1,	Fin			= 2,	Fout			= 4, 	Aclosed		= 0,	Aread,	Awrite, 	Vaudio		= 0,	Vmic,	Vtreb,	Vbass,	Vspeed,	Vbufsize,	Vfilter,	Vinvert,	Nvol, 	Bufsize		= 4* 1024,	/* 46 ms each */	Nbuf			= 10,			/* 1.5 seconds total */ 	Speed		= 44100,	Ncmd		= 50,			/* max volume command words */}; enum {	Flushbuf = 0xe0000000,}; /* System Clock -- according to the manual, it seems that when the UDA is    configured in non MSB/I2S mode, it uses a divisor of 256 to the 12.288MHz    clock.  The other rates are only supported in MSB mode, which should be     implemented at some point */enum {	SC512FS = 0 << 2,	SC384FS = 1 << 2,	SC256FS = 2 << 2,	CLOCKMASK = 3 << 2,}; /* Format */enum {	LSB16 =	1 << 1,	LSB18 =	2 << 1,	LSB20 =	3 << 1,	MSB =	4 << 1,	MSB16 =	5 << 1,	MSB18 =	6 << 1,	MSB20 =	7 << 1,}; Dirtabaudiodir[] ={ 	".",			{Qdir, 0, QTDIR},	0,	DMDIR|0555,	"audio",		{Qaudio},			0,	0666,	"volume",		{Qvolume},		0,	0666,	"audiostatus",	{Qstatus},			0,	0444,	"audiostats",	{Qstats},			0,	0444,}; struct	Buf{	uchar*	virt;	ulong	phys;	uint	nbytes;}; struct	IOstate{	QLock;	Lock			ilock;	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 */	volatile Buf	*current;		/* next dma to finish */	volatile Buf	*next;		/* next candidate for dma */	volatile Buf	*filling;		/* buffer being filled *//* to have defines just like linux — there's a real operating system */#define emptying filling}; static	struct{	QLock;	int		amode;			/* Aclosed/Aread/Awrite for /audio */	int		intr;			/* boolean an interrupt has happened */	int		rivol[Nvol];	/* right/left input/output volumes */	int		livol[Nvol];	int		rovol[Nvol];	int		lovol[Nvol];	ulong	totcount;		/* how many bytes processed since open */	vlong	tottime;		/* time at which totcount bytes were processed */	IOstate	i;	IOstate	o;} audio; int	zerodma;	/* dma buffer used for sending zero */ typedef struct Iostats Iostats;struct Iostats {	ulong	totaldma;	ulong	idledma;	ulong	faildma;	ulong	samedma;	ulong	empties;}; static struct{	ulong	bytes;	Iostats	rx, tx;} iostats; static void setaudio(int in, int out, int left, int right, int value);static void setspeed(int in, int out, int left, int right, int value);static void setbufsize(int in, int out, int left, int right, int value); static	struct{	char*	name;	int		flag;	int		ilval;		/* initial  values */	int		irval;	void		(*setval)(int, int, int, int, int);} volumes[] ={[Vaudio]	{"audio",		Fout|Fmono,	 	80,		80,	setaudio },[Vmic]	{"mic",		Fin|Fmono,		  0,		  0,	nil },[Vtreb]	{"treb",		Fout|Fmono,		50,		50,	nil },[Vbass]	{"bass",		Fout|Fmono, 		50,		50,	nil },[Vspeed]	{"speed",		Fin|Fout|Fmono,	Speed,	Speed,	setspeed },[Vbufsize]	{"bufsize",	Fin|Fout|Fmono,	Bufsize,	Bufsize,	setbufsize },[Vfilter]	{"filter",		Fout|Fmono,		  0,		  0,	nil },[Vinvert]	{"invert",		Fin|Fout|Fmono,	  0,		  0,	nil },[Nvol]	{0}}; static void	setreg(char *name, int val, int n); /* * Grab control of the IIC/L3 shared pins */static voidL3_acquirepins(void){	gpioregs->set = (GPIO_L3_MODE_o | GPIO_L3_SCLK_o | GPIO_L3_SDA_io);	gpioregs->direction |=  (GPIO_L3_MODE_o | GPIO_L3_SCLK_o | GPIO_L3_SDA_io);	microdelay(L3_AcquireTime);} /* * Release control of the IIC/L3 shared pins */static voidL3_releasepins(void){	gpioregs->direction &= ~(GPIO_L3_MODE_o | GPIO_L3_SCLK_o | GPIO_L3_SDA_io);	microdelay(L3_ReleaseTime);} /* * Initialize the interface */static void L3_init(void){	gpioregs->altfunc &= ~(GPIO_L3_SDA_io | GPIO_L3_SCLK_o | GPIO_L3_MODE_o);	L3_releasepins();} /* * Get a bit. The clock is high on entry and on exit. Data is read after * the clock low time has expired. */static intL3_getbit(void){	int data; 	gpioregs->clear = GPIO_L3_SCLK_o;	microdelay(L3_ClockLowTime); 	data = (gpioregs->level & GPIO_L3_SDA_io) ? 1 : 0;  	gpioregs->set = GPIO_L3_SCLK_o;	microdelay(L3_ClockHighTime); 	return data;} /* * Send a bit. The clock is high on entry and on exit. Data is sent only * when the clock is low (I2C compatibility). */static voidL3_sendbit(int bit){	gpioregs->clear = GPIO_L3_SCLK_o; 	if (bit & 1)		gpioregs->set = GPIO_L3_SDA_io;	else		gpioregs->clear = GPIO_L3_SDA_io; 	/* Assumes L3_DataSetupTime < L3_ClockLowTime */	microdelay(L3_ClockLowTime); 	gpioregs->set = GPIO_L3_SCLK_o;	microdelay(L3_ClockHighTime);} /* * Send a byte. The mode line is set or pulsed based on the mode sequence * 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 voidL3_sendbyte(char data, int mode){	int i; 	switch(mode) {	case 0: /* Address mode */		gpioregs->clear = GPIO_L3_MODE_o;		break;	case 1: /* First data byte */		break;	default: /* Subsequent bytes */		gpioregs->clear = GPIO_L3_MODE_o;		microdelay(L3_HaltTime);		gpioregs->set = GPIO_L3_MODE_o;		break;	} 	microdelay(L3_ModeSetupTime); 	for (i = 0; i < 8; i++)		L3_sendbit(data >> i); 	if (mode == 0)  /* Address mode */		gpioregs->set = GPIO_L3_MODE_o; 	microdelay(L3_ModeHoldTime);} /* * Get a byte. The mode line is set or pulsed based on the mode sequence * count. The mode line is high on entry and exit. The mod line is pulsed * before the second data byte and before each byte thereafter. This * function is never valid with mode == 0 (address cycle) as the address * is always sent on the bus, not read. */static charL3_getbyte(int mode){	char data = 0;	int i; 	switch(mode) {	case 0: /* Address mode - never valid */		break;	case 1: /* First data byte */		break;	default: /* Subsequent bytes */		gpioregs->clear = GPIO_L3_MODE_o;		microdelay(L3_HaltTime);		gpioregs->set = GPIO_L3_MODE_o;		break;	} 	microdelay(L3_ModeSetupTime); 	for (i = 0; i < 8; i++)		data |= (L3_getbit() << i); 	microdelay(L3_ModeHoldTime); 	return data;} /* * Write data to a device on the L3 bus. The address is passed as well as * the data and length. The length written is returned. The register space * is encoded in the address (low two bits are set and device address is * in the upper 6 bits). */static intL3_write(uchar addr, uchar *data, int len){	int mode = 0;	int bytes = len; 	L3_acquirepins();	L3_sendbyte(addr, mode++);	while(len--)		L3_sendbyte(*data++, mode++);	L3_releasepins();	return bytes;} /* * Read data from a device on the L3 bus. The address is passed as well as * the data and length. The length read is returned. The register space * is encoded in the address (low two bits are set and device address is * in the upper 6 bits).  * Commented out, not usedstatic intL3_read(uchar addr, uchar *data, int len){	int mode = 0;	int bytes = len; 	L3_acquirepins();	L3_sendbyte(addr, mode++);	gpioregs->direction &= ~(GPIO_L3_SDA_io);	while(len--)		*data++ = L3_getbyte(mode++);	L3_releasepins();	return bytes;} */ voidaudiomute(int on){	egpiobits(EGPIO_audio_mute, on);} static	char	Emode[]		= "illegal open mode";static	char	Evolume[]	= "illegal volume specifier"; static voidbufinit(IOstate *b){	int i; 	if (debug) print("bufinit\n");	for (i = 0; i < Nbuf; i++) {		b->buf[i].virt = xalloc(Bufsize);		b->buf[i].phys = PADDR(b->buf[i].virt);		memset(b->buf[i].virt, 0xAA, Bufsize);	}	b->bufinit = 1;}; static voidsetempty(IOstate *b){	int i; 	if (debug) print("setempty\n");	for (i = 0; i < Nbuf; i++) {		b->buf[i].nbytes = 0;	}	b->filling = b->buf;	b->current = b->buf;	b->next = b->buf;} static intaudioqnotempty(void *x){	IOstate *s = x; 	return dmaidle(s->dma) || s->emptying != s->current;} static intaudioqnotfull(void *x){	IOstate *s = x; 	return dmaidle(s->dma) || s->filling != s->current;} SSPregs *sspregs;MCPregs	*mcpregs; static voidaudioinit(void){	/* Turn MCP operations off */	mcpregs = mapspecial(MCPREGS, sizeof(MCPregs));	mcpregs->status &= ~(1<<16); 	sspregs = mapspecial(SSPREGS, sizeof(SSPregs)); } uchar	status0[1]		= {0x02};uchar	status1[1]		= {0x80};uchar	data00[1]		= {0x00};		/* volume control, bits 0 – 5 */uchar	data01[1]		= {0x40};uchar	data02[1]		= {0x80};uchar	data0e0[2]	= {0xc0, 0xe0};uchar	data0e1[2]	= {0xc1, 0xe0};uchar	data0e2[2]	= {0xc2, 0xf2};

Lines 1–500 of 1400.