/* * Copyright (c) 2022 Andrei-Edward Popa * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT raspberrypi_pico_reset #include #include #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_line_assert(const struct device *dev, uint32_t id) { return reset_rpi_update(dev, id, 1); } static int reset_rpi_line_deassert(const struct device *dev, uint32_t id) { return reset_rpi_update(dev, id, 0); } static int reset_rpi_line_toggle(const struct device *dev, uint32_t id) { int ret; ret = reset_rpi_line_assert(dev, id); if (ret) { return ret; } return reset_rpi_line_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, .line_assert = reset_rpi_line_assert, .line_deassert = reset_rpi_line_deassert, .line_toggle = reset_rpi_line_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);