diff options
Diffstat (limited to 'vlib')
-rw-r--r-- | vlib/Makefile.am | 2 | ||||
-rw-r--r-- | vlib/vlib/i2c.c | 222 | ||||
-rw-r--r-- | vlib/vlib/i2c.h | 57 | ||||
-rw-r--r-- | vlib/vlib/physmem.h | 3 | ||||
-rw-r--r-- | vlib/vlib/unix/physmem.c | 1 | ||||
-rw-r--r-- | vlib/vlib/unix/unix.h | 7 |
6 files changed, 292 insertions, 0 deletions
diff --git a/vlib/Makefile.am b/vlib/Makefile.am index 981c2bef..27475671 100644 --- a/vlib/Makefile.am +++ b/vlib/Makefile.am @@ -31,6 +31,7 @@ libvlib_la_SOURCES = \ vlib/counter.c \ vlib/error.c \ vlib/format.c \ + vlib/i2c.c \ vlib/init.c \ vlib/main.c \ vlib/mc.c \ @@ -61,6 +62,7 @@ nobase_include_HEADERS = \ vlib/error.h \ vlib/format_funcs.h \ vlib/global_funcs.h \ + vlib/i2c.h \ vlib/init.h \ vlib/main.h \ vlib/mc.h \ diff --git a/vlib/vlib/i2c.c b/vlib/vlib/i2c.c new file mode 100644 index 00000000..83a702ed --- /dev/null +++ b/vlib/vlib/i2c.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vlib/vlib.h> +#include <vlib/i2c.h> + +static inline void +i2c_delay (i2c_bus_t * b, f64 timeout) +{ + vlib_main_t * vm = vlib_get_main(); + vlib_time_wait (vm, timeout); +} + +static void +i2c_wait_for_scl (i2c_bus_t * b) +{ + f64 t = 0; + + while (t < b->hold_time) + { + int sda, scl; + i2c_delay(b, b->rise_fall_time); + b->get_bits (b, &scl, &sda); + + if (scl) + return; + + t += b->rise_fall_time; + } + b->timeout = 1; +} + +static void +i2c_start (i2c_bus_t * b) +{ + b->timeout = 0; + + b->put_bits (b, 1, 1); + i2c_wait_for_scl (b); + + if (vlib_i2c_bus_timed_out (b)) + return; + + b->put_bits (b, 1, 0); + i2c_delay (b, b->hold_time); + b->put_bits (b, 0, 0); + i2c_delay (b, b->hold_time); +} + +static void +i2c_stop (i2c_bus_t * b) +{ + b->put_bits (b, 0, 0); + i2c_delay (b, b->rise_fall_time); + + b->put_bits (b, 1, 0); + i2c_delay (b, b->hold_time); + + b->put_bits (b, 1, 1); + i2c_delay (b, b->hold_time); +} + +static void +i2c_write_bit (i2c_bus_t * b, int sda) +{ + b->put_bits (b, 0, sda); + i2c_delay (b, b->rise_fall_time); + + b->put_bits (b, 1, sda); + i2c_wait_for_scl (b); + i2c_delay (b, b->hold_time); + + b->put_bits (b, 0, sda); + i2c_delay (b, b->rise_fall_time); +} + +static void +i2c_read_bit (i2c_bus_t * b, int * sda) +{ + int scl; + + b->put_bits (b, 1, 1); + i2c_wait_for_scl (b); + i2c_delay (b, b->hold_time); + + b->get_bits (b, &scl, sda); + + b->put_bits (b, 0, 1); + i2c_delay (b, b->rise_fall_time); +} + +static void +i2c_write_byte (i2c_bus_t * b, u8 data) +{ + int i, sda; + + for (i = 7; i >= 0; i--) + { + i2c_write_bit (b, (data >> i) & 1); + if (b->timeout) + return; + } + + b->put_bits (b, 0, 1); + i2c_delay (b, b->rise_fall_time); + + i2c_read_bit(b, &sda); + + if (sda) + b->timeout = 1; +} + + +static void +i2c_read_byte (i2c_bus_t * b, u8 * data, int ack) +{ + int i, sda; + + *data = 0; + + b->put_bits (b, 0, 1); + i2c_delay (b, b->rise_fall_time); + + for (i = 7; i >= 0; i--) + { + i2c_read_bit (b, &sda); + if (b->timeout) + return; + + *data |= (sda != 0) << i; + } + + i2c_write_bit (b, ack == 0); +} + + +void +vlib_i2c_init (i2c_bus_t * b) +{ + f64 tick; + if (!b->clock) + b->clock = 400000; + + tick = 1.0 / b->clock; + + /* Spend 40% of time in low and high states */ + if (!b->hold_time) + b->hold_time = 0.4 * tick; + + /* Spend 10% of time waiting for rise and fall */ + if (!b->rise_fall_time) + b->rise_fall_time = 0.1 * tick; +} + +void +vlib_i2c_xfer (i2c_bus_t * bus, i2c_msg_t * msgs) +{ + i2c_msg_t *msg; + int i; + + vec_foreach (msg, msgs) + { + i2c_start (bus); + i2c_write_byte (bus, (msg->addr << 1) + (msg->flags == I2C_MSG_FLAG_READ)); + + if (msg->flags & I2C_MSG_FLAG_READ) + for (i=0; i< msg->len; i++) + { + i2c_read_byte (bus, &msg->buffer[i], /* ack */ i + 1 != msg->len); + if (bus->timeout) + goto done; + } + + else + for (i=0; i< msg->len; i++) + { + i2c_write_byte (bus, msg->buffer[i]); + if (bus->timeout) + goto done; + } + } + +done: + i2c_stop(bus); +} + +void +vlib_i2c_read_eeprom (i2c_bus_t * bus, u8 i2c_addr, u16 start_addr, u16 length, u8 * data) +{ + i2c_msg_t * msg = 0; + u8 start_address[1]; + + vec_validate (msg, 1); + + start_address[0] = start_addr; + msg[0].addr = i2c_addr; + msg[0].flags = I2C_MSG_FLAG_WRITE; + msg[0].buffer = (u8 *) &start_address; + msg[0].len = 1; + + msg[1].addr = i2c_addr; + msg[1].flags = I2C_MSG_FLAG_READ; + msg[1].buffer = data; + msg[1].len = length; + + vlib_i2c_xfer(bus, msg); + + vec_free (msg); +} + diff --git a/vlib/vlib/i2c.h b/vlib/vlib/i2c.h new file mode 100644 index 00000000..451957d8 --- /dev/null +++ b/vlib/vlib/i2c.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef included_vlib_i2c_h +#define included_vlib_i2c_h + +#include <vppinfra/types.h> + + +#define I2C_MSG_FLAG_WRITE 0 +#define I2C_MSG_FLAG_READ 1 + +typedef struct { + u8 addr; + u8 flags; + u16 len; + u8 * buffer; +} i2c_msg_t; + +typedef struct i2c_bus_t { + void (* put_bits) (struct i2c_bus_t * b, int scl, int sda); + void (* get_bits) (struct i2c_bus_t * b, int *scl, int *sda); + + int timeout; + u32 clock; + f64 hold_time; + f64 rise_fall_time; + + /* Private data */ + uword private_data; + +} i2c_bus_t; + +void vlib_i2c_init (i2c_bus_t * bus); +void vlib_i2c_xfer (i2c_bus_t * bus, i2c_msg_t * msgs); +void vlib_i2c_read_eeprom (i2c_bus_t * bus, u8 i2c_addr, u16 start_addr, u16 length, u8 * data); + +static inline int +vlib_i2c_bus_timed_out(i2c_bus_t * bus) +{ + return bus->timeout; +} + +#endif /* included_vlib_i2c_h */ + diff --git a/vlib/vlib/physmem.h b/vlib/vlib/physmem.h index 6e70291c..6f75a0f3 100644 --- a/vlib/vlib/physmem.h +++ b/vlib/vlib/physmem.h @@ -53,6 +53,9 @@ typedef struct { uword page_mask; u64 * page_table; + + /* is fake physmem */ + u8 is_fake; } vlib_physmem_main_t; always_inline u64 diff --git a/vlib/vlib/unix/physmem.c b/vlib/vlib/unix/physmem.c index 67c22339..d3155e0c 100644 --- a/vlib/vlib/unix/physmem.c +++ b/vlib/vlib/unix/physmem.c @@ -245,6 +245,7 @@ clib_error_t * unix_physmem_init (vlib_main_t * vm, int physical_memory_required vpm->virtual.start = pointer_to_uword (pm->mem); vpm->virtual.size = pm->mem_size; vpm->virtual.end = vpm->virtual.start + vpm->virtual.size; + vpm->is_fake = 1; fformat(stderr, "%s: use fake dma pages\n", __FUNCTION__); diff --git a/vlib/vlib/unix/unix.h b/vlib/vlib/unix/unix.h index 75d5df04..6c1f985a 100644 --- a/vlib/vlib/unix/unix.h +++ b/vlib/vlib/unix/unix.h @@ -180,6 +180,13 @@ int vlib_unix_main (int argc, char * argv[]); clib_error_t * unix_physmem_init (vlib_main_t * vm, int fail_if_physical_memory_not_present); +static inline int +unix_physmem_is_fake (vlib_main_t * vm) +{ + vlib_physmem_main_t * vpm = &vm->physmem_main; + return vpm->is_fake; +} + /* Set prompt for CLI. */ void vlib_unix_cli_set_prompt (char * prompt); |