xref: /plan9-contrib/sys/src/9/bcm/i2c.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
1 /*
2  * bcm2835 i2c controller
3  *
4  *	Only i2c1 is supported.
5  *	i2c2 is reserved for HDMI.
6  *	i2c0 SDA0/SCL0 pins are not routed to P1 connector (except for early Rev 0 boards)
7  *
8  * maybe hardware problems lurking, see: https://github.com/raspberrypi/linux/issues/254
9  */
10 
11 #include	"u.h"
12 #include	"../port/lib.h"
13 #include	"../port/error.h"
14 #include	"mem.h"
15 #include	"dat.h"
16 #include	"fns.h"
17 #include	"io.h"
18 
19 #define I2CREGS	(VIRTIO+0x804000)
20 #define SDA0Pin	2
21 #define	SCL0Pin	3
22 #define	Alt0	0x4
23 
24 typedef struct I2c I2c;
25 typedef struct Bsc Bsc;
26 
27 /*
28  * Registers for Broadcom Serial Controller (i2c compatible)
29  */
30 struct Bsc {
31 	u32int	ctrl;
32 	u32int	stat;
33 	u32int	dlen;
34 	u32int	addr;
35 	u32int	fifo;
36 	u32int	clkdiv;		/* default 1500 => 100 KHz assuming 150Mhz input clock */
37 	u32int	delay;		/* default (48<<16)|48 falling:rising edge */
38 	u32int	clktimeout;	/* default 64 */
39 };
40 
41 /*
42  * Per-controller info
43  */
44 struct I2c {
45 	QLock	lock;
46 	Lock	reglock;
47 	Rendez	r;
48 	Bsc	*regs;
49 };
50 
51 static I2c i2c;
52 
53 enum {
54 	/* ctrl */
55 	I2cen	= 1<<15,	/* I2c enable */
56 	Intr	= 1<<10,	/* interrupt on reception */
57 	Intt	= 1<<9,		/* interrupt on transmission */
58 	Intd	= 1<<8,		/* interrupt on done */
59 	Start	= 1<<7,		/* aka ST, start a transfer */
60 	Clear	= 1<<4,		/* clear fifo */
61 	Read	= 1<<0,		/* read transfer */
62 	Write	= 0<<0,		/* write transfer */
63 
64 	/* stat */
65 	Clkt	= 1<<9,		/* clock stretch timeout */
66 	Err	= 1<<8,			/* NAK */
67 	Rxf	= 1<<7,			/* RX fifo full */
68 	Txe	= 1<<6,			/* TX fifo full */
69 	Rxd	= 1<<5,			/* RX fifo has data */
70 	Txd	= 1<<4,			/* TX fifo has space */
71 	Rxr	= 1<<3,			/* RX fiio needs reading */
72 	Txw	= 1<<2,			/* TX fifo needs writing */
73 	Done	= 1<<1,		/* transfer done */
74 	Ta	= 1<<0,			/* Transfer active */
75 
76 	/* maximum I2C I/O (can change) */
77 	MaxIO =	128,
78 	MaxSA =	2,	/* longest subaddress */
79 	Bufsize = (MaxIO+MaxSA+1+4)&~3,		/* extra space for subaddress/clock bytes and alignment */
80 
81 	Chatty = 0,
82 };
83 
84 static void
i2cinterrupt(Ureg *,void *)85 i2cinterrupt(Ureg*, void*)
86 {
87 	Bsc *r;
88 	int st;
89 
90 	r = i2c.regs;
91 	st = 0;
92 	if((r->ctrl & Intr) && (r->stat & Rxd))
93 		st |= Intr;
94 	if((r->ctrl & Intt) && (r->stat & Txd))
95 		st |= Intt;
96 	if(r->stat & Done)
97 		st |= Intd;
98 	if(st){
99 		r->ctrl &= ~st;
100 		wakeup(&i2c.r);
101 	}
102 }
103 
104 static int
i2cready(void * st)105 i2cready(void *st)
106 {
107 	return (i2c.regs->stat & (uintptr)st);
108 }
109 
110 static void
i2cinit(void)111 i2cinit(void)
112 {
113 	i2c.regs = (Bsc*)I2CREGS;
114 	i2c.regs->clkdiv = 2500;
115 
116 	gpiosel(SDA0Pin, Alt0);
117 	gpiosel(SCL0Pin, Alt0);
118 	gpiopullup(SDA0Pin);
119 	gpiopullup(SCL0Pin);
120 
121 	intrenable(IRQi2c, i2cinterrupt, 0, 0, "i2c");
122 }
123 
124 /*
125  * To do subaddressing avoiding a STOP condition between the address and payload.
126  * 	- write the subaddress,
127  *	- poll until the transfer starts,
128  *	- overwrite the registers for the payload transfer, before the subaddress
129  * 		transaction has completed.
130  *
131  * FIXME: neither 10bit adressing nor 100Khz transfers implemented yet.
132  */
133 static void
i2cio(int rw,int tenbit,uint addr,void * buf,int len,int salen,uint subaddr)134 i2cio(int rw, int tenbit, uint addr, void *buf, int len, int salen, uint subaddr)
135 {
136 	Bsc *r;
137 	uchar *p;
138 	int st;
139 
140 	if(tenbit)
141 		error("10bit addressing not supported");
142 	if(salen == 0 && subaddr)	/* default subaddress len == 1byte */
143 		salen = 1;
144 
145 	qlock(&i2c.lock);
146 	r = i2c.regs;
147 	r->ctrl = I2cen | Clear;
148 	r->addr = addr;
149 	r->stat = Clkt|Err|Done;
150 
151 	if(salen){
152 		r->dlen = salen;
153 		r->ctrl = I2cen | Start | Write;
154 		while((r->stat & Ta) == 0) {
155 			if(r->stat & (Err|Clkt)) {
156 				qunlock(&i2c.lock);
157 				error(Eio);
158 			}
159 		}
160 		r->dlen = len;
161 		r->ctrl = I2cen | Start | Intd | rw;
162 		for(; salen > 0; salen--)
163 			r->fifo = subaddr >> ((salen-1)*8);
164 		/*
165 		 * Adapted from Linux code...uses undocumented
166 		 * status information.
167 		 */
168 		if(rw == Read) {
169 			do {
170 				if(r->stat & (Err|Clkt)) {
171 					qunlock(&i2c.lock);
172 					error(Eio);
173 				}
174 				st = r->stat >> 28;
175 			} while(st != 0 && st != 4 && st != 5);
176 		}
177 	}
178 	else {
179 		r->dlen = len;
180 		r->ctrl = I2cen | Start | Intd | rw;
181 	}
182 
183 	p = buf;
184 	st = rw == Read? Rxd : Txd;
185 	while(len > 0){
186 		while((r->stat & (st|Done)) == 0){
187 			r->ctrl |= rw == Read? Intr : Intt;
188 			sleep(&i2c.r, i2cready, (void*)(st|Done));
189 		}
190 		if(r->stat & (Err|Clkt)){
191 			qunlock(&i2c.lock);
192 			error(Eio);
193 		}
194 		if(rw == Read){
195 			do{
196 				*p++ = r->fifo;
197 				len--;
198 			}while ((r->stat & Rxd) && len > 0);
199 		}else{
200 			do{
201 				r->fifo = *p++;
202 				len--;
203 			}while((r->stat & Txd) && len > 0);
204 		}
205 	}
206 	while((r->stat & Done) == 0)
207 		sleep(&i2c.r, i2cready, (void*)Done);
208 	if(r->stat & (Err|Clkt)){
209 		qunlock(&i2c.lock);
210 		error(Eio);
211 	}
212 	r->ctrl = 0;
213 	qunlock(&i2c.lock);
214 }
215 
216 
217 void
i2csetup(int)218 i2csetup(int)
219 {
220 	//print("i2csetup\n");
221 	i2cinit();
222 }
223 
224 long
i2csend(I2Cdev * d,void * buf,long len,ulong offset)225 i2csend(I2Cdev *d, void *buf, long len, ulong offset)
226 {
227 	i2cio(Write, d->tenbit, d->addr, buf, len, d->salen, offset);
228 	return len;
229 }
230 
231 long
i2crecv(I2Cdev * d,void * buf,long len,ulong offset)232 i2crecv(I2Cdev *d, void *buf, long len, ulong offset)
233 {
234 	i2cio(Read, d->tenbit, d->addr, buf, len, d->salen, offset);
235 	return len;
236 }
237