M bitsy/dat.h => bitsy/dat.h +1 -1
@@ 316,7 316,7 @@ struct Cisdat
*/
struct PCMslot
{
- Ref;
+ Ref ref;
long memlen; /* memory length */
uchar slotno; /* slot number */
M bitsy/devpcmcia.c => bitsy/devpcmcia.c +16 -8
@@ 86,6 86,9 @@ pcmciareset(void)
/* set timing to the default, 300 */
slottiming(0, 300, 300, 300, 0);
slottiming(1, 300, 300, 300, 0);
+
+ /* interrupt on card insertion */
+ gpiointrenable(
}
static Chan*
@@ 286,7 289,7 @@ Dev pcmciadevtab = {
/* see what's there */
static void
-slotinfo(void)
+slotinfo(Ureg*, void*)
{
ulong x = gpioregs->level;
@@ 295,8 298,14 @@ slotinfo(void)
slot[0].occupied = 0;
slot[1].occupied = 0;
} else {
- slot[0].occupied = (x & GPIO_CARD_IND0_i) == 0;
- slot[1].occupied = (x & GPIO_CARD_IND1_i) == 0;
+ if(!slot[0].occupied && (x & GPIO_CARD_IND0_i)){
+ slot[0].occupied = 1;
+ slot[0].cisread = 0;
+ }
+ if(!slot[1].occupied && (x & GPIO_CARD_IND1_i)){
+ slot[1].occupied = 1;
+ slot[0].cisread = 0;
+ }
}
}
@@ 304,21 313,20 @@ slotinfo(void)
static void
increfp(PCMslot *pp)
{
+ slotinfo(nil, nil);
if(incref(&pcmcia) == 1){
egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 1);
egpiobits(EGPIO_pcmcia_reset, 0);
- delay(100); /* time to power up */
+ delay(200); /* time to power up */
}
-
incref(pp);
-
- slotinfo();
+ if(pp->occupied && pp->cisread == 0)
+ pcmcisread(pp);
}
static void
decrefp(PCMslot *pp)
{
- slotinfo();
decref(pp);
if(decref(&pcmcia) == 0)
egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
M bitsy/devuda1341.c => bitsy/devuda1341.c +85 -37
@@ 19,7 19,7 @@
#include "io.h"
#include "sa1110dma.h"
-static int debug = 2;
+static int debug = 0;
/*
* GPIO based L3 bus support.
@@ 382,6 382,12 @@ L3_read(uchar addr, uchar *data, int len)
return bytes;
}
+void
+audiomute(int on)
+{
+ egpiobits(EGPIO_audio_mute, on);
+}
+
static char Emode[] = "illegal open mode";
static char Evolume[] = "illegal volume specifier";
@@ 390,7 396,7 @@ bufinit(IOstate *b)
{
int i;
- if (debug) print("#A: bufinit\n");
+ 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);
@@ 403,7 409,7 @@ setempty(IOstate *b)
{
int i;
- if (debug) print("#A: setempty\n");
+ if (debug) print("setempty\n");
for (i = 0; i < Nbuf; i++) {
b->buf[i].nbytes = 0;
}
@@ 470,7 476,7 @@ enable(void)
sspregs->control0 = 0x039f; /* enable */
/* Enable the audio power */
- audiopower(1);
+ egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
/* external clock configured for 44100 samples/sec */
gpioregs->set = GPIO_CLK_SET0_o;
@@ 492,15 498,14 @@ enable(void)
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e6, 2 );
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);
+ print("enable: status0 = 0x%2.2ux\n", status0);
+ print("enable: status1 = 0x%2.2ux\n", status1);
+ print("enable: data02 = 0x%2.2ux\n", data02);
+ print("enable: data0e2 = 0x%4.4ux\n", data0e2);
+ print("enable: data0e4 = 0x%4.4ux\n", data0e4);
+ print("enable: data0e6 = 0x%4.4ux\n", data0e6);
+ print("enable: sspregs->control0 = 0x%lux\n", sspregs->control0);
+ print("enable: sspregs->control1 = 0x%lux\n", sspregs->control1);
}
}
@@ 521,7 526,6 @@ static void
mxvolume(void) {
int *left, *right;
- if (debug) print("mxvolume\n");
if(audio.amode & Aread){
left = audio.livol;
right = audio.rivol;
@@ 540,7 544,16 @@ mxvolume(void) {
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 );
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e5, 2 );
}
-
+ if (left[Vinvert]+right[Vinvert] == 0)
+ status1 &= ~0x04;
+ else
+ status1 |= 0x04;
+ L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
+ if (debug) {
+ print("mxvolume: status1 = 0x%2.2ux\n", status1);
+ print("mxvolume: data0e4 = 0x%4.4ux\n", data0e4);
+ print("mxvolume: data0e5 = 0x%4.4ux\n", data0e5);
+ }
}
if(audio.amode & Awrite){
left = audio.lovol;
@@ 562,27 575,26 @@ mxvolume(void) {
else
data02 |= 0x10;
if (left[Vinvert]+right[Vinvert] == 0)
- status1 &= ~0x14;
+ status1 &= ~0x10;
else
- status1 |= 0x14;
+ status1 |= 0x10;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data01, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1);
if (debug) {
- print("uchar status1 = 0x%2.2ux;\n", status1);
- print("uchar data00 = 0x%2.2ux; /* audio out */\n", data00);
- print("uchar data01 = 0x%2.2ux; /* bass&treb */\n", data01);
- print("uchar data02 = 0x%2.2ux; /* mode */\n", data02);
+ print("mxvolume: status1 = 0x%2.2ux\n", status1);
+ print("mxvolume: data00 = 0x%2.2ux\n", data00);
+ print("mxvolume: data01 = 0x%2.2ux\n", data01);
+ print("mxvolume: data02 = 0x%2.2ux\n", data02);
}
}
-
}
static void
outenable(void) {
/* turn on DAC, set output gain switch */
- amplifierpower(1);
+ egpiobits(EGPIO_audio_power, 1);
audiomute(0);
status1 |= 0x41;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
@@ 590,40 602,62 @@ outenable(void) {
data00 |= 0xf;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1);
if (debug) {
- print("uchar status1 = 0x%2.2ux\n", status1);
- print("uchar data00 = 0x%2.2ux\n", data00);
+ print("outenable: status1 = 0x%2.2ux\n", status1);
+ print("outenable: data00 = 0x%2.2ux\n", data00);
}
}
static void
outdisable(void) {
+ dmastop(audio.o.dma);
/* turn off DAC, clear output gain switch */
audiomute(1);
- amplifierpower(0);
+ egpiobits(EGPIO_audio_power, 0);
status1 &= ~0x41;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
if (debug) {
- print("uchar status1 = 0x%2.2ux\n", status1);
+ print("outdisable: status1 = 0x%2.2ux\n", status1);
}
+ egpiobits(EGPIO_audio_power, 0);
}
static void
inenable(void) {
/* turn on ADC, set input gain switch */
+// egpiobits(EGPIO_audio_power, 1);
+// audiomute(0);
status1 |= 0x22;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
if (debug) {
- print("uchar status1 = 0x%2.2ux\n", status1);
+ print("inenable: status1 = 0x%2.2ux\n", status1);
}
}
static void
indisable(void) {
+ dmastop(audio.i.dma);
/* 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);
+ print("indisable: status1 = 0x%2.2ux\n", status1);
+ }
+}
+
+static void
+disable(void) {
+ egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0);
+}
+
+static void
+audiopower(int flag) {
+ if (flag) {
+ egpiobits(EGPIO_audio_power, 1);
+ egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
+ } else {
+ /* power off */
+ egpiobits(EGPIO_audio_power, 0);
+ egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0);
}
}
@@ 649,7 683,12 @@ sendaudio(IOstate *s) {
iostats.faildma++;
break;
}
- if (debug > 1) print("#A: dmastart @%p\n", s->next);
+ if (debug) {
+ if (debug > 1)
+ print("dmastart @%p\n", s->next);
+ else
+ iprint("+");
+ }
s->next->nbytes = 0;
s->next++;
if (s->next == &s->buf[Nbuf])
@@ 680,7 719,12 @@ recvaudio(IOstate *s) {
iostats.faildma++;
break;
}
- if (debug > 1) print("#A: dmastart @%p\n", s->next);
+ if (debug) {
+ if (debug > 1)
+ print("dmastart @%p\n", s->next);
+ else
+ iprint("+");
+ }
s->next++;
if (s->next == &s->buf[Nbuf])
s->next = &s->buf[0];
@@ 692,7 736,12 @@ static void
audiointr(void *x, ulong ndma) {
IOstate *s = x;
- if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current);
+ if (debug) {
+ if (debug > 1)
+ iprint("#A: audio interrupt @%p\n", s->current);
+ else
+ iprint("-");
+ }
/* Only interrupt routine touches s->current */
s->current++;
if (s->current == &s->buf[Nbuf])
@@ 762,7 811,7 @@ audioopen(Chan *c, int mode)
setempty(s);
s->emptying = &s->buf[Nbuf-1];
s->chan = c;
- s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)s);
+ s->dma = dmaalloc(1, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)s);
}
if (omode & Awrite) {
outenable();
@@ 777,7 826,7 @@ audioopen(Chan *c, int mode)
resetlevel();
mxvolume();
qunlock(&audio);
- if (debug) print("#A: open done\n");
+ if (debug) print("open done\n");
break;
}
c = devopen(c, mode, audiodir, nelem(audiodir), devgen);
@@ 829,7 878,6 @@ audioclose(Chan *c)
}
dmawait(s->dma);
outdisable();
- amplifierpower(0);
setempty(s);
dmafree(s->dma);
qunlock(s);
@@ 844,7 892,6 @@ audioclose(Chan *c)
qunlock(s);
nexterror();
}
- dmawait(s->dma);
indisable();
setempty(s);
dmafree(s->dma);
@@ 853,7 900,7 @@ audioclose(Chan *c)
}
if (audio.amode == 0) {
/* turn audio off */
- audiopower(0);
+ egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0);
}
qunlock(&audio);
poperror();
@@ 1127,4 1174,5 @@ Dev uda1341devtab = {
devbwrite,
devremove,
devwstat,
+ audiopower,
};
M bitsy/fns.h => bitsy/fns.h +1 -0
@@ 25,6 25,7 @@ char* getconf(char*);
ulong getfar(void);
ulong getfsr(void);
#define getpgcolor(a) 0
+void gpiointrenable(ulong, int, void (*)(Ureg*, void*), void*, char*)
void h3650uartsetup(void);
void icacheinvalidate(void);
void idle(void);
M bitsy/io.h => bitsy/io.h +10 -0
@@ 109,6 109,16 @@ enum
GPIO_32_768kHz_o= 1<<27, /* 32.768 kHz clock (O, RTC) */
};
+/*
+ * edge argument for gpiointrenable
+ */
+enum
+{
+ GPIOrising,
+ GPIOfalling,
+ GPIOboth,
+};
+
/* hardware registers */
typedef struct Uartregs Uartregs;
struct Uartregs
M bitsy/main.c => bitsy/main.c +0 -18
@@ 426,24 426,6 @@ lcdpower(int on)
}
void
-audiopower(int on)
-{
- egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, on);
-}
-
-void
-amplifierpower(int on)
-{
- egpiobits(EGPIO_audio_power, on);
-}
-
-void
-audiomute(int on)
-{
- egpiobits(EGPIO_audio_mute, on);
-}
-
-void
flashprogpower(int on)
{
egpiobits(EGPIO_prog_flash, on);
A bitsy/power.c => bitsy/power.c +26 -0
@@ 0,0 1,26 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "init.h"
+#include "pool.h"
+
+/* Power management for the bitsy */
+
+static void
+powerintr(Ureg*, void *x)
+{
+ /* Power button interrupt */
+ int i;
+
+ /* debounce, 50 ms*/
+ for (i = 0; i < 50; i++) {
+ delay(1);
+ if ((gpioregs->level & GPIO_PWR_ON_i) == 0)
+ return; /* bounced */
+ }
+ rs232power(0);
+}
M bitsy/sa1110dma.c => bitsy/sa1110dma.c +15 -1
@@ 115,6 115,11 @@ dmafree(int i) {
dma.chan[i].intr = nil;
}
+void
+dmastop(int i) {
+ dmaregs[i].dcsr_clr = 0xff;
+}
+
ulong
dmastart(int chan, ulong addr, int count) {
ulong status, n;
@@ 194,12 199,21 @@ dmaintr(Ureg*, void *x)
iprint("error, channel %d, status 0x%lux\n", i, dcsr);
donebit = 1<<((dcsr&1<<BIU)?DONEA:DONEB);
if (dcsr & donebit) {
- regs->dcsr_clr = donebit;
+ regs->dcsr_clr = 1<<DONEA|1<<DONEB;
if (dma.chan[i].intr) {
(*dma.chan[i].intr)(dma.chan[i].param, dcsr & (1<<DONEA|1<<DONEB));
}
wakeup(&dma.chan[i].r);
return;
}
+ if (dcsr & 1<<ERROR) {
+ regs->dcsr_clr = ERROR;
+ iprint("DMA error, channel %d, status 0x%lux\n", i, dcsr);
+ if (dma.chan[i].intr) {
+ (*dma.chan[i].intr)(dma.chan[i].param, 0);
+ }
+ wakeup(&dma.chan[i].r);
+ return;
+ }
iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
}
M bitsy/sa1110dma.h => bitsy/sa1110dma.h +1 -0
@@ 14,4 14,5 @@ void dmafree(int);
ulong dmastart(int, ulong, int);
void dmawait(int);
+void dmastop(int);
int dmaidle(int);
M bitsy/trap.c => bitsy/trap.c +42 -0
@@ 128,6 128,44 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
}
/*
+ * enable an interrupt on gpio line. edge is encoded as follows
+ */
+void
+gpiointrenable(ulong bit, int edge, void (*f)(Ureg*, void*), void* a, char *name)
+{
+ int irq;
+
+ /* figure out which interrupt */
+ for(irq = 0; irq < 28; irq++)
+ if((1<<irq) & bit)
+ break;
+ if(irq >= 28)
+ panic("gpiointrenable %lux", bit);
+ if(irq > 11)
+ irq = 11;
+
+ /* it had better be input */
+ if(bit & gpioregs->direction)
+ panic(""gpiointrenable %lux of output pin", bit);
+
+ /* set edge register */
+ switch(edge){
+ case GPIOboth:
+ gpioregs->rising |= bit;
+ gpioregs->falling |= bit;
+ break;
+ case GPIOfalling:
+ gpioregs->falling |= bit;
+ break;
+ case GPIOrising:
+ gpioregs->rising |= bit;
+ break;
+ }
+
+ intrenable(irq, f, a, name);
+}
+
+/*
* called by trap to handle access faults
*/
static void
@@ 196,6 234,10 @@ trap(Ureg *ureg)
if(ureg->type == PsrMirq){
found = 0;
va = intrregs->icip;
+
+ /* clear any gpio edge interrupt */
+ gpioregs->irqbit = va & 0xFFF;
+
for(v = vctl; v != nil; v = v->next){
if(v->irqbit & va){
v->f(ureg, v->a);
M port/portdat.h => port/portdat.h +1 -0
@@ 193,6 193,7 @@ struct Dev
long (*bwrite)(Chan*, Block*, ulong);
void (*remove)(Chan*);
void (*wstat)(Chan*, char*);
+ void (*power)(int); /* power mgt: power(1) → on, power (0) → off */
};
struct Dirtab