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