| /* ipm_dummy.c - Fake IPM driver for testing upper-level drivers */ |
| |
| /* |
| * Copyright (c) 2015 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/drivers/ipm.h> |
| #include <errno.h> |
| #include <zephyr/device.h> |
| #include <zephyr/init.h> |
| #include <zephyr/sys/printk.h> |
| #include <zephyr/irq_offload.h> |
| |
| #include "ipm_dummy.h" |
| |
| |
| |
| /* Implemented as a software interrupt so that callbacks are executed |
| * in the expected context |
| */ |
| static void ipm_dummy_isr(const void *data) |
| { |
| const struct device *d = (const struct device *)data; |
| struct ipm_dummy_driver_data *driver_data = d->data; |
| |
| /* In a real driver the interrupt simply wouldn't fire, we fake |
| * that here |
| */ |
| if (!driver_data->regs.enabled || !driver_data->regs.busy) { |
| return; |
| } |
| |
| if (driver_data->cb) { |
| driver_data->cb(d, |
| driver_data->cb_context, driver_data->regs.id, |
| (volatile void *)&driver_data->regs.data); |
| } |
| driver_data->regs.busy = 0U; |
| } |
| |
| |
| /* IPM API functions for the dummy driver */ |
| |
| static int ipm_dummy_send(const struct device *d, int wait, uint32_t id, |
| const void *data, int size) |
| { |
| struct ipm_dummy_driver_data *driver_data; |
| volatile uint8_t *datareg; |
| const uint8_t *data8; |
| int i; |
| |
| driver_data = d->data; |
| if (size > ipm_max_data_size_get(d)) { |
| return -EMSGSIZE; |
| } |
| |
| if (driver_data->regs.busy) { |
| return -EBUSY; |
| } |
| |
| data8 = (const uint8_t *)data; |
| datareg = (volatile uint8_t *)driver_data->regs.data; |
| |
| for (i = 0; i < size; ++i) { |
| datareg[i] = data8[i]; |
| } |
| driver_data->regs.id = id; |
| driver_data->regs.busy = 1U; |
| |
| irq_offload(ipm_dummy_isr, (const void *)d); |
| |
| if (wait) { |
| while (driver_data->regs.busy) { |
| /* busy-wait */ |
| } |
| } |
| return 0; |
| } |
| |
| static void ipm_dummy_register_callback(const struct device *d, |
| ipm_callback_t cb, |
| void *cb_context) |
| { |
| struct ipm_dummy_driver_data *driver_data; |
| |
| driver_data = d->data; |
| driver_data->cb = cb; |
| driver_data->cb_context = cb_context; |
| } |
| |
| static int ipm_dummy_set_enabled(const struct device *d, int enable) |
| { |
| struct ipm_dummy_driver_data *driver_data = d->data; |
| |
| driver_data->regs.enabled = enable; |
| if (enable) { |
| /* In case there are pending messages */ |
| irq_offload(ipm_dummy_isr, (const void *)d); |
| } |
| return 0; |
| } |
| |
| static uint32_t ipm_dummy_max_id_val_get(const struct device *d) |
| { |
| return 0xFFFFFFFF; |
| } |
| |
| static int ipm_dummy_max_data_size_get(const struct device *d) |
| { |
| return DUMMY_IPM_DATA_WORDS * sizeof(uint32_t); |
| } |
| |
| struct ipm_driver_api ipm_dummy_api = { |
| .send = ipm_dummy_send, |
| .register_callback = ipm_dummy_register_callback, |
| .max_data_size_get = ipm_dummy_max_data_size_get, |
| .max_id_val_get = ipm_dummy_max_id_val_get, |
| .set_enabled = ipm_dummy_set_enabled |
| }; |