83a702edbd677194985bb84a54fea05aaa735b5c
[vpp.git] / vlib / vlib / i2c.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vlib/vlib.h>
17 #include <vlib/i2c.h>
18
19 static inline void
20 i2c_delay (i2c_bus_t * b, f64 timeout)
21 {
22   vlib_main_t * vm = vlib_get_main();
23   vlib_time_wait (vm, timeout);
24 }
25
26 static void
27 i2c_wait_for_scl (i2c_bus_t * b)
28 {
29   f64 t = 0;
30
31   while (t < b->hold_time)
32     {
33       int sda, scl;
34       i2c_delay(b, b->rise_fall_time);
35       b->get_bits (b, &scl, &sda);
36
37       if (scl)
38         return;
39
40       t += b->rise_fall_time;
41     }
42   b->timeout = 1;
43 }
44
45 static void
46 i2c_start (i2c_bus_t * b)
47 {
48   b->timeout = 0;
49
50   b->put_bits (b, 1, 1);
51   i2c_wait_for_scl (b);
52
53   if (vlib_i2c_bus_timed_out (b))
54     return;
55
56   b->put_bits (b, 1, 0);
57   i2c_delay (b, b->hold_time);
58   b->put_bits (b, 0, 0);
59   i2c_delay (b, b->hold_time);
60 }
61
62 static void
63 i2c_stop (i2c_bus_t * b)
64 {
65   b->put_bits (b, 0, 0);
66   i2c_delay (b, b->rise_fall_time);
67
68   b->put_bits (b, 1, 0);
69   i2c_delay (b, b->hold_time);
70
71   b->put_bits (b, 1, 1);
72   i2c_delay (b, b->hold_time);
73 }
74
75 static void
76 i2c_write_bit (i2c_bus_t * b, int sda)
77 {
78   b->put_bits (b, 0, sda);
79   i2c_delay (b, b->rise_fall_time);
80
81   b->put_bits (b, 1, sda);
82   i2c_wait_for_scl (b);
83   i2c_delay (b, b->hold_time);
84
85   b->put_bits (b, 0, sda);
86   i2c_delay (b, b->rise_fall_time);
87 }
88
89 static void
90 i2c_read_bit (i2c_bus_t * b, int * sda)
91 {
92   int scl;
93
94   b->put_bits (b, 1, 1);
95   i2c_wait_for_scl (b);
96   i2c_delay (b, b->hold_time);
97
98   b->get_bits (b, &scl, sda);
99
100   b->put_bits (b, 0, 1);
101   i2c_delay (b, b->rise_fall_time);
102 }
103
104 static void
105 i2c_write_byte (i2c_bus_t * b, u8 data)
106 {
107   int i, sda;
108
109   for (i = 7; i >= 0; i--)
110     {
111       i2c_write_bit (b, (data >> i) & 1);
112       if (b->timeout)
113         return;
114     }
115
116   b->put_bits (b, 0, 1);
117   i2c_delay (b, b->rise_fall_time);
118
119   i2c_read_bit(b, &sda);
120
121   if (sda)
122     b->timeout = 1;
123 }
124
125
126 static void
127 i2c_read_byte (i2c_bus_t * b, u8 * data, int ack)
128 {
129   int i, sda;
130
131   *data = 0;
132
133   b->put_bits (b, 0, 1);
134   i2c_delay (b, b->rise_fall_time);
135
136   for (i = 7; i >= 0; i--)
137     {
138       i2c_read_bit (b, &sda);
139       if (b->timeout)
140         return;
141
142       *data |= (sda != 0) << i;
143     }
144
145   i2c_write_bit (b, ack == 0);
146 }
147
148
149 void
150 vlib_i2c_init (i2c_bus_t * b)
151 {
152   f64 tick;
153   if (!b->clock)
154     b->clock = 400000;
155
156   tick = 1.0 / b->clock;
157
158   /* Spend 40% of time in low and high states */
159   if (!b->hold_time)
160     b->hold_time = 0.4 * tick;
161
162   /* Spend 10% of time waiting for rise and fall */
163   if (!b->rise_fall_time)
164     b->rise_fall_time = 0.1 * tick;
165 }
166
167 void
168 vlib_i2c_xfer (i2c_bus_t * bus, i2c_msg_t * msgs)
169 {
170   i2c_msg_t *msg;
171   int i;
172
173   vec_foreach (msg, msgs)
174     {
175       i2c_start (bus);
176       i2c_write_byte (bus, (msg->addr << 1) + (msg->flags == I2C_MSG_FLAG_READ));
177
178       if (msg->flags & I2C_MSG_FLAG_READ)
179         for (i=0; i< msg->len; i++)
180           {
181             i2c_read_byte (bus, &msg->buffer[i], /* ack */ i + 1 != msg->len);
182             if (bus->timeout)
183               goto done;
184           }
185
186       else
187         for (i=0; i< msg->len; i++)
188           {
189             i2c_write_byte (bus, msg->buffer[i]);
190             if (bus->timeout)
191               goto done;
192           }
193     }
194
195 done:
196   i2c_stop(bus);
197 }
198
199 void
200 vlib_i2c_read_eeprom (i2c_bus_t * bus, u8 i2c_addr, u16 start_addr, u16 length, u8 * data)
201 {
202   i2c_msg_t * msg = 0;
203   u8 start_address[1];
204
205   vec_validate (msg, 1);
206
207   start_address[0] = start_addr;
208   msg[0].addr = i2c_addr;
209   msg[0].flags = I2C_MSG_FLAG_WRITE;
210   msg[0].buffer = (u8 *) &start_address;
211   msg[0].len = 1;
212
213   msg[1].addr = i2c_addr;
214   msg[1].flags = I2C_MSG_FLAG_READ;
215   msg[1].buffer = data;
216   msg[1].len = length;
217
218   vlib_i2c_xfer(bus, msg);
219
220   vec_free (msg);
221 }
222