blob: 97f5bb21cc7d3c9c0cdffe64d1ca5c9d62f6d13e [file] [log] [blame]
Damjan Marionb4d89272016-05-12 22:14:45 +02001/*
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
19static inline void
20i2c_delay (i2c_bus_t * b, f64 timeout)
21{
Dave Barach9b8ffd92016-07-08 08:13:45 -040022 vlib_main_t *vm = vlib_get_main ();
Damjan Marionb4d89272016-05-12 22:14:45 +020023 vlib_time_wait (vm, timeout);
24}
25
26static void
27i2c_wait_for_scl (i2c_bus_t * b)
28{
29 f64 t = 0;
30
31 while (t < b->hold_time)
32 {
33 int sda, scl;
Dave Barach9b8ffd92016-07-08 08:13:45 -040034 i2c_delay (b, b->rise_fall_time);
Damjan Marionb4d89272016-05-12 22:14:45 +020035 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
45static void
46i2c_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
62static void
63i2c_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
75static void
76i2c_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
89static void
Dave Barach9b8ffd92016-07-08 08:13:45 -040090i2c_read_bit (i2c_bus_t * b, int *sda)
Damjan Marionb4d89272016-05-12 22:14:45 +020091{
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
104static void
105i2c_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
Dave Barach9b8ffd92016-07-08 08:13:45 -0400119 i2c_read_bit (b, &sda);
Damjan Marionb4d89272016-05-12 22:14:45 +0200120
121 if (sda)
122 b->timeout = 1;
123}
124
125
126static void
127i2c_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
149void
150vlib_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
167void
168vlib_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)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400174 {
175 i2c_start (bus);
176 i2c_write_byte (bus,
177 (msg->addr << 1) + (msg->flags == I2C_MSG_FLAG_READ));
Damjan Marionb4d89272016-05-12 22:14:45 +0200178
Dave Barach9b8ffd92016-07-08 08:13:45 -0400179 if (msg->flags & I2C_MSG_FLAG_READ)
180 for (i = 0; i < msg->len; i++)
181 {
182 i2c_read_byte (bus, &msg->buffer[i], /* ack */ i + 1 != msg->len);
183 if (bus->timeout)
184 goto done;
185 }
Damjan Marionb4d89272016-05-12 22:14:45 +0200186
Dave Barach9b8ffd92016-07-08 08:13:45 -0400187 else
188 for (i = 0; i < msg->len; i++)
189 {
190 i2c_write_byte (bus, msg->buffer[i]);
191 if (bus->timeout)
192 goto done;
193 }
194 }
Damjan Marionb4d89272016-05-12 22:14:45 +0200195
196done:
Dave Barach9b8ffd92016-07-08 08:13:45 -0400197 i2c_stop (bus);
Damjan Marionb4d89272016-05-12 22:14:45 +0200198}
199
200void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400201vlib_i2c_read_eeprom (i2c_bus_t * bus, u8 i2c_addr, u16 start_addr,
202 u16 length, u8 * data)
Damjan Marionb4d89272016-05-12 22:14:45 +0200203{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400204 i2c_msg_t *msg = 0;
Damjan Marionb4d89272016-05-12 22:14:45 +0200205 u8 start_address[1];
206
207 vec_validate (msg, 1);
208
209 start_address[0] = start_addr;
210 msg[0].addr = i2c_addr;
211 msg[0].flags = I2C_MSG_FLAG_WRITE;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400212 msg[0].buffer = (u8 *) & start_address;
Damjan Marionb4d89272016-05-12 22:14:45 +0200213 msg[0].len = 1;
214
215 msg[1].addr = i2c_addr;
216 msg[1].flags = I2C_MSG_FLAG_READ;
217 msg[1].buffer = data;
218 msg[1].len = length;
219
Dave Barach9b8ffd92016-07-08 08:13:45 -0400220 vlib_i2c_xfer (bus, msg);
Damjan Marionb4d89272016-05-12 22:14:45 +0200221
222 vec_free (msg);
223}
224
Dave Barach9b8ffd92016-07-08 08:13:45 -0400225/*
226 * fd.io coding-style-patch-verification: ON
227 *
228 * Local Variables:
229 * eval: (c-set-style "gnu")
230 * End:
231 */