summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuval Peress <peress@google.com>2021-10-08 13:03:09 -0600
committerCommit Bot <commit-bot@chromium.org>2021-10-11 17:12:50 +0000
commite3389fa1e36e67fac8261096c3d8c1b56d9e26a4 (patch)
tree647b7e068f2b71703d6245ffa25103095f60c313
parent5765523800223bbb60da0e28c179ac59bd344af7 (diff)
downloadchrome-ec-e3389fa1e36e67fac8261096c3d8c1b56d9e26a4.tar.gz
zephyr: test: add an emulated clock to drivers test
BRANCH=none BUG=b:180112248 TEST=zmake configure --test zephyr/test/drivers Signed-off-by: Yuval Peress <peress@google.com> Change-Id: I4a6561c58c7fab33a66ec8fd4a34da38ace6a45c Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3213364 Reviewed-by: Denis Brockus <dbrockus@chromium.org>
-rw-r--r--zephyr/dts/bindings/emul/cros,clock-control-emul.yaml15
-rw-r--r--zephyr/emul/CMakeLists.txt1
-rw-r--r--zephyr/emul/Kconfig1
-rw-r--r--zephyr/emul/Kconfig.clock_control22
-rw-r--r--zephyr/emul/emul_clock_control.c186
-rw-r--r--zephyr/include/emul/emul_clock_control.h9
-rw-r--r--zephyr/test/drivers/overlay.dts8
7 files changed, 241 insertions, 1 deletions
diff --git a/zephyr/dts/bindings/emul/cros,clock-control-emul.yaml b/zephyr/dts/bindings/emul/cros,clock-control-emul.yaml
new file mode 100644
index 0000000000..fa632ea2d4
--- /dev/null
+++ b/zephyr/dts/bindings/emul/cros,clock-control-emul.yaml
@@ -0,0 +1,15 @@
+# Copyright 2021 The chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: Emulated clock
+
+compatible: "cros,clock-control-emul"
+
+include: base.yaml
+properties:
+ clock-frequency:
+ type: int
+ required: true
+ description: |
+ Default frequency in Hz for the output clock.
diff --git a/zephyr/emul/CMakeLists.txt b/zephyr/emul/CMakeLists.txt
index 8bf15666ab..1d0693fa57 100644
--- a/zephyr/emul/CMakeLists.txt
+++ b/zephyr/emul/CMakeLists.txt
@@ -16,3 +16,4 @@ zephyr_library_sources_ifdef(CONFIG_EMUL_LN9310 emul_ln9310.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_LIS2DW12 emul_lis2dw12.c)
zephyr_library_sources_ifdef(CONFIG_I2C_MOCK i2c_mock.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_ISL923X emul_isl923x.c)
+zephyr_library_sources_ifdef(CONFIG_EMUL_CLOCK_CONTROL emul_clock_control.c)
diff --git a/zephyr/emul/Kconfig b/zephyr/emul/Kconfig
index e47232bdd1..aa0d14da44 100644
--- a/zephyr/emul/Kconfig
+++ b/zephyr/emul/Kconfig
@@ -71,3 +71,4 @@ rsource "Kconfig.ln9310"
rsource "Kconfig.lis2dw12"
rsource "Kconfig.i2c_mock"
rsource "Kconfig.isl923x"
+rsource "Kconfig.clock_control"
diff --git a/zephyr/emul/Kconfig.clock_control b/zephyr/emul/Kconfig.clock_control
new file mode 100644
index 0000000000..a4dfbce557
--- /dev/null
+++ b/zephyr/emul/Kconfig.clock_control
@@ -0,0 +1,22 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+DT_COMPAT_CLOCK_CONTROL_EMUL := cros,clock-control-emul
+
+config EMUL_CLOCK_CONTROL
+ bool "Emulated clock control"
+ default $(dt_compat_enabled,$(DT_COMPAT_CLOCK_CONTROL_EMUL))
+ help
+ Enable the emulated clock control module. This module introduces a
+ functioning clock control implementation along with backdoor APIs to
+ verify and override behavior. Emulator API is available in
+ zephyr/include/emul/emul_clock_control.h
+
+if EMUL_CLOCK_CONTROL
+
+module = CLOCK_CONTROL_EMUL
+module-str = clock_control_emul
+source "subsys/logging/Kconfig.template.log_config"
+
+endif # EMUL_CLOCK_CONTROL
diff --git a/zephyr/emul/emul_clock_control.c b/zephyr/emul/emul_clock_control.c
new file mode 100644
index 0000000000..d8eadcca1c
--- /dev/null
+++ b/zephyr/emul/emul_clock_control.c
@@ -0,0 +1,186 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#define DT_DRV_COMPAT cros_clock_control_emul
+
+#include <device.h>
+#include <drivers/clock_control.h>
+#include <kernel.h>
+
+#include "common.h"
+#include "emul/emul_clock_control.h"
+
+#include <logging/log.h>
+LOG_MODULE_REGISTER(clock_control_emul, CONFIG_CLOCK_CONTROL_EMUL_LOG_LEVEL);
+
+/** Data needed to maintain the current emulator state */
+struct emul_clock_ctrl_data {
+ /** The current clock rate */
+ uint32_t rate;
+ /** The current clock status */
+ enum clock_control_status status;
+ /** Async k_work structure */
+ struct k_work async_on_work;
+ /** Mutex used to guard the callback values */
+ struct k_mutex cb_mutex;
+ /** Async callback */
+ clock_control_cb_t cb;
+ /** Async user data to pass to the callback */
+ void *cb_user_data;
+ /** Async device to pass to the callback */
+ const struct device *cb_dev;
+ /** Async subsystem to pass to the callback */
+ clock_control_subsys_t cb_subsys;
+};
+
+static int drv_clock_ctrl_on(const struct device *dev,
+ clock_control_subsys_t sys)
+{
+ struct emul_clock_ctrl_data *data = dev->data;
+ int rc;
+
+ k_mutex_lock(&data->cb_mutex, K_FOREVER);
+ if (data->status == CLOCK_CONTROL_STATUS_OFF) {
+ data->status = CLOCK_CONTROL_STATUS_ON;
+ rc = 0;
+ } else {
+ LOG_ERR("Invalid clock status: %d", data->status);
+ rc = EC_ERROR_UNIMPLEMENTED;
+ }
+ k_mutex_unlock(&data->cb_mutex);
+ return 0;
+}
+
+static int drv_clock_ctrl_off(const struct device *dev,
+ clock_control_subsys_t sys)
+{
+ struct emul_clock_ctrl_data *data = dev->data;
+ int rc;
+
+ k_mutex_lock(&data->cb_mutex, K_FOREVER);
+ if (data->status == CLOCK_CONTROL_STATUS_ON) {
+ data->status = CLOCK_CONTROL_STATUS_OFF;
+ rc = 0;
+ } else {
+ LOG_ERR("Invalid clock status: %d", data->status);
+ rc = EC_ERROR_UNIMPLEMENTED;
+ }
+ k_mutex_unlock(&data->cb_mutex);
+ return rc;
+}
+
+static void clock_ctrl_on_from_work(struct k_work *work)
+{
+ struct emul_clock_ctrl_data *data =
+ CONTAINER_OF(work, struct emul_clock_ctrl_data, async_on_work);
+
+ k_mutex_lock(&data->cb_mutex, K_FOREVER);
+ if (data->status == CLOCK_CONTROL_STATUS_STARTING) {
+ data->status = CLOCK_CONTROL_STATUS_ON;
+ data->cb(data->cb_dev, data->cb_subsys, data->cb_user_data);
+ data->cb = NULL;
+ data->cb_dev = NULL;
+ data->cb_subsys = NULL;
+ data->cb_user_data = NULL;
+ } else {
+ LOG_ERR("Invalid clock status: %d", data->status);
+ }
+ k_mutex_unlock(&data->cb_mutex);
+}
+
+static int drv_clock_ctrl_async_on(const struct device *dev,
+ clock_control_subsys_t sys,
+ clock_control_cb_t cb, void *user_data)
+{
+ struct emul_clock_ctrl_data *data = dev->data;
+ int rc;
+
+ k_mutex_lock(&data->cb_mutex, K_FOREVER);
+ switch (data->status) {
+ case CLOCK_CONTROL_STATUS_ON:
+ rc = 0;
+ break;
+ case CLOCK_CONTROL_STATUS_STARTING:
+ rc = EC_ERROR_BUSY;
+ break;
+ case CLOCK_CONTROL_STATUS_OFF:
+ data->status = CLOCK_CONTROL_STATUS_STARTING;
+ data->cb = cb;
+ data->cb_dev = dev;
+ data->cb_subsys = sys;
+ data->cb_user_data = user_data;
+
+ k_work_init(&data->async_on_work, clock_ctrl_on_from_work);
+ rc = k_work_submit(&data->async_on_work);
+ if (rc > 0) {
+ /*
+ * Work is already submitted, this should never happen
+ * because of the above cases.
+ */
+ rc = EC_ERROR_UNKNOWN;
+ } else if (rc < 0) {
+ rc = EC_ERROR_BUSY;
+ }
+ break;
+ default:
+ LOG_ERR("Invalid clock status: %d", data->status);
+ rc = EC_ERROR_UNIMPLEMENTED;
+ }
+ k_mutex_unlock(&data->cb_mutex);
+
+ return rc;
+}
+
+static int drv_clock_ctrl_get_rate(const struct device *dev,
+ clock_control_subsys_t sys, uint32_t *rate)
+{
+ struct emul_clock_ctrl_data *data = dev->data;
+
+ *rate = data->rate;
+ return 0;
+}
+
+static enum clock_control_status
+drv_clock_ctrl_get_status(const struct device *dev, clock_control_subsys_t sys)
+{
+ struct emul_clock_ctrl_data *data = dev->data;
+ enum clock_control_status status;
+
+ k_mutex_lock(&data->cb_mutex, K_FOREVER);
+ status = data->status;
+ k_mutex_unlock(&data->cb_mutex);
+
+ return status;
+}
+
+static const struct clock_control_driver_api driver_api = {
+ .on = drv_clock_ctrl_on,
+ .off = drv_clock_ctrl_off,
+ .async_on = drv_clock_ctrl_async_on,
+ .get_rate = drv_clock_ctrl_get_rate,
+ .get_status = drv_clock_ctrl_get_status,
+};
+
+static int drv_clock_ctrl_init(const struct device *dev)
+{
+ struct emul_clock_ctrl_data *data = dev->data;
+
+ k_mutex_init(&data->cb_mutex);
+ return 0;
+}
+
+#define INIT_CLOCK_CTRL(n) \
+ static struct emul_clock_ctrl_data emul_clock_ctrl_data_##n = { \
+ .status = COND_CODE_1(DT_INST_PROP(n, clock_frequency) == 0, \
+ (CLOCK_CONTROL_STATUS_OFF), \
+ (CLOCK_CONTROL_STATUS_ON)), \
+ .rate = DT_INST_PROP(n, clock_frequency), \
+ }; \
+ DEVICE_DT_INST_DEFINE(n, drv_clock_ctrl_init, NULL, \
+ &emul_clock_ctrl_data_##n, NULL, PRE_KERNEL_1, \
+ CONFIG_KERNEL_INIT_PRIORITY_OBJECTS, \
+ &driver_api);
+
+DT_INST_FOREACH_STATUS_OKAY(INIT_CLOCK_CTRL)
diff --git a/zephyr/include/emul/emul_clock_control.h b/zephyr/include/emul/emul_clock_control.h
new file mode 100644
index 0000000000..1b3846b0f1
--- /dev/null
+++ b/zephyr/include/emul/emul_clock_control.h
@@ -0,0 +1,9 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef ZEPHYR_INCLUDE_EMUL_EMUL_CLOCK_CONTROL_H_
+#define ZEPHYR_INCLUDE_EMUL_EMUL_CLOCK_CONTROL_H_
+
+#endif /* ZEPHYR_INCLUDE_EMUL_EMUL_CLOCK_CONTROL_H_ */
diff --git a/zephyr/test/drivers/overlay.dts b/zephyr/test/drivers/overlay.dts
index 782345a7be..0ab9392773 100644
--- a/zephyr/test/drivers/overlay.dts
+++ b/zephyr/test/drivers/overlay.dts
@@ -3,8 +3,9 @@
* found in the LICENSE file.
*/
-#include <dt-bindings/gpio_defines.h>
#include <cros/thermistor/thermistor.dtsi>
+#include <dt-bindings/gpio_defines.h>
+#include <freq.h>
/ {
aliases {
@@ -444,6 +445,11 @@
error-on-msb-first-access;
};
};
+
+ clock: clock {
+ compatible = "cros,clock-control-emul";
+ clock-frequency = <DT_FREQ_M(100)>; /* 100 MHz */
+ };
};
&espi0 {