1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <platsupport/mach/pmic_rtc.h> 14#include <platsupport/delay.h> 15#include "../../services.h" 16#include <utils/util.h> 17 18#define RTCREG_INTSTAT 0x00 19#define RTCREG_INTMASK 0x01 20#define RTCREG_CTRLWMASK 0x02 21#define RTCREG_CTRL 0x03 22#define RTCREG_UPDATE 0x04 23#define RTCREG_WATCHDOG 0x06 24 25#define RTCREG_TIME 0x07 26#define RTCREG_ALARM1 0x0E 27#define RTCREG_ALARM(id) (RTCREG_ALARM1 + (id) * sizeof(struct rtc_time)) 28 29#define RTC_NALARMS 2 30 31/* RTCREG_INTSTAT, RTCREG_INTMASK */ 32#define RTCINT(x) ((x) & 0x3f) 33#define RTCINT_READY (1U << 4) 34/* RTCREG_CTRLWMASK, RTCREG_CTRL */ 35#define RTCCTRL_24HOUR (1U << 1) 36#define RTCCTRL_BCD (1U << 0) 37/* RTCREG_UPDATE */ 38#define RTCUPDATE_READ (1U << 4) 39#define RTCUPDATE_WRITE (1U << 0) 40/* RTCREG_WATCHDOG */ 41#define RTCWD_SMPL_EN (1U << 7) 42#define RTCWD_WDT_EN (1U << 6) 43#define RTCWD_SMPL_CFG(x) ((x) << 2) 44#define RTCWD_WDT_CFG(x) ((x) << 0) 45 46/* We can set a 24 hour value for the time, but the RTC always gives us back 47 * flag for AM/PM */ 48#define RTC_HOUR_PM (1U << 6) 49 50static int 51id_valid(pmic_rtc_t* dev, int id) 52{ 53 return id >= 0 && id < pmic_rtc_nalarms(dev); 54} 55 56static int 57pmic_rtc_reg_read(pmic_rtc_t* dev, uint8_t reg, void* data, int count) 58{ 59 return i2c_kvslave_read(&dev->kvslave, reg, data, count); 60} 61 62static int 63pmic_rtc_reg_write(pmic_rtc_t* dev, uint8_t reg, const void* data, int count) 64{ 65 return i2c_kvslave_write(&dev->kvslave, reg, data, count); 66} 67 68static int 69pmic_rtc_update(pmic_rtc_t* dev, uint8_t flag) 70{ 71 int ret; 72 73 /* Write to the update register */ 74 ret = pmic_rtc_reg_write(dev, RTCREG_UPDATE, &flag, 1); 75 if (ret != 1) { 76 ZF_LOGD("Bus error"); 77 return -1; 78 } 79 /* Wait for completion */ 80 ps_mdelay(16); 81 return 0; 82} 83 84static int 85pmic_rtc_set_tval(pmic_rtc_t* dev, int base, const struct rtc_time* time) 86{ 87 int count; 88 count = pmic_rtc_reg_write(dev, base, time, sizeof(*time)); 89 return !(count == sizeof(*time)); 90} 91 92static int 93pmic_rtc_get_tval(pmic_rtc_t* dev, int base, struct rtc_time* time) 94{ 95 int count; 96 count = pmic_rtc_reg_read(dev, base, time, sizeof(*time)); 97 time->hour &= ~RTC_HOUR_PM; 98 return !(count == sizeof(*time)); 99} 100 101int 102pmic_rtc_init(i2c_bus_t* i2c, pmic_rtc_t* pmic_rtc) 103{ 104 uint8_t data[7]; 105 int ret; 106 ret = i2c_slave_init(i2c, MAX77686RTC_BUSADDR, 107 I2C_SLAVE_ADDR_7BIT, I2C_SLAVE_SPEED_FAST, 108 0, &pmic_rtc->i2c_slave); 109 if (ret) { 110 ZF_LOGD("Failed to register I2C slave"); 111 return -1; 112 } 113 114 ret = i2c_kvslave_init(&pmic_rtc->i2c_slave, 115 LITTLE8, LITTLE8, 116 &pmic_rtc->kvslave); 117 if (ret) { 118 ZF_LOGD("Failed to initialize I2C KV-slave lib instance."); 119 return -1; 120 } 121 122 data[RTCREG_INTSTAT ] = 0x00; 123 data[RTCREG_INTMASK ] = 0x3F; 124 data[RTCREG_CTRLWMASK] = RTCCTRL_24HOUR | RTCCTRL_BCD; 125 data[RTCREG_CTRL ] = RTCCTRL_24HOUR; 126 data[RTCREG_UPDATE ] = 0x00; 127 data[RTCREG_WATCHDOG ] = 0x00; 128 ret = pmic_rtc_reg_write(pmic_rtc, RTCREG_INTSTAT, data, sizeof(data)); 129 if (ret != sizeof(data)) { 130 ZF_LOGD("Bus error"); 131 return -1; 132 } 133 134 return pmic_rtc_update(pmic_rtc, RTCUPDATE_WRITE); 135} 136 137int 138pmic_rtc_get_time(pmic_rtc_t* pmic_rtc, struct rtc_time* time) 139{ 140 if (pmic_rtc_update(pmic_rtc, RTCUPDATE_READ)) { 141 return -1; 142 } 143 return pmic_rtc_get_tval(pmic_rtc, RTCREG_TIME, time); 144} 145 146int 147pmic_rtc_set_time(pmic_rtc_t* pmic_rtc, const struct rtc_time* time) 148{ 149 if (pmic_rtc_set_tval(pmic_rtc, RTCREG_TIME, time)) { 150 return -1; 151 } 152 return pmic_rtc_update(pmic_rtc, RTCUPDATE_WRITE); 153} 154 155int 156pmic_rtc_nalarms(pmic_rtc_t* pmic_rtc) 157{ 158 return RTC_NALARMS; 159} 160 161int 162pmic_rtc_get_alarm(pmic_rtc_t* pmic_rtc, int id, struct rtc_time* alarm) 163{ 164 if (!id_valid(pmic_rtc, id)) { 165 return -1; 166 } 167 if (pmic_rtc_update(pmic_rtc, RTCUPDATE_READ)) { 168 return -1; 169 } 170 return pmic_rtc_get_tval(pmic_rtc, RTCREG_ALARM(id), alarm); 171} 172 173int 174pmic_rtc_set_alarm(pmic_rtc_t* pmic_rtc, int id, const struct rtc_time* alarm) 175{ 176 if (!id_valid(pmic_rtc, id)) { 177 return -1; 178 } 179 if (pmic_rtc_set_tval(pmic_rtc, RTCREG_ALARM(id), alarm)) { 180 return -1; 181 } 182 return pmic_rtc_update(pmic_rtc, RTCUPDATE_WRITE); 183} 184