MAX31343 RTC Mbed Driver
MAX31343 RTC Driver
Diff: Max31343.cpp
- Revision:
- 0:aa73b3c9d246
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Max31343.cpp Tue Dec 01 13:32:54 2020 +0300 @@ -0,0 +1,1148 @@ +/******************************************************************************* + * Copyright (C) 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 "Max31343.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 + +#define TRICKLE_ENABLE_CODE 0x5 + +Max31343::Max31343(I2C *i2c, PinName pin_int) +{ + if (i2c == NULL) { + pr_err("i2c object is invalid!"); + while (1); + } + i2c_handler = i2c; + + sw_reset_release(); + + rtc_start(); + + irq_disable_all(); + + post_intr_work_thread = new Thread(); + + post_intr_work_thread->start(Callback<void()>(this, &Max31343::post_interrupt_work)); + + if (pin_int != NC) { + this->pin_int = new InterruptIn(pin_int); + + this->pin_int->fall(Callback<void()>(this, &Max31343::interrupt_handler)); + + this->pin_int->enable_irq(); + } else { + this->pin_int = NULL; + } +} + +Max31343::~Max31343() +{ + if (post_intr_work_thread) { + delete post_intr_work_thread; + } + + if (pin_int) { + delete pin_int; + } +} + +int Max31343::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 Max31343::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 Max31343::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 Max31343::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 Max31343::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(MAX31343_REG_SECONDS_ADDR, (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 Max31343::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(MAX31343_REG_SECONDS_ADDR, (const uint8_t *) &time_regs, sizeof(time_regs)) < 0) { + pr_err("read time registers failed!"); + return -1; + } + + return 0; +} + +int Max31343::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+1); + + if (alarm_time->tm_year >= 200) { + regs.year.bcd.value = BIN2BCD(alarm_time->tm_year - 200); + } else if (alarm_time->tm_year >= 100) { + regs.year.bcd.value = BIN2BCD(alarm_time->tm_year - 100); + } else { + pr_err("Invalid set year!"); + return -1; + } + + return 0; +} + +int Max31343::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); + } + + alarm_time->tm_mon = BCD2BIN(regs->mon.bcd.value) - 1; + + /* XXX no century bit */ + alarm_time->tm_year = BCD2BIN(regs->year.bcd.value) + 100; + + + return 0; +} + +int Max31343::set_alarm_period(alarm_no_t alarm_no, alarm_regs_t ®s, alarm_period_t period) +{ + switch (period) { + case ALARM_PERIOD_ONETIME: + if (alarm_no == ALARM2) { /* not supported! */ + return -1; + } + regs.sec.bits.a1m1 = 0; + regs.min.bits.a1m2 = 0; + regs.hrs.bits.a1m3 = 0; + regs.day_date.bits.a1m4 = 0; + regs.mon.bits.a1m5 = 0; + regs.mon.bits.a1m6 = 0; + regs.day_date.bits.dy_dt = 0; + break; + case ALARM_PERIOD_YEARLY: + if (alarm_no == ALARM2) { /* not supported! */ + return -1; + } + regs.sec.bits.a1m1 = 0; + regs.min.bits.a1m2 = 0; + regs.hrs.bits.a1m3 = 0; + regs.day_date.bits.a1m4 = 0; + regs.mon.bits.a1m5 = 0; + regs.mon.bits.a1m6 = 1; + regs.day_date.bits.dy_dt = 0; + break; + case ALARM_PERIOD_MONTHLY: + regs.sec.bits.a1m1 = 0; + regs.min.bits.a1m2 = 0; + regs.hrs.bits.a1m3 = 0; + regs.day_date.bits.a1m4 = 0; + regs.mon.bits.a1m5 = 1; + regs.mon.bits.a1m6 = 1; + regs.day_date.bits.dy_dt = 0; + break; + case ALARM_PERIOD_WEEKLY: + regs.sec.bits.a1m1 = 0; + regs.min.bits.a1m2 = 0; + regs.hrs.bits.a1m3 = 0; + regs.day_date.bits.a1m4 = 0; + regs.mon.bits.a1m5 = 1; + regs.mon.bits.a1m6 = 1; + regs.day_date.bits.dy_dt = 1; + break; + case ALARM_PERIOD_DAILY: + regs.sec.bits.a1m1 = 0; + regs.min.bits.a1m2 = 0; + regs.hrs.bits.a1m3 = 0; + regs.day_date.bits.a1m4 = 1; + regs.mon.bits.a1m5 = 1; + regs.mon.bits.a1m6 = 1; + regs.day_date.bits.dy_dt = 0; + break; + case ALARM_PERIOD_HOURLY: + regs.sec.bits.a1m1 = 0; + regs.min.bits.a1m2 = 0; + 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 = 0; + break; + case ALARM_PERIOD_EVERYMINUTE: + regs.sec.bits.a1m1 = 0; + 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 = 0; + break; + case ALARM_PERIOD_EVERYSECOND: + if ((alarm_no == ALARM2) && (period == ALARM_PERIOD_EVERYSECOND)) { + return -1; /* Alarm2 does not support "once per second" alarm*/ + } + 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 = 0; + break; + default: + return -1; + } + + return 0; +} + +int Max31343::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 = MAX31343_REG_ALM1_SEC_ADDR; + } else { + dev_ba = MAX31343_REG_ALM2_MIN_ADDR; + off = 1; /* starts from min register */ + len -= 3; /* XXX discard min, mon & sec registers */ + } + + return write_register(dev_ba, &ptr_regs[off], len); +} + +int Max31343::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 = MAX31343_REG_ALM1_SEC_ADDR; + } else { + regs->sec.raw = 0; /* zeroise second register for alarm2 */ + dev_ba = MAX31343_REG_ALM2_MIN_ADDR; + off = 1; /* starts from min register (no sec register) */ + len -= 2; /* XXX discard mon & sec registers */ + } + + return read_register(dev_ba, &ptr_regs[off], len); +} + +int Max31343::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 Max31343::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; + } + + if(alarm_no == ALARM1) { + int alarm = regs.sec.bits.a1m1 | (regs.min.bits.a1m2<<1) + | (regs.hrs.bits.a1m3<<2) | (regs.day_date.bits.a1m4<<3) + | (regs.mon.bits.a1m5<<4) | (regs.mon.bits.a1m6<<5) + | (regs.day_date.bits.dy_dt<<6); + + switch(alarm) { + case 0b1111111: + case 0b0111111: + *period = ALARM_PERIOD_EVERYSECOND; + break; + case 0b1111110: + case 0b0111110: + *period = ALARM_PERIOD_EVERYMINUTE; + break; + case 0b1111100: + case 0b0111100: + *period = ALARM_PERIOD_HOURLY; + break; + case 0b0111000: + case 0b1111000: + *period = ALARM_PERIOD_DAILY; + break; + case 0b0110000: + *period = ALARM_PERIOD_MONTHLY; + break; + case 0b0100000: + *period = ALARM_PERIOD_YEARLY; + break; + case 0b0000000: + *period = ALARM_PERIOD_ONETIME; + break; + case 0b1110000: + *period = ALARM_PERIOD_WEEKLY; + } + } else { + int alarm = (regs.min.bits.a1m2) | (regs.hrs.bits.a1m3<<1) + | (regs.day_date.bits.a1m4<<2) + | (regs.day_date.bits.dy_dt<<3); + + switch(alarm) { + case 0b1111: + case 0b0111: + *period = ALARM_PERIOD_EVERYMINUTE; + break; + case 0b1110: + case 0b0110: + *period = ALARM_PERIOD_HOURLY; + break; + case 0b1100: + case 0b0100: + *period = ALARM_PERIOD_DAILY; + break; + case 0b0000: + *period = ALARM_PERIOD_MONTHLY; + break; + case 0b1000: + *period = ALARM_PERIOD_WEEKLY; + } + } + + ret = read_register(MAX31343_REG_INT_EN_REG_ADDR, (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 Max31343::powerfail_threshold_level(comp_thresh_t th) +{ + int ret; + pwr_mgmt_reg_t reg; + + ret = read_register(MAX31343_REG_PWR_MGMT_REG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + reg.bits.pfvt = th; + + ret = write_register(MAX31343_REG_PWR_MGMT_REG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::supply_select(power_mgmt_supply_t supply) +{ + int ret; + pwr_mgmt_reg_t reg; + + ret = read_register(MAX31343_REG_PWR_MGMT_REG_ADDR, (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_VBACK: + 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(MAX31343_REG_PWR_MGMT_REG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::trickle_charger_enable(trickle_charger_path_t path) +{ + int ret; + struct { + unsigned char path : 4; + unsigned char tche : 4; + } reg; + + ret = read_register(MAX31343_REG_TRICKLE_REG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + reg.tche = TRICKLE_ENABLE_CODE; + reg.path = path; + + ret = write_register(MAX31343_REG_TRICKLE_REG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::trickle_charger_disable() +{ + int ret; + struct { + unsigned char path : 4; + unsigned char tche : 4; + } reg; + + + ret = read_register(MAX31343_REG_TRICKLE_REG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + reg.tche = 0; + + ret = write_register(MAX31343_REG_TRICKLE_REG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::set_output_square_wave_frequency(square_wave_out_freq_t freq) +{ + int ret; + config_reg2_t reg; + + ret = read_register(MAX31343_REG_CONFIG_REG2_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + reg.bits.sqw_hz = freq; + + ret = write_register(MAX31343_REG_CONFIG_REG2_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::clko_enable(clko_freq_t freq) +{ + int ret; + config_reg2_t cfg2; + + ret = read_register(MAX31343_REG_CONFIG_REG2_ADDR, (uint8_t *)&cfg2, 1); + if (ret) { + return ret; + } + + cfg2.bits.enclko = 1; + cfg2.bits.clko_hz = freq; + + ret = write_register(MAX31343_REG_CONFIG_REG2_ADDR, (uint8_t *)&cfg2, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::clko_disable() +{ + int ret; + config_reg2_t cfg2; + + ret = read_register(MAX31343_REG_CONFIG_REG2_ADDR, (uint8_t *)&cfg2, 1); + if (ret) { + return ret; + } + + cfg2.bits.enclko = 0; + + ret = write_register(MAX31343_REG_CONFIG_REG2_ADDR, (uint8_t *)&cfg2, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::timer_init(uint8_t value, bool repeat, timer_freq_t freq) +{ + int ret; + timer_config_t reg_cfg; + + ret = read_register(MAX31343_REG_TIMER_CONFIG_ADDR, (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(MAX31343_REG_TIMER_CONFIG_ADDR, + (uint8_t *)®_cfg, 1); + if (ret) { + return ret; + } + + ret = write_register(MAX31343_REG_TIMER_INIT_ADDR, (uint8_t *)&value, 1); + if (ret) { + return ret; + } + + return 0; +} + +uint8_t Max31343::timer_get() +{ + int ret; + uint8_t reg; + + ret = read_register(MAX31343_REG_TIMER_COUNT_ADDR, (uint8_t *)®, 1); + if (ret) { + return (uint8_t) - 1; + } + + return reg; +} + +int Max31343::timer_start() +{ + int ret; + timer_config_t reg; + + ret = read_register(MAX31343_REG_TIMER_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + reg.bits.te = 1; + reg.bits.tpause = 0; + + ret = write_register(MAX31343_REG_TIMER_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::timer_pause() +{ + int ret; + timer_config_t reg; + + ret = read_register(MAX31343_REG_TIMER_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + reg.bits.te = 1; + reg.bits.tpause = 1; + + ret = write_register(MAX31343_REG_TIMER_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::timer_continue() +{ + int ret; + timer_config_t reg; + + ret = read_register(MAX31343_REG_TIMER_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + reg.bits.te = 1; + reg.bits.tpause = 0; + + ret = write_register(MAX31343_REG_TIMER_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::timer_stop() +{ + int ret; + timer_config_t reg; + + ret = read_register(MAX31343_REG_TIMER_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + reg.bits.te = 0; + reg.bits.tpause = 1; + + ret = write_register(MAX31343_REG_TIMER_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::data_retention_mode_config(int state) +{ + int ret; + config_reg1_t cfg1; + + ret = read_register(MAX31343_REG_CONFIG_REG1_ADDR, (uint8_t *)&cfg1, 1); + if (ret) { + return ret; + } + + if (state) { + cfg1.bits.enosc = 0; + cfg1.bits.data_reten = 1; + } else { + cfg1.bits.enosc = 1; + cfg1.bits.data_reten = 0; + } + + ret = write_register(MAX31343_REG_CONFIG_REG1_ADDR, (uint8_t *)&cfg1, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::data_retention_mode_enter() +{ + return data_retention_mode_config(1); +} + +int Max31343::data_retention_mode_exit() +{ + return data_retention_mode_config(0); +} + +int Max31343::i2c_timeout_config(int enable) +{ + int ret; + config_reg1_t cfg1; + + ret = read_register(MAX31343_REG_CONFIG_REG1_ADDR, (uint8_t *)&cfg1, 1); + if (ret) { + return ret; + } + + cfg1.bits.i2c_timeout = (enable) ? 1 : 0; + + ret = write_register(MAX31343_REG_CONFIG_REG1_ADDR, (uint8_t *)&cfg1, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::i2c_timeout_enable() +{ + return i2c_timeout_config(1); +} + +int Max31343::i2c_timeout_disable() +{ + return i2c_timeout_config(0); +} + +int Max31343::read_temp(float *temp) +{ + int ret; + uint8_t regs[2]; + ts_config_t cfg_reg; + int itemp; + + ret = read_register(MAX31343_REG_TS_CONFIG_ADDR, (uint8_t *)&cfg_reg, 1); + if (ret) { + return ret; + } + + if (cfg_reg.bits.automode) { /* manual mode */ + /* trigger temperature reading */ + cfg_reg.bits.oneshotmode = 1; + + ret = write_register(MAX31343_REG_TS_CONFIG_ADDR, (uint8_t *)&cfg_reg, 1); + if (ret) { + return ret; + } + + while (cfg_reg.bits.oneshotmode) { + ret = read_register(MAX31343_REG_TS_CONFIG_ADDR, (uint8_t *)&cfg_reg, 1); + if (ret) { + return ret; + } + } + } + + ret = read_register(MAX31343_REG_TEMP_MSB_ADDR, regs, 2); + if (ret) { + return ret; + } + + itemp = ((regs[0] << 2) | (regs[1] >> 6)); + if (regs[0] & 0x80) { /* if negative */ + itemp |= -(1 << 10); /* sign extend */ + } + + *temp = (float)itemp / 4; /* LSB resolution: 0.25 C */ + + return 0; +} + +int Max31343::temp_sensor_config(bool automode, ttsint_t interval) +{ + int ret; + ts_config_t reg; + + ret = read_register(MAX31343_REG_TS_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + if (automode) { + reg.bits.automode = 1; + reg.bits.ttint = interval; + } else { + reg.bits.automode = 0; + } + + ret = write_register(MAX31343_REG_TS_CONFIG_ADDR, (uint8_t *)®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::irq_enable(intr_id_t id) +{ + int ret; + uint8_t reg; + + ret = read_register(MAX31343_REG_INT_EN_REG_ADDR, ®, 1); + if (ret) { + return ret; + } + + reg |= (1 << id); + + ret = write_register(MAX31343_REG_INT_EN_REG_ADDR, ®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::irq_disable(intr_id_t id) +{ + int ret; + uint8_t reg; + + ret = read_register(MAX31343_REG_INT_EN_REG_ADDR, ®, 1); + if (ret) { + return ret; + } + + reg &= ~(1 << id); + + ret = write_register(MAX31343_REG_INT_EN_REG_ADDR, ®, 1); + if (ret) { + return ret; + } + + return 0; +} + +int Max31343::irq_disable_all() +{ + int ret; + uint8_t reg = 0; + + ret = write_register(MAX31343_REG_INT_EN_REG_ADDR, ®, 1); + if (ret) { + return ret; + } + + return 0; +} + +void Max31343::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 Max31343::post_interrupt_work() +{ + int ret; + uint8_t reg, inten, mask; + + + while (true) { + Thread::signal_wait(POST_INTR_WORK_SIGNAL_ID); + + ret = read_register(MAX31343_REG_INT_STATUS_REG_ADDR, ®, 1); + if (ret) { + pr_err("Read interrupt status register failed!"); + } + + ret = read_register(MAX31343_REG_INT_EN_REG_ADDR, &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 Max31343::interrupt_handler() +{ + post_intr_work_thread->signal_set(POST_INTR_WORK_SIGNAL_ID); +} + +int Max31343::sw_reset_assert() +{ + int ret; + rtc_reset_reg_t rst_reg; + + ret = read_register(MAX31343_REG_RTC_RESET_ADDR, (uint8_t *) &rst_reg, 1); + if (ret < 0) { + pr_err("read_register failed!"); + return ret; + } + + rst_reg.bits.swrst = 1; /* Put device in reset state */ + + ret = write_register(MAX31343_REG_RTC_RESET_ADDR, (const uint8_t *) &rst_reg, 1); + if (ret < 0) { + pr_err("read_register failed!"); + return ret; + } + + return 0; +} + +int Max31343::sw_reset_release() +{ + int ret; + rtc_reset_reg_t rst_reg; + + ret = read_register(MAX31343_REG_RTC_RESET_ADDR, (uint8_t *) &rst_reg, 1); + if (ret < 0) { + pr_err("read_register failed!"); + return ret; + } + + rst_reg.bits.swrst = 0; /* Remove device from reset state */ + + ret = write_register(MAX31343_REG_RTC_RESET_ADDR, + (const uint8_t *) &rst_reg, 1); + if (ret < 0) { + pr_err("read_register failed!"); + return ret; + } + + return 0; +} + +int Max31343::rtc_start() +{ + int ret; + config_reg1_t cfg1; + + ret = read_register(MAX31343_REG_CONFIG_REG1_ADDR, (uint8_t *) &cfg1, 1); + if (ret < 0) { + return ret; + } + + cfg1.bits.enosc = 1; /* Enable the oscillator */ + + ret = write_register(MAX31343_REG_CONFIG_REG1_ADDR, (const uint8_t *) &cfg1, 1); + if (ret < 0) { + return ret; + } + + return 0; +} + +int Max31343::rtc_stop() +{ + int ret; + config_reg1_t cfg1; + + ret = read_register(MAX31343_REG_CONFIG_REG1_ADDR, (uint8_t *) &cfg1, 1); + if (ret < 0) { + return ret; + } + + cfg1.bits.enosc = 0; /* Disable the oscillator */ + + ret = write_register(MAX31343_REG_CONFIG_REG1_ADDR, + (const uint8_t *) &cfg1, 1); + if (ret < 0) { + return ret; + } + + return 0; +}