[PATCH] rtc: rtc-ds1683 Maxim/Dallas I2C compatible

From: venkat . prashanth2498
Date: Wed Nov 29 2017 - 05:45:35 EST


From: Venkat Prashanth B U <venkat.prashanth2498@xxxxxxxxx>

This is a patch to add support for
maxim/dallas I2C rtc ds1683 chip.

Signed-off-by: Venkat Prashanth B U <venkat.prashanth2498@xxxxxxxxx>
---
drivers/rtc/Kconfig | 9 +++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-ds1683.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 213 insertions(+)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e0e58f3..2528b79 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -294,6 +294,15 @@ config RTC_DRV_DS1672
This driver can also be built as a module. If so, the module
will be called rtc-ds1672.

+config RTC_DRV_DS1683
+ tristate "Dallas/Maxim DS1683"
+ help
+ If you say yes here you get support for the
+ Dallas/Maxim DS1683 I2C timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1683.
+
config RTC_DRV_HYM8563
tristate "Haoyu Microelectronics HYM8563"
depends on OF
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 0bf1fc0..a6f4419 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_RTC_DRV_DS1390) += rtc-ds1390.o
obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
+obj-$(CONFIG_RTC_DRV_DS1683) += rtc-ds1683.o
obj-$(CONFIG_RTC_DRV_DS1685_FAMILY) += rtc-ds1685.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o
diff --git a/drivers/rtc/rtc-ds1683.c b/drivers/rtc/rtc-ds1683.c
index e69de29..7b6dac3 100644
--- a/drivers/rtc/rtc-ds1683.c
+++ b/drivers/rtc/rtc-ds1683.c
@@ -0,0 +1,203 @@
+/* rtc-ds1683.c
+ *
+ * Driver for Maxim/Dallas ds1683, I2C Compatible
+ * Real Time Clock
+ *
+ * Author : Venkat Prashanth B U <venkat.prashanth2498@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/module.h>
+
+/* Registers */
+
+#define ds1683_REG_CNT_BASE 0
+#define ds1683_REG_EVENT 4
+
+#define ds1683_REG_CONTROL_EOSC 0x80
+
+static struct i2c_driver ds1683_driver;
+
+static int ds1683_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+ unsigned long time;
+ unsigned char addr = ds1683_REG_CNT_BASE;
+ unsigned char buf[4];
+
+ struct i2c_msg msgs[] = {
+ { /* setup read pointer */
+ .addr = client->addr,
+ .len = 1,
+ .buf = &addr
+ },
+ {/* read date */
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 4,
+ .buf = buf
+ },
+ };
+
+ /* read date registers */
+ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+ dev_err(&client->dev, "%s: read error\n", __func__);
+ return -EIO;
+ }
+
+ time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+ rtc_time_to_tm(time, tm);
+
+ return 0;
+}
+
+static int ds1683_set_mmss(struct i2c_client *client, unsigned long secs)
+{
+ int xfer;
+ unsigned char buf[6];
+
+ buf[0] = ds1683_REG_CNT_BASE;
+ buf[1] = secs & 0x000000FF;
+ buf[2] = (secs & 0x0000FF00) >> 8;
+ buf[3] = (secs & 0x00FF0000) >> 16;
+ buf[4] = (secs & 0xFF000000) >> 24;
+ buf[5] = 0; /* set control reg to enable counting */
+
+ xfer = i2c_master_send(client, buf, 6);
+ if (xfer != 6) {
+ dev_err(&client->dev, "%s: send: %d\n", __func__, xfer);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ds1683_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return ds1683_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int ds1683_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+ return ds1683_set_mmss(to_i2c_client(dev), secs);
+}
+
+static int ds1683_get_control(struct i2c_client *client, u8 *status)
+{
+ unsigned char addr = ds1683_REG_CONTROL;
+
+ struct i2c_msg msgs[] = {
+ {/* setup read pointer */
+ .addr = client->addr,
+ .len = 1,
+ .buf = &addr
+ },
+ {/* read control */
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = status
+ },
+ };
+
+ /* read control register */
+ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+ dev_err(&client->dev, "%s: read error\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* sysfs callback functions */
+static ssize_t show_control(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 control;
+ int err;
+
+ err = ds1683_get_control(client, &control);
+ if (err)
+ return err;
+
+ return sprintf(buf, "%s\n", (control & ds1683_REG_CONTROL_EOSC)
+ ? "disabled" : "enabled");
+}
+
+static DEVICE_ATTR(control, 0444, show_control, NULL);
+
+static const struct rtc_class_ops ds1683_rtc_ops = {
+ .read_time = ds1683_rtc_read_time,
+ .set_mmss = ds1683_rtc_set_mmss,
+};
+
+static int ds1683_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err = 0;
+ u8 control;
+ struct rtc_device *rtc;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ rtc = devm_rtc_device_register(&client->dev, ds1683_driver.driver.name,
+ &ds1683_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ i2c_set_clientdata(client, rtc);
+
+ /* read control register */
+ err = ds1683_get_control(client, &control);
+ if (err)
+ dev_warn(&client->dev, "Unable to read the control register\n");
+
+ if (control & ds1683_REG_CONTROL_EOSC)
+ dev_warn(&client->dev, "Oscillator not enabled Set time to enable.\n");
+
+ /* Register sysfs hooks */
+ err = device_create_file(&client->dev, &dev_attr_control);
+ if (err)
+ dev_err(&client->dev, "Unable to create sysfs entry: %s\n",
+ dev_attr_control.attr.name);
+
+ return 0;
+}
+
+static const struct i2c_device_id ds1683_id[] = {
+ { "ds1683", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1683_id);
+
+static const struct of_device_id ds1683_of_match[] = {
+ { "dallas,ds1683", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ds1683_of_match);
+
+static struct i2c_driver ds1683_driver = {
+ .driver = {
+ .name = "rtc-ds1683",
+ .of_match_table = of_match_ptr(ds1683_of_match),
+ },
+ .probe = &ds1683_probe,
+ .id_table = ds1683_id,
+};
+
+module_i2c_driver(ds1683_driver);
+
+MODULE_AUTHOR("Venkat Prashanth B U <venkat.prashanth2498@xxxxxxxxx>");
+MODULE_DESCRIPTION("Dallas/Maxim ds1683 I2C driver");
+MODULE_LICENSE("GPL");
--
1.9.1