xref: /haiku/src/add-ons/accelerants/common/i2c.c (revision cda5b8808fd0262f0fac472f6cfa809f846a83cf)
1 /*
2  * Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved.
3  * Copyright 2003, Thomas Kurschel. All Rights Reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 /*!
8 	I2C protocol
9 */
10 
11 #include "i2c.h"
12 
13 #include <KernelExport.h>
14 #include <OS.h>
15 
16 
17 //#define TRACE_I2C
18 #ifdef TRACE_I2C
19 extern "C" void _sPrintf(const char *format, ...);
20 #	define TRACE(x...) _sPrintf("I2C: " x)
21 #else
22 #	define TRACE(x...) ;
23 #endif
24 
25 
26 //!	Timining for 100kHz bus (fractional parts are rounded up)
27 const static i2c_timing kTiming100k = {
28 	buf : 5,
29 	hd_sta : 4,
30 	low : 5,
31 	high : 4,
32 	su_sta : 5,
33 	hd_dat : 0,
34 	su_dat : 1,
35 	r : 1,
36 	f : 1,
37 	su_sto : 4,
38 
39 	// as these are unspecified, we use half a clock cycle as a safe guess
40 	start_timeout : 5,
41 	byte_timeout : 5,
42 	bit_timeout : 5,
43 	ack_start_timeout : 5,
44 	ack_timeout : 5
45 };
46 
47 // timing for 400 kHz bus
48 // (argh! heavy up-rounding here)
49 const static i2c_timing kTiming400k = {
50 	buf : 2,
51 	hd_sta : 1,
52 	low : 2,
53 	high : 1,
54 	su_sta : 1,
55 	hd_dat : 0,
56 	su_dat : 1,
57 	r : 1,
58 	f : 1,
59 	su_sto : 1,
60 
61 	// see kTiming100k
62 	start_timeout : 2,
63 	byte_timeout : 2,
64 	bit_timeout : 2,
65 	ack_start_timeout : 2,
66 	ack_timeout : 2
67 };
68 
69 
70 /*!
71 	There's no spin in user space, but we need it to wait a couple
72 	of microseconds only
73 	(in this case, snooze has much too much overhead)
74 */
75 void
76 spin(bigtime_t delay)
77 {
78 	bigtime_t startTime = system_time();
79 
80 	while (system_time() - startTime < delay)
81 		;
82 }
83 
84 
85 //! Wait until slave releases clock signal ("clock stretching")
86 static status_t
87 wait_for_clk(const i2c_bus *bus, bigtime_t timeout)
88 {
89 	bigtime_t startTime;
90 
91 	// wait for clock signal to raise
92 	spin(bus->timing.r);
93 
94 	startTime = system_time();
95 
96 	while (true) {
97 		int clk, data;
98 
99 		bus->get_signals(bus->cookie, &clk, &data);
100 		if (clk != 0)
101 			return B_OK;
102 
103 		if (system_time() - startTime > timeout)
104 			return B_TIMEOUT;
105 
106 		spin(bus->timing.r);
107 	}
108 }
109 
110 
111 //!	Send start or repeated start condition
112 static status_t
113 send_start_condition(const i2c_bus *bus)
114 {
115 	status_t status;
116 
117 	bus->set_signals(bus->cookie, 1, 1);
118 
119 	status = wait_for_clk(bus, bus->timing.start_timeout);
120 	if (status != B_OK) {
121 		TRACE("send_start_condition(): Timeout sending start condition\n");
122 		return status;
123 	}
124 
125 	spin(bus->timing.su_sta);
126 	bus->set_signals(bus->cookie, 1, 0);
127 	spin(bus->timing.hd_sta);
128 	bus->set_signals(bus->cookie, 0, 0);
129 	spin(bus->timing.f);
130 
131 	return B_OK;
132 }
133 
134 
135 //!	Send stop condition
136 static status_t
137 send_stop_condition(const i2c_bus *bus)
138 {
139 	status_t status;
140 
141 	bus->set_signals(bus->cookie, 0, 0);
142 	spin(bus->timing.r);
143 	bus->set_signals(bus->cookie, 1, 0);
144 
145 	// a slave may wait for us, so let elapse the acknowledge timeout
146 	// to make the slave release bus control
147 	status = wait_for_clk(bus, bus->timing.ack_timeout);
148 	if (status != B_OK) {
149 		TRACE("send_stop_condition(): Timeout sending stop condition\n");
150 		return status;
151 	}
152 
153 	spin(bus->timing.su_sto);
154 	bus->set_signals(bus->cookie, 1, 1);
155 	spin(bus->timing.buf);
156 
157 	return B_OK;
158 }
159 
160 
161 //!	Send one bit
162 static status_t
163 send_bit(const i2c_bus *bus, bool bit, int timeout)
164 {
165 	status_t status;
166 
167 	//TRACE("send_bit(bit = %d)\n", bit & 1);
168 
169 	bus->set_signals(bus->cookie, 0, bit & 1);
170 	spin(bus->timing.su_dat);
171 	bus->set_signals(bus->cookie, 1, bit & 1);
172 
173 	status = wait_for_clk(bus, timeout);
174 	if (status != B_OK) {
175 		TRACE("send_bit(): Timeout when sending next bit\n");
176 		return status;
177 	}
178 
179 	spin(bus->timing.high);
180 	bus->set_signals(bus->cookie, 0, bit & 1);
181 	spin(bus->timing.f + bus->timing.low);
182 
183 	return B_OK;
184 }
185 
186 
187 //!	Send acknowledge and wait for reply
188 static status_t
189 send_acknowledge(const i2c_bus *bus)
190 {
191 	status_t status;
192 	bigtime_t startTime;
193 
194 	// release data so slave can modify it
195 	bus->set_signals(bus->cookie, 0, 1);
196 	spin(bus->timing.su_dat);
197 	bus->set_signals(bus->cookie, 1, 1);
198 
199 	status = wait_for_clk(bus, bus->timing.ack_start_timeout);
200 	if (status != B_OK) {
201 		TRACE("send_acknowledge(): Timeout when sending acknowledge\n");
202 		return status;
203 	}
204 
205 	// data and clock is high, now wait for slave to pull data low
206 	// (according to spec, this can happen any time once clock is high)
207 	startTime = system_time();
208 
209 	while (true) {
210 		int clk, data;
211 
212 		bus->get_signals(bus->cookie, &clk, &data);
213 
214 		if (data == 0)
215 			break;
216 
217 		if (system_time() - startTime > bus->timing.ack_timeout) {
218 			TRACE("send_acknowledge(): Slave didn't acknowledge byte\n");
219 			return B_TIMEOUT;
220 		}
221 
222 		spin(bus->timing.r);
223 	}
224 
225 	TRACE("send_acknowledge(): Success!\n");
226 
227 	// make sure we've waited at least t_high
228 	spin(bus->timing.high);
229 
230 	bus->set_signals(bus->cookie, 0, 1);
231 	spin(bus->timing.f + bus->timing.low);
232 
233 	return B_OK;
234 }
235 
236 
237 //!	Send byte and wait for acknowledge if <ackowledge> is true
238 static status_t
239 send_byte(const i2c_bus *bus, uint8 byte, bool acknowledge)
240 {
241 	int i;
242 
243 	//TRACE("send_byte(byte = %x)\n", byte);
244 
245 	for (i = 7; i >= 0; --i) {
246 		status_t status = send_bit(bus, byte >> i,
247 			i == 7 ? bus->timing.byte_timeout : bus->timing.bit_timeout);
248 		if (status != B_OK)
249 			return status;
250 	}
251 
252 	if (acknowledge)
253 		return send_acknowledge(bus);
254 
255 	return B_OK;
256 }
257 
258 
259 //!	Send slave address, obeying 10-bit addresses and general call addresses
260 static status_t
261 send_slave_address(const i2c_bus *bus, int slaveAddress, bool isWrite)
262 {
263 	status_t status;
264 
265 	status = send_byte(bus, (slaveAddress & 0xfe) | !isWrite, true);
266 	if (status != B_OK)
267 		return status;
268 
269 	// there are the following special cases if the first byte looks like:
270 	// - 0000 0000 - general call address (second byte with address follows)
271 	// - 0000 0001 - start byte
272 	// - 0000 001x - CBus address
273 	// - 0000 010x - address reserved for different bus format
274 	// - 0000 011x |
275 	// - 0000 1xxx |-> reserved
276 	// - 1111 1xxx |
277 	// - 1111 0xxx - 10 bit address  (second byte contains remaining 8 bits)
278 
279 	// the lsb is 0 for write and 1 for read (except for general call address)
280 	if ((slaveAddress & 0xff) != 0 && (slaveAddress & 0xf8) != 0xf0)
281 		return B_OK;
282 
283 	return send_byte(bus, slaveAddress >> 8, true);
284 		// send second byte if required
285 }
286 
287 
288 //!	Receive one bit
289 static status_t
290 receive_bit(const i2c_bus *bus, bool *bit, int timeout)
291 {
292 	status_t status;
293 	int clk, data;
294 
295 	bus->set_signals(bus->cookie, 1, 1);
296 		// release clock
297 
298 	// wait for slave to raise clock
299 	status = wait_for_clk(bus, timeout);
300 	if (status != B_OK) {
301 		TRACE("receive_bit(): Timeout waiting for bit sent by slave\n");
302 		return status;
303 	}
304 
305 	bus->get_signals(bus->cookie, &clk, &data);
306 		// sample data
307 
308 	spin(bus->timing.high);
309 		// leave clock high for minimal time
310 
311 	bus->set_signals(bus->cookie, 0, 1);
312 		// pull clock low so slave waits for us before next bit
313 
314 	spin(bus->timing.f + bus->timing.low);
315 		// let it settle and leave it low for minimal time
316 		// to make sure slave has finished bit transmission too
317 
318 	*bit = data;
319 	return B_OK;
320 }
321 
322 
323 /*!
324 	Send positive acknowledge afterwards if <acknowledge> is true,
325 	else send negative one
326 */
327 static status_t
328 receive_byte(const i2c_bus *bus, uint8 *resultByte, bool acknowledge)
329 {
330 	uint8 byte = 0;
331 	int i;
332 
333 	// pull clock low to let slave wait for us
334 	bus->set_signals(bus->cookie, 0, 1);
335 
336 	for (i = 7; i >= 0; i--) {
337 		bool bit;
338 
339 		status_t status = receive_bit(bus, &bit,
340 			i == 7 ? bus->timing.byte_timeout : bus->timing.bit_timeout);
341 		if (status != B_OK)
342 			return status;
343 
344 		byte = (byte << 1) | bit;
345 	}
346 
347 	//SHOW_FLOW(3, "%x ", byte);
348 
349 	*resultByte = byte;
350 
351 	return send_bit(bus, acknowledge ? 0 : 1, bus->timing.bit_timeout);
352 }
353 
354 
355 //!	Send multiple bytes
356 static status_t
357 send_bytes(const i2c_bus *bus, const uint8 *writeBuffer, ssize_t writeLength)
358 {
359 	TRACE("send_bytes(length = %ld)\n", writeLength);
360 
361 	for (; writeLength > 0; --writeLength, ++writeBuffer) {
362 		status_t status = send_byte(bus, *writeBuffer, true);
363 		if (status != B_OK)
364 			return status;
365 	}
366 
367 	return B_OK;
368 }
369 
370 
371 //!	Receive multiple bytes
372 static status_t
373 receive_bytes(const i2c_bus *bus, uint8 *readBuffer, ssize_t readLength)
374 {
375 	TRACE("receive_bytes(length = %ld)\n", writeLength);
376 
377 	for (; readLength > 0; --readLength, ++readBuffer) {
378 		status_t status = receive_byte(bus, readBuffer, readLength > 1);
379 		if (status != B_OK)
380 			return status;
381 	}
382 
383 	return B_OK;
384 }
385 
386 
387 //	#pragma mark - exported functions
388 
389 
390 //!	Combined i2c send+receive format
391 status_t
392 i2c_send_receive(const i2c_bus *bus, int slaveAddress, const uint8 *writeBuffer,
393 	size_t writeLength, uint8 *readBuffer, size_t readLength)
394 {
395 	status_t status = send_start_condition(bus);
396 	if (status != B_OK)
397 		return status;
398 
399 	status = send_slave_address(bus, slaveAddress, true);
400 	if (status != B_OK)
401 		goto err;
402 
403 	status = send_bytes(bus, writeBuffer, writeLength);
404 	if (status != B_OK)
405 		goto err;
406 
407 	status = send_start_condition(bus);
408 	if (status != B_OK)
409 		return status;
410 
411 	status = send_slave_address(bus, slaveAddress, false);
412 	if (status != B_OK)
413 		goto err;
414 
415 	status = receive_bytes(bus, readBuffer, readLength);
416 	if (status != B_OK)
417 		goto err;
418 
419 	return send_stop_condition(bus);
420 
421 err:
422 	TRACE("i2c_send_receive(): Cancelling transmission\n");
423 	send_stop_condition(bus);
424 	return status;
425 }
426 
427 
428 void
429 i2c_get100k_timing(i2c_timing *timing)
430 {
431 	*timing = kTiming100k;
432 }
433 
434 
435 void
436 i2c_get400k_timing(i2c_timing *timing)
437 {
438 	*timing = kTiming400k;
439 }
440