zephyr/drivers/hwinfo/hwinfo_andes.c
Wei-Tai Lee 5f6ceefb8e drivers: hwinfo: andes: Improve hwinfo_andes driver
Check the driver's readiness at boot and in each
function that depends on the syscon driver.

Signed-off-by: Wei-Tai Lee <wtlee@andestech.com>
2023-07-17 13:19:37 +00:00

124 lines
2.2 KiB
C

/*
* Copyright (c) 2022 Andes Technology Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <zephyr/drivers/hwinfo.h>
#include <zephyr/drivers/syscon.h>
#include <string.h>
#include <zephyr/sys/byteorder.h>
/*
* SMU(System Management Unit) Registers for hwinfo driver
*/
/* Register offset*/
#define SMU_SYSTEMVER 0x00
#define SMU_WRSR 0x10
/* Wake-Up and Reset Status Register bitmask */
#define SMU_WRSR_APOR BIT(0)
#define SMU_WRSR_MPOR BIT(1)
#define SMU_WRSR_HW BIT(2)
#define SMU_WRSR_WDT BIT(3)
#define SMU_WRSR_SW BIT(4)
#define ANDES_RESET_STATUS_MASK BIT_MASK(5)
static const struct device *const syscon_dev =
DEVICE_DT_GET(DT_NODELABEL(syscon));
ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length)
{
int ret = 0;
uint8_t id[3];
uint32_t ver;
if (!device_is_ready(syscon_dev)) {
return -ENODEV;
}
ret = syscon_read_reg(syscon_dev, SMU_SYSTEMVER, &ver);
if (ret < 0) {
return ret;
}
if (length > sizeof(id)) {
length = sizeof(id);
}
sys_put_le24(ver, id);
memcpy(buffer, id, length);
return length;
}
int z_impl_hwinfo_get_reset_cause(uint32_t *cause)
{
int ret = 0;
uint32_t reason, flags = 0;
if (!device_is_ready(syscon_dev)) {
return -ENODEV;
}
ret = syscon_read_reg(syscon_dev, SMU_WRSR, &reason);
if (ret < 0) {
return ret;
}
if (reason & SMU_WRSR_APOR) {
flags |= RESET_POR;
}
if (reason & SMU_WRSR_MPOR) {
flags |= RESET_POR;
}
if (reason & SMU_WRSR_HW) {
flags |= RESET_PIN;
}
if (reason & SMU_WRSR_WDT) {
flags |= RESET_WATCHDOG;
}
if (reason & SMU_WRSR_SW) {
flags |= RESET_SOFTWARE;
}
*cause = flags;
return 0;
}
int z_impl_hwinfo_clear_reset_cause(void)
{
int ret = 0;
uint32_t reason;
if (!device_is_ready(syscon_dev)) {
return -ENODEV;
}
ret = syscon_write_reg(syscon_dev, SMU_WRSR, ANDES_RESET_STATUS_MASK);
if (ret < 0) {
return ret;
}
do {
ret = syscon_read_reg(syscon_dev, SMU_WRSR, &reason);
} while ((reason & ANDES_RESET_STATUS_MASK) && (!ret));
return ret;
}
int z_impl_hwinfo_get_supported_reset_cause(uint32_t *supported)
{
*supported = (RESET_PIN
| RESET_WATCHDOG
| RESET_SOFTWARE
| RESET_POR);
return 0;
}