xref: /plan9-contrib/sys/src/9/bcm/devgpio.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
1*5c47fe09SDavid du Colombier /*
2*5c47fe09SDavid du Colombier  * Raspberry Pi (BCM2835) GPIO
3*5c47fe09SDavid du Colombier  */
4*5c47fe09SDavid du Colombier 
5*5c47fe09SDavid du Colombier #include	"u.h"
6*5c47fe09SDavid du Colombier #include	"../port/lib.h"
7*5c47fe09SDavid du Colombier #include	"mem.h"
8*5c47fe09SDavid du Colombier #include	"dat.h"
9*5c47fe09SDavid du Colombier #include	"fns.h"
10*5c47fe09SDavid du Colombier #include	"../port/error.h"
11*5c47fe09SDavid du Colombier 
12*5c47fe09SDavid du Colombier enum {
13*5c47fe09SDavid du Colombier 	// GPIO registers
14*5c47fe09SDavid du Colombier 	GPLEV = VIRTIO + 0x200034,
15*5c47fe09SDavid du Colombier };
16*5c47fe09SDavid du Colombier 
17*5c47fe09SDavid du Colombier enum{
18*5c47fe09SDavid du Colombier 	Qdir = 0,
19*5c47fe09SDavid du Colombier 	Qgpio,
20*5c47fe09SDavid du Colombier };
21*5c47fe09SDavid du Colombier 
22*5c47fe09SDavid du Colombier Dirtab gpiodir[]={
23*5c47fe09SDavid du Colombier 	".",	{Qdir, 0, QTDIR},	0,	0555,
24*5c47fe09SDavid du Colombier 	"gpio",	{Qgpio, 0},	0,	0664,
25*5c47fe09SDavid du Colombier };
26*5c47fe09SDavid du Colombier 
27*5c47fe09SDavid du Colombier enum {
28*5c47fe09SDavid du Colombier 	// commands
29*5c47fe09SDavid du Colombier 	CMfunc,
30*5c47fe09SDavid du Colombier 	CMset,
31*5c47fe09SDavid du Colombier 	CMpullup,
32*5c47fe09SDavid du Colombier 	CMpulldown,
33*5c47fe09SDavid du Colombier 	CMfloat,
34*5c47fe09SDavid du Colombier };
35*5c47fe09SDavid du Colombier 
36*5c47fe09SDavid du Colombier static Cmdtab gpiocmd[] = {
37*5c47fe09SDavid du Colombier 	{CMfunc, "function", 3},
38*5c47fe09SDavid du Colombier 	{CMset, "set", 3},
39*5c47fe09SDavid du Colombier 	{CMpullup, "pullup", 2},
40*5c47fe09SDavid du Colombier 	{CMpulldown, "pulldown", 2},
41*5c47fe09SDavid du Colombier 	{CMfloat, "float", 2},
42*5c47fe09SDavid du Colombier };
43*5c47fe09SDavid du Colombier 
44*5c47fe09SDavid du Colombier static char *funcs[] = { "in", "out", "alt5", "alt4", "alt0",
45*5c47fe09SDavid du Colombier 	"alt1", "alt2", "alt3", "pulse"};
46*5c47fe09SDavid du Colombier static int ifuncs[] = { Input, Output, Alt5, Alt4, Alt0,
47*5c47fe09SDavid du Colombier 	Alt1, Alt2, Alt3, -1};
48*5c47fe09SDavid du Colombier 
49*5c47fe09SDavid du Colombier static Chan*
gpioattach(char * spec)50*5c47fe09SDavid du Colombier gpioattach(char* spec)
51*5c47fe09SDavid du Colombier {
52*5c47fe09SDavid du Colombier 	return devattach('G', spec);
53*5c47fe09SDavid du Colombier }
54*5c47fe09SDavid du Colombier 
55*5c47fe09SDavid du Colombier static Walkqid*
gpiowalk(Chan * c,Chan * nc,char ** name,int nname)56*5c47fe09SDavid du Colombier gpiowalk(Chan* c, Chan *nc, char** name, int nname)
57*5c47fe09SDavid du Colombier {
58*5c47fe09SDavid du Colombier 	return devwalk(c, nc, name, nname, gpiodir, nelem(gpiodir), devgen);
59*5c47fe09SDavid du Colombier }
60*5c47fe09SDavid du Colombier 
61*5c47fe09SDavid du Colombier static int
gpiostat(Chan * c,uchar * dp,int n)62*5c47fe09SDavid du Colombier gpiostat(Chan* c, uchar* dp, int n)
63*5c47fe09SDavid du Colombier {
64*5c47fe09SDavid du Colombier 	return devstat(c, dp, n, gpiodir, nelem(gpiodir), devgen);
65*5c47fe09SDavid du Colombier }
66*5c47fe09SDavid du Colombier 
67*5c47fe09SDavid du Colombier static Chan*
gpioopen(Chan * c,int omode)68*5c47fe09SDavid du Colombier gpioopen(Chan* c, int omode)
69*5c47fe09SDavid du Colombier {
70*5c47fe09SDavid du Colombier 	return devopen(c, omode, gpiodir, nelem(gpiodir), devgen);
71*5c47fe09SDavid du Colombier }
72*5c47fe09SDavid du Colombier 
73*5c47fe09SDavid du Colombier static void
gpioclose(Chan *)74*5c47fe09SDavid du Colombier gpioclose(Chan*)
75*5c47fe09SDavid du Colombier {
76*5c47fe09SDavid du Colombier }
77*5c47fe09SDavid du Colombier 
78*5c47fe09SDavid du Colombier static long
gpioread(Chan * c,void * buf,long n,vlong)79*5c47fe09SDavid du Colombier gpioread(Chan* c, void *buf, long n, vlong)
80*5c47fe09SDavid du Colombier {
81*5c47fe09SDavid du Colombier 	char lbuf[20];
82*5c47fe09SDavid du Colombier 	char *e;
83*5c47fe09SDavid du Colombier 
84*5c47fe09SDavid du Colombier 	USED(c);
85*5c47fe09SDavid du Colombier 	if(c->qid.path == Qdir)
86*5c47fe09SDavid du Colombier 		return devdirread(c, buf, n, gpiodir, nelem(gpiodir), devgen);
87*5c47fe09SDavid du Colombier 	e = lbuf + sizeof(lbuf);
88*5c47fe09SDavid du Colombier 	seprint(lbuf, e, "%08ulx%08ulx", ((ulong *)GPLEV)[1], ((ulong *)GPLEV)[0]);
89*5c47fe09SDavid du Colombier 	return readstr(0, buf, n, lbuf);
90*5c47fe09SDavid du Colombier }
91*5c47fe09SDavid du Colombier 
92*5c47fe09SDavid du Colombier static long
gpiowrite(Chan * c,void * buf,long n,vlong)93*5c47fe09SDavid du Colombier gpiowrite(Chan* c, void *buf, long n, vlong)
94*5c47fe09SDavid du Colombier {
95*5c47fe09SDavid du Colombier 	Cmdbuf *cb;
96*5c47fe09SDavid du Colombier 	Cmdtab *ct;
97*5c47fe09SDavid du Colombier 	int pin, i;
98*5c47fe09SDavid du Colombier 
99*5c47fe09SDavid du Colombier 	if(c->qid.type & QTDIR)
100*5c47fe09SDavid du Colombier 		error(Eperm);
101*5c47fe09SDavid du Colombier 	cb = parsecmd(buf, n);
102*5c47fe09SDavid du Colombier 	if(waserror()) {
103*5c47fe09SDavid du Colombier 		free(cb);
104*5c47fe09SDavid du Colombier 		nexterror();
105*5c47fe09SDavid du Colombier 	}
106*5c47fe09SDavid du Colombier 	ct = lookupcmd(cb, gpiocmd, nelem(gpiocmd));
107*5c47fe09SDavid du Colombier 	pin = atoi(cb->f[1]);
108*5c47fe09SDavid du Colombier 	switch(ct->index) {
109*5c47fe09SDavid du Colombier 	case CMfunc:
110*5c47fe09SDavid du Colombier 		for(i = 0; i < nelem(funcs); i++)
111*5c47fe09SDavid du Colombier 			if(strcmp(funcs[i], cb->f[2]) == 0)
112*5c47fe09SDavid du Colombier 				break;
113*5c47fe09SDavid du Colombier 		if(i >= nelem(funcs))
114*5c47fe09SDavid du Colombier 			error(Ebadctl);
115*5c47fe09SDavid du Colombier 		if(ifuncs[i] == -1) {
116*5c47fe09SDavid du Colombier 			gpiosel(pin, Output);
117*5c47fe09SDavid du Colombier 			microdelay(2);
118*5c47fe09SDavid du Colombier 			gpiosel(pin, Input);
119*5c47fe09SDavid du Colombier 		}
120*5c47fe09SDavid du Colombier 		else {
121*5c47fe09SDavid du Colombier 			gpiosel(pin, ifuncs[i]);
122*5c47fe09SDavid du Colombier 		}
123*5c47fe09SDavid du Colombier 		break;
124*5c47fe09SDavid du Colombier 	case CMset:
125*5c47fe09SDavid du Colombier 		gpioout(pin, atoi(cb->f[2]));
126*5c47fe09SDavid du Colombier 		break;
127*5c47fe09SDavid du Colombier 	case CMpullup:
128*5c47fe09SDavid du Colombier 		gpiopullup(pin);
129*5c47fe09SDavid du Colombier 		break;
130*5c47fe09SDavid du Colombier 	case CMpulldown:
131*5c47fe09SDavid du Colombier 		gpiopulldown(pin);
132*5c47fe09SDavid du Colombier 		break;
133*5c47fe09SDavid du Colombier 	case CMfloat:
134*5c47fe09SDavid du Colombier 		gpiopulloff(pin);
135*5c47fe09SDavid du Colombier 		break;
136*5c47fe09SDavid du Colombier 	}
137*5c47fe09SDavid du Colombier 	free(cb);
138*5c47fe09SDavid du Colombier 	poperror();
139*5c47fe09SDavid du Colombier 	return n;
140*5c47fe09SDavid du Colombier }
141*5c47fe09SDavid du Colombier 
142*5c47fe09SDavid du Colombier Dev gpiodevtab = {
143*5c47fe09SDavid du Colombier 	'G',
144*5c47fe09SDavid du Colombier 	"gpio",
145*5c47fe09SDavid du Colombier 
146*5c47fe09SDavid du Colombier 	devreset,
147*5c47fe09SDavid du Colombier 	devinit,
148*5c47fe09SDavid du Colombier 	devshutdown,
149*5c47fe09SDavid du Colombier 	gpioattach,
150*5c47fe09SDavid du Colombier 	gpiowalk,
151*5c47fe09SDavid du Colombier 	gpiostat,
152*5c47fe09SDavid du Colombier 	gpioopen,
153*5c47fe09SDavid du Colombier 	devcreate,
154*5c47fe09SDavid du Colombier 	gpioclose,
155*5c47fe09SDavid du Colombier 	gpioread,
156*5c47fe09SDavid du Colombier 	devbread,
157*5c47fe09SDavid du Colombier 	gpiowrite,
158*5c47fe09SDavid du Colombier 	devbwrite,
159*5c47fe09SDavid du Colombier 	devremove,
160*5c47fe09SDavid du Colombier 	devwstat,
161*5c47fe09SDavid du Colombier };
162