diff mbox series

[1/2,SRU,J] UBUNTU: SAUCE: ODM: rtc: add PCF85263 RTC driver

Message ID 20231228031842.1147904-2-acelan.kao@canonical.com
State New
Headers show
Series Add ODM driver rtc-pcf85263 | expand

Commit Message

AceLan Kao Dec. 28, 2023, 3:18 a.m. UTC
From: Filippo Copetti <filippo.copetti@eurotech.com>

BugLink: https://bugs.launchpad.net/bugs/2045385

PCF85263 is an i2c RTC chip with calendar, alarm, watchdog, timestamps
for events (switch to battery, switch to VDD, GPIO trigger).

Signed-off-by: Filippo Copetti <filippo.copetti@eurotech.com>
Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
---
 MAINTAINERS                |    6 +
 drivers/rtc/Kconfig        |   10 +
 drivers/rtc/Makefile       |    1 +
 drivers/rtc/rtc-pcf85263.c | 1784 ++++++++++++++++++++++++++++++++++++
 drivers/rtc/rtc-pcf85263.h |  387 ++++++++
 5 files changed, 2188 insertions(+)
 create mode 100644 drivers/rtc/rtc-pcf85263.c
 create mode 100644 drivers/rtc/rtc-pcf85263.h
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index d43553fe7e0b3..e639e82ec36a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13524,6 +13524,12 @@  S:	Maintained
 F:	Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml
 F:	drivers/gpu/drm/imx/dcss/
 
+NXP PCF85263 RTC DRIVER
+M:	Filippo Copetti <filippo.copetti@eurotech.com>
+S:	Maintained
+F:	drivers/rtc/rtc-pcf85263.c
+F:	drivers/rtc/rtc-pcf85263.h
+
 NXP PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER
 M:	Jagan Teki <jagan@amarulasolutions.com>
 S:	Maintained
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e1bc5214494e2..23ea95cbd2bc5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -457,6 +457,16 @@  config RTC_DRV_PCF85063
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-pcf85063.
 
+config RTC_DRV_PCF85263
+	tristate "NXP PCF85263"
+	depends on UBUNTU_ODM_DRIVERS
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for the PCF85263 RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-pcf85263.
+
 config RTC_DRV_PCF85363
 	tristate "NXP PCF85363"
 	select REGMAP_I2C
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 5ceeafe4d5b23..be44ee12c7726 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -120,6 +120,7 @@  obj-$(CONFIG_RTC_DRV_PCF2127)	+= rtc-pcf2127.o
 obj-$(CONFIG_RTC_DRV_PCF50633)	+= rtc-pcf50633.o
 obj-$(CONFIG_RTC_DRV_PCF85063)	+= rtc-pcf85063.o
 obj-$(CONFIG_RTC_DRV_PCF8523)	+= rtc-pcf8523.o
+obj-$(CONFIG_RTC_DRV_PCF85263)	+= rtc-pcf85263.o
 obj-$(CONFIG_RTC_DRV_PCF85363)	+= rtc-pcf85363.o
 obj-$(CONFIG_RTC_DRV_PCF8563)	+= rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)	+= rtc-pcf8583.o
diff --git a/drivers/rtc/rtc-pcf85263.c b/drivers/rtc/rtc-pcf85263.c
new file mode 100644
index 0000000000000..3635a1715af69
--- /dev/null
+++ b/drivers/rtc/rtc-pcf85263.c
@@ -0,0 +1,1784 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NXP PCF85263 RTC driver
+ * Copyright (C) 2015 Eurotech Ltd Fabrizio Castro
+ *
+ * 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 2
+ * 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/>
+ */
+#define DEBUG 0
+
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/watchdog.h>
+#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
+#include <linux/io.h>
+#include "rtc-pcf85263.h"
+
+/*
+ * This driver implements only a subset of the HW capabilities:
+ * - RTC
+ * - Alarm 1
+ * - watchdog
+ * - timestamps
+ * - RAM byte
+ * - Battery management
+ * - Oscillator
+ */
+/*
+ * workaround for the sleep/wakeup issue
+ * resuming from sleep we need to set the gpio0_19 bit
+ * in this registers. Due to pcb routing there is no need
+ * to configure something
+ */
+#define GPIO0_IRQSTATUS_0_ADDR	0x44E0702C
+#define GPIO0_IRQSTATUS_1_ADDR	0x44E07030
+#define GPIO0_19_SET_BIT_ACK	0x00080000
+
+#define RTC_WAIT_FOR_INTERRUPTS     _IOW('p', 0x15, unsigned char)
+#define RTC_WAIT_FOR_ANY_INTERRUPT  _IOR('p', 0x16, unsigned char)
+#define RTC_CLEAR_INTERRUPT_FLAGS   _IOW('p', 0x17, unsigned char)
+
+#define WATCHDOG_TIMEOUT	60
+#define TAMPER_LEVEL		1
+#define VOLTAGE_THRE		0
+#define WDT_ENABLE		0
+#define WAKE_ENABLE		1
+#define INT_BATT_DEF		"INTA"
+#define INT_WDT_DEF		"NO_INTERRUPT"
+#define INT_TST_DEF		"INTB"
+#define INT_APM_DEF		"INTAPM_INTA"
+#define TSPM_DEF		"TSPM_INPUT_MODE"
+
+static int timeout = WATCHDOG_TIMEOUT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+		 "Watchdog timeout in seconds. (1<=timeout<=124, default="
+		 __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+		 "Watchdog cannot be stopped once started (default="
+		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static bool tsl = TAMPER_LEVEL;
+module_param(tsl, bool, 0);
+MODULE_PARM_DESC(tsl,
+		 "Tamper level, 0 low, 1 high (default="
+		 __MODULE_STRING(TAMPER_LEVEL) ")");
+
+static bool vth = VOLTAGE_THRE;
+module_param(vth, bool, 0);
+MODULE_PARM_DESC(vth,
+		 "Voltage threshold level, 0 -> 1.5V, 1 -> 2.8V (default="
+		 __MODULE_STRING(VOLTAGE_THRE) ")");
+
+static bool wdten = WDT_ENABLE;
+module_param(wdten, bool, 0);
+MODULE_PARM_DESC(wdten,
+		 "Watchdog timer enable, 0 disabled, 1 enabled (default="
+		 __MODULE_STRING(WDT_ENABLE) ")");
+
+static bool wakeen = WAKE_ENABLE;
+module_param(wakeen, bool, 0);
+MODULE_PARM_DESC(wakeen,
+		 "Wakeup function enable, 0 disabled, 1 enabled (default="
+		 __MODULE_STRING(WAKE_ENABLE) ")");
+
+static char *int_batt = INT_BATT_DEF;
+module_param(int_batt, charp, 0);
+MODULE_PARM_DESC(int_batt,
+		 "Battery connection configuration, INTA, INTB, NO_INTERRUPT (default="
+		 __MODULE_STRING(INT_BATT_DEF) ")");
+
+static char *int_wdt = INT_WDT_DEF;
+module_param(int_wdt, charp, 0);
+MODULE_PARM_DESC(int_wdt,
+		 "Watchdog connection configuration, INTA, INTB, NO_INTERRUPT (default="
+		 __MODULE_STRING(INT_WDT_DEF) ")");
+
+static char *int_tst = INT_TST_DEF;
+module_param(int_tst, charp, 0);
+MODULE_PARM_DESC(int_tst,
+		 "Timestamp connection configuration, INTA, INTB, NO_INTERRUPT (default="
+		 __MODULE_STRING(INT_TST_DEF) ")");
+
+static char *intapm_conf = INT_APM_DEF;
+module_param(intapm_conf, charp, 0);
+MODULE_PARM_DESC(intapm_conf,
+		 "INTA Pin mode, INTAPM_CLK_OUTPUT, INTAPM_BATTERY_MODE_INDICATION, INTAPM_INTA, INTAPM_HIGH_IMPEDANCE (default="
+		 __MODULE_STRING(INT_APM_DEF) ")");
+
+static char *tspm = TSPM_DEF;
+module_param(tspm, charp, 0);
+MODULE_PARM_DESC(tspm,
+		 "Timestamp pin mode, TSPM_DISABLED, TSPM_INT, TSPM_CLK_OUTPUT, TSPM_INPUT_MODE (default="
+		 __MODULE_STRING(TSPM_DEF) ")");
+
+static struct i2c_driver pcf85263_driver;
+
+struct pcf85263 {
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+	struct mutex mutex;
+	int ram_byte_file_created;
+	int registers_file_created;
+	int resets_file_created;
+	int inta_gpio;
+	int intb_gpio;
+	int inta_irq;
+	int intb_irq;
+	int interrupt_alarm;
+	int clock_frequency;
+	int clk_pin;
+	int inta_pin;
+	int ts_pin;
+	int ts_pin_pull;
+	int ts_pin_level;
+	int ts_pin_input_type;
+	int watchdog_timeout;
+	int watchdog_disable_on_boot;
+	int interrupt_watchdog;
+	int flags_file_created;
+	int timestamp1_file_created;
+	int timestamp2_file_created;
+	int timestamp3_file_created;
+	int timestamp1_mode;
+	int timestamp2_mode;
+	int timestamp3_mode;
+	int interrupt_timestamp;
+	int battery_switch;
+	int battery_vth;
+	int interrupt_battery;
+	wait_queue_head_t event_queue;
+	unsigned char event_interrupt;
+	struct work_struct work;
+	int irq;
+};
+
+/*******************************************************************************
+ *  Utils
+ */
+static int pcf85263_read_register(struct i2c_client *client,
+				  unsigned char address,
+				  unsigned char *value)
+{
+	int err;
+
+	err = i2c_master_send(client, &address, sizeof(address));
+	if (err != sizeof(address))
+		return err;
+	err = i2c_master_recv(client, value, sizeof(unsigned char));
+	if (err != sizeof(unsigned char))
+		return err;
+	return 0;
+}
+
+static int pcf85263_read_registers(struct i2c_client *client,
+				   unsigned char address,
+				   unsigned char *values, int count)
+{
+	int err;
+
+	err = i2c_master_send(client, &address, sizeof(address));
+	if (err != sizeof(address))
+		return err;
+	err = i2c_master_recv(client, values, count);
+	if (err != count)
+		return err;
+	return 0;
+}
+
+static int pcf85263_write_register(struct i2c_client *client,
+				   unsigned char address,
+				   unsigned char value)
+{
+	int err;
+	unsigned char data[2] = { address, value };
+
+	err = i2c_master_send(client, data, sizeof(data));
+	if (err != sizeof(data))
+		return err;
+	return 0;
+}
+
+static int pcf85263_first_one_index(unsigned char value)
+{
+	int first_one_index = 0;
+
+	if (value == 0)
+		return -EINVAL;
+	while ((value & 0x01) == 0) {
+		value = value >> 1;
+		first_one_index++;
+	}
+	return first_one_index;
+}
+
+/*******************************************************************************
+ * Watchdog
+ */
+
+static int pcf85263_watchdog_enable(struct i2c_client *client, int enable)
+{
+	int err = 0;
+	unsigned char value;
+	struct pcf85263 *pcf85263;
+
+	pcf85263 = i2c_get_clientdata(client);
+	if (pcf85263->interrupt_watchdog == INTA) {
+		err =
+		    pcf85263_read_register(client, REGISTER_INTA_ENABLE,
+					   &value);
+		if (err)
+			return err;
+		value &= ~WDIEA;
+		value |= (enable ? WDIEA_ENABLE : WDIEA_DISABLE);
+		err =
+		    pcf85263_write_register(client, REGISTER_INTA_ENABLE,
+					    value);
+	} else if (pcf85263->interrupt_watchdog == INTB) {
+		err =
+		    pcf85263_read_register(client, REGISTER_INTB_ENABLE,
+					   &value);
+		if (err)
+			return err;
+		value &= ~WDIEB;
+		value |= (enable ? WDIEB_ENABLE : WDIEB_DISABLE);
+		err =
+		    pcf85263_write_register(client, REGISTER_INTB_ENABLE,
+					    value);
+	} else {
+		dev_dbg(&client->dev, "[%s] no interrupt registered\n",
+			__func__);
+	}
+	return err;
+}
+
+static int pcf85263_watchdog_compute_seconds(int *seconds,
+					     unsigned char *_wdr_value,
+					     unsigned char *_wds_value)
+{
+	unsigned char wdr_value, wds_value;
+
+	/* WatchDog-duration = WDR x stepsize */
+	if (*seconds > 120) {
+		wdr_value = 31;
+		wds_value = WDS_4_SECONDS;
+	} else if (*seconds > 31) {
+		wdr_value = (unsigned char)(*seconds / 4);
+		if (((int)wdr_value * 4) != *seconds)
+			wdr_value++;
+		wds_value = WDS_4_SECONDS;
+	} else if (*seconds >= 0) {
+		wdr_value = (unsigned char)*seconds;
+		wds_value = WDS_1_SECOND;
+	} else {
+		return -EINVAL;
+	}
+	if (wds_value == WDS_4_SECONDS)
+		*seconds = (int)wdr_value * 4;
+	else
+		*seconds = wdr_value;
+	if (_wdr_value)
+		*_wdr_value = wdr_value;
+
+	if (_wds_value)
+		*_wds_value = wds_value;
+	return 0;
+}
+
+static int pcf85263_watchdog_set_time(struct i2c_client *client,
+				      int *seconds)
+{
+	int err;
+	unsigned char wdr_value, wds_value, value;
+	struct pcf85263 *pcf85263;
+
+	dev_dbg(&client->dev, "[%s] [input] seconds = %d\n", __func__,
+		*seconds);
+	pcf85263 = i2c_get_clientdata(client);
+	err =
+	    pcf85263_watchdog_compute_seconds(seconds, &wdr_value,
+					      &wds_value);
+	if (err) {
+		dev_dbg(&client->dev,
+			"[%s] problems while computing actual timeout\n",
+			__func__);
+		return err;
+	}
+	err = pcf85263_read_register(client, REGISTER_WATCHDOG, &value);
+	if (err)
+		return err;
+	value &= ~WDR;
+	value |= (wdr_value << pcf85263_first_one_index(WDR));
+	value &= ~WDS;
+	value |= (wds_value << pcf85263_first_one_index(WDS));
+	err = pcf85263_write_register(client, REGISTER_WATCHDOG, value);
+	if (err)
+		return err;
+	dev_dbg(&client->dev, "[%s] [output] seconds = %d\n", __func__,
+		*seconds);
+	return 0;
+}
+
+static int pcf85263_watchdog_get_current_time(struct i2c_client *client,
+					      int *seconds)
+{
+	int err = 0;
+	unsigned char wdr_value, wds_value, value;
+	struct pcf85263 *pcf85263;
+
+	pcf85263 = i2c_get_clientdata(client);
+	err = pcf85263_read_register(client, REGISTER_WATCHDOG, &value);
+	if (err)
+		return err;
+	wdr_value = (value & WDR) >> pcf85263_first_one_index(WDR);
+	wds_value = (value & WDS) >> pcf85263_first_one_index(WDS);
+	if (wds_value == WDS_4_SECONDS)
+		*seconds = wdr_value * 4;
+	else if (wds_value == WDS_1_SECOND)
+		*seconds = wdr_value;
+	else
+		err = -EILSEQ;
+
+	return err;
+}
+
+static int pcf85263_watchdog_ping(struct i2c_client *client)
+{
+	struct pcf85263 *pcf85263 = i2c_get_clientdata(client);
+
+	return pcf85263_watchdog_set_time(client,
+					  &pcf85263->watchdog_timeout);
+}
+
+/*
+ * Watchdog subsystem
+ */
+static int pcf85263_watchdog_start_op(struct watchdog_device *device)
+{
+	int err;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = watchdog_get_drvdata(device);
+	pcf85263 = i2c_get_clientdata(client);
+
+	mutex_lock(&pcf85263->mutex);
+	err =
+	    pcf85263_watchdog_set_time(client,
+				       &pcf85263->watchdog_timeout);
+	if (err)
+		goto exit;
+	err = pcf85263_watchdog_enable(client, 1);
+exit:
+	mutex_unlock(&pcf85263->mutex);
+	return err;
+}
+
+static int pcf85263_watchdog_stop_op(struct watchdog_device *device)
+{
+	int err, seconds = 0;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = watchdog_get_drvdata(device);
+	pcf85263 = i2c_get_clientdata(client);
+
+	mutex_lock(&pcf85263->mutex);
+	err = pcf85263_watchdog_enable(client, 0);
+	if (err)
+		goto exit;
+	err = pcf85263_watchdog_set_time(client, &seconds);
+exit:
+	mutex_unlock(&pcf85263->mutex);
+	return err;
+}
+
+static int pcf85263_watchdog_ping_op(struct watchdog_device *device)
+{
+	int err;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = watchdog_get_drvdata(device);
+	pcf85263 = i2c_get_clientdata(client);
+	mutex_lock(&pcf85263->mutex);
+	err = pcf85263_watchdog_ping(client);
+	mutex_unlock(&pcf85263->mutex);
+	return err;
+}
+
+static int pcf85263_watchdog_set_timeout_op(struct watchdog_device *device,
+					    unsigned int timeout)
+{
+	int seconds, err;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = watchdog_get_drvdata(device);
+	pcf85263 = i2c_get_clientdata(client);
+	seconds = (int)timeout;
+	mutex_lock(&pcf85263->mutex);
+	err = pcf85263_watchdog_compute_seconds(&seconds, NULL, NULL);
+	if (!err) {
+		device->timeout = (unsigned int)seconds;
+		pcf85263->watchdog_timeout = seconds;
+	}
+	mutex_unlock(&pcf85263->mutex);
+	return 0;
+}
+
+static unsigned int pcf85263_watchdog_get_timeleft_op(struct
+						      watchdog_device
+						      * device)
+{
+	int err, seconds = 0;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = watchdog_get_drvdata(device);
+	pcf85263 = i2c_get_clientdata(client);
+	mutex_lock(&pcf85263->mutex);
+	err = pcf85263_watchdog_get_current_time(client, &seconds);
+	mutex_unlock(&pcf85263->mutex);
+	return (unsigned int)seconds;
+}
+
+static struct watchdog_info pcf85263_watchdog_info = {
+	.options =
+	    WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+	.identity = "PCF85263 Watchdog",
+};
+
+static struct watchdog_ops pcf85263_watchdog_ops = {
+	.owner = THIS_MODULE,
+	.start = pcf85263_watchdog_start_op,
+	.stop = pcf85263_watchdog_stop_op,
+	.ping = pcf85263_watchdog_ping_op,
+	.set_timeout = pcf85263_watchdog_set_timeout_op,
+	.get_timeleft = pcf85263_watchdog_get_timeleft_op,
+};
+
+static struct watchdog_device pcf85263_watchdog_device = {
+	.info = &pcf85263_watchdog_info,
+	.ops = &pcf85263_watchdog_ops,
+	.timeout = WATCHDOG_TIMEOUT,
+	.min_timeout = 1,
+	.max_timeout = 124,
+};
+
+/*******************************************************************************
+ * Timestamps
+ */
+static int pcf85263_read_timestamp(struct device *dev, int tsr_number,
+				   int *seconds, int *minutes, int *hours,
+				   int *days, int *months, int *years)
+{
+	int err;
+	unsigned char tsr_register, values[6];
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (tsr_number < 1 || tsr_number > 3)
+		return -EINVAL;
+	if (tsr_number == 1)
+		tsr_register = REGISTER_TSR1_SECONDS;
+	else if (tsr_number == 2)
+		tsr_register = REGISTER_TSR2_SECONDS;
+	else
+		tsr_register = REGISTER_TSR3_SECONDS;
+	err =
+	    pcf85263_read_registers(client, tsr_register, values,
+				    sizeof(values));
+	if (err)
+		return err;
+	*seconds = bcd2bin(values[0] & SECONDS_BITS);
+	*minutes = bcd2bin(values[1] & MINUTES_BITS);
+	*hours = bcd2bin(values[2] & HOURS_BITS);
+	*days = bcd2bin(values[3] & DAYS_BITS);
+	*months = bcd2bin(values[4] & MONTHS_BITS);
+	*years = bcd2bin(values[5] & YEARS_BITS) + 2000;
+	return 0;
+}
+
+static ssize_t pcf85263_timestamp_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf, int tsr_number)
+{
+	int err, seconds = 0, minutes = 0, hours = 0, days = 0, months = 0,
+	    years = 0;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+	unsigned char value;
+	char *event_message;
+	char *no_timestamp_defined = "No timestamp defined";
+	char *first_ts_event = "First TS event";
+	char *last_ts_event = "Last TS event";
+	char *first_switch_to_battery = "First switch to battery";
+	char *last_switch_to_battery = "Last switch to battery";
+	char *last_switch_to_vdd = "Last switch to Vdd";
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	dev_dbg(&client->dev, "[%s] timestamp %d\n", __func__, tsr_number);
+
+	mutex_lock(&pcf85263->mutex);
+	err =
+	    pcf85263_read_timestamp(dev, tsr_number, &seconds, &minutes,
+				    &hours, &days, &months, &years);
+	if (!err)
+		err =
+		    pcf85263_read_register(client, REGISTER_TSR_MODE,
+					   &value);
+	mutex_unlock(&pcf85263->mutex);
+	if (err)
+		return err;
+	if (tsr_number == 1) {
+		switch (value & TSR1M) {
+		case TSR1M_FIRST_TS_EVENT:
+			event_message = first_ts_event;
+			break;
+		case TSR1M_LAST_TS_EVENT:
+			event_message = last_ts_event;
+			break;
+		default:
+			event_message = no_timestamp_defined;
+		}
+	} else if (tsr_number == 2) {
+		switch (value & TSR2M) {
+		case TSR2M_FIRST_TS_EVENT:
+			event_message = first_ts_event;
+			break;
+		case TSR2M_LAST_TS_EVENT:
+			event_message = last_ts_event;
+			break;
+		case TSR2M_FIRST_SWITCH_TO_BATTERY:
+			event_message = first_switch_to_battery;
+			break;
+		case TSR2M_LAST_SWITCH_TO_BATTERY:
+			event_message = last_switch_to_battery;
+			break;
+		case TSR2M_LAST_SWITCH_TO_VDD:
+			event_message = last_switch_to_vdd;
+			break;
+		default:
+			event_message = no_timestamp_defined;
+		}
+	} else {
+		switch (value & TSR3M) {
+		case TSR3M_FIRST_SWITCH_TO_BATTERY:
+			event_message = first_switch_to_battery;
+			break;
+		case TSR3M_LAST_SWITCH_TO_BATTERY:
+			event_message = last_switch_to_battery;
+			break;
+		case TSR3M_LAST_SWITCH_TO_VDD:
+			event_message = last_switch_to_vdd;
+			break;
+		default:
+			event_message = no_timestamp_defined;
+		}
+	}
+
+	if (days == 0) {
+		return sprintf(buf,
+			       "yyyy/mm/dd hh:mm:ss Event\n----/--/-- --:--:-- %s\n",
+			       event_message);
+	} else {
+		return sprintf(buf,
+			       "yyyy/mm/dd hh:mm:ss Event\n%04d/%02d/%02d %02d:%02d:%02d %s\n",
+			       years, months, days, hours, minutes,
+			       seconds, event_message);
+	}
+}
+
+//================================================================================================
+static ssize_t pcf85263_flags_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	unsigned char value;
+	struct i2c_client *client;
+
+	client = to_i2c_client(dev);
+
+	if (pcf85263_read_register(client, REGISTER_FLAGS, &value) == 0)
+		return sprintf(buf, "%d\n", value);
+
+	return -1;
+}
+
+static ssize_t pcf85263_flags_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	int n;
+	unsigned char value;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	value = 0;
+	for (n = 0; n < count; n++) {
+		if ((*buf >= '0') && (*buf <= '9'))
+			value = (value * 10) + (*buf++ - '0');
+	}
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	if (value != 0) {
+		mutex_lock(&pcf85263->mutex);
+		if (pcf85263_write_register(client, REGISTER_FLAGS, value ^ 0xff) == 0) {
+			mutex_unlock(&pcf85263->mutex);
+			return count;
+		}
+		mutex_unlock(&pcf85263->mutex);
+	}
+	return -1;
+}
+
+static const struct device_attribute pcf85263_flags_attribute = {
+	.attr.name	= "flags",
+	.attr.mode	= 0600,
+	.show		= pcf85263_flags_show,
+	.store		= pcf85263_flags_store,
+};
+
+static ssize_t pcf85263_timestamp1_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return pcf85263_timestamp_show(dev, attr, buf, 1);
+}
+
+static const struct device_attribute pcf85263_timestamp1_attribute = {
+	.attr.name	= "timestamp1",
+	.attr.mode	= 0400,
+	.show		= pcf85263_timestamp1_show,
+};
+
+static ssize_t pcf85263_timestamp2_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return pcf85263_timestamp_show(dev, attr, buf, 2);
+}
+
+static const struct device_attribute pcf85263_timestamp2_attribute = {
+	.attr.name = "timestamp2",
+	.attr.mode = 0400,
+	.show = pcf85263_timestamp2_show,
+};
+
+static ssize_t pcf85263_timestamp3_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return pcf85263_timestamp_show(dev, attr, buf, 3);
+}
+
+static const struct device_attribute pcf85263_timestamp3_attribute = {
+	.attr.name = "timestamp3",
+	.attr.mode = 0400,
+	.show = pcf85263_timestamp3_show,
+
+};
+
+/*******************************************************************************
+ * Resets
+ */
+static ssize_t pcf85263_resets_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	return sprintf(buf, "software prescaler timestamps\n");
+}
+
+static ssize_t pcf85263_resets_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	int err = 0;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+	char buffer[11];
+	size_t chars_count;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	if (count < 8 || count > 11 || (count == 11 && buf[count - 1] != '\n'))
+		return -EINVAL;
+
+	chars_count = count;
+	if (buf[count - 1] == '\n')
+		chars_count--;
+	memcpy(buffer, buf, chars_count);
+	buffer[chars_count] = '\0';
+	mutex_lock(&pcf85263->mutex);
+	if (strcmp(buffer, "software") == 0) {
+		err =
+		    pcf85263_write_register(client, REGISTER_RESETS,
+					    SR_CMD);
+	} else if (strcmp(buffer, "prescaler") == 0) {
+		err =
+		    pcf85263_write_register(client, REGISTER_RESETS,
+					    CPR_CMD);
+	} else if (strcmp(buffer, "timestamps") == 0) {
+		err =
+		    pcf85263_write_register(client, REGISTER_RESETS,
+					    CTS_CMD);
+	} else {
+		err = -EINVAL;
+	}
+	mutex_unlock(&pcf85263->mutex);
+	if (err)
+		return err;
+	return count;
+}
+
+static const struct device_attribute pcf85263_resets_attribute = {
+	.attr.name = "resets",
+	.attr.mode = S_IRUSR | S_IWUSR,
+	.show = pcf85263_resets_show,
+	.store = pcf85263_resets_store,
+};
+
+/*******************************************************************************
+ * RTC
+ */
+static int pcf85263_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	int err;
+	unsigned char data[8];
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+
+	mutex_lock(&pcf85263->mutex);
+	err =
+	    pcf85263_read_registers(client, REGISTER_CENTS_OF_SECOND, data,
+				    sizeof(data));
+	mutex_unlock(&pcf85263->mutex);
+	if (err)
+		return err;
+	tm->tm_sec = bcd2bin(data[REGISTER_SECONDS] & SECONDS_BITS);
+	tm->tm_min = bcd2bin(data[REGISTER_MINUTES] & MINUTES_BITS);
+	tm->tm_hour = bcd2bin(data[REGISTER_HOURS] & HOURS_BITS);
+	tm->tm_mday = bcd2bin(data[REGISTER_DAYS] & DAYS_BITS);
+	tm->tm_mon = bcd2bin(data[REGISTER_MONTHS] & MONTHS_BITS) - 1;
+	tm->tm_year = bcd2bin(data[REGISTER_YEARS] & YEARS_BITS) + 100;
+	tm->tm_wday = bcd2bin(data[REGISTER_WEEKDAYS] & WEEKDAYS_BITS);
+	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+	/* Daylight Saving Time */
+	tm->tm_isdst = -1;
+	if (rtc_valid_tm(tm) < 0)
+		dev_err(dev, "retrieved date/time is not valid.\n");
+	return 0;
+}
+
+static int pcf85263_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	int err;
+	unsigned char data[11];
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	if (tm->tm_year < 100)
+		return -EINVAL;
+	data[0] = REGISTER_STOP_ENABLE;
+	data[1] = STOP_RTC_STOPPED;
+	data[2] = CPR_CMD;
+	data[3] = 0;		// cents of second
+	data[4] = bin2bcd(tm->tm_sec); // this will clear OS bit as well,
+	// which makes the oscillator start
+	// if it was stopped
+	data[5] = bin2bcd(tm->tm_min);
+	data[6] = bin2bcd(tm->tm_hour);
+	data[7] = bin2bcd(tm->tm_mday);
+	data[8] = bin2bcd(tm->tm_wday);
+	data[9] = bin2bcd(tm->tm_mon + 1);
+	data[10] = bin2bcd(tm->tm_year - 100);
+	mutex_lock(&pcf85263->mutex);
+	err = i2c_master_send(client, data, sizeof(data));
+	if (err != sizeof(data))
+		err = -EIO;
+	else
+		err =
+		    pcf85263_write_register(client, REGISTER_STOP_ENABLE,
+					    STOP_RTC_RUN);
+	mutex_unlock(&pcf85263->mutex);
+	return err;
+}
+
+/*******************************************************************************
+ * Alarm
+ */
+
+static int pcf85263_rtc_alarm_irq_enable(struct device *dev,
+					 unsigned int enabled)
+{
+	int err = 0;
+	unsigned char value;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	dev_dbg(&client->dev, "[%s] enabled = %u\n", __func__, enabled);
+	mutex_lock(&pcf85263->mutex);
+	if (pcf85263->interrupt_alarm != NO_INTERRUPT) {
+		/* enable/disable alarm1 */
+		if (pcf85263_read_register
+		    (client, REGISTER_ALARM_ENABLES, &value))
+			goto exit;
+		if (enabled)
+			value = (value & ~(ALARM1_BITS)) | ALARM1_ENABLE;
+		else
+			value = (value & ~(ALARM1_BITS)) | ALARM1_DISABLE;
+		if (pcf85263_write_register
+		    (client, REGISTER_ALARM_ENABLES, value))
+			goto exit;
+		/* enabled/disable irq for alarm1 */
+		if (pcf85263->interrupt_alarm == INTA) {
+			if (pcf85263_read_register
+			    (client, REGISTER_INTA_ENABLE, &value))
+				goto exit;
+			value &= ~A1IEA;
+			value |= (enabled ? A1IEA_ENABLE : A1IEA_DISABLE);
+			value &= ~ILPA;
+			value |= ILPA_PERMANENT_SIGNAL;
+			if (pcf85263_write_register
+			    (client, REGISTER_INTA_ENABLE, value))
+				goto exit;
+		} else {
+			if (pcf85263_read_register
+			    (client, REGISTER_INTB_ENABLE, &value))
+				goto exit;
+			value &= ~A1IEB;
+			value |= (enabled ? A1IEB_ENABLE : A1IEB_DISABLE);
+			value &= ~ILPB;
+			value |= ILPB_PERMANENT_SIGNAL;
+			if (pcf85263_write_register
+			    (client, REGISTER_INTB_ENABLE, value))
+				goto exit;
+		}
+		/* clean up interrupt flag when disabling */
+		if (!enabled) {
+			if (pcf85263_read_register
+			    (client, REGISTER_FLAGS, &value))
+				goto exit;
+			value =
+			    (value & ~(ALARM1_FLAG)) | ALARM1_FLAG_CLEAR;
+			if (pcf85263_write_register
+			    (client, REGISTER_FLAGS, value))
+				goto exit;
+		}
+	}
+exit:
+	mutex_unlock(&pcf85263->mutex);
+	return err;
+}
+
+static int pcf85263_rtc_read_alarm(struct device *dev,
+				   struct rtc_wkalrm *alarm)
+{
+	int err;
+	unsigned char data[5];
+	unsigned char value;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	mutex_lock(&pcf85263->mutex);
+	err = pcf85263_read_registers(client, REGISTER_SECOND_ALARM1, data,
+				      sizeof(data));
+	if (err)
+		goto exit;
+	alarm->time.tm_sec = bcd2bin(data[0] & SECONDS_BITS);
+	alarm->time.tm_min = bcd2bin(data[1] & MINUTES_BITS);
+	alarm->time.tm_hour = bcd2bin(data[2] & HOURS_BITS);
+	alarm->time.tm_mday = bcd2bin(data[3] & DAYS_BITS);
+	alarm->time.tm_mon = bcd2bin(data[4] & MONTHS_BITS) - 1;
+	err =
+	    pcf85263_read_register(client, REGISTER_ALARM_ENABLES, &value);
+	if (err)
+		goto exit;
+	alarm->enabled = ((value & ALARM1_BITS) == ALARM1_ENABLE) ?
+	    ALARM_ENABLED : ALARM_DISABLED;
+exit:
+	mutex_unlock(&pcf85263->mutex);
+	return err;
+}
+
+static int pcf85263_rtc_set_alarm(struct device *dev,
+				  struct rtc_wkalrm *alarm)
+{
+	int err;
+	unsigned char data[6];
+	unsigned char value;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	data[0] = REGISTER_SECOND_ALARM1;
+	data[1] = bin2bcd(alarm->time.tm_sec);
+	data[2] = bin2bcd(alarm->time.tm_min);
+	data[3] = bin2bcd(alarm->time.tm_hour);
+	data[4] = bin2bcd(alarm->time.tm_mday);
+	data[5] = bin2bcd(alarm->time.tm_mon + 1);
+	mutex_lock(&pcf85263->mutex);
+	err = i2c_master_send(client, data, sizeof(data));
+	if (err != sizeof(data)) {
+		err = -EIO;
+		goto exit;
+	}
+	if (alarm->enabled) {
+		err =
+		    pcf85263_write_register(client, REGISTER_ALARM_ENABLES,
+					    ALARM1_ENABLE |
+					    ALARM2_DISABLE);
+	} else {
+		err =
+		    pcf85263_write_register(client, REGISTER_ALARM_ENABLES,
+					    ALARM1_DISABLE |
+					    ALARM2_DISABLE);
+	}
+	if (err)
+		goto exit;
+
+	/* enabled/disable irq for alarm1 */
+	if (pcf85263->interrupt_alarm == INTA) {
+		if (pcf85263_read_register
+		    (client, REGISTER_INTA_ENABLE, &value))
+			goto exit;
+		value &= ~A1IEA;
+		value |= (alarm->enabled ? A1IEA_ENABLE : A1IEA_DISABLE);
+		value &= ~ILPA;
+		value |= ILPA_PERMANENT_SIGNAL;
+		if (pcf85263_write_register
+		    (client, REGISTER_INTA_ENABLE, value))
+			goto exit;
+	} else if (pcf85263->interrupt_alarm == INTB) {
+		if (pcf85263_read_register
+		    (client, REGISTER_INTB_ENABLE, &value))
+			goto exit;
+		value &= ~A1IEB;
+		value |= (alarm->enabled ? A1IEB_ENABLE : A1IEB_DISABLE);
+		value &= ~ILPB;
+		value |= ILPB_PERMANENT_SIGNAL;
+		if (pcf85263_write_register
+		    (client, REGISTER_INTB_ENABLE, value))
+			goto exit;
+	}
+	/* clean up interrupt flag when disabling */
+	if (!alarm->enabled) {
+		if (pcf85263_read_register(client, REGISTER_FLAGS, &value))
+			goto exit;
+		value = (value & ~(ALARM1_FLAG)) | ALARM1_FLAG_CLEAR;
+		if (pcf85263_write_register(client, REGISTER_FLAGS, value))
+			goto exit;
+	}
+
+exit:
+	mutex_unlock(&pcf85263->mutex);
+	return err;
+}
+
+static int pcf85263_rtc_ioctl(struct device *dev,
+			      unsigned int cmd, unsigned long arg)
+{
+	int ret;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+	unsigned char user_value;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	switch (cmd) {
+	case RTC_WAIT_FOR_INTERRUPTS:
+		if (copy_from_user
+		    (&user_value, (unsigned char __user *)arg,
+		     sizeof(unsigned char)))
+			return -EFAULT;
+		ret = wait_event_interruptible(pcf85263->event_queue,
+					       ((user_value &
+						 pcf85263->event_interrupt)
+						== user_value));
+		if (ret)
+			return -ERESTARTSYS;
+		mutex_lock(&pcf85263->mutex);
+		pcf85263->event_interrupt &= ~user_value;
+		mutex_unlock(&pcf85263->mutex);
+		return 0;
+	case RTC_WAIT_FOR_ANY_INTERRUPT:
+		ret = wait_event_interruptible(pcf85263->event_queue,
+					       (pcf85263->event_interrupt
+						!= 0));
+		if (ret)
+			return -ERESTARTSYS;
+		mutex_lock(&pcf85263->mutex);
+		user_value = pcf85263->event_interrupt;
+		pcf85263->event_interrupt = 0;
+		mutex_unlock(&pcf85263->mutex);
+		if (copy_to_user((unsigned char __user *)arg, &user_value,
+				 sizeof(unsigned char)))
+			return -EFAULT;
+		return 0;
+	case RTC_CLEAR_INTERRUPT_FLAGS:
+		if (copy_from_user
+		    (&user_value, (unsigned char __user *)arg,
+		     sizeof(unsigned char)))
+			return -EFAULT;
+		mutex_lock(&pcf85263->mutex);
+		pcf85263->event_interrupt &= ~user_value;
+		mutex_unlock(&pcf85263->mutex);
+		return 0;
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static const struct rtc_class_ops pcf85263_rtc_ops = {
+	/* RTC callbacks */
+	.set_time = pcf85263_rtc_set_time,
+	.read_time = pcf85263_rtc_read_time,
+	/* alarm callbacks */
+	.set_alarm = pcf85263_rtc_set_alarm,
+	.read_alarm = pcf85263_rtc_read_alarm,
+	.alarm_irq_enable = pcf85263_rtc_alarm_irq_enable,
+	/* custom APIs */
+	.ioctl = pcf85263_rtc_ioctl,
+};
+
+/*******************************************************************************
+ * RAM byte
+ */
+static ssize_t pcf85263_ram_byte_show(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	int err;
+	unsigned char ram_byte;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	mutex_lock(&pcf85263->mutex);
+	err = pcf85263_read_register(client, REGISTER_RAM_BYTE, &ram_byte);
+	mutex_unlock(&pcf85263->mutex);
+	if (err)
+		return err;
+	return sprintf(buf, "%hhu\n", ram_byte);
+}
+
+static ssize_t pcf85263_ram_byte_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	int err;
+	unsigned char ram_byte;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	err = kstrtou8(buf, 10, &ram_byte);
+	if (err)
+		return err;
+	mutex_lock(&pcf85263->mutex);
+	err = pcf85263_write_register(client, REGISTER_RAM_BYTE, ram_byte);
+	mutex_unlock(&pcf85263->mutex);
+	if (err)
+		return err;
+	return count;
+}
+
+static const struct device_attribute pcf85263_ram_byte_device_attribute = {
+	.attr.name = "ram_byte",
+	.attr.mode = S_IRUSR | S_IWUSR,
+	.show = pcf85263_ram_byte_show,
+	.store = pcf85263_ram_byte_store,
+};
+
+/*******************************************************************************
+ * REGISTERS utility
+ */
+static ssize_t pcf85263_registers_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	int err;
+	unsigned char i, data[48];
+	size_t printed_chars = 0;
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+	mutex_lock(&pcf85263->mutex);
+	err = pcf85263_read_registers(client, REGISTER_CENTS_OF_SECOND,
+				      data, sizeof(data));
+	mutex_unlock(&pcf85263->mutex);
+	if (err)
+		return err;
+	err = sprintf(buf, "Reg  Val\n");
+	if (err < 0)
+		return err;
+	printed_chars += err;
+	for (i = 0; i < sizeof(data); i++) {
+		err =
+		    sprintf(&buf[printed_chars], "0x%02hhx 0x%02hhx\n", i,
+			    data[i]);
+		if (err < 0)
+			return err;
+		printed_chars += err;
+	}
+	return printed_chars;
+}
+
+static ssize_t pcf85263_registers_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int err;
+	unsigned char address, value;
+	char address_string[3], value_string[3];
+	struct i2c_client *client;
+	struct pcf85263 *pcf85263;
+
+	client = to_i2c_client(dev);
+	pcf85263 = i2c_get_clientdata(client);
+#define is_hexadecimal(x)       ((x >= '0' && x <= '9') || \
+				(x >= 'a' && x <= 'f') || \
+				(x >= 'A' && x <= 'F'))
+	if (count != 10)
+		return -EINVAL;
+	if (!(buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X') &&
+	    buf[5] == '0' && (buf[6] == 'x' || buf[6] == 'X') &&
+	    is_hexadecimal(buf[2]) &&
+	    is_hexadecimal(buf[3]) &&
+	    is_hexadecimal(buf[7]) && is_hexadecimal(buf[8])))
+		return -EINVAL;
+	address_string[0] = buf[2];
+	address_string[1] = buf[3];
+	address_string[2] = '\0';
+	value_string[0] = buf[7];
+	value_string[1] = buf[8];
+	value_string[2] = '\0';
+	err = kstrtou8(address_string, 16, &address);
+	if (err)
+		return err;
+	err = kstrtou8(value_string, 16, &value);
+	if (err)
+		return err;
+	if (address > REGISTER_RESETS)
+		return -EINVAL;
+	mutex_lock(&pcf85263->mutex);
+	err = pcf85263_write_register(client, address, value);
+	mutex_unlock(&pcf85263->mutex);
+	if (err)
+		return err;
+	return count;
+}
+
+static const struct device_attribute pcf85263_registers_device_attribute = {
+	.attr.name = "registers",
+	.attr.mode = S_IRUSR | S_IWUSR,
+	.show = pcf85263_registers_show,
+	.store = pcf85263_registers_store,
+};
+
+/*******************************************************************************
+ * HW initialization
+ */
+static int pcf85263_init(struct i2c_client *client)
+{
+	int err;
+	unsigned char value;
+	struct pcf85263 *pcf85263;
+
+	pcf85263 = i2c_get_clientdata(client);
+	/*
+	 * Start the OSC if required. This operation can tamper with time.
+	 */
+	err = pcf85263_read_register(client, REGISTER_SECONDS, &value);
+	if (err)
+		return err;
+
+	// We should only write to this register if the OS bit is high otherwise we risk the
+	// SECONDS changing between the read and the write which will cause us to lose a second.
+	if (value & OS_SET) {
+		//If the OS bit is high, clear the bit to start the Oscillator
+		value &= ~OS;
+
+		err = pcf85263_write_register(client, REGISTER_SECONDS, value);
+		if (err)
+			return err;
+	}
+
+	/*
+	 * Initializing function register
+	 */
+	err = pcf85263_read_register(client, REGISTER_FUNCTION, &value);
+	if (err)
+		return err;
+	/* We don't support stop-watch mode, setting RTC mode. */
+	value &= ~RTCM;
+	value |= RTCM_RTC_MODE;
+	value &= ~COF;
+	value |= (unsigned char)pcf85263->clock_frequency;
+	err = pcf85263_write_register(client, REGISTER_FUNCTION, value);
+	if (err)
+		return err;
+
+	/*
+	 * We don't support 12 hour mode, setting 24 hour mode.
+	 */
+	err = pcf85263_read_register(client, REGISTER_OSCILLATOR, &value);
+	if (err)
+		return err;
+	value &= ~AMPM_12_24;
+	value |= AMPM_24_HOUR_MODE;
+	value &= ~XTAL_CAP_LOAD;
+	value |= XTAL_CAP_12_5_pf;	//We use a 12.5pF load capacitance
+	err = pcf85263_write_register(client, REGISTER_OSCILLATOR, value);
+	if (err)
+		return err;
+
+	/*
+	 * Initializing battery switch register
+	 */
+	err =
+	    pcf85263_read_register(client, REGISTER_BATTERY_SWITCH,
+				   &value);
+	if (err)
+		return err;
+	value &= ~BSRR;
+	value |= BSRR_LOW;
+	value &= ~BSOFF;
+	if (pcf85263->battery_switch == BATTERY_SWITCH_OFF) {
+		value |= BSOFF_DISABLE;
+	} else {
+		value |= BSOFF_ENABLE;
+		value &= ~BSM;
+		if (pcf85263->battery_switch == BATTERY_SWITCH_VTH)
+			value |= BSM_VTH;
+		else if (pcf85263->battery_switch == BATTERY_SWITCH_VBAT)
+			value |= BSM_VBAT;
+		else if (pcf85263->battery_switch == BATTERY_SWITCH_HIGHER)
+			value |= BSM_HIGHER;
+		else
+			value |= BSM_LOWER;
+		value &= ~BSTH;
+		if (pcf85263->battery_vth == BATTERY_VTH_1_5)
+			value |= BSTH_1_5;
+		else
+			value |= BSTH_2_8;
+	}
+	err = pcf85263_write_register(client, REGISTER_BATTERY_SWITCH, value);
+	if (err)
+		return err;
+
+	/*
+	 * Timestamps initialization
+	 */
+	err = pcf85263_read_register(client, REGISTER_TSR_MODE, &value);
+	if (err)
+		return err;
+	value &= ~TSR1M;
+	value |= (unsigned char)pcf85263->timestamp1_mode;
+	value &= ~TSR2M;
+	value |= (unsigned char)pcf85263->timestamp2_mode;
+	value &= ~TSR3M;
+	value |= (unsigned char)pcf85263->timestamp3_mode;
+	err = pcf85263_write_register(client, REGISTER_TSR_MODE, value);
+	if (err)
+		return err;
+
+	/*
+	 * INTA enable register initialization
+	 */
+	err = pcf85263_read_register(client, REGISTER_INTA_ENABLE, &value);
+	if (err)
+		return err;
+	if (pcf85263->watchdog_disable_on_boot) {
+		dev_info(&client->dev, "disabling watchdog interrupt\n");
+		value &= ~WDIEA;
+		value |= WDIEA_DISABLE;
+	}
+	value &= ~BSIEA;
+	if (pcf85263->interrupt_battery == INTA)
+		value |= BSIEA_ENABLE;
+	else
+		value |= BSIEA_DISABLE;
+	value &= ~TSRIEA;
+	if (pcf85263->interrupt_timestamp == INTA)
+		value |= TSRIEA_ENABLE;
+	else
+		value |= TSRIEA_DISABLE;
+	err = pcf85263_write_register(client, REGISTER_INTA_ENABLE, value);
+	if (err)
+		return err;
+
+	/*
+	 * INTB enable register initialization
+	 */
+	err = pcf85263_read_register(client, REGISTER_INTB_ENABLE, &value);
+	if (err)
+		return err;
+	if (pcf85263->watchdog_disable_on_boot) {
+		value &= ~WDIEB;
+		value |= WDIEB_DISABLE;
+	}
+	value &= ~BSIEB;
+	if (pcf85263->interrupt_battery == INTB)
+		value |= BSIEB_ENABLE;
+	else
+		value |= BSIEB_DISABLE;
+	value &= ~TSRIEB;
+	if (pcf85263->interrupt_timestamp == INTB)
+		value |= TSRIEB_ENABLE;
+	else
+		value |= TSRIEB_DISABLE;
+	err = pcf85263_write_register(client, REGISTER_INTB_ENABLE, value);
+	if (err)
+		return err;
+
+	/*
+	 * Watchdog register initialization
+	 */
+	err = pcf85263_read_register(client, REGISTER_WATCHDOG, &value);
+	if (err)
+		return err;
+	value &= ~WDM;
+	value |= WDM_SINGLE_SHOT;
+	err = pcf85263_write_register(client, REGISTER_WATCHDOG, value);
+	if (err)
+		return err;
+
+	/*
+	 * Initializing Pin I/O
+	 */
+	err = pcf85263_read_register(client, REGISTER_PIN_IO, &value);
+	if (err)
+		return err;
+	/* CLKPM */
+	value &= ~CLKPM;
+	value |= (unsigned char)pcf85263->clk_pin;
+	/* TSPULL */
+	value &= ~TSPULL;
+	value |= (unsigned char)pcf85263->ts_pin_pull;
+	/* TSL */
+	value &= ~TSL;
+	value |= (unsigned char)pcf85263->ts_pin_level;
+	/* TSIM */
+	value &= ~TSIM;
+	value |= (unsigned char)pcf85263->ts_pin_input_type;
+	/* TSPM */
+	value &= ~TSPM;
+	value |= (unsigned char)pcf85263->ts_pin;
+	/* INTAPM */
+	value &= ~INTAPM;
+	value |= (unsigned char)pcf85263->inta_pin;
+	err = pcf85263_write_register(client, REGISTER_PIN_IO, value);
+	if (err)
+		return err;
+
+// Clear interrupt flags, but leave the time stamp flags
+	err = pcf85263_write_register(client, REGISTER_FLAGS, 0x07);
+
+	return err;
+}
+
+static void pcf85263_unload(struct i2c_client *client)
+{
+	struct pcf85263 *pcf85263;
+	int err;
+
+	pcf85263 = i2c_get_clientdata(client);
+	if (pcf85263->ram_byte_file_created) {
+		sysfs_remove_file(&client->dev.kobj,
+				  &pcf85263_ram_byte_device_attribute.attr);
+	}
+
+	if (pcf85263->flags_file_created) {
+		sysfs_remove_file(&client->dev.kobj,
+				  &pcf85263_flags_attribute.attr);
+	}
+
+	if (pcf85263->registers_file_created) {
+		sysfs_remove_file(&client->dev.kobj,
+				  &pcf85263_registers_device_attribute.attr);
+	}
+	if (pcf85263->timestamp1_file_created) {
+		sysfs_remove_file(&client->dev.kobj,
+				  &pcf85263_timestamp1_attribute.attr);
+		pcf85263->timestamp1_file_created = 0;
+	}
+	if (pcf85263->timestamp2_file_created) {
+		sysfs_remove_file(&client->dev.kobj,
+				  &pcf85263_timestamp2_attribute.attr);
+		pcf85263->timestamp2_file_created = 0;
+	}
+	if (pcf85263->timestamp3_file_created) {
+		sysfs_remove_file(&client->dev.kobj,
+				  &pcf85263_timestamp3_attribute.attr);
+		pcf85263->timestamp3_file_created = 0;
+	}
+	if (pcf85263->resets_file_created) {
+		sysfs_remove_file(&client->dev.kobj,
+				  &pcf85263_resets_attribute.attr);
+		pcf85263->resets_file_created = 0;
+	}
+	if (wdten == 1) {
+		dev_dbg(&client->dev, "[%s] watchdog unregister\n",
+			__func__);
+		watchdog_unregister_device(&pcf85263_watchdog_device);
+	}
+	dev_dbg(&client->dev, "[%s] pinctrl sleep state\n", __func__);
+	pinctrl_pm_select_sleep_state(&client->dev);
+	dev_dbg(&client->dev, "[%s] devm_kfree\n", __func__);
+	err = device_init_wakeup(&client->dev, false);
+	if (err)
+		dev_err(&client->dev, "dev_init_wakeup [%d] FAIL\n", err);
+	devm_kfree(&client->dev, pcf85263);
+}
+
+/*
+ * Driver hooks
+ */
+static int pcf85263_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	int err;
+	struct pcf85263 *pcf85263;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		return -ENODEV;
+
+	pcf85263 =
+	    devm_kzalloc(&client->dev, sizeof(struct pcf85263),
+			 GFP_KERNEL);
+	if (!pcf85263) {
+		dev_dbg(&client->dev,
+			"[%s] Impossible to allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+	pcf85263->ram_byte_file_created = 0;
+	pcf85263->registers_file_created = 0;
+	pcf85263->timestamp1_file_created = 0;
+	pcf85263->timestamp2_file_created = 0;
+	pcf85263->timestamp3_file_created = 0;
+	pcf85263->resets_file_created = 0;
+	pcf85263->inta_irq = -1;
+	pcf85263->intb_irq = -1;
+	pcf85263->battery_switch = BATTERY_SWITCH_OFF;
+	pcf85263->battery_vth = BATTERY_VTH_1_5;
+	init_waitqueue_head(&pcf85263->event_queue);
+	if (timeout < 1 || timeout > 124) {
+		dev_dbg(&client->dev,
+			"[%s] timeout (= %d) out of bounds ([1,124])\n",
+			__func__, timeout);
+		timeout = WATCHDOG_TIMEOUT;
+	}
+	pcf85263->watchdog_timeout = timeout;
+	mutex_init(&pcf85263->mutex);
+
+	dev_info(&client->dev,
+		 "chip found, driver version " DRIVER_VERSION "\n");
+
+	i2c_set_clientdata(client, pcf85263);
+	pcf85263->client = client;
+	pcf85263->rtc = devm_rtc_device_register(&client->dev,
+						 pcf85263_driver.driver.name,
+						 &pcf85263_rtc_ops,
+						 THIS_MODULE);
+	err = PTR_ERR_OR_ZERO(pcf85263->rtc);
+	if (err) {
+		dev_err(&client->dev, "unable to register RTC device\n");
+		goto exit;
+	}
+
+	pcf85263->rtc->uie_unsupported = 1;
+	/* RAM byte initialization */
+	err = sysfs_create_file(&client->dev.kobj,
+				&pcf85263_ram_byte_device_attribute.attr);
+	if (err) {
+		dev_err(&client->dev,
+			"unable to create sysfs file \"%s\"\n",
+			pcf85263_ram_byte_device_attribute.attr.name);
+		goto exit;
+	}
+	pcf85263->ram_byte_file_created = 1;
+
+	/* Registers debug initialization */
+	err = sysfs_create_file(&client->dev.kobj,
+				&pcf85263_registers_device_attribute.attr);
+	if (err) {
+		dev_err(&client->dev,
+			"unable to create sysfs file \"%s\"\n",
+			pcf85263_registers_device_attribute.attr.name);
+		goto exit;
+	}
+	pcf85263->registers_file_created = 1;
+
+	/* flags initialization */
+	err =
+	    sysfs_create_file(&client->dev.kobj,
+			      &pcf85263_flags_attribute.attr);
+	if (err) {
+		dev_err(&client->dev,
+			"unable to create sysfs file \"%s\"\n",
+			pcf85263_flags_attribute.attr.name);
+		goto exit;
+	}
+	pcf85263->flags_file_created = 1;
+
+	/* Timestamp 1 initialization */
+	err = sysfs_create_file(&client->dev.kobj,
+				&pcf85263_timestamp1_attribute.attr);
+	if (err) {
+		dev_err(&client->dev,
+			"unable to create sysfs file \"%s\"\n",
+			pcf85263_timestamp1_attribute.attr.name);
+		goto exit;
+	}
+	pcf85263->timestamp1_file_created = 1;
+
+	/* Timestamp 2 initialization */
+	err = sysfs_create_file(&client->dev.kobj,
+				&pcf85263_timestamp2_attribute.attr);
+	if (err) {
+		dev_err(&client->dev,
+			"unable to create sysfs file \"%s\"\n",
+			pcf85263_timestamp2_attribute.attr.name);
+		goto exit;
+	}
+	pcf85263->timestamp2_file_created = 1;
+
+	/* Timestamp 3 initialization */
+	err = sysfs_create_file(&client->dev.kobj,
+				&pcf85263_timestamp3_attribute.attr);
+	if (err) {
+		dev_err(&client->dev,
+			"unable to create sysfs file \"%s\"\n",
+			pcf85263_timestamp3_attribute.attr.name);
+		goto exit;
+	}
+	pcf85263->timestamp3_file_created = 1;
+
+	/* Create resets file */
+	err = sysfs_create_file(&client->dev.kobj,
+				&pcf85263_resets_attribute.attr);
+	if (err) {
+		dev_err(&client->dev,
+			"unable to create sysfs file \"%s\"\n",
+			pcf85263_resets_attribute.attr.name);
+	}
+	pcf85263->resets_file_created = 1;
+
+	/* Battery switch specific device tree properties */
+	pcf85263->battery_switch = BATTERY_SWITCH_VTH;
+	if (vth == 0)
+		pcf85263->battery_vth = BATTERY_VTH_1_5;
+	else
+		pcf85263->battery_vth = BATTERY_VTH_2_8;
+	/* Battery switch interrupt initialization */
+
+	pcf85263->interrupt_battery = INTA;
+	if (strcmp(int_batt, "INTA"))
+		pcf85263->interrupt_battery = INTA;
+	else if (strcmp(int_batt, "INTB"))
+		pcf85263->interrupt_battery = INTB;
+	else if (strcmp(int_batt, "NO_INTERRUPT"))
+		pcf85263->interrupt_battery = NO_INTERRUPT;
+
+	/* Timestamps specific device tree properties setup */
+	pcf85263->timestamp1_mode = TSR1M_LAST_TS_EVENT;
+	pcf85263->timestamp2_mode = TSR2M_LAST_SWITCH_TO_BATTERY;
+	pcf85263->timestamp3_mode = TSR3M_LAST_SWITCH_TO_VDD;
+	pcf85263->interrupt_timestamp = INTB;
+	if (strcmp(int_tst, "INTA"))
+		pcf85263->interrupt_timestamp = INTA;
+	else if (strcmp(int_tst, "INTB"))
+		pcf85263->interrupt_timestamp = INTB;
+	else if (strcmp(int_tst, "NO_INTERRUPT"))
+		pcf85263->interrupt_timestamp = NO_INTERRUPT;
+
+	pcf85263->interrupt_watchdog = NO_INTERRUPT;
+	if (strcmp(int_wdt, "INTA"))
+		pcf85263->interrupt_watchdog = INTA;
+	else if (strcmp(int_wdt, "INTB"))
+		pcf85263->interrupt_watchdog = INTB;
+	else if (strcmp(int_wdt, "NO_INTERRUPT"))
+		pcf85263->interrupt_watchdog = NO_INTERRUPT;
+
+	/* INTA pin configuration */
+
+	pcf85263->inta_pin = INTAPM_INTA;
+	if (strcmp(intapm_conf, "INTAPM_CLK_OUTPUT"))
+		pcf85263->inta_pin = INTA;
+	else if (strcmp(intapm_conf, "INTAPM_BATTERY_MODE_INDICATION"))
+		pcf85263->inta_pin = INTB;
+	else if (strcmp(intapm_conf, "INTAPM_INTA"))
+		pcf85263->inta_pin = INTAPM_INTA;
+	else if (strcmp(intapm_conf, "INTAPM_HIGH_IMPEDANCE"))
+		pcf85263->inta_pin = INTAPM_HIGH_IMPEDANCE;
+
+	pcf85263->ts_pin = TSPM_DISABLED;
+	if (strcmp(tspm, "TSPM_DISABLED") == 0)
+		pcf85263->ts_pin = TSPM_DISABLED;
+	else if (strcmp(tspm, "TSPM_INT") == 0)
+		pcf85263->ts_pin = TSPM_INTB;
+	else if (strcmp(tspm, "TSPM_CLK_OUTPUT") == 0)
+		pcf85263->ts_pin = TSPM_CLK_OUTPUT;
+	else if (strcmp(tspm, "TSPM_INPUT_MODE") == 0)
+		pcf85263->ts_pin = TSPM_INPUT_MODE;
+
+	pcf85263->clock_frequency = COF_32768;
+	pcf85263->clk_pin = CLKPM_ENABLE;
+
+	/* TS pin configuration */
+	pcf85263->ts_pin_pull = TSPULL_80_K_OHM;
+
+	if (tsl == 0)
+		pcf85263->ts_pin_level = TSL_ACTIVE_LOW;
+	else
+		pcf85263->ts_pin_level = TSL_ACTIVE_HIGH;
+
+	pcf85263->ts_pin_input_type = TSIM_MECHANICAL_SWITCH_MODE;
+	/* Watchdog specific device tree properties setup */
+	pcf85263->watchdog_disable_on_boot = 0;
+	/* Init the chip with the desired configuration */
+	err = pcf85263_init(client);
+	if (err) {
+		dev_err(&client->dev, "unable to init RTC device\n");
+		goto exit;
+	}
+
+	if (pinctrl_pm_select_default_state(&client->dev))
+		goto exit;
+
+	if (wakeen == 1) {
+		err = device_init_wakeup(&client->dev, true);
+		if (err)
+			dev_err(&client->dev,
+				"dev_init_wakeup [%d] FAIL\n", err);
+	}
+
+	if (wdten == 1) {
+		watchdog_set_drvdata(&pcf85263_watchdog_device, client);
+		watchdog_init_timeout(&pcf85263_watchdog_device,
+				      pcf85263->watchdog_timeout, NULL);
+		watchdog_set_nowayout(&pcf85263_watchdog_device, nowayout);
+		err = watchdog_register_device(&pcf85263_watchdog_device);
+		if (err)
+			goto exit;
+		dev_info(&client->dev, "registered %s as watchdog%d\n",
+			 pcf85263_driver.driver.name,
+			 pcf85263_watchdog_device.id);
+	}
+	dev_info(&client->dev, "probe_end, init OK\n");
+	return 0;
+exit:
+	pcf85263_unload(client);
+	return err;
+}
+
+static int pcf85263_remove(struct i2c_client *client)
+{
+	pcf85263_unload(client);
+	return 0;
+}
+
+static const struct i2c_device_id pcf85263_id[] = {
+	{"pcf85263", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, pcf85263_id);
+
+static struct of_device_id pcf85263_of_match[] = {
+	{.compatible = "nxp,pcf85263"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, pcf85263_of_match);
+
+#ifdef CONFIG_PM_SLEEP
+static int pcf85263_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pcf85263 *pcf85263;
+
+	pcf85263 = i2c_get_clientdata(client);
+
+	if (pcf85263->inta_irq >= 0 && device_may_wakeup(&client->dev))
+		enable_irq_wake(pcf85263->inta_irq);
+
+	return 0;
+}
+
+static int pcf85263_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pcf85263 *pcf85263;
+	void __iomem *reg0 = ioremap(GPIO0_IRQSTATUS_0_ADDR, 4);
+	void __iomem *reg1 = ioremap(GPIO0_IRQSTATUS_1_ADDR, 4);
+
+	pcf85263 = i2c_get_clientdata(client);
+
+	if (pcf85263->inta_irq >= 0 && device_may_wakeup(&client->dev)) {
+		disable_irq_wake(pcf85263->inta_irq);
+		writel(GPIO0_19_SET_BIT_ACK, reg0);
+		writel(GPIO0_19_SET_BIT_ACK, reg1);
+	}
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pcf85263_pm, pcf85263_suspend, pcf85263_resume);
+
+static struct i2c_driver pcf85263_driver = {
+	.driver = {
+		   .name = "rtc-pcf85263",
+		   .owner = THIS_MODULE,
+		   .pm = &pcf85263_pm,
+		   .of_match_table = of_match_ptr(pcf85263_of_match),
+		   },
+	.probe = pcf85263_probe,
+	.remove = pcf85263_remove,
+	.id_table = pcf85263_id,
+};
+
+module_i2c_driver(pcf85263_driver);
+
+MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro@eurotech.com>");
+MODULE_DESCRIPTION("NXP PCF85263 driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/rtc/rtc-pcf85263.h b/drivers/rtc/rtc-pcf85263.h
new file mode 100644
index 0000000000000..59375c2633069
--- /dev/null
+++ b/drivers/rtc/rtc-pcf85263.h
@@ -0,0 +1,387 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ * NXP PCF85263 RTC driver
+ * Copyright (C) 2015 Eurotech Ltd Fabrizio Castro
+ *
+ * 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 2
+ * 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 __RTC_PCF85263_H__
+#define __RTC_PCF85263_H__
+
+#define DRIVER_VERSION "0.1"
+
+#define BIT0 0x01
+#define BIT1 0x02
+#define BIT2 0x04
+#define BIT3 0x08
+#define BIT4 0x10
+#define BIT5 0x20
+#define BIT6 0x40
+#define BIT7 0x80
+
+/*
+ * RTC mode time registers
+ * RTCM = 0
+ */
+
+// RTC time and date registers
+#define REGISTER_CENTS_OF_SECOND 0x00
+#define CENTS_OF_SECONDS_BITS 0xFF
+
+#define REGISTER_SECONDS 0x01
+#define SECONDS_BITS 0x7F
+#define OS BIT7
+#define OS_SET BIT7
+#define OS_CLEAR 0x00
+
+#define REGISTER_MINUTES 0x02
+#define MINUTES_BITS 0x7F
+#define EMON BIT7
+
+#define REGISTER_HOURS 0x03
+#define HOURS_BITS 0x3F
+
+#define REGISTER_DAYS 0x04
+#define DAYS_BITS 0x3F
+
+#define REGISTER_WEEKDAYS 0x05
+#define WEEKDAYS_BITS 0x03
+
+#define REGISTER_MONTHS 0x06
+#define MONTHS_BITS 0x1F
+
+#define REGISTER_YEARS 0x07
+#define YEARS_BITS 0xFF
+
+// RTC alarm1
+#define REGISTER_SECOND_ALARM1 0x08
+
+#define REGISTER_MINUTE_ALARM1 0x09
+
+#define REGISTER_HOUR_ALARM1 0x0A
+
+#define REGISTER_DAY_ALARM1 0x0B
+
+#define REGISTER_MONTH_ALARM1 0x0C
+
+// RTC alarm2
+#define REGISTER_MINUTE_ALARM2 0x0D
+
+#define REGISTER_HOUR_ALARM2 0x0E
+
+#define REGISTER_WEEKDAY_ALARM2 0x0F
+
+// RTC alarm enables
+#define REGISTER_ALARM_ENABLES 0x10
+#define WDAY_A2E BIT7
+#define WDAY_A2E_ENABLE BIT7
+#define WDAY_A2E_DISABLE 0x00
+#define HR_A2E BIT6
+#define HR_A2E_ENABLE BIT6
+#define HR_A2E_DISABLE 0x00
+#define MIN_A2E BIT5
+#define MIN_A2E_ENABLE BIT5
+#define MIN_A2E_DISABLE 0x00
+#define MON_A1E BIT4
+#define MON_A1E_ENABLE BIT4
+#define MON_A1E_DISABLE 0x00
+#define DAY_A1E BIT3
+#define DAY_A1E_ENABLE BIT3
+#define DAY_A1E_DISABLE 0x00
+#define HR_A1E BIT2
+#define HR_A1E_ENABLE BIT2
+#define HR_A1E_DISABLE 0x00
+#define MIN_A1E BIT1
+#define MIN_A1E_ENABLE BIT1
+#define MIN_A1E_DISABLE 0x00
+#define SEC_A1E BIT0
+#define SEC_A1E_ENABLE BIT0
+#define SEC_A1E_DISABLE 0x00
+#define ALARM1_BITS (MON_A1E | \
+	DAY_A1E | \
+	HR_A1E | \
+	MIN_A1E | \
+	SEC_A1E)
+#define ALARM1_ENABLE (MON_A1E_ENABLE | \
+	DAY_A1E_ENABLE | \
+	HR_A1E_ENABLE | \
+	MIN_A1E_ENABLE | \
+	SEC_A1E_ENABLE)
+#define ALARM1_DISABLE (MON_A1E_DISABLE | \
+	DAY_A1E_DISABLE | \
+	HR_A1E_DISABLE | \
+	MIN_A1E_DISABLE | \
+	SEC_A1E_DISABLE)
+#define ALARM2_ENABLE (WDAY_A2E_ENABLE | \
+	HR_A2E_ENABLE | \
+	MIN_A2E_ENABLE)
+#define ALARM2_DISABLE (WDAY_A2E_DISABLE | \
+	HR_A2E_DISABLE | \
+	MIN_A2E_DISABLE)
+
+// RTC timestamp1 (TSR1)
+#define REGISTER_TSR1_SECONDS 0x11
+
+#define REGISTER_TSR1_MINUTES 0x12
+
+#define REGISTER_TSR1_HOURS 0x13
+
+#define REGISTER_TSR1_DAYS 0x14
+
+#define REGISTER_TSR1_MONTHS 0x15
+
+#define REGISTER_TSR1_YEARS 0x16
+
+// RTC timestamp2 (TSR2)
+#define REGISTER_TSR2_SECONDS 0x17
+
+#define REGISTER_TSR2_MINUTES 0x18
+
+#define REGISTER_TSR2_HOURS 0x19
+
+#define REGISTER_TSR2_DAYS 0x1A
+
+#define REGISTER_TSR2_MONTHS 0x1B
+
+#define REGISTER_TSR2_YEARS 0x1C
+
+// RTC timestamp3 (TSR3)
+#define REGISTER_TSR3_SECONDS 0x1D
+
+#define REGISTER_TSR3_MINUTES 0x1E
+
+#define REGISTER_TSR3_HOURS 0x1F
+
+#define REGISTER_TSR3_DAYS 0x20
+
+#define REGISTER_TSR3_MONTHS 0x21
+
+#define REGISTER_TSR3_YEARS 0x22
+
+// RTC timestamp mode control
+#define REGISTER_TSR_MODE 0x23
+#define TSR1M (BIT1 | BIT0)
+#define TSR1M_NO_TIMESTAMP 0x00
+#define TSR1M_FIRST_TS_EVENT BIT0
+#define TSR1M_LAST_TS_EVENT BIT1
+#define TSR2M (BIT4 | BIT3 | BIT2)
+#define TSR2M_NO_TIMESTAMP 0x00
+#define TSR2M_FIRST_SWITCH_TO_BATTERY BIT2
+#define TSR2M_LAST_SWITCH_TO_BATTERY BIT3
+#define TSR2M_LAST_SWITCH_TO_VDD (BIT3 | BIT2)
+#define TSR2M_FIRST_TS_EVENT BIT4
+#define TSR2M_LAST_TS_EVENT (BIT4 | BIT2)
+#define TSR3M (BIT7 | BIT6)
+#define TSR3M_NO_TIMESTAMP 0x00
+#define TSR3M_FIRST_SWITCH_TO_BATTERY BIT6
+#define TSR3M_LAST_SWITCH_TO_BATTERY BIT7
+#define TSR3M_LAST_SWITCH_TO_VDD (BIT7 | BIT6)
+
+/*
+ * Control and function registers overview
+ */
+
+// Offset register
+#define REGISTER_OFFSET 0x24
+
+// Control registers
+#define REGISTER_OSCILLATOR 0x25
+#define AMPM_12_24 BIT5
+#define AMPM_12_HOUR_MODE BIT5
+#define AMPM_24_HOUR_MODE 0x00
+#define XTAL_CAP_LOAD 0x03	//BIT0 & BIT1
+#define XTAL_CAP_7_0pf 0x00
+#define XTAL_CAP_6_0pf 0x01
+#define XTAL_CAP_12_5pf 0x02
+#define XTAL_CAP_12_5_pf 0x03	//Datasheet says 12.5pF for both 0x02 & 0x03
+
+#define REGISTER_BATTERY_SWITCH 0x26
+#define BSOFF BIT4
+#define BSOFF_ENABLE 0X00
+#define BSOFF_DISABLE BIT4
+#define BSRR BIT3
+#define BSRR_LOW 0x00
+#define BSRR_HIGH BIT3
+#define BSM (BIT2 | BIT1)
+#define BSM_VTH 0X00
+#define BSM_VBAT BIT1
+#define BSM_HIGHER BIT2
+#define BSM_LOWER (BIT2 | BIT1)
+#define BSTH BIT0
+#define BSTH_1_5 0x00
+#define BSTH_2_8 BIT0
+
+#define BATTERY_SWITCH_OFF 0
+#define BATTERY_SWITCH_VTH 1
+#define BATTERY_SWITCH_VBAT 2
+#define BATTERY_SWITCH_HIGHER 3
+#define BATTERY_SWITCH_LOWER 4
+
+#define BATTERY_VTH_1_5 0
+#define BATTERY_VTH_2_8 1
+
+#define REGISTER_PIN_IO 0x27
+#define CLKPM BIT7
+#define CLKPM_ENABLE 0x00
+#define CLKPM_DISABLE BIT7
+#define TSPULL BIT6
+#define TSPULL_80_K_OHM 0x00
+#define TSPULL_40_K_OHM BIT6
+#define TSL BIT5
+#define TSL_ACTIVE_HIGH 0x00
+#define TSL_ACTIVE_LOW BIT5
+#define TSIM BIT4
+#define TSIM_CMOS_INPUT 0x00
+#define TSIM_MECHANICAL_SWITCH_MODE BIT4
+#define TSPM (BIT3 | BIT2)
+#define TSPM_DISABLED 0x00
+#define TSPM_INTB BIT2
+#define TSPM_CLK_OUTPUT BIT3
+#define TSPM_INPUT_MODE (BIT3 | BIT2)
+#define INTAPM (BIT1 | BIT0)
+#define INTAPM_CLK_OUTPUT 0x00
+#define INTAPM_BATTERY_MODE_INDICATION BIT0
+#define INTAPM_INTA BIT1
+#define INTAPM_HIGH_IMPEDANCE (BIT1 | BIT0)
+
+#define REGISTER_FUNCTION 0x28
+#define RTCM BIT4
+#define RTCM_RTC_MODE 0x00
+#define RTCM_STOP_WATCH_MODE BIT4
+#define COF (BIT2 | BIT1 | BIT0)
+#define COF_32768 0x00
+#define COF_16384 BIT0
+#define COF_8192 BIT1
+#define COF_4096 (BIT1 | BIT0)
+#define COF_2048 BIT2
+#define COF_1024 (BIT2 | BIT0)
+#define COF_1 (BIT2 | BIT1)
+#define COF_LOW (BIT2 | BIT1 | BIT0)
+
+#define REGISTER_INTA_ENABLE 0x29
+#define ILPA BIT7
+#define ILPA_PULSE_SIGNAL 0x00
+#define ILPA_PERMANENT_SIGNAL BIT7
+#define PIEA BIT6
+#define PIEA_ENABLE BIT6
+#define PIEA_DISABLE 0x00
+#define OIEA BIT5
+#define OIEA_ENABLE BIT5
+#define OIEA_DISABLE 0x00
+#define A1IEA BIT4
+#define A1IEA_ENABLE BIT4
+#define A1IEA_DISABLE 0x00
+#define A2IEA BIT3
+#define A2IEA_ENABLE BIT3
+#define A2IEA_DISABLE 0x00
+#define TSRIEA BIT2
+#define TSRIEA_ENABLE BIT2
+#define TSRIEA_DISABLE 0x00
+#define BSIEA BIT1
+#define BSIEA_ENABLE BIT1
+#define BSIEA_DISABLE 0x00
+#define WDIEA BIT0
+#define WDIEA_ENABLE BIT0
+#define WDIEA_DISABLE 0x00
+
+#define REGISTER_INTB_ENABLE 0x2A
+#define ILPB BIT7
+#define ILPB_PULSE_SIGNAL 0x00
+#define ILPB_PERMANENT_SIGNAL BIT7
+#define PIEB BIT6
+#define PIEB_ENABLE BIT6
+#define PIEB_DISABLE 0x00
+#define OIEB BIT5
+#define OIEB_ENABLE BIT5
+#define OIEB_DISABLE 0x00
+#define A1IEB BIT4
+#define A1IEB_ENABLE BIT4
+#define A1IEB_DISABLE 0x00
+#define A2IEB BIT3
+#define A2IEB_ENABLE BIT3
+#define A2IEB_DISABLE 0x00
+#define TSRIEB BIT2
+#define TSRIEB_ENABLE BIT2
+#define TSRIEB_DISABLE 0x00
+#define BSIEB BIT1
+#define BSIEB_ENABLE BIT1
+#define BSIEB_DISABLE 0x00
+#define WDIEB BIT0
+#define WDIEB_ENABLE BIT0
+#define WDIEB_DISABLE 0x00
+
+#define REGISTER_FLAGS 0x2B
+#define PERIODIC_INTERRUPT_FLAG BIT7
+#define PERIODIC_INTERRUPT_FLAG_ACTIVE BIT7
+#define PERIODIC_INTERRUPT_FLAG_CLEAR 0x00
+#define ALARM2_FLAG BIT6
+#define ALARM2_FLAG_ACTIVE BIT6
+#define ALARM2_FLAG_CLEAR 0x00
+#define ALARM1_FLAG BIT5
+#define ALARM1_FLAG_ACTIVE BIT5
+#define ALARM1_FLAG_CLEAR 0x00
+#define WATCHDOG_FLAG BIT4
+#define WATCHDOG_FLAG_ACTIVE BIT4
+#define WATCHDOG_FLAG_CLEAR 0x00
+#define BATTERY_SWITCH_FLAG BIT3
+#define BATTERY_SWITCH_FLAG_ACTIVE BIT3
+#define BATTERY_SWITCH_FLAG_CLEAR 0x00
+#define TIMESTAMP_3_FLAG BIT2
+#define TIMESTAMP_3_FLAG_ACTIVE BIT2
+#define TIMESTAMP_3_FLAG_CLEAR 0x00
+#define TIMESTAMP_2_FLAG BIT1
+#define TIMESTAMP_2_FLAG_ACTIVE BIT1
+#define TIMESTAMP_2_FLAG_CLEAR 0x00
+#define TIMESTAMP_1_FLAG BIT0
+#define TIMESTAMP_1_FLAG_ACTIVE BIT0
+#define TIMESTAMP_1_FLAG_CLEAR 0x00
+
+// RAM byte
+#define REGISTER_RAM_BYTE 0x2C
+
+// WatchDog registers
+#define REGISTER_WATCHDOG 0x2D
+#define WDM BIT7
+#define WDM_SINGLE_SHOT 0x00
+#define WDM_REPEAT_MODE BIT7
+#define WDR (BIT6 | BIT5 | BIT4 | BIT3 | BIT2)
+#define WDS (BIT1 | BIT0)
+#define WDS_4_SECONDS 0x00
+#define WDS_1_SECOND BIT0
+#define WDS_1_OVER_4_SECOND BIT1
+#define WDS_1_OVER_16_SECOND (BIT1 | BIT0)
+
+// Stop
+#define REGISTER_STOP_ENABLE 0x2E
+#define STOP BIT0
+#define STOP_RTC_RUN 0x00
+#define STOP_RTC_STOPPED BIT0
+
+// Reset
+#define REGISTER_RESETS 0x2F
+#define SR_CMD 0x2C	/* Software Reset, it also triggers CPR and CTS */
+#define CPR_CMD 0xA4	/* Clear PRescaler */
+#define CTS_CMD 0x25	/* Clear TimeStamps */
+#define CPR_CTS_CMD 0xA5	/* Combines CPR and CTS commands */
+
+#define ALARM_ENABLED 1
+#define ALARM_DISABLED 0
+#define ALARM_PENDING 1
+#define ALARM_NOT_PENDING 0
+
+#define NO_INTERRUPT -1
+#define INTA 0
+#define INTB 1
+
+#endif				/* __RTC_PCF85263_H__ */