/* * Copyright (c) 2022 Nordic Semiconductor ASA * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT nordic_npm6001_wdt #include #include #include #include #include #include /* nPM6001 Watchdog related registers */ #define NPM6001_WDARMEDVALUE 0x54U #define NPM6001_WDARMEDSTROBE 0x55U #define NPM6001_WDTRIGGERVALUE0 0x56U #define NPM6001_WDTRIGGERVALUE1 0x57U #define NPM6001_WDTRIGGERVALUE2 0x58U #define NPM6001_WDDATASTROBE 0x5DU #define NPM6001_WDPWRUPVALUE 0x5EU #define NPM6001_WDPWRUPSTROBE 0x5FU #define NPM6001_WDKICK 0x60U #define NPM6001_WDREQPOWERDOWN 0x62U /* nPM6001 WDTRIGGERVALUEx ms/LSB, min/max values */ #define NPM6001_WDTRIGGERVALUE_MS_LSB 4000U #define NPM6001_WDTRIGGERVALUE_MIN 0x2U #define NPM6001_WDTRIGGERVALUE_MAX 0xFFFFFFU /* nPM6001 WDPWRUPVALUE fields */ #define NPM6001_WDPWRUPVALUE_OSC_ENABLE BIT(0) #define NPM6001_WDPWRUPVALUE_COUNTER_ENABLE BIT(1) #define NPM6001_WDPWRUPVALUE_LS_ENABLE BIT(2) struct wdt_npm6001_config { struct i2c_dt_spec bus; }; static int wdt_npm6001_setup(const struct device *dev, uint8_t options) { ARG_UNUSED(dev); ARG_UNUSED(options); return 0; } static int wdt_npm6001_disable(const struct device *dev) { const struct wdt_npm6001_config *config = dev->config; uint8_t buf[4] = {NPM6001_WDARMEDVALUE, 1U, NPM6001_WDARMEDSTROBE, 1U}; return i2c_write_dt(&config->bus, buf, sizeof(buf)); } static int wdt_npm6001_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *timeout) { const struct wdt_npm6001_config *config = dev->config; uint32_t window; uint8_t buf[2]; int ret; if (timeout->window.min != 0U) { return -EINVAL; } /* round-up timeout, e.g. 5s -> 8s */ window = (((timeout->window.max + NPM6001_WDTRIGGERVALUE_MS_LSB - 1U) / NPM6001_WDTRIGGERVALUE_MS_LSB) + 1U); if ((window < NPM6001_WDTRIGGERVALUE_MIN) || (window > NPM6001_WDTRIGGERVALUE_MAX)) { return -EINVAL; } /* enable OSC/COUNTER/LS */ buf[0] = NPM6001_WDPWRUPVALUE; buf[1] = NPM6001_WDPWRUPVALUE_OSC_ENABLE | NPM6001_WDPWRUPVALUE_COUNTER_ENABLE | NPM6001_WDPWRUPVALUE_LS_ENABLE; ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); if (ret < 0) { return ret; } buf[0] = NPM6001_WDPWRUPSTROBE; buf[1] = 1U; ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); if (ret < 0) { return ret; } /* write trigger value */ buf[0] = NPM6001_WDTRIGGERVALUE0; buf[1] = (uint8_t)window; ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); if (ret < 0) { return ret; } buf[0] = NPM6001_WDTRIGGERVALUE1; buf[1] = (uint8_t)(window >> 8U); ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); if (ret < 0) { return ret; } buf[0] = NPM6001_WDTRIGGERVALUE2; buf[1] = (uint8_t)(window >> 16U); ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); if (ret < 0) { return ret; } buf[0] = NPM6001_WDDATASTROBE; buf[1] = 1U; ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); if (ret < 0) { return ret; } /* arm watchdog & kick */ buf[0] = NPM6001_WDARMEDVALUE; buf[1] = 1U; ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); if (ret < 0) { return ret; } buf[0] = NPM6001_WDARMEDSTROBE; buf[1] = 1U; ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); if (ret < 0) { return ret; } buf[0] = NPM6001_WDKICK; buf[1] = 1U; ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); if (ret < 0) { return ret; } return 0; } static int wdt_npm6001_feed(const struct device *dev, int channel_id) { const struct wdt_npm6001_config *config = dev->config; uint8_t buf[2] = {NPM6001_WDKICK, 1U}; ARG_UNUSED(channel_id); return i2c_write_dt(&config->bus, buf, sizeof(buf)); } static const struct wdt_driver_api wdt_npm6001_api = { .setup = wdt_npm6001_setup, .disable = wdt_npm6001_disable, .install_timeout = wdt_npm6001_install_timeout, .feed = wdt_npm6001_feed, }; static int wdt_npm6001_init(const struct device *dev) { const struct wdt_npm6001_config *config = dev->config; if (!device_is_ready(config->bus.bus)) { return -ENODEV; } return 0; } #define WDT_NPM6001_DEFINE(n) \ static const struct wdt_npm6001_config wdt_npm6001_config##n = { \ .bus = I2C_DT_SPEC_GET(DT_INST_PARENT(n)), \ }; \ \ DEVICE_DT_INST_DEFINE(n, &wdt_npm6001_init, NULL, NULL, \ &wdt_npm6001_config##n, POST_KERNEL, \ CONFIG_WDT_NPM6001_INIT_PRIORITY, \ &wdt_npm6001_api); DT_INST_FOREACH_STATUS_OKAY(WDT_NPM6001_DEFINE)