1 /*
2 * I2C master emulation using GPIO pins.
3 * 7 bit addressing only.
4 */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "../port/error.h"
11 #include "io.h"
12 #include "i2c.h"
13
14 /* GPIO bitmasks */
15 static struct {
16 Lock;
17 ulong sda;
18 ulong scl;
19 } i2c;
20
21
22 /* set pin level high by disabling output drive and allowing pull-up to work */
23 static void
i2c_set(int pin)24 i2c_set(int pin)
25 {
26 GPIOREG->gpdr &= ~pin; /* configure pin as input */
27 }
28
29 /* set pin level low with output drive */
30 static void
i2c_clear(int pin)31 i2c_clear(int pin)
32 {
33 GPIOREG->gpcr = pin; /* set pin output low */
34 GPIOREG->gpdr |= pin; /* configure pin as output */
35 }
36
37 static int
i2c_getack(void)38 i2c_getack(void)
39 {
40 /* scl is low, sda is not defined */
41
42 i2c_set(i2c.sda); /* set data high */
43 timer_delay(US2TMR(3));
44
45 i2c_set(i2c.scl); /* raise clock */
46 timer_delay(US2TMR(5));
47
48 /* check for ack from slave! */
49 if (GPIOREG->gplr & i2c.sda)
50 print("I2C: Warning did not get ack!\n");
51
52 i2c_clear(i2c.sda); /* lower data */
53 i2c_clear(i2c.scl); /* lower clock */
54 timer_delay(US2TMR(3));
55
56 /* scl is low, sda is low */
57 return 1;
58 }
59
60
61 static void
i2c_putack(void)62 i2c_putack(void)
63 {
64 /* scl is low, sda is not defined */
65
66 timer_delay(US2TMR(3)); /* lower data */
67 i2c_clear(i2c.sda);
68
69 i2c_set(i2c.scl); /* pulse clock */
70 timer_delay(US2TMR(5));
71
72 i2c_clear(i2c.scl); /* lower clock */
73 timer_delay(US2TMR(3));
74
75 /* scl is low, sda is low */
76 }
77
78
79 static void
i2c_putbyte(uchar b)80 i2c_putbyte(uchar b)
81 {
82 uchar m;
83
84 /* start condition has been sent */
85 /* scl is low, sda is low */
86
87 for(m=0x80; m; m >>= 1) {
88
89 /* set data bit */
90 if(b&m)
91 i2c_set(i2c.sda);
92 else
93 i2c_clear(i2c.sda);
94
95 /* pulse clock */
96 timer_delay(US2TMR(3));
97 i2c_set(i2c.scl);
98 timer_delay(US2TMR(5));
99 i2c_clear(i2c.scl);
100 timer_delay(US2TMR(3));
101 }
102
103 i2c_clear(i2c.sda);
104 /* scl is low, sda is low */
105 }
106
107
108 static uchar
i2c_getbyte(void)109 i2c_getbyte(void)
110 {
111 /* start condition, address and ack been done */
112 /* scl is low, sda is high */
113 uchar data = 0x00;
114 int i;
115
116 i2c_set(i2c.sda);
117 for (i=7; i >= 0; i--) {
118
119 timer_delay(US2TMR(3));
120
121 /* raise clock */
122 i2c_set(i2c.scl);
123 timer_delay(US2TMR(5));
124
125 /* sample data */
126 if(GPIOREG->gplr & i2c.sda)
127 data |= 1<<i;
128
129 /* lower clock */
130 i2c_clear(i2c.scl);
131 timer_delay(US2TMR(3));
132 }
133
134 i2c_clear(i2c.sda);
135 return data;
136 }
137
138 /* generate I2C start condition */
139 static int
i2c_start(void)140 i2c_start(void)
141 {
142 /* check that both scl and sda are high */
143 if ((GPIOREG->gplr & (i2c.sda | i2c.scl)) != (i2c.sda | i2c.scl))
144 print("I2C: Bus not clear when attempting start condition\n");
145
146 i2c_clear(i2c.sda); /* lower sda */
147 timer_delay(US2TMR(5));
148
149 i2c_clear(i2c.scl); /* lower scl */
150 timer_delay(US2TMR(3));
151
152 return 1;
153 }
154
155 /* generate I2C stop condition */
156 static int
i2c_stop(void)157 i2c_stop(void)
158 {
159 /* clock is low, data is low */
160 timer_delay(US2TMR(3));
161
162 i2c_set(i2c.scl);
163 timer_delay(US2TMR(5));
164
165 i2c_set(i2c.sda);
166
167 timer_delay(MS2TMR(1)); /* ensure separation between commands */
168
169 return 1;
170 }
171
172 /*
173 * external I2C interface
174 */
175
176 /* write a byte over the i2c bus */
177 int
i2c_write_byte(uchar addr,uchar data)178 i2c_write_byte(uchar addr, uchar data)
179 {
180 int rc = 0;
181
182 ilock(&i2c);
183 if(i2c_start() < 0) /* start condition */
184 rc = -1;
185
186 i2c_putbyte(addr & 0xfe); /* address byte (LSB = 0 -> write) */
187
188 if (i2c_getack() < 0) /* get ack */
189 rc = -2;
190
191 i2c_putbyte(data); /* data byte */
192
193 if (i2c_getack() < 0) /* get ack */
194 rc = -3;
195
196 if (i2c_stop() < 0)
197 rc = -4; /* stop condition */
198 iunlock(&i2c);
199
200 return rc;
201 }
202
203 /* read a byte over the i2c bus */
204 int
i2c_read_byte(uchar addr,uchar * data)205 i2c_read_byte(uchar addr, uchar *data)
206 {
207 int rc = 0;
208
209 ilock(&i2c);
210 if(i2c_start() < 0) /* start condition */
211 rc = -1;
212
213 i2c_putbyte(addr | 0x01); /* address byte (LSB = 1 -> read) */
214
215 if(i2c_getack() < 0) /* get ack */
216 rc = -2;
217
218 *data = i2c_getbyte(); /* data byte */
219
220 i2c_putack(); /* put ack */
221
222 if (i2c_stop() < 0) /* stop condition */
223 rc = -4;
224 iunlock(&i2c);
225
226 return rc;
227 }
228
229 void
i2c_reset(void)230 i2c_reset(void)
231 {
232 /* initialise bitmasks */
233 i2c.sda = (1 << gpio_i2c_sda);
234 i2c.scl = (1 << gpio_i2c_scl);
235
236 /* ensure that both clock and data are high */
237 i2c_set(i2c.sda);
238 i2c_set(i2c.scl);
239 timer_delay(MS2TMR(5));
240 }
241
242
243 /*
244 * external pin set/clear interface
245 */
246 uchar i2c_iactl[2] = { 0xff, 0xff }; /* defaults overridden in arch?????.c */
247
248 int
i2c_setpin(int b)249 i2c_setpin(int b)
250 {
251 int i = b>>3;
252
253 ilock(&i2c);
254 i2c_iactl[i] |= (1 << (b&7));
255 iunlock(&i2c);
256 return i2c_write_byte(0x40 | (i << 1), i2c_iactl[i]);
257 }
258
259 int
i2c_clrpin(int b)260 i2c_clrpin(int b)
261 {
262 int i = b>>3;
263
264 ilock(&i2c);
265 i2c_iactl[i] &= ~(1 << (b&7));
266 iunlock(&i2c);
267 return i2c_write_byte(0x40 | (i << 1), i2c_iactl[i]);
268 }
269
270 int
i2c_getpin(int b)271 i2c_getpin(int b)
272 {
273 return (i2c_iactl[(b>>3)&1] & (1<<(b&7))) != 0;
274 }
275