/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2023 Lin Chunzhi */ #include #include #include #include #include #include #include #include #include #define MANGO_BOARD_TYPE_MASK 0x80 #define REG_BOARD_TYPE 0x00 #define REG_CMD 0x03 #define CMD_POWEROFF 0x02 #define CMD_RESET 0x03 #define CMD_REBOOT 0x07 static struct i2c_adapter *mcu_adapter = NULL; static uint32_t mcu_reg = 0; static int sg2042_mcu_reset_check(u32 type, u32 reason) { switch (type) { case SBI_SRST_RESET_TYPE_SHUTDOWN: return 1; case SBI_SRST_RESET_TYPE_COLD_REBOOT: case SBI_SRST_RESET_TYPE_WARM_REBOOT: return 255; } return 0; } static void sg2042_mcu_reset(u32 type, u32 reason) { switch (type) { case SBI_SRST_RESET_TYPE_SHUTDOWN: i2c_adapter_reg_write(mcu_adapter, mcu_reg, REG_CMD, CMD_POWEROFF); break; case SBI_SRST_RESET_TYPE_COLD_REBOOT: case SBI_SRST_RESET_TYPE_WARM_REBOOT: i2c_adapter_reg_write(mcu_adapter, mcu_reg, REG_CMD, CMD_REBOOT); break; } } static struct sbi_system_reset_device sg2042_mcu_reset_device = { .name = "sg2042-mcu-reset", .system_reset_check = sg2042_mcu_reset_check, .system_reset = sg2042_mcu_reset }; static int sg2042_mcu_reset_check_board(struct i2c_adapter *adap, uint32_t reg) { static uint8_t val; int ret; /* check board type */ ret = i2c_adapter_reg_read(adap, reg, REG_BOARD_TYPE, &val); if (ret) return ret; if (!(val & MANGO_BOARD_TYPE_MASK)) return SBI_ENODEV; return 0; } static int sg2042_mcu_reset_init(void *fdt, int nodeoff, const struct fdt_match *match) { int ret, i2c_bus; uint64_t addr; ret = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL); if (ret) return ret; mcu_reg = addr; i2c_bus = fdt_parent_offset(fdt, nodeoff); if (i2c_bus < 0) return i2c_bus; ret = fdt_i2c_adapter_get(fdt, i2c_bus, &mcu_adapter); if (ret) return ret; ret = sg2042_mcu_reset_check_board(mcu_adapter, mcu_reg); sbi_system_reset_add_device(&sg2042_mcu_reset_device); return 0; } static const struct fdt_match sg2042_mcu_reset_match[] = { { .compatible = "sophgo,sg2042-hwmon-mcu", .data = (void *)true}, { }, }; struct fdt_reset fdt_reset_sg2042_mcu = { .match_table = sg2042_mcu_reset_match, .init = sg2042_mcu_reset_init, };