|
|
@ -1,10 +1,16 @@ |
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Copyright (c) 2022 Ithinx GmbH |
|
|
|
* Copyright (c) |
|
|
|
|
|
|
|
* 2022 Ithinx GmbH |
|
|
|
|
|
|
|
* 2023 Amrith Venkat Kesavamoorthi <amrith@mr-beam.org> |
|
|
|
|
|
|
|
* 2023 Mr Beam Lasers GmbH. |
|
|
|
* |
|
|
|
* |
|
|
|
* SPDX-License-Identifier: Apache-2.0 |
|
|
|
* SPDX-License-Identifier: Apache-2.0 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @see https://www.nxp.com/docs/en/data-sheet/PCF8575.pdf
|
|
|
|
|
|
|
|
* @see https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
#define DT_DRV_COMPAT nxp_pcf8574 |
|
|
|
#define DT_DRV_COMPAT nxp_pcf857x |
|
|
|
|
|
|
|
|
|
|
|
#include <zephyr/drivers/gpio/gpio_utils.h> |
|
|
|
#include <zephyr/drivers/gpio/gpio_utils.h> |
|
|
|
|
|
|
|
|
|
|
@ -12,28 +18,31 @@ |
|
|
|
#include <zephyr/drivers/i2c.h> |
|
|
|
#include <zephyr/drivers/i2c.h> |
|
|
|
#include <zephyr/kernel.h> |
|
|
|
#include <zephyr/kernel.h> |
|
|
|
#include <zephyr/logging/log.h> |
|
|
|
#include <zephyr/logging/log.h> |
|
|
|
LOG_MODULE_REGISTER(pcf8574, CONFIG_GPIO_LOG_LEVEL); |
|
|
|
#include <zephyr/sys/byteorder.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOG_MODULE_REGISTER(pcf857x, CONFIG_GPIO_LOG_LEVEL); |
|
|
|
|
|
|
|
|
|
|
|
struct pcf8574_pins_cfg { |
|
|
|
struct pcf857x_pins_cfg { |
|
|
|
uint8_t configured_as_outputs; /* 0 for input, 1 for output */ |
|
|
|
uint16_t configured_as_outputs; /* 0 for input, 1 for output */ |
|
|
|
uint8_t outputs_state; |
|
|
|
uint16_t outputs_state; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** Runtime driver data of the pcf8574*/ |
|
|
|
/** Runtime driver data of the pcf857x*/ |
|
|
|
struct pcf8574_drv_data { |
|
|
|
struct pcf857x_drv_data { |
|
|
|
/* gpio_driver_data needs to be first */ |
|
|
|
/* gpio_driver_data needs to be first */ |
|
|
|
struct gpio_driver_data common; |
|
|
|
struct gpio_driver_data common; |
|
|
|
struct pcf8574_pins_cfg pins_cfg; |
|
|
|
struct pcf857x_pins_cfg pins_cfg; |
|
|
|
sys_slist_t callbacks; |
|
|
|
sys_slist_t callbacks; |
|
|
|
struct k_sem lock; |
|
|
|
struct k_sem lock; |
|
|
|
struct k_work work; |
|
|
|
struct k_work work; |
|
|
|
const struct device *dev; |
|
|
|
const struct device *dev; |
|
|
|
struct gpio_callback int_gpio_cb; |
|
|
|
struct gpio_callback int_gpio_cb; |
|
|
|
uint8_t input_port_last; |
|
|
|
uint16_t input_port_last; |
|
|
|
|
|
|
|
int num_bytes; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** Configuration data*/ |
|
|
|
/** Configuration data*/ |
|
|
|
struct pcf8574_drv_cfg { |
|
|
|
struct pcf857x_drv_cfg { |
|
|
|
/* gpio_driver_config needs to be first */ |
|
|
|
/* gpio_driver_config needs to be first */ |
|
|
|
struct gpio_driver_config common; |
|
|
|
struct gpio_driver_config common; |
|
|
|
struct i2c_dt_spec i2c; |
|
|
|
struct i2c_dt_spec i2c; |
|
|
@ -41,52 +50,53 @@ struct pcf8574_drv_cfg { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @brief Reads the value of the pins from pcf8574 respectively from a connected device. |
|
|
|
* @brief Reads the value of the pins from pcf857x respectively from a connected device. |
|
|
|
* |
|
|
|
* |
|
|
|
* @param dev Pointer to the device structure of the driver instance. |
|
|
|
* @param dev Pointer to the device structure of the driver instance. |
|
|
|
* @param value Pointer to the input value. It contains the received Byte. |
|
|
|
* @param value Pointer to the input value. It contains the received Bytes(receives 2 Bytes for P0 |
|
|
|
|
|
|
|
* and P1). |
|
|
|
* |
|
|
|
* |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval Negative value for error code. |
|
|
|
* @retval Negative value for error code. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int pcf8574_process_input(const struct device *dev, gpio_port_value_t *value) |
|
|
|
static int pcf857x_process_input(const struct device *dev, gpio_port_value_t *value) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const struct pcf8574_drv_cfg *drv_cfg = dev->config; |
|
|
|
const struct pcf857x_drv_cfg *drv_cfg = dev->config; |
|
|
|
struct pcf8574_drv_data *drv_data = dev->data; |
|
|
|
struct pcf857x_drv_data *drv_data = dev->data; |
|
|
|
int rc = 0; |
|
|
|
int rc = 0; |
|
|
|
uint8_t rx_buf; |
|
|
|
uint8_t rx_buf[2] = {0}; |
|
|
|
|
|
|
|
|
|
|
|
rc = i2c_read_dt(&drv_cfg->i2c, &rx_buf, sizeof(rx_buf)); |
|
|
|
rc = i2c_read_dt(&drv_cfg->i2c, rx_buf, drv_data->num_bytes); |
|
|
|
if (rc != 0) { |
|
|
|
if (rc != 0) { |
|
|
|
LOG_ERR("%s: failed to read from device: %d", dev->name, rc); |
|
|
|
LOG_ERR("%s: failed to read from device: %d", dev->name, rc); |
|
|
|
return -EIO; |
|
|
|
return -EIO; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (value) { |
|
|
|
if (value) { |
|
|
|
*value = rx_buf; |
|
|
|
*value = sys_get_le16(rx_buf); /*format P17-P10..P07-P00 (bit15-bit8..bit7-bit0)*/ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
drv_data->input_port_last = rx_buf; |
|
|
|
drv_data->input_port_last = sys_get_le16(rx_buf); |
|
|
|
|
|
|
|
|
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Register the read-task as work*/ |
|
|
|
/** Register the read-task as work*/ |
|
|
|
static void pcf8574_work_handler(struct k_work *work) |
|
|
|
static void pcf857x_work_handler(struct k_work *work) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct pcf8574_drv_data *drv_data = CONTAINER_OF(work, struct pcf8574_drv_data, work); |
|
|
|
struct pcf857x_drv_data *drv_data = CONTAINER_OF(work, struct pcf857x_drv_data, work); |
|
|
|
|
|
|
|
|
|
|
|
k_sem_take(&drv_data->lock, K_FOREVER); |
|
|
|
k_sem_take(&drv_data->lock, K_FOREVER); |
|
|
|
|
|
|
|
|
|
|
|
uint32_t changed_pins; |
|
|
|
uint32_t changed_pins; |
|
|
|
uint8_t input_port_last_temp = drv_data->input_port_last; |
|
|
|
uint16_t input_port_last_temp = drv_data->input_port_last; |
|
|
|
int rc = pcf8574_process_input(drv_data->dev, &changed_pins); |
|
|
|
int rc = pcf857x_process_input(drv_data->dev, &changed_pins); |
|
|
|
|
|
|
|
|
|
|
|
if (rc) { |
|
|
|
if (rc) { |
|
|
|
LOG_ERR("Failed to read interrupt sources: %d", rc); |
|
|
|
LOG_ERR("Failed to read interrupt sources: %d", rc); |
|
|
|
} |
|
|
|
} |
|
|
|
k_sem_give(&drv_data->lock); |
|
|
|
k_sem_give(&drv_data->lock); |
|
|
|
if (input_port_last_temp != (uint8_t)changed_pins && !rc) { |
|
|
|
if (input_port_last_temp != (uint16_t)changed_pins && !rc) { |
|
|
|
|
|
|
|
|
|
|
|
/** Find changed bits*/ |
|
|
|
/** Find changed bits*/ |
|
|
|
changed_pins ^= input_port_last_temp; |
|
|
|
changed_pins ^= input_port_last_temp; |
|
|
@ -94,15 +104,15 @@ static void pcf8574_work_handler(struct k_work *work) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Callback for interrupt through some level changes on pcf8574 pins*/ |
|
|
|
/** Callback for interrupt through some level changes on pcf857x pins*/ |
|
|
|
static void pcf8574_int_gpio_handler(const struct device *dev, struct gpio_callback *gpio_cb, |
|
|
|
static void pcf857x_int_gpio_handler(const struct device *dev, struct gpio_callback *gpio_cb, |
|
|
|
uint32_t pins) |
|
|
|
uint32_t pins) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ARG_UNUSED(dev); |
|
|
|
ARG_UNUSED(dev); |
|
|
|
ARG_UNUSED(pins); |
|
|
|
ARG_UNUSED(pins); |
|
|
|
|
|
|
|
|
|
|
|
struct pcf8574_drv_data *drv_data = |
|
|
|
struct pcf857x_drv_data *drv_data = |
|
|
|
CONTAINER_OF(gpio_cb, struct pcf8574_drv_data, int_gpio_cb); |
|
|
|
CONTAINER_OF(gpio_cb, struct pcf857x_drv_data, int_gpio_cb); |
|
|
|
|
|
|
|
|
|
|
|
k_work_submit(&drv_data->work); |
|
|
|
k_work_submit(&drv_data->work); |
|
|
|
} |
|
|
|
} |
|
|
@ -116,16 +126,16 @@ static void pcf8574_int_gpio_handler(const struct device *dev, struct gpio_callb |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval Negative value for error code. |
|
|
|
* @retval Negative value for error code. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int pcf8574_port_get_raw(const struct device *dev, gpio_port_value_t *value) |
|
|
|
static int pcf857x_port_get_raw(const struct device *dev, gpio_port_value_t *value) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct pcf8574_drv_data *drv_data = dev->data; |
|
|
|
struct pcf857x_drv_data *drv_data = dev->data; |
|
|
|
int rc; |
|
|
|
int rc; |
|
|
|
|
|
|
|
|
|
|
|
if (k_is_in_isr()) { |
|
|
|
if (k_is_in_isr()) { |
|
|
|
return -EWOULDBLOCK; |
|
|
|
return -EWOULDBLOCK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ((~drv_data->pins_cfg.configured_as_outputs & (uint8_t)*value) != (uint8_t)*value) { |
|
|
|
if ((~drv_data->pins_cfg.configured_as_outputs & (uint16_t)*value) != (uint16_t)*value) { |
|
|
|
LOG_ERR("Pin(s) is/are configured as output which should be input."); |
|
|
|
LOG_ERR("Pin(s) is/are configured as output which should be input."); |
|
|
|
return -EOPNOTSUPP; |
|
|
|
return -EOPNOTSUPP; |
|
|
|
} |
|
|
|
} |
|
|
@ -136,7 +146,7 @@ static int pcf8574_port_get_raw(const struct device *dev, gpio_port_value_t *val |
|
|
|
* Reading of the input port also clears the generated interrupt, |
|
|
|
* Reading of the input port also clears the generated interrupt, |
|
|
|
* thus the configured callbacks must be fired also here if needed. |
|
|
|
* thus the configured callbacks must be fired also here if needed. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
rc = pcf8574_process_input(dev, value); |
|
|
|
rc = pcf857x_process_input(dev, value); |
|
|
|
|
|
|
|
|
|
|
|
k_sem_give(&drv_data->lock); |
|
|
|
k_sem_give(&drv_data->lock); |
|
|
|
|
|
|
|
|
|
|
@ -148,19 +158,20 @@ static int pcf8574_port_get_raw(const struct device *dev, gpio_port_value_t *val |
|
|
|
* |
|
|
|
* |
|
|
|
* @param dev A pointer to the device structure |
|
|
|
* @param dev A pointer to the device structure |
|
|
|
* @param mask A mask of bits to set some bits to LOW or HIGH |
|
|
|
* @param mask A mask of bits to set some bits to LOW or HIGH |
|
|
|
* @param value The value which is written via i2c to the pfc8574's output pins |
|
|
|
* @param value The value which is written via i2c to the pcf857x's output pins |
|
|
|
* @param toggle A way to toggle some bits with xor |
|
|
|
* @param toggle A way to toggle some bits with xor |
|
|
|
* |
|
|
|
* |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval Negative value for error code. |
|
|
|
* @retval Negative value for error code. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int pcf8574_port_set_raw(const struct device *dev, uint8_t mask, uint8_t value, |
|
|
|
static int pcf857x_port_set_raw(const struct device *dev, uint16_t mask, uint16_t value, |
|
|
|
uint8_t toggle) |
|
|
|
uint16_t toggle) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const struct pcf8574_drv_cfg *drv_cfg = dev->config; |
|
|
|
const struct pcf857x_drv_cfg *drv_cfg = dev->config; |
|
|
|
struct pcf8574_drv_data *drv_data = dev->data; |
|
|
|
struct pcf857x_drv_data *drv_data = dev->data; |
|
|
|
int rc = 0; |
|
|
|
int rc = 0; |
|
|
|
uint8_t tx_buf; |
|
|
|
uint16_t tx_buf; |
|
|
|
|
|
|
|
uint8_t tx_buf_p[2]; |
|
|
|
|
|
|
|
|
|
|
|
if (k_is_in_isr()) { |
|
|
|
if (k_is_in_isr()) { |
|
|
|
return -EWOULDBLOCK; |
|
|
|
return -EWOULDBLOCK; |
|
|
@ -174,14 +185,13 @@ static int pcf8574_port_set_raw(const struct device *dev, uint8_t mask, uint8_t |
|
|
|
tx_buf = (drv_data->pins_cfg.outputs_state & ~mask); |
|
|
|
tx_buf = (drv_data->pins_cfg.outputs_state & ~mask); |
|
|
|
tx_buf |= (value & mask); |
|
|
|
tx_buf |= (value & mask); |
|
|
|
tx_buf ^= toggle; |
|
|
|
tx_buf ^= toggle; |
|
|
|
|
|
|
|
sys_put_le16(tx_buf, tx_buf_p); |
|
|
|
|
|
|
|
|
|
|
|
rc = i2c_write_dt(&drv_cfg->i2c, &tx_buf, sizeof(tx_buf)); |
|
|
|
rc = i2c_write_dt(&drv_cfg->i2c, tx_buf_p, drv_data->num_bytes); |
|
|
|
|
|
|
|
|
|
|
|
if (rc != 0) { |
|
|
|
if (rc != 0) { |
|
|
|
LOG_ERR("%s: failed to write output port: %d", dev->name, rc); |
|
|
|
LOG_ERR("%s: failed to write output port: %d", dev->name, rc); |
|
|
|
return -EIO; |
|
|
|
return -EIO; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
k_sem_take(&drv_data->lock, K_FOREVER); |
|
|
|
k_sem_take(&drv_data->lock, K_FOREVER); |
|
|
|
drv_data->pins_cfg.outputs_state = tx_buf; |
|
|
|
drv_data->pins_cfg.outputs_state = tx_buf; |
|
|
|
k_sem_give(&drv_data->lock); |
|
|
|
k_sem_give(&drv_data->lock); |
|
|
@ -190,9 +200,9 @@ static int pcf8574_port_set_raw(const struct device *dev, uint8_t mask, uint8_t |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @brief This function fills a dummy because the pfc8574 has no pins to configure. |
|
|
|
* @brief This function fills a dummy because the pcf857x has no pins to configure. |
|
|
|
* You can use it to set some pins permanent to HIGH or LOW until reset. It uses the port_set_raw |
|
|
|
* You can use it to set some pins permanent to HIGH or LOW until reset. It uses the port_set_raw |
|
|
|
* function to set the pins of pcf8574 directly. |
|
|
|
* function to set the pins of pcf857x directly. |
|
|
|
* |
|
|
|
* |
|
|
|
* @param dev Pointer to the device structure for the driver instance. |
|
|
|
* @param dev Pointer to the device structure for the driver instance. |
|
|
|
* @param pin The bit in the io register which is set to high |
|
|
|
* @param pin The bit in the io register which is set to high |
|
|
@ -201,12 +211,12 @@ static int pcf8574_port_set_raw(const struct device *dev, uint8_t mask, uint8_t |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval Negative value for error. |
|
|
|
* @retval Negative value for error. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int pcf8574_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) |
|
|
|
static int pcf857x_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct pcf8574_drv_data *drv_data = dev->data; |
|
|
|
struct pcf857x_drv_data *drv_data = dev->data; |
|
|
|
int ret = 0; |
|
|
|
int ret = 0; |
|
|
|
uint8_t temp_pins = drv_data->pins_cfg.outputs_state; |
|
|
|
uint16_t temp_pins = drv_data->pins_cfg.outputs_state; |
|
|
|
uint8_t temp_outputs = drv_data->pins_cfg.configured_as_outputs; |
|
|
|
uint16_t temp_outputs = drv_data->pins_cfg.configured_as_outputs; |
|
|
|
|
|
|
|
|
|
|
|
if (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN | GPIO_DISCONNECTED | GPIO_SINGLE_ENDED)) { |
|
|
|
if (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN | GPIO_DISCONNECTED | GPIO_SINGLE_ENDED)) { |
|
|
|
return -ENOTSUP; |
|
|
|
return -ENOTSUP; |
|
|
@ -225,7 +235,7 @@ static int pcf8574_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ |
|
|
|
temp_pins &= ~(1 << pin); |
|
|
|
temp_pins &= ~(1 << pin); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ret = pcf8574_port_set_raw(dev, drv_data->pins_cfg.configured_as_outputs, temp_pins, 0); |
|
|
|
ret = pcf857x_port_set_raw(dev, drv_data->pins_cfg.configured_as_outputs, temp_pins, 0); |
|
|
|
|
|
|
|
|
|
|
|
if (ret == 0) { |
|
|
|
if (ret == 0) { |
|
|
|
k_sem_take(&drv_data->lock, K_FOREVER); |
|
|
|
k_sem_take(&drv_data->lock, K_FOREVER); |
|
|
@ -238,7 +248,7 @@ static int pcf8574_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @brief Sets a value to the pins of pcf8574 |
|
|
|
* @brief Sets a value to the pins of pcf857x |
|
|
|
* |
|
|
|
* |
|
|
|
* @param dev Pointer to the device structure for the driver instance. |
|
|
|
* @param dev Pointer to the device structure for the driver instance. |
|
|
|
* @param mask The bit mask which bits should be set |
|
|
|
* @param mask The bit mask which bits should be set |
|
|
@ -247,24 +257,24 @@ static int pcf8574_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval Negative value for error. |
|
|
|
* @retval Negative value for error. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int pcf8574_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, |
|
|
|
static int pcf857x_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, |
|
|
|
gpio_port_value_t value) |
|
|
|
gpio_port_value_t value) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return pcf8574_port_set_raw(dev, (uint8_t)mask, (uint8_t)value, 0); |
|
|
|
return pcf857x_port_set_raw(dev, (uint16_t)mask, (uint16_t)value, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @brief Sets some output pins of the pcf8574 |
|
|
|
* @brief Sets some output pins of the pcf857x |
|
|
|
* |
|
|
|
* |
|
|
|
* @param dev Pointer to the device structure for the driver instance. |
|
|
|
* @param dev Pointer to the device structure for the driver instance. |
|
|
|
* @param pins The pin(s) which will be set in a range from 0 to 7 |
|
|
|
* @param pins The pin(s) which will be set in a range from P17-P10..P07-P00 |
|
|
|
* |
|
|
|
* |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval Negative value for error. |
|
|
|
* @retval Negative value for error. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int pcf8574_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) |
|
|
|
static int pcf857x_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return pcf8574_port_set_raw(dev, (uint8_t)pins, (uint8_t)pins, 0); |
|
|
|
return pcf857x_port_set_raw(dev, (uint16_t)pins, (uint16_t)pins, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -276,9 +286,9 @@ static int pcf8574_port_set_bits_raw(const struct device *dev, gpio_port_pins_t |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval Negative value for error. |
|
|
|
* @retval Negative value for error. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int pcf8574_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) |
|
|
|
static int pcf857x_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return pcf8574_port_set_raw(dev, (uint8_t)pins, 0, 0); |
|
|
|
return pcf857x_port_set_raw(dev, (uint16_t)pins, 0, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -290,16 +300,16 @@ static int pcf8574_port_clear_bits_raw(const struct device *dev, gpio_port_pins_ |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval 0 If successful. |
|
|
|
* @retval Negative value for error. |
|
|
|
* @retval Negative value for error. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int pcf8574_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) |
|
|
|
static int pcf857x_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return pcf8574_port_set_raw(dev, 0, 0, (uint8_t)pins); |
|
|
|
return pcf857x_port_set_raw(dev, 0, 0, (uint16_t)pins); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Each pin gives an interrupt at pcf8574. In this function the configuration is checked. */ |
|
|
|
/* Each pin gives an interrupt at pcf857x. In this function the configuration is checked. */ |
|
|
|
static int pcf8574_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, |
|
|
|
static int pcf857x_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, |
|
|
|
enum gpio_int_mode mode, enum gpio_int_trig trig) |
|
|
|
enum gpio_int_mode mode, enum gpio_int_trig trig) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const struct pcf8574_drv_cfg *drv_cfg = dev->config; |
|
|
|
const struct pcf857x_drv_cfg *drv_cfg = dev->config; |
|
|
|
|
|
|
|
|
|
|
|
if (!drv_cfg->gpio_int.port) { |
|
|
|
if (!drv_cfg->gpio_int.port) { |
|
|
|
return -ENOTSUP; |
|
|
|
return -ENOTSUP; |
|
|
@ -314,19 +324,19 @@ static int pcf8574_pin_interrupt_configure(const struct device *dev, gpio_pin_t |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Register the callback in the callback list */ |
|
|
|
/** Register the callback in the callback list */ |
|
|
|
static int pcf8574_manage_callback(const struct device *dev, struct gpio_callback *callback, |
|
|
|
static int pcf857x_manage_callback(const struct device *dev, struct gpio_callback *callback, |
|
|
|
bool set) |
|
|
|
bool set) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct pcf8574_drv_data *drv_data = dev->data; |
|
|
|
struct pcf857x_drv_data *drv_data = dev->data; |
|
|
|
|
|
|
|
|
|
|
|
return gpio_manage_callback(&drv_data->callbacks, callback, set); |
|
|
|
return gpio_manage_callback(&drv_data->callbacks, callback, set); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Initialize the pcf8574 */ |
|
|
|
/** Initialize the pcf857x */ |
|
|
|
static int pcf8574_init(const struct device *dev) |
|
|
|
static int pcf857x_init(const struct device *dev) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const struct pcf8574_drv_cfg *drv_cfg = dev->config; |
|
|
|
const struct pcf857x_drv_cfg *drv_cfg = dev->config; |
|
|
|
struct pcf8574_drv_data *drv_data = dev->data; |
|
|
|
struct pcf857x_drv_data *drv_data = dev->data; |
|
|
|
int rc; |
|
|
|
int rc; |
|
|
|
|
|
|
|
|
|
|
|
if (!device_is_ready(drv_cfg->i2c.bus)) { |
|
|
|
if (!device_is_ready(drv_cfg->i2c.bus)) { |
|
|
@ -353,7 +363,7 @@ static int pcf8574_init(const struct device *dev) |
|
|
|
return -EIO; |
|
|
|
return -EIO; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
gpio_init_callback(&drv_data->int_gpio_cb, pcf8574_int_gpio_handler, |
|
|
|
gpio_init_callback(&drv_data->int_gpio_cb, pcf857x_int_gpio_handler, |
|
|
|
BIT(drv_cfg->gpio_int.pin)); |
|
|
|
BIT(drv_cfg->gpio_int.pin)); |
|
|
|
rc = gpio_add_callback(drv_cfg->gpio_int.port, &drv_data->int_gpio_cb); |
|
|
|
rc = gpio_add_callback(drv_cfg->gpio_int.port, &drv_data->int_gpio_cb); |
|
|
|
if (rc != 0) { |
|
|
|
if (rc != 0) { |
|
|
@ -365,20 +375,20 @@ static int pcf8574_init(const struct device *dev) |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Realizes the functions of gpio.h for pcf8574*/ |
|
|
|
/** Realizes the functions of gpio.h for pcf857x*/ |
|
|
|
static const struct gpio_driver_api pcf8574_drv_api = { |
|
|
|
static const struct gpio_driver_api pcf857x_drv_api = { |
|
|
|
.pin_configure = pcf8574_pin_configure, |
|
|
|
.pin_configure = pcf857x_pin_configure, |
|
|
|
.port_get_raw = pcf8574_port_get_raw, |
|
|
|
.port_get_raw = pcf857x_port_get_raw, |
|
|
|
.port_set_masked_raw = pcf8574_port_set_masked_raw, |
|
|
|
.port_set_masked_raw = pcf857x_port_set_masked_raw, |
|
|
|
.port_set_bits_raw = pcf8574_port_set_bits_raw, |
|
|
|
.port_set_bits_raw = pcf857x_port_set_bits_raw, |
|
|
|
.port_clear_bits_raw = pcf8574_port_clear_bits_raw, |
|
|
|
.port_clear_bits_raw = pcf857x_port_clear_bits_raw, |
|
|
|
.port_toggle_bits = pcf8574_port_toggle_bits, |
|
|
|
.port_toggle_bits = pcf857x_port_toggle_bits, |
|
|
|
.pin_interrupt_configure = pcf8574_pin_interrupt_configure, |
|
|
|
.pin_interrupt_configure = pcf857x_pin_interrupt_configure, |
|
|
|
.manage_callback = pcf8574_manage_callback, |
|
|
|
.manage_callback = pcf857x_manage_callback, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#define GPIO_PCF8574_INST(idx) \ |
|
|
|
#define GPIO_PCF857X_INST(idx) \ |
|
|
|
static const struct pcf8574_drv_cfg pcf8574_cfg##idx = { \ |
|
|
|
static const struct pcf857x_drv_cfg pcf857x_cfg##idx = { \ |
|
|
|
.common = \ |
|
|
|
.common = \ |
|
|
|
{ \ |
|
|
|
{ \ |
|
|
|
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx), \ |
|
|
|
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx), \ |
|
|
@ -386,12 +396,13 @@ static const struct gpio_driver_api pcf8574_drv_api = { |
|
|
|
.gpio_int = GPIO_DT_SPEC_INST_GET_OR(idx, int_gpios, {0}), \ |
|
|
|
.gpio_int = GPIO_DT_SPEC_INST_GET_OR(idx, int_gpios, {0}), \ |
|
|
|
.i2c = I2C_DT_SPEC_INST_GET(idx), \ |
|
|
|
.i2c = I2C_DT_SPEC_INST_GET(idx), \ |
|
|
|
}; \ |
|
|
|
}; \ |
|
|
|
static struct pcf8574_drv_data pcf8574_data##idx = { \ |
|
|
|
static struct pcf857x_drv_data pcf857x_data##idx = { \ |
|
|
|
.lock = Z_SEM_INITIALIZER(pcf8574_data##idx.lock, 1, 1), \ |
|
|
|
.lock = Z_SEM_INITIALIZER(pcf857x_data##idx.lock, 1, 1), \ |
|
|
|
.work = Z_WORK_INITIALIZER(pcf8574_work_handler), \ |
|
|
|
.work = Z_WORK_INITIALIZER(pcf857x_work_handler), \ |
|
|
|
.dev = DEVICE_DT_INST_GET(idx), \ |
|
|
|
.dev = DEVICE_DT_INST_GET(idx), \ |
|
|
|
|
|
|
|
.num_bytes = DT_INST_ENUM_IDX(idx, ngpios) + 1, \ |
|
|
|
}; \ |
|
|
|
}; \ |
|
|
|
DEVICE_DT_INST_DEFINE(idx, pcf8574_init, NULL, &pcf8574_data##idx, &pcf8574_cfg##idx, \ |
|
|
|
DEVICE_DT_INST_DEFINE(idx, pcf857x_init, NULL, &pcf857x_data##idx, &pcf857x_cfg##idx, \ |
|
|
|
POST_KERNEL, CONFIG_GPIO_PCF8574_INIT_PRIORITY, &pcf8574_drv_api); |
|
|
|
POST_KERNEL, CONFIG_GPIO_PCF857X_INIT_PRIORITY, &pcf857x_drv_api); |
|
|
|
|
|
|
|
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(GPIO_PCF8574_INST); |
|
|
|
DT_INST_FOREACH_STATUS_OKAY(GPIO_PCF857X_INST); |