|  | /* | 
|  | * 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) |