1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7 #include <mod_i2c.h>
8
9 #include <fwk_assert.h>
10 #include <fwk_core.h>
11 #include <fwk_event.h>
12 #include <fwk_id.h>
13 #include <fwk_mm.h>
14 #include <fwk_module.h>
15 #include <fwk_module_idx.h>
16 #include <fwk_status.h>
17
18 #include <stdbool.h>
19 #include <string.h>
20
21 enum mod_i2c_dev_state {
22 MOD_I2C_DEV_IDLE,
23 MOD_I2C_DEV_TX,
24 MOD_I2C_DEV_RX,
25 MOD_I2C_DEV_TX_RX,
26 MOD_I2C_DEV_RELOAD,
27 MOD_I2C_DEV_PANIC,
28 };
29
30 struct mod_i2c_dev_ctx {
31 const struct mod_i2c_dev_config *config;
32 const struct mod_i2c_driver_api *driver_api;
33 struct mod_i2c_request request;
34 enum mod_i2c_dev_state state;
35 };
36
37 static struct mod_i2c_dev_ctx *ctx_table;
38
39 enum mod_i2c_internal_event_idx {
40 MOD_I2C_EVENT_IDX_REQUEST_COMPLETED = MOD_I2C_EVENT_IDX_COUNT,
41 MOD_I2C_EVENT_IDX_RELOAD,
42 MOD_I2C_EVENT_IDX_TOTAL_COUNT,
43 };
44
45 /*! Request completed event identifier */
46 static const fwk_id_t mod_i2c_event_id_request_completed = FWK_ID_EVENT_INIT(
47 FWK_MODULE_IDX_I2C, MOD_I2C_EVENT_IDX_REQUEST_COMPLETED);
48
49 /*! Reload event identifier */
50 static const fwk_id_t mod_i2c_event_id_reload = FWK_ID_EVENT_INIT(
51 FWK_MODULE_IDX_I2C, MOD_I2C_EVENT_IDX_RELOAD);
52
53 /*
54 * Static helpers
55 */
get_ctx(fwk_id_t id,struct mod_i2c_dev_ctx ** ctx)56 static void get_ctx(fwk_id_t id, struct mod_i2c_dev_ctx **ctx)
57 {
58 fwk_assert(fwk_module_is_valid_element_id(id));
59
60 *ctx = ctx_table + fwk_id_get_element_idx(id);
61 }
62
create_i2c_request(fwk_id_t dev_id,struct mod_i2c_request * request)63 static int create_i2c_request(fwk_id_t dev_id,
64 struct mod_i2c_request *request)
65 {
66 int status;
67 struct fwk_event event;
68 struct mod_i2c_request *event_param =
69 (struct mod_i2c_request *)event.params;
70
71 /* The target address should be on 7 bits */
72 if (!fwk_expect(request->target_address < 0x80)) {
73 return FWK_E_PARAM;
74 }
75
76 event = (struct fwk_event) {
77 .target_id = dev_id,
78 .response_requested = true,
79 };
80
81 *event_param = *request;
82
83 if ((request->transmit_byte_count > 0) &&
84 (request->receive_byte_count > 0)) {
85 event.id = mod_i2c_event_id_request_tx_rx;
86 } else if (request->transmit_byte_count > 0) {
87 event.id = mod_i2c_event_id_request_tx;
88 } else if (request->receive_byte_count > 0) {
89 event.id = mod_i2c_event_id_request_rx;
90 }
91
92 status = fwk_put_event(&event);
93 if (status == FWK_SUCCESS) {
94 /*
95 * The request has been successfully queued for later processing by the
96 * I2C device but processing of this request has not yet begun. The
97 * caller is notified that the I2C request is in progress.
98 */
99 return FWK_PENDING;
100 }
101
102 return status;
103 }
104
105 /*
106 * I2C API
107 */
transmit_as_controller(fwk_id_t dev_id,uint8_t target_address,uint8_t * data,uint8_t byte_count)108 static int transmit_as_controller(
109 fwk_id_t dev_id,
110 uint8_t target_address,
111 uint8_t *data,
112 uint8_t byte_count)
113 {
114 if (!fwk_expect(byte_count != 0)) {
115 return FWK_E_PARAM;
116 }
117
118 if (!fwk_expect(data != NULL)) {
119 return FWK_E_PARAM;
120 }
121
122 struct mod_i2c_request request = {
123 .target_address = target_address,
124 .transmit_data = data,
125 .transmit_byte_count = byte_count,
126 };
127
128 return create_i2c_request(dev_id, &request);
129 }
130
receive_as_controller(fwk_id_t dev_id,uint8_t target_address,uint8_t * data,uint8_t byte_count)131 static int receive_as_controller(
132 fwk_id_t dev_id,
133 uint8_t target_address,
134 uint8_t *data,
135 uint8_t byte_count)
136 {
137 if (!fwk_expect(byte_count != 0)) {
138 return FWK_E_PARAM;
139 }
140
141 if (!fwk_expect(data != NULL)) {
142 return FWK_E_PARAM;
143 }
144
145 struct mod_i2c_request request = {
146 .target_address = target_address,
147 .receive_data = data,
148 .receive_byte_count = byte_count,
149 };
150
151 return create_i2c_request(dev_id, &request);
152 }
153
transmit_then_receive_as_controller(fwk_id_t dev_id,uint8_t target_address,uint8_t * transmit_data,uint8_t * receive_data,uint8_t transmit_byte_count,uint8_t receive_byte_count)154 static int transmit_then_receive_as_controller(
155 fwk_id_t dev_id,
156 uint8_t target_address,
157 uint8_t *transmit_data,
158 uint8_t *receive_data,
159 uint8_t transmit_byte_count,
160 uint8_t receive_byte_count)
161 {
162 if (!fwk_expect((transmit_byte_count != 0) && (receive_byte_count != 0))) {
163 return FWK_E_PARAM;
164 }
165
166 if (!fwk_expect((transmit_data != NULL) && (receive_data != NULL))) {
167 return FWK_E_PARAM;
168 }
169
170 struct mod_i2c_request request = {
171 .target_address = target_address,
172 .transmit_data = transmit_data,
173 .receive_data = receive_data,
174 .transmit_byte_count = transmit_byte_count,
175 .receive_byte_count = receive_byte_count,
176 };
177
178 return create_i2c_request(dev_id, &request);
179 }
180
181 static struct mod_i2c_api i2c_api = {
182 .transmit_as_controller = transmit_as_controller,
183 .receive_as_controller = receive_as_controller,
184 .transmit_then_receive_as_controller = transmit_then_receive_as_controller,
185 };
186
187 /*
188 * Driver response API
189 */
transaction_completed(fwk_id_t dev_id,int i2c_status)190 static void transaction_completed(fwk_id_t dev_id, int i2c_status)
191 {
192 int status;
193 struct fwk_event event;
194 struct mod_i2c_event_param* param =
195 (struct mod_i2c_event_param *)event.params;
196
197 event = (struct fwk_event) {
198 .target_id = dev_id,
199 .source_id = dev_id,
200 .id = mod_i2c_event_id_request_completed,
201 };
202
203 param->status = i2c_status;
204
205 status = fwk_put_event(&event);
206 fwk_assert(status == FWK_SUCCESS);
207 }
208
209 static struct mod_i2c_driver_response_api driver_response_api = {
210 .transaction_completed = transaction_completed,
211 };
212
213 /*
214 * Framework handlers
215 */
mod_i2c_init(fwk_id_t module_id,unsigned int element_count,const void * unused)216 static int mod_i2c_init(fwk_id_t module_id,
217 unsigned int element_count,
218 const void *unused)
219 {
220 ctx_table = fwk_mm_calloc(element_count, sizeof(ctx_table[0]));
221
222 return FWK_SUCCESS;
223 }
224
mod_i2c_dev_init(fwk_id_t element_id,unsigned int unused,const void * data)225 static int mod_i2c_dev_init(fwk_id_t element_id,
226 unsigned int unused,
227 const void *data)
228 {
229 struct mod_i2c_dev_ctx *ctx;
230
231 ctx = ctx_table + fwk_id_get_element_idx(element_id);
232 ctx->config = (struct mod_i2c_dev_config *)data;
233
234 return FWK_SUCCESS;
235 }
236
mod_i2c_bind(fwk_id_t id,unsigned int round)237 static int mod_i2c_bind(fwk_id_t id, unsigned int round)
238 {
239 int status;
240 struct mod_i2c_dev_ctx *ctx;
241
242 /*
243 * Only bind in first round of calls
244 * Nothing to do for module
245 */
246 if ((round > 0) || fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
247 return FWK_SUCCESS;
248 }
249
250 ctx = ctx_table + fwk_id_get_element_idx(id);
251
252 /* Bind to driver */
253 status = fwk_module_bind(ctx->config->driver_id,
254 ctx->config->api_id,
255 &ctx->driver_api);
256 if (status != FWK_SUCCESS) {
257 return status;
258 }
259
260 if ((ctx->driver_api->transmit_as_controller == NULL) ||
261 (ctx->driver_api->receive_as_controller == NULL)) {
262 return FWK_E_DATA;
263 }
264
265 return FWK_SUCCESS;
266 }
267
mod_i2c_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)268 static int mod_i2c_process_bind_request(fwk_id_t source_id,
269 fwk_id_t target_id,
270 fwk_id_t api_id,
271 const void **api)
272 {
273 struct mod_i2c_dev_ctx *ctx;
274
275 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
276 return FWK_E_PARAM;
277 }
278
279 ctx = ctx_table + fwk_id_get_element_idx(target_id);
280
281 if (fwk_id_is_equal(source_id, ctx->config->driver_id)) {
282 if (fwk_id_is_equal(api_id, mod_i2c_api_id_driver_response)) {
283 *api = &driver_response_api;
284 } else {
285 return FWK_E_PARAM;
286 }
287 } else {
288 *api = &i2c_api;
289 }
290
291 return FWK_SUCCESS;
292 }
293
respond_to_caller(fwk_id_t dev_id,struct mod_i2c_dev_ctx * ctx,int drv_status)294 static int respond_to_caller(
295 fwk_id_t dev_id,
296 struct mod_i2c_dev_ctx *ctx,
297 int drv_status)
298 {
299 int status;
300 struct fwk_event resp;
301 struct mod_i2c_event_param *param =
302 (struct mod_i2c_event_param *)resp.params;
303
304 status = fwk_get_first_delayed_response(dev_id, &resp);
305 if (status != FWK_SUCCESS) {
306 return status;
307 }
308
309 param->status = (drv_status == FWK_SUCCESS) ? FWK_SUCCESS : FWK_E_DEVICE;
310
311 return fwk_put_event(&resp);
312 }
313
process_request(struct mod_i2c_dev_ctx * ctx,fwk_id_t event_id)314 static int process_request(struct mod_i2c_dev_ctx *ctx, fwk_id_t event_id)
315 {
316 int drv_status = FWK_E_PARAM;
317 const struct mod_i2c_driver_api *driver_api = ctx->driver_api;
318 fwk_id_t driver_id = ctx->config->driver_id;
319 enum mod_i2c_event_idx event_id_type =
320 (enum mod_i2c_event_idx)fwk_id_get_event_idx(event_id);
321
322 switch (event_id_type) {
323 case MOD_I2C_EVENT_IDX_REQUEST_TRANSMIT:
324 ctx->state = MOD_I2C_DEV_TX;
325 drv_status =
326 driver_api->transmit_as_controller(driver_id, &ctx->request);
327 break;
328
329 case MOD_I2C_EVENT_IDX_REQUEST_TRANSMIT_THEN_RECEIVE:
330 ctx->state = MOD_I2C_DEV_TX_RX;
331 drv_status =
332 driver_api->transmit_as_controller(driver_id, &ctx->request);
333
334 if (drv_status != FWK_SUCCESS) {
335 /* The request has failed or been acknowledged */
336 break;
337 }
338 /* fall through */
339
340 case MOD_I2C_EVENT_IDX_REQUEST_RECEIVE:
341 ctx->state = MOD_I2C_DEV_RX;
342 drv_status =
343 driver_api->receive_as_controller(driver_id, &ctx->request);
344 break;
345
346 default:
347 break;
348 }
349
350 return drv_status;
351 }
352
reload(fwk_id_t dev_id,struct mod_i2c_dev_ctx * ctx)353 static int reload(fwk_id_t dev_id, struct mod_i2c_dev_ctx *ctx)
354 {
355 int status;
356 bool is_empty;
357 struct fwk_event event;
358
359 status = fwk_is_delayed_response_list_empty(dev_id, &is_empty);
360 if (status != FWK_SUCCESS) {
361 return status;
362 }
363
364 if (is_empty) {
365 ctx->state = MOD_I2C_DEV_IDLE;
366 } else {
367 ctx->state = MOD_I2C_DEV_RELOAD;
368 event = (struct fwk_event) {
369 .target_id = dev_id,
370 .id = mod_i2c_event_id_reload,
371 };
372 status = fwk_put_event(&event);
373 }
374
375 return status;
376 }
377
process_next_request(fwk_id_t dev_id,struct mod_i2c_dev_ctx * ctx)378 static int process_next_request(fwk_id_t dev_id, struct mod_i2c_dev_ctx *ctx)
379 {
380 int status, drv_status;
381 bool is_empty;
382 struct fwk_event delayed_response;
383 struct mod_i2c_request *request;
384 struct mod_i2c_event_param *event_param;
385
386 status = fwk_is_delayed_response_list_empty(dev_id, &is_empty);
387 if (status != FWK_SUCCESS) {
388 return status;
389 }
390
391 if (is_empty) {
392 ctx->state = MOD_I2C_DEV_IDLE;
393 return FWK_SUCCESS;
394 }
395
396 status = fwk_get_first_delayed_response(dev_id, &delayed_response);
397 if (status != FWK_SUCCESS) {
398 return status;
399 }
400
401 request = (struct mod_i2c_request *)delayed_response.params;
402 ctx->request = *request;
403
404 drv_status = process_request(ctx, delayed_response.id);
405 if (drv_status != FWK_PENDING) {
406 event_param = (struct mod_i2c_event_param *)delayed_response.params;
407 event_param->status = drv_status;
408
409 status = fwk_put_event(&delayed_response);
410 if (status == FWK_SUCCESS) {
411 status = reload(dev_id, ctx);
412 }
413 }
414
415 return status;
416 }
417
mod_i2c_process_event(const struct fwk_event * event,struct fwk_event * resp_event)418 static int mod_i2c_process_event(const struct fwk_event *event,
419 struct fwk_event *resp_event)
420 {
421 fwk_id_t dev_id;
422 int status, drv_status;
423 bool is_request;
424 struct mod_i2c_dev_ctx *ctx;
425 struct mod_i2c_request *request;
426 struct mod_i2c_event_param *event_param, *resp_param;
427
428 enum mod_i2c_internal_event_idx event_id_type;
429
430 dev_id = event->target_id;
431 get_ctx(dev_id, &ctx);
432
433 is_request = fwk_id_get_event_idx(event->id) < MOD_I2C_EVENT_IDX_COUNT;
434
435 if (is_request) {
436 if (ctx->state == MOD_I2C_DEV_PANIC) {
437 event_param = (struct mod_i2c_event_param *)resp_event->params;
438 event_param->status = FWK_E_PANIC;
439
440 return FWK_SUCCESS;
441 } else if (ctx->state != MOD_I2C_DEV_IDLE) {
442 resp_event->is_delayed_response = true;
443
444 return FWK_SUCCESS;
445 }
446
447 request = (struct mod_i2c_request *)event->params;
448 ctx->request = *request;
449
450 drv_status = process_request(ctx, event->id);
451
452 if (drv_status == FWK_PENDING) {
453 resp_event->is_delayed_response = true;
454 } else {
455 /* The request has succeeded or failed, respond now */
456 resp_param = (struct mod_i2c_event_param *)resp_event->params;
457
458 resp_param->status = (drv_status == FWK_SUCCESS) ?
459 FWK_SUCCESS : FWK_E_DEVICE;
460 ctx->state = MOD_I2C_DEV_IDLE;
461 }
462
463 return FWK_SUCCESS;
464 }
465
466 event_id_type =
467 (enum mod_i2c_internal_event_idx)fwk_id_get_event_idx(event->id);
468
469 switch (event_id_type) {
470 case MOD_I2C_EVENT_IDX_REQUEST_COMPLETED:
471 event_param = (struct mod_i2c_event_param *)event->params;
472
473 if ((ctx->state == MOD_I2C_DEV_TX) || (ctx->state == MOD_I2C_DEV_RX)) {
474 status = respond_to_caller(dev_id, ctx, event_param->status);
475 if (status == FWK_SUCCESS) {
476 status = process_next_request(dev_id, ctx);
477 }
478
479 } else if (ctx->state == MOD_I2C_DEV_TX_RX) {
480 drv_status = event_param->status;
481
482 if (drv_status == FWK_SUCCESS) {
483 /* The TX request succeeded, proceed with the RX */
484 ctx->state = MOD_I2C_DEV_RX;
485
486 drv_status = ctx->driver_api->receive_as_controller(
487 ctx->config->driver_id, &ctx->request);
488
489 if (drv_status == FWK_PENDING) {
490 status = FWK_SUCCESS;
491 break;
492 }
493 }
494
495 status = respond_to_caller(dev_id, ctx, drv_status);
496 if (status == FWK_SUCCESS) {
497 status = process_next_request(dev_id, ctx);
498 }
499 } else {
500 status = FWK_E_STATE;
501 }
502
503 break;
504
505 case MOD_I2C_EVENT_IDX_RELOAD:
506 status = process_next_request(dev_id, ctx);
507 break;
508
509 default:
510 status = FWK_E_PANIC;
511 break;
512 }
513
514 if (status != FWK_SUCCESS) {
515 ctx->state = MOD_I2C_DEV_PANIC;
516 }
517
518 return status;
519 }
520
521 const struct fwk_module module_i2c = {
522 .type = FWK_MODULE_TYPE_HAL,
523 .api_count = (unsigned int)MOD_I2C_API_IDX_COUNT,
524 .event_count = (unsigned int)MOD_I2C_EVENT_IDX_TOTAL_COUNT,
525 .init = mod_i2c_init,
526 .element_init = mod_i2c_dev_init,
527 .bind = mod_i2c_bind,
528 .process_bind_request = mod_i2c_process_bind_request,
529 .process_event = mod_i2c_process_event,
530 };
531