zephyr/drivers/hwinfo/hwinfo_silabs_series2.c
Aksel Skauge Mellbye e77ea215bd drivers: hwinfo: silabs: Add hwinfo driver for Series 2
Add hwinfo driver for Silicon Labs Series 2 devices. The driver
is separate from the Series 0/1 Gecko driver because the available
reset causes are completely different.

Signed-off-by: Aksel Skauge Mellbye <aksel.mellbye@silabs.com>
2025-01-14 13:26:23 +01:00

124 lines
3 KiB
C

/*
* Copyright (c) 2025 Silicon Laboratories Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/hwinfo.h>
#include <zephyr/sys/byteorder.h>
#include <string.h>
#include <em_system.h>
#include <em_rmu.h>
/* Ensure that all possible reset causes have a definition */
#ifndef EMU_RSTCAUSE_BOOSTON
#define EMU_RSTCAUSE_BOOSTON 0
#endif
#ifndef EMU_RSTCAUSE_WDOG1
#define EMU_RSTCAUSE_WDOG1 0
#endif
#ifndef EMU_RSTCAUSE_IOVDD1BOD
#define EMU_RSTCAUSE_IOVDD1BOD 0
#endif
#ifndef EMU_RSTCAUSE_IOVDD2BOD
#define EMU_RSTCAUSE_IOVDD2BOD 0
#endif
#ifndef EMU_RSTCAUSE_SETAMPER
#define EMU_RSTCAUSE_SETAMPER 0
#endif
#ifndef EMU_RSTCAUSE_SESYSREQ
#define EMU_RSTCAUSE_SESYSREQ 0
#endif
#ifndef EMU_RSTCAUSE_SELOCKUP
#define EMU_RSTCAUSE_SELOCKUP 0
#endif
#ifndef EMU_RSTCAUSE_DCI
#define EMU_RSTCAUSE_DCI 0
#endif
/* The Zephyr API expects hwinfo_get_reset_cause() to return 0 after hwinfo_clear_reset_cause() has
* been called. This matches the hardware behavior on Series 2, but not the HAL API. The HAL stores
* the reset cause upon first read, and returns this cached value on subsequent calls to the API
* to allow multiple subsystems to read the reset cause despite it having been cleared in hardware
* already. Emulate the hardware behavior while staying compatible with other users of the HAL API
* by keeping track of whether the reset cause should be considered cleared or not ourselves.
*/
static bool reset_cleared;
ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length)
{
uint64_t unique_id = sys_cpu_to_be64(SYSTEM_GetUnique());
if (length > sizeof(unique_id)) {
length = sizeof(unique_id);
}
memcpy(buffer, &unique_id, length);
return length;
}
int z_impl_hwinfo_get_reset_cause(uint32_t *cause)
{
uint32_t flags = 0;
uint32_t rmu = RMU_ResetCauseGet();
if (reset_cleared) {
*cause = 0;
return 0;
}
if (rmu & EMU_RSTCAUSE_POR) {
flags |= RESET_POR;
}
if (rmu & EMU_RSTCAUSE_PIN) {
flags |= RESET_PIN;
}
if (rmu & (EMU_RSTCAUSE_EM4 | EMU_RSTCAUSE_BOOSTON)) {
flags |= RESET_LOW_POWER_WAKE;
}
if (rmu & (EMU_RSTCAUSE_WDOG0 | EMU_RSTCAUSE_WDOG1)) {
flags |= RESET_WATCHDOG;
}
if (rmu & EMU_RSTCAUSE_LOCKUP) {
flags |= RESET_CPU_LOCKUP;
}
if (rmu & EMU_RSTCAUSE_SYSREQ) {
flags |= RESET_SOFTWARE;
}
if (rmu & (EMU_RSTCAUSE_DVDDBOD | EMU_RSTCAUSE_DVDDLEBOD | EMU_RSTCAUSE_DECBOD |
EMU_RSTCAUSE_AVDDBOD | EMU_RSTCAUSE_IOVDD0BOD |
EMU_RSTCAUSE_IOVDD1BOD | EMU_RSTCAUSE_IOVDD2BOD)) {
flags |= RESET_BROWNOUT;
}
if (rmu & (EMU_RSTCAUSE_SETAMPER | EMU_RSTCAUSE_SESYSREQ |
EMU_RSTCAUSE_SELOCKUP | EMU_RSTCAUSE_DCI)) {
flags |= RESET_SECURITY;
}
*cause = flags;
return 0;
}
int z_impl_hwinfo_clear_reset_cause(void)
{
RMU_ResetCauseClear();
reset_cleared = true;
return 0;
}
int z_impl_hwinfo_get_supported_reset_cause(uint32_t *supported)
{
*supported = RESET_PIN | RESET_SOFTWARE | RESET_BROWNOUT | RESET_POR | RESET_WATCHDOG |
RESET_SECURITY | RESET_LOW_POWER_WAKE | RESET_CPU_LOCKUP;
return 0;
}