You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
3.2 KiB
98 lines
3.2 KiB
/* |
|
* 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 DEVICE_API(i2c, 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), \ |
|
}; \ |
|
\ |
|
I2C_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)
|
|
|