minor changes

This commit is contained in:
Your Name
2026-06-17 13:07:58 +03:00
parent 8d5af0b70c
commit 26f3263a05
33 changed files with 935 additions and 508 deletions
@@ -1,5 +1,4 @@
if(CONFIG_CD74HC4067)
target_sources(app PRIVATE ${CMAKE_CURRENT_LIST_DIR}/cd74hc4067.c)
target_include_directories(app PRIVATE ${CMAKE_CURRENT_LIST_DIR})
endif()
target_sources(app PRIVATE ${CMAKE_CURRENT_LIST_DIR}/cd74hc4067.c)
target_include_directories(app PRIVATE ${CMAKE_CURRENT_LIST_DIR})
@@ -2,8 +2,8 @@ menuconfig CD74HC4067
bool "TI CD74HC4067 analog multiplexer"
depends on GPIO
help
Enable support for the TI CD74HC4067 16-channel analog/digital
multiplexer/demultiplexer controlled through GPIO selection pins.
Enable support for the TI CD74HC4067 16-channel analog
multiplexer controlled through GPIO selection pins.
if CD74HC4067
@@ -11,10 +11,10 @@ config CD74HC4067_INIT_PRIORITY
int "Initialization priority"
default 80
help
Device initialization priority for the CD74HC4067 driver. This should
be higher (lower numeric value) than any clients that depend on the
multiplexer being ready.
Device initialization priority for the CD74HC4067 driver.
# Creates "CONFIG_CD74HC4067_LOG_LEVEL"
module = CD74HC4067
module-str = cd74hc4067
source "subsys/logging/Kconfig.template.log_config"
@@ -1,42 +1,74 @@
#define DT_DRV_COMPAT cd74hc4067
#include <errno.h>
#include <stdbool.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>
#include "cd74hc4067.h"
LOG_MODULE_REGISTER(cd74hc4067, CONFIG_CD74HC4067_LOG_LEVEL);
LOG_MODULE_REGISTER(cd74hc4067);
#define CD74HC4067_CHANNEL_COUNT 16U
#define CD74HC4067_SELECTION_PIN_COUNT 4U
//-------------------------------------------------------------------------
// Declarations
struct cd74hc4067_config {
struct gpio_dt_spec sel[CD74HC4067_SELECTION_PIN_COUNT];
struct gpio_dt_spec enable;
bool has_enable;
};
static int cd74hc4067_init(const struct device *dev);
static int cd74hc4067_enable_pin(const struct device *dev, bool state);
struct cd74hc4067_data {
struct k_mutex lock;
uint8_t current_channel;
bool enabled;
};
//-------------------------------------------------------------------------
// Private
static int cd74hc4067_sync_enable_state(const struct device *dev, bool enable)
{
const struct cd74hc4067_config *cfg = dev->config;
static int cd74hc4067_init(const struct device *dev) {
int ret;
const struct cd74hc4067_cfg *cfg = dev->config;
struct cd74hc4067_data *data = dev->data;
k_mutex_init(&data->lock);
data->current_channel = 0U;
data->enabled = !cfg->has_enable;
// Init the select pins
for (int i = 0; i < CD74HC4067_SELECT_PIN_COUNT; i++) {
const struct gpio_dt_spec *pin = &(cfg->select[i]);
if (!gpio_is_ready_dt(pin)) {
LOG_ERR("Select pin %d not ready.\r\n", i);
return -ENODEV;
}
ret = gpio_pin_configure_dt(pin, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Could not configure select pin %d as output\r\n", i);
return -ENODEV;
}
}
if (cfg->has_enable) {
// Init the enable pin
const struct gpio_dt_spec *enable = &cfg->enable;
LOG_DBG("Initializing enable pin.\r\n");
if (!gpio_is_ready_dt(enable)) {
LOG_ERR("Enable pin not ready.\r\n");
return -ENODEV;
}
ret = gpio_pin_configure_dt(enable, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Could not configure ENABLE pin as output\r\n");
return -ENODEV;
}
}
return 0;
}
static int cd74hc4067_enable_pin(const struct device *dev, bool state) {
const struct cd74hc4067_cfg *cfg = dev->config;
struct cd74hc4067_data *data = dev->data;
int ret = 0;
if (!cfg->has_enable) {
if (!enable) {
if (!state) {
return -ENOTSUP;
}
@@ -49,95 +81,68 @@ static int cd74hc4067_sync_enable_state(const struct device *dev, bool enable)
return -ENODEV;
}
ret = gpio_pin_set_dt(&cfg->enable, enable ? 0 : 1);
ret = gpio_pin_set_dt(&cfg->enable, state ? 0 : 1);
if (ret == 0) {
data->enabled = enable;
data->enabled = state;
}
return ret;
}
static int cd74hc4067_configure_gpios(const struct device *dev)
{
const struct cd74hc4067_config *cfg = dev->config;
int ret;
//-------------------------------------------------------------------------
// Public
for (size_t i = 0; i < ARRAY_SIZE(cfg->sel); i++) {
const struct gpio_dt_spec *sel = &cfg->sel[i];
if (!device_is_ready(sel->port)) {
LOG_ERR("%s sel%zu GPIO not ready", dev->name, i);
return -ENODEV;
}
ret = gpio_pin_configure_dt(sel, GPIO_OUTPUT_INACTIVE);
if (ret != 0) {
LOG_ERR("%s failed to configure sel%zu GPIO (%d)", dev->name, i, ret);
return ret;
}
}
if (cfg->has_enable) {
if (!device_is_ready(cfg->enable.port)) {
LOG_ERR("%s enable GPIO not ready", dev->name);
return -ENODEV;
}
ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_HIGH);
if (ret != 0) {
LOG_ERR("%s failed to configure enable GPIO (%d)", dev->name, ret);
return ret;
}
}
return 0;
}
static int cd74hc4067_init(const struct device *dev)
{
const struct cd74hc4067_config *cfg = dev->config;
int cd74hc4067_enable(const struct device *dev) {
struct cd74hc4067_data *data = dev->data;
int ret;
k_mutex_init(&data->lock);
data->current_channel = 0U;
data->enabled = !cfg->has_enable;
ret = cd74hc4067_configure_gpios(dev);
if (ret != 0) {
return ret;
}
/* Latch the default channel (0) */
ret = cd74hc4067_select_channel(dev, 0U);
if (ret != 0) {
return ret;
}
LOG_INF("%s initialized (enable pin %s)", dev->name, cfg->has_enable ? "present" : "absent");
return 0;
}
int cd74hc4067_select_channel(const struct device *dev, uint8_t channel)
{
const struct cd74hc4067_config *cfg = dev->config;
struct cd74hc4067_data *data = dev->data;
int ret = 0;
if (channel >= CD74HC4067_CHANNEL_COUNT) {
return -EINVAL;
}
ret = k_mutex_lock(&data->lock, K_FOREVER);
if (ret != 0) {
return ret;
}
for (size_t i = 0; i < ARRAY_SIZE(cfg->sel); i++) {
ret = gpio_pin_set_dt(&cfg->sel[i], (channel >> i) & 0x1);
if (ret != 0) {
LOG_ERR("%s failed to drive sel%zu GPIO (%d)", dev->name, i, ret);
ret = cd74hc4067_enable_pin(dev, true);
k_mutex_unlock(&data->lock);
return ret;
}
int cd74hc4067_disable(const struct device *dev) {
struct cd74hc4067_data *data = dev->data;
int ret;
ret = k_mutex_lock(&data->lock, K_FOREVER);
if (ret != 0) {
return ret;
}
ret = cd74hc4067_enable_pin(dev, false);
k_mutex_unlock(&data->lock);
return ret;
}
int cd74hc4067_select_channel(const struct device *dev, uint8_t channel) {
if (channel >= CD74HC4067_SELECT_CHANNEL_COUNT) {
LOG_ERR("Channel not found.\r\n");
return -ENODEV;
}
int ret;
const struct cd74hc4067_cfg *cfg = dev->config;
struct cd74hc4067_data *data = dev->data;
ret = k_mutex_lock(&data->lock, K_FOREVER);
if (ret < 0) {
LOG_ERR("Mutex error");
return ret;
}
for (int i = 0; i < CD74HC4067_SELECT_PIN_COUNT; i++) {
bool state = (channel >> i) & 0x1;
ret = gpio_pin_set_dt(&cfg->select[i], state);
if (ret < 0) {
LOG_ERR("Unable to set channel pin: %d", ret);
goto out;
}
}
@@ -149,69 +154,38 @@ out:
return ret;
}
int cd74hc4067_enable(const struct device *dev)
{
struct cd74hc4067_data *data = dev->data;
int ret;
//-------------------------------------------------------------------------
// Devicetree
ret = k_mutex_lock(&data->lock, K_FOREVER);
if (ret != 0) {
return ret;
}
// static const struct cd74hc4067_api cd74hc4067_api_funcs = {
// .enable = cd74hc4067_enable,
// .disable = cd74hc4067_disable,
// .select_channel = cd74hc4067_select_channel,
// };
ret = cd74hc4067_sync_enable_state(dev, true);
k_mutex_unlock(&data->lock);
return ret;
}
int cd74hc4067_disable(const struct device *dev)
{
struct cd74hc4067_data *data = dev->data;
int ret;
ret = k_mutex_lock(&data->lock, K_FOREVER);
if (ret != 0) {
return ret;
}
ret = cd74hc4067_sync_enable_state(dev, false);
k_mutex_unlock(&data->lock);
return ret;
}
uint8_t cd74hc4067_get_current_channel(const struct device *dev)
{
struct cd74hc4067_data *data = dev->data;
uint8_t channel;
k_mutex_lock(&data->lock, K_FOREVER);
channel = data->current_channel;
k_mutex_unlock(&data->lock);
return channel;
}
#define CD74HC4067_DEFINE(inst) \
BUILD_ASSERT(DT_PROP_LEN(DT_DRV_INST(inst), sel_gpios) == CD74HC4067_SELECTION_PIN_COUNT, \
"cd74hc4067 requires exactly 4 selection GPIOs"); \
static const struct cd74hc4067_config cd74hc4067_config_##inst = { \
.sel = { \
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), sel_gpios, 0), \
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), sel_gpios, 1), \
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), sel_gpios, 2), \
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), sel_gpios, 3), \
}, \
.enable = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, enable_gpios), \
(GPIO_DT_SPEC_GET(DT_DRV_INST(inst), enable_gpios)), \
((struct gpio_dt_spec){0})), \
.has_enable = DT_INST_NODE_HAS_PROP(inst, enable_gpios), \
}; \
static struct cd74hc4067_data cd74hc4067_data_##inst; \
DEVICE_DT_INST_DEFINE(inst, cd74hc4067_init, NULL, &cd74hc4067_data_##inst, \
&cd74hc4067_config_##inst, POST_KERNEL, \
CONFIG_CD74HC4067_INIT_PRIORITY, NULL);
DT_INST_FOREACH_STATUS_OKAY(CD74HC4067_DEFINE)
#define CD74HC4067_DEFINE(inst) \
\
static const struct cd74hc4067_cfg cd74hc4067_cfg_##inst = { \
.select = { \
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), select_gpios, 0), \
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), select_gpios, 1), \
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), select_gpios, 2), \
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), select_gpios, 3), \
}, \
.enable = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, enable_gpio), \
(GPIO_DT_SPEC_GET(DT_DRV_INST(inst), enable_gpio)), \
((struct gpio_dt_spec){0})), \
.has_enable = DT_INST_NODE_HAS_PROP(inst, enable_gpio), \
}; \
static struct cd74hc4067_data cd74hc4067_data_##inst; \
DEVICE_DT_INST_DEFINE( inst, \
cd74hc4067_init, \
NULL, \
&cd74hc4067_data_##inst, \
&cd74hc4067_cfg_##inst, \
POST_KERNEL, \
CONFIG_CD74HC4067_INIT_PRIORITY, \
NULL);
DT_INST_FOREACH_STATUS_OKAY(CD74HC4067_DEFINE)
@@ -3,58 +3,39 @@
#include <stdint.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Select one of the 16 multiplexed channels.
*
* @param dev CD74HC4067 device instance.
* @param channel Channel number to route (0-15).
*
* @retval 0 If the channel was selected.
* @retval -EINVAL If the channel number is out of range.
* @retval -ENODEV If one of the selection GPIOs is not ready.
* @retval other Negative errno value from the GPIO driver.
*/
// struct cd74hc4067_api {
// int (*enable)(const struct device *dev);
// int (*disable)(const struct device *dev);
// int (*select_channel)(const struct device *dev, uint8_t channel);
// };
struct cd74hc4067_data {
struct k_mutex lock;
uint8_t current_channel;
bool enabled;
};
#define CD74HC4067_SELECT_CHANNEL_COUNT 16U
#define CD74HC4067_SELECT_PIN_COUNT 4U
struct cd74hc4067_cfg {
struct gpio_dt_spec select[CD74HC4067_SELECT_PIN_COUNT];
struct gpio_dt_spec enable;
bool has_enable;
};
int cd74hc4067_enable(const struct device *dev);
int cd74hc4067_disable(const struct device *dev);
int cd74hc4067_select_channel(const struct device *dev, uint8_t channel);
/**
* @brief Enable the multiplexer output (drives the /EN pin low).
*
* If the instance does not provide an enable GPIO, this call is a no-op.
*
* @param dev CD74HC4067 device instance.
*
* @retval 0 On success.
* @retval -ENODEV If the enable GPIO is not ready.
* @retval negative errno on GPIO failures.
*/
int cd74hc4067_enable(const struct device *dev);
/**
* @brief Disable the multiplexer output (drives the /EN pin high).
*
* @param dev CD74HC4067 device instance.
*
* @retval 0 On success.
* @retval -ENOTSUP If the instance does not expose an enable GPIO.
* @retval -ENODEV If the enable GPIO is not ready.
* @retval negative errno on GPIO failures.
*/
int cd74hc4067_disable(const struct device *dev);
/**
* @brief Return the last channel value written to the device.
*
* @param dev CD74HC4067 device instance.
*
* @return Channel number in the range [0, 15].
*/
uint8_t cd74hc4067_get_current_channel(const struct device *dev);
#ifdef __cplusplus
}