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