diff --git a/drivers/reset/CMakeLists.txt b/drivers/reset/CMakeLists.txt index 28a0cecce8a..223db50a3a6 100644 --- a/drivers/reset/CMakeLists.txt +++ b/drivers/reset/CMakeLists.txt @@ -1,3 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library() +zephyr_library_sources_ifdef(CONFIG_RESET_RPI_PICO reset_rpi_pico.c) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index fc53589998a..0211fcac8c0 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -27,4 +27,6 @@ config RESET_INIT_PRIORITY comment "Reset Controller Drivers" +rsource "Kconfig.rpi_pico" + endif # RESET diff --git a/drivers/reset/Kconfig.rpi_pico b/drivers/reset/Kconfig.rpi_pico new file mode 100644 index 00000000000..f5e4b969a30 --- /dev/null +++ b/drivers/reset/Kconfig.rpi_pico @@ -0,0 +1,9 @@ +# Copyright (c) 2022 Andrei-Edward Popa +# SPDX-License-Identifier: Apache-2.0 + +# Workaround for not being able to have commas in macro arguments +DT_COMPAT_RPI_PICO_RESET := raspberrypi,pico-reset + +config RESET_RPI_PICO + bool "Raspberry Pi Reset Controller driver" + default $(dt_compat_enabled,$(DT_COMPAT_RPI_PICO_RESET)) diff --git a/drivers/reset/reset_rpi_pico.c b/drivers/reset/reset_rpi_pico.c new file mode 100644 index 00000000000..3550cbd3efa --- /dev/null +++ b/drivers/reset/reset_rpi_pico.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2022 Andrei-Edward Popa + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT raspberrypi_pico_reset + +#include +#include + +struct reset_rpi_config { + DEVICE_MMIO_ROM; + uint8_t reg_width; + uint8_t active_low; + uintptr_t base_address; +}; + +static int reset_rpi_read_register(const struct device *dev, uint16_t offset, uint32_t *value) +{ + const struct reset_rpi_config *config = dev->config; + uint32_t base_address = config->base_address; + + switch (config->reg_width) { + case 1: + *value = sys_read8(base_address + offset); + break; + case 2: + *value = sys_read16(base_address + offset); + break; + case 4: + *value = sys_read32(base_address + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int reset_rpi_write_register(const struct device *dev, uint16_t offset, uint32_t value) +{ + const struct reset_rpi_config *config = dev->config; + uint32_t base_address = config->base_address; + + switch (config->reg_width) { + case 1: + sys_write8(value, base_address + offset); + break; + case 2: + sys_write16(value, base_address + offset); + break; + case 4: + sys_write32(value, base_address + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int reset_rpi_status(const struct device *dev, uint32_t id, uint8_t *status) +{ + const struct reset_rpi_config *config = dev->config; + uint16_t offset; + uint32_t value; + uint8_t regbit; + int ret; + + offset = id / (config->reg_width * CHAR_BIT); + regbit = id % (config->reg_width * CHAR_BIT); + + ret = reset_rpi_read_register(dev, offset, &value); + if (ret) { + return ret; + } + + *status = !(value & BIT(regbit)) ^ !config->active_low; + + return ret; +} + +static int reset_rpi_update(const struct device *dev, uint32_t id, uint8_t assert) +{ + const struct reset_rpi_config *config = dev->config; + uint16_t offset; + uint32_t value; + uint8_t regbit; + int ret; + + offset = id / (config->reg_width * CHAR_BIT); + regbit = id % (config->reg_width * CHAR_BIT); + + ret = reset_rpi_read_register(dev, offset, &value); + if (ret) { + return ret; + } + + if (assert ^ config->active_low) { + value |= BIT(regbit); + } else { + value &= ~BIT(regbit); + } + + return reset_rpi_write_register(dev, offset, value); +} + +static int reset_rpi_assert(const struct device *dev, uint32_t id) +{ + return reset_rpi_update(dev, id, 1); +} + +static int reset_rpi_deassert(const struct device *dev, uint32_t id) +{ + return reset_rpi_update(dev, id, 0); +} + +static int reset_rpi_toggle(const struct device *dev, uint32_t id) +{ + int ret; + + ret = reset_rpi_assert(dev, id); + if (ret) { + return ret; + } + + return reset_rpi_deassert(dev, id); +} + +static int reset_rpi_init(const struct device *dev) +{ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + return 0; +} + +static const struct reset_driver_api reset_rpi_driver_api = { + .status = reset_rpi_status, + .assert = reset_rpi_assert, + .deassert = reset_rpi_deassert, + .toggle = reset_rpi_toggle, +}; + +#define RPI_RESET_INIT(idx) \ + static const struct reset_rpi_config reset_rpi_config_##idx = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(idx)), \ + .reg_width = DT_INST_PROP_OR(idx, reg_width, 4), \ + .active_low = DT_INST_PROP_OR(idx, active_low, 0), \ + .base_address = DT_INST_REG_ADDR(idx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, reset_rpi_init, \ + NULL, NULL, \ + &reset_rpi_config_##idx, PRE_KERNEL_1, \ + CONFIG_RESET_INIT_PRIORITY, \ + &reset_rpi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RPI_RESET_INIT);