Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | /* wdt_xec.c - Microchip XEC watchdog driver */ /* * Copyright (c) 2019 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ #define LOG_LEVEL CONFIG_WDT_LOG_LEVEL #include <logging/log.h> LOG_MODULE_REGISTER(wdt_mchp_xec); #include <drivers/watchdog.h> #include <soc.h> #include <errno.h> #include <assert.h> #define WDT_XEC_REG_BASE \ ((WDT_Type *)(DT_INST_0_MICROCHIP_XEC_WATCHDOG_BASE_ADDRESS)) struct wdt_xec_data { wdt_callback_t cb; bool timeout_installed; }; DEVICE_DECLARE(wdt_xec); static int wdt_xec_setup(struct device *dev, u8_t options) { WDT_Type *wdt_regs = WDT_XEC_REG_BASE; struct wdt_xec_data *data = dev->driver_data; if (wdt_regs->CTRL & MCHP_WDT_CTRL_EN) { return -EBUSY; } if (!data->timeout_installed) { LOG_ERR("No valid WDT timeout installed"); return -EINVAL; } if (options & WDT_OPT_PAUSE_IN_SLEEP) { LOG_WRN("WDT_OPT_PAUSE_IN_SLEEP is not supported"); return -ENOTSUP; } if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { wdt_regs->CTRL |= MCHP_WDT_CTRL_JTAG_STALL_EN; } else { wdt_regs->CTRL &= ~MCHP_WDT_CTRL_JTAG_STALL_EN; } wdt_regs->CTRL |= MCHP_WDT_CTRL_EN; LOG_DBG("WDT Setup and enabled"); return 0; } static int wdt_xec_disable(struct device *dev) { WDT_Type *wdt_regs = WDT_XEC_REG_BASE; struct wdt_xec_data *data = dev->driver_data; if (!(wdt_regs->CTRL & MCHP_WDT_CTRL_EN)) { return -EALREADY; } wdt_regs->CTRL &= ~MCHP_WDT_CTRL_EN; data->timeout_installed = false; LOG_DBG("WDT Disabled"); return 0; } static int wdt_xec_install_timeout(struct device *dev, const struct wdt_timeout_cfg *config) { WDT_Type *wdt_regs = WDT_XEC_REG_BASE; struct wdt_xec_data *data = dev->driver_data; if (wdt_regs->CTRL & MCHP_WDT_CTRL_EN) { return -EBUSY; } if (config->window.min > 0U) { data->timeout_installed = false; return -EINVAL; } wdt_regs->LOAD = 0; data->cb = config->callback; if (data->cb) { wdt_regs->CTRL |= MCHP_WDT_CTRL_MODE_IRQ; wdt_regs->IEN |= MCHP_WDT_IEN_EVENT_IRQ_EN; LOG_DBG("WDT callback enabled"); } else { /* Setting WDT_FLAG_RESET_SOC or not will have no effect: * even after the cb, if anything is done, SoC will reset */ wdt_regs->CTRL &= ~MCHP_WDT_CTRL_MODE_IRQ; wdt_regs->IEN &= ~MCHP_WDT_IEN_EVENT_IRQ_EN; LOG_DBG("WDT Reset enabled"); } /* Since it almost takes 1ms to decrement the load register * (See datasheet 18.6.1.4: 33/32.768 KHz = 1.007ms) * Let's use the given window directly. */ wdt_regs->LOAD = config->window.max; data->timeout_installed = true; return 0; } static int wdt_xec_feed(struct device *dev, int channel_id) { WDT_Type *wdt_regs = WDT_XEC_REG_BASE; ARG_UNUSED(dev); ARG_UNUSED(channel_id); if (!(wdt_regs->CTRL & MCHP_WDT_CTRL_EN)) { return -EINVAL; } LOG_DBG("WDT Kicking"); wdt_regs->KICK = 1; return 0; } static void wdt_xec_isr(struct device *dev) { WDT_Type *wdt_regs = WDT_XEC_REG_BASE; struct wdt_xec_data *data = dev->driver_data; LOG_DBG("WDT ISR"); if (data->cb) { data->cb(dev, 0); } MCHP_GIRQ_SRC(MCHP_WDT_GIRQ) = MCHP_WDT_GIRQ_VAL; wdt_regs->IEN &= ~MCHP_WDT_IEN_EVENT_IRQ_EN; } static const struct wdt_driver_api wdt_xec_api = { .setup = wdt_xec_setup, .disable = wdt_xec_disable, .install_timeout = wdt_xec_install_timeout, .feed = wdt_xec_feed, }; static int wdt_xec_init(struct device *dev) { if (IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) { wdt_xec_disable(dev); } MCHP_GIRQ_ENSET(MCHP_WDT_GIRQ) = MCHP_WDT_GIRQ_VAL; IRQ_CONNECT(DT_INST_0_MICROCHIP_XEC_WATCHDOG_IRQ_0, DT_INST_0_MICROCHIP_XEC_WATCHDOG_IRQ_0_PRIORITY, wdt_xec_isr, DEVICE_GET(wdt_xec), 0); irq_enable(DT_INST_0_MICROCHIP_XEC_WATCHDOG_IRQ_0); return 0; } static struct wdt_xec_data wdt_xec_dev_data; DEVICE_AND_API_INIT(wdt_xec, DT_INST_0_MICROCHIP_XEC_WATCHDOG_LABEL, wdt_xec_init, &wdt_xec_dev_data, NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdt_xec_api); |