diff options
author | Yuval Peress <peress@google.com> | 2021-10-08 13:03:09 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-10-11 17:12:50 +0000 |
commit | e3389fa1e36e67fac8261096c3d8c1b56d9e26a4 (patch) | |
tree | 647b7e068f2b71703d6245ffa25103095f60c313 | |
parent | 5765523800223bbb60da0e28c179ac59bd344af7 (diff) | |
download | chrome-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.yaml | 15 | ||||
-rw-r--r-- | zephyr/emul/CMakeLists.txt | 1 | ||||
-rw-r--r-- | zephyr/emul/Kconfig | 1 | ||||
-rw-r--r-- | zephyr/emul/Kconfig.clock_control | 22 | ||||
-rw-r--r-- | zephyr/emul/emul_clock_control.c | 186 | ||||
-rw-r--r-- | zephyr/include/emul/emul_clock_control.h | 9 | ||||
-rw-r--r-- | zephyr/test/drivers/overlay.dts | 8 |
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 { |