MAX31341/2 RTC Driver
RtcBase.cpp
- Committer:
- Mahir Ozturk
- Date:
- 2019-04-10
- Revision:
- 0:1efa49a69ff8
File content as of revision 0:1efa49a69ff8:
/******************************************************************************* * Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of Maxim Integrated * Products, Inc. shall not be used except as stated in the Maxim Integrated * Products, Inc. Branding Policy. * * The mere transfer of this software does not imply any licenses * of trade secrets, proprietary technology, copyrights, patents, * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. ******************************************************************************* */ #include "RtcBase.h" #define pr_err(fmt, ...) if(1) printf(fmt " (%s:%d)\r\n", ## __VA_ARGS__, __func__, __LINE__) #define pr_debug(fmt, ...) if(0) printf(fmt " (%s:%d)\r\n", ## __VA_ARGS__, __func__, __LINE__) #define BCD2BIN(val) (((val) & 15) + ((val) >> 4) * 10) #define BIN2BCD(val) ((((val) / 10) << 4) + (val) % 10) #define POST_INTR_WORK_SIGNAL_ID 0x1 RtcBase::RtcBase(const regmap_t *regmap, I2C *i2c, PinName inta_pin = NC, PinName intb_pin = NC) { if (i2c == NULL) { pr_err("i2c object is invalid!"); while (1); } i2c_handler = i2c; this->regmap = regmap; sw_reset_release(); rtc_start(); irq_disable_all(); post_intr_work_thread = new Thread(); post_intr_work_thread->start(Callback<void()>(this, &RtcBase::post_interrupt_work)); if (inta_pin != NC) { this->inta_pin = new InterruptIn(inta_pin); this->inta_pin->fall(Callback<void()>(this, &RtcBase::interrupt_handler)); this->inta_pin->enable_irq(); } else { this->inta_pin = NULL; } if (intb_pin != NC) { this->intb_pin = new InterruptIn(intb_pin); this->intb_pin->fall(Callback<void()>(this, &RtcBase::interrupt_handler)); this->intb_pin->enable_irq(); } else { this->intb_pin = NULL; } } RtcBase::~RtcBase() { if (post_intr_work_thread) { delete post_intr_work_thread; } if (inta_pin) { delete inta_pin; } if (intb_pin) { delete intb_pin; } } int RtcBase::read_register(uint8_t reg, uint8_t *value, uint8_t len) { int ret; if (value == NULL) { pr_err("value is invalid!"); return -1; } ret = i2c_handler->write(MAX3134X_I2C_W, (const char *) ®, 1, true); if (ret != 0) { pr_err("i2c write failed with %d!", ret); return -1; } ret = i2c_handler->read(MAX3134X_I2C_R, (char *) value, len, false); if (ret < 0) { pr_err("i2c read failed with %d!", ret); return -1; } return 0; } int RtcBase::write_register(uint8_t reg, const uint8_t *value, uint8_t len) { int ret; uint8_t *buffer; if (value == NULL) { pr_err("value is invalid!"); return -1; } buffer = new uint8_t[1 + len]; buffer[0] = reg; memcpy(&buffer[1], value, len); ret = i2c_handler->write(MAX3134X_I2C_W, (const char *)buffer, 1 + len); if (ret != 0) { pr_err("i2c write failed with %d!", ret); } delete[] buffer; return ret; } int RtcBase::rtc_regs_to_time(struct tm *time, const rtc_time_regs_t *regs) { /* tm_sec seconds [0,61] */ time->tm_sec = BCD2BIN(regs->seconds.bcd.value); /* tm_min minutes [0,59] */ time->tm_min = BCD2BIN(regs->minutes.bcd.value); /* tm_hour hour [0,23] */ time->tm_hour = BCD2BIN(regs->hours.bcd.value); /* tm_wday day of week [0,6] (Sunday = 0) */ time->tm_wday = BCD2BIN(regs->day.bcd.value) - 1; /* tm_mday day of month [1,31] */ time->tm_mday = BCD2BIN(regs->date.bcd.value); /* tm_mon month of year [0,11] */ time->tm_mon = BCD2BIN(regs->month.bcd.value) - 1; /* tm_year years since 2000 */ if (regs->month.bits.century) { time->tm_year = BCD2BIN(regs->year.bcd.value) + 200; } else { time->tm_year = BCD2BIN(regs->year.bcd.value) + 100; } /* tm_yday day of year [0,365] */ time->tm_yday = 0; /* TODO */ /* tm_isdst daylight savings flag */ time->tm_isdst = 0; /* TODO */ return 0; } int RtcBase::time_to_rtc_regs(rtc_time_regs_t *regs, const struct tm *time) { /********************************************************* * +----------+------+---------------------------+-------+ * | Member | Type | Meaning | Range | * +----------+------+---------------------------+-------+ * | tm_sec | int | seconds after the minute | 0-61* | * | tm_min | int | minutes after the hour | 0-59 | * | tm_hour | int | hours since midnight | 0-23 | * | tm_mday | int | day of the month | 1-31 | * | tm_mon | int | months since January | 0-11 | * | tm_year | int | years since 1900 | | * | tm_wday | int | days since Sunday | 0-6 | * | tm_yday | int | days since January 1 | 0-365 | * | tm_isdst | int | Daylight Saving Time flag | | * +----------+------+---------------------------+-------+ * * tm_sec is generally 0-59. The extra range is to accommodate for leap * seconds in certain systems. *********************************************************/ regs->seconds.bcd.value = BIN2BCD(time->tm_sec); regs->minutes.bcd.value = BIN2BCD(time->tm_min); regs->hours.bcd.value= BIN2BCD(time->tm_hour); regs->day.bcd.value = BIN2BCD(time->tm_wday + 1); regs->date.bcd.value = BIN2BCD(time->tm_mday); regs->month.bcd.value = BIN2BCD(time->tm_mon + 1); if (time->tm_year >= 200) { regs->month.bits.century = 1; regs->year.bcd.value = BIN2BCD(time->tm_year - 200); } else if (time->tm_year >= 100) { regs->month.bits.century = 0; regs->year.bcd.value = BIN2BCD(time->tm_year - 100); } else { pr_err("Invalid set date!"); return -1; } return 0; } int RtcBase::get_time(struct tm *time) { rtc_time_regs_t time_regs; if (time == NULL) { pr_err("rtc_ctime is invalid!"); return -1; } if (read_register(regmap->seconds, (uint8_t *) &time_regs, sizeof(time_regs)) < 0) { pr_err("read time registers failed!"); return -1; } return rtc_regs_to_time(time, &time_regs); } int RtcBase::set_rtc_time() { config_reg2_t reg; /* Toggle Set_RTC bit to set RTC date */ if (read_register(regmap->config_reg2, (uint8_t *)®, 1) < 0) { pr_err("read time registers failed!"); return -1; } reg.bits.set_rtc = CONFIG_REG2_SET_RTC_RTCPRGM; if (write_register(regmap->config_reg2, (uint8_t *)®, 1) < 0) { pr_err("write config2 register failed!"); return -1; } /* SET_RTC bit should be kept high at least 10ms */ ThisThread::sleep_for(10); reg.bits.set_rtc = CONFIG_REG2_SET_RTC_RTCRUN; if (write_register(regmap->config_reg2, (uint8_t *)®, 1) < 0) { pr_err("write config2 register failed!"); return -1; } return 0; } int RtcBase::set_time(const struct tm *time) { rtc_time_regs_t time_regs; if (time == NULL) { pr_err("rtc_ctime is invalid!"); return -1; } time_to_rtc_regs(&time_regs, time); if (write_register(regmap->seconds, (const uint8_t *) &time_regs, sizeof(time_regs)) < 0) { pr_err("read time registers failed!"); return -1; } return set_rtc_time(); } int RtcBase::nvram_write(const uint8_t *buffer, int offset, int length) { int totlen; if (regmap->ram_start == REG_NOT_AVAILABLE) { pr_err("Device does not have NVRAM!"); return -1; } totlen = regmap->ram_end - regmap->ram_start + 1; if ((offset + length) > totlen) { return -1; } if (length == 0) { return 0; } if (write_register(regmap->ram_start + offset, buffer, length) < 0) { return -1; } return 0; } int RtcBase::nvram_read(uint8_t *buffer, int offset, int length) { int totlen; if (regmap->ram_start == REG_NOT_AVAILABLE) { pr_err("Device does not have NVRAM!"); return -1; } totlen = regmap->ram_end - regmap->ram_start + 1; if ((offset + length) > totlen) { return -1; } if (length == 0) { return -1; } if (read_register(regmap->ram_start + offset, buffer, length) < 0) { return -1; } return 0; } int RtcBase::nvram_size() { if ((regmap->ram_start == REG_NOT_AVAILABLE) || (regmap->ram_end == REG_NOT_AVAILABLE)) { return 0; } return regmap->ram_end - regmap->ram_start + 1; } int RtcBase::time_to_alarm_regs(alarm_regs_t ®s, const struct tm *alarm_time) { regs.sec.bcd.value = BIN2BCD(alarm_time->tm_sec); regs.min.bcd.value = BIN2BCD(alarm_time->tm_min); regs.hrs.bcd.value = BIN2BCD(alarm_time->tm_hour); if (regs.day_date.bits.dy_dt == 0) { /* Date match */ regs.day_date.bcd_date.value = BIN2BCD(alarm_time->tm_mday); } else { /* Day match */ regs.day_date.bcd_day.value = BIN2BCD(alarm_time->tm_wday); } regs.mon.bcd.value = BIN2BCD(alarm_time->tm_mon); return 0; } int RtcBase::alarm_regs_to_time(struct tm *alarm_time, const alarm_regs_t *regs) { alarm_time->tm_sec = BCD2BIN(regs->sec.bcd.value); alarm_time->tm_min = BCD2BIN(regs->min.bcd.value); alarm_time->tm_hour = BCD2BIN(regs->hrs.bcd.value); if (regs->day_date.bits.dy_dt == 0) { /* date */ alarm_time->tm_mday = BCD2BIN(regs->day_date.bcd_date.value); } else { /* day */ alarm_time->tm_wday = BCD2BIN(regs->day_date.bcd_day.value); } if (regmap->alm1_mon != REG_NOT_AVAILABLE) { alarm_time->tm_mon = BCD2BIN(regs->mon.bcd.value) - 1; } if (regmap->alm1_year != REG_NOT_AVAILABLE) { alarm_time->tm_year = BCD2BIN(regs->year.bcd.value) + 100; /* XXX no century bit */ } return 0; } int RtcBase::set_alarm_period(alarm_no_t alarm_no, alarm_regs_t ®s, alarm_period_t period) { regs.sec.bits.a1m1 = 1; regs.min.bits.a1m2 = 1; regs.hrs.bits.a1m3 = 1; regs.day_date.bits.a1m4 = 1; regs.mon.bits.a1m5 = 1; regs.mon.bits.a1m6 = 1; regs.day_date.bits.dy_dt = 1; switch (period) { case ALARM_PERIOD_ONETIME: if ((alarm_no == ALARM2) || (regmap->alm1_year == REG_NOT_AVAILABLE)) { /* not supported! */ return -1; } regs.mon.bits.a1m6 = 0; case ALARM_PERIOD_YEARLY: if ((alarm_no == ALARM2) || (regmap->alm1_mon == REG_NOT_AVAILABLE)) { /* not supported! */ return -1; } regs.mon.bits.a1m5 = 0; case ALARM_PERIOD_MONTHLY: regs.day_date.bits.dy_dt = 0; case ALARM_PERIOD_WEEKLY: regs.day_date.bits.a1m4 = 0; case ALARM_PERIOD_DAILY: regs.hrs.bits.a1m3 = 0; case ALARM_PERIOD_HOURLY: regs.min.bits.a1m2 = 0; case ALARM_PERIOD_EVERYMINUTE: regs.sec.bits.a1m1 = 0; case ALARM_PERIOD_EVERYSECOND: if ((alarm_no == ALARM2) && (period == ALARM_PERIOD_EVERYSECOND)) { return -1; /* Alarm2 does not support "once per second" alarm*/ } break; default: return -1; } return 0; } int RtcBase::set_alarm_regs(alarm_no_t alarm_no, const alarm_regs_t *regs) { uint8_t *ptr_regs = (uint8_t *)regs; uint8_t off = 0; uint8_t dev_ba; uint8_t len = sizeof(alarm_regs_t); if (alarm_no == ALARM1) { dev_ba = regmap->alm1_sec; if (regmap->alm1_mon == REG_NOT_AVAILABLE) len -= 2; /* discard mon & year registers */ } else { dev_ba = regmap->alm2_min; off = 1; /* starts from min register */ len -= 3; /* discard min, mon & sec registers */ } return write_register(dev_ba, &ptr_regs[off], len); } int RtcBase::get_alarm_regs(alarm_no_t alarm_no, alarm_regs_t *regs) { uint8_t *ptr_regs = (uint8_t *)regs; uint8_t off = 0; uint8_t dev_ba; uint8_t len = sizeof(alarm_regs_t); if (alarm_no == ALARM1) { dev_ba = regmap->alm1_sec; if (regmap->alm1_mon == REG_NOT_AVAILABLE) len -= 2; /* discard mon & year registers */ } else { regs->sec.raw = 0; /* zeroise second register for alarm2 */ dev_ba = regmap->alm2_min; off = 1; /* starts from min register (no sec register) */ len -= 2; /* discard mon & sec registers */ } return read_register(dev_ba, &ptr_regs[off], len); } int RtcBase::set_alarm(alarm_no_t alarm_no, const struct tm *alarm_time, alarm_period_t period) { int ret; alarm_regs_t regs; ret = set_alarm_period(alarm_no, regs, period); if (ret) { return ret; } /* Convert time structure to alarm registers */ ret = time_to_alarm_regs(regs, alarm_time); if (ret) { return ret; } ret = set_alarm_regs(alarm_no, ®s); if (ret) { return ret; } return 0; } int RtcBase::get_alarm(alarm_no_t alarm_no, struct tm *alarm_time, alarm_period_t *period, bool *is_enabled) { int ret; alarm_regs_t regs; uint8_t reg; ret = get_alarm_regs(alarm_no, ®s); if (ret) { return ret; } /* Convert alarm registers to time structure */ ret = alarm_regs_to_time(alarm_time, ®s); if (ret) { return ret; } *period = (alarm_no == ALARM1) ? ALARM_PERIOD_EVERYSECOND : ALARM_PERIOD_EVERYMINUTE; if ((alarm_no == ALARM1) && (regs.sec.bits.a1m1 == 0)) *period = ALARM_PERIOD_EVERYMINUTE; if (regs.min.bits.a1m2 == 0) *period = ALARM_PERIOD_HOURLY; if (regs.hrs.bits.a1m3 == 0) *period = ALARM_PERIOD_DAILY; if (regs.day_date.bits.a1m4 == 0) *period = ALARM_PERIOD_WEEKLY; if (regs.day_date.bits.dy_dt == 0) *period = ALARM_PERIOD_MONTHLY; if ((alarm_no == ALARM1) && (regmap->alm1_mon != REG_NOT_AVAILABLE) && (regs.mon.bits.a1m5 == 0)) *period = ALARM_PERIOD_YEARLY; if ((alarm_no == ALARM1) && (regmap->alm1_mon != REG_NOT_AVAILABLE) && (regs.mon.bits.a1m6 == 0)) *period = ALARM_PERIOD_ONETIME; ret = read_register(regmap->int_en_reg, (uint8_t *)®, 1); if (ret) { return ret; } if (alarm_no == ALARM1) { *is_enabled = (reg & (1 << INTR_ID_ALARM1)) != 0; } else { *is_enabled = (reg & (1 << INTR_ID_ALARM2)) != 0; } return 0; } int RtcBase::set_power_mgmt_mode(power_mgmt_mode_t mode) { int ret; pwr_mgmt_reg_t reg; if (regmap->pwr_mgmt_reg == REG_NOT_AVAILABLE) { pr_err("Device does not support power mgmt!"); return -1; } ret = read_register(regmap->pwr_mgmt_reg, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.d_mode = mode; ret = write_register(regmap->pwr_mgmt_reg, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::comparator_threshold_level(comp_thresh_t th) { int ret; config_reg2_t reg; if (regmap->pwr_mgmt_reg == REG_NOT_AVAILABLE) { pr_err("Device does not support analog comparator!"); return -1; } ret = read_register(regmap->config_reg2, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.bref = th; ret = write_register(regmap->config_reg2, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::supply_select(power_mgmt_supply_t supply) { int ret; pwr_mgmt_reg_t reg; if (regmap->pwr_mgmt_reg == REG_NOT_AVAILABLE) { pr_err("Device does not support power mgmt!"); return -1; } ret = read_register(regmap->pwr_mgmt_reg, (uint8_t *)®, 1); if (ret) { return ret; } switch (supply) { case POW_MGMT_SUPPLY_SEL_VCC: reg.bits.d_man_sel = 1; reg.bits.d_vback_sel = 0; break; case POW_MGMT_SUPPLY_SEL_AIN: reg.bits.d_man_sel = 1; reg.bits.d_vback_sel = 1; break; case POW_MGMT_SUPPLY_SEL_AUTO: default: reg.bits.d_man_sel = 0; break; } ret = write_register(regmap->pwr_mgmt_reg, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::trickle_charger_enable(trickle_charger_ohm_t res, bool diode) { int ret; struct { unsigned char ohm : 2; unsigned char diode : 1; unsigned char schottky : 1; unsigned char : 4; } reg; if (regmap->trickle_reg == REG_NOT_AVAILABLE) { /* trickle charger not supported! */ pr_err("Device does not support trickle charger!"); return -1; } reg.ohm = res; reg.diode = (diode) ? 1 : 0; reg.schottky = 1; /* always enabled */ ret = write_register(regmap->trickle_reg, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::trickle_charger_disable() { int ret; uint8_t reg; if (regmap->trickle_reg == REG_NOT_AVAILABLE) { /* trickle charger not supported! */ pr_err("Device does not support trickle charger!"); return -1; } reg = 0; ret = write_register(regmap->trickle_reg, ®, 1); if (ret) { return ret; } return 0; } int RtcBase::set_output_square_wave_frequency(square_wave_out_freq_t freq) { int ret; config_reg1_t reg; ret = read_register(regmap->config_reg1, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.rs = freq; ret = write_register(regmap->config_reg1, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::set_clock_sync_delay(sync_delay_t delay) { int ret; clock_sync_reg_t reg; ret = read_register(regmap->clock_sync_delay, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.sync_delay = delay; ret = write_register(regmap->clock_sync_delay, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::set_clkin_frequency(clkin_freq_t freq) { int ret; config_reg1_t reg; ret = read_register(regmap->config_reg1, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.clksel = freq; ret = write_register(regmap->config_reg1, (uint8_t *)®, 1); if (ret) { return ret; } if (freq == CLKIN_FREQ_1HZ) { ret = set_clock_sync_delay(SYNC_DLY_LESS_THAN_1SEC); } else { ret = set_clock_sync_delay(SYNC_DLY_LESS_THAN_100MS); } return ret; } int RtcBase::configure_intb_clkout_pin(config_intb_clkout_pin_t sel) { int ret; config_reg1_t reg; ret = read_register(regmap->config_reg1, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.intcn = (sel == CONFIGURE_PIN_AS_INTB) ? 1 : 0; ret = write_register(regmap->config_reg1, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::configure_inta_clkin_pin(config_inta_clkin_pin_t sel) { int ret; config_reg1_t reg; ret = read_register(regmap->config_reg1, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.eclk = (sel == CONFIGURE_PIN_AS_CLKIN) ? 1 : 0; ret = write_register(regmap->config_reg1, (uint8_t *)®, 1); if (ret) { return ret; } if (sel == CONFIGURE_PIN_AS_CLKIN) { /* Default synchronization delay for external clock mode */ ret = set_clock_sync_delay(SYNC_DLY_LESS_THAN_1SEC); } else { /* Synchronization delay for internal oscillator mode */ ret = set_clock_sync_delay(SYNC_DLY_LESS_THAN_20MS); } return ret; } int RtcBase::timer_init(uint8_t value, bool repeat, timer_freq_t freq) { int ret; timer_config_t reg_cfg; ret = read_register(regmap->timer_config, (uint8_t *)®_cfg, 1); if (ret) { return ret; } reg_cfg.bits.te = 0; /* timer is reset */ reg_cfg.bits.tpause = 1; /* timer is paused */ reg_cfg.bits.trpt = repeat ? 1 : 0; /* Timer repeat mode */ reg_cfg.bits.tfs = freq; /* Timer frequency */ ret = write_register(regmap->timer_config, (uint8_t *)®_cfg, 1); if (ret) { return ret; } ret = write_register(regmap->timer_init, (uint8_t *)&value, 1); if (ret) { return ret; } return 0; } uint8_t RtcBase::timer_get() { int ret; uint8_t reg; ret = read_register(regmap->timer_count, (uint8_t *)®, 1); if (ret) { return (uint8_t) - 1; } return reg; } int RtcBase::timer_start() { int ret; timer_config_t reg; ret = read_register(regmap->timer_config, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.te = 1; reg.bits.tpause = 0; ret = write_register(regmap->timer_config, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::timer_pause() { int ret; timer_config_t reg; ret = read_register(regmap->timer_config, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.te = 1; reg.bits.tpause = 1; ret = write_register(regmap->timer_config, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::timer_continue() { int ret; timer_config_t reg; ret = read_register(regmap->timer_config, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.te = 1; reg.bits.tpause = 0; ret = write_register(regmap->timer_config, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::timer_stop() { int ret; timer_config_t reg; ret = read_register(regmap->timer_config, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.te = 0; reg.bits.tpause = 1; ret = write_register(regmap->timer_config, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::data_retention_mode_config(int state) { int ret; config_reg1_t cfg1; config_reg2_t cfg2; ret = read_register(regmap->config_reg1, (uint8_t *)&cfg1, 1); if (ret) { return ret; } ret = read_register(regmap->config_reg2, (uint8_t *)&cfg2, 1); if (ret) { return ret; } if (state) { cfg1.bits.osconz = 1; cfg2.bits.data_reten = 1; } else { cfg1.bits.osconz = 0; cfg2.bits.data_reten = 0; } ret = write_register(regmap->config_reg1, (uint8_t *)&cfg1, 1); if (ret) { return ret; } ret = write_register(regmap->config_reg2, (uint8_t *)&cfg2, 1); if (ret) { return ret; } return 0; } int RtcBase::data_retention_mode_enter() { return data_retention_mode_config(1); } int RtcBase::data_retention_mode_exit() { return data_retention_mode_config(0); } int RtcBase::i2c_timeout_config(int enable) { int ret; config_reg2_t reg; ret = read_register(regmap->config_reg2, (uint8_t *)®, 1); if (ret) { return ret; } reg.bits.i2c_timeout = (enable) ? 1 : 0; ret = write_register(regmap->config_reg2, (uint8_t *)®, 1); if (ret) { return ret; } return 0; } int RtcBase::i2c_timeout_enable() { return i2c_timeout_config(1); } int RtcBase::i2c_timeout_disable() { return i2c_timeout_config(0); } int RtcBase::irq_enable(intr_id_t id) { int ret; uint8_t reg; ret = read_register(regmap->int_en_reg, ®, 1); if (ret) { return ret; } reg |= (1 << id); ret = write_register(regmap->int_en_reg, ®, 1); if (ret) { return ret; } return 0; } int RtcBase::irq_disable(intr_id_t id) { int ret; uint8_t reg; ret = read_register(regmap->int_en_reg, ®, 1); if (ret) { return ret; } reg &= ~(1 << id); ret = write_register(regmap->int_en_reg, ®, 1); if (ret) { return ret; } return 0; } int RtcBase::irq_disable_all() { int ret; uint8_t reg = 0; ret = write_register(regmap->int_en_reg, ®, 1); if (ret) { return ret; } return 0; } void RtcBase::set_intr_handler(intr_id_t id, interrupt_handler_function func, void *cb) { interrupt_handler_list[id].func = func; interrupt_handler_list[id].cb = cb; } void RtcBase::post_interrupt_work() { int ret; uint8_t reg, inten, mask; while (true) { Thread::signal_wait(POST_INTR_WORK_SIGNAL_ID); ret = read_register(regmap->int_status_reg, ®, 1); if (ret) { pr_err("Read interrupt status register failed!"); } ret = read_register(regmap->int_en_reg, &inten, 1); if (ret) { pr_err("Read interrupt enable register failed!"); } for (int i = 0; i < INTR_ID_END; i++) { mask = (1 << i); if ((reg & mask) && (inten & mask)) { if (interrupt_handler_list[i].func != NULL) { interrupt_handler_list[i].func(interrupt_handler_list[i].cb); } } } } } void RtcBase::interrupt_handler() { post_intr_work_thread->signal_set(POST_INTR_WORK_SIGNAL_ID); } int RtcBase::sw_reset_assert() { int ret; config_reg1_t config_reg1; ret = read_register(regmap->config_reg1, (uint8_t *) &config_reg1, 1); if (ret < 0) { pr_err("read_register failed!"); return ret; } config_reg1.bits.swrstn = 0; /* Put device in reset state */ ret = write_register(regmap->config_reg1, (const uint8_t *) &config_reg1, 1); if (ret < 0) { pr_err("read_register failed!"); return ret; } return 0; } int RtcBase::sw_reset_release() { int ret; config_reg1_t config_reg1; ret = read_register(regmap->config_reg1, (uint8_t *) &config_reg1, 1); if (ret < 0) { pr_err("read_register failed!"); return ret; } config_reg1.bits.swrstn = 1; /* Remove device from reset state */ ret = write_register(regmap->config_reg1, (const uint8_t *) &config_reg1, 1); if (ret < 0) { pr_err("read_register failed!"); return ret; } return 0; } int RtcBase::rtc_start() { int ret; config_reg1_t config_reg1; ret = read_register(regmap->config_reg1, (uint8_t *) &config_reg1, 1); if (ret < 0) { pr_err("read_register failed!"); return ret; } config_reg1.bits.osconz = 0; /* Enable the oscillator */ ret = write_register(regmap->config_reg1, (const uint8_t *) &config_reg1, 1); if (ret < 0) { pr_err("read_register failed!"); return ret; } return 0; } int RtcBase::rtc_stop() { int ret; config_reg1_t config_reg1; ret = read_register(regmap->config_reg1, (uint8_t *) &config_reg1, 1); if (ret < 0) { pr_err("read_register failed!"); return ret; } config_reg1.bits.osconz = 1; /* Disable the oscillator */ ret = write_register(regmap->config_reg1, (const uint8_t *) &config_reg1, 1); if (ret < 0) { pr_err("read_register failed!"); return ret; } return 0; }