1 /*
2  * Copyright (c) 2022 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * Verify SMBUS Basic API, tests should work on any board
9  */
10 
11 #include <zephyr/kernel.h>
12 #include <zephyr/ztest.h>
13 #include <zephyr/drivers/smbus.h>
14 
15 #include <smbus_utils.h>
16 
17 BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(smbus0), okay),
18 	     "SMBus node is disabled!");
19 
20 #define FAKE_ADDRESS	0x10
21 
22 /**
23  * The test is run in userspace only if CONFIG_USERSPACE option is
24  * enabled, otherwise it is the same as ZTEST()
25  */
ZTEST_USER(test_smbus_general,test_smbus_basic_api)26 ZTEST_USER(test_smbus_general, test_smbus_basic_api)
27 {
28 	const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(smbus0));
29 	uint32_t cfg = SMBUS_MODE_CONTROLLER;
30 	uint32_t cfg_tmp;
31 	int ret;
32 
33 	zassert_true(device_is_ready(dev), "Device is not ready");
34 
35 	ret = smbus_configure(dev, cfg);
36 	zassert_ok(ret, "SMBUS config failed");
37 
38 	ret = smbus_get_config(dev, &cfg_tmp);
39 	zassert_ok(ret, "SMBUS get_config failed");
40 
41 	zassert_equal(cfg, cfg_tmp, "get_config returned invalid config");
42 }
43 
44 /**
45  * The test is run in userspace only if CONFIG_USERSPACE option is
46  * enabled, otherwise it is the same as ZTEST()
47  */
ZTEST(test_smbus_general,test_smbus_smbalert_api)48 ZTEST(test_smbus_general, test_smbus_smbalert_api)
49 {
50 	const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(smbus0));
51 	void *dummy; /* For the dummy function pointer use this */
52 	int ret;
53 
54 	/* Note! Only for test using stack variables to ease userspace tests */
55 	struct smbus_callback callback = {
56 		.handler = (void *)&dummy,
57 		.addr = FAKE_ADDRESS,
58 	};
59 
60 	zassert_true(device_is_ready(dev), "Device is not ready");
61 
62 	/* Smbalert callbacks */
63 
64 	/* Try to remove not existing callback */
65 	ret = smbus_smbalert_remove_cb(dev, &callback);
66 	if (IS_ENABLED(CONFIG_SMBUS_INTEL_PCH_SMBALERT)) {
67 		zassert_equal(ret, -ENOENT, "Callback remove failed");
68 	} else {
69 		zassert_equal(ret, -ENOSYS, "Check for ENOSYS failed");
70 	}
71 
72 	/* Set callback */
73 	ret = smbus_smbalert_set_cb(dev, &callback);
74 	if (IS_ENABLED(CONFIG_SMBUS_INTEL_PCH_SMBALERT)) {
75 		zassert_ok(ret, "Callback set failed");
76 	} else {
77 		zassert_equal(ret, -ENOSYS, "Check for ENOSYS failed");
78 	}
79 
80 	/* Remove existing callback */
81 	ret = smbus_smbalert_remove_cb(dev, &callback);
82 	if (IS_ENABLED(CONFIG_SMBUS_INTEL_PCH_SMBALERT)) {
83 		zassert_ok(ret, "Callback remove failed");
84 	} else {
85 		zassert_equal(ret, -ENOSYS, "Check for ENOSYS failed");
86 	}
87 }
88 
89 /**
90  * The test is run in userspace only if CONFIG_USERSPACE option is
91  * enabled, otherwise it is the same as ZTEST()
92  */
ZTEST(test_smbus_general,test_smbus_host_notify_api)93 ZTEST(test_smbus_general, test_smbus_host_notify_api)
94 {
95 	const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(smbus0));
96 	void *dummy; /* For the dummy function pointer use this */
97 	int ret;
98 
99 	/* Note! Only for test using stack variables to ease userspace tests */
100 	struct smbus_callback callback = {
101 		.handler = (void *)&dummy,
102 		.addr = FAKE_ADDRESS,
103 	};
104 
105 	zassert_true(device_is_ready(dev), "Device is not ready");
106 
107 	/* Host Notify callbacks */
108 
109 	/* Try to remove not existing callback */
110 	ret = smbus_host_notify_remove_cb(dev, &callback);
111 	if (IS_ENABLED(CONFIG_SMBUS_INTEL_PCH_HOST_NOTIFY)) {
112 		zassert_equal(ret, -ENOENT, "Callback remove failed");
113 	} else {
114 		zassert_equal(ret, -ENOSYS, "Check for ENOSYS failed");
115 	}
116 
117 	/* Set callback */
118 	ret = smbus_host_notify_set_cb(dev, &callback);
119 	if (IS_ENABLED(CONFIG_SMBUS_INTEL_PCH_HOST_NOTIFY)) {
120 		zassert_ok(ret, "Callback set failed");
121 	} else {
122 		zassert_equal(ret, -ENOSYS, "Check for ENOSYS failed");
123 	}
124 
125 	/* Remove existing callback */
126 	ret = smbus_host_notify_remove_cb(dev, &callback);
127 	if (IS_ENABLED(CONFIG_SMBUS_INTEL_PCH_HOST_NOTIFY)) {
128 		zassert_ok(ret, "Callback remove failed");
129 	} else {
130 		zassert_equal(ret, -ENOSYS, "Check for ENOSYS failed");
131 	}
132 }
133 
134 /**
135  * The test is run in userspace only if CONFIG_USERSPACE option is
136  * enabled, otherwise it is the same as ZTEST()
137  */
ZTEST_USER(test_smbus_general,test_smbus_api_errors)138 ZTEST_USER(test_smbus_general, test_smbus_api_errors)
139 {
140 	const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(smbus0));
141 	uint8_t fake_addr = 0x10;
142 	uint8_t buf[2];
143 	int ret;
144 
145 	zassert_true(device_is_ready(dev), "Device is not ready");
146 
147 	/* Test parsing SMBus quick */
148 	ret = smbus_quick(dev, fake_addr, 3);
149 	zassert_equal(ret, -EINVAL, "Wrong parameter check failed");
150 
151 	/* Test parsing SMBus block_write */
152 	ret = smbus_block_write(dev, fake_addr, 0, 0, buf);
153 	zassert_equal(ret, -EINVAL, "Wrong parameter check failed");
154 	ret = smbus_block_write(dev, fake_addr, 0, SMBUS_BLOCK_BYTES_MAX + 1,
155 				buf);
156 	zassert_equal(ret, -EINVAL, "Wrong parameter check failed");
157 }
158 
159 /* Setup is needed for userspace access */
smbus_test_setup(void)160 static void *smbus_test_setup(void)
161 {
162 	const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(smbus0));
163 
164 	zassert_true(device_is_ready(dev), "Device is not ready");
165 
166 	k_object_access_grant(dev, k_current_get());
167 
168 	return NULL;
169 }
170 
171 ZTEST_SUITE(test_smbus_general, NULL, smbus_test_setup, NULL, NULL, NULL);
172