Add PCF85363A RTC support
authorNathael Pajani <nathael.pajani@ed3l.fr>
Wed, 18 Aug 2021 08:12:05 +0000 (10:12 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Fri, 10 Feb 2023 18:02:59 +0000 (19:02 +0100)
extdrv/rtc_pcf85363a.c [new file with mode: 0644]
include/extdrv/rtc_pcf85363a.h [new file with mode: 0644]

diff --git a/extdrv/rtc_pcf85363a.c b/extdrv/rtc_pcf85363a.c
new file mode 100644 (file)
index 0000000..9f2eadb
--- /dev/null
@@ -0,0 +1,499 @@
+/****************************************************************************
+ *   extdrv/rtc_pcf85363a.c
+ *
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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 <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+#include "core/system.h"
+#include "lib/errno.h"
+#include "lib/string.h"
+#include "lib/stdio.h"
+#include "drivers/i2c.h"
+#include "extdrv/rtc_pcf85363a.h"
+
+
+
+/***************************************************************************** */
+/*          Support for PCF85363A RTC from NXP                                 */
+/***************************************************************************** */
+
+enum rtc_pcf85363a_regs {
+       /* Time registers */
+       PCF85363A_TIME = 0x00,
+       /* Alarm registers */
+       /* Timestamp registers */
+       PCF85363A_TSTMP_1 = 0x11,
+       PCF85363A_TSTMP_2 = 0x17,
+       PCF85363A_TSTMP_3 = 0x1D,
+       PCF85363A_TSTMP_CTRL = 0x23,
+       /* Offset register */
+       PCF85363A_OFFSET = 0x24,
+       /* Control registers */
+       PCF85363A_CTRL_OSC = 0x25,
+       PCF85363A_CTRL_BATT,
+       PCF85363A_CTRL_PIN_IO,
+       PCF85363A_CTRL_FUNC,
+       PCF85363A_CTRL_INTA,
+       PCF85363A_CTRL_INTB,
+       PCF85363A_CTRL_FLAGS,
+       /* Single RAM byte */
+       PCF85363A_SINGLE_RAM = 0x2C,
+       /* Watchdog */
+       PCF85363A_WATCHDOG = 0x2D,
+       /* Stop and reset */
+       PCF85363A_STOP,
+       PCF85363A_RESETS,
+       /* RAM */
+       PCF85363A_RAM_START = 0x40,
+       PCF85363A_RAM_END = 0x7F,
+};
+#define RTC_RAM_SIZE  64
+
+/* Time bits */
+#define PCF85363A_TIME_OS       (0x01 << 7)  /* This one is in the "seconds" register */
+#define PCF85363A_TIME_EMON     (0x01 << 7)  /* This one is in the "minutes" register */
+#define PCF85363A_TIME_AMPM     (0x01 << 5)  /* This one is in the "hours" register */
+/* Alarm enable bits */
+/* Oscilator bits */
+#define PCF85363A_OSC_CLKIV     (0x01 << 7)
+#define PCF85363A_OSC_OFFM      (0x01 << 6)
+#define PCF85363A_OSC_12_24     (0x01 << 5)
+#define PCF85363A_OSC_LOWJ      (0x01 << 4)
+#define PCF85363A_OSC_CLK_MASK  (PCF85363A_OSC_CLKIV | PCF85363A_OSC_LOWJ)
+#define PCF85363A_OSC_OSCD(x)   (((x) & 0x03) << 2)
+#define PCF85363A_OSC_LC(x)     (((x) & 0x03) << 0)
+/* Battery control bits */
+#define PCF85363A_BATT_BSOFF      (0x01 << 4)
+#define PCF85363A_BATT_BSRR_HIGH  (0x01 << 3)
+#define PCF85363A_BATT_BSM(x)     (((x) & 0x03) << 1)
+#define PCF85363A_BATT_BSTH_2_8V  (0x01 << 0)
+#define PCF85363A_BATT_MASK       0x1F
+/* Pin IO controll bits */
+#define PCF85363A_PIO_CLKPM_DIS (0x01 << 7)
+#define PCF85363A_PIO_TSPULL    (0x01 << 6)
+#define PCF85363A_PIO_TSL       (0x01 << 5)
+#define PCF85363A_PIO_TSIM      (0x01 << 4)
+#define PCF85363A_PIO_TSPM(x)   (((x) & 0x03) << 2)
+ #define PCF85363A_PIO_INTB_DIS   0
+ #define PCF85363A_PIO_INTB       1
+ #define PCF85363A_PIO_INTB_CLK   2
+ #define PCF85363A_PIO_INTB_INPUT 3
+#define PCF85363A_PIO_INTAPM(x) (((x) & 0x03) << 0)
+ #define PCF85363A_PIO_INTA_CLK   0
+ #define PCF85363A_PIO_INTA_BATT  1
+ #define PCF85363A_PIO_INTA       2
+ #define PCF85363A_PIO_INTA_HI_Z  3
+/* Function bits */
+#define PCF85363A_FUNC_100TH    (0x01 << 7)
+#define PCF85363A_FUNC_PI(x)    (((x) & 0x03) << 5)
+#define PCF85363A_FUNC_RTCM     (0x01 << 4)
+#define PCF85363A_FUNC_STOPM    (0x01 << 3)
+#define PCF85363A_FUNC_COF(x)   (((x) & 0x07) << 0)
+#define PCF85363A_FUNC_COF_MASK 0x07
+/* Interrupt enable bits */
+#define PCF85363A_INT_ILP       (0x01 << 7)
+#define PCF85363A_INT_PIE       (0x01 << 6)
+#define PCF85363A_INT_OIE       (0x01 << 5)
+#define PCF85363A_INT_A1IE      (0x01 << 4)
+#define PCF85363A_INT_A2IE      (0x01 << 3)
+#define PCF85363A_INT_TSRIE     (0x01 << 2)
+#define PCF85363A_INT_BSIE      (0x01 << 1)
+#define PCF85363A_INT_WDIE      (0x01 << 0)
+/* Interrupt flags bits */
+#define PCF85363A_FLAGS_PI      (0x01 << 7)
+#define PCF85363A_FLAGS_A2      (0x01 << 6)
+#define PCF85363A_FLAGS_A1      (0x01 << 5)
+#define PCF85363A_FLAGS_WD      (0x01 << 4)
+#define PCF85363A_FLAGS_BS      (0x01 << 3)
+#define PCF85363A_FLAGS_TSR3    (0x01 << 2)
+#define PCF85363A_FLAGS_TSR2    (0x01 << 1)
+#define PCF85363A_FLAGS_TSR1    (0x01 << 0)
+/* Watchdog bits */
+#define PCF85363A_WD_WDM        (0x01 << 7)
+#define PCF85363A_WD_WDR(x)     (((x) & 0x0F) << 2)
+#define PCF85363A_WD_WDS(x)     (((x) & 0x03) << 0)
+/* Stop bits */
+#define PCF85363A_STOP_BIT      (0x01 << 0)
+/* Reset bits */
+#define PCF85363A_RESET_CPR     (0x01 << 7)
+#define PCF85363A_RESET_SR      (0x01 << 3)
+#define PCF85363A_RESET_CTS     (0x01 << 0)
+#define PCF85363A_RESET_MASK    (0x24)
+
+
+
+
+#define REG_WR_CMD_SIZE 2
+#define READ_CMD_SIZE 3
+/* Let's consider that maximum write size is whole RAM */
+#define MAX_WR_BUF_SIZE  (REG_WR_CMD_SIZE + RTC_RAM_SIZE)
+
+
+/* Check RTC presence */
+static int rtc_pcf85363_probe(struct rtc_pcf85363a_config* conf)
+{
+       /* Read single RAM byte */
+       char cmd_buf[READ_CMD_SIZE] = { conf->addr, PCF85363A_SINGLE_RAM, (conf->addr | I2C_READ_BIT), };
+       char ctrl_buf[READ_CMD_SIZE] = { I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
+       uint8_t marker = 0;
+
+       /* Did we already probe the sensor ? */
+       if (conf->probe_ok != 1) {
+               conf->probe_ok = i2c_read(conf->bus_num, cmd_buf, READ_CMD_SIZE, ctrl_buf, &marker, 1);
+               conf->rtc_config_marker = marker;
+               msleep(10);
+       }
+       return conf->probe_ok;
+}
+
+static int rtc_pcf85363_set_regs(struct rtc_pcf85363a_config* conf,
+                                       uint8_t reg_start, uint8_t* values, uint8_t len)
+{
+       int ret = 0;
+       char buf[MAX_WR_BUF_SIZE] = { conf->addr, };
+
+       if (rtc_pcf85363_probe(conf) != 1) {
+               return -ENODEV;
+       }
+       if (values == NULL) {
+               return -EINVAL;
+       }
+       if ((reg_start + len - 1) > PCF85363A_RAM_END) {
+               return -EINVAL;
+       }
+       buf[1] = reg_start;
+
+       memcpy((buf + REG_WR_CMD_SIZE), values, len);
+       ret = i2c_write(conf->bus_num, buf, (REG_WR_CMD_SIZE + len), NULL);
+       if (ret != (REG_WR_CMD_SIZE + len)) {
+               conf->probe_ok = 0;
+               return ret;
+       }
+       return 0;
+}
+static int rtc_pcf85363_get_regs(struct rtc_pcf85363a_config* conf,
+                                       uint8_t reg_start, uint8_t* values, uint8_t len)
+{
+       int ret = 0;
+       char cmd_buf[READ_CMD_SIZE] = { conf->addr, 0, (conf->addr | I2C_READ_BIT), };
+       char ctrl_buf[READ_CMD_SIZE] = { I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
+
+       if (rtc_pcf85363_probe(conf) != 1) {
+               return -ENODEV;
+       }
+       if (values == NULL) {
+               return -EINVAL;
+       }
+       if ((reg_start + len - 1) > PCF85363A_RAM_END) {
+               return -EINVAL;
+       }
+       cmd_buf[1] = reg_start;
+
+       ret = i2c_read(conf->bus_num, cmd_buf, READ_CMD_SIZE, ctrl_buf, values, len);
+       if (ret != len) {
+               conf->probe_ok = 0;
+               return ret;
+       }
+       return 0;
+}
+
+
+/* Time Read
+ * When performing a time read operation, all time registers have to be read at once as
+ *  a copy of the internal values is made by the device to a temporary buffer at the
+ *  beginning of the read for data coherency.
+ */
+int rtc_pcf85363_time_read(struct rtc_pcf85363a_config* conf, struct rtc_time* time)
+{
+       int ret = 0;
+       ret = rtc_pcf85363_get_regs(conf, PCF85363A_TIME, (uint8_t*)time, sizeof(struct rtc_time));
+       if (ret != 0) {
+               return ret;
+       }
+       /* Remove flags from time values */
+       time->sec &= ~(PCF85363A_TIME_OS);
+       time->min &= ~(PCF85363A_TIME_EMON);
+       return 0;
+}
+
+/* Time Write
+ * A time write operation has to be done in one go for all time registers for time data
+ *  coherency.
+ * Also, when performing a time write, the STOP bit must be set and the prescalers should
+ *  be cleared.
+ */
+int rtc_pcf85363_time_write(struct rtc_pcf85363a_config* conf, struct rtc_time* time)
+{
+       int ret = 0;
+       uint8_t stop_cmd_buf[2] = {
+               PCF85363A_STOP_BIT,
+               PCF85363A_RESET_CPR | PCF85363A_RESET_MASK,
+       };
+       if (time == NULL) {
+               return -EINVAL;
+       }
+       /* Stop the RTC */
+       ret = rtc_pcf85363_set_regs(conf, PCF85363A_STOP, stop_cmd_buf, 2);
+       if (ret != 0) {
+               return ret;
+       }
+       /* Set time */
+       ret = rtc_pcf85363_set_regs(conf, PCF85363A_TIME, (uint8_t*)time, sizeof(struct rtc_time));
+       if (ret != 0) {
+               return ret;
+       }
+       /* And let RTC count again */
+       stop_cmd_buf[0] = 0x00;
+       ret = rtc_pcf85363_set_regs(conf, PCF85363A_STOP, stop_cmd_buf, 1);
+       if (ret != 0) {
+               return ret;
+       }
+       conf->time_set = 1;
+       return 0;
+}
+
+
+/* Get one of the timestamps
+ */
+int rtc_pcf85363_get_timestamp(struct rtc_pcf85363a_config* conf,
+                                                                       struct rtc_timestamp* tstmp, uint8_t timestamp_num)
+{
+       uint8_t addr = 0;
+       if ((timestamp_num == 0) || (timestamp_num > 3)) {
+               return -EINVAL;
+       }
+
+       addr = PCF85363A_TSTMP_1 + ((timestamp_num - 1) * sizeof(struct rtc_timestamp));
+       return rtc_pcf85363_get_regs(conf, addr, (uint8_t*)tstmp, sizeof(struct rtc_timestamp));
+}
+
+
+/* Erase timestamps */
+int rtc_pcf85363_erase_timestamps(struct rtc_pcf85363a_config* conf)
+{
+       uint8_t value = (PCF85363A_RESET_CTS | PCF85363A_RESET_MASK);
+       return rtc_pcf85363_set_regs(conf, PCF85363A_RESETS, &value, 1);
+}
+
+
+/* Print the time to a usable string, in a unix format which "date" could understand. */
+int rtc_pcf85363_time_to_str(struct rtc_time* time, char* str, int size)
+{
+       int len = 0;
+       len = snprintf(str, size, "20%02x/%02x/%02x %02x:%02x:%02x (%02x)\n",
+                       time->year, time->month, time->day,
+                       time->hour, time->min, time->sec, time->weekday);
+       return len;
+}
+
+/* Return the number of seconds of the curent day */
+uint32_t rtc_pcf85363_daytime_to_seconds(struct rtc_time* time)
+{
+       uint32_t seconds = ((time->sec & 0x0F) + ((time->sec & 0xF0) >> 4) * 10);
+       seconds += ((time->min & 0x0F) + ((time->min & 0xF0) >> 4) * 10) * 60;
+       seconds += ((time->hour & 0x0F) + ((time->hour & 0xF0) >> 4) * 10) * 3600;
+       return seconds;
+}
+
+/* Update the hours, minutes and seconds fields of the given time according to the number
+ * of seconds given in second argument.
+ * LPC1224 uses a Cortex M0, which has no modulo or division instruction, so this solution
+ * limits the calls to the ROM division routines to 5.
+ */
+void rtc_pcf85363_seconds_to_daytime(struct rtc_time* time, uint32_t seconds)
+{
+       uint32_t sec_tmp, min_tmp, hour_tmp;
+       hour_tmp = seconds / 3600;
+       seconds -= 3600 * hour_tmp;
+       min_tmp = seconds / 60;
+       sec_tmp = seconds - 60 * min_tmp;
+
+       time->hour = (hour_tmp / 10) << 4;
+       time->hour += (hour_tmp - (time->hour >> 4) * 10);
+
+       time->min = (min_tmp / 10) << 4;
+       time->min += (min_tmp - (time->min >> 4) * 10);
+
+       time->sec = (sec_tmp / 10) << 4;
+       time->sec += (sec_tmp - (time->sec >> 4) * 10);
+}
+
+/* Compare two times
+ * Return 0 if they are equal, 1 if t1 > t2, and -1 if t1 < t2
+ */
+int rtc_pcf85363a_time_cmp(const struct rtc_time* t1, const struct rtc_time* t2)
+{
+       /* Check years first ... */
+       if (t1->year > t2->year) return 1;
+       if (t1->year < t2->year) return -1;
+       /* Same year. Check months */
+       if (t1->month > t2->month) return 1;
+       if (t1->month < t2->month) return -1;
+       /* Go on with days ... */
+       if (t1->day > t2->day) return 1;
+       if (t1->day < t2->day) return -1;
+       /* Go on with hours ... */
+       if (t1->hour > t2->hour) return 1;
+       if (t1->hour < t2->hour) return -1;
+       /* Minutes */
+       if (t1->min > t2->min) return 1;
+       if (t1->min < t2->min) return -1;
+       /* Seconds */
+       if (t1->sec > t2->sec) return 1;
+       if (t1->sec < t2->sec) return -1;
+       /* 100th of seconds not activated yet ... */
+       if (t1->hundredth_sec > t2->hundredth_sec) return 1;
+       if (t1->hundredth_sec < t2->hundredth_sec) return -1;
+       /* Hey ... equal ! */
+       return 0;
+}
+
+/* Check if RTC is configured and holds a valid time
+ * This is done by reading the "SINGLE_RAM" byte, looking for PCF85363A_CONFIGURED,
+ *  and checking that the date is after the oldest possible date given as parameter.
+ * Returns -EFAULT if current time is older than "oldest" awaited time.
+ * Returns 0 if device was not configured.
+ * Returns 1 if device is configured and holds a valid time.
+ */
+int rtc_pcf85363a_is_up(struct rtc_pcf85363a_config* conf, const struct rtc_time* oldest)
+{
+       int ret = 0;
+       struct rtc_time now;
+
+       /* Get configured status */
+       if (conf->need_config_marker != conf->rtc_config_marker) {
+               return 0; /* Unconfigured */
+       }
+
+       /* Get current RTC time */
+       ret =  rtc_pcf85363_time_read(conf, &now);
+       if (ret != 0) {
+               return ret;
+       }
+       /* Compare to oldest allowed time */
+       if (rtc_pcf85363a_time_cmp(&now, oldest) <= 0) {
+               return -EFAULT;
+       }
+
+       /* OK, up and running */
+       conf->time_set = 1;
+       return 1;
+}
+
+
+/* Read RAM memory */
+int rtc_pcf85363a_read_ram(struct rtc_pcf85363a_config* conf,
+                                                               uint8_t offset, uint8_t* data, uint8_t len)
+{
+       if ((offset + len - 1) > RTC_RAM_SIZE) {
+               return -EINVAL;
+       }
+       return rtc_pcf85363_get_regs(conf, (PCF85363A_RAM_START + offset), data, len);
+}
+
+/* Write RAM memory */
+int rtc_pcf85363a_write_ram(struct rtc_pcf85363a_config* conf,
+                                                               uint8_t offset, uint8_t* data, uint8_t len)
+{
+       if ((offset + len - 1) > RTC_RAM_SIZE) {
+               return -EINVAL;
+       }
+       return rtc_pcf85363_set_regs(conf, (PCF85363A_RAM_START + offset), data, len);
+}
+
+
+
+/* RTC config according to given structure fields
+ * This configuration function relies on the value stored in the SINGLE_RAM
+ *   byte to check for existing configuration.
+ * Returns 1 if the RTC is considered as already configured, or 0 on configuration
+ *   success.
+ * Returns the error code of the failed configuration call upon errors.
+ */
+enum rtc_pcf85363a_cfg_regs {
+       PCF85363A_CFG_TSTMP_CTRL = 0, /* 0x23 */
+       PCF85363A_CFG_OFFSET,
+       PCF85363A_CFG_CTRL_OSC,
+       PCF85363A_CFG_CTRL_BATT,
+       PCF85363A_CFG_CTRL_PIN_IO,
+       PCF85363A_CFG_CTRL_FUNC,
+       PCF85363A_CFG_CTRL_INTA,
+       PCF85363A_CFG_CTRL_INTB,
+       PCF85363A_CFG_CTRL_FLAGS,
+       PCF85363A_CFG_SINGLE_RAM,
+       PCF85363A_CFG_WATCHDOG,
+       RTC_CONFIG_BUF_SIZE,
+};
+int rtc_pcf85363a_config(struct rtc_pcf85363a_config* conf)
+{
+       uint8_t config[RTC_CONFIG_BUF_SIZE];
+       int ret = 0;
+
+       /* Get the configuration marker (SINGLE RAM byte) */
+       ret = rtc_pcf85363_probe(conf);
+       if (ret != 1) {
+               return ret;
+       } else if (conf->need_config_marker == conf->rtc_config_marker) {
+               return 1; /* Already configured */
+       }
+
+       /* Prepare configuration :
+        *  - timestamp control and offset set to 0x00
+        */
+       memset(config, 0x00, RTC_CONFIG_BUF_SIZE);
+       /* Oscilator */
+       if (conf->mode & PCF85363A_MODE_12H) {
+               config[PCF85363A_CFG_CTRL_OSC] |= PCF85363A_OSC_12_24;
+       }
+       if (conf->mode & PCF85363A_MODE_CLKOUT_ON) {
+               config[PCF85363A_CFG_CTRL_OSC] |= (conf->clkout_ctrl & PCF85363A_OSC_CLK_MASK);
+       }
+       config[PCF85363A_CFG_CTRL_OSC] |= conf->oscilator_ctrl;
+       /* Battery */
+       config[PCF85363A_CFG_CTRL_BATT] |= (conf->batt_ctrl & PCF85363A_BATT_MASK);
+       /* Pin IO */
+       if ((conf->mode & PCF85363A_MODE_CLKOUT_ON) == 0) {
+               config[PCF85363A_CFG_CTRL_PIN_IO] =
+                               PCF85363A_PIO_CLKPM_DIS | PCF85363A_PIO_INTAPM(PCF85363A_PIO_INTA_HI_Z);
+       }
+       config[PCF85363A_CFG_CTRL_PIN_IO] |= 0x00;
+       /* Function */
+       if (conf->mode & PCF85363A_MODE_100TH) {
+               config[PCF85363A_CFG_CTRL_FUNC] |= PCF85363A_FUNC_100TH;
+       }
+       if (conf->mode & PCF85363A_MODE_STOP_WATCH) {
+               config[PCF85363A_CFG_CTRL_FUNC] |= PCF85363A_FUNC_RTCM;
+       }
+       if (conf->mode & PCF85363A_MODE_CLKOUT_ON) {
+               config[PCF85363A_CFG_CTRL_FUNC] |= (conf->clkout_ctrl & PCF85363A_FUNC_COF_MASK);
+       }
+       /* Mark the device as configured */
+       config[PCF85363A_CFG_SINGLE_RAM] = conf->need_config_marker;
+       /* Reset flags */
+       config[PCF85363A_CFG_CTRL_FLAGS] = 0x00;
+
+       /* Perform configuration */     
+       ret = rtc_pcf85363_set_regs(conf, PCF85363A_TSTMP_CTRL, config, RTC_CONFIG_BUF_SIZE);
+       if (ret != 0) {
+               return ret;
+       }
+       return 0; /* Config success */
+}
+
diff --git a/include/extdrv/rtc_pcf85363a.h b/include/extdrv/rtc_pcf85363a.h
new file mode 100644 (file)
index 0000000..a1184e2
--- /dev/null
@@ -0,0 +1,207 @@
+/****************************************************************************
+ *   extdrv/rtc_pcf85363a.h
+ *
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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 <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef EXTDRV_RTC_PCF85363A
+#define EXTDRV_RTC_PCF85363A
+
+/* This driver actually has support only for the main time registers in RTC mode.
+ */
+
+struct rtc_time {
+       uint8_t hundredth_sec; /* 0 to 99 - BCD encoding */
+       uint8_t sec; /* 0 to 59 - BCD encoding */
+       uint8_t min; /* 0 to 59 - BCD encoding */
+       uint8_t hour; /* 0 to 24 or AM/PM + 0 to 12 - BCD encoding */
+       uint8_t day; /* 1 to 31 - BCD encoding */
+       uint8_t weekday; /* 0 to 6 - BCD encoding */
+       uint8_t month; /* 1 to  12 - BCD encoding */
+       uint8_t year; /* 0 to 99 - BCD encoding */
+};
+
+struct rtc_timestamp {
+       uint8_t sec; /* 0 to 59 - BCD encoding */
+       uint8_t min; /* 0 to 59 - BCD encoding */
+       uint8_t hour; /* 0 to 24 or AM/PM + 0 to 12 - BCD encoding */
+       uint8_t day; /* 1 to 31 - BCD encoding */
+       uint8_t month; /* 1 to  12 - BCD encoding */
+       uint8_t year; /* 0 to 99 - BCD encoding */
+};
+
+
+
+struct rtc_pcf85363a_config {
+       uint8_t bus_num; /* I2C bus number */
+       uint8_t addr; /* Address on I2C bus. 8bit format */
+       /* probe_ok is set to 1 once RTC got probed, reset to 0 upon communication
+        *  errors */
+       uint8_t probe_ok;
+       /* time_set is set to 1 once time got set or time is found to be newer than
+        *  the date given on rtc_pcf85363a_is_up() call. */
+       uint8_t time_set;
+
+       /* config_marker should be set to one of the PCF85363A_CONFIGURED_* values
+        *  and changed whenever the configuration is changed within the program in
+        *  order to perform re-configuration only on configuration changes */
+#define PCF85363A_CONFIGURED_0   0x5A
+#define PCF85363A_CONFIGURED_1   0x78
+#define PCF85363A_CONFIGURED_2   0x33
+       uint8_t need_config_marker;
+       uint8_t rtc_config_marker;
+
+       /* mode is a bit mask of mode settings
+        * Concerned bits :
+        *  - 12_24 from PCF85363A_CTRL_OSC
+        *  - CLKPM from PCF85363A_CTRL_PIN_IO
+        *  - 100TH and RTCM from PCF85363A_CTRL_FUNC
+        * Default (0) sets RTC mode, 24 hours, and clkout off.
+        */
+#define PCF85363A_MODE_RTC         (0x00 << 0)
+#define PCF85363A_MODE_STOP_WATCH  (0x01 << 0)
+#define PCF85363A_MODE_12H         (0x01 << 1)
+#define PCF85363A_MODE_CLKOUT_ON   (0x01 << 2)
+#define PCF85363A_MODE_100TH       (0x01 << 3)
+       uint8_t mode;
+
+       /* Control of oscilator.
+        * Concerned bits :
+        *  - OSCD[1:0] and CL[1:0] from PCF85363A_CTRL_OSC
+        */
+#define PCF85363A_CONF_OSC_OSCD(x)   (((x) & 0x03) << 2)
+ #define PCF85363A_OSC_NORMAL_DRIVE 0
+ #define PCF85363A_OSC_LOW_DRIVE    1
+ #define PCF85363A_OSC_HIGH_DRIVE   2
+#define PCF85363A_CONF_OSC_LC(x)     (((x) & 0x03) << 0)
+ #define PCF85363A_OSC_CAP_7pF    0
+ #define PCF85363A_OSC_CAP_6pF    1
+ #define PCF85363A_OSC_CAP_12pF   2
+       uint8_t oscilator_ctrl;
+
+       /* Control of clk out features.
+        * Concerned bits :
+        *  - CLKIV and LOWJ from PCF85363A_CTRL_OSC : bits 7 and 4
+        *  - COF[2:0] from PCF85363A_CTRL_FUNC : bits 0 to 2
+        */
+#define PCF85363A_CONF_CLK_INV     (0x01 << 7)
+#define PCF85363A_CONF_CLK_LOWJ    (0x01 << 4)
+#define PCF85363A_CONF_CLK_FREQ(x) (((x) & 0x07) << 0)
+ #define PCF85363A_CLKOUT_32KHZ 0
+ #define PCF85363A_CLKOUT_16KHZ 1
+ #define PCF85363A_CLKOUT_8KHZ  2
+ #define PCF85363A_CLKOUT_4KHZ  3
+ #define PCF85363A_CLKOUT_2KHZ  4
+ #define PCF85363A_CLKOUT_1KHZ  5
+ #define PCF85363A_CLKOUT_1HZ   6
+ #define PCF85363A_CLKOUT_FIXED 7
+       uint8_t clkout_ctrl;
+
+       /* Control of Battery switching
+        * Concerned bits :
+        *  - All of PCF85363A_CTRL_BATT
+        *  - BSIEA and BSIEB from PCF85363A_CTRL_INTA and PCF85363A_CTRL_INTB
+        * Default (0) is Battery switch ON at low refresh rate, switching at Vth level
+        *  and Vth of 1.5V
+        */
+#define PCF85363A_CONF_BATT_SWITCH_OFF (0x01 << 4)
+#define PCF85363A_CONF_BATT_ST_REFRESH_HIGH  (0x01 << 3)
+#define PCF85363A_CONF_BATT_TH_1_5V    (0x00 << 0)
+#define PCF85363A_CONF_BATT_TH_2_8V    (0x01 << 0)
+       uint8_t batt_ctrl;
+
+       /* Pin "INTB" */
+       uint8_t pin_inta;
+
+       /* Pin "INTB" */
+       uint8_t pin_intb;
+
+       /* Interrupts */
+       uint8_t interrupt_inta;
+       uint8_t interrupt_intb;
+
+       /* Watchdog
+        * Reset or "0" defaults to watchdog off
+        */
+       uint8_t watchdog;
+       
+};
+
+
+/* Time Read from RTC */
+int rtc_pcf85363_time_read(struct rtc_pcf85363a_config* conf, struct rtc_time* time);
+
+/* Time Write to RTC */
+int rtc_pcf85363_time_write(struct rtc_pcf85363a_config* conf, struct rtc_time* time);
+
+
+
+/* Get one of the timestamps */
+int rtc_pcf85363_get_timestamp(struct rtc_pcf85363a_config* conf,
+                                                                       struct rtc_timestamp* tstmp, uint8_t timestamp_num);
+/* Erase timestamps */
+int rtc_pcf85363_erase_timestamps(struct rtc_pcf85363a_config* conf);
+
+
+
+/* Print the time to a usable string, in a unix format which "date" could understand. */
+int rtc_pcf85363_time_to_str(struct rtc_time* time, char* str, int size);
+
+/* Return the number of seconds of the curent day */
+uint32_t rtc_pcf85363_daytime_to_seconds(struct rtc_time* time);
+
+/* Update the hours, minutes and seconds fields of the given time according to the number
+ * of seconds given in second argument. */
+void rtc_pcf85363_seconds_to_daytime(struct rtc_time* time, uint32_t seconds);
+
+/* Compare two times
+ * Return 0 if they are equal, 1 if t1 > t2, and -1 if t1 < t2
+ */
+int rtc_pcf85363a_time_cmp(const struct rtc_time* t1, const struct rtc_time* t2);
+
+
+/* Read RAM memory */
+int rtc_pcf85363a_read_ram(struct rtc_pcf85363a_config* conf,
+                                                               uint8_t offset, uint8_t* data, uint8_t len);
+/* Write RAM memory */
+int rtc_pcf85363a_write_ram(struct rtc_pcf85363a_config* conf,
+                                                               uint8_t offset, uint8_t* data, uint8_t len);
+
+
+
+/* Check if RTC is configured and holds a valid time
+ * This is done by reading the "SINGLE_RAM" byte, looking for PCF85363A_CONFIGURED,
+ *  and checking that the date is after the oldest possible date given as parameter.
+ * Returns -EFAULT if current time is older than "oldest" awaited time.
+ * Returns 0 if device was not configured.
+ * Returns 1 if device is configured and holds a valid time.
+ */
+int rtc_pcf85363a_is_up(struct rtc_pcf85363a_config* conf, const struct rtc_time* oldest);
+
+/* RTC config according to given structure fields
+ * This configuration function relies on the value stored in the SINGLE_RAM
+ *   byte to check for existing configuration.
+ * Returns 1 if the RTC is considered as already configured, or 0 on configuration
+ *   success.
+ * Returns the error code of the failed configuration call upon errors.
+ */ 
+int rtc_pcf85363a_config(struct rtc_pcf85363a_config* conf);
+
+
+#endif /* EXTDRV_RTC_PCF85363A */