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_ */