1 /*
2  * Copyright (c) 2022 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * @addtogroup t_smbus_basic
9  * @{
10  * @defgroup t_smbus
11  * @brief TestPurpose: verify SMBUS can read and write
12  * @}
13  */
14 
15 #include <zephyr/kernel.h>
16 #include <zephyr/ztest.h>
17 #include <zephyr/drivers/smbus.h>
18 
19 BUILD_ASSERT(DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(smbus0)),
20 	     "SMBus node is disabled!");
21 
22 /* Qemu q35 has default emulated EEPROM-like devices */
23 #define QEMU_SMBUS_EEPROM_ADDR	0x50
24 #define QEMU_SMBUS_EEPROM_SIZE	256
25 
26 /**
27  * The test is run in userspace only if CONFIG_USERSPACE option is
28  * enabled, otherwise it is the same as ZTEST()
29  */
ZTEST_USER(test_smbus_qemu,test_smbus_api_read_write)30 ZTEST_USER(test_smbus_qemu, test_smbus_api_read_write)
31 {
32 	int ret;
33 
34 	const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(smbus0));
35 
36 	zassert_true(device_is_ready(dev), "Device is not ready");
37 
38 	/* Test SMBus quick */
39 	ret = smbus_quick(dev, QEMU_SMBUS_EEPROM_ADDR, SMBUS_MSG_WRITE);
40 	zassert_ok(ret, "SMBUS Quick W failed, ret %d", ret);
41 
42 	ret = smbus_quick(dev, QEMU_SMBUS_EEPROM_ADDR, SMBUS_MSG_READ);
43 	zassert_ok(ret, "SMBUS Quick R failed, ret %d", ret);
44 
45 	/* Test SMBus Read / Write Byte Data */
46 	for (uint16_t addr = 0; addr < QEMU_SMBUS_EEPROM_SIZE; addr++) {
47 		/* Randomize buffer */
48 		uint8_t send_byte = (uint8_t)addr;
49 		uint8_t recv_byte;
50 
51 		ret = smbus_byte_data_write(dev, QEMU_SMBUS_EEPROM_ADDR, addr,
52 					    send_byte);
53 		zassert_ok(ret, "SMBUS write byte data failed, ret %d", ret);
54 
55 		ret = smbus_byte_data_read(dev, QEMU_SMBUS_EEPROM_ADDR, addr,
56 					   &recv_byte);
57 		zassert_ok(ret, "SMBUS read byte data failed, ret %d", ret);
58 
59 		zassert_equal(send_byte, recv_byte, "SMBUS data compare fail");
60 	}
61 
62 	/* Test SMBus Read / Write Word Data */
63 	for (uint16_t addr = 0; addr < QEMU_SMBUS_EEPROM_SIZE; addr += 2) {
64 		uint16_t send_word = addr;
65 		uint16_t recv_word;
66 
67 		ret = smbus_word_data_write(dev, QEMU_SMBUS_EEPROM_ADDR, addr,
68 					    send_word);
69 		zassert_ok(ret, "SMBUS write word data failed, ret %d", ret);
70 
71 		ret = smbus_word_data_read(dev, QEMU_SMBUS_EEPROM_ADDR, addr,
72 					   &recv_word);
73 		zassert_ok(ret, "SMBUS read word data failed, ret %d", ret);
74 
75 		zassert_equal(send_word, recv_word, "SMBUS data compare fail");
76 	}
77 
78 	/* Test SMBus Read / Write Byte on special Qemu SMBus peripheral */
79 	for (uint16_t addr = 0; addr < QEMU_SMBUS_EEPROM_SIZE; addr++) {
80 		/* Randomize buffer */
81 		uint8_t send_byte = (uint8_t)addr;
82 		uint8_t recv_byte;
83 
84 		/* Write byte data to EEPROM device */
85 		ret = smbus_byte_data_write(dev, QEMU_SMBUS_EEPROM_ADDR, addr,
86 					    send_byte);
87 		zassert_ok(ret, "SMBUS write byte data failed, ret %d", ret);
88 
89 		/**
90 		 * Reading is done through executing two consequitive
91 		 * operations: write, which sets offset, followed by read, which
92 		 * reads data from given offset
93 		 */
94 
95 		ret = smbus_byte_write(dev, QEMU_SMBUS_EEPROM_ADDR, addr);
96 		zassert_ok(ret, "SMBUS write byte failed, ret %d", ret);
97 
98 		ret = smbus_byte_read(dev, QEMU_SMBUS_EEPROM_ADDR, &recv_byte);
99 		zassert_ok(ret, "SMBUS read byte failed, ret %d", ret);
100 		zassert_equal(send_byte, recv_byte, "SMBUS data compare fail");
101 	}
102 
103 	/**
104 	 * The Qemu SMBus implementation does not always correctly
105 	 * emulate SMBus Block protocol, however it is good enough
106 	 * to test Block Write followed by Block Read
107 	 */
108 
109 	/* Test SMBus Block Write / Block Read */
110 	for (uint16_t addr = 0; addr < QEMU_SMBUS_EEPROM_SIZE;
111 	     addr += SMBUS_BLOCK_BYTES_MAX) {
112 		uint8_t send_block[SMBUS_BLOCK_BYTES_MAX];
113 		uint8_t recv_block[SMBUS_BLOCK_BYTES_MAX];
114 		uint8_t count;
115 
116 		/* Poor man randomize ;) */
117 		for (int i = 0; i < sizeof(send_block); i++) {
118 			send_block[i] = addr + i;
119 		}
120 		ret = smbus_block_write(dev, QEMU_SMBUS_EEPROM_ADDR, addr,
121 					sizeof(send_block), send_block);
122 		zassert_ok(ret, "SMBUS write block failed, ret %d", ret);
123 
124 		ret = smbus_block_read(dev, QEMU_SMBUS_EEPROM_ADDR, addr,
125 				       &count, recv_block);
126 		zassert_ok(ret, "SMBUS read block failed, ret %d", ret);
127 
128 		zassert_equal(count, SMBUS_BLOCK_BYTES_MAX,
129 			      "Read wrong %d of bytes", count);
130 
131 		zassert_true(!memcmp(send_block, recv_block, count),
132 			     "Read / Write data differs");
133 	}
134 }
135 
136 /* Setup is needed for userspace access */
smbus_test_setup(void)137 static void *smbus_test_setup(void)
138 {
139 	const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(smbus0));
140 
141 	zassert_true(device_is_ready(dev), "Device is not ready");
142 
143 	k_object_access_grant(dev, k_current_get());
144 
145 	return NULL;
146 }
147 
148 ZTEST_SUITE(test_smbus_qemu, NULL, smbus_test_setup, NULL, NULL, NULL);
149