1
2 // Copyright 2018 The Fuchsia Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #pragma once
7
8 #include <string.h>
9
10 #include <ddk/protocol/i2c.h>
11 #include <lib/sync/completion.h>
12 #include <zircon/assert.h>
13 #include <zircon/compiler.h>
14 #include <zircon/types.h>
15
16 __BEGIN_CDECLS;
17
18 typedef struct {
19 size_t length;
20 bool is_read;
21 bool stop;
22 } __PACKED i2c_rpc_op_t;
23
24 // Writes and reads data on an i2c channel. If both write_length and read_length
25 // are greater than zero, this call will perform a write operation immediately followed
26 // by a read operation with no other traffic occurring on the bus in between.
27 // If read_length is zero, then i2c_write_read will only perform a write operation,
28 // and if write_length is zero, then it will only perform a read operation.
29 // The results of the operation are returned asynchronously via the transact_cb.
30 // The cookie parameter can be used to pass your own private data to the transact_cb callback.
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)31 static inline void i2c_write_read(const i2c_protocol_t* i2c, const void* write_buf,
32 size_t write_length, size_t read_length,
33 i2c_transact_callback transact_cb, void* cookie) {
34 i2c_op_t ops[2];
35 size_t count = 0;
36 if (write_length) {
37 ops[count].data_buffer = (void*)write_buf;
38 ops[count].data_size = (uint32_t)write_length;
39 ops[count].is_read = false;
40 ops[count].stop = !read_length;
41 count++;
42 }
43 if (read_length) {
44 ops[count].data_buffer = NULL;
45 ops[count].data_size = (uint32_t)read_length;
46 ops[count].is_read = true;
47 ops[count].stop = true;
48 count++;
49 }
50 i2c_transact(i2c, ops, count, transact_cb, cookie);
51 }
52
53 typedef struct {
54 sync_completion_t completion;
55 void* read_buf;
56 size_t read_length;
57 zx_status_t result;
58 } i2c_write_read_ctx_t;
59
i2c_write_read_sync_cb(void * cookie,zx_status_t status,const i2c_op_t * ops,size_t cnt)60 static inline void i2c_write_read_sync_cb(void* cookie, zx_status_t status, const i2c_op_t* ops,
61 size_t cnt) {
62 i2c_write_read_ctx_t* ctx = (i2c_write_read_ctx_t*)cookie;
63 ctx->result = status;
64 if (status == ZX_OK && ctx->read_buf && ctx->read_length) {
65 ZX_DEBUG_ASSERT(cnt == 1);
66 memcpy(ctx->read_buf, ops[0].data_buffer, ctx->read_length);
67 }
68
69 sync_completion_signal(&ctx->completion);
70 }
71
i2c_write_read_sync(const i2c_protocol_t * i2c,const void * write_buf,size_t write_length,void * read_buf,size_t read_length)72 static inline zx_status_t i2c_write_read_sync(const i2c_protocol_t* i2c, const void* write_buf,
73 size_t write_length, void* read_buf,
74 size_t read_length) {
75 i2c_write_read_ctx_t ctx;
76 sync_completion_reset(&ctx.completion);
77 ctx.read_buf = read_buf;
78 ctx.read_length = read_length;
79
80 i2c_write_read(i2c, write_buf, write_length, read_length, i2c_write_read_sync_cb, &ctx);
81 zx_status_t status = sync_completion_wait(&ctx.completion, ZX_TIME_INFINITE);
82 if (status == ZX_OK) {
83 return ctx.result;
84 } else {
85 return status;
86 }
87 }
88
i2c_write_sync(const i2c_protocol_t * i2c,const void * write_buf,size_t write_length)89 static inline zx_status_t i2c_write_sync(const i2c_protocol_t* i2c, const void* write_buf,
90 size_t write_length) {
91 return i2c_write_read_sync(i2c, write_buf, write_length, NULL, 0);
92 }
93
i2c_read_sync(const i2c_protocol_t * i2c,void * read_buf,size_t read_length)94 static inline zx_status_t i2c_read_sync(const i2c_protocol_t* i2c, void* read_buf,
95 size_t read_length) {
96 return i2c_write_read_sync(i2c, NULL, 0, read_buf, read_length);
97 }
98
99 __END_CDECLS;
100