1 /*
2  * Copyright (c) 2023 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/i2c.h>
8 #include <zephyr/drivers/i2c/rtio.h>
9 #include <zephyr/rtio/rtio.h>
10 #include <zephyr/sys/mpsc_lockfree.h>
11 #include <zephyr/sys/__assert.h>
12 
13 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(i2c_rtio);
16 
17 const struct rtio_iodev_api i2c_iodev_api = {
18 	.submit = i2c_iodev_submit,
19 };
20 
i2c_rtio_copy(struct rtio * r,struct rtio_iodev * iodev,const struct i2c_msg * msgs,uint8_t num_msgs)21 struct rtio_sqe *i2c_rtio_copy(struct rtio *r, struct rtio_iodev *iodev, const struct i2c_msg *msgs,
22 			       uint8_t num_msgs)
23 {
24 	__ASSERT(num_msgs > 0, "Expecting at least one message to copy");
25 
26 	struct rtio_sqe *sqe = NULL;
27 
28 	for (uint8_t i = 0; i < num_msgs; i++) {
29 		sqe = rtio_sqe_acquire(r);
30 
31 		if (sqe == NULL) {
32 			rtio_sqe_drop_all(r);
33 			return NULL;
34 		}
35 
36 		if (msgs[i].flags & I2C_MSG_READ) {
37 			rtio_sqe_prep_read(sqe, iodev, RTIO_PRIO_NORM, msgs[i].buf, msgs[i].len,
38 					   NULL);
39 		} else {
40 			rtio_sqe_prep_write(sqe, iodev, RTIO_PRIO_NORM, msgs[i].buf, msgs[i].len,
41 					    NULL);
42 		}
43 		sqe->flags |= RTIO_SQE_TRANSACTION;
44 		sqe->iodev_flags =
45 			((msgs[i].flags & I2C_MSG_STOP) ? RTIO_IODEV_I2C_STOP : 0) |
46 			((msgs[i].flags & I2C_MSG_RESTART) ? RTIO_IODEV_I2C_RESTART : 0) |
47 			((msgs[i].flags & I2C_MSG_ADDR_10_BITS) ? RTIO_IODEV_I2C_10_BITS : 0);
48 	}
49 
50 	sqe->flags &= ~RTIO_SQE_TRANSACTION;
51 
52 	return sqe;
53 }
54 
i2c_rtio_init(struct i2c_rtio * ctx,const struct device * dev)55 void i2c_rtio_init(struct i2c_rtio *ctx, const struct device *dev)
56 {
57 	k_sem_init(&ctx->lock, 1, 1);
58 	mpsc_init(&ctx->io_q);
59 	ctx->txn_curr = NULL;
60 	ctx->txn_head = NULL;
61 	ctx->dt_spec.bus = dev;
62 	ctx->iodev.data = &ctx->dt_spec;
63 	ctx->iodev.api = &i2c_iodev_api;
64 }
65 
66 /**
67  * @private
68  * @brief Setup the next transaction (could be a single op) if needed
69  *
70  * @retval true New transaction to start with the hardware is setup
71  * @retval false No new transaction to start
72  */
i2c_rtio_next(struct i2c_rtio * ctx,bool completion)73 static bool i2c_rtio_next(struct i2c_rtio *ctx, bool completion)
74 {
75 	k_spinlock_key_t key = k_spin_lock(&ctx->slock);
76 
77 	/* Already working on something, bail early */
78 	if (!completion && ctx->txn_head != NULL) {
79 		k_spin_unlock(&ctx->slock, key);
80 		return false;
81 	}
82 
83 	struct mpsc_node *next = mpsc_pop(&ctx->io_q);
84 
85 	/* Nothing left to do */
86 	if (next == NULL) {
87 		ctx->txn_head = NULL;
88 		ctx->txn_curr = NULL;
89 		k_spin_unlock(&ctx->slock, key);
90 		return false;
91 	}
92 
93 	ctx->txn_head = CONTAINER_OF(next, struct rtio_iodev_sqe, q);
94 	ctx->txn_curr = ctx->txn_head;
95 
96 	k_spin_unlock(&ctx->slock, key);
97 
98 	return true;
99 }
100 
i2c_rtio_complete(struct i2c_rtio * ctx,int status)101 bool i2c_rtio_complete(struct i2c_rtio *ctx, int status)
102 {
103 	/* On error bail */
104 	if (status < 0) {
105 		rtio_iodev_sqe_err(ctx->txn_head, status);
106 		return i2c_rtio_next(ctx, true);
107 	}
108 
109 	/* Try for next submission in the transaction */
110 	ctx->txn_curr = rtio_txn_next(ctx->txn_curr);
111 	if (ctx->txn_curr) {
112 		return true;
113 	}
114 
115 	rtio_iodev_sqe_ok(ctx->txn_head, status);
116 	return i2c_rtio_next(ctx, true);
117 }
i2c_rtio_submit(struct i2c_rtio * ctx,struct rtio_iodev_sqe * iodev_sqe)118 bool i2c_rtio_submit(struct i2c_rtio *ctx, struct rtio_iodev_sqe *iodev_sqe)
119 {
120 	mpsc_push(&ctx->io_q, &iodev_sqe->q);
121 	return i2c_rtio_next(ctx, false);
122 }
123 
i2c_rtio_transfer(struct i2c_rtio * ctx,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)124 int i2c_rtio_transfer(struct i2c_rtio *ctx, struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr)
125 {
126 	struct rtio_iodev *iodev = &ctx->iodev;
127 	struct rtio *const r = ctx->r;
128 	struct rtio_sqe *sqe = NULL;
129 	struct rtio_cqe *cqe = NULL;
130 	int res = 0;
131 
132 	k_sem_take(&ctx->lock, K_FOREVER);
133 
134 	ctx->dt_spec.addr = addr;
135 
136 	sqe = i2c_rtio_copy(r, iodev, msgs, num_msgs);
137 	if (sqe == NULL) {
138 		LOG_ERR("Not enough submission queue entries");
139 		res = -ENOMEM;
140 		goto out;
141 	}
142 
143 	rtio_submit(r, 1);
144 
145 	cqe = rtio_cqe_consume(r);
146 	while (cqe != NULL) {
147 		res = cqe->result;
148 		rtio_cqe_release(r, cqe);
149 		cqe = rtio_cqe_consume(r);
150 	}
151 
152 out:
153 	k_sem_give(&ctx->lock);
154 	return res;
155 }
156 
i2c_rtio_configure(struct i2c_rtio * ctx,uint32_t i2c_config)157 int i2c_rtio_configure(struct i2c_rtio *ctx, uint32_t i2c_config)
158 {
159 	struct rtio_iodev *iodev = &ctx->iodev;
160 	struct rtio *const r = ctx->r;
161 	struct rtio_sqe *sqe = NULL;
162 	struct rtio_cqe *cqe = NULL;
163 	int res = 0;
164 
165 	k_sem_take(&ctx->lock, K_FOREVER);
166 
167 	sqe = rtio_sqe_acquire(r);
168 	if (sqe == NULL) {
169 		LOG_ERR("Not enough submission queue entries");
170 		res = -ENOMEM;
171 		goto out;
172 	}
173 
174 	sqe->op = RTIO_OP_I2C_CONFIGURE;
175 	sqe->iodev = iodev;
176 	sqe->i2c_config = i2c_config;
177 
178 	rtio_submit(r, 1);
179 
180 	cqe = rtio_cqe_consume(r);
181 	res = cqe->result;
182 	rtio_cqe_release(r, cqe);
183 
184 out:
185 	k_sem_give(&ctx->lock);
186 	return res;
187 }
188 
i2c_rtio_recover(struct i2c_rtio * ctx)189 int i2c_rtio_recover(struct i2c_rtio *ctx)
190 {
191 	struct rtio_iodev *iodev = &ctx->iodev;
192 	struct rtio *const r = ctx->r;
193 	struct rtio_sqe *sqe = NULL;
194 	struct rtio_cqe *cqe = NULL;
195 	int res = 0;
196 
197 	k_sem_take(&ctx->lock, K_FOREVER);
198 
199 	sqe = rtio_sqe_acquire(r);
200 	if (sqe == NULL) {
201 		LOG_ERR("Not enough submission queue entries");
202 		res = -ENOMEM;
203 		goto out;
204 	}
205 
206 	sqe->op = RTIO_OP_I2C_RECOVER;
207 	sqe->iodev = iodev;
208 
209 	rtio_submit(r, 1);
210 
211 	cqe = rtio_cqe_consume(r);
212 	res = cqe->result;
213 	rtio_cqe_release(r, cqe);
214 
215 out:
216 	k_sem_give(&ctx->lock);
217 	return res;
218 }
219