All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] rtc: add NXP PCF2131 support (i2c)
@ 2022-09-25 20:08 Angelo Dureghello
  2022-09-25 20:08 ` [PATCH 2/2] dt-bindings: rtc: add pcf2131 Angelo Dureghello
  0 siblings, 1 reply; 2+ messages in thread
From: Angelo Dureghello @ 2022-09-25 20:08 UTC (permalink / raw)
  To: a.zummo, alexandre.belloni; +Cc: linux-rtc, Angelo Dureghello

Started up this driver from similar rtc pcf2127.
Actually only i2c communication has been tested, spi
part can be easily added as needed in a later time.

Signed-off-by: Angelo Dureghello <angelo.dureghello@timesys.com>
---
 drivers/rtc/Kconfig       |  15 +
 drivers/rtc/Makefile      |   1 +
 drivers/rtc/rtc-pcf2131.c | 569 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 585 insertions(+)
 create mode 100644 drivers/rtc/rtc-pcf2131.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index b8de25118ad0..81aaa43ac8a0 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -920,6 +920,21 @@ config RTC_DRV_PCF2127
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-pcf2127.
 
+config RTC_DRV_PCF2131
+	tristate "NXP PCF2131"
+	depends on RTC_I2C
+	select REGMAP_I2C if I2C
+	select WATCHDOG_CORE if WATCHDOG
+	help
+	  If you say yes here you enable support for the NXP PCF2131 RTC
+	  chip, a CMOS RTC and calendar with an integrated temperature
+	  compensated crystal (Xtal) oscillator (TCXO) and a 32.768 kHz
+	  quartz crystal optimized for very high accuracy and ultra-low
+	  power consumption.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-pcf2131.
+
 config RTC_DRV_RV3029C2
 	tristate "Micro Crystal RV3029/3049"
 	depends on RTC_I2C_AND_SPI
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index aab22bc63432..30b429733c70 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -121,6 +121,7 @@ obj-$(CONFIG_RTC_DRV_PALMAS)	+= rtc-palmas.o
 obj-$(CONFIG_RTC_DRV_PCAP)	+= rtc-pcap.o
 obj-$(CONFIG_RTC_DRV_PCF2123)	+= rtc-pcf2123.o
 obj-$(CONFIG_RTC_DRV_PCF2127)	+= rtc-pcf2127.o
+obj-$(CONFIG_RTC_DRV_PCF2131)   += rtc-pcf2131.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
diff --git a/drivers/rtc/rtc-pcf2131.c b/drivers/rtc/rtc-pcf2131.c
new file mode 100644
index 000000000000..38fabbc49030
--- /dev/null
+++ b/drivers/rtc/rtc-pcf2131.c
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * An I2C and SPI driver for the NXP PCF2131 RTC
+ * Copyright 2022 Timesys Corp.
+ *
+ * Author: Angelo Dureghello <angelo.dureghello@timesys.com>
+ *
+ * Based on the other drivers in this same directory.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/watchdog.h>
+
+#define PCF2131_REG_CTRL1		0x00
+#define PCF2131_BIT_CTRL1_STOP		BIT(5)
+
+#define PCF2131_REG_CTRL2		0x01
+
+/* Control register 3 */
+#define PCF2131_REG_CTRL3		0x02
+#define PCF2131_BIT_CTRL3_BLIE		BIT(0)
+#define PCF2131_BIT_CTRL3_BIE		BIT(1)
+#define PCF2131_BIT_CTRL3_BLF		BIT(2)
+#define PCF2131_BIT_CTRL3_BF		BIT(3)
+#define PCF2131_BIT_CTRL3_BTSE		BIT(4)
+
+#define PCF2131_REG_CTRL4		0x03
+#define PCF2131_BIT_CTRL4_TSF4		BIT(4)
+#define PCF2131_BIT_CTRL4_TSF3		BIT(5)
+#define PCF2131_BIT_CTRL4_TSF2		BIT(6)
+#define PCF2131_BIT_CTRL4_TSF1		BIT(7)
+
+#define PCF2131_REG_CTRL5		0x04
+#define PCF2131_BIT_CTRL5_TSIE4		BIT(4)
+#define PCF2131_BIT_CTRL5_TSIE3		BIT(5)
+#define PCF2131_BIT_CTRL5_TSIE2		BIT(6)
+#define PCF2131_BIT_CTRL5_TSIE1		BIT(7)
+
+#define PCF2131_REG_SW_RST		0x05
+#define PCF2131_BIT_SW_RST_CPR		BIT(7)
+
+/* Time and date registers */
+#define PCF2131_REG_SC			0x07
+#define PCF2131_BIT_SC_OSF		BIT(7)
+#define PCF2131_REG_MN			0x08
+#define PCF2131_REG_HR			0x09
+#define PCF2131_REG_DM			0x0a
+#define PCF2131_REG_DW			0x0b
+#define PCF2131_REG_MO			0x0c
+#define PCF2131_REG_YR			0x0d
+
+/* Timestamps registers */
+#define PCF2131_TIMESTAMPS		4
+#define PCF2131_REG_TS_SIZE		7
+#define PCF2131_REG_TS1_CTRL		0x14
+#define PCF2131_REG_TS2_CTRL		0x1b
+#define PCF2131_REG_TS3_CTRL		0x22
+#define PCF2131_REG_TS4_CTRL		0x29
+#define PCF2131_BIT_TS_CTRL_TSOFF	BIT(6)
+#define PCF2131_BIT_TS_CTRL_TSM		BIT(7)
+
+/* Watchdog registers */
+#define PCF2131_REG_WD_CTL		0x35
+#define PCF2131_BIT_WD_CTL_TF0		BIT(0)
+#define PCF2131_BIT_WD_CTL_TF1		BIT(1)
+#define PCF2131_BIT_WD_CTL_TI_TP	BIT(5)
+#define PCF2131_BIT_WD_CTL_CD		BIT(7)
+#define PCF2131_REG_WD_VAL		0x36
+
+/* Watchdog timer value constants */
+#define PCF2131_WD_VAL_STOP		0
+#define PCF2131_WD_VAL_MIN		2
+#define PCF2131_WD_VAL_MAX		255
+#define PCF2131_WD_VAL_DEFAULT		60
+
+struct pcf2131 {
+	struct rtc_device *rtc;
+	struct regmap *regmap;
+	struct watchdog_device wdd;
+};
+
+static int pcf2131_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct pcf2131 *pcf2131 = dev_get_drvdata(dev);
+	u8 buf[16];
+	int ret;
+
+	ret = regmap_bulk_read(pcf2131->regmap, PCF2131_REG_CTRL1,
+			       buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	if (buf[PCF2131_REG_CTRL3] & PCF2131_BIT_CTRL3_BLF)
+		dev_info(dev, "low voltage, check/replace RTC battery.\n");
+
+	if (buf[PCF2131_REG_SC] & PCF2131_BIT_SC_OSF) {
+		dev_err(dev, "oscillator stop detected, time not reliable.\n");
+
+		return -EINVAL;
+	}
+
+	tm->tm_sec = bcd2bin(buf[PCF2131_REG_SC] & 0x7F);
+	tm->tm_min = bcd2bin(buf[PCF2131_REG_MN] & 0x7F);
+	tm->tm_hour = bcd2bin(buf[PCF2131_REG_HR] & 0x3F);
+	tm->tm_mday = bcd2bin(buf[PCF2131_REG_DM] & 0x3F);
+	tm->tm_wday = bcd2bin(buf[PCF2131_REG_DW] & 0x07);
+	tm->tm_mon = bcd2bin(buf[PCF2131_REG_MO] & 0x1F) - 1;
+	tm->tm_year = bcd2bin(buf[PCF2131_REG_YR]);
+	if (tm->tm_year < 70)
+		tm->tm_year += 100;
+
+	return 0;
+}
+
+static int pcf2131_rtc_stop(struct regmap *regmap)
+{
+	return regmap_update_bits(regmap, PCF2131_REG_CTRL1,
+					  PCF2131_BIT_CTRL1_STOP,
+					  PCF2131_BIT_CTRL1_STOP);
+}
+
+static int pcf2131_start_rtc(struct regmap *regmap)
+{
+	return regmap_update_bits(regmap, PCF2131_REG_CTRL1,
+					  PCF2131_BIT_CTRL1_STOP,
+					  0);
+}
+
+static int pcf2131_rtc_clear_prescaler(struct regmap *regmap)
+{
+	return regmap_update_bits(regmap, PCF2131_REG_SW_RST,
+					  PCF2131_BIT_SW_RST_CPR,
+					  PCF2131_BIT_SW_RST_CPR);
+}
+
+static int pcf2131_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct pcf2131 *pcf2131 = dev_get_drvdata(dev);
+	unsigned char buf[7];
+	int i = 0, err;
+
+	if (tm->tm_year < 100 || tm->tm_year >= 200)
+		return -EINVAL;
+
+	err = pcf2131_rtc_stop(pcf2131->regmap);
+	if (err)
+		goto ret_err;
+
+	err = pcf2131_rtc_clear_prescaler(pcf2131->regmap);
+	if (err)
+		goto ret_err;
+
+	/* this will also clear OSF flag */
+	buf[i++] = bin2bcd(tm->tm_sec);
+	buf[i++] = bin2bcd(tm->tm_min);
+	buf[i++] = bin2bcd(tm->tm_hour);
+	buf[i++] = bin2bcd(tm->tm_mday);
+	buf[i++] = bin2bcd(tm->tm_wday) & 0x07;
+	buf[i++] = bin2bcd(tm->tm_mon + 1);
+	buf[i++] = bin2bcd(tm->tm_year % 100);
+
+	err = regmap_bulk_write(pcf2131->regmap, PCF2131_REG_SC, buf, i);
+	if (err < 0) {
+		pcf2131_start_rtc(pcf2131->regmap);
+		goto ret_err;
+	}
+
+	if (pcf2131_start_rtc(pcf2131->regmap))
+		goto ret_err;
+
+	return 0;
+
+ret_err:
+	dev_err(dev, "%s: err=%d", __func__, err);
+
+	return err;
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+static int pcf2131_rtc_ioctl(struct device *dev,
+				unsigned int cmd, unsigned long arg)
+{
+	struct pcf2131 *pcf2131 = dev_get_drvdata(dev);
+	int ret, touser;
+
+	switch (cmd) {
+	case RTC_VL_READ:
+		ret = regmap_read(pcf2131->regmap, PCF2131_REG_CTRL3, &touser);
+		if (ret < 0)
+			return ret;
+
+		touser = touser & PCF2131_BIT_CTRL3_BLF ? 1 : 0;
+
+		if (copy_to_user((void __user *)arg, &touser, sizeof(int)))
+			return -EFAULT;
+		return 0;
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+#else
+#define pcf2131_rtc_ioctl NULL
+#endif
+
+static const struct rtc_class_ops pcf2131_rtc_ops = {
+	.ioctl = pcf2131_rtc_ioctl,
+	.read_time = pcf2131_rtc_read_time,
+	.set_time = pcf2131_rtc_set_time,
+};
+
+/* watchdog driver */
+
+static int pcf2131_wdt_ping(struct watchdog_device *wdd)
+{
+	struct pcf2131 *pcf2131 = watchdog_get_drvdata(wdd);
+
+	return regmap_write(pcf2131->regmap, PCF2131_REG_WD_VAL, wdd->timeout);
+}
+
+/*
+ * Restart watchdog timer if feature is active.
+ *
+ * Note: Reading CTRL2 register causes watchdog to stop which is unfortunate,
+ * since register also contain control/status flags for other features.
+ * Always call this function after reading CTRL2 register.
+ */
+static int pcf2131_wdt_active_ping(struct watchdog_device *wdd)
+{
+	int ret = 0;
+
+	if (watchdog_active(wdd)) {
+		ret = pcf2131_wdt_ping(wdd);
+		if (ret)
+			dev_err(wdd->parent,
+				"%s: watchdog restart failed, ret=%d\n",
+				__func__, ret);
+	}
+
+	return ret;
+}
+
+static int pcf2131_wdt_start(struct watchdog_device *wdd)
+{
+	return pcf2131_wdt_ping(wdd);
+}
+
+static int pcf2131_wdt_stop(struct watchdog_device *wdd)
+{
+	struct pcf2131 *pcf2131 = watchdog_get_drvdata(wdd);
+
+	return regmap_write(pcf2131->regmap, PCF2131_REG_WD_VAL,
+					     PCF2131_WD_VAL_STOP);
+}
+
+static int pcf2131_wdt_set_timeout(struct watchdog_device *wdd,
+				   unsigned int new_timeout)
+{
+	dev_dbg(wdd->parent, "new watchdog timeout: %is (old: %is)\n",
+		new_timeout, wdd->timeout);
+
+	wdd->timeout = new_timeout;
+
+	return pcf2131_wdt_active_ping(wdd);
+}
+
+static const struct watchdog_info pcf2131_wdt_info = {
+	.identity = "NXP PCF2131 Watchdog",
+	.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+};
+
+static const struct watchdog_ops pcf2131_watchdog_ops = {
+	.owner = THIS_MODULE,
+	.start = pcf2131_wdt_start,
+	.stop = pcf2131_wdt_stop,
+	.ping = pcf2131_wdt_ping,
+	.set_timeout = pcf2131_wdt_set_timeout,
+};
+
+/* sysfs interface */
+
+static ssize_t __timestamp_store(int idx,
+				 struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct pcf2131 *pcf2131 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(pcf2131->regmap,
+					PCF2131_REG_CTRL4,
+					PCF2131_BIT_CTRL4_TSF1 >> idx, 0);
+	if (ret < 0) {
+		dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = pcf2131_wdt_active_ping(&pcf2131->wdd);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t timestamp0_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return __timestamp_store(0, dev, attr, buf, count);
+}
+
+static ssize_t timestamp1_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return __timestamp_store(1, dev, attr, buf, count);
+}
+
+static ssize_t timestamp2_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return __timestamp_store(2, dev, attr, buf, count);
+}
+
+static ssize_t timestamp3_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return __timestamp_store(3, dev, attr, buf, count);
+}
+
+static ssize_t __timestamp_show(int idx, struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct pcf2131 *pcf2131 = dev_get_drvdata(dev);
+	struct rtc_time tm;
+	int ret;
+	int offs;
+	unsigned char data[48];
+
+	ret = regmap_bulk_read(pcf2131->regmap, PCF2131_REG_CTRL1,
+			       data, sizeof(data));
+	if (ret < 0)
+		return ret;
+
+	offs = PCF2131_REG_TS1_CTRL + (idx * PCF2131_REG_TS_SIZE);
+
+	ret = pcf2131_wdt_active_ping(&pcf2131->wdd);
+	if (ret)
+		return ret;
+
+	if (!(data[PCF2131_REG_CTRL4] & (PCF2131_BIT_CTRL4_TSF1 >> idx)))
+		return 0;
+
+	tm.tm_sec = bcd2bin(data[offs + 1] & 0x7F);
+	tm.tm_min = bcd2bin(data[offs + 2] & 0x7F);
+	tm.tm_hour = bcd2bin(data[offs + 3] & 0x3F);
+	tm.tm_mday = bcd2bin(data[offs + 4] & 0x3F);
+	tm.tm_mon = bcd2bin(data[offs + 5] & 0x1F) - 1;
+	tm.tm_year = bcd2bin(data[offs + 6]);
+	if (tm.tm_year < 70)
+		tm.tm_year += 100;
+
+	ret = rtc_valid_tm(&tm);
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%llu\n",
+		       (unsigned long long)rtc_tm_to_time64(&tm));
+};
+
+static ssize_t timestamp0_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return __timestamp_show(0, dev, attr, buf);
+}
+
+static ssize_t timestamp1_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return __timestamp_show(1, dev, attr, buf);
+}
+static ssize_t timestamp2_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return __timestamp_show(2, dev, attr, buf);
+}
+
+static ssize_t timestamp3_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return __timestamp_show(3, dev, attr, buf);
+}
+
+static DEVICE_ATTR_RW(timestamp0);
+static DEVICE_ATTR_RW(timestamp1);
+static DEVICE_ATTR_RW(timestamp2);
+static DEVICE_ATTR_RW(timestamp3);
+
+static struct attribute *pcf2131_attrs[] = {
+	&dev_attr_timestamp0.attr,
+	&dev_attr_timestamp1.attr,
+	&dev_attr_timestamp2.attr,
+	&dev_attr_timestamp3.attr,
+	NULL
+};
+
+static const struct attribute_group pcf2131_attr_group = {
+	.attrs	= pcf2131_attrs,
+};
+
+/*
+ * This device does not support bulk transferts.
+ */
+static const struct regmap_config regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0x36,
+	.use_single_read = 1,
+	.use_single_write = 1,
+};
+
+static int pcf2131_rtc_probe(struct i2c_client *client)
+{
+	struct pcf2131 *pcf2131;
+	struct rtc_device *rtc;
+	int i, ret = 0;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		return -ENODEV;
+
+	pcf2131 = devm_kzalloc(&client->dev,
+			       sizeof(struct pcf2131), GFP_KERNEL);
+	if (!pcf2131)
+		return -ENOMEM;
+
+	pcf2131->regmap = devm_regmap_init_i2c(client, &regmap_config);
+	if (IS_ERR(pcf2131->regmap))
+		return PTR_ERR(pcf2131->regmap);
+
+	i2c_set_clientdata(client, pcf2131);
+
+	rtc = devm_rtc_allocate_device(&client->dev);
+	if (IS_ERR(rtc))
+		return PTR_ERR(rtc);
+	pcf2131->rtc = rtc;
+
+	pcf2131->rtc->ops = &pcf2131_rtc_ops;
+
+	pcf2131->wdd.parent = &client->dev;
+	pcf2131->wdd.info = &pcf2131_wdt_info;
+	pcf2131->wdd.ops = &pcf2131_watchdog_ops;
+	pcf2131->wdd.min_timeout = PCF2131_WD_VAL_MIN;
+	pcf2131->wdd.max_timeout = PCF2131_WD_VAL_MAX;
+	pcf2131->wdd.timeout = PCF2131_WD_VAL_DEFAULT;
+	pcf2131->wdd.min_hw_heartbeat_ms = 500;
+
+	watchdog_set_drvdata(&pcf2131->wdd, pcf2131);
+
+	/*
+	 * Watchdog timer enabled and int pins /INTA/B activated when timed out.
+	 * Select 4Hz clock source for watchdog timer.
+	 * Timer is not started until WD_VAL is loaded with a valid value.
+	 * Note: countdown timer not available.
+	 */
+	ret = regmap_update_bits(pcf2131->regmap, PCF2131_REG_WD_CTL,
+					PCF2131_BIT_WD_CTL_CD |
+					PCF2131_BIT_WD_CTL_TI_TP |
+					PCF2131_BIT_WD_CTL_TF1 |
+					PCF2131_BIT_WD_CTL_TF0,
+					PCF2131_BIT_WD_CTL_CD |
+					PCF2131_BIT_WD_CTL_TF0);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: watchdog config failed, err %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+#ifdef CONFIG_WATCHDOG
+	ret = devm_watchdog_register_device(&client->dev, &pcf2131->wdd);
+	if (ret)
+		return ret;
+#endif /* CONFIG_WATCHDOG */
+
+	/*
+	 * Disable battery low/switch-over timestamp and interrupts.
+	 * Clear battery interrupt flags which can block new trigger events.
+	 * Note: This is the default chip behaviour but added to ensure
+	 * correct tamper timestamp and interrupt function.
+	 */
+	ret = regmap_update_bits(pcf2131->regmap, PCF2131_REG_CTRL3,
+					PCF2131_BIT_CTRL3_BTSE |
+					PCF2131_BIT_CTRL3_BF |
+					PCF2131_BIT_CTRL3_BIE |
+					PCF2131_BIT_CTRL3_BLIE, 0);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: interrupt config (ctrl3) failed\n",
+			__func__);
+		return ret;
+	}
+
+	for (i = 0; i < PCF2131_TIMESTAMPS; i++) {
+		int reg = PCF2131_REG_TS1_CTRL + i * PCF2131_REG_TS_SIZE;
+
+		ret = regmap_update_bits(pcf2131->regmap, reg,
+						PCF2131_BIT_TS_CTRL_TSOFF |
+						PCF2131_BIT_TS_CTRL_TSM,
+						PCF2131_BIT_TS_CTRL_TSM);
+		if (ret < 0) {
+			dev_err(&client->dev,
+				"%s: tamper detection %d config failed\n",
+				__func__, i);
+			return ret;
+		}
+
+		ret = regmap_update_bits(pcf2131->regmap, PCF2131_REG_CTRL5,
+						PCF2131_BIT_CTRL5_TSIE1 >> i,
+						PCF2131_BIT_CTRL5_TSIE1 >> i);
+		if (ret < 0) {
+			dev_err(&client->dev,
+				"%s: tamper interrupt config %d failed\n",
+				__func__, i);
+			return ret;
+		}
+	}
+
+	ret = rtc_add_group(rtc, &pcf2131_attr_group);
+	if (ret) {
+		dev_err(&client->dev, "%s: tamper sysfs registering failed\n",
+			__func__);
+		return ret;
+	}
+
+	return devm_rtc_register_device(rtc);
+}
+
+static const struct i2c_device_id pcf2131_id[] = {
+	{ "pcf2131", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, pcf2131_id);
+
+static const struct of_device_id pcf2131_rtc_of_match[] = {
+	{ .compatible = "nxp,pcf2131" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, pcf2131_rtc_of_match);
+
+static struct i2c_driver pcf2131_rtc_driver = {
+	.driver = {
+		.name = "rtc-pcf2131-i2c",
+		.of_match_table = of_match_ptr(pcf2131_rtc_of_match),
+	},
+	.probe_new = pcf2131_rtc_probe,
+	.id_table = pcf2131_id,
+};
+module_i2c_driver(pcf2131_rtc_driver);
+
+MODULE_AUTHOR("Angelo Dureghello <angelo.dureghello@timesys.com>");
+MODULE_DESCRIPTION("NXP PCF2131 RTC driver");
+MODULE_LICENSE("GPL");
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH 2/2] dt-bindings: rtc: add pcf2131
  2022-09-25 20:08 [PATCH 1/2] rtc: add NXP PCF2131 support (i2c) Angelo Dureghello
@ 2022-09-25 20:08 ` Angelo Dureghello
  0 siblings, 0 replies; 2+ messages in thread
From: Angelo Dureghello @ 2022-09-25 20:08 UTC (permalink / raw)
  To: a.zummo, alexandre.belloni; +Cc: linux-rtc, Angelo Dureghello

Add NXP pcf2131 fdt bindings..

Signed-off-by: Angelo Dureghello <angelo.dureghello@timesys.com>
---
 .../devicetree/bindings/rtc/nxp,pcf2131.yaml  | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/nxp,pcf2131.yaml

diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf2131.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf2131.yaml
new file mode 100644
index 000000000000..5e0e040a2631
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/nxp,pcf2131.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/nxp,pcf2131.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP PCF2131 Real Time Clock
+
+allOf:
+  - $ref: "rtc.yaml#"
+
+maintainers:
+  - Alexandre Belloni <alexandre.belloni@bootlin.com>
+
+properties:
+  compatible:
+    const: nxp,pcf2131
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  start-year: true
+
+  reset-source: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        rtc@53 {
+            compatible = "nxp,pcf2131";
+            reg = <0x53>;
+            pinctrl-0 = <&rtc_nint_pins>;
+        };
+    };
+
+...
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-09-25 20:09 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-25 20:08 [PATCH 1/2] rtc: add NXP PCF2131 support (i2c) Angelo Dureghello
2022-09-25 20:08 ` [PATCH 2/2] dt-bindings: rtc: add pcf2131 Angelo Dureghello

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.