Annotation of src/sys/dev/i2c/i2c_bitbang.c, Revision 1.9.14.2
1.9.14.2! wrstuden 1: /* $NetBSD: i2c_bitbang.c,v 1.9.14.1 2008/06/23 04:31:01 wrstuden Exp $ */
1.1 thorpej 2:
3: /*
4: * Copyright (c) 2003 Wasabi Systems, Inc.
5: * All rights reserved.
6: *
7: * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed for the NetBSD Project by
20: * Wasabi Systems, Inc.
21: * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22: * or promote products derived from this software without specific prior
23: * written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35: * POSSIBILITY OF SUCH DAMAGE.
36: */
37:
38: /*
39: * Common module for bit-bang'ing an I2C bus.
40: */
41:
1.9 lukem 42: #include <sys/cdefs.h>
1.9.14.2! wrstuden 43: __KERNEL_RCSID(0, "$NetBSD: i2c_bitbang.c,v 1.9.14.1 2008/06/23 04:31:01 wrstuden Exp $");
1.9 lukem 44:
1.1 thorpej 45: #include <sys/param.h>
46:
47: #include <dev/i2c/i2cvar.h>
48: #include <dev/i2c/i2c_bitbang.h>
49:
1.3 christos 50: #define SETBITS(x) ops->ibo_set_bits(v, (x))
1.1 thorpej 51: #define DIR(x) ops->ibo_set_dir(v, (x))
52: #define READ ops->ibo_read_bits(v)
53:
54: #define SDA ops->ibo_bits[I2C_BIT_SDA] /* i2c signal */
55: #define SCL ops->ibo_bits[I2C_BIT_SCL] /* i2c signal */
56: #define OUTPUT ops->ibo_bits[I2C_BIT_OUTPUT] /* SDA is output */
57: #define INPUT ops->ibo_bits[I2C_BIT_INPUT] /* SDA is input */
58:
1.7 macallan 59: #ifndef SCL_BAIL_COUNT
60: #define SCL_BAIL_COUNT 1000
61: #endif
62:
63: static inline int i2c_wait_for_scl(void *, i2c_bitbang_ops_t);
64:
65: static inline int
66: i2c_wait_for_scl(void *v, i2c_bitbang_ops_t ops)
67: {
68: int bail = 0;
69:
70: while (((READ & SCL) == 0) && (bail < SCL_BAIL_COUNT)) {
71: delay(1);
72: bail++;
73: }
74: if (bail == SCL_BAIL_COUNT) {
75: i2c_bitbang_send_stop(v, 0, ops);
76: return EIO;
77: }
78: return 0;
79: }
80:
1.1 thorpej 81: /*ARGSUSED*/
82: int
1.6 christos 83: i2c_bitbang_send_start(void *v, int flags, i2c_bitbang_ops_t ops)
1.1 thorpej 84: {
85:
1.9.14.1 wrstuden 86: /* start condition: put SDL H->L edge during SCL=H */
87:
1.1 thorpej 88: DIR(OUTPUT);
1.3 christos 89: SETBITS(SDA | SCL);
1.9.14.1 wrstuden 90: delay(5); /* bus free time (4.7 us) */
91: SETBITS( 0 | SCL);
1.7 macallan 92: if (i2c_wait_for_scl(v, ops) != 0)
93: return EIO;
1.9.14.1 wrstuden 94: delay(4); /* start hold time (4.0 us) */
1.8 kiyohara 95:
1.9.14.1 wrstuden 96: /* leave SCL=L and SDL=L to avoid unexpected start/stop condition */
97: SETBITS( 0 | 0);
1.1 thorpej 98:
1.9.14.1 wrstuden 99: return 0;
1.1 thorpej 100: }
101:
102: /*ARGSUSED*/
103: int
1.6 christos 104: i2c_bitbang_send_stop(void *v, int flags, i2c_bitbang_ops_t ops)
1.1 thorpej 105: {
106:
1.9.14.1 wrstuden 107: /* stop condition: put SDL L->H edge during SCL=H */
108:
109: /* assume SCL=L, SDL=L here */
1.1 thorpej 110: DIR(OUTPUT);
1.9.14.1 wrstuden 111: SETBITS( 0 | SCL);
112: delay(4); /* stop setup time (4.0 us) */
1.3 christos 113: SETBITS(SDA | SCL);
1.1 thorpej 114:
1.9.14.1 wrstuden 115: return 0;
1.1 thorpej 116: }
117:
118: int
119: i2c_bitbang_initiate_xfer(void *v, i2c_addr_t addr, int flags,
120: i2c_bitbang_ops_t ops)
121: {
122:
1.4 gdamore 123: if (addr < 0x80) {
124: uint8_t i2caddr;
1.1 thorpej 125:
1.4 gdamore 126: /* disallow the 10-bit address prefix */
127: if ((addr & 0x78) == 0x78)
128: return EINVAL;
129: i2caddr = (addr << 1) | ((flags & I2C_F_READ) ? 1 : 0);
130: (void) i2c_bitbang_send_start(v, flags, ops);
131:
132: return (i2c_bitbang_write_byte(v, i2caddr,
133: flags & ~I2C_F_STOP, ops));
134:
135: } else if (addr < 0x400) {
136: uint16_t i2caddr;
137: int rv;
138:
139: i2caddr = (addr << 1) | ((flags & I2C_F_READ) ? 1 : 0) |
140: 0xf000;
141:
142: (void) i2c_bitbang_send_start(v, flags, ops);
143: rv = i2c_bitbang_write_byte(v, i2caddr >> 8,
144: flags & ~I2C_F_STOP, ops);
145: /* did a slave ack the 10-bit prefix? */
146: if (rv != 0)
147: return rv;
148:
149: /* send the lower 7-bits (+ read/write mode) */
150: return (i2c_bitbang_write_byte(v, i2caddr & 0xff,
151: flags & ~I2C_F_STOP, ops));
1.1 thorpej 152:
1.4 gdamore 153: } else
154: return EINVAL;
1.1 thorpej 155: }
156:
157: int
1.9.14.1 wrstuden 158: i2c_bitbang_read_byte(void *v, uint8_t *valp, int flags, i2c_bitbang_ops_t ops)
1.1 thorpej 159: {
160: int i;
161: uint8_t val = 0;
162: uint32_t bit;
163:
1.9.14.1 wrstuden 164: /* assume SCL=L, SDA=L here */
165:
166: DIR(INPUT);
1.1 thorpej 167:
168: for (i = 0; i < 8; i++) {
169: val <<= 1;
1.8 kiyohara 170:
1.9.14.1 wrstuden 171: /* data is set at SCL H->L edge */
1.9.14.2! wrstuden 172: /* SDA is set here because DIR() is INPUT */
! 173: SETBITS(SDA | 0);
1.9.14.1 wrstuden 174: delay(5); /* clock low time (4.7 us) */
1.8 kiyohara 175:
1.9.14.1 wrstuden 176: /* read data at SCL L->H edge */
1.9.14.2! wrstuden 177: SETBITS(SDA | SCL);
1.7 macallan 178: if (i2c_wait_for_scl(v, ops) != 0)
179: return EIO;
1.1 thorpej 180: if (READ & SDA)
181: val |= 1;
1.9.14.1 wrstuden 182: delay(4); /* clock high time (4.0 us) */
1.1 thorpej 183: }
1.9.14.1 wrstuden 184: /* set SCL H->L before set SDA direction OUTPUT */
1.9.14.2! wrstuden 185: SETBITS(SDA | 0);
1.1 thorpej 186:
1.9.14.1 wrstuden 187: /* set ack after SCL H->L edge */
1.1 thorpej 188: bit = (flags & I2C_F_LAST) ? SDA : 0;
189: DIR(OUTPUT);
1.9.14.1 wrstuden 190: SETBITS(bit | 0);
191: delay(5); /* clock low time (4.7 us) */
1.8 kiyohara 192:
1.9.14.1 wrstuden 193: /* ack is checked at SCL L->H edge */
194: SETBITS(bit | SCL);
1.7 macallan 195: if (i2c_wait_for_scl(v, ops) != 0)
196: return EIO;
1.9.14.1 wrstuden 197: delay(4); /* clock high time (4.0 us) */
1.8 kiyohara 198:
1.9.14.1 wrstuden 199: /* set SCL H->L for next data; don't change SDA here */
200: SETBITS(bit | 0);
1.1 thorpej 201:
1.9.14.1 wrstuden 202: /* leave SCL=L and SDL=L to avoid unexpected start/stop condition */
203: SETBITS( 0 | 0);
204:
1.1 thorpej 205:
206: if ((flags & (I2C_F_STOP | I2C_F_LAST)) == (I2C_F_STOP | I2C_F_LAST))
207: (void) i2c_bitbang_send_stop(v, flags, ops);
208:
209: *valp = val;
1.9.14.1 wrstuden 210: return 0;
1.1 thorpej 211: }
212:
213: int
1.9.14.1 wrstuden 214: i2c_bitbang_write_byte(void *v, uint8_t val, int flags, i2c_bitbang_ops_t ops)
1.1 thorpej 215: {
216: uint32_t bit;
217: uint8_t mask;
218: int error;
219:
1.9.14.1 wrstuden 220: /* assume at SCL=L, SDA=L here */
221:
222: DIR(OUTPUT);
223:
1.1 thorpej 224: for (mask = 0x80; mask != 0; mask >>= 1) {
225: bit = (val & mask) ? SDA : 0;
1.8 kiyohara 226:
1.9.14.1 wrstuden 227: /* set data after SCL H->L edge */
228: SETBITS(bit | 0);
229: delay(5); /* clock low time (4.7 us) */
1.8 kiyohara 230:
1.9.14.1 wrstuden 231: /* data is fetched at SCL L->H edge */
232: SETBITS(bit | SCL);
1.7 macallan 233: if (i2c_wait_for_scl(v, ops))
234: return EIO;
1.9.14.1 wrstuden 235: delay(4); /* clock high time (4.0 us) */
1.8 kiyohara 236:
1.9.14.1 wrstuden 237: /* put SCL H->L edge; don't change SDA here */
238: SETBITS(bit | 0);
1.1 thorpej 239: }
240:
1.9.14.1 wrstuden 241: /* ack is set at H->L edge */
242: DIR(INPUT);
243: delay(5); /* clock low time (4.7 us) */
1.8 kiyohara 244:
1.9.14.1 wrstuden 245: /* read ack at L->H edge */
1.9.14.2! wrstuden 246: /* SDA is set here because DIR() is INPUT */
! 247: SETBITS(SDA | SCL);
1.7 macallan 248: if (i2c_wait_for_scl(v, ops) != 0)
249: return EIO;
1.1 thorpej 250: error = (READ & SDA) ? EIO : 0;
1.9.14.1 wrstuden 251: delay(4); /* clock high time (4.0 us) */
1.8 kiyohara 252:
1.9.14.1 wrstuden 253: /* set SCL H->L before set SDA direction OUTPUT */
1.9.14.2! wrstuden 254: SETBITS(SDA | 0);
1.8 kiyohara 255: DIR(OUTPUT);
1.9.14.2! wrstuden 256: /* leave SCL=L and SDL=L to avoid unexpected start/stop condition */
! 257: SETBITS( 0 | 0);
1.1 thorpej 258:
259: if (flags & I2C_F_STOP)
260: (void) i2c_bitbang_send_stop(v, flags, ops);
261:
1.9.14.1 wrstuden 262: return error;
1.1 thorpej 263: }
CVSweb <webmaster@jp.NetBSD.org>