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