2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify,
8 * merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
27 #include <KernelExport.h>
37 static status_t
i2c_writebyte(i2c_bus
*bus
, uint8 byte
, int *ack
);
38 static status_t
i2c_readbyte(i2c_bus
*bus
, uint8
*pbyte
);
39 static status_t
i2c_read_unlocked(i2c_bus
*bus
, int address
, void *data
, int size
);
40 static status_t
i2c_write_unlocked(i2c_bus
*bus
, int address
, const void *data
, int size
);
57 i2c_create_bus(void *cookie
,
65 i2c_bus
*bus
= malloc(sizeof(i2c_bus
));
69 bus
->sem
= create_sem(1, "i2c bus access");
76 bus
->delay
= 1000000 / frequency
;
79 bus
->timeout
= timeout
;
80 bus
->set_scl
= set_scl
;
81 bus
->set_sda
= set_sda
;
82 bus
->get_scl
= get_scl
;
83 bus
->get_sda
= get_sda
;
93 i2c_delete_bus(i2c_bus
*bus
)
103 set_sda_low(i2c_bus
*bus
)
105 bus
->set_sda(bus
->cookie
, 0);
111 set_sda_high(i2c_bus
*bus
)
113 bus
->set_sda(bus
->cookie
, 1);
119 set_scl_low(i2c_bus
*bus
)
121 bus
->set_scl(bus
->cookie
, 0);
126 static inline status_t
127 set_scl_high(i2c_bus
*bus
)
129 bigtime_t end
= system_time() + bus
->timeout
;
130 bus
->set_scl(bus
->cookie
, 1);
131 while (0 == bus
->get_scl(bus
->cookie
)) {
132 if (system_time() > end
)
142 i2c_start(i2c_bus
*bus
)
150 i2c_stop(i2c_bus
*bus
)
158 static inline status_t
159 i2c_start_address(i2c_bus
*bus
, int address
, int read
/* 1 = read, 0 = write */)
166 // TRACE("i2c_start_address: enter\n");
168 addr
= (address
<< 1) | (read
& 1);
169 for (i
= 0; i
< 5; i
++) {
171 res
= i2c_writebyte(bus
, addr
, &ack
);
177 if (res
== B_TIMED_OUT
)
183 // TRACE("i2c_start_address: %s, ack %d, i %d\n", strerror(res), ack, i);
188 /* write one byte and the ack/nack
190 * B_OK => byte transmitted
191 * B_ERROR => arbitration lost
192 * B_TIMED_OUT => time out
195 i2c_writebyte(i2c_bus
*bus
, uint8 byte
, int *ack
)
201 for (i
= 7; i
>= 0; i
--) {
202 int bit
= (byte
>> i
) & 1;
203 if (has_arbitration
) {
209 if (set_scl_high(bus
) != B_OK
) {
210 set_sda_high(bus
); // avoid blocking the bus
211 TRACE("i2c_writebyte timeout at bit %d\n", i
);
214 if (has_arbitration
) {
215 if (bit
== 1 && 0 == bus
->get_sda(bus
->cookie
)) {
217 // TRACE("i2c_writebyte lost arbitration at bit %d\n", i);
223 if (set_scl_high(bus
) != B_OK
) {
224 TRACE("i2c_writebyte timeout at ack\n");
227 *ack
= 0 == bus
->get_sda(bus
->cookie
);
230 return has_arbitration
? B_OK
: B_ERROR
;
234 /* read one byte, don't generate ack
237 i2c_readbyte(i2c_bus
*bus
, uint8
*pbyte
)
244 for (i
= 7; i
>= 0; i
--) {
245 if (set_scl_high(bus
) != B_OK
) {
246 TRACE("i2c_readbyte timeout at bit %d\n", i
);
249 byte
= (byte
<< 1) | bus
->get_sda(bus
->cookie
);
258 i2c_read_unlocked(i2c_bus
*bus
, int address
, void *data
, int size
)
266 status
= i2c_start_address(bus
, address
, 1 /* 1 = read, 0 = write */);
267 if (status
!= B_OK
) {
268 TRACE("i2c_read: error on i2c_start_address: %s\n", strerror(status
));
274 if (i2c_readbyte(bus
, bytes
) != B_OK
) { // timeout
275 TRACE("i2c_read: timeout error on byte %ld\n", bytes
- (uint8
*)data
);
279 set_sda_low(bus
); // ack
281 set_sda_high(bus
); // nack
283 if (set_scl_high(bus
) != B_OK
) {
284 set_sda_high(bus
); // avoid blocking the bus
285 TRACE("i2c_read: timeout at ack\n");
302 i2c_write_unlocked(i2c_bus
*bus
, int address
, const void *data
, int size
)
311 status
= i2c_start_address(bus
, address
, 0 /* 1 = read, 0 = write */);
312 if (status
!= B_OK
) {
313 TRACE("i2c_write: error on i2c_start_address: %s\n", strerror(status
));
319 status
= i2c_writebyte(bus
, *bytes
, &ack
);
320 if (status
== B_TIMED_OUT
) {
321 TRACE("i2c_write: timeout error on byte %ld\n", bytes
- (uint8
*)data
);
324 if (status
!= B_OK
) {
325 TRACE("i2c_write: arbitration lost on byte %ld\n", bytes
- (uint8
*)data
);
329 TRACE("i2c_write: error, got NACK on byte %ld\n", bytes
- (uint8
*)data
);
340 return ack
? B_OK
: B_ERROR
;
345 i2c_read(i2c_bus
*bus
, int address
, void *data
, int size
)
348 acquire_sem(bus
->sem
);
349 res
= i2c_read_unlocked(bus
, address
, data
, size
);
350 release_sem(bus
->sem
);
356 i2c_write(i2c_bus
*bus
, int address
, const void *data
, int size
)
359 acquire_sem(bus
->sem
);
360 res
= i2c_write_unlocked(bus
, address
, data
, size
);
361 release_sem(bus
->sem
);
367 i2c_xfer(i2c_bus
*bus
, int address
,
368 const void *write_data
, int write_size
,
369 void *read_data
, int read_size
)
373 acquire_sem(bus
->sem
);
375 if (write_data
!= 0 && write_size
!= 0) {
376 res
= i2c_write_unlocked(bus
, address
, write_data
, write_size
);
378 release_sem(bus
->sem
);
383 if (read_data
!= 0 && read_size
!= 0) {
384 res
= i2c_read_unlocked(bus
, address
, read_data
, read_size
);
386 release_sem(bus
->sem
);
391 release_sem(bus
->sem
);