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