| |
| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <string.h> |
| |
| #include <ddk/protocol/i2c.h> |
| #include <lib/sync/completion.h> |
| #include <zircon/assert.h> |
| #include <zircon/compiler.h> |
| #include <zircon/types.h> |
| |
| __BEGIN_CDECLS; |
| |
| typedef struct { |
| size_t length; |
| bool is_read; |
| bool stop; |
| } __PACKED i2c_rpc_op_t; |
| |
| // Writes and reads data on an i2c channel. If both write_length and read_length |
| // are greater than zero, this call will perform a write operation immediately followed |
| // by a read operation with no other traffic occurring on the bus in between. |
| // If read_length is zero, then i2c_write_read will only perform a write operation, |
| // and if write_length is zero, then it will only perform a read operation. |
| // The results of the operation are returned asynchronously via the transact_cb. |
| // The cookie parameter can be used to pass your own private data to the transact_cb callback. |
| static inline void i2c_write_read(const i2c_protocol_t* i2c, const void* write_buf, |
| size_t write_length, size_t read_length, |
| i2c_transact_callback transact_cb, void* cookie) { |
| i2c_op_t ops[2]; |
| size_t count = 0; |
| if (write_length) { |
| ops[count].data_buffer = (void*)write_buf; |
| ops[count].data_size = (uint32_t)write_length; |
| ops[count].is_read = false; |
| ops[count].stop = !read_length; |
| count++; |
| } |
| if (read_length) { |
| ops[count].data_buffer = NULL; |
| ops[count].data_size = (uint32_t)read_length; |
| ops[count].is_read = true; |
| ops[count].stop = true; |
| count++; |
| } |
| i2c_transact(i2c, ops, count, transact_cb, cookie); |
| } |
| |
| typedef struct { |
| sync_completion_t completion; |
| void* read_buf; |
| size_t read_length; |
| zx_status_t result; |
| } i2c_write_read_ctx_t; |
| |
| static inline void i2c_write_read_sync_cb(void* cookie, zx_status_t status, const i2c_op_t* ops, |
| size_t cnt) { |
| i2c_write_read_ctx_t* ctx = (i2c_write_read_ctx_t*)cookie; |
| ctx->result = status; |
| if (status == ZX_OK && ctx->read_buf && ctx->read_length) { |
| ZX_DEBUG_ASSERT(cnt == 1); |
| memcpy(ctx->read_buf, ops[0].data_buffer, ctx->read_length); |
| } |
| |
| sync_completion_signal(&ctx->completion); |
| } |
| |
| static inline zx_status_t i2c_write_read_sync(const i2c_protocol_t* i2c, const void* write_buf, |
| size_t write_length, void* read_buf, |
| size_t read_length) { |
| i2c_write_read_ctx_t ctx; |
| sync_completion_reset(&ctx.completion); |
| ctx.read_buf = read_buf; |
| ctx.read_length = read_length; |
| |
| i2c_write_read(i2c, write_buf, write_length, read_length, i2c_write_read_sync_cb, &ctx); |
| zx_status_t status = sync_completion_wait(&ctx.completion, ZX_TIME_INFINITE); |
| if (status == ZX_OK) { |
| return ctx.result; |
| } else { |
| return status; |
| } |
| } |
| |
| static inline zx_status_t i2c_write_sync(const i2c_protocol_t* i2c, const void* write_buf, |
| size_t write_length) { |
| return i2c_write_read_sync(i2c, write_buf, write_length, NULL, 0); |
| } |
| |
| static inline zx_status_t i2c_read_sync(const i2c_protocol_t* i2c, void* read_buf, |
| size_t read_length) { |
| return i2c_write_read_sync(i2c, NULL, 0, read_buf, read_length); |
| } |
| |
| __END_CDECLS; |