zephyr/drivers/i2c/gpio_i2c_switch.c
Yuval Peress 8974c248cf rtio: Add default i2c submit handler
Use the RTIO work queue to fake the i2c submit calls for drivers which
haven't yet implemented the API. Applications can change the size of
the work queue pool depending on how much traffic they have on the buses.

Signed-off-by: Yuval Peress <peress@google.com>
2024-09-04 21:28:26 +02:00

99 lines
3.2 KiB
C

/*
* Copyright (c) 2023 Ayush Singh <ayushdevel1325@gmail.com>
* Copyright (c) 2021 Jason Kridner, BeagleBoard.org Foundation
* Copyright (c) 2020 Innoseis BV
*
* Based on i2c_tca9656a.c
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT gpio_i2c_switch
#define GPIO_I2C_TOGGLE_DELAY_US 1
#define GPIO_I2C_LOCK_TIMEOUT_US (GPIO_I2C_TOGGLE_DELAY_US * 2 + 100)
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(gpio_i2c_switch, CONFIG_I2C_LOG_LEVEL);
struct gpio_i2c_switch_config {
const struct device *bus;
const struct gpio_dt_spec gpio;
};
struct gpio_i2c_switch_data {
struct k_mutex lock;
};
static int gpio_i2c_switch_configure(const struct device *dev, uint32_t dev_config)
{
const struct gpio_i2c_switch_config *config = dev->config;
return i2c_configure(config->bus, dev_config);
}
static int gpio_i2c_switch_transfer(const struct device *dev, struct i2c_msg *msgs,
uint8_t num_msgs, uint16_t addr)
{
int res;
struct gpio_i2c_switch_data *data = dev->data;
const struct gpio_i2c_switch_config *config = dev->config;
res = k_mutex_lock(&data->lock, K_USEC(GPIO_I2C_LOCK_TIMEOUT_US));
if (res != 0) {
return res;
}
/* enable switch */
gpio_pin_set_dt(&config->gpio, 1);
k_busy_wait(GPIO_I2C_TOGGLE_DELAY_US);
res = i2c_transfer(config->bus, msgs, num_msgs, addr);
/* disable switch */
gpio_pin_set_dt(&config->gpio, 0);
k_busy_wait(GPIO_I2C_TOGGLE_DELAY_US);
k_mutex_unlock(&data->lock);
return res;
}
static const struct i2c_driver_api gpio_i2c_switch_api_funcs = {
.configure = gpio_i2c_switch_configure,
.transfer = gpio_i2c_switch_transfer,
#ifdef CONFIG_I2C_RTIO
.iodev_submit = i2c_iodev_submit_fallback,
#endif
};
static int gpio_i2c_switch_init(const struct device *dev)
{
const struct gpio_i2c_switch_config *config = dev->config;
struct gpio_i2c_switch_data *data = dev->data;
k_mutex_init(&data->lock);
return gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT_INACTIVE);
}
#define DEFINE_GPIO_I2C_SWITCH(inst) \
\
static struct gpio_i2c_switch_data gpio_i2c_switch_dev_data_##inst; \
\
static const struct gpio_i2c_switch_config gpio_i2c_switch_dev_cfg_##inst = { \
.bus = DEVICE_DT_GET(DT_PHANDLE(DT_DRV_INST(inst), controller)), \
.gpio = GPIO_DT_SPEC_GET(DT_DRV_INST(inst), gpios), \
}; \
\
DEVICE_DT_INST_DEFINE(inst, gpio_i2c_switch_init, device_pm_control_nop, \
&gpio_i2c_switch_dev_data_##inst, &gpio_i2c_switch_dev_cfg_##inst, \
POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, &gpio_i2c_switch_api_funcs);
DT_INST_FOREACH_STATUS_OKAY(DEFINE_GPIO_I2C_SWITCH)