Root/qiboot/src/drivers/i2c-bitbang.c

1/*
2 * (C) Copyright 2007 OpenMoko, Inc.
3 * Author: Andy Green <andy@openmoko.com>
4 *
5 * Generic i2c bitbang state machine
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 *
22 */
23
24#include <qi.h>
25#include <i2c-bitbang.h>
26
27void i2c_read(struct i2c_bitbang * bb, unsigned char ads7, unsigned char reg)
28{
29    bb->data[0] = (ads7 << 1); /* write the register address */
30    bb->data[1] = reg;
31    bb->data[2] = IBCONTROL_DO_START;
32    bb->data[3] = (ads7 << 1) | 1; /* then issue read cycle to device */
33    bb->data[4] = IBCONTROL_DO_READ;
34    bb->data[5] = IBCONTROL_DO_STOP;
35    bb->data[6] = IBCONTROL_COMPLETE;
36    bb->state = IBS_INIT;
37}
38
39void i2c_write(struct i2c_bitbang * bb, unsigned char ads7, unsigned char reg,
40                                unsigned char b)
41{
42    bb->data[0] = (ads7 << 1);
43    bb->data[1] = reg;
44    bb->data[2] = b;
45    bb->data[3] = IBCONTROL_DO_STOP;
46    bb->data[4] = IBCONTROL_COMPLETE;
47    bb->state = IBS_INIT;
48}
49
50int i2c_next_state(struct i2c_bitbang * bb)
51{
52    switch (bb->state) {
53    case IBS_INIT:
54        bb->index = 0;
55        bb->index_read = 0;
56        (bb->set)(1, 1);
57        bb->state = IBS_START1;
58        break;
59
60    case IBS_START1:
61        (bb->set)(1, 0);
62        bb->state = IBS_START2;
63        break;
64
65    case IBS_START2:
66        (bb->set)(0, 0); /* start */
67        bb->count = 8;
68        bb->state = IBS_ADS_TX_S;
69        break;
70
71    /* transmit address or data */
72    case IBS_ADS_TX_S:
73        (bb->set)(0, !!(bb->data[bb->index] & 0x80));
74        bb->state = IBS_ADS_TX_H;
75        break;
76    case IBS_ADS_TX_H:
77        (bb->set)(1, !!(bb->data[bb->index] & 0x80));
78        bb->state = IBS_ADS_TX_L;
79        break;
80    case IBS_ADS_TX_L:
81        (bb->set)(0, !!(bb->data[bb->index] & 0x80));
82        bb->data[bb->index] <<= 1;
83        bb->count--;
84        if (bb->count) {
85            bb->state = IBS_ADS_TX_S;
86            break;
87        }
88
89        (bb->set)(0, 1);
90        bb->state = IBS_ADS_TX_ACK_H;
91        break;
92
93    case IBS_ADS_TX_ACK_H:
94        /* we finished... we expect an ack now */
95        if ((bb->read_sda)())
96            return -1;
97
98        (bb->set)(1, 1);
99        bb->state = IBS_ADS_TX_ACK_L;
100        break;
101
102    case IBS_ADS_TX_ACK_L:
103        (bb->set)(0, 1);
104
105        bb->count = 8;
106        bb->index++;
107        switch (bb->data[bb->index]) {
108        case IBCONTROL_DO_START:
109            bb->state = IBS_START1;
110            bb->index++;
111            break;
112        case IBCONTROL_DO_STOP:
113            bb->state = IBS_STOP1;
114            bb->index++;
115            break;
116        case IBCONTROL_DO_READ:
117            bb->data[bb->index_read] = 0;
118            bb->state = IBS_DATA_RX_S;
119            break;
120        case IBCONTROL_COMPLETE:
121            return 1;
122        default:
123            bb->state = IBS_ADS_TX_S; /* write it out */
124            break;
125        }
126        break;
127
128
129    /* receive data */
130    case IBS_DATA_RX_S:
131        (bb->set)(0, 1);
132        bb->state = IBS_DATA_RX_H;
133        break;
134
135    case IBS_DATA_RX_H:
136        (bb->set)(1, 1);
137        bb->state = IBS_DATA_RX_L;
138        break;
139
140    case IBS_DATA_RX_L:
141        bb->data[bb->index_read] <<= 1;
142        bb->data[bb->index_read] |= !!(bb->read_sda)();
143        bb->count--;
144        if (bb->count) {
145            (bb->set)(0, 1);
146            bb->state = IBS_DATA_RX_S;
147            break;
148        }
149
150        /* slave has released SDA now, bang down ACK */
151        if (bb->data[bb->index + 1] != IBCONTROL_DO_READ)
152            (bb->set)(0, 1);
153        else
154            (bb->set)(0, 0);
155        bb->state = IBS_DATA_RX_ACK_H;
156        break;
157
158    case IBS_DATA_RX_ACK_H:
159        if (bb->data[bb->index + 1] != IBCONTROL_DO_READ)
160            (bb->set)(1, 1); /* NAK */
161        else
162            (bb->set)(1, 0); /* ACK */
163        bb->state = IBS_DATA_RX_ACK_L;
164        break;
165
166    case IBS_DATA_RX_ACK_L:
167        if (bb->data[bb->index + 1] != IBCONTROL_DO_READ)
168            (bb->set)(0, 1); /* NAK */
169        else
170            (bb->set)(0, 0); /* ACK */
171        bb->index_read++;
172        bb->index++;
173        switch (bb->data[bb->index]) {
174        case IBCONTROL_DO_START:
175            bb->state = IBS_START1;
176            bb->index++;
177            break;
178        case IBCONTROL_DO_STOP:
179            bb->state = IBS_STOP1;
180            bb->index++;
181            break;
182        case IBCONTROL_DO_READ:
183            bb->state = IBS_DATA_RX_S;
184            bb->data[bb->index_read] = 0;
185            break;
186        case IBCONTROL_COMPLETE:
187            return 1;
188        default:
189            bb->state = IBS_ADS_TX_S; /* write it out */
190            break;
191        }
192        break;
193
194        break;
195
196
197    case IBS_STOP1:
198        (bb->set)(0, 0);
199        bb->state = IBS_STOP2;
200        break;
201
202    case IBS_STOP2:
203        (bb->set)(1, 0);
204        bb->state = IBS_STOP3;
205        break;
206
207    case IBS_STOP3:
208        (bb->set)(1, 1);
209        bb->state = IBS_STOP4;
210        break;
211
212    case IBS_STOP4:
213        (bb->set)(1, 1);
214        return 1; /* done */
215    }
216
217    return 0; /* keep going */
218}
219
220static int i2c_complete_synchronously(struct i2c_bitbang * bb)
221{
222    int ret = 0;
223
224    while (!ret) {
225        ret = i2c_next_state(bb);
226        (bb->spin)();
227    }
228
229    if (ret < 0) {
230        puts("i2c transaction failed ");
231        printdec(ret);
232        puts("\n");
233    }
234    return ret;
235}
236
237int i2c_read_sync(struct i2c_bitbang * bb, unsigned char ads7,
238                                  unsigned char reg)
239{
240    i2c_read(bb, ads7, reg);
241    if (i2c_complete_synchronously(bb) < 0)
242        return -1;
243
244    return bb->data[0];
245}
246
247void i2c_write_sync(struct i2c_bitbang * bb, unsigned char ads7,
248                         unsigned char reg, unsigned char b)
249{
250    i2c_write(bb, ads7, reg, b);
251    i2c_complete_synchronously(bb);
252}
253

Archive Download this file



interactive