/* * Copyright (c) 2023 Efinix Inc. * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT efinix_sapphire_gpio #include #include #include #include #include #include #include #include LOG_MODULE_REGISTER(gpio_efinix_sapphire); #define SUPPORTED_FLAGS \ (GPIO_INPUT | GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH | \ GPIO_ACTIVE_LOW | GPIO_ACTIVE_HIGH) #define GPIO_LOW 0 #define GPIO_HIGH 1 #define BSP_GPIO_INPUT 0x00 #define BSP_GPIO_OUTPUT 0x04 #define BSP_GPIO_OUTPUT_ENABLE 0x08 #define BSP_GPIO_INTERRUPT_RISE_ENABLE 0x20 #define BSP_GPIO_INTERRUPT_FALL_ENABLE 0x24 #define BSP_GPIO_INTERRUPT_HIGH_ENABLE 0x28 #define BSP_GPIO_INTERRUPT_LOW_ENABLE 0x2c /* efinix sapphire specific gpio config struct */ struct gpio_efinix_sapphire_cfg { uint32_t base_addr; int n_gpios; struct gpio_driver_config common; }; /* efinix sapphire specific gpio data struct */ struct gpio_efinix_sapphire_data { struct gpio_driver_data common; const struct device *dev; sys_slist_t cb; }; /* Device access pointer helpers */ #define DEV_GPIO_CFG(dev) ((const struct gpio_efinix_sapphire_cfg *)(dev)->config) #define GPIO_OUTPUT_ADDR config->base_addr + BSP_GPIO_OUTPUT static inline void cfg_output_enable_bit(const struct gpio_efinix_sapphire_cfg *config, gpio_pin_t pin, uint32_t type) { #define GPIO_OUTPUT_ENABLE_ADDR config->base_addr + BSP_GPIO_OUTPUT_ENABLE uint32_t c_reg_val = sys_read32(GPIO_OUTPUT_ENABLE_ADDR); if (type == GPIO_INPUT) { sys_write32(c_reg_val &= ~pin, GPIO_OUTPUT_ENABLE_ADDR); } else if (type == GPIO_OUTPUT) { sys_write32(c_reg_val |= pin, GPIO_OUTPUT_ENABLE_ADDR); } } static inline void cfg_output_bit(const struct gpio_efinix_sapphire_cfg *config, gpio_pin_t pin, uint32_t value) { uint32_t c_reg_val = sys_read32(GPIO_OUTPUT_ADDR); if (value == GPIO_LOW) { sys_write32(c_reg_val &= ~pin, GPIO_OUTPUT_ADDR); } else if (value == GPIO_HIGH) { sys_write32(c_reg_val |= pin, GPIO_OUTPUT_ADDR); } } /* To use the controller bare minimum as IO, Peripheral has to configure, */ /* the Output enable register, b0 : Input, b1 : Output */ static int gpio_efinix_sapphire_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); /* Check if the controller supports the requested GPIO configuration. */ if (flags & ~SUPPORTED_FLAGS) { return -ENOTSUP; } if ((flags & GPIO_DIR_MASK) == GPIO_DIR_MASK) { /* Pin cannot be configured as input and output */ return -ENOTSUP; } else if ((flags & GPIO_DIR_MASK) == GPIO_DISCONNECTED) { /* Pin has to be configured as input or output */ return -ENOTSUP; } /* Configure the output register based on the direction flag */ if (flags & GPIO_OUTPUT) { /* Set the pin as output */ cfg_output_enable_bit(config, BIT(pin), GPIO_OUTPUT); if (flags & GPIO_OUTPUT_INIT_HIGH) { /* Set the pin to high */ cfg_output_bit(config, BIT(pin), GPIO_HIGH); } else if (flags & GPIO_OUTPUT_INIT_LOW) { /* Set the pin to low */ cfg_output_bit(config, BIT(pin), GPIO_LOW); } } else { /* Set the pin as input */ cfg_output_enable_bit(config, BIT(pin), GPIO_INPUT); } return 0; } static inline uint32_t get_port(const struct gpio_efinix_sapphire_cfg *config) { uint32_t c_reg_val = sys_read32(GPIO_OUTPUT_ADDR); return (c_reg_val & BIT_MASK(config->n_gpios)); } static inline void set_port(const struct gpio_efinix_sapphire_cfg *config, uint32_t value) { sys_write32(value, GPIO_OUTPUT_ADDR); } static int gpio_efinix_sapphire_port_get_raw(const struct device *dev, gpio_port_value_t *value) { const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); *value = get_port(config); return 0; } static int gpio_efinix_sapphire_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, gpio_port_value_t value) { const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); uint32_t c_reg_val = get_port(config); /* Sets ports value at one go */ c_reg_val &= ~mask; c_reg_val |= (value & mask); set_port(config, c_reg_val); return 0; } static int gpio_efinix_sapphire_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) { const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); uint32_t c_reg_val = get_port(config); /* Sets ports value at one go */ c_reg_val |= pins; set_port(config, c_reg_val); return 0; } static int gpio_efinix_sapphire_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) { const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); uint32_t c_reg_val = get_port(config); /* Sets ports value at one go */ c_reg_val &= ~pins; set_port(config, c_reg_val); return 0; } static int gpio_efinix_sapphire_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) { const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); uint32_t c_reg_val = get_port(config); /* Sets ports value at one go */ c_reg_val ^= pins; set_port(config, c_reg_val); return 0; } static int gpio_efinix_sapphire_init(const struct device *dev) { const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); if (config->n_gpios > 4) { return -EINVAL; } return 0; } /* API map */ static const struct gpio_driver_api gpio_efinix_sapphire_api = { .pin_configure = gpio_efinix_sapphire_config, .port_get_raw = gpio_efinix_sapphire_port_get_raw, .port_set_masked_raw = gpio_efinix_sapphire_port_set_masked_raw, .port_set_bits_raw = gpio_efinix_sapphire_port_set_bits_raw, .port_clear_bits_raw = gpio_efinix_sapphire_port_clear_bits_raw, .port_toggle_bits = gpio_efinix_sapphire_port_toggle_bits, }; #define GPIO_EFINIX_SAPPHIRE_INIT(n) \ static struct gpio_efinix_sapphire_cfg gpio_efinix_sapphire_cfg_##n = { \ .base_addr = DT_INST_REG_ADDR(n), \ .n_gpios = DT_INST_PROP(n, ngpios), \ }; \ static struct gpio_efinix_sapphire_data gpio_efinix_sapphire_data_##n; \ DEVICE_DT_INST_DEFINE(n, \ gpio_efinix_sapphire_init, \ NULL, \ &gpio_efinix_sapphire_data_##n, \ &gpio_efinix_sapphire_cfg_##n, \ POST_KERNEL, \ CONFIG_GPIO_INIT_PRIORITY, \ &gpio_efinix_sapphire_api \ ); \ DT_INST_FOREACH_STATUS_OKAY(GPIO_EFINIX_SAPPHIRE_INIT)