/* Reflow Oven Controller * * Copyright (C) 2020 Mario Hüttel * * This file is part of the Reflow Oven Controller Project. * * The reflow oven controller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the reflow oven controller project. * If not, see . */ #include #include #include #include struct rcc_enable_count { volatile uint32_t *rcc_reg_addr; uint32_t enable_bit_cnt; uint8_t rcc_enable_bit_pos; }; #if RCC_ENABLE_MANAGER_STATIC static struct rcc_enable_count enable_count_list[RCC_ENABLE_MANAGER_COUNT] = {0}; #else #error "RCC manager with dynamic memory not implemented!" #endif #if RCC_ENABLE_MANAGER_STATIC static struct rcc_enable_count *search_enable_entry_in_list(volatile uint32_t *reg_addr, uint8_t bit_pos) { unsigned int i; struct rcc_enable_count *ret_element = NULL; struct rcc_enable_count *current_element; for (i = 0; i < COUNT_OF(enable_count_list); i++) { current_element = &enable_count_list[i]; /* Check if register address and bit position match */ if (reg_addr != current_element->rcc_reg_addr) continue; if (bit_pos != current_element->rcc_enable_bit_pos) continue; /* Found entry. Wohoo! */ ret_element = current_element; } return ret_element; } static struct rcc_enable_count *enable_entry_list_get_free_entry() { struct rcc_enable_count *ret_ptr = NULL; const int list_len = COUNT_OF(enable_count_list); int i; for (i = 0; i < list_len; i++) { if (enable_count_list[i].rcc_reg_addr == NULL) { ret_ptr = &enable_count_list[i]; /* Clear the count value to be safe */ ret_ptr->enable_bit_cnt = 0; break; } } return ret_ptr; } static void enable_entry_list_remove_entry(struct rcc_enable_count *entry) { if (!entry) return; entry->rcc_reg_addr = NULL; entry->enable_bit_cnt = 0; entry->rcc_enable_bit_pos = 0; } #endif int rcc_manager_enable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no) { int ret_val = 0; struct rcc_enable_count *entry; if (!rcc_enable_register || bit_no > 31) { return -1000; } /* Enable the clock in any case, no matter what follows */ *rcc_enable_register |= (1U<rcc_reg_addr = rcc_enable_register; entry->rcc_enable_bit_pos = bit_no; } /* Increment enable counter */ entry->enable_bit_cnt++; ret_error_code: return ret_val; } int rcc_manager_disable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no) { int ret_val = -1; struct rcc_enable_count *entry; if (!rcc_enable_register || bit_no > 31) { return -1000; } entry = search_enable_entry_in_list(rcc_enable_register, bit_no); /* If entry is found and has a count of zero, disable clock */ if (entry) { /* Found entry => Decrement count and delete if zero */ entry->enable_bit_cnt--; if (entry->enable_bit_cnt <= 0) { enable_entry_list_remove_entry(entry); /* Disable clock */ *rcc_enable_register &= ~(1U<CSR; if (rcc_csr & RCC_CSR_LPWRRSTF) ret |= RCC_RESET_SOURCE_LOW_POWER; if (rcc_csr & RCC_CSR_WWDGRSTF) ret |= RCC_RESET_SOURCE_WWD; if (rcc_csr & RCC_CSR_WDGRSTF) ret |= RCC_RESET_SOURCE_IWDG; if (rcc_csr & RCC_CSR_SFTRSTF) ret |= RCC_RESET_SOURCE_SOFTWARE; if (rcc_csr & RCC_CSR_PORRSTF) ret |= RCC_RESET_SOURCE_POWER_ON; if (rcc_csr & RCC_CSR_PADRSTF) ret |= RCC_RESET_SOURCE_PIN; if (rcc_csr & RCC_CSR_BORRSTF) ret |= RCC_RESET_BOR_POR; if (clear_flags) RCC->CSR |= RCC_CSR_RMVF; return ret; }