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