1 /* $OpenBSD: i2c_bitbang.c,v 1.3 2006/01/13 23:56:46 grange Exp $ */
2 /* $NetBSD: i2c_bitbang.c,v 1.1 2003/09/30 00:35:31 thorpej Exp $ */
3
4 /*
5 * Copyright (c) 2003 Wasabi Systems, Inc.
6 * All rights reserved.
7 *
8 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed for the NetBSD Project by
21 * Wasabi Systems, Inc.
22 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23 * or promote products derived from this software without specific prior
24 * written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Common module for bit-bang'ing an I2C bus.
41 */
42
43 #include <sys/param.h>
44
45 #include <dev/i2c/i2cvar.h>
46 #include <dev/i2c/i2c_bitbang.h>
47
48 #define BB_SET(x) ops->ibo_set_bits(v, (x))
49 #define BB_DIR(x) ops->ibo_set_dir(v, (x))
50 #define BB_READ ops->ibo_read_bits(v)
51
52 #define SDA ops->ibo_bits[I2C_BIT_SDA] /* i2c signal */
53 #define SCL ops->ibo_bits[I2C_BIT_SCL] /* i2c signal */
54 #define OUTPUT ops->ibo_bits[I2C_BIT_OUTPUT] /* SDA is output */
55 #define INPUT ops->ibo_bits[I2C_BIT_INPUT] /* SDA is input */
56
57 /*ARGSUSED*/
58 int
59 i2c_bitbang_send_start(void *v, int flags, i2c_bitbang_ops_t ops)
60 {
61
62 BB_DIR(OUTPUT);
63
64 BB_SET(SDA | SCL);
65 delay(5); /* bus free time (4.7 uS) */
66 BB_SET( SCL);
67 delay(4); /* start hold time (4.0 uS) */
68 BB_SET( 0);
69 delay(5); /* clock low time (4.7 uS) */
70
71 return (0);
72 }
73
74 /*ARGSUSED*/
75 int
76 i2c_bitbang_send_stop(void *v, int flags, i2c_bitbang_ops_t ops)
77 {
78
79 BB_DIR(OUTPUT);
80
81 BB_SET( SCL);
82 delay(4); /* stop setup time (4.0 uS) */
83 BB_SET(SDA | SCL);
84
85 return (0);
86 }
87
88 int
89 i2c_bitbang_initiate_xfer(void *v, i2c_addr_t addr, int flags,
90 i2c_bitbang_ops_t ops)
91 {
92 int i2caddr;
93
94 /* XXX Only support 7-bit addressing for now. */
95 if ((addr & 0x78) == 0x78)
96 return (EINVAL);
97
98 i2caddr = (addr << 1) | ((flags & I2C_F_READ) ? 1 : 0);
99
100 (void) i2c_bitbang_send_start(v, flags, ops);
101 return (i2c_bitbang_write_byte(v, i2caddr, flags & ~I2C_F_STOP, ops));
102 }
103
104 int
105 i2c_bitbang_read_byte(void *v, uint8_t *valp, int flags,
106 i2c_bitbang_ops_t ops)
107 {
108 int i;
109 uint8_t val = 0;
110 uint32_t bit;
111
112 BB_DIR(INPUT);
113 BB_SET(SDA );
114
115 for (i = 0; i < 8; i++) {
116 val <<= 1;
117 BB_SET(SDA | SCL);
118 delay(4); /* clock high time (4.0 uS) */
119 if (BB_READ & SDA)
120 val |= 1;
121 BB_SET(SDA );
122 delay(5); /* clock low time (4.7 uS) */
123 }
124
125 bit = (flags & I2C_F_LAST) ? SDA : 0;
126 BB_DIR(OUTPUT);
127 BB_SET(bit );
128 delay(1); /* data setup time (250 nS) */
129 BB_SET(bit | SCL);
130 delay(4); /* clock high time (4.0 uS) */
131 BB_SET(bit );
132 delay(5); /* clock low time (4.7 uS) */
133
134 BB_DIR(INPUT);
135 BB_SET(SDA );
136 delay(5);
137
138 if ((flags & (I2C_F_STOP | I2C_F_LAST)) == (I2C_F_STOP | I2C_F_LAST))
139 (void) i2c_bitbang_send_stop(v, flags, ops);
140
141 *valp = val;
142 return (0);
143 }
144
145 int
146 i2c_bitbang_write_byte(void *v, uint8_t val, int flags,
147 i2c_bitbang_ops_t ops)
148 {
149 uint32_t bit;
150 uint8_t mask;
151 int error;
152
153 BB_DIR(OUTPUT);
154
155 for (mask = 0x80; mask != 0; mask >>= 1) {
156 bit = (val & mask) ? SDA : 0;
157 BB_SET(bit );
158 delay(1); /* data setup time (250 nS) */
159 BB_SET(bit | SCL);
160 delay(4); /* clock high time (4.0 uS) */
161 BB_SET(bit );
162 delay(5); /* clock low time (4.7 uS) */
163 }
164
165 BB_DIR(INPUT);
166
167 BB_SET(SDA );
168 delay(5);
169 BB_SET(SDA | SCL);
170 delay(4);
171 error = (BB_READ & SDA) ? EIO : 0;
172 BB_SET(SDA );
173 delay(5);
174
175 if (flags & I2C_F_STOP)
176 (void) i2c_bitbang_send_stop(v, flags, ops);
177
178 return (error);
179 }