xref: /inferno-os/os/sa1110/devgpio.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1  #include	"u.h"
2  #include	"../port/lib.h"
3  #include	"mem.h"
4  #include	"dat.h"
5  #include	"fns.h"
6  #include	"../port/error.h"
7  #include	"io.h"
8  
9  enum{
10  	Qdir,
11  	Qgpioset,
12  	Qgpioclear,
13  	Qgpioedge,
14  	Qgpioctl,
15  	Qgpiostatus,
16  };
17  
18  Dirtab gpiodir[]={
19  	".",				{Qdir,0},			0,	0555,
20  	"gpioset",			{Qgpioset, 0},		0,	0664,
21  	"gpioclear",		{Qgpioclear, 0},		0,	0664,
22  	"gpioedge",		{Qgpioedge, 0},		0,	0664,
23  	"gpioctl",			{Qgpioctl,0},		0,	0664,
24  	"gpiostatus",		{Qgpiostatus,0},	0,	0444,
25  };
26  
27  static Chan*
28  gpioattach(char* spec)
29  {
30  	return devattach('G', spec);
31  }
32  
33  static Walkqid*
34  gpiowalk(Chan* c, Chan *nc, char **name, int nname)
35  {
36  	return devwalk(c, nc, name, nname, gpiodir, nelem(gpiodir), devgen);
37  }
38  
39  static int
40  gpiostat(Chan* c, uchar *dp, int n)
41  {
42  	return devstat(c, dp, n, gpiodir, nelem(gpiodir), devgen);
43  }
44  
45  static Chan*
46  gpioopen(Chan* c, int omode)
47  {
48  	return devopen(c, omode, gpiodir, nelem(gpiodir), devgen);
49  }
50  
51  static void
52  gpioclose(Chan*)
53  {
54  }
55  
56  static long
57  gpioread(Chan* c, void *buf, long n, vlong offset)
58  {
59  	char str[128];
60  	GpioReg *g;
61  
62  	if(c->qid.type & QTDIR)
63  		return devdirread(c, buf, n, gpiodir, nelem(gpiodir), devgen);
64  
65  	g = GPIOREG;
66  	switch((ulong)c->qid.path){
67  	case Qgpioset:
68  	case Qgpioclear:
69  		sprint(str, "%8.8lux", g->gplr);
70  		break;
71  	case Qgpioedge:
72  		sprint(str, "%8.8lux", g->gedr);
73  		break;
74  	case Qgpioctl:
75  		/* return 0; */
76  	case Qgpiostatus:
77  		snprint(str, sizeof(str), "GPDR:%8.8lux\nGRER:%8.8lux\nGFER:%8.8lux\nGAFR:%8.8lux\nGPLR:%8.8lux\n", g->gpdr, g->grer, g->gfer, g->gafr, g->gplr);
78  		break;
79  	default:
80  		error(Ebadarg);
81  		return 0;
82  	}
83  	return readstr(offset, buf, n, str);
84  }
85  
86  static long
87  gpiowrite(Chan *c, void *a, long n, vlong)
88  {
89  	char buf[128], *field[3];
90  	int pin, set;
91  	ulong *r;
92  	GpioReg *g;
93  
94  	if(n >= sizeof(buf))
95  		n = sizeof(buf)-1;
96  	memmove(buf, a, n);
97  	buf[n] = 0;
98  	g = GPIOREG;
99  	switch((ulong)c->qid.path){
100  	case Qgpioset:
101  		g->gpsr = strtol(buf, 0, 16);
102  		break;
103  	case Qgpioclear:
104  		g->gpcr = strtol(buf, 0, 16);
105  		break;
106  	case Qgpioedge:
107  		g->gedr = strtol(buf, 0, 16);
108  		break;
109  	case Qgpioctl:
110  		if(getfields(buf, field, 3, 1, " \n\t") == 3) {
111  			pin = strtol(field[1], 0, 0);
112  			if(pin < 0 || pin >= 32)
113  				error(Ebadarg);
114  			set = strtol(field[2], 0, 0);
115  			switch(*field[0]) {
116  			case 'd':
117  				r = &g->gpdr;
118  				break;
119  			case 'r':
120  				r = &g->grer;
121  				break;
122  			case 'f':
123  				r = &g->gfer;
124  				break;
125  			case 'a':
126  				r = &g->gafr;
127  				break;
128  			default:
129  				error(Ebadarg);
130  				return 0;
131  			}
132  			if(set)
133  				*r |= 1 << pin;
134  			else
135  				*r &= ~(1 << pin);
136  		} else
137  			error(Ebadarg);
138  		break;
139  	default:
140  		error(Ebadusefd);
141  		return 0;
142  	}
143  	return n;
144  }
145  
146  Dev gpiodevtab = {
147  	'G',
148  	"gpio",
149  
150  	devreset,
151  	devinit,
152  	devshutdown,
153  	gpioattach,
154  	gpiowalk,
155  	gpiostat,
156  	gpioopen,
157  	devcreate,
158  	gpioclose,
159  	gpioread,
160  	devbread,
161  	gpiowrite,
162  	devbwrite,
163  	devremove,
164  	devwstat,
165  };
166