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