Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/9/kw/devtwsi.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * kirkwood two-wire serial interface (TWSI) and
3
 * inter-integrated circuit (I⁲C) driver
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
#include "io.h"
12
 
13
enum {
14
	Qdir,
15
	Qtwsi,
16
};
17
 
18
typedef struct Kwtwsi Kwtwsi;
19
typedef struct Twsi Twsi;
20
 
21
struct Kwtwsi {				/* device registers */
22
	ulong	saddr;
23
	ulong	data;
24
	ulong	ctl;
25
	union {
26
		ulong	status;		/* ro */
27
		ulong	rate;		/* wo: baud rate */
28
	};
29
 
30
	ulong	saddrext;
31
	uchar	_pad0[0x1c-0x14];
32
	ulong	reset;
33
	uchar	_pad1[0x98-0x20];
34
	ulong	initlastdata;
35
};
36
 
37
enum {
38
	Twsidowrite,
39
	Twsidoread,
40
 
41
	/* ctl bits */
42
	Twsiack		= 1<<2,		/* recv'd data; clear to ack */
43
	Twsiint		= 1<<3,		/* interrupt conditions true */
44
	Twsistop	= 1<<4,		
45
	Twsistart	= 1<<5,
46
	Twsislaveen	= 1<<6,
47
	Twsiinten	= 1<<7,		/* interrupts enabled */
48
 
49
	/* status codes */
50
	SStart	= 0x08,
51
	SWa	= 0x18,
52
	SWda	= 0x28,
53
	SRa	= 0x40,
54
	SRda	= 0x50,
55
	SRna	= 0x58,
56
};
57
 
58
struct Twsi {
59
	QLock;
60
	Rendez	nextbyte;
61
 
62
	/* remainder is state needed to track the operation in progress */
63
	int	intr;
64
	int	done;
65
 
66
	uchar	*bp;			/* current ptr into buf */
67
	uchar	*end;
68
 
69
	ulong	addr;			/* device address */
70
	char	*error;
71
};
72
 
73
static Twsi twsi;
74
 
75
static Dirtab twsidir[] = {
76
	".",	{Qdir, 0, QTDIR},	0,	DMDIR|0555,
77
	"twsi",	{Qtwsi},		0,	0660,
78
};
79
 
80
static char Eabsts[] = "abnormal status";
81
 
82
static void
83
twsifinish(void)
84
{
85
	Kwtwsi *krp = (Kwtwsi *)soc.twsi;
86
 
87
	twsi.done = 1;
88
	krp->ctl |= Twsistop;
89
	coherence();
90
}
91
 
92
static void
93
twsidoread(void)
94
{
95
	Kwtwsi *krp = (Kwtwsi *)soc.twsi;
96
 
97
	switch(krp->status){
98
	case SStart:
99
		krp->data = twsi.addr << 1 | Twsidoread;
100
		break;
101
	case SRa:
102
		krp->ctl |= Twsiack;
103
		break;
104
	case SRda:
105
		if(twsi.bp < twsi.end) {
106
			*twsi.bp++ = krp->data;
107
			krp->ctl |= Twsiack;
108
		} else
109
			krp->ctl &= ~Twsiack;
110
		break;
111
	case SRna:
112
		twsifinish();
113
		break;
114
	default:
115
		twsifinish();
116
		twsi.error = Eabsts;
117
		break;
118
	}
119
}
120
 
121
static void
122
twsidowrite(void)
123
{
124
	Kwtwsi *krp = (Kwtwsi *)soc.twsi;
125
 
126
	switch(krp->status){
127
	case SStart:
128
		krp->data = twsi.addr << 1 | Twsidowrite;
129
		break;
130
	case SWa:
131
	case SWda:
132
		if(twsi.bp < twsi.end)
133
			krp->data = *twsi.bp++;
134
		else
135
			twsifinish();
136
		break;
137
	default:
138
		twsifinish();
139
		twsi.error = Eabsts;
140
		break;
141
	}
142
}
143
 
144
static int
145
twsigotintr(void *)
146
{
147
	return twsi.intr;
148
}
149
 
150
static long
151
twsixfer(uchar *buf, ulong len, ulong offset, void (*op)(void))
152
{
153
	ulong off;
154
	char *err;
155
	Kwtwsi *krp = (Kwtwsi *)soc.twsi;
156
 
157
	qlock(&twsi);
158
	twsi.bp = buf;
159
	twsi.end = buf + len;
160
 
161
	twsi.addr = offset;
162
	twsi.done = twsi.intr = 0;
163
	twsi.error = nil;
164
 
165
	krp->ctl = (krp->ctl & ~Twsiint) | Twsistart;
166
	coherence();
167
	while (!twsi.done) {
168
		sleep(&twsi.nextbyte, twsigotintr, 0);
169
		twsi.intr = 0;
170
		(*op)();
171
		/* signal to start new op & extinguish intr source */
172
		krp->ctl &= ~Twsiint;
173
		coherence();
174
		krp->ctl |= Twsiinten;
175
		coherence();
176
	}
177
	twsifinish();
178
	err = twsi.error;
179
	off = twsi.bp - buf;
180
	twsi.bp = nil;				/* prevent accidents */
181
	qunlock(&twsi);
182
 
183
	if(err)
184
		error(err);
185
	return off;
186
}
187
 
188
static void
189
interrupt(Ureg *, void *)
190
{
191
	Kwtwsi *krp = (Kwtwsi *)soc.twsi;
192
 
193
	twsi.intr = 1;
194
	wakeup(&twsi.nextbyte);
195
 
196
	krp->ctl &= ~Twsiinten;			/* stop further interrupts */
197
	coherence();
198
	intrclear(Irqlo, IRQ0twsi);
199
}
200
 
201
static void
202
twsiinit(void)
203
{
204
	Kwtwsi *krp = (Kwtwsi *)soc.twsi;
205
 
206
	intrenable(Irqlo, IRQ0twsi, interrupt, nil, "twsi");
207
	krp->ctl &= ~Twsiint;
208
	krp->ctl |= Twsiinten;
209
	coherence();
210
}
211
 
212
static void
213
twsishutdown(void)
214
{
215
	Kwtwsi *krp = (Kwtwsi *)soc.twsi;
216
 
217
	krp->ctl &= ~Twsiinten;
218
	coherence();
219
	intrdisable(Irqlo, IRQ0twsi, interrupt, nil, "twsi");
220
}
221
 
222
static Chan*
223
twsiattach(char *param)
224
{
225
	return devattach(L'⁲', param);
226
}
227
 
228
static Walkqid*
229
twsiwalk(Chan *c, Chan *nc, char **name, int nname)
230
{
231
	return devwalk(c, nc, name, nname, twsidir, nelem(twsidir), devgen);
232
}
233
 
234
static int
235
twsistat(Chan *c, uchar *db, int n)
236
{
237
	return devstat(c, db, n, twsidir, nelem(twsidir), devgen);
238
}
239
 
240
static Chan*
241
twsiopen(Chan *c, int omode)
242
{
243
	switch((ulong)c->qid.path){
244
	default:
245
		error(Eperm);
246
	case Qdir:
247
	case Qtwsi:
248
		break;
249
	}
250
	c = devopen(c, omode, twsidir, nelem(twsidir), devgen);
251
	c->mode = openmode(omode);
252
	c->flag |= COPEN;
253
	c->offset = 0;
254
	return c;
255
}
256
 
257
static void
258
twsiclose(Chan *)
259
{
260
}
261
 
262
static long
263
twsiread(Chan *c, void *v, long n, vlong off)
264
{
265
	switch((ulong)c->qid.path){
266
	default:
267
		error(Eperm);
268
	case Qdir:
269
		return devdirread(c, v, n, twsidir, nelem(twsidir), devgen);
270
	case Qtwsi:
271
		return twsixfer(v, n, off, twsidoread);
272
	}
273
}
274
 
275
static long
276
twsiwrite(Chan *c, void *v, long n, vlong off)
277
{
278
	switch((ulong)c->qid.path){
279
	default:
280
		error(Eperm);
281
	case Qtwsi:
282
		return twsixfer(v, n, off, twsidowrite);
283
	}
284
}
285
 
286
Dev twsidevtab = {
287
	L'⁲',
288
	"twsi",
289
 
290
	devreset,
291
	twsiinit,
292
	twsishutdown,
293
	twsiattach,
294
	twsiwalk,
295
	twsistat,
296
	twsiopen,
297
	devcreate,
298
	twsiclose,
299
	twsiread,
300
	devbread,
301
	twsiwrite,
302
	devbwrite,
303
	devremove,
304
	devwstat,
305
};