these devices were forgotten last week Reference: /n/atom/patch/applied/pidevspii2c Date: Sun Jan 10 18:27:06 CET 2016 Signed-off-by: quanstro@quanstro.net --- /sys/src/9/bcm/devi2c.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/bcm/devi2c.c Sun Jan 10 18:26:58 2016 @@ -0,0 +1,227 @@ +/* + * i2c + * + * Copyright © 1998, 2003 Vita Nuova Limited. + */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +typedef struct I2Cdir I2Cdir; + +enum{ + Qdir, + Qdata, + Qctl, +}; + +static +Dirtab i2ctab[]={ + ".", {Qdir, 0, QTDIR}, 0, 0555, + "i2cdata", {Qdata, 0}, 256, 0660, + "i2cctl", {Qctl, 0}, 0, 0660, +}; + +struct I2Cdir { + Ref; + I2Cdev; + Dirtab tab[nelem(i2ctab)]; +}; + +static void +i2creset(void) +{ + i2csetup(0); +} + +static Chan* +i2cattach(char* spec) +{ + char *s; + ulong addr; + I2Cdir *d; + Chan *c; + + addr = strtoul(spec, &s, 16); + if(*spec == 0 || *s || addr >= (1<<10)) + error("invalid i2c address"); + d = malloc(sizeof(I2Cdir)); + if(d == nil) + error(Enomem); + d->ref = 1; + d->addr = addr; + d->salen = 0; + d->tenbit = addr >= 128; + memmove(d->tab, i2ctab, sizeof(d->tab)); + sprint(d->tab[1].name, "i2c.%lux.data", addr); + sprint(d->tab[2].name, "i2c.%lux.ctl", addr); + + c = devattach('J', spec); + c->aux = d; + return c; +} + +static Walkqid* +i2cwalk(Chan* c, Chan *nc, char **name, int nname) +{ + Walkqid *wq; + I2Cdir *d; + + d = c->aux; + wq = devwalk(c, nc, name, nname, d->tab, nelem(d->tab), devgen); + if(wq != nil && wq->clone != nil && wq->clone != c) + incref(d); + return wq; +} + +static int +i2cstat(Chan* c, uchar *dp, int n) +{ + I2Cdir *d; + + d = c->aux; + return devstat(c, dp, n, d->tab, nelem(d->tab), devgen); +} + +static Chan* +i2copen(Chan* c, int omode) +{ + I2Cdir *d; + + d = c->aux; + return devopen(c, omode, d->tab, nelem(d->tab), devgen); +} + +static void +i2cclose(Chan *c) +{ + I2Cdir *d; + + d = c->aux; + if(decref(d) == 0) + free(d); +} + +static long +i2cread(Chan *c, void *a, long n, vlong offset) +{ + I2Cdir *d; + char *s, *e; + ulong len; + + d = c->aux; + switch((ulong)c->qid.path){ + case Qdir: + return devdirread(c, a, n, d->tab, nelem(d->tab), devgen); + case Qdata: + len = d->tab[1].length; + if(offset+n >= len){ + n = len - offset; + if(n <= 0) + return 0; + } + n = i2crecv(d, a, n, offset); + break; + case Qctl: + s = smalloc(READSTR); + if(waserror()){ + free(s); + nexterror(); + } + e = seprint(s, s+READSTR, "size %lud\n", (ulong)d->tab[1].length); + if(d->salen) + e = seprint(e, s+READSTR, "subaddress %d\n", d->salen); + if(d->tenbit) + seprint(e, s+READSTR, "a10\n"); + n = readstr(offset, a, n, s); + poperror(); + free(s); + return n; + default: + n=0; + break; + } + return n; +} + +static long +i2cwrite(Chan *c, void *a, long n, vlong offset) +{ + I2Cdir *d; + long len; + Cmdbuf *cb; + + USED(offset); + switch((ulong)c->qid.path){ + case Qdata: + d = c->aux; + len = d->tab[1].length; + if(offset+n >= len){ + n = len - offset; + if(n <= 0) + return 0; + } + n = i2csend(d, a, n, offset); + break; + case Qctl: + cb = parsecmd(a, n); + if(waserror()){ + free(cb); + nexterror(); + } + if(cb->nf < 1) + error(Ebadctl); + d = c->aux; + if(strcmp(cb->f[0], "subaddress") == 0){ + if(cb->nf > 1){ + len = strtol(cb->f[1], nil, 0); + if(len <= 0) + len = 0; + if(len > 4) + cmderror(cb, "subaddress too long"); + }else + len = 1; + d->salen = len; + }else if(cb->nf > 1 && strcmp(cb->f[0], "size") == 0){ + len = strtol(cb->f[1], nil, 0); + if(len < 0) + cmderror(cb, "size is negative"); + d->tab[1].length = len; + }else if(strcmp(cb->f[0], "a10") == 0) + d->tenbit = 1; + else + cmderror(cb, "unknown control request"); + poperror(); + free(cb); + break; + default: + error(Ebadusefd); + } + return n; +} + +Dev i2cdevtab = { + 'J', + "i2c", + + i2creset, + devinit, + devshutdown, + i2cattach, + i2cwalk, + i2cstat, + i2copen, + devcreate, + i2cclose, + i2cread, + devbread, + i2cwrite, + devbwrite, + devremove, + devwstat, +}; --- /sys/src/9/bcm/devspi.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/bcm/devspi.c Sun Jan 10 18:26:58 2016 @@ -0,0 +1,230 @@ +/* + * minimal spi interface for testing + */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +extern int qstate(Queue*); + +enum { + QMAX = 64*1024, + Nspislave = 2, +}; + +typedef struct Spi Spi; + +struct Spi { + int csel; + int opens; + QLock; + Queue *iq; + Queue *oq; +}; + +Spi spidev[Nspislave]; + +enum{ + Qdir = 0, + Qctl, + Qspi, +}; + +Dirtab spidir[]={ + ".", {Qdir, 0, QTDIR}, 0, 0555, + "spictl", {Qctl, 0}, 0, 0664, + "spi0", {Qspi+0, 0}, 0, 0664, + "spi1", {Qspi+1, 0}, 0, 0664, +}; + +#define DEVID(path) ((ulong)path - Qspi) + +enum { + CMclock, + CMmode, + CMlossi, +}; + +Cmdtab spitab[] = { + {CMclock, "clock", 2}, + {CMmode, "mode", 2}, + {CMlossi, "lossi", 1}, +}; + +static void +spikick(void *a) +{ + Block *b; + Spi *spi; + + spi = a; + b = qget(spi->oq); + if(b == nil) + return; + if(waserror()){ + freeb(b); + nexterror(); + } + spirw(spi->csel, b->rp, BLEN(b)); + qpass(spi->iq, b); + poperror(); +} + +static void +spiinit(void) +{ +} + +static long +spiread(Chan *c, void *a, long n, vlong off) +{ + Spi *spi; + u32int *sp; + char *p, *e; + char buf[256]; + + if(c->qid.type & QTDIR) + return devdirread(c, a, n, spidir, nelem(spidir), devgen); + + if(c->qid.path == Qctl) { + sp = (u32int *)0x7e204000; + p = buf; + e = p + sizeof(buf); + p = seprint(p, e, "CS: %08x\n", sp[0]); + p = seprint(p, e, "CLK: %08x\n", sp[2]); + p = seprint(p, e, "DLEN: %08x\n", sp[3]); + p = seprint(p, e, "LTOH: %08x\n", sp[4]); + seprint(p, e, "DC: %08x\n", sp[5]); + return readstr(off, a, n, buf); + } + + spi = &spidev[DEVID(c->qid.path)]; + n = qread(spi->iq, a, n); + + return n; +} + +static long +spiwrite(Chan*c, void *a, long n, vlong) +{ + Spi *spi; + Cmdbuf *cb; + Cmdtab *ct; + + if(c->qid.type & QTDIR) + error(Eperm); + + if(c->qid.path == Qctl) { + cb = parsecmd(a, n); + if(waserror()) { + free(cb); + nexterror(); + } + ct = lookupcmd(cb, spitab, nelem(spitab)); + switch(ct->index) { + case CMclock: + spiclock(atoi(cb->f[1])); + break; + case CMmode: + spimode(atoi(cb->f[1])); + break; + case CMlossi: + break; + } + return n; + } + + spi = &spidev[DEVID(c->qid.path)]; + n = qwrite(spi->oq, a, n); + + return n; +} + +static Chan* +spiattach(char* spec) +{ + return devattach(L'π', spec); +} + +static Walkqid* +spiwalk(Chan* c, Chan *nc, char** name, int nname) +{ + return devwalk(c, nc, name, nname, spidir, nelem(spidir), devgen); +} + +static int +spistat(Chan* c, uchar* dp, int n) +{ + return devstat(c, dp, n, spidir, nelem(spidir), devgen); +} + +static Chan* +spiopen(Chan* c, int omode) +{ + Spi *spi; + + c = devopen(c, omode, spidir, nelem(spidir), devgen); + if(c->qid.type & QTDIR) + return c; + + spi = &spidev[DEVID(c->qid.path)]; + qlock(spi); + if(spi->opens++ == 0){ + spi->csel = DEVID(c->qid.path); + if(spi->iq == nil) + spi->iq = qopen(QMAX, 0, nil, nil); + else + qreopen(spi->iq); + if(spi->oq == nil) + spi->oq = qopen(QMAX, Qkick, spikick, spi); + else + qreopen(spi->oq); + } + qunlock(spi); + c->iounit = qiomaxatomic; + return c; +} + +static void +spiclose(Chan *c) +{ + Spi *spi; + + if(c->qid.type & QTDIR) + return; + if((c->flag & COPEN) == 0) + return; + spi = &spidev[DEVID(c->qid.path)]; + qlock(spi); + if(--spi->opens == 0){ + qclose(spi->iq); + qhangup(spi->oq, nil); + qclose(spi->oq); + } + qunlock(spi); +} + +Dev spidevtab = { + L'π', + "spi", + + devreset, + spiinit, + devshutdown, + spiattach, + spiwalk, + spistat, + spiopen, + devcreate, + spiclose, + spiread, + devbread, + spiwrite, + devbwrite, + devremove, + devwstat, +}; +