xref: /plan9-contrib/sys/src/9/bcm/devspi.c (revision 0a4f5b8ee35d2d62b8600a1c256abb8ff2d92d7d)
1 /*
2  * minimal spi interface for testing
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 #define SPIREGS	(VIRTIO+0x204000)
13 
14 extern int qstate(Queue*);
15 
16 enum {
17 	QMAX		= 64*1024,
18 	Nspislave	= 2,
19 };
20 
21 typedef struct Spi Spi;
22 
23 struct Spi {
24 	int	csel;
25 	int	opens;
26 	QLock;
27 	Queue	*iq;
28 	Queue	*oq;
29 };
30 
31 Spi spidev[Nspislave];
32 
33 enum{
34 	Qdir = 0,
35 	Qctl,
36 	Qspi,
37 };
38 
39 Dirtab spidir[]={
40 	".",	{Qdir, 0, QTDIR},	0,	0555,
41 	"spictl",		{Qctl, 0},	0,	0664,
42 	"spi0",		{Qspi+0, 0},	0,	0664,
43 	"spi1",		{Qspi+1, 0}, 0, 0664,
44 };
45 
46 #define DEVID(path)	((ulong)path - Qspi)
47 
48 enum {
49 	CMclock,
50 	CMmode,
51 	CMlossi,
52 };
53 
54 Cmdtab spitab[] = {
55 	{CMclock, "clock", 2},
56 	{CMmode, "mode", 2},
57 	{CMlossi, "lossi", 1},
58 };
59 
60 static void
61 spikick(void *a)
62 {
63 	Block *b;
64 	Spi *spi;
65 
66 	spi = a;
67 	b = qget(spi->oq);
68 	if(b == nil)
69 		return;
70 	if(waserror()){
71 		freeb(b);
72 		nexterror();
73 	}
74 	spirw(spi->csel, b->rp, BLEN(b));
75 	qpass(spi->iq, b);
76 	poperror();
77 }
78 
79 static void
80 spiinit(void)
81 {
82 }
83 
84 static long
85 spiread(Chan *c, void *a, long n, vlong off)
86 {
87 	Spi *spi;
88 	u32int *sp;
89 	char *p, *e;
90 	char buf[256];
91 
92 	if(c->qid.type & QTDIR)
93 		return devdirread(c, a, n, spidir, nelem(spidir), devgen);
94 
95 	if(c->qid.path == Qctl) {
96 		sp = (u32int *)SPIREGS;
97 		p = buf;
98 		e = p + sizeof(buf);
99 		p = seprint(p, e, "CS: %08x\n", sp[0]);
100 		p = seprint(p, e, "CLK: %08x\n", sp[2]);
101 		p = seprint(p, e, "DLEN: %08x\n", sp[3]);
102 		p = seprint(p, e, "LTOH: %08x\n", sp[4]);
103 		seprint(p, e, "DC: %08x\n", sp[5]);
104 		return readstr(off, a, n, buf);
105 	}
106 
107 	spi = &spidev[DEVID(c->qid.path)];
108 	n = qread(spi->iq, a, n);
109 
110 	return n;
111 }
112 
113 static long
114 spiwrite(Chan*c, void *a, long n, vlong)
115 {
116 	Spi *spi;
117 	Cmdbuf *cb;
118 	Cmdtab *ct;
119 
120 	if(c->qid.type & QTDIR)
121 		error(Eperm);
122 
123 	if(c->qid.path == Qctl) {
124 		cb = parsecmd(a, n);
125 		if(waserror()) {
126 			free(cb);
127 			nexterror();
128 		}
129 		ct = lookupcmd(cb, spitab, nelem(spitab));
130 		switch(ct->index) {
131 		case CMclock:
132 			spiclock(atoi(cb->f[1]));
133 			break;
134 		case CMmode:
135 			spimode(atoi(cb->f[1]));
136 			break;
137 		case CMlossi:
138 			break;
139 		}
140 		poperror();
141 		return n;
142 	}
143 
144 	spi = &spidev[DEVID(c->qid.path)];
145 	n = qwrite(spi->oq, a, n);
146 
147 	return n;
148 }
149 
150 static Chan*
151 spiattach(char* spec)
152 {
153 	return devattach(L'π', spec);
154 }
155 
156 static Walkqid*
157 spiwalk(Chan* c, Chan *nc, char** name, int nname)
158 {
159 	return devwalk(c, nc, name, nname, spidir, nelem(spidir), devgen);
160 }
161 
162 static int
163 spistat(Chan* c, uchar* dp, int n)
164 {
165 	return devstat(c, dp, n, spidir, nelem(spidir), devgen);
166 }
167 
168 static Chan*
169 spiopen(Chan* c, int omode)
170 {
171 	Spi *spi;
172 
173 	c = devopen(c, omode, spidir, nelem(spidir), devgen);
174 	if(c->qid.type & QTDIR)
175 		return c;
176 
177 	spi = &spidev[DEVID(c->qid.path)];
178 	qlock(spi);
179 	if(spi->opens++ == 0){
180 		spi->csel = DEVID(c->qid.path);
181 		if(spi->iq == nil)
182 			spi->iq = qopen(QMAX, 0, nil, nil);
183 		else
184 			qreopen(spi->iq);
185 		if(spi->oq == nil)
186 			spi->oq = qopen(QMAX, Qkick, spikick, spi);
187 		else
188 			qreopen(spi->oq);
189 	}
190 	qunlock(spi);
191 	c->iounit = qiomaxatomic;
192 	return c;
193 }
194 
195 static void
196 spiclose(Chan *c)
197 {
198 	Spi *spi;
199 
200 	if(c->qid.type & QTDIR)
201 		return;
202 	if((c->flag & COPEN) == 0)
203 		return;
204 	spi = &spidev[DEVID(c->qid.path)];
205 	qlock(spi);
206 	if(--spi->opens == 0){
207 		qclose(spi->iq);
208 		qhangup(spi->oq, nil);
209 		qclose(spi->oq);
210 	}
211 	qunlock(spi);
212 }
213 
214 Dev spidevtab = {
215 	L'π',
216 	"spi",
217 
218 	devreset,
219 	spiinit,
220 	devshutdown,
221 	spiattach,
222 	spiwalk,
223 	spistat,
224 	spiopen,
225 	devcreate,
226 	spiclose,
227 	spiread,
228 	devbread,
229 	spiwrite,
230 	devbwrite,
231 	devremove,
232 	devwstat,
233 };
234 
235