1 /*
2  * Copyright (c) 2024 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/i2c.h>
9 #include <zephyr/logging/log_backend.h>
10 #include <zephyr/logging/log_core.h>
11 #include <zephyr/logging/log_ctrl.h>
12 #include <zephyr/logging/log_msg.h>
13 #include <zephyr/logging/log_output.h>
14 #include <zephyr/logging/log_backend_std.h>
15 #include <zephyr/sys/__assert.h>
16 #include <sedi_driver_i2c.h>
17 
18 static uint32_t log_format_current = CONFIG_LOG_BACKEND_I2C_OUTPUT_DEFAULT;
19 static uint8_t log_i2c_buf[CONFIG_LOG_I2C_MAX_MSG_LEN];
20 static bool panic_mode;
21 static uint8_t i2c_bus;
22 
log_i2c_char_out(uint8_t * data,size_t length,void * ctx)23 static int log_i2c_char_out(uint8_t *data, size_t length, void *ctx)
24 {
25 	ARG_UNUSED(ctx);
26 
27 	__ASSERT_NO_MSG(length > 0 && length <= CONFIG_LOG_I2C_MAX_MSG_LEN);
28 
29 	sedi_i2c_master_poll_write(i2c_bus, CONFIG_LOG_I2C_DEV_ADDR,
30 				data, length, false);
31 
32 	return length;
33 }
34 
35 LOG_OUTPUT_DEFINE(log_output_i2c, log_i2c_char_out,
36 		log_i2c_buf, CONFIG_LOG_I2C_MAX_MSG_LEN);
37 
log_i2c_panic(struct log_backend const * const backend)38 static void log_i2c_panic(struct log_backend const *const backend)
39 {
40 	ARG_UNUSED(backend);
41 
42 	panic_mode = true;
43 	sedi_i2c_control(i2c_bus, SEDI_I2C_ABORT_TRANSFER, 0);
44 	log_backend_std_panic(&log_output_i2c);
45 }
46 
log_i2c_dropped(const struct log_backend * const backend,uint32_t cnt)47 static void log_i2c_dropped(const struct log_backend *const backend,
48 		uint32_t cnt)
49 {
50 	ARG_UNUSED(backend);
51 
52 	log_backend_std_dropped(&log_output_i2c, cnt);
53 }
54 
process(const struct log_backend * const backend,union log_msg_generic * msg)55 static void process(const struct log_backend *const backend,
56 		union log_msg_generic *msg)
57 {
58 	uint32_t flags = log_backend_std_get_flags();
59 	log_format_func_t log_output_func = log_format_func_t_get(log_format_current);
60 
61 	log_output_func(&log_output_i2c, &msg->log, flags);
62 }
63 
format_set(const struct log_backend * const backend,uint32_t log_type)64 static int format_set(const struct log_backend *const backend, uint32_t log_type)
65 {
66 	log_format_current = log_type;
67 	return 0;
68 }
69 
log_backend_i2c_init(const struct log_backend * const backend)70 static void log_backend_i2c_init(const struct log_backend *const backend)
71 {
72 #if DT_HAS_CHOSEN(zephyr_log_i2c)
73 	uint32_t cfg = I2C_SPEED_SET(I2C_SPEED_FAST) | I2C_MODE_CONTROLLER;
74 	int ret = i2c_configure(DEVICE_DT_GET(DT_CHOSEN(zephyr_log_i2c)), cfg);
75 
76 	if (ret) {
77 		goto disable;
78 	}
79 
80 	i2c_bus = DT_PROP(DT_CHOSEN(zephyr_log_i2c), peripheral_id);
81 	panic_mode = false;
82 
83 	return;
84 
85 disable:
86 #endif
87 	/* No specified log i2c device or device not ready */
88 	log_backend_disable(backend);
89 }
90 
91 static const struct log_backend_api log_backend_i2c_api = {
92 	.process = process,
93 	.panic = log_i2c_panic,
94 	.init = log_backend_i2c_init,
95 	.dropped = IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) ? NULL : log_i2c_dropped,
96 	.format_set = format_set,
97 };
98 
99 LOG_BACKEND_DEFINE(log_backend_i2c, log_backend_i2c_api,
100 		IS_ENABLED(CONFIG_LOG_BACKEND_I2C_AUTOSTART));
101