From 2146b19cc737917b094ae953bde210ea1e3c9e12 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 5 Oct 2022 15:40:39 +0300 Subject: [PATCH] smbus: Add Host Notify and smbalert API Add API for SMBus Host Notify and SMBALERT. Signed-off-by: Andrei Emeltchenko --- drivers/smbus/smbus_handlers.c | 23 ++++++- include/zephyr/drivers/smbus.h | 98 ++++++++++++++++++++++++++++ include/zephyr/drivers/smbus_utils.h | 85 ++++++++++++++++++++++++ 3 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 include/zephyr/drivers/smbus_utils.h diff --git a/drivers/smbus/smbus_handlers.c b/drivers/smbus/smbus_handlers.c index 547814fe692..fd03a7cad48 100644 --- a/drivers/smbus/smbus_handlers.c +++ b/drivers/smbus/smbus_handlers.c @@ -4,8 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include +#include static inline int z_vrfy_smbus_configure(const struct device *dev, uint32_t dev_config) @@ -142,3 +143,23 @@ static inline int z_vrfy_smbus_block_pcall(const struct device *dev, rcv_count, rcv_buf); } #include + +static inline int z_vrfy_smbus_manage_smbalert_cb(const struct device *dev, + struct smbus_callback *cb, + bool set) +{ + Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + + return z_impl_smbus_manage_smbalert_cb(dev, cb, set); +} +#include + +static inline int z_vrfy_smbus_manage_host_notify_cb(const struct device *dev, + struct smbus_callback *cb, + bool set) +{ + Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SMBUS)); + + return z_impl_smbus_manage_host_notify_cb(dev, cb, set); +} +#include diff --git a/include/zephyr/drivers/smbus.h b/include/zephyr/drivers/smbus.h index 872f0481f29..d20786f7d11 100644 --- a/include/zephyr/drivers/smbus.h +++ b/include/zephyr/drivers/smbus.h @@ -209,6 +209,12 @@ extern "C" { /** Support Packet Error Code (PEC) checking */ #define SMBUS_MODE_PEC BIT(1) +/** Support Host Notify functionality */ +#define SMBUS_MODE_HOST_NOTIFY BIT(2) + +/** Support SMBALERT signal functionality */ +#define SMBUS_MODE_SMBALERT BIT(3) + /** @} */ /** @@ -247,6 +253,32 @@ enum smbus_direction { #define SMBUS_MSG_RW_MASK BIT(0) /** @endcond */ +struct smbus_callback; + +typedef void (*smbus_callback_handler_t)(const struct device *dev, + struct smbus_callback *cb, + uint8_t addr); + +/** + * @brief SMBus callback structure + * + * Used to register a callback in the driver instance callback list. + * As many callbacks as needed can be added as long as each of them + * are unique pointers of struct smbus_callback. + * + * Note: Such struct should not be allocated on stack. + */ +struct smbus_callback { + /** This should be used in driver for a callback list management */ + sys_snode_t node; + + /** Actual callback function being called when relevant */ + smbus_callback_handler_t handler; + + /** Peripheral device address */ + uint8_t addr; +}; + /** * @brief Complete SMBus DT information * @@ -326,6 +358,12 @@ typedef int (*smbus_api_block_pcall_t)(const struct device *dev, uint16_t addr, uint8_t cmd, uint8_t send_count, uint8_t *send_buf, uint8_t *recv_count, uint8_t *recv_buf); +typedef int (*smbus_api_manage_smbalert_cb_t)(const struct device *dev, + struct smbus_callback *cb, + bool set); +typedef int (*smbus_api_manage_host_notify_cb_t)(const struct device *dev, + struct smbus_callback *cb, + bool set); __subsystem struct smbus_driver_api { smbus_api_configure_t configure; @@ -341,6 +379,8 @@ __subsystem struct smbus_driver_api { smbus_api_block_write_t smbus_block_write; smbus_api_block_read_t smbus_block_read; smbus_api_block_pcall_t smbus_block_pcall; + smbus_api_manage_smbalert_cb_t smbus_manage_smbalert_cb; + smbus_api_manage_host_notify_cb_t smbus_manage_host_notify_cb; }; /** @@ -547,6 +587,64 @@ static inline int z_impl_smbus_get_config(const struct device *dev, return api->get_config(dev, dev_config); } +/** + * @brief Add SMBUSALERT callback for a SMBus host controller. + * + * @param dev Pointer to the device structure for the driver instance. + * @param cb Pointer to a callback structure. + * @param set A boolean indicating insertion or removal of the callback. + * + * @retval 0 If successful. + * @retval -EIO General input / output error, failed to configure device. + * @retval -ENOSYS If get config is not implemented + */ +__syscall int smbus_manage_smbalert_cb(const struct device *dev, + struct smbus_callback *cb, + bool set); + +static inline int z_impl_smbus_manage_smbalert_cb(const struct device *dev, + struct smbus_callback *cb, + bool set) +{ + const struct smbus_driver_api *api = + (const struct smbus_driver_api *)dev->api; + + if (api->smbus_manage_smbalert_cb == NULL) { + return -ENOSYS; + } + + return api->smbus_manage_smbalert_cb(dev, cb, set); +} + +/** + * @brief Add Host Notify callback for a SMBus host controller. + * + * @param dev Pointer to the device structure for the driver instance. + * @param cb Pointer to a callback structure. + * @param set A boolean indicating insertion or removal of the callback. + * + * @retval 0 If successful. + * @retval -EIO General input / output error, failed to configure device. + * @retval -ENOSYS If get config is not implemented + */ +__syscall int smbus_manage_host_notify_cb(const struct device *dev, + struct smbus_callback *cb, + bool set); + +static inline int z_impl_smbus_manage_host_notify_cb(const struct device *dev, + struct smbus_callback *cb, + bool set) +{ + const struct smbus_driver_api *api = + (const struct smbus_driver_api *)dev->api; + + if (api->smbus_manage_host_notify_cb == NULL) { + return -ENOSYS; + } + + return api->smbus_manage_host_notify_cb(dev, cb, set); +} + /** * @brief Perform SMBus Quick operation * diff --git a/include/zephyr/drivers/smbus_utils.h b/include/zephyr/drivers/smbus_utils.h new file mode 100644 index 00000000000..426891dfdf6 --- /dev/null +++ b/include/zephyr/drivers/smbus_utils.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ +#define ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ + +/** + * @brief Generic function to insert or remove a callback from a callback list + * + * @param callbacks A pointer to the original list of callbacks (can be NULL) + * @param callback A pointer of the callback to insert or remove from the list + * @param set A boolean indicating insertion or removal of the callback + * + * @return 0 on success, negative errno otherwise. + */ +static inline int smbus_manage_smbus_callback(sys_slist_t *callbacks, + struct smbus_callback *callback, + bool set) +{ + __ASSERT(callback, "No callback!"); + __ASSERT(callback->handler, "No callback handler!"); + + if (!sys_slist_is_empty(callbacks)) { + if (!sys_slist_find_and_remove(callbacks, &callback->node)) { + if (!set) { + return -ENOENT; + } + } + } else { + if (!set) { + return -ENOENT; + } + } + + if (set) { + sys_slist_prepend(callbacks, &callback->node); + } + + return 0; +} + +/** + * @brief Generic function to go through and fire callback from a callback list + * + * @param list A pointer on the SMBus callback list + * @param dev A pointer on the SMBus device instance + * @param addr A SMBus peripheral device address. + */ +static inline void smbus_fire_callbacks(sys_slist_t *list, + const struct device *dev, + uint8_t addr) +{ + struct smbus_callback *cb, *tmp; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(list, cb, tmp, node) { + if (cb->addr == addr) { + __ASSERT(cb->handler, "No callback handler!"); + cb->handler(dev, cb, addr); + } + } +} + +/** + * @brief Helper to initialize a struct smbus_callback properly + * + * @param callback A valid Application's callback structure pointer. + * @param handler A valid handler function pointer. + * @param addr A SMBus peripheral device address. + */ +static inline void smbus_init_callback(struct smbus_callback *callback, + smbus_callback_handler_t handler, + uint8_t addr) +{ + __ASSERT(callback, "Callback pointer should not be NULL"); + __ASSERT(handler, "Callback handler pointer should not be NULL"); + + callback->handler = handler; + callback->addr = addr; +} + + +#endif /* ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ */