| 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,22 – 2000/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,128 – 2000/1110/sys/src/9/bitsy/devuda1341.c:123,128 | ||
| 2000/1103 | struct Buf { | |
| 2000/1109 |
| |
| 2000/1103 | uchar* virt; | |
| 2000/1109 | uint nbytes; | |
| 2000/1103 | }; | |
| 2000/1109/sys/src/9/bitsy/devuda1341.c:130,140 – 2000/1110/sys/src/9/bitsy/devuda1341.c:130,144 | ||
| 2000/1109 | struct IOstate | |
| 2000/1103 | { QLock; | |
| 2000/1109 |
| |
| 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,205 – 2000/1110/sys/src/9/bitsy/devuda1341.c:181,212 | ||
| 2000/1103 | /* * Grab control of the IIC/L3 shared pins */ | |
| 2000/1104 |
| |
| 2000/1110 | static void L3_acquirepins(void) | |
| 2000/1103 | { | |
| 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 |
| |
| 2000/1110 | static void L3_releasepins(void) | |
| 2000/1103 | { | |
| 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 */ | |
| 2000/1110 | static void L3_init(void) | |
| 2000/1103 | { | |
| 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,223 – 2000/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 |
| |
| 2000/1110 | static int L3_getbit(void) | |
| 2000/1103 | { int data; | |
| 2000/1110 | gpioregs->clear = GPIO_L3_SCLK_o; µdelay(L3_ClockLowTime); | |
| 2000/1103 |
| |
| 2000/1110 | data = (gpioregs->level & GPIO_L3_SDA_io) ? 1 : 0; | |
| 2000/1103 |
| |
| 2000/1110 | gpioregs->set = GPIO_L3_SCLK_o; µdelay(L3_ClockHighTime); | |
| 2000/1103 | return data; } | |
| 2000/1109/sys/src/9/bitsy/devuda1341.c:226,245 – 2000/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 |
| |
| 2000/1110 | static void L3_sendbit(int bit) | |
| 2000/1103 | { | |
| 2000/1110 | gpioregs->clear = GPIO_L3_SCLK_o; | |
| 2000/1103 | if (bit & 1) | |
| 2000/1110 | gpioregs->set = GPIO_L3_SDA_io; | |
| 2000/1103 | else | |
| 2000/1110 | gpioregs->clear = GPIO_L3_SDA_io; | |
| 2000/1103 | /* Assumes L3_DataSetupTime < L3_ClockLowTime */ | |
| 2000/1110 | µdelay(L3_ClockLowTime); | |
| 2000/1103 |
| |
| 2000/1110 | gpioregs->set = GPIO_L3_SCLK_o; µdelay(L3_ClockHighTime); | |
| 2000/1103 | } /* | |
| 2000/1109/sys/src/9/bitsy/devuda1341.c:247,253 – 2000/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. */ | |
| 2000/1110 | static void L3_sendbyte(char data, int mode) | |
| 2000/1103 | { int i; | |
| 2000/1109/sys/src/9/bitsy/devuda1341.c:254,280 – 2000/1110/sys/src/9/bitsy/devuda1341.c:264,290 | ||
| 2000/1103 | L3_acquirepins(); switch(mode) { | |
| 2000/1110 | case 0: /* Address mode */ gpioregs->clear = GPIO_L3_MODE_o; | |
| 2000/1103 | break; | |
| 2000/1110 | case 1: /* First data byte */ | |
| 2000/1103 | break; | |
| 2000/1110 | default: /* Subsequent bytes */ gpioregs->clear = GPIO_L3_MODE_o; µdelay(L3_HaltTime); gpioregs->set = GPIO_L3_MODE_o; | |
| 2000/1103 | break; } | |
| 2000/1110 | µdelay(L3_ModeSetupTime); | |
| 2000/1103 | for (i = 0; i < 8; i++) L3_sendbit(data >> i); if (mode == 0) /* Address mode */ | |
| 2000/1110 | gpioregs->set = GPIO_L3_MODE_o; | |
| 2000/1103 |
| |
| 2000/1110 | µdelay(L3_ModeHoldTime); | |
| 2000/1103 | L3_releasepins(); } | |
| 2000/1109/sys/src/9/bitsy/devuda1341.c:286,317 – 2000/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. */ | |
| 2000/1110 | static char L3_getbyte(int mode) | |
| 2000/1103 | { char data = 0; int i; L3_acquirepins(); | |
| 2000/1110 | gpioregs->direction &= ~(GPIO_L3_SDA_io); | |
| 2000/1103 | switch(mode) { | |
| 2000/1110 | case 0: /* Address mode - never valid */ | |
| 2000/1103 | break; | |
| 2000/1110 | case 1: /* First data byte */ | |
| 2000/1103 | break; | |
| 2000/1110 | default: /* Subsequent bytes */ gpioregs->clear = GPIO_L3_MODE_o; µdelay(L3_HaltTime); gpioregs->set = GPIO_L3_MODE_o; | |
| 2000/1103 | break; } | |
| 2000/1110 | µdelay(L3_ModeSetupTime); | |
| 2000/1103 | for (i = 0; i < 8; i++) data |= (L3_getbit() << i); | |
| 2000/1110 | µdelay(L3_ModeHoldTime); | |
| 2000/1103 | L3_releasepins(); | |
| 2000/1109/sys/src/9/bitsy/devuda1341.c:324,330 – 2000/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). */ | |
| 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,348 – 2000/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). */ | |
| 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,405 – 2000/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; | |
| 2000/1110 | /* Setup the uarts */ ppcregs->assignment &= ~(1<<18); /* Could be the other way round! */ | |
| 2000/1103 |
| |
| 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,438 – 2000/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 ); | |
| 2000/1110 | print("audio enabled\n"); | |
| 2000/1103 |
| |
| 2000/1107 | static void | |
| 2000/1109 | sendaudio(IOstat *b) { | |
| 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,477 – 2000/1110/sys/src/9/bitsy/devuda1341.c:546,553 | ||
| 2000/1107 | case Qaudio: | |
| 2000/1109 | omode = (omode & 0x7) + 1; | |
| 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,496 – 2000/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,513 – 2000/1110/sys/src/9/bitsy/devuda1341.c:589,595 | ||
| 2000/1107 | static void audioclose(Chan *c) { | |
| 2000/1110 | IOstate *b; | |
| 2000/1107 | switch(c->qid.path & ~CHDIR) { default: | |
| 2000/1109/sys/src/9/bitsy/devuda1341.c:522,543 – 2000/1110/sys/src/9/bitsy/devuda1341.c:604,641 | ||
| 2000/1107 | case Qaudio: if(c->flag & COPEN) { qlock(&audio); | |
| 2000/1109 |
| |
| 2000/1107 |
| |
| 2000/1109 |
| |
| 2000/1107 |
| |
| 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) { /* 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,605 – 2000/1110/sys/src/9/bitsy/devuda1341.c:664,669 | ||
| 2000/1107 | return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); case Qaudio: | |
| 2000/1109/sys/src/9/bitsy/devuda1341.c:752,759 – 2000/1110/sys/src/9/bitsy/devuda1341.c:816,823 | ||
| 2000/1107 | } while(n > 0) { | |
| 2000/1109 | /* wait if dma in progress */ | |
| 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,773 – 2000/1110/sys/src/9/bitsy/devuda1341.c:828,837 | ||
| 2000/1107 | n -= m; | |
| 2000/1109 | p += m; if(a->filling->nbytes >= Bufsize) { | |
| 2000/1110 | sendaudio(a); | |
| 2000/1107 | } } poperror(); | |