| 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,54 – 2000/1117/sys/src/9/bitsy/devuda1341.c:41,54 (short | long | prev | next) | ||
| 2000/1103 | */ /* | |
| 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 */ | |
| 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,82 – 2000/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 |
| |
| 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,96 – 2000/1117/sys/src/9/bitsy/devuda1341.c:90,96 | ||
| 2000/1103 | Qstatus, Fmono = 1, | |
| 2000/1117 | Fin = 2, | |
| 2000/1103 | Fout = 4, Aclosed = 0, | |
| 2000/1116/sys/src/9/bitsy/devuda1341.c:98,108 – 2000/1117/sys/src/9/bitsy/devuda1341.c:98,104 | ||
| 2000/1103 | Awrite, Vaudio = 0, | |
| 2000/1116/sys/src/9/bitsy/devuda1341.c:164,169 – 2000/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,188 – 2000/1117/sys/src/9/bitsy/devuda1341.c:171,181 | ||
| 2000/1103 | int irval; } volumes[] = { | |
| 2000/1117 | [Vaudio] "audio", Fout|Fmono, 50, 50, [Vmic] "mic", Fin, 0, 0, | |
| 2000/1103 |
| |
| 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,439 – 2000/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 | |
| 2000/1117 | enable(void) | |
| 2000/1110 | { | |
| 2000/1111 |
| |
| 2000/1117 | ushort data; | |
| 2000/1103 | L3_init(); | |
| 2000/1110 | /* Setup the uarts */ | |
| 2000/1116 |
| |
| 2000/1117 | ppcregs->assignment &= ~(1<<18); | |
| 2000/1103 | ||
| 2000/1111 |
| |
| 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,523 – 2000/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 |
| |
| 2000/1116 |
| |
| 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 |
| |
| 2000/1111 |
| |
| 2000/1116 |
| |
| 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] */ | |
| 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 |
| |
| 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 |
| |
| 2000/1116 |
| |
| 2000/1111 |
| |
| 2000/1117 | static void resetlevel(void) { int i; | |
| 2000/1111 |
| |
| 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 |
| |
| 2000/1117 | static void mxvolume(void) { int *left, *right; | |
| 2000/1111 |
| |
| 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 |
| |
| 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) { | |
| 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 |
| |
| 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"); | |
| 2000/1110 |
| |
| 2000/1116 |
| |
| 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++; | |
| 2000/1115 |
| |
| 2000/1110 |
| |
| 2000/1111 |
| |
| 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 |
| |
| 2000/1117 | iunlock(&s->ilock); | |
| 2000/1110 | } static void | |
| 2000/1116/sys/src/9/bitsy/devuda1341.c:557,562 – 2000/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,608 – 2000/1117/sys/src/9/bitsy/devuda1341.c:659,691 | ||
| 2000/1107 | qunlock(&audio); error(Einuse); } | |
| 2000/1111 |
| |
| 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 |
| |
| 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; | |
| 2000/1110 |
| |
| 2000/1114 |
| |
| 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 |
| |
| 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,623 – 2000/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,665 – 2000/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 |
| |
| 2000/1107 | if(waserror()){ | |
| 2000/1110 |
| |
| 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 |
| |
| 2000/1110 |
| |
| 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 |
| |
| 2000/1117 | dmawait(s->dma); outdisable(); | |
| 2000/1111 | amplifierpower(0); | |
| 2000/1110 |
| |
| 2000/1116 |
| |
| 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,677 – 2000/1117/sys/src/9/bitsy/devuda1341.c:756,767 | ||
| 2000/1110 | /* turn audio off */ audiopower(0); } | |
| 2000/1107 |
| |
| 2000/1110 |
| |
| 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,814 – 2000/1117/sys/src/9/bitsy/devuda1341.c:897,904 | ||
| 2000/1107 | } if(strcmp(field[i], "reset") == 0) { | |
| 2000/1111 |
| |
| 2000/1117 | resetlevel(); mxvolume(); | |
| 2000/1107 | goto cont0; } if(strcmp(field[i], "in") == 0) { | |