diff --git a/Makefile b/Makefile index 570d18f..e5aae46 100755 --- a/Makefile +++ b/Makefile @@ -53,6 +53,7 @@ OBJS = $(addprefix $(BUILD)/$(TARGET)/, \ ini.o \ ianos.o \ smmu.o \ + max77620-rtc.o \ ) OBJS += $(addprefix $(BUILD)/$(TARGET)/, \ diff --git a/bootloader/main.c b/bootloader/main.c index 029fd07..bca9874 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -31,6 +31,7 @@ #include "mem/heap.h" #include "mem/sdram.h" #include "power/max77620.h" +#include "rtc/max77620-rtc.h" #include "soc/hw_init.h" #include "soc/i2c.h" #include "soc/pmc.h" @@ -229,6 +230,10 @@ void reboot_rcm() void power_off() { sd_unmount(); + + // Stop the alarm, in case we injected and powered off too fast. + max77620_rtc_stop_alarm(); + #ifdef MENU_LOGO_ENABLE free(Kc_MENU_LOGO); #endif //MENU_LOGO_ENABLE @@ -243,6 +248,10 @@ void check_power_off_from_hos() if (hosWakeup & MAX77620_IRQ_TOP_RTC_MASK) { sd_unmount(); + + // Stop the alarm, in case we injected too fast. + max77620_rtc_stop_alarm(); + if (h_cfg.autohosoff == 1) { gfx_clear_grey(&gfx_ctxt, 0x1B); diff --git a/bootloader/rtc/max77620-rtc.c b/bootloader/rtc/max77620-rtc.c new file mode 100644 index 0000000..85895af --- /dev/null +++ b/bootloader/rtc/max77620-rtc.c @@ -0,0 +1,77 @@ +/* + * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "max77620-rtc.h" +#include "../soc/i2c.h" +#include "../utils/util.h" + +void max77620_rtc_get_time(rtc_time_t *time) +{ + u8 val = 0; + + // Update RTC regs from RTC clock. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE); + + // Get control reg config. + val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG); + // TODO: Check for binary format also? + + // Get time. + time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F; + time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; + + time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F; + + if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK) + time->hour = (time->hour & 0xF) + 12; + + // Get day of week. 1: Monday to 7: Sunday. + time->weekday = 0; + val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG); + for (int i = 0; i < 8; i++) + { + time->weekday++; + if (val & 1) + break; + val >>= 1; + } + + // Get date. + time->date = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; + time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1; + time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000; +} + +void max77620_rtc_stop_alarm() +{ + u8 val = 0; + + // Update RTC regs from RTC clock. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE); + + // Stop alarm for both ALARM1 and ALARM2. Horizon uses ALARM2. + for (int i = 0; i < (MAX77620_RTC_NR_TIME_REGS * 2); i++) + { + val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i); + val &= ~MAX77620_RTC_ALARM_EN_MASK; + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i, val); + } + + // Update RTC clock from RTC regs. + i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE); +} diff --git a/bootloader/rtc/max77620-rtc.h b/bootloader/rtc/max77620-rtc.h new file mode 100644 index 0000000..756e67c --- /dev/null +++ b/bootloader/rtc/max77620-rtc.h @@ -0,0 +1,75 @@ +/* + * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC + * + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _MFD_MAX77620_RTC_H_ +#define _MFD_MAX77620_RTC_H_ + +#include "../utils/types.h" + +#define MAX77620_RTC_I2C_ADDR 0x68 + +#define MAX77620_RTC_NR_TIME_REGS 7 + +#define MAX77620_RTC_CONTROLM_REG 0x02 +#define MAX77620_RTC_CONTROL_REG 0x03 +#define MAX77620_RTC_BIN_FORMAT (1 << 0) +#define MAX77620_RTC_24H (1 << 1) + +#define MAX77620_RTC_UPDATE0_REG 0x04 +#define MAX77620_RTC_WRITE_UPDATE (1 << 0) +#define MAX77620_RTC_READ_UPDATE (1 << 4) + +#define MAX77620_RTC_SEC_REG 0x07 +#define MAX77620_RTC_MIN_REG 0x08 +#define MAX77620_RTC_HOUR_REG 0x09 +#define MAX77620_RTC_HOUR_PM_MASK (1 << 6) +#define MAX77620_RTC_WEEKDAY_REG 0x0A +#define MAX77620_RTC_MONTH_REG 0x0B +#define MAX77620_RTC_YEAR_REG 0x0C +#define MAX77620_RTC_DATE_REG 0x0D + +#define MAX77620_ALARM1_SEC_REG 0x0E +#define MAX77620_ALARM1_MIN_REG 0x0F +#define MAX77620_ALARM1_HOUR_REG 0x10 +#define MAX77620_ALARM1_WEEKDAY_REG 0x11 +#define MAX77620_ALARM1_MONTH_REG 0x12 +#define MAX77620_ALARM1_YEAR_REG 0x13 +#define MAX77620_ALARM1_DATE_REG 0x14 +#define MAX77620_ALARM2_SEC_REG 0x15 +#define MAX77620_ALARM2_MIN_REG 0x16 +#define MAX77620_ALARM2_HOUR_REG 0x17 +#define MAX77620_ALARM2_WEEKDAY_REG 0x18 +#define MAX77620_ALARM2_MONTH_REG 0x19 +#define MAX77620_ALARM2_YEAR_REG 0x1A +#define MAX77620_ALARM2_DATE_REG 0x1B +#define MAX77620_RTC_ALARM_EN_MASK (1 << 7) + +typedef struct _rtc_time_t { + u8 weekday; + u8 sec; + u8 min; + u8 hour; + u8 date; + u8 month; + u16 year; +} rtc_time_t; + +void max77620_rtc_get_time(rtc_time_t *time); +void max77620_rtc_stop_alarm(); + +#endif /* _MFD_MAX77620_RTC_H_ */