All of lore.kernel.org
 help / color / mirror / Atom feed
* [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality
@ 2017-01-20 12:36 Sean Nyekjaer
  2017-01-20 12:36 ` [rtc-linux] [PATCH 2/2] rtc: pcf2127: add support for pcf2127 tamper functionality Sean Nyekjaer
  2017-08-29 15:07 ` [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality Alexandre Belloni
  0 siblings, 2 replies; 5+ messages in thread
From: Sean Nyekjaer @ 2017-01-20 12:36 UTC (permalink / raw)
  To: rtc-linux; +Cc: Sean Nyekjaer

PCF2129 does not have watchdog functionality built-in so we
are only allowing to enable watchdog for PCF2127.

Watchdog functionality is done with great inspiration from
the rtc-ds1374 driver.

Signed-off-by: Sean Nyekjaer <sean.nyekjaer@prevas.dk>
---
 drivers/rtc/Kconfig       |   7 ++
 drivers/rtc/rtc-pcf2127.c | 174 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 180 insertions(+), 1 deletion(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e859d148aba9..c8985be81d83 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -799,6 +799,13 @@ 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_PCF2127_WDT
+	bool "NXP PCF2127 watchdog timer"
+	depends on RTC_DRV_PCF2127
+	help
+	  If you say Y here you will get support for the
+	  watchdog timer in the NXP PCF2127 chip real-time clock chips.
+
 config RTC_DRV_RV3029C2
 	tristate "Micro Crystal RV3029/3049"
 	depends on RTC_I2C_AND_SPI
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 2bfdf638b673..31627c59c44d 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -21,6 +21,13 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
+#ifdef CONFIG_RTC_DRV_PCF2127_WDT
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/miscdevice.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+#endif
 
 #define PCF2127_REG_CTRL1       (0x00)  /* Control Register 1 */
 #define PCF2127_REG_CTRL2       (0x01)  /* Control Register 2 */
@@ -28,6 +35,13 @@
 #define PCF2127_REG_CTRL3       (0x02)  /* Control Register 3 */
 #define PCF2127_REG_CTRL3_BLF		BIT(2)
 
+#define PCF2127_REG_WDG_TIMCTL		(0x10)
+#define PCF2127_REG_WDG_TIMCTL_CD	(BIT(7) | BIT(6))
+#define PCF2127_REG_WDG_T_CD_EN_RST	(BIT(7) | BIT(6))	/* WD en,rst assert */
+#define PCF2127_REG_WDG_TIMCTL_TF	(BIT(1) | BIT(0))
+#define PCF2127_REG_WDG_T_TF_1HZ	BIT(1)	/* Timer clock source */
+#define PCF2127_REG_WDG_TIMVAL		(0x11)
+
 #define PCF2127_REG_SC          (0x03)  /* datetime */
 #define PCF2127_REG_MN          (0x04)
 #define PCF2127_REG_HR          (0x05)
@@ -43,6 +57,138 @@ struct pcf2127 {
 	struct regmap *regmap;
 };
 
+#ifdef CONFIG_RTC_DRV_PCF2127_WDT
+static struct pcf2127 *save_pcf2127;
+
+/* default 32 sec timeout */
+#define WD_TIMO 32
+
+static int wdt_margin = WD_TIMO;
+
+static const struct watchdog_info pcf2127_wdt_info = {
+	.identity = "PCF2127 WDT",
+	.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+};
+
+static int pcf2127_wdt_enable(void)
+{
+	return regmap_write(save_pcf2127->regmap, PCF2127_REG_WDG_TIMCTL,
+			    PCF2127_REG_WDG_T_CD_EN_RST |
+			    PCF2127_REG_WDG_T_TF_1HZ);
+}
+
+static int pcf2127_wdt_settimeout(unsigned int timeout)
+{
+	int err;
+
+	err = pcf2127_wdt_enable();
+	if (err)
+		return err;
+
+	err = regmap_write(save_pcf2127->regmap, PCF2127_REG_WDG_TIMVAL,
+			   timeout);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void pcf2127_wdt_ping(void)
+{
+	int ret = 0;
+
+	ret = pcf2127_wdt_settimeout(wdt_margin);
+	if (ret)
+		pr_info("WD TICK FAIL!!!!!!!!!! %i\n", ret);
+}
+
+static int pcf2127_wdt_disable(void)
+{
+	return regmap_write_bits(save_pcf2127->regmap, PCF2127_REG_WDG_TIMCTL,
+				 PCF2127_REG_WDG_TIMCTL_CD, 0x00);
+}
+
+static long pcf2127_wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
+				       unsigned long arg)
+{
+	int new_margin, options;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		return copy_to_user((struct watchdog_info __user *)arg,
+				    &pcf2127_wdt_info,
+				    sizeof(pcf2127_wdt_info)) ? -EFAULT : 0;
+	case WDIOC_SETOPTIONS:
+		if (copy_from_user(&options, (int __user *)arg, sizeof(int)))
+			return -EFAULT;
+
+		if (options & WDIOS_DISABLECARD) {
+			pr_info("disable watchdog\n");
+			if (pcf2127_wdt_disable())
+				return -EFAULT;
+		}
+
+		if (options & WDIOS_ENABLECARD) {
+			pr_info("enable watchdog\n");
+			pcf2127_wdt_settimeout(wdt_margin);
+			pcf2127_wdt_ping();
+		}
+
+		return -EINVAL;
+	case WDIOC_KEEPALIVE:
+		pcf2127_wdt_ping();
+		return 0;
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_margin, (int __user *)arg))
+			return -EFAULT;
+
+		if (new_margin < 1 || new_margin > 255)
+			return -EINVAL;
+
+		wdt_margin = new_margin;
+		if (pcf2127_wdt_settimeout(new_margin))
+			return -EFAULT;
+		pcf2127_wdt_ping();
+		/* fallthrough */
+	case WDIOC_GETTIMEOUT:
+		return put_user(wdt_margin, (int __user *)arg);
+	default:
+		return -ENOTTY;
+	}
+}
+
+static ssize_t pcf2127_wdt_write(struct file *file, const char *data,
+				 size_t len, loff_t *ppos)
+{
+	if (len) {
+		pcf2127_wdt_ping();
+		return 1;
+	}
+	return 0;
+}
+
+static ssize_t pcf2127_wdt_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos)
+{
+	return 0;
+}
+
+static const struct file_operations pcf2127_wdt_fops = {
+	.owner = THIS_MODULE,
+	.read = pcf2127_wdt_read,
+	.unlocked_ioctl = pcf2127_wdt_unlocked_ioctl,
+	.write = pcf2127_wdt_write,
+	.llseek = no_llseek,
+};
+
+static struct miscdevice pcf2127_wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &pcf2127_wdt_fops,
+};
+
+#endif
+
 /*
  * In the routines that deal directly with the pcf2127 hardware, we use
  * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
@@ -175,6 +321,9 @@ static const struct rtc_class_ops pcf2127_rtc_ops = {
 static int pcf2127_probe(struct device *dev, struct regmap *regmap,
 			const char *name)
 {
+#ifdef CONFIG_RTC_DRV_PCF2127_WDT
+	int ret;
+#endif
 	struct pcf2127 *pcf2127;
 
 	dev_dbg(dev, "%s\n", __func__);
@@ -183,6 +332,10 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
 	if (!pcf2127)
 		return -ENOMEM;
 
+#ifdef CONFIG_RTC_DRV_PCF2127_WDT
+	save_pcf2127 = pcf2127;
+#endif
+
 	pcf2127->regmap = regmap;
 
 	dev_set_drvdata(dev, pcf2127);
@@ -190,7 +343,22 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
 	pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops,
 						THIS_MODULE);
 
-	return PTR_ERR_OR_ZERO(pcf2127->rtc);
+	if (IS_ERR(pcf2127->rtc))
+		return PTR_ERR_OR_ZERO(pcf2127->rtc);
+
+#ifdef CONFIG_RTC_DRV_PCF2127_WDT
+	if (!of_device_is_compatible(dev->of_node, "nxp,pcf2127"))
+		return 0;
+
+	if (of_property_read_bool(dev->of_node, "watchdog")) {
+		ret = misc_register(&pcf2127_wdt_miscdev);
+		if (ret)
+			return ret;
+	}
+	pcf2127_wdt_settimeout(32);
+#endif
+
+	return 0;
 }
 
 #ifdef CONFIG_OF
@@ -427,6 +595,10 @@ static void __exit pcf2127_exit(void)
 {
 	pcf2127_spi_unregister_driver();
 	pcf2127_i2c_unregister_driver();
+
+#ifdef CONFIG_RTC_DRV_PCF2127_WDT
+	misc_deregister(&pcf2127_wdt_miscdev);
+#endif
 }
 module_exit(pcf2127_exit)
 
-- 
2.11.0

-- 
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
--- 
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

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

* [rtc-linux] [PATCH 2/2] rtc: pcf2127: add support for pcf2127 tamper functionality
  2017-01-20 12:36 [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality Sean Nyekjaer
@ 2017-01-20 12:36 ` Sean Nyekjaer
  2017-08-29 15:07 ` [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality Alexandre Belloni
  1 sibling, 0 replies; 5+ messages in thread
From: Sean Nyekjaer @ 2017-01-20 12:36 UTC (permalink / raw)
  To: rtc-linux; +Cc: Sean Nyekjaer

Signed-off-by: Sean Nyekjaer <sean.nyekjaer@prevas.dk>
---
 drivers/rtc/Kconfig       |   7 +++
 drivers/rtc/rtc-pcf2127.c | 128 +++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 129 insertions(+), 6 deletions(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index c8985be81d83..e8d7944a4018 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -806,6 +806,13 @@ config RTC_DRV_PCF2127_WDT
 	  If you say Y here you will get support for the
 	  watchdog timer in the NXP PCF2127 chip real-time clock chips.
 
+config RTC_DRV_PCF2127_TAMPER
+	bool "NXP PCF2127 tamper"
+	depends on RTC_DRV_PCF2127
+	help
+	  If you say Y here you will get support for the
+	  tamper device in the NXP PCF2127 chip real-time clock chips.
+
 config RTC_DRV_RV3029C2
 	tristate "Micro Crystal RV3029/3049"
 	depends on RTC_I2C_AND_SPI
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 31627c59c44d..5f96cff9ebd5 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -30,7 +30,10 @@
 #endif
 
 #define PCF2127_REG_CTRL1       (0x00)  /* Control Register 1 */
+#define PCF2127_TSF1		BIT(4)
 #define PCF2127_REG_CTRL2       (0x01)  /* Control Register 2 */
+#define PCF2127_TSIE		BIT(2)
+#define PCF2127_TSF2		BIT(5)
 
 #define PCF2127_REG_CTRL3       (0x02)  /* Control Register 3 */
 #define PCF2127_REG_CTRL3_BLF		BIT(2)
@@ -42,6 +45,17 @@
 #define PCF2127_REG_WDG_T_TF_1HZ	BIT(1)	/* Timer clock source */
 #define PCF2127_REG_WDG_TIMVAL		(0x11)
 
+#define PCF2127_REG_TIMSTP_CTL		(0x12)
+#define PCF2127_TSM			BIT(7)
+#define PCF2127_TSOFF			BIT(6)
+
+#define PCF2127_REG_TIMSTP_SC		(0x01)
+#define PCF2127_REG_TIMSTP_MN		(0x02)
+#define PCF2127_REG_TIMSTP_HR		(0x03)
+#define PCF2127_REG_TIMSTP_DM		(0x04)
+#define PCF2127_REG_TIMSTP_MO		(0x05)
+#define PCF2127_REG_TIMSTP_YR		(0x06)
+
 #define PCF2127_REG_SC          (0x03)  /* datetime */
 #define PCF2127_REG_MN          (0x04)
 #define PCF2127_REG_HR          (0x05)
@@ -55,10 +69,84 @@
 struct pcf2127 {
 	struct rtc_device *rtc;
 	struct regmap *regmap;
+	struct rtc_time tamper_event;
+	bool tamper_enabled;
+	int irq;
 };
 
-#ifdef CONFIG_RTC_DRV_PCF2127_WDT
+#if defined(CONFIG_RTC_DRV_PCF2127_TAMPER) || defined(CONFIG_RTC_DRV_PCF2127_WDT)
 static struct pcf2127 *save_pcf2127;
+#endif
+
+#ifdef CONFIG_RTC_DRV_PCF2127_TAMPER
+static int pcf2127_tamper_event_print(struct device *dev)
+{
+	int err;
+	unsigned char buf[7];
+	struct rtc_time *tm;
+
+	err = regmap_bulk_read(save_pcf2127->regmap, PCF2127_REG_TIMSTP_CTL,
+			       buf, sizeof(buf));
+	if (err)
+		return err;
+
+	tm = &save_pcf2127->tamper_event;
+
+	tm->tm_sec = bcd2bin(buf[PCF2127_REG_TIMSTP_SC] & 0x7F);
+	tm->tm_min = bcd2bin(buf[PCF2127_REG_TIMSTP_MN] & 0x7F);
+	tm->tm_hour = bcd2bin(buf[PCF2127_REG_TIMSTP_HR] & 0x3F);
+	tm->tm_mday = bcd2bin(buf[PCF2127_REG_TIMSTP_DM] & 0x3F);
+	tm->tm_mon = bcd2bin(buf[PCF2127_REG_TIMSTP_MO] & 0x1F) - 1;
+	tm->tm_year = bcd2bin(buf[PCF2127_REG_TIMSTP_YR]);
+
+	dev_emerg(dev, "%s: Tamper detected at secs=%d, mins=%d, hours=%d, "
+		  "mday=%d, mon=%d, year=%d\n",
+		  __func__,
+		  tm->tm_sec, tm->tm_min, tm->tm_hour,
+		  tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+	return 0;
+}
+
+static int pcf2127_tamper_enable(void)
+{
+	int err;
+
+	/* Enable interrupt on tamper event */
+	err = regmap_write_bits(save_pcf2127->regmap, PCF2127_REG_CTRL2,
+				PCF2127_TSIE, PCF2127_TSIE);
+	if (err)
+		return err;
+
+	/* Enable timestamp function */
+	err = regmap_write_bits(save_pcf2127->regmap, PCF2127_REG_TIMSTP_CTL,
+				PCF2127_TSM | PCF2127_TSOFF, PCF2127_TSM);
+	if (err)
+		return err;
+
+	save_pcf2127->tamper_enabled = true;
+
+	return 0;
+}
+
+static irqreturn_t pcf2127_tamper_event_irq(int irq, void *data)
+{
+	struct device *dev = data;
+	struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
+
+	pcf2127_tamper_event_print(dev);
+
+	/* Clear interrupt pin */
+	regmap_write_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
+			PCF2127_TSF1, 0);
+	regmap_write_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
+			PCF2127_TSF2, 0);
+
+	return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_RTC_DRV_PCF2127_WDT
 
 /* default 32 sec timeout */
 #define WD_TIMO 32
@@ -219,6 +307,11 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
 			 "oscillator stop detected, date/time is not reliable\n");
 		return -EINVAL;
 	}
+#ifdef CONFIG_RTC_DRV_PCF2127_TAMPER
+	if (buf[PCF2127_REG_CTRL1] & PCF2127_TSF1) {
+		pcf2127_tamper_event_print(dev);
+	}
+#endif
 
 	dev_dbg(dev,
 		"%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, "
@@ -319,9 +412,9 @@ static const struct rtc_class_ops pcf2127_rtc_ops = {
 };
 
 static int pcf2127_probe(struct device *dev, struct regmap *regmap,
-			const char *name)
+			 const char *name, int irq)
 {
-#ifdef CONFIG_RTC_DRV_PCF2127_WDT
+#if defined(CONFIG_RTC_DRV_PCF2127_TAMPER) || defined(CONFIG_RTC_DRV_PCF2127_WDT)
 	int ret;
 #endif
 	struct pcf2127 *pcf2127;
@@ -332,7 +425,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
 	if (!pcf2127)
 		return -ENOMEM;
 
-#ifdef CONFIG_RTC_DRV_PCF2127_WDT
+#if defined(CONFIG_RTC_DRV_PCF2127_TAMPER) || defined(CONFIG_RTC_DRV_PCF2127_WDT)
 	save_pcf2127 = pcf2127;
 #endif
 
@@ -358,6 +451,28 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
 	pcf2127_wdt_settimeout(32);
 #endif
 
+#ifdef CONFIG_RTC_DRV_PCF2127_TAMPER
+	pcf2127->tamper_enabled = false;
+
+	if (!of_device_is_compatible(dev->of_node, "nxp,pcf2127"))
+		return 0;
+
+	if (of_property_read_bool(dev->of_node, "tamper")) {
+		pcf2127_tamper_enable();
+
+		ret = devm_request_threaded_irq(dev, irq, NULL,
+						pcf2127_tamper_event_irq,
+						IRQF_ONESHOT | IRQF_TRIGGER_FALLING, dev_name(dev),
+						dev);
+		if (ret < 0) {
+			dev_err(dev, "IRQ is not free.\n");
+			return ret;
+		}
+
+		pcf2127->irq = irq;
+	}
+#endif
+
 	return 0;
 }
 
@@ -466,7 +581,7 @@ static int pcf2127_i2c_probe(struct i2c_client *client,
 	}
 
 	return pcf2127_probe(&client->dev, regmap,
-				pcf2127_i2c_driver.driver.name);
+				pcf2127_i2c_driver.driver.name, client->irq);
 }
 
 static const struct i2c_device_id pcf2127_i2c_id[] = {
@@ -529,7 +644,8 @@ static int pcf2127_spi_probe(struct spi_device *spi)
 		return PTR_ERR(regmap);
 	}
 
-	return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name);
+	return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name,
+			     spi->irq);
 }
 
 static const struct spi_device_id pcf2127_spi_id[] = {
-- 
2.11.0

-- 
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
--- 
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

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

* Re: [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality
  2017-01-20 12:36 [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality Sean Nyekjaer
  2017-01-20 12:36 ` [rtc-linux] [PATCH 2/2] rtc: pcf2127: add support for pcf2127 tamper functionality Sean Nyekjaer
@ 2017-08-29 15:07 ` Alexandre Belloni
  2017-08-30  7:45   ` Sean Nyekjær
  1 sibling, 1 reply; 5+ messages in thread
From: Alexandre Belloni @ 2017-08-29 15:07 UTC (permalink / raw)
  To: Sean Nyekjaer; +Cc: rtc-linux

Hi Sean,

I know this patch is 7 months old but I never had the time to write a
proper reply.

This is using a pretty old API. Can you register a proper watchdog using
the watchdog subsystem (see drivers/watchdog)? Also, please copy the
watchdog maintainers.

I understand this will require a significant rewrite effort but the
final code will be quite cleaner.

On 20/01/2017 at 13:36:43 +0100, Sean Nyekjaer wrote:
> PCF2129 does not have watchdog functionality built-in so we
> are only allowing to enable watchdog for PCF2127.
> 
> Watchdog functionality is done with great inspiration from
> the rtc-ds1374 driver.
> 
> Signed-off-by: Sean Nyekjaer <sean.nyekjaer@prevas.dk>
> ---
>  drivers/rtc/Kconfig       |   7 ++
>  drivers/rtc/rtc-pcf2127.c | 174 +++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 180 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index e859d148aba9..c8985be81d83 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -799,6 +799,13 @@ 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_PCF2127_WDT
> +	bool "NXP PCF2127 watchdog timer"
> +	depends on RTC_DRV_PCF2127
> +	help
> +	  If you say Y here you will get support for the
> +	  watchdog timer in the NXP PCF2127 chip real-time clock chips.
> +
>  config RTC_DRV_RV3029C2
>  	tristate "Micro Crystal RV3029/3049"
>  	depends on RTC_I2C_AND_SPI
> diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
> index 2bfdf638b673..31627c59c44d 100644
> --- a/drivers/rtc/rtc-pcf2127.c
> +++ b/drivers/rtc/rtc-pcf2127.c
> @@ -21,6 +21,13 @@
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/regmap.h>
> +#ifdef CONFIG_RTC_DRV_PCF2127_WDT
> +#include <linux/fs.h>
> +#include <linux/ioctl.h>
> +#include <linux/miscdevice.h>
> +#include <linux/reboot.h>
> +#include <linux/watchdog.h>
> +#endif
>  
>  #define PCF2127_REG_CTRL1       (0x00)  /* Control Register 1 */
>  #define PCF2127_REG_CTRL2       (0x01)  /* Control Register 2 */
> @@ -28,6 +35,13 @@
>  #define PCF2127_REG_CTRL3       (0x02)  /* Control Register 3 */
>  #define PCF2127_REG_CTRL3_BLF		BIT(2)
>  
> +#define PCF2127_REG_WDG_TIMCTL		(0x10)
> +#define PCF2127_REG_WDG_TIMCTL_CD	(BIT(7) | BIT(6))
> +#define PCF2127_REG_WDG_T_CD_EN_RST	(BIT(7) | BIT(6))	/* WD en,rst assert */
> +#define PCF2127_REG_WDG_TIMCTL_TF	(BIT(1) | BIT(0))
> +#define PCF2127_REG_WDG_T_TF_1HZ	BIT(1)	/* Timer clock source */
> +#define PCF2127_REG_WDG_TIMVAL		(0x11)
> +
>  #define PCF2127_REG_SC          (0x03)  /* datetime */
>  #define PCF2127_REG_MN          (0x04)
>  #define PCF2127_REG_HR          (0x05)
> @@ -43,6 +57,138 @@ struct pcf2127 {
>  	struct regmap *regmap;
>  };
>  
> +#ifdef CONFIG_RTC_DRV_PCF2127_WDT
> +static struct pcf2127 *save_pcf2127;
> +
> +/* default 32 sec timeout */
> +#define WD_TIMO 32
> +
> +static int wdt_margin = WD_TIMO;
> +
> +static const struct watchdog_info pcf2127_wdt_info = {
> +	.identity = "PCF2127 WDT",
> +	.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
> +};
> +
> +static int pcf2127_wdt_enable(void)
> +{
> +	return regmap_write(save_pcf2127->regmap, PCF2127_REG_WDG_TIMCTL,
> +			    PCF2127_REG_WDG_T_CD_EN_RST |
> +			    PCF2127_REG_WDG_T_TF_1HZ);
> +}
> +
> +static int pcf2127_wdt_settimeout(unsigned int timeout)
> +{
> +	int err;
> +
> +	err = pcf2127_wdt_enable();
> +	if (err)
> +		return err;
> +
> +	err = regmap_write(save_pcf2127->regmap, PCF2127_REG_WDG_TIMVAL,
> +			   timeout);
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static void pcf2127_wdt_ping(void)
> +{
> +	int ret = 0;
> +
> +	ret = pcf2127_wdt_settimeout(wdt_margin);
> +	if (ret)
> +		pr_info("WD TICK FAIL!!!!!!!!!! %i\n", ret);
> +}
> +
> +static int pcf2127_wdt_disable(void)
> +{
> +	return regmap_write_bits(save_pcf2127->regmap, PCF2127_REG_WDG_TIMCTL,
> +				 PCF2127_REG_WDG_TIMCTL_CD, 0x00);
> +}
> +
> +static long pcf2127_wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
> +				       unsigned long arg)
> +{
> +	int new_margin, options;
> +
> +	switch (cmd) {
> +	case WDIOC_GETSUPPORT:
> +		return copy_to_user((struct watchdog_info __user *)arg,
> +				    &pcf2127_wdt_info,
> +				    sizeof(pcf2127_wdt_info)) ? -EFAULT : 0;
> +	case WDIOC_SETOPTIONS:
> +		if (copy_from_user(&options, (int __user *)arg, sizeof(int)))
> +			return -EFAULT;
> +
> +		if (options & WDIOS_DISABLECARD) {
> +			pr_info("disable watchdog\n");
> +			if (pcf2127_wdt_disable())
> +				return -EFAULT;
> +		}
> +
> +		if (options & WDIOS_ENABLECARD) {
> +			pr_info("enable watchdog\n");
> +			pcf2127_wdt_settimeout(wdt_margin);
> +			pcf2127_wdt_ping();
> +		}
> +
> +		return -EINVAL;
> +	case WDIOC_KEEPALIVE:
> +		pcf2127_wdt_ping();
> +		return 0;
> +	case WDIOC_SETTIMEOUT:
> +		if (get_user(new_margin, (int __user *)arg))
> +			return -EFAULT;
> +
> +		if (new_margin < 1 || new_margin > 255)
> +			return -EINVAL;
> +
> +		wdt_margin = new_margin;
> +		if (pcf2127_wdt_settimeout(new_margin))
> +			return -EFAULT;
> +		pcf2127_wdt_ping();
> +		/* fallthrough */
> +	case WDIOC_GETTIMEOUT:
> +		return put_user(wdt_margin, (int __user *)arg);
> +	default:
> +		return -ENOTTY;
> +	}
> +}
> +
> +static ssize_t pcf2127_wdt_write(struct file *file, const char *data,
> +				 size_t len, loff_t *ppos)
> +{
> +	if (len) {
> +		pcf2127_wdt_ping();
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +static ssize_t pcf2127_wdt_read(struct file *file, char __user *data,
> +				size_t len, loff_t *ppos)
> +{
> +	return 0;
> +}
> +
> +static const struct file_operations pcf2127_wdt_fops = {
> +	.owner = THIS_MODULE,
> +	.read = pcf2127_wdt_read,
> +	.unlocked_ioctl = pcf2127_wdt_unlocked_ioctl,
> +	.write = pcf2127_wdt_write,
> +	.llseek = no_llseek,
> +};
> +
> +static struct miscdevice pcf2127_wdt_miscdev = {
> +	.minor = WATCHDOG_MINOR,
> +	.name = "watchdog",
> +	.fops = &pcf2127_wdt_fops,
> +};
> +
> +#endif
> +
>  /*
>   * In the routines that deal directly with the pcf2127 hardware, we use
>   * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
> @@ -175,6 +321,9 @@ static const struct rtc_class_ops pcf2127_rtc_ops = {
>  static int pcf2127_probe(struct device *dev, struct regmap *regmap,
>  			const char *name)
>  {
> +#ifdef CONFIG_RTC_DRV_PCF2127_WDT
> +	int ret;
> +#endif
>  	struct pcf2127 *pcf2127;
>  
>  	dev_dbg(dev, "%s\n", __func__);
> @@ -183,6 +332,10 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
>  	if (!pcf2127)
>  		return -ENOMEM;
>  
> +#ifdef CONFIG_RTC_DRV_PCF2127_WDT
> +	save_pcf2127 = pcf2127;
> +#endif
> +
>  	pcf2127->regmap = regmap;
>  
>  	dev_set_drvdata(dev, pcf2127);
> @@ -190,7 +343,22 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
>  	pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops,
>  						THIS_MODULE);
>  
> -	return PTR_ERR_OR_ZERO(pcf2127->rtc);
> +	if (IS_ERR(pcf2127->rtc))
> +		return PTR_ERR_OR_ZERO(pcf2127->rtc);
> +
> +#ifdef CONFIG_RTC_DRV_PCF2127_WDT
> +	if (!of_device_is_compatible(dev->of_node, "nxp,pcf2127"))
> +		return 0;
> +
> +	if (of_property_read_bool(dev->of_node, "watchdog")) {
> +		ret = misc_register(&pcf2127_wdt_miscdev);
> +		if (ret)
> +			return ret;
> +	}
> +	pcf2127_wdt_settimeout(32);
> +#endif
> +
> +	return 0;
>  }
>  
>  #ifdef CONFIG_OF
> @@ -427,6 +595,10 @@ static void __exit pcf2127_exit(void)
>  {
>  	pcf2127_spi_unregister_driver();
>  	pcf2127_i2c_unregister_driver();
> +
> +#ifdef CONFIG_RTC_DRV_PCF2127_WDT
> +	misc_deregister(&pcf2127_wdt_miscdev);
> +#endif
>  }
>  module_exit(pcf2127_exit)
>  
> -- 
> 2.11.0
> 
> -- 
> You received this message because you are subscribed to "rtc-linux".
> Membership options at http://groups.google.com/group/rtc-linux .
> Please read http://groups.google.com/group/rtc-linux/web/checklist
> before submitting a driver.
> --- 
> You received this message because you are subscribed to the Google Groups "rtc-linux" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

* Re: [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality
  2017-08-29 15:07 ` [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality Alexandre Belloni
@ 2017-08-30  7:45   ` Sean Nyekjær
  2017-08-30  7:52     ` Alexandre Belloni
  0 siblings, 1 reply; 5+ messages in thread
From: Sean Nyekjær @ 2017-08-30  7:45 UTC (permalink / raw)
  To: Alexandre Belloni; +Cc: linux-rtc



On 2017-08-29 17:07, Alexandre Belloni wrote:
> Hi Sean,
>
> I know this patch is 7 months old but I never had the time to write a
> proper reply.
>
> This is using a pretty old API. Can you register a proper watchdog using
> the watchdog subsystem (see drivers/watchdog)? Also, please copy the
> watchdog maintainers.
>
> I understand this will require a significant rewrite effort but the
> final code will be quite cleaner.
Hi Alexandre

I unfortunately don't have access to the hardware anymore...
I think it would be very risky to rewrite the whole code without testing 
it :-)

Yes this driver is quite hacky in some ways. It could be nice if the 
watchdog part for this could be in the driver/watchdog and the rtc part 
here. Maybe we could have 2 entries in the devicetree that shared the 
same i2c device address.

/Sean

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

* Re: [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality
  2017-08-30  7:45   ` Sean Nyekjær
@ 2017-08-30  7:52     ` Alexandre Belloni
  0 siblings, 0 replies; 5+ messages in thread
From: Alexandre Belloni @ 2017-08-30  7:52 UTC (permalink / raw)
  To: Sean Nyekjær; +Cc: linux-rtc

On 30/08/2017 at 09:45:06 +0200, Sean Nyekjær wrote:
> 
> 
> On 2017-08-29 17:07, Alexandre Belloni wrote:
> > Hi Sean,
> > 
> > I know this patch is 7 months old but I never had the time to write a
> > proper reply.
> > 
> > This is using a pretty old API. Can you register a proper watchdog using
> > the watchdog subsystem (see drivers/watchdog)? Also, please copy the
> > watchdog maintainers.
> > 
> > I understand this will require a significant rewrite effort but the
> > final code will be quite cleaner.
> Hi Alexandre
> 
> I unfortunately don't have access to the hardware anymore...
> I think it would be very risky to rewrite the whole code without testing it
> :-)
> 

Ok, too bad. :(

> Yes this driver is quite hacky in some ways. It could be nice if the
> watchdog part for this could be in the driver/watchdog and the rtc part
> here. Maybe we could have 2 entries in the devicetree that shared the same
> i2c device address.
> 

If you want to go that route, the proper way is to use the MFD
subsystem.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

end of thread, other threads:[~2017-08-30  7:56 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-20 12:36 [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality Sean Nyekjaer
2017-01-20 12:36 ` [rtc-linux] [PATCH 2/2] rtc: pcf2127: add support for pcf2127 tamper functionality Sean Nyekjaer
2017-08-29 15:07 ` [rtc-linux] [PATCH 1/2] rtc: pcf2127: add support for pcf2127 watchdog functionality Alexandre Belloni
2017-08-30  7:45   ` Sean Nyekjær
2017-08-30  7:52     ` Alexandre Belloni

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.