blob: 0fd5a9d20eb6220a9390d02ff4c0cb280a0a8c39 [file] [log] [blame]
// 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;